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