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