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