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