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