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