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