Release 950727
[wine] / windows / mdi.c
1 /* MDI.C
2  *
3  * Copyright 1994, Bob Amstadt
4  *
5  * This file contains routines to support MDI features.
6  */
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <math.h>
10 #include "windows.h"
11 #include "win.h"
12 #include "nonclient.h"
13 #include "mdi.h"
14 #include "user.h"
15 #include "menu.h"
16 #include "sysmetrics.h"
17 #include "stddebug.h"
18 #include "debug.h"
19
20 /**********************************************************************
21  *                                      MDIRecreateMenuList
22  */
23 void MDIRecreateMenuList(MDICLIENTINFO *ci)
24 {
25     HLOCAL hinfo;
26     
27     char buffer[128];
28     int id, n, index;
29
30     dprintf_mdi(stddeb, "MDIRecreateMenuList: hWindowMenu %0x\n", 
31             ci->hWindowMenu);
32     
33     id = ci->idFirstChild; 
34     while (DeleteMenu(ci->hWindowMenu, id, MF_BYCOMMAND))
35         id++;
36
37     dprintf_mdi(stddeb, "MDIRecreateMenuList: id %04x, idFirstChild %04x\n", 
38             id, ci->idFirstChild);
39
40     if (!ci->flagMenuAltered)
41     {
42         ci->flagMenuAltered = TRUE;
43         AppendMenu(ci->hWindowMenu, MF_SEPARATOR, 0, NULL);
44     }
45     
46     id = ci->idFirstChild;
47     index = 1;
48     for (hinfo = ci->infoActiveChildren; hinfo != 0;)
49     {
50         MDICHILDINFO *chi = USER_HEAP_LIN_ADDR(hinfo);
51         
52         n = sprintf(buffer, "%d ", index++);
53         GetWindowText(chi->hwnd, buffer + n, sizeof(buffer) - n - 1);
54
55         dprintf_mdi(stddeb, "MDIRecreateMenuList: id %04x, '%s'\n",
56                 id, buffer);
57
58         AppendMenu(ci->hWindowMenu, MF_STRING, id++, buffer);
59         hinfo = chi->next;
60     }
61 }
62
63 /**********************************************************************
64  *                                      MDISetMenu
65  * FIXME: This is not complete.
66  */
67 HMENU MDISetMenu(HWND hwnd, BOOL fRefresh, HMENU hmenuFrame, HMENU hmenuWindow)
68 {
69     dprintf_mdi(stddeb, "WM_MDISETMENU: %04x %04x %04x %04x\n", hwnd, fRefresh, hmenuFrame, hmenuWindow);
70     if (!fRefresh) {
71         HWND hwndFrame = GetParent(hwnd);
72         HMENU oldFrameMenu = GetMenu(hwndFrame);
73         SetMenu(hwndFrame, hmenuFrame);
74         return oldFrameMenu;
75     }
76     return 0;
77 }
78
79 /**********************************************************************
80  *                                      MDIIconArrange
81  */
82 WORD MDIIconArrange(HWND parent)
83 {
84   return ArrangeIconicWindows(parent);          /* Any reason why the    */
85                                                 /* existing icon arrange */
86                                                 /* can't be used here?   */
87                                                 /* -DRP                  */
88 }
89
90 /**********************************************************************
91  *                                      MDICreateChild
92  */
93 HWND MDICreateChild(WND *w, MDICLIENTINFO *ci, HWND parent, LPARAM lParam )
94 {
95     MDICREATESTRUCT *cs = (MDICREATESTRUCT *)PTR_SEG_TO_LIN(lParam);
96     HWND hwnd;
97     int spacing;
98
99     /*
100      * Create child window
101      */
102     cs->style &= (WS_MINIMIZE | WS_MAXIMIZE | WS_HSCROLL | WS_VSCROLL);
103
104                                 /* The child windows should probably  */
105                                 /* stagger, shouldn't they? -DRP      */
106     spacing = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME);
107     cs->x = ci->nActiveChildren * spacing;  
108     cs->y = ci->nActiveChildren * spacing;
109
110     hwnd = CreateWindowEx(0, PTR_SEG_TO_LIN(cs->szClass),
111                           PTR_SEG_TO_LIN(cs->szTitle), 
112                           WS_CHILD | WS_BORDER | WS_CAPTION | WS_CLIPSIBLINGS |
113                           WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU |
114                           WS_THICKFRAME | WS_VISIBLE | cs->style,
115                           cs->x, cs->y, cs->cx, cs->cy, parent, (HMENU) 0,
116                           w->hInstance, lParam);
117
118     if (hwnd)
119     {
120         HANDLE h = USER_HEAP_ALLOC( sizeof(MDICHILDINFO) );
121         MDICHILDINFO *child_info = USER_HEAP_LIN_ADDR(h);
122         
123         if (!h)
124         {
125             DestroyWindow(hwnd);
126             return 0;
127         }
128
129         ci->nActiveChildren++;
130
131         child_info->next = ci->infoActiveChildren;
132         child_info->prev = 0;
133         child_info->hwnd = hwnd;
134
135         if (ci->infoActiveChildren) {
136             MDICHILDINFO *nextinfo = USER_HEAP_LIN_ADDR(ci->infoActiveChildren);
137             nextinfo->prev = h;
138         }
139
140         ci->infoActiveChildren = h;
141
142         SendMessage(parent, WM_CHILDACTIVATE, 0, 0);
143     }
144         
145     return hwnd;
146 }
147
148 /**********************************************************************
149  *                                      MDIDestroyChild
150  */
151 HWND MDIDestroyChild(WND *w_parent, MDICLIENTINFO *ci, HWND parent,
152                      HWND child, BOOL flagDestroy)
153 {
154     MDICHILDINFO  *chi;
155     HLOCAL hinfo;
156     
157     hinfo = ci->infoActiveChildren;
158     while (hinfo != 0) {
159         chi = (MDICHILDINFO *)USER_HEAP_LIN_ADDR(hinfo);
160         if (chi->hwnd == child) break;
161         hinfo = chi->next;
162     }
163     
164     if (hinfo != 0)
165     {
166         if (chi->prev)
167             ((MDICHILDINFO *)USER_HEAP_LIN_ADDR(chi->prev))->next = chi->next;
168         if (chi->next)
169             ((MDICHILDINFO *)USER_HEAP_LIN_ADDR(chi->next))->prev = chi->prev;
170         if (ci->infoActiveChildren == hinfo)
171             ci->infoActiveChildren = chi->next;
172
173         ci->nActiveChildren--;
174         
175         if (chi->hwnd == ci->hwndActiveChild)
176             SendMessage(parent, WM_CHILDACTIVATE, 0, 0);
177
178         USER_HEAP_FREE(hinfo);
179         
180         if (flagDestroy)
181             DestroyWindow(child);
182     }
183     
184     return 0;
185 }
186
187 /**********************************************************************
188  *                                      MDIBringChildToTop
189  */
190 void MDIBringChildToTop(HWND parent, WORD id, WORD by_id, BOOL send_to_bottom)
191 {
192     HLOCAL hinfo;
193     MDICHILDINFO  *chi;
194     MDICLIENTINFO *ci;
195     WND           *w;
196     int            i;
197
198     w  = WIN_FindWndPtr(parent);
199     ci = (MDICLIENTINFO *) w->wExtra;
200     
201     dprintf_mdi(stddeb, "MDIBringToTop: id %04x, by_id %d\n", id, by_id);
202
203     if (by_id)
204         id -= ci->idFirstChild;
205     if (!by_id || id < ci->nActiveChildren)
206     {
207         hinfo = ci->infoActiveChildren;
208
209         if (by_id)
210         {
211             for (i = 0; i < id; i++)
212                 hinfo = ((MDICHILDINFO *)USER_HEAP_LIN_ADDR(hinfo))->next;
213             chi = USER_HEAP_LIN_ADDR(hinfo);
214         }
215         else
216         {
217             while (hinfo != 0) {
218                 chi = (MDICHILDINFO *)USER_HEAP_LIN_ADDR(hinfo);
219                 if (chi->hwnd == id) break;
220                 hinfo = chi->next;
221             }
222         }
223
224         if (hinfo == 0)
225             return;
226
227         dprintf_mdi(stddeb, "MDIBringToTop: child %04x\n", chi->hwnd);
228         if (hinfo != ci->infoActiveChildren)
229         {
230             if (ci->flagChildMaximized)
231             {
232                 RECT rectOldRestore, rect;
233
234                 w = WIN_FindWndPtr(chi->hwnd);
235                 
236                 rectOldRestore = ci->rectRestore;
237                 GetWindowRect(chi->hwnd, &ci->rectRestore);
238
239                 rect.top    = (ci->rectMaximize.top -
240                                (w->rectClient.top - w->rectWindow.top));
241                 rect.bottom = (ci->rectMaximize.bottom + 
242                                (w->rectWindow.bottom - w->rectClient.bottom));
243                 rect.left   = (ci->rectMaximize.left - 
244                                (w->rectClient.left - w->rectWindow.left));
245                 rect.right  = (ci->rectMaximize.right +
246                                (w->rectWindow.right - w->rectClient.right));
247                 w->dwStyle |= WS_MAXIMIZE;
248                 SetWindowPos(chi->hwnd, HWND_TOP, rect.left, rect.top, 
249                              rect.right - rect.left + 1,
250                              rect.bottom - rect.top + 1, 0);
251                 SendMessage(chi->hwnd, WM_SIZE, SIZE_MAXIMIZED,
252                             MAKELONG(w->rectClient.right-w->rectClient.left,
253                                      w->rectClient.bottom-w->rectClient.top));
254
255                 w = WIN_FindWndPtr(ci->hwndActiveChild);
256                 w->dwStyle &= ~WS_MAXIMIZE;
257                 SetWindowPos(ci->hwndActiveChild, HWND_BOTTOM, 
258                              rectOldRestore.left, rectOldRestore.top, 
259                              rectOldRestore.right - rectOldRestore.left + 1, 
260                              rectOldRestore.bottom - rectOldRestore.top + 1,
261                              SWP_NOACTIVATE | 
262                              (send_to_bottom ? 0 : SWP_NOZORDER));
263             }
264             else
265             {
266                 SetWindowPos(chi->hwnd, HWND_TOP, 0, 0, 0, 0, 
267                              SWP_NOMOVE | SWP_NOSIZE );
268                 if (send_to_bottom)
269                 {
270                     SetWindowPos(ci->hwndActiveChild, HWND_BOTTOM, 0, 0, 0, 0, 
271                                  SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
272                 }
273             }
274                 
275             if (chi->next)
276                 ((MDICHILDINFO *)USER_HEAP_LIN_ADDR(chi->next))->prev = chi->prev;
277
278             if (chi->prev)
279                 ((MDICHILDINFO *)USER_HEAP_LIN_ADDR(chi->prev))->next = chi->next;
280             
281             chi->prev              = 0;
282             chi->next              = ci->infoActiveChildren;
283             ((MDICHILDINFO *)USER_HEAP_LIN_ADDR(chi->next))->prev = hinfo;
284             ci->infoActiveChildren = hinfo;
285
286             SendMessage(parent, WM_CHILDACTIVATE, 0, 0);
287         }
288         
289         dprintf_mdi(stddeb, "MDIBringToTop: pos %04x, hwnd %04x\n", 
290                 id, chi->hwnd);
291     }
292 }
293
294 /**********************************************************************
295  *                                      MDIMaximizeChild
296  */
297 LONG MDIMaximizeChild(HWND parent, HWND child, MDICLIENTINFO *ci)
298 {
299     WND *w = WIN_FindWndPtr(child);
300     RECT rect;
301     
302     MDIBringChildToTop(parent, child, FALSE, FALSE);
303     ci->rectRestore = w->rectWindow;
304
305     rect.top    = (ci->rectMaximize.top -
306                    (w->rectClient.top - w->rectWindow.top));
307     rect.bottom = (ci->rectMaximize.bottom + 
308                    (w->rectWindow.bottom - w->rectClient.bottom));
309     rect.left   = (ci->rectMaximize.left - 
310                    (w->rectClient.left - w->rectWindow.left));
311     rect.right  = (ci->rectMaximize.right +
312                    (w->rectWindow.right - w->rectClient.right));
313     w->dwStyle |= WS_MAXIMIZE;
314     SetWindowPos(child, 0, rect.left, rect.top, 
315                  rect.right - rect.left + 1, rect.bottom - rect.top + 1,
316                  SWP_NOACTIVATE | SWP_NOZORDER);
317     
318     ci->flagChildMaximized = TRUE;
319     
320     SendMessage(child, WM_SIZE, SIZE_MAXIMIZED,
321                 MAKELONG(w->rectClient.right-w->rectClient.left,
322                          w->rectClient.bottom-w->rectClient.top));
323     SendMessage(GetParent(parent), WM_NCPAINT, 0, 0);
324
325     return 0;
326 }
327
328 /**********************************************************************
329  *                                      MDIRestoreChild
330  */
331 LONG MDIRestoreChild(HWND parent, MDICLIENTINFO *ci)
332 {
333     HWND    child;
334
335     dprintf_mdi(stddeb,"restoring mdi child\n");
336
337     child = ci->hwndActiveChild;
338     ci->flagChildMaximized = FALSE;
339
340     ShowWindow(child, SW_RESTORE);              /* display the window */
341     MDIBringChildToTop(parent, child, FALSE, FALSE);
342     SendMessage(GetParent(parent), WM_NCPAINT, 0, 0);
343
344     return 0;
345 }
346
347 /**********************************************************************
348  *                                      MDIChildActivated
349  */
350 LONG MDIChildActivated(WND *w, MDICLIENTINFO *ci, HWND parent)
351 {
352     HLOCAL hinfo;
353     MDICHILDINFO *chi;
354     HWND          deact_hwnd;
355     HWND          act_hwnd;
356     LONG          lParam;
357
358     dprintf_mdi(stddeb, "MDIChildActivate: top %04x\n", w->hwndChild);
359
360     hinfo = ci->infoActiveChildren;
361     if (hinfo)
362     {
363         chi = (MDICHILDINFO *)USER_HEAP_LIN_ADDR(hinfo);
364         deact_hwnd = ci->hwndActiveChild;
365         act_hwnd   = chi->hwnd;
366         lParam     = ((LONG) deact_hwnd << 16) | act_hwnd;
367
368         dprintf_mdi(stddeb, "MDIChildActivate: deact %04x, act %04x\n",
369                deact_hwnd, act_hwnd);
370
371         ci->hwndActiveChild = act_hwnd;
372
373         if (deact_hwnd != act_hwnd)
374         {
375             MDIRecreateMenuList(ci);
376             SendMessage(deact_hwnd,  WM_NCACTIVATE, FALSE, 0);
377             SendMessage(deact_hwnd, WM_MDIACTIVATE, FALSE, lParam);
378         }
379         
380         SendMessage(act_hwnd,  WM_NCACTIVATE, TRUE, 0);
381         SendMessage(act_hwnd, WM_MDIACTIVATE, TRUE, lParam);
382     }
383
384     if (hinfo || ci->nActiveChildren == 0)
385     {
386         MDIRecreateMenuList(ci);
387         SendMessage(GetParent(parent), WM_NCPAINT, 0, 0);
388     }
389     
390     return 0;
391 }
392
393 /**********************************************************************
394  *                                      MDICascade
395  */
396 LONG MDICascade(HWND parent, MDICLIENTINFO *ci)
397 {
398     HLOCAL hinfo;
399     MDICHILDINFO *chi;
400     RECT          rect;
401     int           spacing, xsize, ysize;
402     int           x, y;
403
404     if (ci->flagChildMaximized)
405         MDIRestoreChild(parent, ci);
406
407     /* If there aren't any children, don't even bother.
408      */
409     if (ci->nActiveChildren == 0)
410         return 0;
411
412     GetClientRect(parent, &rect);
413     spacing = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME);
414     ysize   = rect.bottom - 8 * spacing;
415     xsize   = rect.right  - 8 * spacing;
416     
417     dprintf_mdi(stddeb, 
418             "MDICascade: Client wnd at (%d,%d) - (%d,%d), spacing %d\n", 
419             rect.left, rect.top, rect.right, rect.bottom, spacing);
420     dprintf_mdi(stddeb, "MDICascade: searching for last child\n");
421     hinfo = ci->infoActiveChildren;
422     while(1) {
423         chi = USER_HEAP_LIN_ADDR(hinfo);
424         if (chi->next == 0) break;
425         hinfo = chi->next;
426     }
427     
428     dprintf_mdi(stddeb, "MDICascade: last child is %04x\n", chi->hwnd);
429     x = 0;
430     y = 0;
431     while (hinfo != 0)
432     {
433         chi = USER_HEAP_LIN_ADDR(hinfo);
434         dprintf_mdi(stddeb, "MDICascade: move %04x to (%d,%d) size [%d,%d]\n", 
435                 chi->hwnd, x, y, xsize, ysize);
436         if (IsIconic(chi->hwnd)) continue;
437         SetWindowPos(chi->hwnd, 0, x, y, xsize, ysize, 
438                      SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
439
440         x += spacing;
441         y += spacing;
442         
443         hinfo = chi->prev;
444     }
445
446     return 0;
447 }
448
449 /**********************************************************************
450  *                                      MDITile
451  */
452 LONG MDITile(HWND parent, MDICLIENTINFO *ci)
453 {
454     HLOCAL hinfo;
455     MDICHILDINFO *chi;
456     RECT          rect;
457     int           xsize, ysize;
458     int           x, y;
459     int           rows, columns;
460     int           r, c;
461     int           i;
462
463     if (ci->flagChildMaximized)
464         MDIRestoreChild(parent, ci);
465
466     /* If there aren't any children, don't even bother.
467      */
468     if (ci->nActiveChildren == 0)
469         return 0;
470
471     GetClientRect(parent, &rect);
472     rows    = (int) sqrt((double) ci->nActiveChildren);
473     columns = ci->nActiveChildren / rows;
474     ysize   = rect.bottom / rows;
475     xsize   = rect.right  / columns;
476     
477     hinfo   = ci->infoActiveChildren;
478     x       = 0;
479     i       = 0;
480     for (c = 1; c <= columns; c++)
481     {
482         if (c == columns)
483         {
484             rows  = ci->nActiveChildren - i;
485             ysize = rect.bottom / rows;
486         }
487
488         y = 0;
489         for (r = 1; r <= rows; r++, i++)
490         {
491             chi = (MDICHILDINFO *)USER_HEAP_LIN_ADDR(hinfo);
492             SetWindowPos(chi->hwnd, 0, x, y, xsize, ysize, 
493                          SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
494
495             y += ysize;
496             hinfo = chi->next;
497         }
498
499         x += xsize;
500     }
501     
502
503     return 0;
504 }
505
506 /**********************************************************************
507  *                                      MDIHandleLButton
508  */
509 BOOL MDIHandleLButton(HWND hwndFrame, HWND hwndClient, 
510                       WORD wParam, LONG lParam)
511 {
512     MDICLIENTINFO *ci;
513     WND           *w;
514     RECT           rect;
515     WORD           x;
516
517     w  = WIN_FindWndPtr(hwndClient);
518     ci = (MDICLIENTINFO *) w->wExtra;
519
520     if (wParam == HTMENU && ci->flagChildMaximized)
521     {
522         x = LOWORD(lParam);
523         
524         NC_GetInsideRect(hwndFrame, &rect);
525         if (x < rect.left + SYSMETRICS_CXSIZE)
526         {
527             SendMessage(ci->hwndActiveChild, WM_SYSCOMMAND, 
528                         SC_CLOSE, lParam);
529             return TRUE;
530         }
531         else if (x >= rect.right - SYSMETRICS_CXSIZE)
532         {
533             SendMessage(ci->hwndActiveChild, WM_SYSCOMMAND, 
534                         SC_RESTORE, lParam);
535             return TRUE;
536         }
537     }
538
539     return FALSE;
540 }
541
542 /**********************************************************************
543  *                                      MDIPaintMaximized
544  */
545 LONG MDIPaintMaximized(HWND hwndFrame, HWND hwndClient, WORD message,
546                        WORD wParam, LONG lParam)
547 {
548     static HBITMAP hbitmapClose     = 0;
549     static HBITMAP hbitmapMaximized = 0;
550     
551     MDICLIENTINFO *ci;
552     WND           *w;
553     HDC           hdc, hdcMem;
554     RECT          rect;
555     WND           *wndPtr = WIN_FindWndPtr(hwndFrame);
556
557     w  = WIN_FindWndPtr(hwndClient);
558     ci = (MDICLIENTINFO *) w->wExtra;
559
560     dprintf_mdi(stddeb, "MDIPaintMaximized: frame %04x,  client %04x"
561                 ",  max flag %d,  menu %04x\n", hwndFrame, hwndClient, 
562                 ci->flagChildMaximized, wndPtr ? wndPtr->wIDmenu : 0);
563
564     if (ci->flagChildMaximized && wndPtr && wndPtr->wIDmenu != 0)
565     {
566         NC_DoNCPaint(hwndFrame, wParam, TRUE);
567
568         hdc = GetDCEx(hwndFrame, 0, DCX_CACHE | DCX_WINDOW);
569         if (!hdc) return 0;
570
571         hdcMem = CreateCompatibleDC(hdc);
572
573         if (hbitmapClose == 0)
574         {
575             hbitmapClose     = LoadBitmap(0, MAKEINTRESOURCE(OBM_OLD_CLOSE));
576             hbitmapMaximized = LoadBitmap(0, MAKEINTRESOURCE(OBM_RESTORE));
577         }
578
579         dprintf_mdi(stddeb, 
580                     "MDIPaintMaximized: hdcMem %04x, close bitmap %04x, "
581                     "maximized bitmap %04x\n",
582                     hdcMem, hbitmapClose, hbitmapMaximized);
583
584         NC_GetInsideRect(hwndFrame, &rect);
585         rect.top += (wndPtr->dwStyle & WS_CAPTION) ? SYSMETRICS_CYSIZE + 1 : 0;
586         SelectObject(hdcMem, hbitmapClose);
587         BitBlt(hdc, rect.left, rect.top + 1, 
588                SYSMETRICS_CXSIZE, SYSMETRICS_CYSIZE,
589                hdcMem, 1, 1, SRCCOPY);
590         
591         NC_GetInsideRect(hwndFrame, &rect);
592         rect.top += (wndPtr->dwStyle & WS_CAPTION) ? SYSMETRICS_CYSIZE + 1 : 0;
593         rect.left   = rect.right - SYSMETRICS_CXSIZE;
594         SelectObject(hdcMem, hbitmapMaximized);
595         BitBlt(hdc, rect.left, rect.top + 1, 
596                SYSMETRICS_CXSIZE, SYSMETRICS_CYSIZE,
597                hdcMem, 1, 1, SRCCOPY);
598         
599         NC_GetInsideRect(hwndFrame, &rect);
600         rect.top += (wndPtr->dwStyle & WS_CAPTION) ? SYSMETRICS_CYSIZE + 1 : 0;
601         rect.left += SYSMETRICS_CXSIZE;
602         rect.right -= SYSMETRICS_CXSIZE;
603         rect.bottom = rect.top + SYSMETRICS_CYMENU;
604
605         MENU_DrawMenuBar(hdc, &rect, hwndFrame, FALSE);
606         
607         DeleteDC(hdcMem);
608         ReleaseDC(hwndFrame, hdc);
609     }
610     else
611         return DefWindowProc(hwndFrame, message, wParam, lParam);
612
613     return 0;
614 }
615
616 /**********************************************************************
617  *                                      MDIClientWndProc
618  *
619  * This function is the handler for all MDI requests.
620  */
621 LONG MDIClientWndProc(HWND hwnd, WORD message, WORD wParam, LONG lParam)
622 {
623     LPCREATESTRUCT       cs;
624     LPCLIENTCREATESTRUCT ccs;
625     MDICLIENTINFO       *ci;
626     WND                 *w;
627
628     w  = WIN_FindWndPtr(hwnd);
629     ci = (MDICLIENTINFO *) w->wExtra;
630     
631     switch (message)
632     {
633       case WM_CHILDACTIVATE:
634         return MDIChildActivated(w, ci, hwnd);
635
636       case WM_CREATE:
637         cs                      = (LPCREATESTRUCT) PTR_SEG_TO_LIN(lParam);
638         ccs                     = (LPCLIENTCREATESTRUCT) PTR_SEG_TO_LIN(cs->lpCreateParams);
639         ci->hWindowMenu         = ccs->hWindowMenu;
640         ci->idFirstChild        = ccs->idFirstChild;
641         ci->infoActiveChildren  = 0;
642         ci->flagMenuAltered     = FALSE;
643         ci->flagChildMaximized  = FALSE;
644         w->dwStyle             |= WS_CLIPCHILDREN;
645
646         GetClientRect(w->hwndParent, &ci->rectMaximize);
647         MoveWindow(hwnd, 0, 0, 
648                    ci->rectMaximize.right, ci->rectMaximize.bottom, 1);
649
650         return 0;
651
652       case WM_MDIACTIVATE:
653         MDIBringChildToTop(hwnd, wParam, FALSE, FALSE);
654         return 0;
655
656       case WM_MDICASCADE:
657         return MDICascade(hwnd, ci);
658
659       case WM_MDICREATE:
660         return MDICreateChild(w, ci, hwnd, lParam );
661
662       case WM_MDIDESTROY:
663         return MDIDestroyChild(w, ci, hwnd, wParam, TRUE);
664
665       case WM_MDIGETACTIVE:
666         return ((LONG) ci->hwndActiveChild | 
667                 ((LONG) ci->flagChildMaximized << 16));
668
669       case WM_MDIICONARRANGE:
670         return MDIIconArrange(hwnd);
671         
672       case WM_MDIMAXIMIZE:
673         return MDIMaximizeChild(hwnd, wParam, ci);
674
675       case WM_MDINEXT:
676         MDIBringChildToTop(hwnd, wParam, FALSE, TRUE);
677         break;
678         
679       case WM_MDIRESTORE:
680         return MDIRestoreChild(hwnd, ci);
681
682       case WM_MDISETMENU:
683         return MDISetMenu(hwnd, wParam, LOWORD(lParam), HIWORD(lParam));
684         
685       case WM_MDITILE:
686         return MDITile(hwnd, ci);
687         
688       case WM_NCACTIVATE:
689         SendMessage(ci->hwndActiveChild, message, wParam, lParam);
690         break;
691         
692       case WM_PARENTNOTIFY:
693         if (wParam == WM_DESTROY)
694             return MDIDestroyChild(w, ci, hwnd, LOWORD(lParam), FALSE);
695         else if (wParam == WM_LBUTTONDOWN)
696             MDIBringChildToTop(hwnd, ci->hwndHitTest, FALSE, FALSE);
697         break;
698
699       case WM_SIZE:
700         GetClientRect(w->hwndParent, &ci->rectMaximize);
701         break;
702
703     }
704     
705     return DefWindowProc(hwnd, message, wParam, lParam);
706 }
707
708 /**********************************************************************
709  *                                      DefFrameProc (USER.445)
710  *
711  */
712 LONG DefFrameProc(HWND hwnd, HWND hwndMDIClient, WORD message, 
713                   WORD wParam, LONG lParam)
714 {
715     if (hwndMDIClient)
716     {
717         switch (message)
718         {
719           case WM_COMMAND:
720             MDIBringChildToTop(hwndMDIClient, wParam, TRUE, FALSE);
721             break;
722
723           case WM_NCLBUTTONDOWN:
724             if (MDIHandleLButton(hwnd, hwndMDIClient, wParam, lParam))
725                 return 0;
726             break;
727             
728           case WM_NCACTIVATE:
729             SendMessage(hwndMDIClient, message, wParam, lParam);
730             return MDIPaintMaximized(hwnd, hwndMDIClient, 
731                                      message, wParam, lParam);
732
733           case WM_NCPAINT:
734             return MDIPaintMaximized(hwnd, hwndMDIClient, 
735                                      message, wParam, lParam);
736         
737           case WM_SETFOCUS:
738             SendMessage(hwndMDIClient, WM_SETFOCUS, wParam, lParam);
739             break;
740
741           case WM_SIZE:
742             MoveWindow(hwndMDIClient, 0, 0, 
743                        LOWORD(lParam), HIWORD(lParam), TRUE);
744             break;
745         }
746     }
747     
748     return DefWindowProc(hwnd, message, wParam, lParam);
749 }
750
751 /**********************************************************************
752  *                                      DefMDIChildProc (USER.447)
753  *
754  */
755 LONG DefMDIChildProc(HWND hwnd, WORD message, WORD wParam, LONG lParam)
756 {
757     MDICLIENTINFO       *ci;
758     WND                 *w;
759
760     w  = WIN_FindWndPtr(GetParent(hwnd));
761     ci = (MDICLIENTINFO *) w->wExtra;
762     
763     switch (message)
764     {
765       case WM_NCHITTEST:
766         ci->hwndHitTest = hwnd;
767         break;
768         
769       case WM_NCPAINT:
770         NC_DoNCPaint( hwnd, hwnd == ci->hwndActiveChild, FALSE );
771         return 0;
772
773       case WM_SYSCOMMAND:
774         switch (wParam)
775         {
776           case SC_MAXIMIZE:
777             return SendMessage(GetParent(hwnd), WM_MDIMAXIMIZE, hwnd, 0);
778
779           case SC_RESTORE:
780             return SendMessage(GetParent(hwnd), WM_MDIRESTORE, hwnd, 0);
781         }
782         break;
783         
784     }
785         
786     return DefWindowProc(hwnd, message, wParam, lParam);
787 }
788
789 /**********************************************************************
790  *                                      TranslateMDISysAccel (USER.451)
791  *
792  */
793 BOOL TranslateMDISysAccel(HWND hwndClient, LPMSG msg)
794 {
795     return 0;
796 }
797
798
799 /***********************************************************************
800  *           CalcChildScroll   (USER.462)
801  */
802 void CalcChildScroll( HWND hwnd, WORD scroll )
803 {
804     RECT childRect, clientRect;
805     HWND hwndChild;
806
807     GetClientRect( hwnd, &clientRect );
808     SetRectEmpty( &childRect );
809     hwndChild = GetWindow( hwnd, GW_CHILD );
810     while (hwndChild)
811     {
812         WND *wndPtr = WIN_FindWndPtr( hwndChild );
813         UnionRect( &childRect, &wndPtr->rectWindow, &childRect );
814         hwndChild = wndPtr->hwndNext;
815     }
816     UnionRect( &childRect, &clientRect, &childRect );
817
818     if ((scroll == SB_HORZ) || (scroll == SB_BOTH))
819     {
820         SetScrollRange( hwnd, SB_HORZ, childRect.left,
821                         childRect.right - clientRect.right, FALSE );
822         SetScrollPos( hwnd, SB_HORZ, clientRect.left - childRect.left, TRUE );
823     }
824     if ((scroll == SB_VERT) || (scroll == SB_BOTH))
825     {
826         SetScrollRange( hwnd, SB_VERT, childRect.top,
827                         childRect.bottom - clientRect.bottom, FALSE );
828         SetScrollPos( hwnd, SB_HORZ, clientRect.top - childRect.top, TRUE );
829     }
830 }