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