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