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