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