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