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