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