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