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