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