Added wParam and lParam as parameters in SPY_ExitMessage
[wine] / windows / mdi.c
1 /* MDI.C
2  *
3  * Copyright 1994, Bob Amstadt
4  *           1995,1996 Alex Korobka
5  *
6  * This file contains routines to support MDI (Multiple Document
7  * Interface) features .
8  *
9  * Notes: Fairly complete implementation.
10  *        Also, Excel and WinWord do _not_ use MDI so if you're trying
11  *        to fix them look elsewhere. 
12  *
13  * Notes on how the "More Windows..." is implemented:
14  *
15  *      When we have more than 9 opened windows, a "More Windows..."
16  *      option appears in the "Windows" menu. Each child window has
17  *      a WND* associated with it, accesible via the children list of
18  *      the parent window. This WND* has a wIDmenu member, which reflects
19  *      the position of the child in the window list. For example, with
20  *      9 child windows, we could have the following pattern:
21  *
22  *
23  *
24  *                Name of the child window    pWndChild->wIDmenu
25  *                     Doc1                       5000
26  *                     Doc2                       5001
27  *                     Doc3                       5002
28  *                     Doc4                       5003
29  *                     Doc5                       5004
30  *                     Doc6                       5005
31  *                     Doc7                       5006
32  *                     Doc8                       5007
33  *                     Doc9                       5008
34  *
35  *
36  *       The "Windows" menu, as the "More windows..." dialog, are constructed
37  *       in this order. If we add a child, we would have the following list:
38  *
39  *
40  *               Name of the child window    pWndChild->wIDmenu
41  *                     Doc1                       5000
42  *                     Doc2                       5001
43  *                     Doc3                       5002
44  *                     Doc4                       5003
45  *                     Doc5                       5004
46  *                     Doc6                       5005
47  *                     Doc7                       5006
48  *                     Doc8                       5007
49  *                     Doc9                       5008
50  *                     Doc10                      5009
51  *
52  *       But only 5000 to 5008 would be displayed in the "Windows" menu. We want
53  *       the last created child to be in the menu, so we swap the last child with
54  *       the 9th... Doc9 will be accessible via the "More Windows..." option.
55  *
56  *                     Doc1                       5000
57  *                     Doc2                       5001
58  *                     Doc3                       5002
59  *                     Doc4                       5003
60  *                     Doc5                       5004
61  *                     Doc6                       5005
62  *                     Doc7                       5006
63  *                     Doc8                       5007
64  *                     Doc9                       5009
65  *                     Doc10                      5008
66  *
67  */
68
69 #include <stdlib.h>
70 #include <stdio.h>
71 #include <string.h>
72 #include <math.h>
73 #include "windef.h"
74 #include "wingdi.h"
75 #include "winuser.h"
76 #include "wine/unicode.h"
77 #include "win.h"
78 #include "class.h"
79 #include "heap.h"
80 #include "nonclient.h"
81 #include "mdi.h"
82 #include "user.h"
83 #include "menu.h"
84 #include "scroll.h"
85 #include "struct32.h"
86 #include "tweak.h"
87 #include "debugtools.h"
88 #include "dlgs.h"
89
90 DEFAULT_DEBUG_CHANNEL(mdi);
91
92 #define MDIF_NEEDUPDATE         0x0001
93
94 static HBITMAP16 hBmpClose   = 0;
95 static HBITMAP16 hBmpRestore = 0;
96
97 /* ----------------- declarations ----------------- */
98 static void MDI_UpdateFrameText(WND *, HWND, BOOL, LPCWSTR);
99 static BOOL MDI_AugmentFrameMenu(MDICLIENTINFO*, WND *, HWND);
100 static BOOL MDI_RestoreFrameMenu(WND *, HWND);
101
102 static LONG MDI_ChildActivate( WND*, HWND );
103
104 static HWND MDI_MoreWindowsDialog(WND*);
105 static void MDI_SwapMenuItems(WND *, UINT, UINT);
106 /* -------- Miscellaneous service functions ----------
107  *
108  *                      MDI_GetChildByID
109  */
110
111 static HWND MDI_GetChildByID(WND* wndPtr, INT id)
112 {
113     for (wndPtr = wndPtr->child; wndPtr; wndPtr = wndPtr->next)
114         if (wndPtr->wIDmenu == id) return wndPtr->hwndSelf;
115     return 0;
116 }
117
118 static void MDI_PostUpdate(HWND hwnd, MDICLIENTINFO* ci, WORD recalc)
119 {
120     if( !(ci->mdiFlags & MDIF_NEEDUPDATE) )
121     {
122         ci->mdiFlags |= MDIF_NEEDUPDATE;
123         PostMessageA( hwnd, WM_MDICALCCHILDSCROLL, 0, 0);
124     }
125     ci->sbRecalc = recalc;
126 }
127
128 /**********************************************************************
129  *                      MDI_MenuModifyItem
130  */
131 static BOOL MDI_MenuModifyItem(WND* clientWnd, HWND hWndChild )
132 {
133     WCHAR           buffer[128];
134     static const WCHAR format[] = {'%','d',' ',0};
135     MDICLIENTINFO  *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
136     WND            *wndPtr     = WIN_FindWndPtr(hWndChild);
137     UINT            n          = wsprintfW(buffer, format,
138                                            wndPtr->wIDmenu - clientInfo->idFirstChild + 1);
139     BOOL            bRet            = 0;
140
141     if( !clientInfo->hWindowMenu )
142     {
143         bRet =  FALSE;
144         goto END;
145     }
146
147     if (wndPtr->text) lstrcpynW(buffer + n, wndPtr->text, sizeof(buffer)/sizeof(WCHAR) - n );
148
149     n    = GetMenuState(clientInfo->hWindowMenu,wndPtr->wIDmenu ,MF_BYCOMMAND); 
150     bRet = ModifyMenuW(clientInfo->hWindowMenu , wndPtr->wIDmenu, 
151                       MF_BYCOMMAND | MF_STRING, wndPtr->wIDmenu, buffer );
152     CheckMenuItem(clientInfo->hWindowMenu ,wndPtr->wIDmenu , n & MF_CHECKED);
153 END:
154     WIN_ReleaseWndPtr(wndPtr);
155     return bRet;
156 }
157
158 /**********************************************************************
159  *                      MDI_MenuDeleteItem
160  */
161 static BOOL MDI_MenuDeleteItem(WND* clientWnd, HWND hWndChild )
162 {
163     WCHAR        buffer[128];
164     static const WCHAR format[] = {'&','%','d',' ',0};
165     MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
166     WND         *wndPtr     = WIN_FindWndPtr(hWndChild);
167     UINT         index      = 0,id,n;
168     BOOL         retvalue;
169
170     if( !clientInfo->nActiveChildren ||
171         !clientInfo->hWindowMenu )
172     {
173         retvalue = FALSE;
174         goto END;
175     }
176
177     id = wndPtr->wIDmenu;
178     DeleteMenu(clientInfo->hWindowMenu,id,MF_BYCOMMAND);
179
180  /* walk the rest of MDI children to prevent gaps in the id 
181   * sequence and in the menu child list */
182
183     for( index = id+1; index <= clientInfo->nActiveChildren + 
184                                 clientInfo->idFirstChild; index++ )
185     {
186         WND *tmpWnd = WIN_FindWndPtr(MDI_GetChildByID(clientWnd,index));
187         if( !tmpWnd )
188         {
189               TRACE("no window for id=%i\n",index);
190             WIN_ReleaseWndPtr(tmpWnd);
191               continue;
192         }
193     
194         /* set correct id */
195         tmpWnd->wIDmenu--;
196
197         n = wsprintfW(buffer, format ,index - clientInfo->idFirstChild);
198         if (tmpWnd->text)
199             lstrcpynW(buffer + n, tmpWnd->text, sizeof(buffer)/sizeof(WCHAR) - n );     
200
201         /*  change menu if the current child is to be shown in the 
202          *  "Windows" menu
203          */
204         if (index <= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT) 
205         ModifyMenuW(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING,
206                       index - 1 , buffer ); 
207         WIN_ReleaseWndPtr(tmpWnd);
208     }
209
210     /*  We must restore the "More Windows..." option if there is enough child 
211      */
212     if (clientInfo->nActiveChildren - 1 > MDI_MOREWINDOWSLIMIT)
213     {
214         char szTmp[50];
215         LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
216
217         AppendMenuA(clientInfo->hWindowMenu ,MF_STRING ,clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT, szTmp );
218     }
219     retvalue = TRUE;
220 END:
221     WIN_ReleaseWndPtr(wndPtr);
222     return retvalue;
223 }
224
225 /**********************************************************************
226  *                      MDI_GetWindow
227  *
228  * returns "activateable" child different from the current or zero
229  */
230 static HWND MDI_GetWindow(WND *clientWnd, HWND hWnd, BOOL bNext,
231                             DWORD dwStyleMask )
232 {
233     MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
234     WND *wndPtr, *pWnd, *pWndLast = NULL;
235     
236     dwStyleMask |= WS_DISABLED | WS_VISIBLE;
237     if( !hWnd ) hWnd = clientInfo->hwndActiveChild;
238
239     if( !(wndPtr = WIN_FindWndPtr(hWnd)) ) return 0;
240
241     for ( pWnd = WIN_LockWndPtr(wndPtr->next); ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
242     {
243         if (!pWnd ) WIN_UpdateWndPtr(&pWnd,wndPtr->parent->child);
244
245         if ( pWnd == wndPtr ) break; /* went full circle */
246
247         if (!pWnd->owner && (pWnd->dwStyle & dwStyleMask) == WS_VISIBLE )
248         {
249             pWndLast = pWnd;
250             if ( bNext ) break;
251         }
252     }
253     WIN_ReleaseWndPtr(wndPtr);
254     WIN_ReleaseWndPtr(pWnd);
255     return pWndLast ? pWndLast->hwndSelf : 0;
256 }
257
258 /**********************************************************************
259  *                      MDI_CalcDefaultChildPos
260  *
261  *  It seems that the default height is about 2/3 of the client rect
262  */
263 static void MDI_CalcDefaultChildPos( WND* w, WORD n, LPPOINT lpPos,
264                                      INT delta)
265 {
266     INT  nstagger;
267     RECT rect = w->rectClient;
268     INT  spacing = GetSystemMetrics(SM_CYCAPTION) +
269                      GetSystemMetrics(SM_CYFRAME) - 1; 
270
271     if( rect.bottom - rect.top - delta >= spacing ) 
272         rect.bottom -= delta;
273
274     nstagger = (rect.bottom - rect.top)/(3 * spacing);
275     lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
276     lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
277     lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
278 }
279
280 /**********************************************************************
281  *            MDISetMenu
282  */
283 static LRESULT MDISetMenu( HWND hwnd, HMENU hmenuFrame,
284                            HMENU hmenuWindow)
285 {
286     WND *w;
287     MDICLIENTINFO *ci;
288     HWND hwndFrame = GetParent(hwnd);
289     HMENU oldFrameMenu = GetMenu(hwndFrame);
290
291     TRACE("%04x %04x %04x\n",
292                 hwnd, hmenuFrame, hmenuWindow);
293
294     if (hmenuFrame && !IsMenu(hmenuFrame))
295     {
296         WARN("hmenuFrame is not a menu handle\n");
297         return 0L;
298     }
299         
300     if (hmenuWindow && !IsMenu(hmenuWindow))
301     {
302         WARN("hmenuWindow is not a menu handle\n");
303         return 0L;
304     }
305         
306     w = WIN_FindWndPtr(hwnd);
307     ci = (MDICLIENTINFO *) w->wExtra;
308
309     if( ci->hwndChildMaximized && hmenuFrame && hmenuFrame!=oldFrameMenu )
310         MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized );
311
312     if( hmenuWindow && ci->hWindowMenu && hmenuWindow!=ci->hWindowMenu )
313     {
314         /* delete menu items from ci->hWindowMenu 
315          * and add them to hmenuWindow */
316
317         INT i = GetMenuItemCount(ci->hWindowMenu) - 1;
318         INT pos = GetMenuItemCount(hmenuWindow) + 1;
319
320         AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL);
321
322         if( ci->nActiveChildren )
323         {
324             INT j;
325             LPWSTR buffer = NULL;
326             MENUITEMINFOW mii;
327             INT nbWindowsMenuItems; /* num of documents shown + "More Windows..." if present */
328
329             if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
330                 nbWindowsMenuItems = ci->nActiveChildren;
331             else
332                 nbWindowsMenuItems = MDI_MOREWINDOWSLIMIT + 1;
333
334             j = i - nbWindowsMenuItems + 1;
335
336             for( ; i >= j ; i-- )
337             {
338                 memset(&mii, 0, sizeof(mii));
339                 mii.cbSize = sizeof(mii);
340                 mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE
341                   | MIIM_SUBMENU | MIIM_TYPE | MIIM_BITMAP;
342
343                 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
344                 if(mii.cch) { /* Menu is MFT_STRING */
345                     mii.cch++; /* add room for '\0' */
346                     buffer = HeapAlloc(GetProcessHeap(), 0,
347                                        mii.cch * sizeof(WCHAR));
348                     mii.dwTypeData = buffer;
349                     GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
350                 }
351                 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
352                 InsertMenuItemW(hmenuWindow, pos, TRUE, &mii);
353                 if(buffer) {
354                     HeapFree(GetProcessHeap(), 0, buffer);
355                     buffer = NULL;
356                 }
357             }
358         }
359
360         /* remove separator */
361         DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION); 
362
363         ci->hWindowMenu = hmenuWindow;
364     } 
365
366     if (hmenuFrame)
367     {
368         SetMenu(hwndFrame, hmenuFrame);
369         if( hmenuFrame!=oldFrameMenu )
370         {
371             if( ci->hwndChildMaximized )
372                 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
373             WIN_ReleaseWndPtr(w);
374             return oldFrameMenu;
375         }
376     }
377     else
378     {
379         INT nItems = GetMenuItemCount(w->parent->wIDmenu) - 1;
380         UINT iId = GetMenuItemID(w->parent->wIDmenu,nItems) ;
381
382         if( !(iId == SC_RESTORE || iId == SC_CLOSE) )
383         {
384             /* SetMenu() may already have been called, meaning that this window
385              * already has its menu. But they may have done a SetMenu() on
386              * an MDI window, and called MDISetMenu() after the fact, meaning
387              * that the "if" to this "else" wouldn't catch the need to
388              * augment the frame menu.
389              */
390             if( ci->hwndChildMaximized )
391                 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
392         }
393     }
394     WIN_ReleaseWndPtr(w);
395     return 0;
396 }
397
398 /**********************************************************************
399  *            MDIRefreshMenu
400  */
401 static LRESULT MDIRefreshMenu( HWND hwnd, HMENU hmenuFrame,
402                            HMENU hmenuWindow)
403 {
404     HWND hwndFrame = GetParent(hwnd);
405     HMENU oldFrameMenu = GetMenu(hwndFrame);
406
407     TRACE("%04x %04x %04x\n",
408                 hwnd, hmenuFrame, hmenuWindow);
409
410     FIXME("partially function stub\n");
411
412     return oldFrameMenu;
413 }
414
415
416 /* ------------------ MDI child window functions ---------------------- */
417
418
419 /**********************************************************************
420  *                                      MDICreateChild
421  */
422 static HWND MDICreateChild( WND *w, MDICLIENTINFO *ci, HWND parent, 
423                               LPMDICREATESTRUCTA cs )
424 {
425     POINT          pos[2]; 
426     DWORD            style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
427     HWND             hwnd, hwndMax = 0;
428     WORD             wIDmenu = ci->idFirstChild + ci->nActiveChildren;
429     char             lpstrDef[]="junk!";
430
431     TRACE("origin %i,%i - dim %i,%i, style %08lx\n", 
432                 cs->x, cs->y, cs->cx, cs->cy, cs->style);
433     /* calculate placement */
434     MDI_CalcDefaultChildPos(w, ci->nTotalCreated++, pos, 0);
435
436     if (cs->cx == CW_USEDEFAULT || !cs->cx) cs->cx = pos[1].x;
437     if (cs->cy == CW_USEDEFAULT || !cs->cy) cs->cy = pos[1].y;
438
439     if( cs->x == CW_USEDEFAULT )
440     {
441         cs->x = pos[0].x;
442         cs->y = pos[0].y;
443     }
444
445     /* restore current maximized child */
446     if( (style & WS_VISIBLE) && ci->hwndChildMaximized )
447     {
448         TRACE("Restoring current maximized child %04x\n", ci->hwndChildMaximized);
449         if( style & WS_MAXIMIZE )
450             SendMessageA(w->hwndSelf, WM_SETREDRAW, FALSE, 0L );
451         hwndMax = ci->hwndChildMaximized;
452         ShowWindow( hwndMax, SW_SHOWNOACTIVATE );
453         if( style & WS_MAXIMIZE )
454             SendMessageA(w->hwndSelf, WM_SETREDRAW, TRUE, 0L );
455     }
456
457     if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
458     /* this menu is needed to set a check mark in MDI_ChildActivate */
459     if (ci->hWindowMenu != 0)
460         AppendMenuA(ci->hWindowMenu ,MF_STRING ,wIDmenu, lpstrDef );
461
462     ci->nActiveChildren++;
463
464     /* fix window style */
465     if( !(w->dwStyle & MDIS_ALLCHILDSTYLES) )
466     {
467         TRACE("MDIS_ALLCHILDSTYLES is missing, fixing window style\n");
468         style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE |
469                   WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL );
470         style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW);
471     }
472
473     if( w->flags & WIN_ISWIN32 )
474     {
475         hwnd = CreateWindowA( cs->szClass, cs->szTitle, style, 
476                                 cs->x, cs->y, cs->cx, cs->cy, parent, 
477                                 (HMENU)wIDmenu, cs->hOwner, cs );
478     }
479     else
480     {
481         MDICREATESTRUCT16 *cs16;
482         LPSTR title, cls;
483
484         cs16 = SEGPTR_NEW(MDICREATESTRUCT16);
485         STRUCT32_MDICREATESTRUCT32Ato16( cs, cs16 );
486         title = SEGPTR_STRDUP( cs->szTitle );
487         cls   = SEGPTR_STRDUP( cs->szClass );
488         cs16->szTitle = SEGPTR_GET(title);
489         cs16->szClass = SEGPTR_GET(cls);
490
491         hwnd = CreateWindow16( cs->szClass, cs->szTitle, style, 
492                                cs16->x, cs16->y, cs16->cx, cs16->cy, parent, 
493                                (HMENU)wIDmenu, cs16->hOwner,
494                                (LPVOID)SEGPTR_GET(cs16) );
495         SEGPTR_FREE( title );
496         SEGPTR_FREE( cls );
497         SEGPTR_FREE( cs16 );
498     }
499
500     /* MDI windows are WS_CHILD so they won't be activated by CreateWindow */
501
502     if (hwnd)
503     {
504         WND* wnd = WIN_FindWndPtr( hwnd );
505
506         /* All MDI child windows have the WS_EX_MDICHILD style */
507         wnd->dwExStyle |= WS_EX_MDICHILD;
508
509         /*  If we have more than 9 windows, we must insert the new one at the
510          *  9th position in order to see it in the "Windows" menu
511          */
512         if (ci->nActiveChildren > MDI_MOREWINDOWSLIMIT)
513             MDI_SwapMenuItems(wnd->parent, wnd->wIDmenu, ci->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
514
515         MDI_MenuModifyItem(w ,hwnd); 
516
517         /* Have we hit the "More Windows..." limit? If so, we must 
518          * add a "More Windows..." option 
519          */
520         if (ci->nActiveChildren == MDI_MOREWINDOWSLIMIT + 1)
521         {
522             char szTmp[50];
523             LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
524
525             ModifyMenuA(ci->hWindowMenu,
526                         ci->idFirstChild + MDI_MOREWINDOWSLIMIT, 
527                         MF_BYCOMMAND | MF_STRING, 
528                         ci->idFirstChild + MDI_MOREWINDOWSLIMIT, 
529                         szTmp);
530         }
531         
532         if( (wnd->dwStyle & WS_MINIMIZE) && ci->hwndActiveChild )
533         {
534             TRACE("Minimizing created MDI child %04x\n", hwnd);
535             ShowWindow( hwnd, SW_SHOWMINNOACTIVE );
536         }
537         else
538         {
539             /* WS_VISIBLE is clear if a) the MDI client has
540              * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the
541              * MDICreateStruct. If so the created window is not shown nor 
542              * activated.
543              */
544             if(wnd->dwStyle & WS_VISIBLE)
545                 ShowWindow(hwnd, SW_SHOW);
546         }
547         WIN_ReleaseWndPtr(wnd);
548         TRACE("created child - %04x\n",hwnd);
549     }
550     else
551     {
552         ci->nActiveChildren--;
553         DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
554         if( IsWindow(hwndMax) )
555             ShowWindow(hwndMax, SW_SHOWMAXIMIZED);
556     }
557         
558     return hwnd;
559 }
560
561 /**********************************************************************
562  *                      MDI_ChildGetMinMaxInfo
563  *
564  * Note: The rule here is that client rect of the maximized MDI child 
565  *       is equal to the client rect of the MDI client window.
566  */
567 static void MDI_ChildGetMinMaxInfo( WND* clientWnd, HWND hwnd,
568                                     MINMAXINFO16* lpMinMax )
569 {
570     WND*        childWnd = WIN_FindWndPtr(hwnd);
571     RECT        rect     = clientWnd->rectClient;
572
573     MapWindowPoints( clientWnd->parent->hwndSelf, 
574                      ((MDICLIENTINFO*)clientWnd->wExtra)->self, (LPPOINT)&rect, 2);
575     AdjustWindowRectEx( &rect, childWnd->dwStyle, 0, childWnd->dwExStyle );
576
577     lpMinMax->ptMaxSize.x = rect.right -= rect.left;
578     lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
579
580     lpMinMax->ptMaxPosition.x = rect.left;
581     lpMinMax->ptMaxPosition.y = rect.top; 
582
583     WIN_ReleaseWndPtr(childWnd);
584     
585     TRACE("max rect (%i,%i - %i, %i)\n", 
586                         rect.left,rect.top,rect.right,rect.bottom);
587     
588 }
589
590 /**********************************************************************
591  *                      MDI_SwitchActiveChild
592  * 
593  * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
594  *       being activated 
595  */
596 static void MDI_SwitchActiveChild( HWND clientHwnd, HWND childHwnd,
597                                    BOOL bNextWindow )
598 {
599     WND           *w         = WIN_FindWndPtr(clientHwnd);
600     HWND           hwndTo    = 0;
601     HWND           hwndPrev  = 0;
602     MDICLIENTINFO *ci;
603
604     hwndTo = MDI_GetWindow(w, childHwnd, bNextWindow, 0);
605  
606     ci = (MDICLIENTINFO *) w->wExtra;
607
608     TRACE("from %04x, to %04x\n",childHwnd,hwndTo);
609
610     if ( !hwndTo ) goto END; /* no window to switch to */
611
612     hwndPrev = ci->hwndActiveChild;
613
614     if ( hwndTo != hwndPrev )
615     {
616         BOOL bOptimize = 0;
617
618         if( ci->hwndChildMaximized )
619         {
620             bOptimize = 1; 
621             w->dwStyle &= ~WS_VISIBLE;
622         }
623
624         SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0, 
625                         SWP_NOMOVE | SWP_NOSIZE );
626
627         if( bNextWindow && hwndPrev )
628             SetWindowPos( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0, 
629                             SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
630         if( bOptimize )
631             ShowWindow( clientHwnd, SW_SHOW );
632     }
633 END:
634     WIN_ReleaseWndPtr(w);
635 }
636
637             
638 /**********************************************************************
639  *                                      MDIDestroyChild
640  */
641 static LRESULT MDIDestroyChild( WND *w_parent, MDICLIENTINFO *ci,
642                                 HWND parent, HWND child,
643                                 BOOL flagDestroy )
644 {
645     WND         *childPtr = WIN_FindWndPtr(child);
646
647     if( childPtr )
648     {
649         if( child == ci->hwndActiveChild )
650         {
651             MDI_SwitchActiveChild(parent, child, TRUE);
652
653             if( child == ci->hwndActiveChild )
654             {
655                 ShowWindow( child, SW_HIDE);
656                 if( child == ci->hwndChildMaximized )
657                 {
658                     MDI_RestoreFrameMenu(w_parent->parent, child);
659                     ci->hwndChildMaximized = 0;
660                     MDI_UpdateFrameText(w_parent->parent,parent,TRUE,NULL);
661                 }
662
663                 MDI_ChildActivate(w_parent, 0);
664             }
665         }
666
667         MDI_MenuDeleteItem(w_parent, child);
668
669         WIN_ReleaseWndPtr(childPtr);
670         
671         ci->nActiveChildren--;
672
673         TRACE("child destroyed - %04x\n",child);
674
675         if (flagDestroy)
676         {
677             MDI_PostUpdate(GetParent(child), ci, SB_BOTH+1);
678             DestroyWindow(child);
679         }
680     }
681
682     return 0;
683 }
684
685
686 /**********************************************************************
687  *                                      MDI_ChildActivate
688  *
689  * Note: hWndChild is NULL when last child is being destroyed
690  */
691 static LONG MDI_ChildActivate( WND *clientPtr, HWND hWndChild )
692 {
693     MDICLIENTINFO       *clientInfo = (MDICLIENTINFO*)clientPtr->wExtra; 
694     HWND               prevActiveWnd = clientInfo->hwndActiveChild;
695     WND                 *wndPtr = WIN_FindWndPtr( hWndChild );
696     WND                 *wndPrev = WIN_FindWndPtr( prevActiveWnd );
697     BOOL                 isActiveFrameWnd = 0;   
698     LONG               retvalue;
699
700     if( wndPtr )
701     {
702         if( wndPtr->dwStyle & WS_DISABLED )
703         {
704             retvalue = 0L;
705             goto END;
706         }
707     }
708
709     /* Don't activate if it is already active. Might happen 
710        since ShowWindow DOES activate MDI children */
711     if (clientInfo->hwndActiveChild == hWndChild)
712     {
713       retvalue = 0L;
714       goto END;
715     }
716
717     TRACE("%04x\n", hWndChild);
718
719     if( GetActiveWindow() == clientPtr->parent->hwndSelf )
720         isActiveFrameWnd = TRUE;
721         
722     /* deactivate prev. active child */
723     if( wndPrev )
724     {
725         wndPrev->dwStyle |= WS_SYSMENU;
726         SendMessageA( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
727         SendMessageA( prevActiveWnd, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
728                         (LPARAM)hWndChild);
729         /* uncheck menu item */
730         if( clientInfo->hWindowMenu )
731         {
732             WORD wPrevID = wndPrev->wIDmenu - clientInfo->idFirstChild;
733
734             if (wPrevID < MDI_MOREWINDOWSLIMIT)
735                 CheckMenuItem( clientInfo->hWindowMenu,
736                                  wndPrev->wIDmenu, 0);
737             else
738                 CheckMenuItem( clientInfo->hWindowMenu,
739                                clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1, 0);
740     }
741     }
742
743     /* set appearance */
744     if( clientInfo->hwndChildMaximized )
745     {
746       if( clientInfo->hwndChildMaximized != hWndChild ) {
747         if( hWndChild ) {
748                   clientInfo->hwndActiveChild = hWndChild;
749                   ShowWindow( hWndChild, SW_SHOWMAXIMIZED);
750         } else
751                 ShowWindow( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
752       }
753     }
754
755     clientInfo->hwndActiveChild = hWndChild;
756
757     /* check if we have any children left */
758     if( !hWndChild )
759     {
760         if( isActiveFrameWnd )
761             SetFocus( clientInfo->self );
762         retvalue = 0;
763         goto END;
764     }
765         
766     /* check menu item */
767     if( clientInfo->hWindowMenu )
768     {
769           /* The window to be activated must be displayed in the "Windows" menu */
770           if (wndPtr->wIDmenu >= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
771           {
772               MDI_SwapMenuItems(wndPtr->parent, wndPtr->wIDmenu, clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);    
773               MDI_MenuModifyItem(wndPtr->parent ,wndPtr->hwndSelf); 
774           }
775
776           CheckMenuItem(clientInfo->hWindowMenu, wndPtr->wIDmenu, MF_CHECKED);
777     }
778     /* bring active child to the top */
779     SetWindowPos( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
780
781     if( isActiveFrameWnd )
782     {
783             SendMessageA( hWndChild, WM_NCACTIVATE, TRUE, 0L);
784             if( GetFocus() == clientInfo->self )
785                 SendMessageA( clientInfo->self, WM_SETFOCUS, 
786                                 (WPARAM)clientInfo->self, 0L );
787             else
788                 SetFocus( clientInfo->self );
789     }
790     SendMessageA( hWndChild, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
791                     (LPARAM)hWndChild );
792     retvalue = 1;
793 END:
794     WIN_ReleaseWndPtr(wndPtr);
795     WIN_ReleaseWndPtr(wndPrev);
796     return retvalue;
797 }
798
799 /* -------------------- MDI client window functions ------------------- */
800
801 /**********************************************************************
802  *                              CreateMDIMenuBitmap
803  */
804 static HBITMAP16 CreateMDIMenuBitmap(void)
805 {
806  HDC            hDCSrc  = CreateCompatibleDC(0);
807  HDC            hDCDest = CreateCompatibleDC(hDCSrc);
808  HBITMAP16      hbClose = LoadBitmap16(0, MAKEINTRESOURCE16(OBM_CLOSE) );
809  HBITMAP16      hbCopy;
810  HANDLE16       hobjSrc, hobjDest;
811
812  hobjSrc = SelectObject(hDCSrc, hbClose);
813  hbCopy = CreateCompatibleBitmap(hDCSrc,GetSystemMetrics(SM_CXSIZE),GetSystemMetrics(SM_CYSIZE));
814  hobjDest = SelectObject(hDCDest, hbCopy);
815
816  BitBlt(hDCDest, 0, 0, GetSystemMetrics(SM_CXSIZE), GetSystemMetrics(SM_CYSIZE),
817           hDCSrc, GetSystemMetrics(SM_CXSIZE), 0, SRCCOPY);
818   
819  SelectObject(hDCSrc, hobjSrc);
820  DeleteObject(hbClose);
821  DeleteDC(hDCSrc);
822
823  hobjSrc = SelectObject( hDCDest, GetStockObject(BLACK_PEN) );
824
825  MoveToEx( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, 0, NULL );
826  LineTo( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, GetSystemMetrics(SM_CYSIZE) - 1);
827
828  SelectObject(hDCDest, hobjSrc );
829  SelectObject(hDCDest, hobjDest);
830  DeleteDC(hDCDest);
831
832  return hbCopy;
833 }
834
835 /**********************************************************************
836  *                              MDICascade
837  */
838 static LONG MDICascade(WND* clientWnd, MDICLIENTINFO *ci)
839 {
840     WND**       ppWnd;
841     UINT        total;
842   
843     if (ci->hwndChildMaximized)
844         SendMessageA( clientWnd->hwndSelf, WM_MDIRESTORE,
845                         (WPARAM)ci->hwndChildMaximized, 0);
846
847     if (ci->nActiveChildren == 0) return 0;
848
849     if ((ppWnd = WIN_BuildWinArray(clientWnd, BWA_SKIPHIDDEN | BWA_SKIPOWNED | 
850                                               BWA_SKIPICONIC, &total)))
851     {
852         WND**   heapPtr = ppWnd;
853         if( total )
854         {
855             INT delta = 0, n = 0;
856             POINT       pos[2];
857             if( total < ci->nActiveChildren )
858                 delta = GetSystemMetrics(SM_CYICONSPACING) +
859                         GetSystemMetrics(SM_CYICON);
860
861             /* walk the list (backwards) and move windows */
862             while (*ppWnd) ppWnd++;
863             while (ppWnd != heapPtr)
864             {
865                 ppWnd--;
866                 TRACE("move %04x to (%ld,%ld) size [%ld,%ld]\n", 
867                             (*ppWnd)->hwndSelf, pos[0].x, pos[0].y, pos[1].x, pos[1].y);
868
869                 MDI_CalcDefaultChildPos(clientWnd, n++, pos, delta);
870                 SetWindowPos( (*ppWnd)->hwndSelf, 0, pos[0].x, pos[0].y,
871                                 pos[1].x, pos[1].y,
872                                 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
873             }
874         }
875         WIN_ReleaseWinArray(heapPtr);
876     }
877
878     if( total < ci->nActiveChildren )
879         ArrangeIconicWindows( clientWnd->hwndSelf );
880     return 0;
881 }
882
883 /**********************************************************************
884  *                                      MDITile
885  */
886 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM wParam )
887 {
888     WND**       ppWnd;
889     UINT        total = 0;
890
891     if (ci->hwndChildMaximized)
892         SendMessageA( wndClient->hwndSelf, WM_MDIRESTORE,
893                         (WPARAM)ci->hwndChildMaximized, 0);
894
895     if (ci->nActiveChildren == 0) return;
896
897     ppWnd = WIN_BuildWinArray(wndClient, BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
898             ((wParam & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
899
900     TRACE("%u windows to tile\n", total);
901
902     if( ppWnd )
903     {
904         WND**   heapPtr = ppWnd;
905
906         if( total )
907         {
908             RECT        rect;
909             int         x, y, xsize, ysize;
910             int         rows, columns, r, c, i;
911
912             GetClientRect(wndClient->hwndSelf,&rect);
913             rows    = (int) sqrt((double)total);
914             columns = total / rows;
915
916             if( wParam & MDITILE_HORIZONTAL )  /* version >= 3.1 */
917             {
918                 i = rows;
919                 rows = columns;  /* exchange r and c */
920                 columns = i;
921             }
922
923             if( total != ci->nActiveChildren)
924             {
925                 y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
926                 rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
927             }
928
929             ysize   = rect.bottom / rows;
930             xsize   = rect.right  / columns;
931     
932             for (x = i = 0, c = 1; c <= columns && *ppWnd; c++)
933             {
934                 if (c == columns)
935                 {
936                     rows  = total - i;
937                     ysize = rect.bottom / rows;
938                 }
939
940                 y = 0;
941                 for (r = 1; r <= rows && *ppWnd; r++, i++)
942                 {
943                     SetWindowPos((*ppWnd)->hwndSelf, 0, x, y, xsize, ysize, 
944                                    SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
945                     y += ysize;
946                     ppWnd++;
947                 }
948                 x += xsize;
949             }
950         }
951         WIN_ReleaseWinArray(heapPtr);
952     }
953   
954     if( total < ci->nActiveChildren ) ArrangeIconicWindows( wndClient->hwndSelf );
955 }
956
957 /* ----------------------- Frame window ---------------------------- */
958
959
960 /**********************************************************************
961  *                                      MDI_AugmentFrameMenu
962  */
963 static BOOL MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
964                                     HWND hChild )
965 {
966     WND*        child = WIN_FindWndPtr(hChild);
967     HMENU       hSysPopup = 0;
968   HBITMAP hSysMenuBitmap = 0;
969
970     TRACE("frame %p,child %04x\n",frame,hChild);
971
972     if( !frame->wIDmenu || !child->hSysMenu )
973     {
974         WIN_ReleaseWndPtr(child);
975         return 0;
976     }
977     WIN_ReleaseWndPtr(child);
978
979     /* create a copy of sysmenu popup and insert it into frame menu bar */
980
981     if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
982         return 0;
983  
984     TRACE("\tgot popup %04x in sysmenu %04x\n", 
985                 hSysPopup, child->hSysMenu);
986  
987     AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
988                    SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
989     AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
990                    SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
991
992   /* In Win 95 look, the system menu is replaced by the child icon */
993
994   if(TWEAK_WineLook > WIN31_LOOK)
995   {
996     HICON hIcon = GetClassLongA(hChild, GCL_HICONSM);
997     if (!hIcon)
998       hIcon = GetClassLongA(hChild, GCL_HICON);
999     if (hIcon)
1000     {
1001       HDC hMemDC;
1002       HBITMAP hBitmap, hOldBitmap;
1003       HBRUSH hBrush;
1004       HDC hdc = GetDC(hChild);
1005
1006       if (hdc)
1007       {
1008         int cx, cy;
1009         cx = GetSystemMetrics(SM_CXSMICON);
1010         cy = GetSystemMetrics(SM_CYSMICON);
1011         hMemDC = CreateCompatibleDC(hdc);
1012         hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
1013         hOldBitmap = SelectObject(hMemDC, hBitmap);
1014         SetMapMode(hMemDC, MM_TEXT);
1015         hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
1016         DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL);
1017         SelectObject (hMemDC, hOldBitmap);
1018         DeleteObject(hBrush);
1019         DeleteDC(hMemDC);
1020         ReleaseDC(hChild, hdc);
1021         hSysMenuBitmap = hBitmap;
1022       }
1023     }
1024   }
1025   else
1026     hSysMenuBitmap = hBmpClose;
1027
1028     if( !InsertMenuA(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
1029                     hSysPopup, (LPSTR)(DWORD)hSysMenuBitmap))
1030     {  
1031         TRACE("not inserted\n");
1032         DestroyMenu(hSysPopup); 
1033         return 0; 
1034     }
1035
1036     /* The close button is only present in Win 95 look */
1037     if(TWEAK_WineLook > WIN31_LOOK)
1038     {
1039         AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
1040                        SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
1041     }
1042
1043     EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
1044     EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
1045     EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
1046     SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE);
1047
1048     /* redraw menu */
1049     DrawMenuBar(frame->hwndSelf);
1050
1051     return 1;
1052 }
1053
1054 /**********************************************************************
1055  *                                      MDI_RestoreFrameMenu
1056  */
1057 static BOOL MDI_RestoreFrameMenu( WND *frameWnd, HWND hChild )
1058 {
1059     MENUITEMINFOA menuInfo;
1060     INT nItems = GetMenuItemCount(frameWnd->wIDmenu) - 1;
1061     UINT iId = GetMenuItemID(frameWnd->wIDmenu,nItems) ;
1062
1063     TRACE("frameWnd %p,(%04x),child %04x,nIt=%d,iId=%d\n",
1064            frameWnd,frameWnd->hwndSelf,hChild,nItems,iId);
1065
1066     if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
1067         return 0; 
1068
1069     /*
1070      * Remove the system menu, If that menu is the icon of the window
1071      * as it is in win95, we have to delete the bitmap.
1072      */
1073     menuInfo.cbSize = sizeof(MENUITEMINFOA);
1074     menuInfo.fMask  = MIIM_DATA | MIIM_TYPE;
1075
1076     GetMenuItemInfoA(frameWnd->wIDmenu, 
1077                      0, 
1078                      TRUE,
1079                      &menuInfo);
1080
1081     RemoveMenu(frameWnd->wIDmenu,0,MF_BYPOSITION);
1082
1083     if ( (menuInfo.fType & MFT_BITMAP)           &&
1084          (LOWORD(menuInfo.dwTypeData)!=0)        &&
1085          (LOWORD(menuInfo.dwTypeData)!=hBmpClose) )
1086     {
1087       DeleteObject((HBITMAP)LOWORD(menuInfo.dwTypeData));
1088     }
1089
1090     if(TWEAK_WineLook > WIN31_LOOK)
1091     {
1092         /* close */
1093         DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1094     }
1095     /* restore */
1096     DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1097     /* minimize */
1098     DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1099
1100     DrawMenuBar(frameWnd->hwndSelf);
1101
1102     return 1;
1103 }
1104
1105
1106 /**********************************************************************
1107  *                                      MDI_UpdateFrameText
1108  *
1109  * used when child window is maximized/restored 
1110  *
1111  * Note: lpTitle can be NULL
1112  */
1113 static void MDI_UpdateFrameText( WND *frameWnd, HWND hClient,
1114                                  BOOL repaint, LPCWSTR lpTitle )
1115 {
1116     WCHAR   lpBuffer[MDI_MAXTITLELENGTH+1];
1117     WND*   clientWnd = WIN_FindWndPtr(hClient);
1118     MDICLIENTINFO *ci = (MDICLIENTINFO *) clientWnd->wExtra;
1119
1120     TRACE("repaint %i, frameText %s\n", repaint, (lpTitle)?debugstr_w(lpTitle):"NULL");
1121
1122     if (!clientWnd)
1123            return;
1124
1125     if (!ci)
1126     {
1127        WIN_ReleaseWndPtr(clientWnd);
1128            return;
1129     }
1130
1131     /* store new "default" title if lpTitle is not NULL */
1132     if (lpTitle) 
1133     {
1134         if (ci->frameTitle) HeapFree( SystemHeap, 0, ci->frameTitle );
1135         ci->frameTitle = HEAP_strdupW( SystemHeap, 0, lpTitle );
1136     }
1137
1138     if (ci->frameTitle)
1139     {
1140         WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );     
1141
1142         if( childWnd && childWnd->text )
1143         {
1144             /* combine frame title and child title if possible */
1145
1146             static const WCHAR lpBracket[]  = {' ','-',' ','[',0};
1147             static const WCHAR lpBracket2[]  = {']',0};
1148             int i_frame_text_length = strlenW(ci->frameTitle);
1149             int i_child_text_length = strlenW(childWnd->text);
1150
1151             lstrcpynW( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
1152
1153             if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
1154             {
1155                 strcatW( lpBuffer, lpBracket );
1156
1157                 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
1158                 {
1159                     strcatW( lpBuffer, childWnd->text );
1160                     strcatW( lpBuffer, lpBracket2 );
1161                 }
1162                 else
1163                 {
1164                     lstrcpynW( lpBuffer + i_frame_text_length + 4, 
1165                                  childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
1166                     strcatW( lpBuffer, lpBracket2 );
1167                 }
1168             }
1169         }
1170         else
1171         {
1172             lstrcpynW(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH+1 );
1173         }
1174         WIN_ReleaseWndPtr(childWnd);
1175
1176     }
1177     else
1178         lpBuffer[0] = '\0';
1179
1180     DEFWND_SetTextW( frameWnd, lpBuffer );
1181     if( repaint == MDI_REPAINTFRAME)
1182         SetWindowPos( frameWnd->hwndSelf, 0,0,0,0,0, SWP_FRAMECHANGED |
1183                         SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
1184
1185     WIN_ReleaseWndPtr(clientWnd);
1186
1187 }
1188
1189
1190 /* ----------------------------- Interface ---------------------------- */
1191
1192
1193 /**********************************************************************
1194  *                                      MDIClientWndProc
1195  *
1196  * This function handles all MDI requests.
1197  */
1198 LRESULT WINAPI MDIClientWndProc( HWND hwnd, UINT message, WPARAM wParam,
1199                                  LPARAM lParam )
1200 {
1201     LPCREATESTRUCTA      cs;
1202     MDICLIENTINFO       *ci;
1203     RECT                 rect;
1204     WND                 *w, *frameWnd;
1205     INT                  nItems;
1206     LRESULT              retvalue;
1207     
1208     if ( ( w = WIN_FindWndPtr(hwnd) ) == NULL )
1209        return 0;
1210
1211     if ( ( frameWnd = WIN_LockWndPtr(w->parent) ) == NULL ) {
1212        WIN_ReleaseWndPtr(w);
1213        return 0;
1214     }
1215
1216     ci = (MDICLIENTINFO *) w->wExtra;    
1217
1218     switch (message)
1219     {
1220       case WM_CREATE:
1221
1222         cs = (LPCREATESTRUCTA)lParam;
1223
1224         /* Translation layer doesn't know what's in the cs->lpCreateParams
1225          * so we have to keep track of what environment we're in. */
1226
1227         if( w->flags & WIN_ISWIN32 )
1228         {
1229 #define ccs ((LPCLIENTCREATESTRUCT)cs->lpCreateParams)
1230             ci->hWindowMenu     = ccs->hWindowMenu;
1231             ci->idFirstChild    = ccs->idFirstChild;
1232 #undef ccs
1233         }
1234         else    
1235         {
1236             LPCLIENTCREATESTRUCT16 ccs = (LPCLIENTCREATESTRUCT16) 
1237                                    PTR_SEG_TO_LIN(cs->lpCreateParams);
1238             ci->hWindowMenu     = ccs->hWindowMenu;
1239             ci->idFirstChild    = ccs->idFirstChild;
1240         }
1241
1242         ci->hwndChildMaximized  = 0;
1243         ci->nActiveChildren     = 0;
1244         ci->nTotalCreated       = 0;
1245         ci->frameTitle          = NULL;
1246         ci->mdiFlags            = 0;
1247         ci->self                = hwnd;
1248         w->dwStyle             |= WS_CLIPCHILDREN;
1249
1250         if (!hBmpClose)
1251         {
1252             hBmpClose = CreateMDIMenuBitmap();
1253             hBmpRestore = LoadBitmap16( 0, MAKEINTRESOURCE16(OBM_RESTORE) );
1254         }
1255         MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
1256
1257         if (ci->hWindowMenu != 0)
1258             AppendMenuA( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
1259
1260         GetClientRect(frameWnd->hwndSelf, &rect);
1261         NC_HandleNCCalcSize( w, &rect );
1262         w->rectClient = rect;
1263
1264         TRACE("Client created - hwnd = %04x, idFirst = %u\n",
1265                            hwnd, ci->idFirstChild );
1266
1267         retvalue = 0;
1268         goto END;
1269       
1270       case WM_DESTROY:
1271         if( ci->hwndChildMaximized )
1272             MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized);
1273         if((ci->hWindowMenu != 0) && 
1274            (nItems = GetMenuItemCount(ci->hWindowMenu)) > 0) 
1275         {
1276             ci->idFirstChild = nItems - 1;
1277             ci->nActiveChildren++;              /* to delete a separator */
1278             while( ci->nActiveChildren-- )
1279                 DeleteMenu(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
1280         }
1281         retvalue = 0;
1282         goto END;
1283
1284       case WM_MDIACTIVATE:
1285         if( ci->hwndActiveChild != (HWND)wParam )
1286             SetWindowPos((HWND)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
1287         retvalue = 0;
1288         goto END;
1289
1290       case WM_MDICASCADE:
1291         retvalue = MDICascade(w, ci);
1292         goto END;
1293
1294       case WM_MDICREATE:
1295         if (lParam) retvalue = MDICreateChild( w, ci, hwnd,
1296                                            (MDICREATESTRUCTA*)lParam );
1297         else retvalue = 0;
1298         goto END;
1299
1300       case WM_MDIDESTROY:
1301         retvalue = MDIDestroyChild( w, ci, hwnd, (HWND)wParam, TRUE );
1302         goto END;
1303
1304       case WM_MDIGETACTIVE:
1305           if (lParam) *(BOOL *)lParam = (ci->hwndChildMaximized > 0);
1306           retvalue = ci->hwndActiveChild;
1307           goto END;
1308
1309       case WM_MDIICONARRANGE:
1310         ci->mdiFlags |= MDIF_NEEDUPDATE;
1311         ArrangeIconicWindows(hwnd);
1312         ci->sbRecalc = SB_BOTH+1;
1313         SendMessageA(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
1314         retvalue = 0;
1315         goto END;
1316         
1317       case WM_MDIMAXIMIZE:
1318         ShowWindow( (HWND)wParam, SW_MAXIMIZE );
1319         retvalue = 0;
1320         goto END;
1321
1322       case WM_MDINEXT: /* lParam != 0 means previous window */
1323         MDI_SwitchActiveChild(hwnd, (HWND)wParam, (lParam)? FALSE : TRUE );
1324         break;
1325         
1326       case WM_MDIRESTORE:
1327         SendMessageA( (HWND)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
1328         retvalue = 0;
1329         goto END;
1330
1331       case WM_MDISETMENU:
1332           retvalue = MDISetMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1333           goto END;
1334       case WM_MDIREFRESHMENU:
1335           retvalue = MDIRefreshMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1336           goto END;
1337
1338       case WM_MDITILE:
1339         ci->mdiFlags |= MDIF_NEEDUPDATE;
1340         ShowScrollBar(hwnd,SB_BOTH,FALSE);
1341         MDITile(w, ci, wParam);
1342         ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1343         retvalue = 0;
1344         goto END;
1345
1346       case WM_VSCROLL:
1347       case WM_HSCROLL:
1348         ci->mdiFlags |= MDIF_NEEDUPDATE;
1349         ScrollChildren(hwnd, message, wParam, lParam);
1350         ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1351         retvalue = 0;
1352         goto END;
1353
1354       case WM_SETFOCUS:
1355         if( ci->hwndActiveChild )
1356         {
1357            WND* pw = WIN_FindWndPtr( ci->hwndActiveChild );
1358            if( !(pw->dwStyle & WS_MINIMIZE) )
1359                SetFocus( ci->hwndActiveChild );
1360            WIN_ReleaseWndPtr(pw);
1361         } 
1362         retvalue = 0;
1363         goto END;
1364         
1365       case WM_NCACTIVATE:
1366         if( ci->hwndActiveChild )
1367              SendMessageA(ci->hwndActiveChild, message, wParam, lParam);
1368         break;
1369         
1370       case WM_PARENTNOTIFY:
1371         if (LOWORD(wParam) == WM_LBUTTONDOWN)
1372         {
1373             HWND child;
1374             POINT pt;
1375             pt.x = SLOWORD(lParam);
1376             pt.y = SHIWORD(lParam);
1377             child = ChildWindowFromPoint(hwnd, pt);
1378
1379             TRACE("notification from %04x (%li,%li)\n",child,pt.x,pt.y);
1380
1381             if( child && child != hwnd && child != ci->hwndActiveChild )
1382                 SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1383         }
1384         retvalue = 0;
1385         goto END;
1386
1387       case WM_SIZE:
1388         if( IsWindow(ci->hwndChildMaximized) )
1389         {
1390             WND*        child = WIN_FindWndPtr(ci->hwndChildMaximized);
1391             RECT        rect;
1392
1393             rect.left = 0;
1394             rect.top = 0;
1395             rect.right = LOWORD(lParam);
1396             rect.bottom = HIWORD(lParam);
1397
1398             AdjustWindowRectEx(&rect, child->dwStyle, 0, child->dwExStyle);
1399             MoveWindow(ci->hwndChildMaximized, rect.left, rect.top,
1400                          rect.right - rect.left, rect.bottom - rect.top, 1);
1401             WIN_ReleaseWndPtr(child);
1402         }
1403         else
1404             MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1405
1406         break;
1407
1408       case WM_MDICALCCHILDSCROLL:
1409         if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1410         {
1411             CalcChildScroll16(hwnd, ci->sbRecalc-1);
1412             ci->sbRecalc = 0;
1413             ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1414         }
1415         retvalue = 0;
1416         goto END;
1417     }
1418     
1419     retvalue = DefWindowProcA( hwnd, message, wParam, lParam );
1420 END:
1421     WIN_ReleaseWndPtr(w);
1422     WIN_ReleaseWndPtr(frameWnd);
1423     return retvalue;
1424 }
1425
1426
1427 /***********************************************************************
1428  *           DefFrameProc16   (USER.445)
1429  */
1430 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1431                                UINT16 message, WPARAM16 wParam, LPARAM lParam )
1432 {
1433     HWND16               childHwnd;
1434     MDICLIENTINFO*       ci;
1435     WND*                 wndPtr;
1436
1437     if (hwndMDIClient)
1438     {
1439         switch (message)
1440         {
1441           case WM_COMMAND:
1442             wndPtr = WIN_FindWndPtr(hwndMDIClient);
1443
1444             if (!wndPtr) {
1445                ERR("null wndPtr for mdi window hwndMDIClient=%04x\n",
1446                              hwndMDIClient);
1447                return 0;
1448             } 
1449
1450             ci     = (MDICLIENTINFO*)wndPtr->wExtra;
1451
1452             /* check for possible syscommands for maximized MDI child */
1453             WIN_ReleaseWndPtr(wndPtr);
1454
1455             if( ci && (
1456                 wParam <  ci->idFirstChild || 
1457                 wParam >= ci->idFirstChild + ci->nActiveChildren
1458             )){
1459                 if( (wParam - 0xF000) & 0xF00F ) break;
1460                 switch( wParam )
1461                   {
1462                     case SC_SIZE:
1463                     case SC_MOVE:
1464                     case SC_MINIMIZE:
1465                     case SC_MAXIMIZE:
1466                     case SC_NEXTWINDOW:
1467                     case SC_PREVWINDOW:
1468                     case SC_CLOSE:
1469                     case SC_RESTORE:
1470                        if( ci->hwndChildMaximized )
1471                            return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1472                                                wParam, lParam);
1473                   }
1474               }
1475             else
1476               {
1477                 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1478                 ci     = (MDICLIENTINFO*)wndPtr->wExtra;
1479
1480                 if (wParam - ci->idFirstChild == MDI_MOREWINDOWSLIMIT)
1481                     /* User chose "More Windows..." */
1482                     childHwnd = MDI_MoreWindowsDialog(wndPtr);
1483                 else
1484                     /* User chose one of the windows listed in the "Windows" menu */
1485                 childHwnd = MDI_GetChildByID(wndPtr,wParam );
1486
1487                 WIN_ReleaseWndPtr(wndPtr);
1488                 if( childHwnd )
1489                     SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1490                                   (WPARAM16)childHwnd , 0L);
1491               }
1492             break;
1493
1494           case WM_NCACTIVATE:
1495             SendMessage16(hwndMDIClient, message, wParam, lParam);
1496             break;
1497
1498           case WM_SETTEXT:
1499             {
1500                 LPWSTR text = HEAP_strdupAtoW( GetProcessHeap(), 0, 
1501                                                (LPCSTR)PTR_SEG_TO_LIN(lParam) );
1502                 wndPtr = WIN_FindWndPtr(hwnd);
1503                 MDI_UpdateFrameText(wndPtr, hwndMDIClient,
1504                                     MDI_REPAINTFRAME, text );
1505                 WIN_ReleaseWndPtr(wndPtr);
1506                 HeapFree( GetProcessHeap(), 0, text );
1507             }
1508             return 0;
1509         
1510           case WM_SETFOCUS:
1511             SetFocus(hwndMDIClient);
1512             break;
1513
1514           case WM_SIZE:
1515             MoveWindow16(hwndMDIClient, 0, 0, 
1516                          LOWORD(lParam), HIWORD(lParam), TRUE);
1517             break;
1518
1519           case WM_NEXTMENU:
1520
1521             wndPtr = WIN_FindWndPtr(hwndMDIClient);
1522             ci     = (MDICLIENTINFO*)wndPtr->wExtra;
1523
1524             if( !(wndPtr->parent->dwStyle & WS_MINIMIZE) 
1525                 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1526             {
1527                 /* control menu is between the frame system menu and 
1528                  * the first entry of menu bar */
1529
1530                 if( (wParam == VK_LEFT &&
1531                      wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1532                     (wParam == VK_RIGHT &&
1533                      GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1534                 {
1535                     LRESULT retvalue;
1536                     WIN_ReleaseWndPtr(wndPtr);
1537                     wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1538                     retvalue = MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1539                                                   ci->hwndActiveChild);
1540                     WIN_ReleaseWndPtr(wndPtr);
1541                     return retvalue;
1542                 }
1543             }
1544             WIN_ReleaseWndPtr(wndPtr);
1545             break;
1546         }
1547     }
1548     
1549     return DefWindowProc16(hwnd, message, wParam, lParam);
1550 }
1551
1552
1553 /***********************************************************************
1554  *           DefFrameProcA   (USER32.122)
1555  */
1556 LRESULT WINAPI DefFrameProcA( HWND hwnd, HWND hwndMDIClient,
1557                                 UINT message, WPARAM wParam, LPARAM lParam)
1558 {
1559     if (hwndMDIClient)
1560     {
1561         switch (message)
1562         {
1563           case WM_COMMAND:
1564               return DefFrameProc16( hwnd, hwndMDIClient, message,
1565                                      (WPARAM16)wParam,
1566                               MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1567
1568           case WM_NCACTIVATE:
1569             SendMessageA(hwndMDIClient, message, wParam, lParam);
1570             break;
1571
1572           case WM_SETTEXT: {
1573                 LRESULT ret;
1574                 LPSTR   segstr = SEGPTR_STRDUP((LPSTR)lParam);
1575
1576                 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1577                                      wParam, (LPARAM)SEGPTR_GET(segstr) );
1578                 SEGPTR_FREE(segstr);
1579                 return ret;
1580           }
1581         
1582           case WM_NEXTMENU:
1583           case WM_SETFOCUS:
1584           case WM_SIZE:
1585               return DefFrameProc16( hwnd, hwndMDIClient, message,
1586                                      wParam, lParam );
1587         }
1588     }
1589     
1590     return DefWindowProcA(hwnd, message, wParam, lParam);
1591 }
1592
1593
1594 /***********************************************************************
1595  *           DefFrameProcW   (USER32.123)
1596  */
1597 LRESULT WINAPI DefFrameProcW( HWND hwnd, HWND hwndMDIClient,
1598                                 UINT message, WPARAM wParam, LPARAM lParam)
1599 {
1600     if (hwndMDIClient)
1601     {
1602         switch (message)
1603         {
1604           case WM_COMMAND:
1605               return DefFrameProc16( hwnd, hwndMDIClient, message,
1606                                      (WPARAM16)wParam,
1607                               MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1608
1609           case WM_NCACTIVATE:
1610             SendMessageW(hwndMDIClient, message, wParam, lParam);
1611             break;
1612
1613           case WM_SETTEXT: 
1614           {
1615               LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1616               LRESULT ret = DefFrameProcA( hwnd, hwndMDIClient, message,
1617                                      wParam, (DWORD)txt );
1618               HeapFree(GetProcessHeap(),0,txt);
1619               return ret;
1620           }
1621           case WM_NEXTMENU:
1622           case WM_SETFOCUS:
1623           case WM_SIZE:
1624               return DefFrameProcA( hwnd, hwndMDIClient, message,
1625                                       wParam, lParam );
1626         }
1627     }
1628     
1629     return DefWindowProcW( hwnd, message, wParam, lParam );
1630 }
1631
1632
1633 /***********************************************************************
1634  *           DefMDIChildProc16   (USER.447)
1635  */
1636 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1637                                   WPARAM16 wParam, LPARAM lParam )
1638 {
1639     MDICLIENTINFO       *ci;
1640     WND                 *clientWnd,*tmpWnd = 0;
1641     LRESULT             retvalue;
1642
1643     tmpWnd     = WIN_FindWndPtr(hwnd);
1644     if (!tmpWnd) return 0;
1645     clientWnd  = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1646     ci         = (MDICLIENTINFO *) clientWnd->wExtra;
1647     WIN_ReleaseWndPtr(tmpWnd);
1648
1649     /* Sanity check */
1650     if (clientWnd->class->cbWndExtra < sizeof(MDICLIENTINFO))
1651     {
1652         WARN("called on non-MDI child window %x\n", hwnd);
1653         WIN_ReleaseWndPtr(clientWnd);
1654         return DefWindowProc16(hwnd, message, wParam, lParam);
1655     }
1656
1657     switch (message)
1658     {
1659       case WM_SETTEXT:
1660         DefWindowProc16(hwnd, message, wParam, lParam);
1661         MDI_MenuModifyItem(clientWnd,hwnd);
1662         if( ci->hwndChildMaximized == hwnd )
1663             MDI_UpdateFrameText( clientWnd->parent, ci->self,
1664                                  MDI_REPAINTFRAME, NULL );
1665         retvalue = 0;
1666         goto END;
1667
1668       case WM_CLOSE:
1669         SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1670         retvalue = 0;
1671         goto END;
1672
1673       case WM_SETFOCUS:
1674         if( ci->hwndActiveChild != hwnd )
1675             MDI_ChildActivate(clientWnd, hwnd);
1676         break;
1677
1678       case WM_CHILDACTIVATE:
1679         MDI_ChildActivate(clientWnd, hwnd);
1680         retvalue = 0;
1681         goto END;
1682
1683       case WM_NCPAINT:
1684         TRACE("WM_NCPAINT for %04x, active %04x\n",
1685                                              hwnd, ci->hwndActiveChild );
1686         break;
1687
1688       case WM_SYSCOMMAND:
1689         switch( wParam )
1690         {
1691                 case SC_MOVE:
1692                      if( ci->hwndChildMaximized == hwnd)
1693                      {
1694                          retvalue = 0;
1695                          goto END;
1696                      }
1697                      break;
1698                 case SC_RESTORE:
1699                 case SC_MINIMIZE:
1700                      tmpWnd = WIN_FindWndPtr(hwnd);
1701                      tmpWnd->dwStyle |= WS_SYSMENU;
1702                      WIN_ReleaseWndPtr(tmpWnd);
1703                      break;
1704                 case SC_MAXIMIZE:
1705                      if( ci->hwndChildMaximized == hwnd) 
1706                      {
1707                           retvalue = SendMessage16( clientWnd->parent->hwndSelf,
1708                                              message, wParam, lParam);
1709                           goto END;
1710                      }
1711                      tmpWnd = WIN_FindWndPtr(hwnd);
1712                      tmpWnd->dwStyle &= ~WS_SYSMENU;
1713                      WIN_ReleaseWndPtr(tmpWnd);
1714                      break;
1715                 case SC_NEXTWINDOW:
1716                      SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1717                      retvalue = 0;
1718                      goto END;
1719                 case SC_PREVWINDOW:
1720                      SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1721                      retvalue = 0;
1722                      goto END;
1723         }
1724         break;
1725         
1726       case WM_GETMINMAXINFO:
1727         MDI_ChildGetMinMaxInfo(clientWnd, hwnd, (MINMAXINFO16*) PTR_SEG_TO_LIN(lParam));
1728         retvalue = 0;
1729         goto END;
1730
1731       case WM_SETVISIBLE:
1732          if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1733          else
1734             MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1735         break;
1736
1737       case WM_SIZE:
1738         /* do not change */
1739
1740         if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1741         {
1742             ci->hwndChildMaximized = 0;
1743             
1744             MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1745             MDI_UpdateFrameText( clientWnd->parent, ci->self,
1746                                  MDI_REPAINTFRAME, NULL );
1747         }
1748
1749         if( wParam == SIZE_MAXIMIZED )
1750         {
1751             HWND16 hMaxChild = ci->hwndChildMaximized;
1752
1753             if( hMaxChild == hwnd ) break;
1754
1755             if( hMaxChild)
1756             {       
1757                 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1758
1759                 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1760                 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1761
1762                 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1763             }
1764
1765             TRACE("maximizing child %04x\n", hwnd );
1766
1767             /*
1768              * Keep track of the maximized window.
1769              */
1770             ci->hwndChildMaximized = hwnd; /* !!! */
1771
1772             /*
1773              * The maximized window should also be the active window
1774              */
1775             MDI_ChildActivate(clientWnd, hwnd);
1776
1777             MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1778             MDI_UpdateFrameText( clientWnd->parent, ci->self,
1779                                  MDI_REPAINTFRAME, NULL ); 
1780         }
1781
1782         if( wParam == SIZE_MINIMIZED )
1783         {
1784             HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1785
1786             if( switchTo )
1787                 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1788         }
1789          
1790         MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1791         break;
1792
1793       case WM_MENUCHAR:
1794
1795         /* MDI children don't have menu bars */
1796         retvalue = 0x00010000L;
1797         goto END;
1798
1799       case WM_NEXTMENU:
1800
1801         if( wParam == VK_LEFT )         /* switch to frame system menu */
1802         {
1803             retvalue = MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1804                            clientWnd->parent->hwndSelf );
1805             goto END;
1806         }
1807         if( wParam == VK_RIGHT )        /* to frame menu bar */
1808         {
1809             retvalue = MAKELONG( clientWnd->parent->wIDmenu,
1810                            clientWnd->parent->hwndSelf );
1811             goto END;
1812         }
1813
1814         break;  
1815
1816       case WM_SYSCHAR:
1817            if (wParam == '-')
1818            {
1819                 SendMessage16(hwnd,WM_SYSCOMMAND,
1820                         (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1821                 retvalue = 0;
1822                 goto END;
1823            }
1824     }
1825         
1826     retvalue = DefWindowProc16(hwnd, message, wParam, lParam);
1827 END:
1828     WIN_ReleaseWndPtr(clientWnd);
1829     return retvalue;
1830 }
1831
1832
1833 /***********************************************************************
1834  *           DefMDIChildProcA   (USER32.124)
1835  */
1836 LRESULT WINAPI DefMDIChildProcA( HWND hwnd, UINT message,
1837                                    WPARAM wParam, LPARAM lParam )
1838 {
1839     MDICLIENTINFO       *ci;
1840     WND                 *clientWnd,*tmpWnd;
1841     LRESULT             retvalue;
1842
1843     tmpWnd     = WIN_FindWndPtr(hwnd);
1844     if (!tmpWnd) return 0;
1845     clientWnd  = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1846     ci         = (MDICLIENTINFO *) clientWnd->wExtra;
1847     WIN_ReleaseWndPtr(tmpWnd);
1848
1849     /* Sanity check */
1850     if (clientWnd->class->cbWndExtra < sizeof(MDICLIENTINFO))
1851     {
1852         WARN("called on non-MDI child window %x\n", hwnd);
1853         WIN_ReleaseWndPtr(clientWnd);
1854         return DefWindowProcA(hwnd, message, wParam, lParam);
1855     }
1856
1857     switch (message)
1858     {
1859       case WM_SETTEXT:
1860         DefWindowProcA(hwnd, message, wParam, lParam);
1861         MDI_MenuModifyItem(clientWnd,hwnd);
1862         if( ci->hwndChildMaximized == hwnd )
1863             MDI_UpdateFrameText( clientWnd->parent, ci->self,
1864                                  MDI_REPAINTFRAME, NULL );
1865         retvalue = 0;
1866         goto END;
1867
1868       case WM_GETMINMAXINFO:
1869         {
1870             MINMAXINFO16 mmi;
1871             STRUCT32_MINMAXINFO32to16( (MINMAXINFO *)lParam, &mmi );
1872             MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1873             STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO *)lParam );
1874         }
1875         retvalue = 0;
1876         goto END;
1877
1878       case WM_MENUCHAR:
1879
1880         /* MDI children don't have menu bars */
1881         retvalue = 0x00010000L;
1882         goto END;
1883
1884       case WM_CLOSE:
1885       case WM_SETFOCUS:
1886       case WM_CHILDACTIVATE:
1887       case WM_NCPAINT:
1888       case WM_SYSCOMMAND:
1889       case WM_SETVISIBLE:
1890       case WM_SIZE:
1891       case WM_NEXTMENU:
1892           retvalue = DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1893           goto END;
1894
1895       case WM_SYSCHAR:
1896            if (wParam == '-')
1897            {
1898                 SendMessageA(hwnd,WM_SYSCOMMAND,
1899                         (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1900                 retvalue = 0;
1901                 goto END;
1902            }
1903     }
1904     retvalue = DefWindowProcA(hwnd, message, wParam, lParam);
1905 END:
1906     WIN_ReleaseWndPtr(clientWnd);
1907     return retvalue;
1908 }
1909
1910
1911 /***********************************************************************
1912  *           DefMDIChildProcW   (USER32.125)
1913  */
1914 LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message,
1915                                    WPARAM wParam, LPARAM lParam )
1916 {
1917     MDICLIENTINFO       *ci;
1918     WND                 *clientWnd,*tmpWnd;
1919     LRESULT             retvalue;
1920
1921     tmpWnd     = WIN_FindWndPtr(hwnd);
1922     if (!tmpWnd) return 0;
1923     clientWnd  = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1924     ci         = (MDICLIENTINFO *) clientWnd->wExtra;
1925     WIN_ReleaseWndPtr(tmpWnd);
1926
1927     /* Sanity check */
1928     if (clientWnd->class->cbWndExtra < sizeof(MDICLIENTINFO))
1929     {
1930         WARN("called on non-MDI child window %x\n", hwnd);
1931         WIN_ReleaseWndPtr(clientWnd);
1932         return DefWindowProcW(hwnd, message, wParam, lParam);
1933     }
1934
1935     switch (message)
1936     {
1937       case WM_SETTEXT:
1938         DefWindowProcW(hwnd, message, wParam, lParam);
1939         MDI_MenuModifyItem(clientWnd,hwnd);
1940         if( ci->hwndChildMaximized == hwnd )
1941             MDI_UpdateFrameText( clientWnd->parent, ci->self,
1942                                  MDI_REPAINTFRAME, NULL );
1943         retvalue = 0;
1944         goto END;
1945
1946       case WM_GETMINMAXINFO:
1947       case WM_MENUCHAR:
1948       case WM_CLOSE:
1949       case WM_SETFOCUS:
1950       case WM_CHILDACTIVATE:
1951       case WM_NCPAINT:
1952       case WM_SYSCOMMAND:
1953       case WM_SETVISIBLE:
1954       case WM_SIZE:
1955       case WM_NEXTMENU:
1956           retvalue = DefMDIChildProcA( hwnd, message, (WPARAM16)wParam, lParam );
1957           goto END;
1958
1959       case WM_SYSCHAR:
1960            if (wParam == '-')
1961            {
1962                 SendMessageW(hwnd,WM_SYSCOMMAND,
1963                         (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1964                 retvalue = 0;
1965                 goto END;
1966            }
1967     }
1968     retvalue = DefWindowProcW(hwnd, message, wParam, lParam);
1969 END:
1970     WIN_ReleaseWndPtr(clientWnd);
1971     return retvalue;
1972     
1973 }
1974
1975
1976 /**********************************************************************
1977  * CreateMDIWindowA [USER32.79] Creates a MDI child in new thread
1978  * FIXME: its in the same thread now
1979  *
1980  * RETURNS
1981  *    Success: Handle to created window
1982  *    Failure: NULL
1983  */
1984 HWND WINAPI CreateMDIWindowA(
1985     LPCSTR lpClassName,    /* [in] Pointer to registered child class name */
1986     LPCSTR lpWindowName,   /* [in] Pointer to window name */
1987     DWORD dwStyle,         /* [in] Window style */
1988     INT X,               /* [in] Horizontal position of window */
1989     INT Y,               /* [in] Vertical position of window */
1990     INT nWidth,          /* [in] Width of window */
1991     INT nHeight,         /* [in] Height of window */
1992     HWND hWndParent,     /* [in] Handle to parent window */
1993     HINSTANCE hInstance, /* [in] Handle to application instance */
1994     LPARAM lParam)         /* [in] Application-defined value */
1995 {
1996     WARN("is only single threaded!\n");
1997     return MDI_CreateMDIWindowA(lpClassName, lpWindowName, dwStyle, X, Y, 
1998             nWidth, nHeight, hWndParent, hInstance, lParam);
1999 }
2000  
2001 /**********************************************************************
2002  * MDI_CreateMDIWindowA 
2003  * single threaded version of CreateMDIWindowA
2004  * called by CreateWindowExA
2005  */
2006 HWND MDI_CreateMDIWindowA(
2007     LPCSTR lpClassName,
2008     LPCSTR lpWindowName,
2009     DWORD dwStyle,
2010     INT X,
2011     INT Y,
2012     INT nWidth,
2013     INT nHeight,
2014     HWND hWndParent,
2015     HINSTANCE hInstance,
2016     LPARAM lParam)
2017 {
2018     MDICLIENTINFO* pCi;
2019     MDICREATESTRUCTA cs;
2020     WND *pWnd=WIN_FindWndPtr(hWndParent);
2021     HWND retvalue;
2022
2023     TRACE("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
2024           debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
2025           nWidth,nHeight,hWndParent,hInstance,lParam);
2026
2027     if(!pWnd){
2028         ERR(" bad hwnd for MDI-client: %d\n",hWndParent);
2029         return 0;
2030     }
2031     cs.szClass=lpClassName;
2032     cs.szTitle=lpWindowName;
2033     cs.hOwner=hInstance;
2034     cs.x=X;
2035     cs.y=Y;
2036     cs.cx=nWidth;
2037     cs.cy=nHeight;
2038     cs.style=dwStyle;
2039     cs.lParam=lParam;
2040
2041     pCi=(MDICLIENTINFO *)pWnd->wExtra;
2042     
2043     retvalue = MDICreateChild(pWnd,pCi,hWndParent,&cs);
2044     WIN_ReleaseWndPtr(pWnd);
2045     return retvalue;
2046 }
2047
2048 /***********************************************************************
2049  * CreateMDIWindowW [USER32.80] Creates a MDI child in new thread
2050  *
2051  * RETURNS
2052  *    Success: Handle to created window
2053  *    Failure: NULL
2054  */
2055 HWND WINAPI CreateMDIWindowW(
2056     LPCWSTR lpClassName,    /* [in] Pointer to registered child class name */
2057     LPCWSTR lpWindowName,   /* [in] Pointer to window name */
2058     DWORD dwStyle,         /* [in] Window style */
2059     INT X,               /* [in] Horizontal position of window */
2060     INT Y,               /* [in] Vertical position of window */
2061     INT nWidth,          /* [in] Width of window */
2062     INT nHeight,         /* [in] Height of window */
2063     HWND hWndParent,     /* [in] Handle to parent window */
2064     HINSTANCE hInstance, /* [in] Handle to application instance */
2065     LPARAM lParam)         /* [in] Application-defined value */
2066 {
2067     FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
2068           debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
2069           nWidth,nHeight,hWndParent,hInstance,lParam);
2070     return (HWND)NULL;
2071 }
2072
2073
2074 /******************************************************************************
2075  * CreateMDIWindowW [USER32.80]  Creates a MDI child window
2076  * single threaded version of CreateMDIWindow
2077  * called by CreateWindowExW(). 
2078  */
2079 HWND MDI_CreateMDIWindowW(
2080     LPCWSTR lpClassName,   /* [in] Pointer to registered child class name */
2081     LPCWSTR lpWindowName,  /* [in] Pointer to window name */
2082     DWORD dwStyle,         /* [in] Window style */
2083     INT X,               /* [in] Horizontal position of window */
2084     INT Y,               /* [in] Vertical position of window */
2085     INT nWidth,          /* [in] Width of window */
2086     INT nHeight,         /* [in] Height of window */
2087     HWND hWndParent,     /* [in] Handle to parent window */
2088     HINSTANCE hInstance, /* [in] Handle to application instance */
2089     LPARAM lParam)         /* [in] Application-defined value */
2090 {
2091     FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
2092           debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
2093           nWidth,nHeight,hWndParent,hInstance,lParam);
2094     return (HWND)NULL;
2095 }
2096
2097
2098 /**********************************************************************
2099  *             TranslateMDISysAccel   (USER32.555)
2100  */
2101 BOOL WINAPI TranslateMDISysAccel( HWND hwndClient, LPMSG msg )
2102 {
2103     MSG16 msg16;
2104  
2105     STRUCT32_MSG32to16(msg,&msg16);
2106     /* MDICLIENTINFO is still the same for win32 and win16 ... */
2107     return TranslateMDISysAccel16(hwndClient,&msg16);
2108 }
2109
2110
2111 /**********************************************************************
2112  *             TranslateMDISysAccel16   (USER.451)
2113  */
2114 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
2115 {
2116
2117     if( IsWindow(hwndClient) && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
2118     {
2119         MDICLIENTINFO   *ci = NULL;
2120         HWND            wnd;
2121         WND             *clientWnd = WIN_FindWndPtr(hwndClient);
2122
2123         ci = (MDICLIENTINFO*) clientWnd->wExtra;
2124         wnd = ci->hwndActiveChild;
2125
2126         WIN_ReleaseWndPtr(clientWnd);
2127
2128         if( IsWindow(wnd) && !(GetWindowLongA(wnd,GWL_STYLE) & WS_DISABLED) )
2129         {
2130             WPARAM16    wParam = 0;
2131
2132             /* translate if the Ctrl key is down and Alt not. */
2133   
2134             if( (GetKeyState(VK_CONTROL) & 0x8000) && 
2135                !(GetKeyState(VK_MENU) & 0x8000))
2136             {
2137                 switch( msg->wParam )
2138                 {
2139                     case VK_F6:
2140                     case VK_TAB:
2141                          wParam = ( GetKeyState(VK_SHIFT) & 0x8000 )
2142                                   ? SC_NEXTWINDOW : SC_PREVWINDOW;
2143                          break;
2144                     case VK_F4:
2145                     case VK_RBUTTON:
2146                          wParam = SC_CLOSE; 
2147                          break;
2148                     default:
2149                          return 0;
2150                 }
2151                 TRACE("wParam = %04x\n", wParam);
2152                 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND, 
2153                                         wParam, (LPARAM)msg->wParam);
2154                 return 1;
2155             }
2156         }
2157     }
2158     return 0; /* failure */
2159 }
2160
2161
2162 /***********************************************************************
2163  *           CalcChildScroll   (USER.462)
2164  */
2165 void WINAPI CalcChildScroll16( HWND16 hwnd, WORD scroll )
2166 {
2167     SCROLLINFO info;
2168     RECT childRect, clientRect;
2169     INT  vmin, vmax, hmin, hmax, vpos, hpos;
2170     WND *pWnd, *Wnd;
2171
2172     if (!(pWnd = WIN_FindWndPtr( hwnd ))) return;
2173     Wnd = WIN_FindWndPtr(hwnd);
2174     GetClientRect( hwnd, &clientRect );
2175     SetRectEmpty( &childRect );
2176
2177     for ( WIN_UpdateWndPtr(&pWnd,pWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2178     {
2179           if( pWnd->dwStyle & WS_MAXIMIZE )
2180           {
2181               ShowScrollBar(hwnd, SB_BOTH, FALSE);
2182               WIN_ReleaseWndPtr(pWnd);
2183               WIN_ReleaseWndPtr(Wnd);
2184               return;
2185           }
2186           UnionRect( &childRect, &pWnd->rectWindow, &childRect );
2187     } 
2188     WIN_ReleaseWndPtr(pWnd);
2189     UnionRect( &childRect, &clientRect, &childRect );
2190
2191     hmin = childRect.left; hmax = childRect.right - clientRect.right;
2192     hpos = clientRect.left - childRect.left;
2193     vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
2194     vpos = clientRect.top - childRect.top;
2195
2196     switch( scroll )
2197     {
2198         case SB_HORZ:
2199                         vpos = hpos; vmin = hmin; vmax = hmax;
2200         case SB_VERT:
2201                         info.cbSize = sizeof(info);
2202                         info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
2203                         info.fMask = SIF_POS | SIF_RANGE;
2204                         SetScrollInfo(hwnd, scroll, &info, TRUE);
2205                         break;
2206         case SB_BOTH:
2207                         SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
2208                                                   hmin, hmax, hpos);
2209     }    
2210     WIN_ReleaseWndPtr(Wnd);
2211 }
2212
2213
2214 /***********************************************************************
2215  *           ScrollChildren16   (USER.463)
2216  */
2217 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
2218 {
2219     ScrollChildren( hWnd, uMsg, wParam, lParam );
2220 }
2221
2222
2223 /***********************************************************************
2224  *           ScrollChildren   (USER32.448)
2225  */
2226 void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
2227                              LPARAM lParam)
2228 {
2229     WND *wndPtr = WIN_FindWndPtr(hWnd);
2230     INT newPos = -1;
2231     INT curPos, length, minPos, maxPos, shift;
2232
2233     if( !wndPtr ) return;
2234
2235     if( uMsg == WM_HSCROLL )
2236     {
2237         GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
2238         curPos = GetScrollPos(hWnd,SB_HORZ);
2239         length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
2240         shift = GetSystemMetrics(SM_CYHSCROLL);
2241     }
2242     else if( uMsg == WM_VSCROLL )
2243     {
2244         GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
2245         curPos = GetScrollPos(hWnd,SB_VERT);
2246         length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
2247         shift = GetSystemMetrics(SM_CXVSCROLL);
2248     }
2249     else
2250     {
2251         WIN_ReleaseWndPtr(wndPtr);
2252         return;
2253     }
2254
2255     WIN_ReleaseWndPtr(wndPtr);
2256     switch( wParam )
2257     {
2258         case SB_LINEUP: 
2259                         newPos = curPos - shift;
2260                         break;
2261         case SB_LINEDOWN:    
2262                         newPos = curPos + shift;
2263                         break;
2264         case SB_PAGEUP: 
2265                         newPos = curPos - length;
2266                         break;
2267         case SB_PAGEDOWN:    
2268                         newPos = curPos + length;
2269                         break;
2270
2271         case SB_THUMBPOSITION: 
2272                         newPos = LOWORD(lParam);
2273                         break;
2274
2275         case SB_THUMBTRACK:  
2276                         return;
2277
2278         case SB_TOP:            
2279                         newPos = minPos;
2280                         break;
2281         case SB_BOTTOM: 
2282                         newPos = maxPos;
2283                         break;
2284         case SB_ENDSCROLL:
2285                         CalcChildScroll16(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
2286                         return;
2287     }
2288
2289     if( newPos > maxPos )
2290         newPos = maxPos;
2291     else 
2292         if( newPos < minPos )
2293             newPos = minPos;
2294
2295     SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
2296
2297     if( uMsg == WM_VSCROLL )
2298         ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL, 
2299                         SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2300     else
2301         ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
2302                         SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2303 }
2304
2305
2306 /******************************************************************************
2307  * CascadeWindows [USER32.21] Cascades MDI child windows
2308  *
2309  * RETURNS
2310  *    Success: Number of cascaded windows.
2311  *    Failure: 0
2312  */
2313 WORD WINAPI
2314 CascadeWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2315                 UINT cKids, const HWND *lpKids)
2316 {
2317     FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2318            hwndParent, wFlags, cKids);
2319
2320     return 0;
2321 }
2322
2323
2324 /******************************************************************************
2325  * TileWindows [USER32.545] Tiles MDI child windows
2326  *
2327  * RETURNS
2328  *    Success: Number of tiled windows.
2329  *    Failure: 0
2330  */
2331 WORD WINAPI
2332 TileWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2333              UINT cKids, const HWND *lpKids)
2334 {
2335     FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2336            hwndParent, wFlags, cKids);
2337
2338     return 0;
2339 }
2340
2341 /************************************************************************
2342  *              "More Windows..." functionality
2343  */
2344
2345 /*              MDI_MoreWindowsDlgProc
2346  *
2347  *    This function will process the messages sent to the "More Windows..."
2348  *    dialog.
2349  *    Return values:  0    = cancel pressed
2350  *                    HWND = ok pressed or double-click in the list...
2351  *
2352  */
2353
2354 static BOOL WINAPI MDI_MoreWindowsDlgProc (HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
2355 {
2356     switch (iMsg)
2357     {
2358        case WM_INITDIALOG:
2359        {
2360            WND  *pWnd;
2361            UINT widest       = 0;
2362            UINT length;
2363            UINT i;
2364            WND  *pParentWnd  = (WND *)lParam;
2365            MDICLIENTINFO *ci = (MDICLIENTINFO*)pParentWnd->wExtra;
2366            HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2367
2368            /* Fill the list, sorted by id... */
2369            for (i = 0; i < ci->nActiveChildren; i++)
2370            {
2371
2372                /* Find the window with the current ID */
2373                for (pWnd = WIN_LockWndPtr(pParentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd, pWnd->next))
2374                    if (pWnd->wIDmenu == ci->idFirstChild + i)
2375                        break;
2376
2377                SendMessageW(hListBox, LB_ADDSTRING, 0, (LPARAM) pWnd->text);
2378                SendMessageA(hListBox, LB_SETITEMDATA, i, (LPARAM) pWnd);
2379                length = strlenW(pWnd->text);
2380                WIN_ReleaseWndPtr(pWnd);
2381
2382                if (length > widest)
2383                    widest = length;
2384            }
2385            /* Make sure the horizontal scrollbar scrolls ok */
2386            SendMessageA(hListBox, LB_SETHORIZONTALEXTENT, widest * 6, 0);
2387
2388            /* Set the current selection */
2389            SendMessageA(hListBox, LB_SETCURSEL, MDI_MOREWINDOWSLIMIT, 0);
2390            return TRUE;
2391        }
2392
2393        case WM_COMMAND:
2394            switch (LOWORD(wParam))
2395            {
2396                 case IDOK:
2397                 {
2398                     /*  windows are sorted by menu ID, so we must return the
2399                      *  window associated to the given id
2400                      */
2401                     HWND hListBox     = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2402                     UINT index        = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
2403                     WND* pWnd         = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
2404
2405                     EndDialog(hDlg, pWnd->hwndSelf);
2406                     return TRUE;
2407                 }
2408                 case IDCANCEL:
2409                     EndDialog(hDlg, 0);
2410                     return TRUE;
2411
2412                 default:
2413                     switch (HIWORD(wParam))
2414                     {
2415                         case LBN_DBLCLK:
2416                         {
2417                             /*  windows are sorted by menu ID, so we must return the
2418                              *  window associated to the given id
2419                              */
2420                             HWND hListBox     = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2421                             UINT index        = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
2422                             WND* pWnd         = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
2423
2424                             EndDialog(hDlg, pWnd->hwndSelf);
2425                             return TRUE;
2426                         }
2427                     }
2428                     break;
2429            }
2430            break;
2431     }
2432     return FALSE;
2433 }
2434
2435 /*
2436  *
2437  *                      MDI_MoreWindowsDialog
2438  *
2439  *     Prompts the user with a listbox containing the opened
2440  *     documents. The user can then choose a windows and click
2441  *     on OK to set the current window to the one selected, or
2442  *     CANCEL to cancel. The function returns a handle to the
2443  *     selected window.
2444  */
2445
2446 static HWND MDI_MoreWindowsDialog(WND* wndPtr)
2447 {
2448     LPCVOID template;
2449     HRSRC hRes;
2450     HANDLE hDlgTmpl;
2451
2452     hRes = FindResourceA(GetModuleHandleA("USER32"), "MDI_MOREWINDOWS", RT_DIALOGA);
2453
2454     if (hRes == 0)
2455         return 0;
2456
2457     hDlgTmpl = LoadResource(GetModuleHandleA("USER32"), hRes );
2458
2459     if (hDlgTmpl == 0)
2460         return 0;
2461
2462     template = LockResource( hDlgTmpl );
2463
2464     if (template == 0)
2465         return 0;
2466
2467     return (HWND) DialogBoxIndirectParamA(GetModuleHandleA("USER32"),
2468                                           (LPDLGTEMPLATEA) template,
2469                                           wndPtr->hwndSelf,
2470                                           (DLGPROC) MDI_MoreWindowsDlgProc,
2471                                           (LPARAM) wndPtr);
2472 }
2473
2474 /*
2475  *
2476  *                      MDI_SwapMenuItems
2477  *
2478  *      Will swap the menu IDs for the given 2 positions.
2479  *      pos1 and pos2 are menu IDs
2480  *     
2481  *    
2482  */
2483
2484 static void MDI_SwapMenuItems(WND *parentWnd, UINT pos1, UINT pos2)
2485 {
2486     WND *pWnd;
2487
2488     for (pWnd = WIN_LockWndPtr(parentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2489     {
2490         if (pWnd->wIDmenu == pos1)
2491             pWnd->wIDmenu = pos2;
2492         else
2493             if (pWnd->wIDmenu == pos2)
2494                 pWnd->wIDmenu = pos1;
2495     }
2496
2497     WIN_ReleaseWndPtr(pWnd);
2498 }
2499