3 * Copyright 1994, Bob Amstadt
5 * This file contains routines to support MDI features.
15 #include "sysmetrics.h"
17 /* #define DEBUG_MDI */
20 /**********************************************************************
24 MDIRecreateMenuList(MDICLIENTINFO
*ci
)
30 dprintf_mdi(stddeb
, "MDIRecreateMenuList: hWindowMenu %0x\n",
33 id
= ci
->idFirstChild
;
34 while (DeleteMenu(ci
->hWindowMenu
, id
, MF_BYCOMMAND
))
37 dprintf_mdi(stddeb
, "MDIRecreateMenuList: id %04x, idFirstChild %04x\n",
38 id
, ci
->idFirstChild
);
40 if (!ci
->flagMenuAltered
)
42 ci
->flagMenuAltered
= TRUE
;
43 AppendMenu(ci
->hWindowMenu
, MF_SEPARATOR
, 0, NULL
);
46 id
= ci
->idFirstChild
;
48 for (chi
= ci
->infoActiveChildren
; chi
!= NULL
; chi
= chi
->next
)
50 n
= sprintf(buffer
, "%d ", index
++);
51 GetWindowText(chi
->hwnd
, buffer
+ n
, sizeof(buffer
) - n
- 1);
53 dprintf_mdi(stddeb
, "MDIRecreateMenuList: id %04x, '%s'\n",
56 AppendMenu(ci
->hWindowMenu
, MF_STRING
, id
++, buffer
);
60 /**********************************************************************
64 MDICreateChild(WND
*w
, MDICLIENTINFO
*ci
, HWND parent
, LPMDICREATESTRUCT cs
)
71 cs
->style
&= (WS_MINIMIZE
| WS_MAXIMIZE
| WS_HSCROLL
| WS_VSCROLL
);
73 hwnd
= CreateWindowEx(0, cs
->szClass
, cs
->szTitle
,
74 WS_CHILD
| WS_BORDER
| WS_CAPTION
| WS_CLIPSIBLINGS
|
75 WS_MAXIMIZEBOX
| WS_MINIMIZEBOX
| WS_SYSMENU
|
76 WS_THICKFRAME
| WS_VISIBLE
| cs
->style
,
77 cs
->x
, cs
->y
, cs
->cx
, cs
->cy
, parent
, (HMENU
) 0,
78 w
->hInstance
, (LPSTR
) cs
);
82 HANDLE h
= USER_HEAP_ALLOC(GMEM_MOVEABLE
, sizeof(MDICHILDINFO
));
83 MDICHILDINFO
*child_info
= USER_HEAP_ADDR(h
);
90 ci
->nActiveChildren
++;
92 child_info
->next
= ci
->infoActiveChildren
;
93 child_info
->prev
= NULL
;
94 child_info
->hwnd
= hwnd
;
96 if (ci
->infoActiveChildren
)
97 ci
->infoActiveChildren
->prev
= child_info
;
99 ci
->infoActiveChildren
= child_info
;
101 SendMessage(parent
, WM_CHILDACTIVATE
, 0, 0);
107 /**********************************************************************
111 MDIDestroyChild(WND
*w_parent
, MDICLIENTINFO
*ci
, HWND parent
, HWND child
,
116 chi
= ci
->infoActiveChildren
;
117 while (chi
&& chi
->hwnd
!= child
)
123 chi
->prev
->next
= chi
->next
;
125 chi
->next
->prev
= chi
->prev
;
126 if (ci
->infoActiveChildren
== chi
)
127 ci
->infoActiveChildren
= chi
->next
;
129 ci
->nActiveChildren
--;
131 if (chi
->hwnd
== ci
->hwndActiveChild
)
132 SendMessage(parent
, WM_CHILDACTIVATE
, 0, 0);
134 USER_HEAP_FREE((HANDLE
) (LONG
) chi
);
137 DestroyWindow(child
);
143 /**********************************************************************
146 void MDIBringChildToTop(HWND parent
, WORD id
, WORD by_id
, BOOL send_to_bottom
)
153 w
= WIN_FindWndPtr(parent
);
154 ci
= (MDICLIENTINFO
*) w
->wExtra
;
156 dprintf_mdi(stddeb
, "MDIBringToTop: id %04x, by_id %d\n", id
, by_id
);
159 id
-= ci
->idFirstChild
;
160 if (!by_id
|| id
< ci
->nActiveChildren
)
162 chi
= ci
->infoActiveChildren
;
166 for (i
= 0; i
< id
; i
++)
171 while (chi
&& chi
->hwnd
!= id
)
178 dprintf_mdi(stddeb
, "MDIBringToTop: child %04x\n", chi
->hwnd
);
179 if (chi
!= ci
->infoActiveChildren
)
181 if (ci
->flagChildMaximized
)
183 RECT rectOldRestore
, rect
;
185 w
= WIN_FindWndPtr(chi
->hwnd
);
187 rectOldRestore
= ci
->rectRestore
;
188 GetWindowRect(chi
->hwnd
, &ci
->rectRestore
);
190 rect
.top
= (ci
->rectMaximize
.top
-
191 (w
->rectClient
.top
- w
->rectWindow
.top
));
192 rect
.bottom
= (ci
->rectMaximize
.bottom
+
193 (w
->rectWindow
.bottom
- w
->rectClient
.bottom
));
194 rect
.left
= (ci
->rectMaximize
.left
-
195 (w
->rectClient
.left
- w
->rectWindow
.left
));
196 rect
.right
= (ci
->rectMaximize
.right
+
197 (w
->rectWindow
.right
- w
->rectClient
.right
));
198 w
->dwStyle
|= WS_MAXIMIZE
;
199 SetWindowPos(chi
->hwnd
, HWND_TOP
, rect
.left
, rect
.top
,
200 rect
.right
- rect
.left
+ 1,
201 rect
.bottom
- rect
.top
+ 1, 0);
202 SendMessage(chi
->hwnd
, WM_SIZE
, SIZE_MAXIMIZED
,
203 MAKELONG(w
->rectClient
.right
-w
->rectClient
.left
,
204 w
->rectClient
.bottom
-w
->rectClient
.top
));
206 w
= WIN_FindWndPtr(ci
->hwndActiveChild
);
207 w
->dwStyle
&= ~WS_MAXIMIZE
;
208 SetWindowPos(ci
->hwndActiveChild
, HWND_BOTTOM
,
209 rectOldRestore
.left
, rectOldRestore
.top
,
210 rectOldRestore
.right
- rectOldRestore
.left
+ 1,
211 rectOldRestore
.bottom
- rectOldRestore
.top
+ 1,
213 (send_to_bottom
? 0 : SWP_NOZORDER
));
217 SetWindowPos(chi
->hwnd
, HWND_TOP
, 0, 0, 0, 0,
218 SWP_NOMOVE
| SWP_NOSIZE
);
221 SetWindowPos(ci
->hwndActiveChild
, HWND_BOTTOM
, 0, 0, 0, 0,
222 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
227 chi
->next
->prev
= chi
->prev
;
230 chi
->prev
->next
= chi
->next
;
233 chi
->next
= ci
->infoActiveChildren
;
234 chi
->next
->prev
= chi
;
235 ci
->infoActiveChildren
= chi
;
237 SendMessage(parent
, WM_CHILDACTIVATE
, 0, 0);
240 dprintf_mdi(stddeb
, "MDIBringToTop: pos %04x, hwnd %04x\n",
245 /**********************************************************************
248 LONG
MDIMaximizeChild(HWND parent
, HWND child
, MDICLIENTINFO
*ci
)
250 WND
*w
= WIN_FindWndPtr(child
);
253 MDIBringChildToTop(parent
, child
, FALSE
, FALSE
);
254 ci
->rectRestore
= w
->rectWindow
;
256 rect
.top
= (ci
->rectMaximize
.top
-
257 (w
->rectClient
.top
- w
->rectWindow
.top
));
258 rect
.bottom
= (ci
->rectMaximize
.bottom
+
259 (w
->rectWindow
.bottom
- w
->rectClient
.bottom
));
260 rect
.left
= (ci
->rectMaximize
.left
-
261 (w
->rectClient
.left
- w
->rectWindow
.left
));
262 rect
.right
= (ci
->rectMaximize
.right
+
263 (w
->rectWindow
.right
- w
->rectClient
.right
));
264 w
->dwStyle
|= WS_MAXIMIZE
;
265 SetWindowPos(child
, 0, rect
.left
, rect
.top
,
266 rect
.right
- rect
.left
+ 1, rect
.bottom
- rect
.top
+ 1,
267 SWP_NOACTIVATE
| SWP_NOZORDER
);
269 ci
->flagChildMaximized
= TRUE
;
271 SendMessage(child
, WM_SIZE
, SIZE_MAXIMIZED
,
272 MAKELONG(w
->rectClient
.right
-w
->rectClient
.left
,
273 w
->rectClient
.bottom
-w
->rectClient
.top
));
274 SendMessage(GetParent(parent
), WM_NCPAINT
, 1, 0);
279 /**********************************************************************
282 LONG
MDIRestoreChild(HWND parent
, MDICLIENTINFO
*ci
)
285 WND
*w
= WIN_FindWndPtr(parent
);
286 LPRECT lprect
= &ci
->rectRestore
;
288 dprintf_mdi(stddeb
,"restoring mdi child\n");
290 child
= ci
->hwndActiveChild
;
292 w
->dwStyle
&= ~WS_MAXIMIZE
;
293 SetWindowPos(child
, 0, lprect
->left
, lprect
->top
,
294 lprect
->right
- lprect
->left
+ 1,
295 lprect
->bottom
- lprect
->top
+ 1,
296 SWP_NOACTIVATE
| SWP_NOZORDER
);
298 ci
->flagChildMaximized
= FALSE
;
300 ShowWindow(child
, SW_RESTORE
); /* display the window */
301 SendMessage(GetParent(parent
), WM_NCPAINT
, 1, 0);
302 MDIBringChildToTop(parent
, child
, FALSE
, FALSE
);
307 /**********************************************************************
310 LONG
MDIChildActivated(WND
*w
, MDICLIENTINFO
*ci
, HWND parent
)
317 dprintf_mdi(stddeb
, "MDIChildActivate: top %04x\n", w
->hwndChild
);
319 chi
= ci
->infoActiveChildren
;
322 deact_hwnd
= ci
->hwndActiveChild
;
323 act_hwnd
= chi
->hwnd
;
324 lParam
= ((LONG
) deact_hwnd
<< 16) | act_hwnd
;
326 dprintf_mdi(stddeb
, "MDIChildActivate: deact %04x, act %04x\n",
327 deact_hwnd
, act_hwnd
);
329 ci
->hwndActiveChild
= act_hwnd
;
331 if (deact_hwnd
!= act_hwnd
)
333 MDIRecreateMenuList(ci
);
334 SendMessage(deact_hwnd
, WM_NCACTIVATE
, FALSE
, 0);
335 SendMessage(deact_hwnd
, WM_MDIACTIVATE
, FALSE
, lParam
);
338 SendMessage(act_hwnd
, WM_NCACTIVATE
, TRUE
, 0);
339 SendMessage(act_hwnd
, WM_MDIACTIVATE
, TRUE
, lParam
);
342 if (chi
|| ci
->nActiveChildren
== 0)
344 MDIRecreateMenuList(ci
);
345 SendMessage(GetParent(parent
), WM_NCPAINT
, 0, 0);
351 /**********************************************************************
354 LONG
MDICascade(HWND parent
, MDICLIENTINFO
*ci
)
358 int spacing
, xsize
, ysize
;
361 if (ci
->flagChildMaximized
)
362 MDIRestoreChild(parent
, ci
);
364 GetClientRect(parent
, &rect
);
365 spacing
= GetSystemMetrics(SM_CYCAPTION
) + GetSystemMetrics(SM_CYFRAME
);
366 ysize
= rect
.bottom
- 8 * spacing
;
367 xsize
= rect
.right
- 8 * spacing
;
370 "MDICascade: Client wnd at (%d,%d) - (%d,%d), spacing %d\n",
371 rect
.left
, rect
.top
, rect
.right
, rect
.bottom
, spacing
);
372 dprintf_mdi(stddeb
, "MDICascade: searching for last child\n");
373 for (chi
= ci
->infoActiveChildren
; chi
->next
!= NULL
; chi
= chi
->next
)
376 dprintf_mdi(stddeb
, "MDICascade: last child is %04x\n", chi
->hwnd
);
379 for ( ; chi
!= NULL
; chi
= chi
->prev
)
381 dprintf_mdi(stddeb
, "MDICascade: move %04x to (%d,%d) size [%d,%d]\n",
382 chi
->hwnd
, x
, y
, xsize
, ysize
);
383 SetWindowPos(chi
->hwnd
, 0, x
, y
, xsize
, ysize
,
384 SWP_DRAWFRAME
| SWP_NOACTIVATE
| SWP_NOZORDER
);
393 /**********************************************************************
396 LONG
MDITile(HWND parent
, MDICLIENTINFO
*ci
)
406 if (ci
->flagChildMaximized
)
407 MDIRestoreChild(parent
, ci
);
409 GetClientRect(parent
, &rect
);
410 rows
= (int) sqrt((double) ci
->nActiveChildren
);
411 columns
= ci
->nActiveChildren
/ rows
;
412 ysize
= rect
.bottom
/ rows
;
413 xsize
= rect
.right
/ columns
;
415 chi
= ci
->infoActiveChildren
;
418 for (c
= 1; c
<= columns
; c
++)
422 rows
= ci
->nActiveChildren
- i
;
423 ysize
= rect
.bottom
/ rows
;
427 for (r
= 1; r
<= rows
; r
++, i
++, chi
= chi
->next
)
429 SetWindowPos(chi
->hwnd
, 0, x
, y
, xsize
, ysize
,
430 SWP_DRAWFRAME
| SWP_NOACTIVATE
| SWP_NOZORDER
);
442 /**********************************************************************
445 BOOL
MDIHandleLButton(HWND hwndFrame
, HWND hwndClient
,
446 WORD wParam
, LONG lParam
)
453 w
= WIN_FindWndPtr(hwndClient
);
454 ci
= (MDICLIENTINFO
*) w
->wExtra
;
456 if (wParam
== HTMENU
&& ci
->flagChildMaximized
)
460 NC_GetInsideRect(hwndFrame
, &rect
);
461 if (x
< rect
.left
+ SYSMETRICS_CXSIZE
)
463 SendMessage(ci
->hwndActiveChild
, WM_SYSCOMMAND
,
467 else if (x
>= rect
.right
- SYSMETRICS_CXSIZE
)
469 SendMessage(ci
->hwndActiveChild
, WM_SYSCOMMAND
,
478 /**********************************************************************
481 LONG
MDIPaintMaximized(HWND hwndFrame
, HWND hwndClient
, WORD message
,
482 WORD wParam
, LONG lParam
)
484 static HBITMAP hbitmapClose
= 0;
485 static HBITMAP hbitmapMaximized
= 0;
492 WND
*wndPtr
= WIN_FindWndPtr(hwndFrame
);
494 w
= WIN_FindWndPtr(hwndClient
);
495 ci
= (MDICLIENTINFO
*) w
->wExtra
;
498 "MDIPaintMaximized: frame %04x, client %04x"
499 ", max flag %d, menu %04x\n",
500 hwndFrame
, hwndClient
,
501 ci
->flagChildMaximized
, wndPtr
? wndPtr
->wIDmenu
: 0);
503 if (ci
->flagChildMaximized
&& wndPtr
&& wndPtr
->wIDmenu
!= 0)
505 rv
= NC_DoNCPaint( hwndFrame
, (HRGN
) 1, wParam
, TRUE
);
507 hdc
= GetDCEx(hwndFrame
, 0, DCX_CACHE
| DCX_WINDOW
);
511 hdcMem
= CreateCompatibleDC(hdc
);
513 if (hbitmapClose
== 0)
515 hbitmapClose
= LoadBitmap(0, MAKEINTRESOURCE(OBM_OLD_CLOSE
));
516 hbitmapMaximized
= LoadBitmap(0, MAKEINTRESOURCE(OBM_RESTORE
));
520 "MDIPaintMaximized: hdcMem %04x, close bitmap %04x, "
521 "maximized bitmap %04x\n",
522 hdcMem
, hbitmapClose
, hbitmapMaximized
);
524 NC_GetInsideRect(hwndFrame
, &rect
);
525 rect
.top
+= ((wndPtr
->dwStyle
& WS_CAPTION
) ?
526 SYSMETRICS_CYSIZE
+ 1 : 0);
527 SelectObject(hdcMem
, hbitmapClose
);
528 BitBlt(hdc
, rect
.left
, rect
.top
+ 1,
529 SYSMETRICS_CXSIZE
, SYSMETRICS_CYSIZE
,
530 hdcMem
, 1, 1, SRCCOPY
);
532 NC_GetInsideRect(hwndFrame
, &rect
);
533 rect
.top
+= ((wndPtr
->dwStyle
& WS_CAPTION
) ?
534 SYSMETRICS_CYSIZE
+ 1 : 0);
535 rect
.left
= rect
.right
- SYSMETRICS_CXSIZE
;
536 SelectObject(hdcMem
, hbitmapMaximized
);
537 BitBlt(hdc
, rect
.left
, rect
.top
+ 1,
538 SYSMETRICS_CXSIZE
, SYSMETRICS_CYSIZE
,
539 hdcMem
, 1, 1, SRCCOPY
);
541 NC_GetInsideRect(hwndFrame
, &rect
);
542 rect
.top
+= ((wndPtr
->dwStyle
& WS_CAPTION
) ?
543 SYSMETRICS_CYSIZE
+ 1 : 0);
544 rect
.left
+= SYSMETRICS_CXSIZE
;
545 rect
.right
-= SYSMETRICS_CXSIZE
;
546 rect
.bottom
= rect
.top
+ SYSMETRICS_CYMENU
;
548 MENU_DrawMenuBar(hdc
, &rect
, hwndFrame
, FALSE
);
551 ReleaseDC(hwndFrame
, hdc
);
554 DefWindowProc(hwndFrame
, message
, wParam
, lParam
);
559 /**********************************************************************
562 * This function is the handler for all MDI requests.
565 MDIClientWndProc(HWND hwnd
, WORD message
, WORD wParam
, LONG lParam
)
568 LPCLIENTCREATESTRUCT ccs
;
572 w
= WIN_FindWndPtr(hwnd
);
573 ci
= (MDICLIENTINFO
*) w
->wExtra
;
577 case WM_CHILDACTIVATE
:
578 return MDIChildActivated(w
, ci
, hwnd
);
581 cs
= (LPCREATESTRUCT
) lParam
;
582 ccs
= (LPCLIENTCREATESTRUCT
) cs
->lpCreateParams
;
583 ci
->hWindowMenu
= ccs
->hWindowMenu
;
584 ci
->idFirstChild
= ccs
->idFirstChild
;
585 ci
->infoActiveChildren
= NULL
;
586 ci
->flagMenuAltered
= FALSE
;
587 ci
->flagChildMaximized
= FALSE
;
588 w
->dwStyle
|= WS_CLIPCHILDREN
;
590 GetClientRect(w
->hwndParent
, &ci
->rectMaximize
);
591 MoveWindow(hwnd
, 0, 0,
592 ci
->rectMaximize
.right
, ci
->rectMaximize
.bottom
, 1);
597 MDIBringChildToTop(hwnd
, wParam
, FALSE
, FALSE
);
601 return MDICascade(hwnd
, ci
);
604 return MDICreateChild(w
, ci
, hwnd
, (LPMDICREATESTRUCT
) lParam
);
607 return MDIDestroyChild(w
, ci
, hwnd
, wParam
, TRUE
);
609 case WM_MDIGETACTIVE
:
610 return ((LONG
) ci
->hwndActiveChild
|
611 ((LONG
) ci
->flagChildMaximized
<< 16));
613 case WM_MDIICONARRANGE
:
614 /* return MDIIconArrange(...) */
618 return MDIMaximizeChild(hwnd
, wParam
, ci
);
621 MDIBringChildToTop(hwnd
, wParam
, FALSE
, TRUE
);
625 return MDIRestoreChild(hwnd
, ci
);
628 /* return MDISetMenu(...) */
632 return MDITile(hwnd
, ci
);
635 SendMessage(ci
->hwndActiveChild
, message
, wParam
, lParam
);
638 case WM_PARENTNOTIFY
:
639 if (wParam
== WM_DESTROY
)
640 return MDIDestroyChild(w
, ci
, hwnd
, LOWORD(lParam
), FALSE
);
641 else if (wParam
== WM_LBUTTONDOWN
)
642 MDIBringChildToTop(hwnd
, ci
->hwndHitTest
, FALSE
, FALSE
);
646 GetClientRect(w
->hwndParent
, &ci
->rectMaximize
);
651 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
654 /**********************************************************************
655 * DefFrameProc (USER.445)
659 DefFrameProc(HWND hwnd
, HWND hwndMDIClient
, WORD message
,
660 WORD wParam
, LONG lParam
)
667 MDIBringChildToTop(hwndMDIClient
, wParam
, TRUE
, FALSE
);
670 case WM_NCLBUTTONDOWN
:
671 if (MDIHandleLButton(hwnd
, hwndMDIClient
, wParam
, lParam
))
676 SendMessage(hwndMDIClient
, message
, wParam
, lParam
);
677 return MDIPaintMaximized(hwnd
, hwndMDIClient
,
678 message
, wParam
, lParam
);
681 return MDIPaintMaximized(hwnd
, hwndMDIClient
,
682 message
, wParam
, lParam
);
685 SendMessage(hwndMDIClient
, WM_SETFOCUS
, wParam
, lParam
);
689 MoveWindow(hwndMDIClient
, 0, 0,
690 LOWORD(lParam
), HIWORD(lParam
), TRUE
);
695 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
698 /**********************************************************************
699 * DefMDIChildProc (USER.447)
703 DefMDIChildProc(HWND hwnd
, WORD message
, WORD wParam
, LONG lParam
)
708 w
= WIN_FindWndPtr(GetParent(hwnd
));
709 ci
= (MDICLIENTINFO
*) w
->wExtra
;
714 ci
->hwndHitTest
= hwnd
;
718 return NC_DoNCPaint(hwnd
, (HRGN
)1,
719 hwnd
== ci
->hwndActiveChild
);
725 return SendMessage(GetParent(hwnd
), WM_MDIMAXIMIZE
, hwnd
, 0);
728 return SendMessage(GetParent(hwnd
), WM_MDIRESTORE
, hwnd
, 0);
734 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
737 /**********************************************************************
738 * TranslateMDISysAccel (USER.451)
741 BOOL
TranslateMDISysAccel(HWND hwndClient
, LPMSG msg
)