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