3 * Copyright 1994, Bob Amstadt
6 * This file contains routines to support MDI features.
8 * Notes: Windows keeps ID of MDI menu item in the wIDenu field
9 * of corresponding MDI child.
11 * Basic child activation routine is MDI_ChildActivate and
12 * SetWindowPos(childHwnd,...) implicitly calls it if SWP_NOACTIVATE i
22 #include "nonclient.h"
26 #include "sysmetrics.h"
30 void ScrollChildren(HWND
, UINT
, WPARAM
, LPARAM
);
31 void CalcChildScroll(HWND
, WORD
);
33 /* ----------------- declarations ----------------- */
35 static LONG
MDI_ChildActivate(WND
* ,HWND
);
37 /* -------- Miscellaneous service functions ----------
42 static HWND
MDI_GetChildByID(WND
* mdiClient
,int id
)
44 HWND hWnd
= mdiClient
->hwndChild
;
45 WND
* wndPtr
= WIN_FindWndPtr( hWnd
);
47 if( !wndPtr
) return 0;
51 if( wndPtr
->wIDmenu
== id
) return hWnd
;
52 wndPtr
= WIN_FindWndPtr(hWnd
= wndPtr
->hwndNext
);
58 /**********************************************************************
61 #ifdef SUPERFLUOUS_FUNCTIONS
62 static BOOL
MDI_MenuAppendItem(WND
*clientWnd
, HWND hWndChild
)
65 MDICLIENTINFO
*clientInfo
= (MDICLIENTINFO
*)clientWnd
->wExtra
;
66 WND
*wndPtr
= WIN_FindWndPtr(hWndChild
);
67 LPSTR lpWndText
= (LPSTR
) USER_HEAP_LIN_ADDR(wndPtr
->hText
);
68 int n
= sprintf(buffer
, "%d ",
69 clientInfo
->nActiveChildren
);
71 if( !clientInfo
->hWindowMenu
) return 0;
74 strncpy(buffer
+ n
, lpWndText
, sizeof(buffer
) - n
- 1);
75 return AppendMenu(clientInfo
->hWindowMenu
,MF_STRING
,
76 wndPtr
->wIDmenu
,(LPSTR
)buffer
);
80 /**********************************************************************
83 static BOOL
MDI_MenuModifyItem(WND
* clientWnd
, HWND hWndChild
)
86 MDICLIENTINFO
*clientInfo
= (MDICLIENTINFO
*)clientWnd
->wExtra
;
87 WND
*wndPtr
= WIN_FindWndPtr(hWndChild
);
88 LPSTR lpWndText
= (LPSTR
) USER_HEAP_LIN_ADDR(wndPtr
->hText
);
89 UINT n
= sprintf(buffer
, "%d ",
90 wndPtr
->wIDmenu
- clientInfo
->idFirstChild
+ 1);
93 if( !clientInfo
->hWindowMenu
) return 0;
96 strncpy(buffer
+ n
, lpWndText
, sizeof(buffer
) - n
- 1);
98 n
= GetMenuState(clientInfo
->hWindowMenu
,wndPtr
->wIDmenu
,MF_BYCOMMAND
);
99 bRet
= ModifyMenu(clientInfo
->hWindowMenu
, wndPtr
->wIDmenu
,
100 MF_BYCOMMAND
| MF_STRING
, wndPtr
->wIDmenu
,(LPSTR
)buffer
);
101 CheckMenuItem(clientInfo
->hWindowMenu
,wndPtr
->wIDmenu
, n
& MF_CHECKED
);
105 /**********************************************************************
108 static BOOL
MDI_MenuDeleteItem(WND
* clientWnd
, HWND hWndChild
)
111 MDICLIENTINFO
*clientInfo
= (MDICLIENTINFO
*)clientWnd
->wExtra
;
112 WND
*wndPtr
= WIN_FindWndPtr(hWndChild
);
116 if( !clientInfo
->nActiveChildren
||
117 !clientInfo
->hWindowMenu
) return 0;
119 id
= wndPtr
->wIDmenu
;
120 DeleteMenu(clientInfo
->hWindowMenu
,id
,MF_BYCOMMAND
);
122 /* walk the rest of MDI children to prevent gaps in the id
123 * sequence and in the menu child list
126 for( index
= id
+1; index
<= clientInfo
->nActiveChildren
+
127 clientInfo
->idFirstChild
; index
++ )
129 wndPtr
= WIN_FindWndPtr(MDI_GetChildByID(clientWnd
,index
));
132 dprintf_mdi(stddeb
,"MDIMenuDeleteItem: no window for id=%i\n",index
);
139 n
= sprintf(buffer
, "%d ",index
- clientInfo
->idFirstChild
);
140 lpWndText
= (LPSTR
) USER_HEAP_LIN_ADDR(wndPtr
->hText
);
143 strncpy(buffer
+ n
, lpWndText
, sizeof(buffer
) - n
- 1);
146 ModifyMenu(clientInfo
->hWindowMenu
,index
,MF_BYCOMMAND
| MF_STRING
,
147 index
- 1 ,(LPSTR
)buffer
);
152 /**********************************************************************
155 * returns "activateable" child or zero
157 HWND
MDI_GetWindow(WND
*clientWnd
, HWND hWnd
, WORD wTo
)
160 MDICLIENTINFO
*clientInfo
= (MDICLIENTINFO
*)clientWnd
->wExtra
;
163 if( !hWnd
) hWnd
= clientInfo
->hwndActiveChild
;
165 if( !(wndPtr
= WIN_FindWndPtr(hWnd
)) ) return 0;
168 wTo
= wTo
? GW_HWNDPREV
: GW_HWNDNEXT
;
172 if( clientWnd
->hwndChild
== hWndNext
&& wTo
== GW_HWNDPREV
)
173 hWndNext
= GetWindow( hWndNext
, GW_HWNDLAST
);
174 else if( wndPtr
->hwndNext
== 0 && wTo
== GW_HWNDNEXT
)
175 hWndNext
= clientWnd
->hwndChild
;
177 hWndNext
= GetWindow( hWndNext
, wTo
);
179 wndPtr
= WIN_FindWndPtr( hWndNext
);
181 if( (wndPtr
->dwStyle
& WS_VISIBLE
) &&
182 !(wndPtr
->dwStyle
& WS_DISABLED
) )
185 /* check if all windows were iterated through */
186 if( hWndNext
== hWnd
) break;
189 return ( hWnd
== hWndNext
)? 0 : hWndNext
;
193 /**********************************************************************
195 * FIXME: This is not complete.
197 HMENU
MDISetMenu(HWND hwnd
, BOOL fRefresh
, HMENU hmenuFrame
, HMENU hmenuWindow
)
199 dprintf_mdi(stddeb
, "WM_MDISETMENU: "NPFMT
" %04x "NPFMT
" "NPFMT
"\n", hwnd
, fRefresh
, hmenuFrame
, hmenuWindow
);
201 HWND hwndFrame
= GetParent(hwnd
);
202 HMENU oldFrameMenu
= GetMenu(hwndFrame
);
203 SetMenu(hwndFrame
, hmenuFrame
);
209 /**********************************************************************
212 WORD
MDIIconArrange(HWND parent
)
214 return ArrangeIconicWindows(parent
); /* Any reason why the */
215 /* existing icon arrange */
216 /* can't be used here? */
220 /**********************************************************************
223 HWND
MDICreateChild(WND
*w
, MDICLIENTINFO
*ci
, HWND parent
, LPARAM lParam
)
225 MDICREATESTRUCT
*cs
= (MDICREATESTRUCT
*)PTR_SEG_TO_LIN(lParam
);
227 WORD wIDmenu
= ci
->idFirstChild
+ ci
->nActiveChildren
;
232 * Create child window
234 cs
->style
&= (WS_MINIMIZE
| WS_MAXIMIZE
| WS_HSCROLL
| WS_VSCROLL
);
236 /* The child windows should probably */
237 /* stagger, shouldn't they? -DRP */
238 spacing
= GetSystemMetrics(SM_CYCAPTION
) + GetSystemMetrics(SM_CYFRAME
);
239 cs
->x
= ci
->nActiveChildren
* spacing
;
240 cs
->y
= ci
->nActiveChildren
* spacing
;
242 /* this menu is needed to set a check mark in MDI_ChildActivate */
243 AppendMenu(ci
->hWindowMenu
,MF_STRING
,wIDmenu
, (LPSTR
)&chDef
);
245 hwnd
= CreateWindow( cs
->szClass
, cs
->szTitle
,
246 WS_CHILD
| WS_BORDER
| WS_CAPTION
| WS_CLIPSIBLINGS
|
247 WS_MAXIMIZEBOX
| WS_MINIMIZEBOX
| WS_SYSMENU
|
248 WS_THICKFRAME
| WS_VISIBLE
| cs
->style
,
249 cs
->x
, cs
->y
, cs
->cx
, cs
->cy
, parent
,
250 (HMENU
)(DWORD
)(WORD
)wIDmenu
, w
->hInstance
,
255 ci
->nActiveChildren
++;
256 MDI_MenuModifyItem(w
,hwnd
);
258 /* FIXME: at this point NC area of hwnd stays inactive */
261 DeleteMenu(ci
->hWindowMenu
,wIDmenu
,MF_BYCOMMAND
);
266 /**********************************************************************
267 * MDI_SwitchActiveChild
269 * Notes: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
272 * Ideally consecutive SetWindowPos should be replaced by
273 * BeginDeferWindowPos/EndDeferWindowPos but currently it doesn't
276 * wTo is basically lParam of WM_MDINEXT message
278 void MDI_SwitchActiveChild(HWND clientHwnd
, HWND childHwnd
, WORD wTo
)
280 WND
*w
= WIN_FindWndPtr(clientHwnd
);
281 HWND hwndTo
= MDI_GetWindow(w
,childHwnd
,wTo
);
286 ci
= (MDICLIENTINFO
*) w
->wExtra
;
288 dprintf_mdi(stddeb
, "MDI_SwitchActiveChild: "NPFMT
", %i\n",childHwnd
,wTo
);
290 if ( !childHwnd
|| !hwndTo
) return;
292 hwndPrev
= ci
->hwndActiveChild
;
294 if ( hwndTo
!= hwndPrev
)
296 if (ci
->flagChildMaximized
)
298 RECT rectOldRestore
, rect
;
300 w
= WIN_FindWndPtr(hwndTo
);
302 /* save old window dimensions */
303 rectOldRestore
= ci
->rectRestore
;
304 GetWindowRect(hwndTo
, &ci
->rectRestore
);
306 rect
.top
= (ci
->rectMaximize
.top
-
307 (w
->rectClient
.top
- w
->rectWindow
.top
));
308 rect
.bottom
= (ci
->rectMaximize
.bottom
+
309 (w
->rectWindow
.bottom
- w
->rectClient
.bottom
));
310 rect
.left
= (ci
->rectMaximize
.left
-
311 (w
->rectClient
.left
- w
->rectWindow
.left
));
312 rect
.right
= (ci
->rectMaximize
.right
+
313 (w
->rectWindow
.right
- w
->rectClient
.right
));
314 w
->dwStyle
|= WS_MAXIMIZE
;
317 ci
->flagChildMaximized
= childHwnd
; /* prevent maximization
318 * in MDI_ChildActivate
321 SetWindowPos( hwndTo
, HWND_TOP
, rect
.left
, rect
.top
,
322 rect
.right
- rect
.left
+ 1,
323 rect
.bottom
- rect
.top
+ 1, 0);
325 SendMessage( hwndTo
, WM_SIZE
, SIZE_MAXIMIZED
,
326 MAKELONG(w
->rectClient
.right
-w
->rectClient
.left
,
327 w
->rectClient
.bottom
-w
->rectClient
.top
));
329 w
= WIN_FindWndPtr(hwndPrev
);
333 w
->dwStyle
&= ~WS_MAXIMIZE
;
335 /* push hwndPrev to the bottom if needed */
337 SetWindowPos(hwndPrev
, HWND_BOTTOM
,
338 rectOldRestore
.left
, rectOldRestore
.top
,
339 rectOldRestore
.right
- rectOldRestore
.left
+ 1,
340 rectOldRestore
.bottom
- rectOldRestore
.top
+ 1,
346 SetWindowPos( hwndTo
, HWND_TOP
, 0, 0, 0, 0,
347 SWP_NOMOVE
| SWP_NOSIZE
);
348 if( !wTo
&& hwndPrev
)
350 SetWindowPos( hwndPrev
, HWND_BOTTOM
, 0, 0, 0, 0,
351 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
359 /**********************************************************************
362 HWND
MDIDestroyChild(WND
*w_parent
, MDICLIENTINFO
*ci
, HWND parent
,
363 HWND child
, BOOL flagDestroy
)
365 WND
*childPtr
= WIN_FindWndPtr(child
);
369 if( child
== ci
->hwndActiveChild
)
371 MDI_SwitchActiveChild(parent
,child
,0);
373 if( child
== ci
->hwndActiveChild
)
374 MDI_ChildActivate(w_parent
,0);
376 MDI_MenuDeleteItem(w_parent
, child
);
379 ci
->nActiveChildren
--;
381 if( ci
->flagChildMaximized
== child
)
382 ci
->flagChildMaximized
= (HWND
)1;
386 DestroyWindow(child
);
387 PostMessage(parent
,WM_MDICALCCHILDSCROLL
,0,0L);
388 ci
->sbRecalc
|= (SB_BOTH
+1);
396 /**********************************************************************
399 LONG
MDIMaximizeChild(HWND parent
, HWND child
, MDICLIENTINFO
*ci
)
402 WND
*w
= WIN_FindWndPtr(child
);
405 if( !SendMessage( child
, WM_QUERYOPEN
, 0, 0L) )
408 ci
->rectRestore
= w
->rectWindow
;
410 rect
.top
= (ci
->rectMaximize
.top
-
411 (w
->rectClient
.top
- w
->rectWindow
.top
));
412 rect
.bottom
= (ci
->rectMaximize
.bottom
+
413 (w
->rectWindow
.bottom
- w
->rectClient
.bottom
));
414 rect
.left
= (ci
->rectMaximize
.left
-
415 (w
->rectClient
.left
- w
->rectWindow
.left
));
416 rect
.right
= (ci
->rectMaximize
.right
+
417 (w
->rectWindow
.right
- w
->rectClient
.right
));
418 w
->dwStyle
|= WS_MAXIMIZE
;
420 SetWindowPos(child
, 0, rect
.left
, rect
.top
,
421 rect
.right
- rect
.left
+ 1, rect
.bottom
- rect
.top
+ 1, 0);
423 ci
->flagChildMaximized
= child
;
425 SendMessage(child
, WM_SIZE
, SIZE_MAXIMIZED
,
426 MAKELONG(w
->rectClient
.right
-w
->rectClient
.left
,
427 w
->rectClient
.bottom
-w
->rectClient
.top
));
429 SendMessage(GetParent(parent
), WM_NCPAINT
, 0, 0);
434 /**********************************************************************
437 LONG
MDIRestoreChild(HWND parent
, MDICLIENTINFO
*ci
)
441 hWnd
= ci
->hwndActiveChild
;
443 dprintf_mdi(stddeb
,"MDIRestoreChild: restore "NPFMT
"\n", hWnd
);
445 ci
->flagChildMaximized
= FALSE
;
447 ShowWindow(hWnd
, SW_RESTORE
); /* display the window */
449 hWnd
= GetParent(parent
);
451 SendMessage(hWnd
,WM_NCPAINT
, 0, 0);
456 /**********************************************************************
459 * Note: hWndChild is NULL when last child is being destroyed
461 LONG
MDI_ChildActivate(WND
*clientPtr
, HWND hWndChild
)
463 MDICLIENTINFO
*clientInfo
= (MDICLIENTINFO
*)clientPtr
->wExtra
;
464 HWND prevActiveWnd
= clientInfo
->hwndActiveChild
;
465 WND
*wndPtr
= WIN_FindWndPtr( hWndChild
);
466 WND
*wndPrev
= WIN_FindWndPtr( prevActiveWnd
);
467 BOOL isActiveFrameWnd
= 0;
469 if( hWndChild
== prevActiveWnd
) return 0L;
472 if( wndPtr
->dwStyle
& WS_DISABLED
) return 0L;
474 dprintf_mdi(stddeb
,"MDI_ChildActivate: "NPFMT
"\n", hWndChild
);
476 if( GetActiveWindow() == clientPtr
->hwndParent
)
477 isActiveFrameWnd
= TRUE
;
479 /* deactivate prev. active child */
482 SendMessage( prevActiveWnd
, WM_NCACTIVATE
, FALSE
, 0L );
484 SendMessage( prevActiveWnd
, WM_MDIACTIVATE
, (WPARAM
)prevActiveWnd
,
487 SendMessage( prevActiveWnd
, WM_MDIACTIVATE
, FALSE
,
488 MAKELONG(hWndChild
,prevActiveWnd
));
490 /* uncheck menu item */
491 if( clientInfo
->hWindowMenu
)
492 CheckMenuItem( clientInfo
->hWindowMenu
,
493 wndPrev
->wIDmenu
, 0);
497 if( clientInfo
->flagChildMaximized
)
498 if( clientInfo
->flagChildMaximized
!= hWndChild
)
501 clientInfo
->hwndActiveChild
= hWndChild
;
502 MDIMaximizeChild(GetParent(hWndChild
),hWndChild
,clientInfo
);
505 clientInfo
->hwndActiveChild
= hWndChild
;
507 /* check if we have any children left */
510 if( isActiveFrameWnd
)
511 SetFocus( GetParent(hWndChild
) );
515 /* check menu item */
516 if( clientInfo
->hWindowMenu
)
517 CheckMenuItem( clientInfo
->hWindowMenu
,
518 wndPtr
->wIDmenu
, MF_CHECKED
);
520 /* bring active child to the top */
521 SetWindowPos( hWndChild
, 0,0,0,0,0, SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
523 if( isActiveFrameWnd
)
525 SendMessage( hWndChild
, WM_NCACTIVATE
, TRUE
, 0L);
526 if( GetFocus() == GetParent(hWndChild
) )
527 SendMessage( GetParent(hWndChild
), WM_SETFOCUS
,
528 (WPARAM
)GetParent(hWndChild
), 0L );
530 SetFocus( GetParent(hWndChild
) );
534 SendMessage( hWndChild
, WM_MDIACTIVATE
, (WPARAM
)hWndChild
,
535 (LPARAM
)prevActiveWnd
);
537 SendMessage( hWndChild
, WM_MDIACTIVATE
, TRUE
,
538 MAKELONG(prevActiveWnd
,hWndChild
) );
544 /**********************************************************************
547 * iTotal returns number of children available for tiling or cascading
549 MDIWCL
* MDI_BuildWCL(WND
* clientWnd
, int* iTotal
)
551 MDIWCL
*listTop
,*listNext
;
554 if (!(listTop
= (MDIWCL
*)malloc( sizeof(MDIWCL
) ))) return NULL
;
556 listTop
->hChild
= clientWnd
->hwndChild
;
557 listTop
->prev
= NULL
;
560 /* build linked list from top child to bottom */
562 childWnd
= WIN_FindWndPtr( listTop
->hChild
);
563 while( childWnd
&& childWnd
->hwndNext
)
565 listNext
= (MDIWCL
*)malloc(sizeof(MDIWCL
));
569 /* quit gracefully */
570 listNext
= listTop
->prev
;
573 listNext
= listTop
->prev
;
577 fprintf(stdnimp
,"MDICascade: allocation failed\n");
581 if( (childWnd
->dwStyle
& WS_DISABLED
) ||
582 (childWnd
->dwStyle
& WS_MINIMIZE
) ||
583 !(childWnd
->dwStyle
& WS_VISIBLE
) )
589 listNext
->hChild
= childWnd
->hwndNext
;
590 listNext
->prev
= listTop
;
594 childWnd
= WIN_FindWndPtr( childWnd
->hwndNext
);
597 if( (childWnd
->dwStyle
& WS_DISABLED
) ||
598 (childWnd
->dwStyle
& WS_MINIMIZE
) ||
599 !(childWnd
->dwStyle
& WS_VISIBLE
) )
608 /**********************************************************************
611 LONG
MDICascade(HWND parent
, MDICLIENTINFO
*ci
)
614 MDIWCL
*listTop
,*listPrev
;
616 int spacing
, xsize
, ysize
;
620 if (ci
->flagChildMaximized
)
621 MDIRestoreChild(parent
, ci
);
623 if (ci
->nActiveChildren
== 0) return 0;
625 GetClientRect(parent
, &rect
);
626 spacing
= GetSystemMetrics(SM_CYCAPTION
) + GetSystemMetrics(SM_CYFRAME
);
627 ysize
= rect
.bottom
- 8 * spacing
;
628 xsize
= rect
.right
- 8 * spacing
;
631 "MDICascade: Client wnd at (%ld,%ld) - (%ld,%ld), spacing %d\n",
632 (LONG
)rect
.left
, (LONG
)rect
.top
, (LONG
)rect
.right
, (LONG
)rect
.bottom
,
635 clientWnd
= WIN_FindWndPtr( parent
);
637 listTop
= MDI_BuildWCL(clientWnd
,&iToPosition
);
639 if( !listTop
) return 0;
644 /* walk list and move windows */
647 dprintf_mdi(stddeb
, "MDICascade: move "NPFMT
" to (%d,%d) size [%d,%d]\n",
648 listTop
->hChild
, x
, y
, xsize
, ysize
);
650 if( listTop
->hChild
)
652 SetWindowPos(listTop
->hChild
, 0, x
, y
, xsize
, ysize
,
653 SWP_DRAWFRAME
| SWP_NOACTIVATE
| SWP_NOZORDER
);
659 listPrev
= listTop
->prev
;
667 /**********************************************************************
671 LONG
MDITile(HWND parent
, MDICLIENTINFO
*ci
)
673 WND
*wndClient
= WIN_FindWndPtr(parent
);
674 MDIWCL
*listTop
,*listPrev
;
683 if (ci
->flagChildMaximized
)
684 MDIRestoreChild(parent
, ci
);
686 if (ci
->nActiveChildren
== 0) return 0;
688 listTop
= MDI_BuildWCL(wndClient
, &iToPosition
);
690 dprintf_mdi(stddeb
,"MDITile: %i windows to tile\n",iToPosition
);
692 if( !listTop
) return 0;
694 /* just free memory and return if zero windows to tile */
695 if ( iToPosition
== 0 )
698 GetClientRect(parent
, &rect
);
700 rows
= (int) sqrt((double) iToPosition
);
701 columns
= iToPosition
/ rows
;
704 if( iToPosition
!= ci
->nActiveChildren
)
706 y
= rect
.bottom
- 2 * SYSMETRICS_CYICONSPACING
- SYSMETRICS_CYICON
;
707 rect
.bottom
= ( y
- SYSMETRICS_CYICON
< rect
.top
)? rect
.bottom
: y
;
710 ysize
= rect
.bottom
/ rows
;
711 xsize
= rect
.right
/ columns
;
716 for (c
= 1; c
<= columns
; c
++)
720 rows
= iToPosition
- i
;
721 ysize
= rect
.bottom
/ rows
;
725 for (r
= 1; r
<= rows
; r
++, i
++)
727 /* shouldn't happen but... */
731 if( listTop
->hChild
)
733 SetWindowPos(listTop
->hChild
, 0, x
, y
, xsize
, ysize
,
734 SWP_DRAWFRAME
| SWP_NOACTIVATE
| SWP_NOZORDER
);
738 listPrev
= listTop
->prev
;
747 /* free the rest if any */
749 listPrev
= listTop
->prev
;
751 listTop
= listPrev
; }
756 /**********************************************************************
759 BOOL
MDIHandleLButton(HWND hwndFrame
, HWND hwndClient
,
760 WORD wParam
, LONG lParam
)
767 w
= WIN_FindWndPtr(hwndClient
);
768 ci
= (MDICLIENTINFO
*) w
->wExtra
;
770 if (wParam
== HTMENU
&& ci
->flagChildMaximized
)
774 NC_GetInsideRect(hwndFrame
, &rect
);
775 if (x
< rect
.left
+ SYSMETRICS_CXSIZE
)
777 SendMessage(ci
->hwndActiveChild
, WM_SYSCOMMAND
,
781 else if (x
>= rect
.right
- SYSMETRICS_CXSIZE
)
783 SendMessage(ci
->hwndActiveChild
, WM_SYSCOMMAND
,
792 /**********************************************************************
795 LONG
MDIPaintMaximized(HWND hwndFrame
, HWND hwndClient
, WORD message
,
796 WORD wParam
, LONG lParam
)
798 static HBITMAP hbitmapClose
= 0;
799 static HBITMAP hbitmapMaximized
= 0;
805 WND
*wndPtr
= WIN_FindWndPtr(hwndFrame
);
807 w
= WIN_FindWndPtr(hwndClient
);
808 ci
= (MDICLIENTINFO
*) w
->wExtra
;
810 dprintf_mdi(stddeb
, "MDIPaintMaximized: frame "NPFMT
", client "NPFMT
811 ", max flag %d, menu %04x\n", hwndFrame
, hwndClient
,
812 (int)ci
->flagChildMaximized
, wndPtr
? wndPtr
->wIDmenu
: 0);
814 if (ci
->flagChildMaximized
&& wndPtr
&& wndPtr
->wIDmenu
!= 0)
816 NC_DoNCPaint(hwndFrame
, wParam
, TRUE
);
818 hdc
= GetDCEx(hwndFrame
, 0, DCX_CACHE
| DCX_WINDOW
);
821 hdcMem
= CreateCompatibleDC(hdc
);
823 if (hbitmapClose
== 0)
825 hbitmapClose
= LoadBitmap(0, MAKEINTRESOURCE(OBM_OLD_CLOSE
));
826 hbitmapMaximized
= LoadBitmap(0, MAKEINTRESOURCE(OBM_RESTORE
));
830 "MDIPaintMaximized: hdcMem "NPFMT
", close bitmap "NPFMT
", "
831 "maximized bitmap "NPFMT
"\n",
832 hdcMem
, hbitmapClose
, hbitmapMaximized
);
834 NC_GetInsideRect(hwndFrame
, &rect
);
835 rect
.top
+= (wndPtr
->dwStyle
& WS_CAPTION
) ? SYSMETRICS_CYSIZE
+ 1 : 0;
836 SelectObject(hdcMem
, hbitmapClose
);
837 BitBlt(hdc
, rect
.left
, rect
.top
+ 1,
838 SYSMETRICS_CXSIZE
, SYSMETRICS_CYSIZE
,
839 hdcMem
, 1, 1, SRCCOPY
);
841 NC_GetInsideRect(hwndFrame
, &rect
);
842 rect
.top
+= (wndPtr
->dwStyle
& WS_CAPTION
) ? SYSMETRICS_CYSIZE
+ 1 : 0;
843 rect
.left
= rect
.right
- SYSMETRICS_CXSIZE
;
844 SelectObject(hdcMem
, hbitmapMaximized
);
845 BitBlt(hdc
, rect
.left
, rect
.top
+ 1,
846 SYSMETRICS_CXSIZE
, SYSMETRICS_CYSIZE
,
847 hdcMem
, 1, 1, SRCCOPY
);
849 NC_GetInsideRect(hwndFrame
, &rect
);
850 rect
.top
+= (wndPtr
->dwStyle
& WS_CAPTION
) ? SYSMETRICS_CYSIZE
+ 1 : 0;
851 rect
.left
+= SYSMETRICS_CXSIZE
;
852 rect
.right
-= SYSMETRICS_CXSIZE
;
853 rect
.bottom
= rect
.top
+ SYSMETRICS_CYMENU
;
855 MENU_DrawMenuBar(hdc
, &rect
, hwndFrame
, FALSE
);
858 ReleaseDC(hwndFrame
, hdc
);
861 return DefWindowProc(hwndFrame
, message
, wParam
, lParam
);
866 /**********************************************************************
869 * This function is the handler for all MDI requests.
871 LRESULT
MDIClientWndProc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
874 LPCLIENTCREATESTRUCT ccs
;
878 w
= WIN_FindWndPtr(hwnd
);
879 ci
= (MDICLIENTINFO
*) w
->wExtra
;
884 cs
= (LPCREATESTRUCT
) PTR_SEG_TO_LIN(lParam
);
885 ccs
= (LPCLIENTCREATESTRUCT
) PTR_SEG_TO_LIN(cs
->lpCreateParams
);
886 ci
->hWindowMenu
= ccs
->hWindowMenu
;
887 ci
->idFirstChild
= ccs
->idFirstChild
;
888 ci
->flagChildMaximized
= FALSE
;
891 w
->dwStyle
|= WS_CLIPCHILDREN
;
893 AppendMenu(ccs
->hWindowMenu
,MF_SEPARATOR
,0,NULL
);
895 GetClientRect(w
->hwndParent
, &ci
->rectMaximize
);
896 MoveWindow(hwnd
, 0, 0,
897 ci
->rectMaximize
.right
, ci
->rectMaximize
.bottom
, 1);
902 SetWindowPos((HWND
)wParam
,0,0,0,0,0, SWP_NOSIZE
| SWP_NOMOVE
);
906 return MDICascade(hwnd
, ci
);
909 return (LONG
)MDICreateChild(w
, ci
, hwnd
, lParam
);
912 return (LONG
)MDIDestroyChild(w
, ci
, hwnd
, (HWND
)wParam
, TRUE
);
914 case WM_MDIGETACTIVE
:
915 return ((LONG
) ci
->hwndActiveChild
|
916 ((LONG
) (ci
->flagChildMaximized
>0) << 16));
918 case WM_MDIICONARRANGE
:
920 MDIIconArrange(hwnd
);
922 SendMessage(hwnd
,WM_MDICALCCHILDSCROLL
,0,0L);
926 return MDIMaximizeChild(hwnd
, (HWND
)wParam
, ci
);
929 MDI_SwitchActiveChild(hwnd
, (HWND
)wParam
, lParam
);
933 return MDIRestoreChild(hwnd
, ci
);
937 return (LRESULT
)MDISetMenu(hwnd
, FALSE
, (HMENU
)wParam
, (HMENU
)lParam
);
939 return (LRESULT
)MDISetMenu(hwnd
, wParam
, LOWORD(lParam
), HIWORD(lParam
));
944 ShowScrollBar(hwnd
,SB_BOTH
,FALSE
);
952 ScrollChildren(hwnd
,message
,wParam
,lParam
);
957 if( ci
->hwndActiveChild
)
959 w
= WIN_FindWndPtr( ci
->hwndActiveChild
);
960 if( !(w
->dwStyle
& WS_MINIMIZE
) )
961 SetFocus( ci
->hwndActiveChild
);
966 if( ci
->hwndActiveChild
)
967 SendMessage(ci
->hwndActiveChild
, message
, wParam
, lParam
);
970 case WM_PARENTNOTIFY
:
971 if (wParam
== WM_LBUTTONDOWN
)
972 SetWindowPos(ci
->hwndHitTest
, 0,0,0,0,0, SWP_NOSIZE
| SWP_NOMOVE
);
976 GetClientRect(w
->hwndParent
, &ci
->rectMaximize
);
977 if( !ci
->hwndActiveChild
)
979 PostMessage(hwnd
,WM_MDICALCCHILDSCROLL
,0,0L);
980 ci
->sbRecalc
|= (SB_BOTH
+1);
984 case WM_MDICALCCHILDSCROLL
:
988 CalcChildScroll(hwnd
, ci
->sbRecalc
-1);
994 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
997 /**********************************************************************
998 * DefFrameProc (USER.445)
1001 LRESULT
DefFrameProc(HWND hwnd
, HWND hwndMDIClient
, UINT message
,
1002 WPARAM wParam
, LPARAM lParam
)
1011 childHwnd
= MDI_GetChildByID( WIN_FindWndPtr(hwndMDIClient
),
1014 #ifdef WINELIB32 /* FIXME: need to find out the equivalent Win32 message */
1015 SendMessage(hwndMDIClient
, WM_MDIACTIVATE
, 0 , 0);
1017 SendMessage(hwndMDIClient
, WM_MDIACTIVATE
, childHwnd
, 0L);
1021 case WM_NCLBUTTONDOWN
:
1022 if (MDIHandleLButton(hwnd
, hwndMDIClient
, wParam
, lParam
))
1027 SendMessage(hwndMDIClient
, message
, wParam
, lParam
);
1028 return MDIPaintMaximized(hwnd
, hwndMDIClient
,
1029 message
, wParam
, lParam
);
1032 return MDIPaintMaximized(hwnd
, hwndMDIClient
,
1033 message
, wParam
, lParam
);
1036 SetFocus(hwndMDIClient
);
1040 MoveWindow(hwndMDIClient
, 0, 0,
1041 LOWORD(lParam
), HIWORD(lParam
), TRUE
);
1046 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
1049 /**********************************************************************
1050 * DefMDIChildProc (USER.447)
1054 LONG
DefMDIChildProc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1056 LONG
DefMDIChildProc(HWND hwnd
, WORD message
, WORD wParam
, LONG lParam
)
1062 clientWnd
= WIN_FindWndPtr(GetParent(hwnd
));
1063 ci
= (MDICLIENTINFO
*) clientWnd
->wExtra
;
1068 ci
->hwndHitTest
= hwnd
;
1072 DefWindowProc(hwnd
, message
, wParam
, lParam
);
1073 MDI_MenuModifyItem(clientWnd
,hwnd
);
1077 SendMessage(GetParent(hwnd
),WM_MDIDESTROY
,(WPARAM
)hwnd
,0L);
1081 if( ci
->hwndActiveChild
!= hwnd
)
1082 MDI_ChildActivate(clientWnd
, hwnd
);
1085 case WM_CHILDACTIVATE
:
1086 MDI_ChildActivate(clientWnd
, hwnd
);
1090 dprintf_mdi(stddeb
,"DefMDIChildProc: WM_NCPAINT for "NPFMT
", active "NPFMT
"\n",
1091 hwnd
, ci
->hwndActiveChild
);
1098 return SendMessage(GetParent(hwnd
), WM_MDIMAXIMIZE
, (WPARAM
)hwnd
, 0);
1101 return SendMessage(GetParent(hwnd
), WM_MDIRESTORE
, (WPARAM
)hwnd
, 0);
1105 /* should also handle following messages */
1106 case WM_GETMINMAXINFO
:
1107 /* should return rect of MDI client
1108 * so that normal ShowWindow will be able to handle
1109 * actions that are handled by MDIMaximize and MDIRestore */
1114 PostMessage(GetParent(hwnd
),WM_MDICALCCHILDSCROLL
,0,0L);
1115 ci
->sbRecalc
|= (SB_BOTH
+1);
1119 if( IsChild( GetActiveWindow(), GetParent(hwnd
)) )
1120 SendMessage(clientWnd
->hwndChild
,WM_CHILDACTIVATE
,0,0L);
1123 PostMessage(GetParent(hwnd
),WM_MDICALCCHILDSCROLL
,0,0L);
1124 ci
->sbRecalc
|= (SB_BOTH
+1);
1130 /* set current menu to child system menu */
1135 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
1138 /**********************************************************************
1139 * TranslateMDISysAccel (USER.451)
1142 BOOL
TranslateMDISysAccel(HWND hwndClient
, LPMSG msg
)
1148 /***********************************************************************
1149 * CalcChildScroll (USER.462)
1151 void CalcChildScroll( HWND hwnd
, WORD scroll
)
1153 RECT childRect
, clientRect
;
1156 GetClientRect( hwnd
, &clientRect
);
1157 SetRectEmpty( &childRect
);
1158 hwndChild
= GetWindow( hwnd
, GW_CHILD
);
1161 WND
*wndPtr
= WIN_FindWndPtr( hwndChild
);
1162 UnionRect( &childRect
, &wndPtr
->rectWindow
, &childRect
);
1163 hwndChild
= wndPtr
->hwndNext
;
1165 UnionRect( &childRect
, &clientRect
, &childRect
);
1167 if ((scroll
== SB_HORZ
) || (scroll
== SB_BOTH
))
1169 SetScrollRange( hwnd
, SB_HORZ
, childRect
.left
,
1170 childRect
.right
- clientRect
.right
, FALSE
);
1171 SetScrollPos( hwnd
, SB_HORZ
, clientRect
.left
- childRect
.left
, TRUE
);
1173 if ((scroll
== SB_VERT
) || (scroll
== SB_BOTH
))
1175 SetScrollRange( hwnd
, SB_VERT
, childRect
.top
,
1176 childRect
.bottom
- clientRect
.bottom
, FALSE
);
1177 SetScrollPos( hwnd
, SB_HORZ
, clientRect
.top
- childRect
.top
, TRUE
);
1181 /***********************************************************************
1182 * ScrollChildren (USER.463)
1184 void ScrollChildren(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1186 WND
*wndPtr
= WIN_FindWndPtr(hWnd
);
1194 if( !wndPtr
) return;
1196 if( uMsg
== WM_HSCROLL
)
1198 GetScrollRange(hWnd
,SB_HORZ
,&minPos
,&maxPos
);
1199 curPos
= GetScrollPos(hWnd
,SB_HORZ
);
1200 length
= (wndPtr
->rectClient
.right
- wndPtr
->rectClient
.left
)/2;
1201 shift
= SYSMETRICS_CYHSCROLL
;
1203 else if( uMsg
== WM_VSCROLL
)
1205 GetScrollRange(hWnd
,SB_VERT
,&minPos
,&maxPos
);
1206 curPos
= GetScrollPos(hWnd
,SB_VERT
);
1207 length
= (wndPtr
->rectClient
.bottom
- wndPtr
->rectClient
.top
)/2;
1208 shift
= SYSMETRICS_CXVSCROLL
;
1215 newPos
= curPos
- shift
;
1218 newPos
= curPos
+ shift
;
1221 newPos
= curPos
- length
;
1224 newPos
= curPos
+ length
;
1227 case SB_THUMBPOSITION
:
1228 newPos
= LOWORD(lParam
);
1241 CalcChildScroll(hWnd
,(uMsg
== WM_VSCROLL
)?SB_VERT
:SB_HORZ
);
1245 if( newPos
> maxPos
)
1247 else if( newPos
< minPos
)
1250 SetScrollPos(hWnd
, (uMsg
== WM_VSCROLL
)?SB_VERT
:SB_HORZ
, newPos
, TRUE
);
1252 if( uMsg
== WM_VSCROLL
)
1253 ScrollWindow(hWnd
,0 ,curPos
- newPos
, NULL
, NULL
);
1255 ScrollWindow(hWnd
,curPos
- newPos
, 0, NULL
, NULL
);