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