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