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