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