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