Release 951226
[wine/gsoc-2012-control.git] / windows / mdi.c
blob86d54132a36cce64d7333dfe53b4be9522f4d35a
1 /* MDI.C
3 * Copyright 1994, Bob Amstadt
4 * 1995, Alex Korobka
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
13 * is not used.
16 #include <stdlib.h>
17 #include <string.h>
18 #include <stdio.h>
19 #include <math.h>
20 #include "windows.h"
21 #include "win.h"
22 #include "nonclient.h"
23 #include "mdi.h"
24 #include "user.h"
25 #include "menu.h"
26 #include "sysmetrics.h"
27 #include "stddebug.h"
28 #include "debug.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 ----------
39 * MDI_GetChildByID
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;
49 while( wndPtr )
51 if( wndPtr->wIDmenu == id ) return hWnd;
52 wndPtr = WIN_FindWndPtr(hWnd = wndPtr->hwndNext);
55 return 0;
58 /**********************************************************************
59 * MDI_MenuAppendItem
61 #ifdef SUPERFLUOUS_FUNCTIONS
62 static BOOL MDI_MenuAppendItem(WND *clientWnd, HWND hWndChild)
64 char buffer[128];
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;
73 if( lpWndText )
74 strncpy(buffer + n, lpWndText, sizeof(buffer) - n - 1);
75 return AppendMenu(clientInfo->hWindowMenu,MF_STRING,
76 wndPtr->wIDmenu,(LPSTR)buffer);
78 #endif
80 /**********************************************************************
81 * MDI_MenuModifyItem
83 static BOOL MDI_MenuModifyItem(WND* clientWnd, HWND hWndChild )
85 char buffer[128];
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);
91 BOOL bRet = 0;
93 if( !clientInfo->hWindowMenu ) return 0;
95 if( lpWndText )
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);
102 return bRet;
105 /**********************************************************************
106 * MDI_MenuDeleteItem
108 static BOOL MDI_MenuDeleteItem(WND* clientWnd, HWND hWndChild )
110 char buffer[128];
111 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
112 WND *wndPtr = WIN_FindWndPtr(hWndChild);
113 LPSTR lpWndText;
114 INT index = 0,id,n;
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));
130 if( !wndPtr )
132 dprintf_mdi(stddeb,"MDIMenuDeleteItem: no window for id=%i\n",index);
133 continue;
136 /* set correct id */
137 wndPtr->wIDmenu--;
139 n = sprintf(buffer, "%d ",index - clientInfo->idFirstChild);
140 lpWndText = (LPSTR) USER_HEAP_LIN_ADDR(wndPtr->hText);
142 if( lpWndText )
143 strncpy(buffer + n, lpWndText, sizeof(buffer) - n - 1);
145 /* change menu */
146 ModifyMenu(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING,
147 index - 1 ,(LPSTR)buffer );
149 return 1;
152 /**********************************************************************
153 * MDI_GetWindow
155 * returns "activateable" child or zero
157 HWND MDI_GetWindow(WND *clientWnd, HWND hWnd, WORD wTo )
159 HWND hWndNext;
160 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
161 WND *wndPtr;
163 if( !hWnd ) hWnd = clientInfo->hwndActiveChild;
165 if( !(wndPtr = WIN_FindWndPtr(hWnd)) ) return 0;
167 hWndNext = hWnd;
168 wTo = wTo ? GW_HWNDPREV : GW_HWNDNEXT;
170 while( 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;
176 else
177 hWndNext = GetWindow( hWndNext, wTo );
179 wndPtr = WIN_FindWndPtr( hWndNext );
181 if( (wndPtr->dwStyle & WS_VISIBLE) &&
182 !(wndPtr->dwStyle & WS_DISABLED) )
183 break;
185 /* check if all windows were iterated through */
186 if( hWndNext == hWnd ) break;
189 return ( hWnd == hWndNext )? 0 : hWndNext;
193 /**********************************************************************
194 * MDISetMenu
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);
200 if (!fRefresh) {
201 HWND hwndFrame = GetParent(hwnd);
202 HMENU oldFrameMenu = GetMenu(hwndFrame);
203 SetMenu(hwndFrame, hmenuFrame);
204 return oldFrameMenu;
206 return 0;
209 /**********************************************************************
210 * MDIIconArrange
212 WORD MDIIconArrange(HWND parent)
214 return ArrangeIconicWindows(parent); /* Any reason why the */
215 /* existing icon arrange */
216 /* can't be used here? */
217 /* -DRP */
220 /**********************************************************************
221 * MDICreateChild
223 HWND MDICreateChild(WND *w, MDICLIENTINFO *ci, HWND parent, LPARAM lParam )
225 MDICREATESTRUCT *cs = (MDICREATESTRUCT *)PTR_SEG_TO_LIN(lParam);
226 HWND hwnd;
227 WORD wIDmenu = ci->idFirstChild + ci->nActiveChildren;
228 int spacing;
229 char chDef = '\0';
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,
251 (SEGPTR)lParam);
253 if (hwnd)
255 ci->nActiveChildren++;
256 MDI_MenuModifyItem(w ,hwnd);
258 /* FIXME: at this point NC area of hwnd stays inactive */
260 else
261 DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
263 return hwnd;
266 /**********************************************************************
267 * MDI_SwitchActiveChild
269 * Notes: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
270 * being activated
272 * Ideally consecutive SetWindowPos should be replaced by
273 * BeginDeferWindowPos/EndDeferWindowPos but currently it doesn't
274 * matter.
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);
282 HWND hwndPrev;
283 MDICLIENTINFO *ci;
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;
316 /* maximize it */
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);
331 if( w )
333 w->dwStyle &= ~WS_MAXIMIZE;
335 /* push hwndPrev to the bottom if needed */
336 if( !wTo )
337 SetWindowPos(hwndPrev, HWND_BOTTOM,
338 rectOldRestore.left, rectOldRestore.top,
339 rectOldRestore.right - rectOldRestore.left + 1,
340 rectOldRestore.bottom - rectOldRestore.top + 1,
341 SWP_NOACTIVATE );
344 else
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 /**********************************************************************
360 * MDIDestroyChild
362 HWND MDIDestroyChild(WND *w_parent, MDICLIENTINFO *ci, HWND parent,
363 HWND child, BOOL flagDestroy)
365 WND *childPtr = WIN_FindWndPtr(child);
367 if( childPtr )
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;
384 if (flagDestroy)
386 DestroyWindow(child);
387 PostMessage(parent,WM_MDICALCCHILDSCROLL,0,0L);
388 ci->sbRecalc |= (SB_BOTH+1);
392 return 0;
396 /**********************************************************************
397 * MDIMaximizeChild
399 LONG MDIMaximizeChild(HWND parent, HWND child, MDICLIENTINFO *ci)
402 WND *w = WIN_FindWndPtr(child);
403 RECT rect;
405 if( !SendMessage( child, WM_QUERYOPEN, 0, 0L) )
406 return 0;
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);
431 return 0;
434 /**********************************************************************
435 * MDIRestoreChild
437 LONG MDIRestoreChild(HWND parent, MDICLIENTINFO *ci)
439 HWND hWnd;
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);
453 return 0;
456 /**********************************************************************
457 * MDI_ChildActivate
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;
471 if( wndPtr )
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 */
480 if( wndPrev )
482 SendMessage( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
483 #ifdef WINELIB32
484 SendMessage( prevActiveWnd, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
485 (LPARAM)hWndChild);
486 #else
487 SendMessage( prevActiveWnd, WM_MDIACTIVATE, FALSE,
488 MAKELONG(hWndChild,prevActiveWnd));
489 #endif
490 /* uncheck menu item */
491 if( clientInfo->hWindowMenu )
492 CheckMenuItem( clientInfo->hWindowMenu,
493 wndPrev->wIDmenu, 0);
496 /* set appearance */
497 if( clientInfo->flagChildMaximized )
498 if( clientInfo->flagChildMaximized != hWndChild )
499 if( hWndChild )
501 clientInfo->hwndActiveChild = hWndChild;
502 MDIMaximizeChild(GetParent(hWndChild),hWndChild,clientInfo);
505 clientInfo->hwndActiveChild = hWndChild;
507 /* check if we have any children left */
508 if( !hWndChild )
510 if( isActiveFrameWnd )
511 SetFocus( GetParent(hWndChild) );
512 return 0;
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 );
529 else
530 SetFocus( GetParent(hWndChild) );
533 #ifdef WINELIB32
534 SendMessage( hWndChild, WM_MDIACTIVATE, (WPARAM)hWndChild,
535 (LPARAM)prevActiveWnd );
536 #else
537 SendMessage( hWndChild, WM_MDIACTIVATE, TRUE,
538 MAKELONG(prevActiveWnd,hWndChild) );
539 #endif
541 return 1;
544 /**********************************************************************
545 * MDI_BuildWCL
547 * iTotal returns number of children available for tiling or cascading
549 MDIWCL* MDI_BuildWCL(WND* clientWnd, int* iTotal)
551 MDIWCL *listTop,*listNext;
552 WND *childWnd;
554 if (!(listTop = (MDIWCL*)malloc( sizeof(MDIWCL) ))) return NULL;
556 listTop->hChild = clientWnd->hwndChild;
557 listTop->prev = NULL;
558 *iTotal = 1;
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));
567 if( !listNext )
569 /* quit gracefully */
570 listNext = listTop->prev;
571 while( listTop )
573 listNext = listTop->prev;
574 free(listTop);
575 listTop = listNext;
577 fprintf(stdnimp,"MDICascade: allocation failed\n");
578 return NULL;
581 if( (childWnd->dwStyle & WS_DISABLED) ||
582 (childWnd->dwStyle & WS_MINIMIZE) ||
583 !(childWnd->dwStyle & WS_VISIBLE) )
585 listTop->hChild = 0;
586 (*iTotal)--;
589 listNext->hChild = childWnd->hwndNext;
590 listNext->prev = listTop;
591 listTop = listNext;
592 (*iTotal)++;
594 childWnd = WIN_FindWndPtr( childWnd->hwndNext );
597 if( (childWnd->dwStyle & WS_DISABLED) ||
598 (childWnd->dwStyle & WS_MINIMIZE) ||
599 !(childWnd->dwStyle & WS_VISIBLE) )
601 listTop->hChild = 0;
602 (*iTotal)--;
605 return listTop;
608 /**********************************************************************
609 * MDICascade
611 LONG MDICascade(HWND parent, MDICLIENTINFO *ci)
613 WND *clientWnd;
614 MDIWCL *listTop,*listPrev;
615 RECT rect;
616 int spacing, xsize, ysize;
617 int x, y;
618 int iToPosition = 0;
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;
630 dprintf_mdi(stddeb,
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,
633 spacing);
635 clientWnd = WIN_FindWndPtr( parent );
637 listTop = MDI_BuildWCL(clientWnd,&iToPosition);
639 if( !listTop ) return 0;
641 x = 0;
642 y = 0;
644 /* walk list and move windows */
645 while ( listTop )
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);
655 x += spacing;
656 y += spacing;
659 listPrev = listTop->prev;
660 free(listTop);
661 listTop = listPrev;
664 return 0;
667 /**********************************************************************
668 * MDITile
671 LONG MDITile(HWND parent, MDICLIENTINFO *ci)
673 WND *wndClient = WIN_FindWndPtr(parent);
674 MDIWCL *listTop,*listPrev;
675 RECT rect;
676 int xsize, ysize;
677 int x, y;
678 int rows, columns;
679 int r, c;
680 int i;
681 int iToPosition = 0;
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 )
696 goto MDITile_free;
698 GetClientRect(parent, &rect);
700 rows = (int) sqrt((double) iToPosition);
701 columns = iToPosition / rows;
703 /* hack */
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;
713 x = 0;
714 i = 0;
716 for (c = 1; c <= columns; c++)
718 if (c == columns)
720 rows = iToPosition - i;
721 ysize = rect.bottom / rows;
724 y = 0;
725 for (r = 1; r <= rows; r++, i++)
727 /* shouldn't happen but... */
728 if( !listTop )
729 break;
731 if( listTop->hChild )
733 SetWindowPos(listTop->hChild, 0, x, y, xsize, ysize,
734 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
735 y += ysize;
738 listPrev = listTop->prev;
739 free(listTop);
740 listTop = listPrev;
743 x += xsize;
746 MDITile_free:
747 /* free the rest if any */
748 while( listTop ) {
749 listPrev = listTop->prev;
750 free(listTop);
751 listTop = listPrev; }
753 return 0;
756 /**********************************************************************
757 * MDIHandleLButton
759 BOOL MDIHandleLButton(HWND hwndFrame, HWND hwndClient,
760 WORD wParam, LONG lParam)
762 MDICLIENTINFO *ci;
763 WND *w;
764 RECT rect;
765 WORD x;
767 w = WIN_FindWndPtr(hwndClient);
768 ci = (MDICLIENTINFO *) w->wExtra;
770 if (wParam == HTMENU && ci->flagChildMaximized)
772 x = LOWORD(lParam);
774 NC_GetInsideRect(hwndFrame, &rect);
775 if (x < rect.left + SYSMETRICS_CXSIZE)
777 SendMessage(ci->hwndActiveChild, WM_SYSCOMMAND,
778 SC_CLOSE, lParam);
779 return TRUE;
781 else if (x >= rect.right - SYSMETRICS_CXSIZE)
783 SendMessage(ci->hwndActiveChild, WM_SYSCOMMAND,
784 SC_RESTORE, lParam);
785 return TRUE;
789 return FALSE;
792 /**********************************************************************
793 * MDIPaintMaximized
795 LONG MDIPaintMaximized(HWND hwndFrame, HWND hwndClient, WORD message,
796 WORD wParam, LONG lParam)
798 static HBITMAP hbitmapClose = 0;
799 static HBITMAP hbitmapMaximized = 0;
801 MDICLIENTINFO *ci;
802 WND *w;
803 HDC hdc, hdcMem;
804 RECT rect;
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);
819 if (!hdc) return 0;
821 hdcMem = CreateCompatibleDC(hdc);
823 if (hbitmapClose == 0)
825 hbitmapClose = LoadBitmap(0, MAKEINTRESOURCE(OBM_OLD_CLOSE));
826 hbitmapMaximized = LoadBitmap(0, MAKEINTRESOURCE(OBM_RESTORE));
829 dprintf_mdi(stddeb,
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);
857 DeleteDC(hdcMem);
858 ReleaseDC(hwndFrame, hdc);
860 else
861 return DefWindowProc(hwndFrame, message, wParam, lParam);
863 return 0;
866 /**********************************************************************
867 * MDIClientWndProc
869 * This function is the handler for all MDI requests.
871 LRESULT MDIClientWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
873 LPCREATESTRUCT cs;
874 LPCLIENTCREATESTRUCT ccs;
875 MDICLIENTINFO *ci;
876 WND *w;
878 w = WIN_FindWndPtr(hwnd);
879 ci = (MDICLIENTINFO *) w->wExtra;
881 switch (message)
883 case WM_CREATE:
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;
889 ci->sbStop = 0;
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);
899 return 0;
901 case WM_MDIACTIVATE:
902 SetWindowPos((HWND)wParam,0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
903 return 0;
905 case WM_MDICASCADE:
906 return MDICascade(hwnd, ci);
908 case WM_MDICREATE:
909 return (LONG)MDICreateChild(w, ci, hwnd, lParam );
911 case WM_MDIDESTROY:
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:
919 ci->sbStop = TRUE;
920 MDIIconArrange(hwnd);
921 ci->sbStop = FALSE;
922 SendMessage(hwnd,WM_MDICALCCHILDSCROLL,0,0L);
923 return 0;
925 case WM_MDIMAXIMIZE:
926 return MDIMaximizeChild(hwnd, (HWND)wParam, ci);
928 case WM_MDINEXT:
929 MDI_SwitchActiveChild(hwnd, (HWND)wParam, lParam);
930 break;
932 case WM_MDIRESTORE:
933 return MDIRestoreChild(hwnd, ci);
935 case WM_MDISETMENU:
936 #ifdef WINELIB32
937 return (LRESULT)MDISetMenu(hwnd, FALSE, (HMENU)wParam, (HMENU)lParam);
938 #else
939 return (LRESULT)MDISetMenu(hwnd, wParam, LOWORD(lParam), HIWORD(lParam));
940 #endif
942 case WM_MDITILE:
943 ci->sbStop = TRUE;
944 ShowScrollBar(hwnd,SB_BOTH,FALSE);
945 MDITile(hwnd, ci);
946 ci->sbStop = FALSE;
947 return 0;
949 case WM_VSCROLL:
950 case WM_HSCROLL:
951 ci->sbStop = TRUE;
952 ScrollChildren(hwnd,message,wParam,lParam);
953 ci->sbStop = FALSE;
954 return 0;
956 case WM_SETFOCUS:
957 if( ci->hwndActiveChild )
959 w = WIN_FindWndPtr( ci->hwndActiveChild );
960 if( !(w->dwStyle & WS_MINIMIZE) )
961 SetFocus( ci->hwndActiveChild );
963 return 0;
965 case WM_NCACTIVATE:
966 if( ci->hwndActiveChild )
967 SendMessage(ci->hwndActiveChild, message, wParam, lParam);
968 break;
970 case WM_PARENTNOTIFY:
971 if (wParam == WM_LBUTTONDOWN)
972 SetWindowPos(ci->hwndHitTest, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
973 break;
975 case WM_SIZE:
976 GetClientRect(w->hwndParent, &ci->rectMaximize);
977 if( !ci->hwndActiveChild )
979 PostMessage(hwnd,WM_MDICALCCHILDSCROLL,0,0L);
980 ci->sbRecalc |= (SB_BOTH+1);
982 break;
984 case WM_MDICALCCHILDSCROLL:
985 if( !ci->sbStop )
986 if( ci->sbRecalc )
988 CalcChildScroll(hwnd, ci->sbRecalc-1);
989 ci->sbRecalc = 0;
991 return 0;
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)
1004 HWND childHwnd;
1006 if (hwndMDIClient)
1008 switch (message)
1010 case WM_COMMAND:
1011 childHwnd = MDI_GetChildByID( WIN_FindWndPtr(hwndMDIClient),
1012 wParam );
1013 if( childHwnd )
1014 #ifdef WINELIB32 /* FIXME: need to find out the equivalent Win32 message */
1015 SendMessage(hwndMDIClient, WM_MDIACTIVATE, 0 , 0);
1016 #else
1017 SendMessage(hwndMDIClient, WM_MDIACTIVATE, childHwnd , 0L);
1018 #endif
1019 break;
1021 case WM_NCLBUTTONDOWN:
1022 if (MDIHandleLButton(hwnd, hwndMDIClient, wParam, lParam))
1023 return 0;
1024 break;
1026 case WM_NCACTIVATE:
1027 SendMessage(hwndMDIClient, message, wParam, lParam);
1028 return MDIPaintMaximized(hwnd, hwndMDIClient,
1029 message, wParam, lParam);
1031 case WM_NCPAINT:
1032 return MDIPaintMaximized(hwnd, hwndMDIClient,
1033 message, wParam, lParam);
1035 case WM_SETFOCUS:
1036 SetFocus(hwndMDIClient);
1037 break;
1039 case WM_SIZE:
1040 MoveWindow(hwndMDIClient, 0, 0,
1041 LOWORD(lParam), HIWORD(lParam), TRUE);
1042 break;
1046 return DefWindowProc(hwnd, message, wParam, lParam);
1049 /**********************************************************************
1050 * DefMDIChildProc (USER.447)
1053 #ifdef WINELIB32
1054 LONG DefMDIChildProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1055 #else
1056 LONG DefMDIChildProc(HWND hwnd, WORD message, WORD wParam, LONG lParam)
1057 #endif
1059 MDICLIENTINFO *ci;
1060 WND *clientWnd;
1062 clientWnd = WIN_FindWndPtr(GetParent(hwnd));
1063 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1065 switch (message)
1067 case WM_NCHITTEST:
1068 ci->hwndHitTest = hwnd;
1069 break;
1071 case WM_SETTEXT:
1072 DefWindowProc(hwnd, message, wParam, lParam);
1073 MDI_MenuModifyItem(clientWnd,hwnd);
1074 return 0;
1076 case WM_CLOSE:
1077 SendMessage(GetParent(hwnd),WM_MDIDESTROY,(WPARAM)hwnd,0L);
1078 return 0;
1080 case WM_SIZE:
1081 if( ci->hwndActiveChild != hwnd )
1082 MDI_ChildActivate(clientWnd, hwnd);
1083 break;
1085 case WM_CHILDACTIVATE:
1086 MDI_ChildActivate(clientWnd, hwnd);
1087 return 0;
1089 case WM_NCPAINT:
1090 dprintf_mdi(stddeb,"DefMDIChildProc: WM_NCPAINT for "NPFMT", active "NPFMT"\n",
1091 hwnd, ci->hwndActiveChild );
1092 break;
1094 case WM_SYSCOMMAND:
1095 switch (wParam)
1097 case SC_MAXIMIZE:
1098 return SendMessage(GetParent(hwnd), WM_MDIMAXIMIZE, (WPARAM)hwnd, 0);
1100 case SC_RESTORE:
1101 return SendMessage(GetParent(hwnd), WM_MDIRESTORE, (WPARAM)hwnd, 0);
1103 break;
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 */
1111 case WM_SETVISIBLE:
1112 if( !ci->sbStop )
1114 PostMessage(GetParent(hwnd),WM_MDICALCCHILDSCROLL,0,0L);
1115 ci->sbRecalc |= (SB_BOTH+1);
1117 break;
1118 case WM_SETFOCUS:
1119 if( IsChild( GetActiveWindow(), GetParent(hwnd)) )
1120 SendMessage(clientWnd->hwndChild,WM_CHILDACTIVATE,0,0L);
1121 if( !ci->sbStop )
1123 PostMessage(GetParent(hwnd),WM_MDICALCCHILDSCROLL,0,0L);
1124 ci->sbRecalc |= (SB_BOTH+1);
1126 break;
1128 case WM_MENUCHAR:
1129 case WM_NEXTMENU:
1130 /* set current menu to child system menu */
1132 break;
1135 return DefWindowProc(hwnd, message, wParam, lParam);
1138 /**********************************************************************
1139 * TranslateMDISysAccel (USER.451)
1142 BOOL TranslateMDISysAccel(HWND hwndClient, LPMSG msg)
1144 return 0;
1148 /***********************************************************************
1149 * CalcChildScroll (USER.462)
1151 void CalcChildScroll( HWND hwnd, WORD scroll )
1153 RECT childRect, clientRect;
1154 HWND hwndChild;
1156 GetClientRect( hwnd, &clientRect );
1157 SetRectEmpty( &childRect );
1158 hwndChild = GetWindow( hwnd, GW_CHILD );
1159 while (hwndChild)
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);
1187 short newPos=-1;
1188 short curPos;
1189 short length;
1190 INT minPos;
1191 INT maxPos;
1192 short shift;
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;
1210 else return;
1212 switch( wParam )
1214 case SB_LINEUP:
1215 newPos = curPos - shift;
1216 break;
1217 case SB_LINEDOWN:
1218 newPos = curPos + shift;
1219 break;
1220 case SB_PAGEUP:
1221 newPos = curPos - length;
1222 break;
1223 case SB_PAGEDOWN:
1224 newPos = curPos + length;
1225 break;
1227 case SB_THUMBPOSITION:
1228 newPos = LOWORD(lParam);
1229 break;
1231 case SB_THUMBTRACK:
1232 return;
1234 case SB_TOP:
1235 newPos = minPos;
1236 break;
1237 case SB_BOTTOM:
1238 newPos = maxPos;
1239 break;
1240 case SB_ENDSCROLL:
1241 CalcChildScroll(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
1242 return;
1245 if( newPos > maxPos )
1246 newPos = maxPos;
1247 else if( newPos < minPos )
1248 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);
1254 else
1255 ScrollWindow(hWnd ,curPos - newPos, 0, NULL, NULL);