3 * Copyright 1994, Bob Amstadt
5 * This file contains routines to support MDI features.
14 #include "sysmetrics.h"
16 #define DEBUG_MDI /* */
18 extern WORD
MENU_DrawMenuBar( HDC hDC
, LPRECT lprect
,
19 HMENU hmenu
, BOOL suppress_draw
); /* menu.c */
21 /**********************************************************************
25 MDIRecreateMenuList(MDICLIENTINFO
*ci
)
32 fprintf(stderr
, "MDIRecreateMenuList: hWindowMenu %04.4x\n",
36 id
= ci
->idFirstChild
;
37 while (DeleteMenu(ci
->hWindowMenu
, id
, MF_BYCOMMAND
))
41 fprintf(stderr
, "MDIRecreateMenuList: id %04.4x, idFirstChild %04.4x\n",
42 id
, ci
->idFirstChild
);
45 if (!ci
->flagMenuAltered
)
47 ci
->flagMenuAltered
= TRUE
;
48 AppendMenu(ci
->hWindowMenu
, MF_SEPARATOR
, 0, NULL
);
51 id
= ci
->idFirstChild
;
53 for (chi
= ci
->infoActiveChildren
; chi
!= NULL
; chi
= chi
->next
)
55 n
= sprintf(buffer
, "%d ", index
++);
56 GetWindowText(chi
->hwnd
, buffer
+ n
, sizeof(buffer
) - n
- 1);
59 fprintf(stderr
, "MDIRecreateMenuList: id %04.4x, '%s'\n",
63 AppendMenu(ci
->hWindowMenu
, MF_STRING
, id
++, buffer
);
67 /**********************************************************************
71 MDICreateChild(WND
*w
, MDICLIENTINFO
*ci
, HWND parent
, LPMDICREATESTRUCT cs
)
78 cs
->style
&= (WS_MINIMIZE
| WS_MAXIMIZE
| WS_HSCROLL
| WS_VSCROLL
);
80 hwnd
= CreateWindowEx(0, cs
->szClass
, cs
->szTitle
,
81 WS_CHILD
| WS_BORDER
| WS_CAPTION
| WS_CLIPSIBLINGS
|
82 WS_MAXIMIZEBOX
| WS_MINIMIZEBOX
| WS_SYSMENU
|
83 WS_THICKFRAME
| WS_VISIBLE
| cs
->style
,
84 cs
->x
, cs
->y
, cs
->cx
, cs
->cy
, parent
, (HMENU
) 0,
85 w
->hInstance
, (LPSTR
) cs
);
89 HANDLE h
= USER_HEAP_ALLOC(GMEM_MOVEABLE
, sizeof(MDICHILDINFO
));
90 MDICHILDINFO
*child_info
= USER_HEAP_ADDR(h
);
97 ci
->nActiveChildren
++;
99 child_info
->next
= ci
->infoActiveChildren
;
100 child_info
->prev
= NULL
;
101 child_info
->hwnd
= hwnd
;
103 if (ci
->infoActiveChildren
)
104 ci
->infoActiveChildren
->prev
= child_info
;
106 ci
->infoActiveChildren
= child_info
;
108 SendMessage(parent
, WM_CHILDACTIVATE
, 0, 0);
114 /**********************************************************************
118 MDIDestroyChild(WND
*w_parent
, MDICLIENTINFO
*ci
, HWND parent
, HWND child
,
123 chi
= ci
->infoActiveChildren
;
124 while (chi
&& chi
->hwnd
!= child
)
130 chi
->prev
->next
= chi
->next
;
132 chi
->next
->prev
= chi
->prev
;
133 if (ci
->infoActiveChildren
== chi
)
134 ci
->infoActiveChildren
= chi
->next
;
136 ci
->nActiveChildren
--;
138 if (chi
->hwnd
== ci
->hwndActiveChild
)
139 SendMessage(parent
, WM_CHILDACTIVATE
, 0, 0);
141 USER_HEAP_FREE((HANDLE
) (LONG
) chi
);
144 DestroyWindow(child
);
150 /**********************************************************************
153 void MDIBringChildToTop(HWND parent
, WORD id
, WORD by_id
, BOOL send_to_bottom
)
160 w
= WIN_FindWndPtr(parent
);
161 ci
= (MDICLIENTINFO
*) w
->wExtra
;
164 fprintf(stderr
, "MDIBringToTop: id %04.4x, by_id %d\n", id
, by_id
);
168 id
-= ci
->idFirstChild
;
169 if (!by_id
|| id
< ci
->nActiveChildren
)
171 chi
= ci
->infoActiveChildren
;
175 for (i
= 0; i
< id
; i
++)
180 while (chi
&& chi
->hwnd
!= id
)
188 fprintf(stderr
, "MDIBringToTop: child %04.4x\n", chi
->hwnd
);
190 if (chi
!= ci
->infoActiveChildren
)
192 if (ci
->flagChildMaximized
)
194 RECT rectOldRestore
, rect
;
196 w
= WIN_FindWndPtr(chi
->hwnd
);
198 rectOldRestore
= ci
->rectRestore
;
199 GetWindowRect(chi
->hwnd
, &ci
->rectRestore
);
201 rect
.top
= (ci
->rectMaximize
.top
-
202 (w
->rectClient
.top
- w
->rectWindow
.top
));
203 rect
.bottom
= (ci
->rectMaximize
.bottom
+
204 (w
->rectWindow
.bottom
- w
->rectClient
.bottom
));
205 rect
.left
= (ci
->rectMaximize
.left
-
206 (w
->rectClient
.left
- w
->rectWindow
.left
));
207 rect
.right
= (ci
->rectMaximize
.right
+
208 (w
->rectWindow
.right
- w
->rectClient
.right
));
209 w
->dwStyle
|= WS_MAXIMIZE
;
210 SetWindowPos(chi
->hwnd
, HWND_TOP
, rect
.left
, rect
.top
,
211 rect
.right
- rect
.left
+ 1,
212 rect
.bottom
- rect
.top
+ 1, 0);
213 SendMessage(chi
->hwnd
, WM_SIZE
, SIZE_MAXIMIZED
,
214 MAKELONG(w
->rectClient
.right
-w
->rectClient
.left
,
215 w
->rectClient
.bottom
-w
->rectClient
.top
));
217 w
= WIN_FindWndPtr(ci
->hwndActiveChild
);
218 w
->dwStyle
&= ~WS_MAXIMIZE
;
219 SetWindowPos(ci
->hwndActiveChild
, HWND_BOTTOM
,
220 rectOldRestore
.left
, rectOldRestore
.top
,
221 rectOldRestore
.right
- rectOldRestore
.left
+ 1,
222 rectOldRestore
.bottom
- rectOldRestore
.top
+ 1,
224 (send_to_bottom
? 0 : SWP_NOZORDER
));
228 SetWindowPos(chi
->hwnd
, HWND_TOP
, 0, 0, 0, 0,
229 SWP_NOMOVE
| SWP_NOSIZE
);
232 SetWindowPos(ci
->hwndActiveChild
, HWND_BOTTOM
, 0, 0, 0, 0,
233 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
238 chi
->next
->prev
= chi
->prev
;
241 chi
->prev
->next
= chi
->next
;
244 chi
->next
= ci
->infoActiveChildren
;
245 chi
->next
->prev
= chi
;
246 ci
->infoActiveChildren
= chi
;
248 SendMessage(parent
, WM_CHILDACTIVATE
, 0, 0);
252 fprintf(stderr
, "MDIBringToTop: pos %04.4x, hwnd %04.4x\n",
258 /**********************************************************************
261 LONG
MDIMaximizeChild(HWND parent
, HWND child
, MDICLIENTINFO
*ci
)
263 WND
*w
= WIN_FindWndPtr(child
);
266 MDIBringChildToTop(parent
, child
, FALSE
, FALSE
);
267 ci
->rectRestore
= w
->rectWindow
;
269 rect
.top
= (ci
->rectMaximize
.top
-
270 (w
->rectClient
.top
- w
->rectWindow
.top
));
271 rect
.bottom
= (ci
->rectMaximize
.bottom
+
272 (w
->rectWindow
.bottom
- w
->rectClient
.bottom
));
273 rect
.left
= (ci
->rectMaximize
.left
-
274 (w
->rectClient
.left
- w
->rectWindow
.left
));
275 rect
.right
= (ci
->rectMaximize
.right
+
276 (w
->rectWindow
.right
- w
->rectClient
.right
));
277 w
->dwStyle
|= WS_MAXIMIZE
;
278 SetWindowPos(child
, 0, rect
.left
, rect
.top
,
279 rect
.right
- rect
.left
+ 1, rect
.bottom
- rect
.top
+ 1,
280 SWP_NOACTIVATE
| SWP_NOZORDER
);
282 ci
->flagChildMaximized
= TRUE
;
284 SendMessage(child
, WM_SIZE
, SIZE_MAXIMIZED
,
285 MAKELONG(w
->rectClient
.right
-w
->rectClient
.left
,
286 w
->rectClient
.bottom
-w
->rectClient
.top
));
287 SendMessage(GetParent(parent
), WM_NCPAINT
, 1, 0);
292 /**********************************************************************
295 LONG
MDIRestoreChild(HWND parent
, MDICLIENTINFO
*ci
)
298 WND
*w
= WIN_FindWndPtr(child
);
299 LPRECT lprect
= &ci
->rectRestore
;
301 printf("restoring mdi child\n");
303 child
= ci
->hwndActiveChild
;
305 w
->dwStyle
&= ~WS_MAXIMIZE
;
306 SetWindowPos(child
, 0, lprect
->left
, lprect
->top
,
307 lprect
->right
- lprect
->left
+ 1,
308 lprect
->bottom
- lprect
->top
+ 1,
309 SWP_NOACTIVATE
| SWP_NOZORDER
);
311 ci
->flagChildMaximized
= FALSE
;
313 SendMessage(GetParent(parent
), WM_NCPAINT
, 1, 0);
314 MDIBringChildToTop(parent
, child
, FALSE
, FALSE
);
319 /**********************************************************************
322 LONG
MDIChildActivated(WND
*w
, MDICLIENTINFO
*ci
, HWND parent
)
330 fprintf(stderr
, "MDIChildActivate: top %04.4x\n", w
->hwndChild
);
333 chi
= ci
->infoActiveChildren
;
336 deact_hwnd
= ci
->hwndActiveChild
;
337 act_hwnd
= chi
->hwnd
;
338 lParam
= ((LONG
) deact_hwnd
<< 16) | act_hwnd
;
341 fprintf(stderr
, "MDIChildActivate: deact %04.4x, act %04.4x\n",
342 deact_hwnd
, act_hwnd
);
345 ci
->hwndActiveChild
= act_hwnd
;
347 if (deact_hwnd
!= act_hwnd
)
349 MDIRecreateMenuList(ci
);
350 SendMessage(deact_hwnd
, WM_NCACTIVATE
, FALSE
, 0);
351 SendMessage(deact_hwnd
, WM_MDIACTIVATE
, FALSE
, lParam
);
354 SendMessage(act_hwnd
, WM_NCACTIVATE
, TRUE
, 0);
355 SendMessage(act_hwnd
, WM_MDIACTIVATE
, TRUE
, lParam
);
358 if (chi
|| ci
->nActiveChildren
== 0)
360 MDIRecreateMenuList(ci
);
361 SendMessage(GetParent(parent
), WM_NCPAINT
, 0, 0);
367 /**********************************************************************
370 LONG
MDICascade(HWND parent
, MDICLIENTINFO
*ci
)
374 int spacing
, xsize
, ysize
;
377 if (ci
->flagChildMaximized
)
378 MDIRestoreChild(parent
, ci
);
380 GetClientRect(parent
, &rect
);
381 spacing
= GetSystemMetrics(SM_CYCAPTION
) + GetSystemMetrics(SM_CYFRAME
);
382 ysize
= rect
.bottom
- 8 * spacing
;
383 xsize
= rect
.right
- 8 * spacing
;
387 "MDICascade: Client wnd at (%d,%d) - (%d,%d), spacing %d\n",
388 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
, spacing
);
389 fprintf(stderr
, "MDICascade: searching for last child\n");
391 for (chi
= ci
->infoActiveChildren
; chi
->next
!= NULL
; chi
= chi
->next
)
395 fprintf(stderr
, "MDICascade: last child is %04.4x\n", chi
->hwnd
);
399 for ( ; chi
!= NULL
; chi
= chi
->prev
)
402 fprintf(stderr
, "MDICascade: move %04.4x to (%d,%d) size [%d,%d]\n",
403 chi
->hwnd
, x
, y
, xsize
, ysize
);
405 SetWindowPos(chi
->hwnd
, 0, x
, y
, xsize
, ysize
,
406 SWP_DRAWFRAME
| SWP_NOACTIVATE
| SWP_NOZORDER
);
415 /**********************************************************************
418 LONG
MDITile(HWND parent
, MDICLIENTINFO
*ci
)
428 if (ci
->flagChildMaximized
)
429 MDIRestoreChild(parent
, ci
);
431 GetClientRect(parent
, &rect
);
432 rows
= (int) sqrt((double) ci
->nActiveChildren
);
433 columns
= ci
->nActiveChildren
/ rows
;
434 ysize
= rect
.bottom
/ rows
;
435 xsize
= rect
.right
/ columns
;
437 chi
= ci
->infoActiveChildren
;
440 for (c
= 1; c
<= columns
; c
++)
444 rows
= ci
->nActiveChildren
- i
;
445 ysize
= rect
.bottom
/ rows
;
449 for (r
= 1; r
<= rows
; r
++, i
++, chi
= chi
->next
)
451 SetWindowPos(chi
->hwnd
, 0, x
, y
, xsize
, ysize
,
452 SWP_DRAWFRAME
| SWP_NOACTIVATE
| SWP_NOZORDER
);
464 /**********************************************************************
467 BOOL
MDIHandleLButton(HWND hwndFrame
, HWND hwndClient
,
468 WORD wParam
, LONG lParam
)
475 w
= WIN_FindWndPtr(hwndClient
);
476 ci
= (MDICLIENTINFO
*) w
->wExtra
;
478 if (wParam
== HTMENU
&& ci
->flagChildMaximized
)
482 NC_GetInsideRect(hwndFrame
, &rect
);
483 if (x
< rect
.left
+ SYSMETRICS_CXSIZE
)
485 SendMessage(ci
->hwndActiveChild
, WM_SYSCOMMAND
,
489 else if (x
>= rect
.right
- SYSMETRICS_CXSIZE
)
491 SendMessage(ci
->hwndActiveChild
, WM_SYSCOMMAND
,
500 /**********************************************************************
503 LONG
MDIPaintMaximized(HWND hwndFrame
, HWND hwndClient
, WORD message
,
504 WORD wParam
, LONG lParam
)
506 static HBITMAP hbitmapClose
= 0;
507 static HBITMAP hbitmapMaximized
= 0;
514 WND
*wndPtr
= WIN_FindWndPtr(hwndFrame
);
516 w
= WIN_FindWndPtr(hwndClient
);
517 ci
= (MDICLIENTINFO
*) w
->wExtra
;
521 "MDIPaintMaximized: frame %04x, client %04x"
522 ", max flag %d, menu %04x\n",
523 hwndFrame
, hwndClient
,
524 ci
->flagChildMaximized
, wndPtr
? wndPtr
->wIDmenu
: 0);
527 if (ci
->flagChildMaximized
&& wndPtr
&& wndPtr
->wIDmenu
!= 0)
529 rv
= NC_DoNCPaint( hwndFrame
, (HRGN
) 1, wParam
, TRUE
);
531 hdc
= GetDCEx(hwndFrame
, 0, DCX_CACHE
| DCX_WINDOW
);
535 hdcMem
= CreateCompatibleDC(hdc
);
537 if (hbitmapClose
== 0)
539 hbitmapClose
= LoadBitmap(0, MAKEINTRESOURCE(OBM_OLD_CLOSE
));
540 hbitmapMaximized
= LoadBitmap(0, MAKEINTRESOURCE(OBM_RESTORE
));
545 "MDIPaintMaximized: hdcMem %04x, close bitmap %04x, "
546 "maximized bitmap %04x\n",
547 hdcMem
, hbitmapClose
, hbitmapMaximized
);
550 NC_GetInsideRect(hwndFrame
, &rect
);
551 rect
.top
+= ((wndPtr
->dwStyle
& WS_CAPTION
) ?
552 SYSMETRICS_CYSIZE
+ 1 : 0);
553 SelectObject(hdcMem
, hbitmapClose
);
554 BitBlt(hdc
, rect
.left
, rect
.top
+ 1,
555 SYSMETRICS_CXSIZE
, SYSMETRICS_CYSIZE
,
556 hdcMem
, 1, 1, SRCCOPY
);
558 NC_GetInsideRect(hwndFrame
, &rect
);
559 rect
.top
+= ((wndPtr
->dwStyle
& WS_CAPTION
) ?
560 SYSMETRICS_CYSIZE
+ 1 : 0);
561 rect
.left
= rect
.right
- SYSMETRICS_CXSIZE
;
562 SelectObject(hdcMem
, hbitmapMaximized
);
563 BitBlt(hdc
, rect
.left
, rect
.top
+ 1,
564 SYSMETRICS_CXSIZE
, SYSMETRICS_CYSIZE
,
565 hdcMem
, 1, 1, SRCCOPY
);
567 NC_GetInsideRect(hwndFrame
, &rect
);
568 rect
.top
+= ((wndPtr
->dwStyle
& WS_CAPTION
) ?
569 SYSMETRICS_CYSIZE
+ 1 : 0);
570 rect
.left
+= SYSMETRICS_CXSIZE
;
571 rect
.right
-= SYSMETRICS_CXSIZE
;
572 rect
.bottom
= rect
.top
+ SYSMETRICS_CYMENU
;
574 MENU_DrawMenuBar(hdc
, &rect
, wndPtr
->wIDmenu
, FALSE
);
577 ReleaseDC(hwndFrame
, hdc
);
580 DefWindowProc(hwndFrame
, message
, wParam
, lParam
);
585 /**********************************************************************
588 * This function is the handler for all MDI requests.
591 MDIClientWndProc(HWND hwnd
, WORD message
, WORD wParam
, LONG lParam
)
594 LPCLIENTCREATESTRUCT ccs
;
598 w
= WIN_FindWndPtr(hwnd
);
599 ci
= (MDICLIENTINFO
*) w
->wExtra
;
603 case WM_CHILDACTIVATE
:
604 return MDIChildActivated(w
, ci
, hwnd
);
607 cs
= (LPCREATESTRUCT
) lParam
;
608 ccs
= (LPCLIENTCREATESTRUCT
) cs
->lpCreateParams
;
609 ci
->hWindowMenu
= ccs
->hWindowMenu
;
610 ci
->idFirstChild
= ccs
->idFirstChild
;
611 ci
->infoActiveChildren
= NULL
;
612 ci
->flagMenuAltered
= FALSE
;
613 ci
->flagChildMaximized
= FALSE
;
614 w
->dwStyle
|= WS_CLIPCHILDREN
;
616 GetClientRect(w
->hwndParent
, &ci
->rectMaximize
);
617 MoveWindow(hwnd
, 0, 0,
618 ci
->rectMaximize
.right
, ci
->rectMaximize
.bottom
, 1);
623 MDIBringChildToTop(hwnd
, wParam
, FALSE
, FALSE
);
627 return MDICascade(hwnd
, ci
);
630 return MDICreateChild(w
, ci
, hwnd
, (LPMDICREATESTRUCT
) lParam
);
633 return MDIDestroyChild(w
, ci
, hwnd
, wParam
, TRUE
);
635 case WM_MDIGETACTIVE
:
636 return ((LONG
) ci
->hwndActiveChild
|
637 ((LONG
) ci
->flagChildMaximized
<< 16));
639 case WM_MDIICONARRANGE
:
640 /* return MDIIconArrange(...) */
644 return MDIMaximizeChild(hwnd
, wParam
, ci
);
647 MDIBringChildToTop(hwnd
, wParam
, FALSE
, TRUE
);
651 return MDIRestoreChild(hwnd
, ci
);
654 /* return MDISetMenu(...) */
658 return MDITile(hwnd
, ci
);
661 SendMessage(ci
->hwndActiveChild
, message
, wParam
, lParam
);
664 case WM_PARENTNOTIFY
:
665 if (wParam
== WM_DESTROY
)
666 return MDIDestroyChild(w
, ci
, hwnd
, LOWORD(lParam
), FALSE
);
667 else if (wParam
== WM_LBUTTONDOWN
)
668 MDIBringChildToTop(hwnd
, ci
->hwndHitTest
, FALSE
, FALSE
);
672 GetClientRect(w
->hwndParent
, &ci
->rectMaximize
);
677 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
680 /**********************************************************************
681 * DefFrameProc (USER.445)
685 DefFrameProc(HWND hwnd
, HWND hwndMDIClient
, WORD message
,
686 WORD wParam
, LONG lParam
)
693 MDIBringChildToTop(hwndMDIClient
, wParam
, TRUE
, FALSE
);
696 case WM_NCLBUTTONDOWN
:
697 if (MDIHandleLButton(hwnd
, hwndMDIClient
, wParam
, lParam
))
702 SendMessage(hwndMDIClient
, message
, wParam
, lParam
);
703 return MDIPaintMaximized(hwnd
, hwndMDIClient
,
704 message
, wParam
, lParam
);
707 return MDIPaintMaximized(hwnd
, hwndMDIClient
,
708 message
, wParam
, lParam
);
711 SendMessage(hwndMDIClient
, WM_SETFOCUS
, wParam
, lParam
);
715 MoveWindow(hwndMDIClient
, 0, 0,
716 LOWORD(lParam
), HIWORD(lParam
), TRUE
);
721 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
724 /**********************************************************************
725 * DefMDIChildProc (USER.447)
729 DefMDIChildProc(HWND hwnd
, WORD message
, WORD wParam
, LONG lParam
)
734 w
= WIN_FindWndPtr(GetParent(hwnd
));
735 ci
= (MDICLIENTINFO
*) w
->wExtra
;
740 ci
->hwndHitTest
= hwnd
;
744 return NC_DoNCPaint(hwnd
, (HRGN
)1,
745 hwnd
== ci
->hwndActiveChild
);
751 return SendMessage(GetParent(hwnd
), WM_MDIMAXIMIZE
, hwnd
, 0);
755 ICON_Deiconify(hwnd
);
756 return SendMessage(GetParent(hwnd
), WM_MDIRESTORE
, hwnd
, 0);
762 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
765 /**********************************************************************
766 * TranslateMDISysAccel (USER.451)
769 BOOL
TranslateMDISysAccel(HWND hwndClient
, LPMSG msg
)