Paper size and orientation prop sheet for wineps.
[wine.git] / windows / mdi.c
blob2fb8409e518997bf74d9b596aaa7ac1bac9600ab
1 /* MDI.C
3 * Copyright 1994, Bob Amstadt
4 * 1995,1996 Alex Korobka
6 * This file contains routines to support MDI (Multiple Document
7 * Interface) features .
9 * Notes: Fairly complete implementation.
10 * Also, Excel and WinWord do _not_ use MDI so if you're trying
11 * to fix them look elsewhere.
13 * Notes on how the "More Windows..." is implemented:
15 * When we have more than 9 opened windows, a "More Windows..."
16 * option appears in the "Windows" menu. Each child window has
17 * a WND* associated with it, accesible via the children list of
18 * the parent window. This WND* has a wIDmenu member, which reflects
19 * the position of the child in the window list. For example, with
20 * 9 child windows, we could have the following pattern:
24 * Name of the child window pWndChild->wIDmenu
25 * Doc1 5000
26 * Doc2 5001
27 * Doc3 5002
28 * Doc4 5003
29 * Doc5 5004
30 * Doc6 5005
31 * Doc7 5006
32 * Doc8 5007
33 * Doc9 5008
36 * The "Windows" menu, as the "More windows..." dialog, are constructed
37 * in this order. If we add a child, we would have the following list:
40 * Name of the child window pWndChild->wIDmenu
41 * Doc1 5000
42 * Doc2 5001
43 * Doc3 5002
44 * Doc4 5003
45 * Doc5 5004
46 * Doc6 5005
47 * Doc7 5006
48 * Doc8 5007
49 * Doc9 5008
50 * Doc10 5009
52 * But only 5000 to 5008 would be displayed in the "Windows" menu. We want
53 * the last created child to be in the menu, so we swap the last child with
54 * the 9th... Doc9 will be accessible via the "More Windows..." option.
56 * Doc1 5000
57 * Doc2 5001
58 * Doc3 5002
59 * Doc4 5003
60 * Doc5 5004
61 * Doc6 5005
62 * Doc7 5006
63 * Doc8 5007
64 * Doc9 5009
65 * Doc10 5008
69 #include <stdlib.h>
70 #include <stdio.h>
71 #include <string.h>
72 #include <math.h>
73 #include "windef.h"
74 #include "wingdi.h"
75 #include "winuser.h"
76 #include "wine/unicode.h"
77 #include "win.h"
78 #include "heap.h"
79 #include "nonclient.h"
80 #include "mdi.h"
81 #include "user.h"
82 #include "menu.h"
83 #include "scroll.h"
84 #include "struct32.h"
85 #include "tweak.h"
86 #include "debugtools.h"
87 #include "dlgs.h"
89 DEFAULT_DEBUG_CHANNEL(mdi);
91 #define MDIF_NEEDUPDATE 0x0001
93 static HBITMAP16 hBmpClose = 0;
94 static HBITMAP16 hBmpRestore = 0;
96 /* ----------------- declarations ----------------- */
97 static void MDI_UpdateFrameText(WND *, HWND, BOOL, LPCWSTR);
98 static BOOL MDI_AugmentFrameMenu(MDICLIENTINFO*, WND *, HWND);
99 static BOOL MDI_RestoreFrameMenu(WND *, HWND);
101 static LONG MDI_ChildActivate( WND*, HWND );
103 static HWND MDI_MoreWindowsDialog(WND*);
104 static void MDI_SwapMenuItems(WND *, UINT, UINT);
105 /* -------- Miscellaneous service functions ----------
107 * MDI_GetChildByID
110 static HWND MDI_GetChildByID(WND* wndPtr, INT id)
112 for (wndPtr = wndPtr->child; wndPtr; wndPtr = wndPtr->next)
113 if (wndPtr->wIDmenu == id) return wndPtr->hwndSelf;
114 return 0;
117 static void MDI_PostUpdate(HWND hwnd, MDICLIENTINFO* ci, WORD recalc)
119 if( !(ci->mdiFlags & MDIF_NEEDUPDATE) )
121 ci->mdiFlags |= MDIF_NEEDUPDATE;
122 PostMessageA( hwnd, WM_MDICALCCHILDSCROLL, 0, 0);
124 ci->sbRecalc = recalc;
127 /**********************************************************************
128 * MDI_MenuModifyItem
130 static BOOL MDI_MenuModifyItem(WND* clientWnd, HWND hWndChild )
132 WCHAR buffer[128];
133 static const WCHAR format[] = {'%','d',' ',0};
134 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
135 WND *wndPtr = WIN_FindWndPtr(hWndChild);
136 UINT n = wsprintfW(buffer, format,
137 wndPtr->wIDmenu - clientInfo->idFirstChild + 1);
138 BOOL bRet = 0;
140 if( !clientInfo->hWindowMenu )
142 bRet = FALSE;
143 goto END;
146 if (wndPtr->text) lstrcpynW(buffer + n, wndPtr->text, sizeof(buffer)/sizeof(WCHAR) - n );
148 n = GetMenuState(clientInfo->hWindowMenu,wndPtr->wIDmenu ,MF_BYCOMMAND);
149 bRet = ModifyMenuW(clientInfo->hWindowMenu , wndPtr->wIDmenu,
150 MF_BYCOMMAND | MF_STRING, wndPtr->wIDmenu, buffer );
151 CheckMenuItem(clientInfo->hWindowMenu ,wndPtr->wIDmenu , n & MF_CHECKED);
152 END:
153 WIN_ReleaseWndPtr(wndPtr);
154 return bRet;
157 /**********************************************************************
158 * MDI_MenuDeleteItem
160 static BOOL MDI_MenuDeleteItem(WND* clientWnd, HWND hWndChild )
162 WCHAR buffer[128];
163 static const WCHAR format[] = {'&','%','d',' ',0};
164 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
165 WND *wndPtr = WIN_FindWndPtr(hWndChild);
166 UINT index = 0,id,n;
167 BOOL retvalue;
169 if( !clientInfo->nActiveChildren ||
170 !clientInfo->hWindowMenu )
172 retvalue = FALSE;
173 goto END;
176 id = wndPtr->wIDmenu;
177 DeleteMenu(clientInfo->hWindowMenu,id,MF_BYCOMMAND);
179 /* walk the rest of MDI children to prevent gaps in the id
180 * sequence and in the menu child list */
182 for( index = id+1; index <= clientInfo->nActiveChildren +
183 clientInfo->idFirstChild; index++ )
185 WND *tmpWnd = WIN_FindWndPtr(MDI_GetChildByID(clientWnd,index));
186 if( !tmpWnd )
188 TRACE("no window for id=%i\n",index);
189 WIN_ReleaseWndPtr(tmpWnd);
190 continue;
193 /* set correct id */
194 tmpWnd->wIDmenu--;
196 n = wsprintfW(buffer, format ,index - clientInfo->idFirstChild);
197 if (tmpWnd->text)
198 lstrcpynW(buffer + n, tmpWnd->text, sizeof(buffer)/sizeof(WCHAR) - n );
200 /* change menu if the current child is to be shown in the
201 * "Windows" menu
203 if (index <= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
204 ModifyMenuW(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING,
205 index - 1 , buffer );
206 WIN_ReleaseWndPtr(tmpWnd);
209 /* We must restore the "More Windows..." option if there is enough child
211 if (clientInfo->nActiveChildren - 1 > MDI_MOREWINDOWSLIMIT)
213 char szTmp[50];
214 LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
216 AppendMenuA(clientInfo->hWindowMenu ,MF_STRING ,clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT, szTmp );
218 retvalue = TRUE;
219 END:
220 WIN_ReleaseWndPtr(wndPtr);
221 return retvalue;
224 /**********************************************************************
225 * MDI_GetWindow
227 * returns "activateable" child different from the current or zero
229 static HWND MDI_GetWindow(WND *clientWnd, HWND hWnd, BOOL bNext,
230 DWORD dwStyleMask )
232 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
233 WND *wndPtr, *pWnd, *pWndLast = NULL;
235 dwStyleMask |= WS_DISABLED | WS_VISIBLE;
236 if( !hWnd ) hWnd = clientInfo->hwndActiveChild;
238 if( !(wndPtr = WIN_FindWndPtr(hWnd)) ) return 0;
240 for ( pWnd = WIN_LockWndPtr(wndPtr->next); ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
242 if (!pWnd ) WIN_UpdateWndPtr(&pWnd,wndPtr->parent->child);
244 if ( pWnd == wndPtr ) break; /* went full circle */
246 if (!pWnd->owner && (pWnd->dwStyle & dwStyleMask) == WS_VISIBLE )
248 pWndLast = pWnd;
249 if ( bNext ) break;
252 WIN_ReleaseWndPtr(wndPtr);
253 WIN_ReleaseWndPtr(pWnd);
254 return pWndLast ? pWndLast->hwndSelf : 0;
257 /**********************************************************************
258 * MDI_CalcDefaultChildPos
260 * It seems that the default height is about 2/3 of the client rect
262 static void MDI_CalcDefaultChildPos( WND* w, WORD n, LPPOINT lpPos,
263 INT delta)
265 INT nstagger;
266 RECT rect = w->rectClient;
267 INT spacing = GetSystemMetrics(SM_CYCAPTION) +
268 GetSystemMetrics(SM_CYFRAME) - 1;
270 if( rect.bottom - rect.top - delta >= spacing )
271 rect.bottom -= delta;
273 nstagger = (rect.bottom - rect.top)/(3 * spacing);
274 lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
275 lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
276 lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
279 /**********************************************************************
280 * MDISetMenu
282 static LRESULT MDISetMenu( HWND hwnd, HMENU hmenuFrame,
283 HMENU hmenuWindow)
285 WND *w;
286 MDICLIENTINFO *ci;
287 HWND hwndFrame = GetParent(hwnd);
288 HMENU oldFrameMenu = GetMenu(hwndFrame);
290 TRACE("%04x %04x %04x\n",
291 hwnd, hmenuFrame, hmenuWindow);
293 if (hmenuFrame && !IsMenu(hmenuFrame))
295 WARN("hmenuFrame is not a menu handle\n");
296 return 0L;
299 if (hmenuWindow && !IsMenu(hmenuWindow))
301 WARN("hmenuWindow is not a menu handle\n");
302 return 0L;
305 w = WIN_FindWndPtr(hwnd);
306 ci = (MDICLIENTINFO *) w->wExtra;
308 if( ci->hwndChildMaximized && hmenuFrame && hmenuFrame!=oldFrameMenu )
309 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized );
311 if( hmenuWindow && ci->hWindowMenu && hmenuWindow!=ci->hWindowMenu )
313 /* delete menu items from ci->hWindowMenu
314 * and add them to hmenuWindow */
316 INT i = GetMenuItemCount(ci->hWindowMenu) - 1;
317 INT pos = GetMenuItemCount(hmenuWindow) + 1;
319 AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL);
321 if( ci->nActiveChildren )
323 INT j;
324 LPWSTR buffer = NULL;
325 MENUITEMINFOW mii;
326 INT nbWindowsMenuItems; /* num of documents shown + "More Windows..." if present */
328 if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
329 nbWindowsMenuItems = ci->nActiveChildren;
330 else
331 nbWindowsMenuItems = MDI_MOREWINDOWSLIMIT + 1;
333 j = i - nbWindowsMenuItems + 1;
335 for( ; i >= j ; i-- )
337 memset(&mii, 0, sizeof(mii));
338 mii.cbSize = sizeof(mii);
339 mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE
340 | MIIM_SUBMENU | MIIM_TYPE | MIIM_BITMAP;
342 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
343 if(mii.cch) { /* Menu is MFT_STRING */
344 mii.cch++; /* add room for '\0' */
345 buffer = HeapAlloc(GetProcessHeap(), 0,
346 mii.cch * sizeof(WCHAR));
347 mii.dwTypeData = buffer;
348 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
350 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
351 InsertMenuItemW(hmenuWindow, pos, TRUE, &mii);
352 if(buffer) {
353 HeapFree(GetProcessHeap(), 0, buffer);
354 buffer = NULL;
359 /* remove separator */
360 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
362 ci->hWindowMenu = hmenuWindow;
365 if (hmenuFrame)
367 SetMenu(hwndFrame, hmenuFrame);
368 if( hmenuFrame!=oldFrameMenu )
370 if( ci->hwndChildMaximized )
371 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
372 WIN_ReleaseWndPtr(w);
373 return oldFrameMenu;
376 else
378 INT nItems = GetMenuItemCount(w->parent->wIDmenu) - 1;
379 UINT iId = GetMenuItemID(w->parent->wIDmenu,nItems) ;
381 if( !(iId == SC_RESTORE || iId == SC_CLOSE) )
383 /* SetMenu() may already have been called, meaning that this window
384 * already has its menu. But they may have done a SetMenu() on
385 * an MDI window, and called MDISetMenu() after the fact, meaning
386 * that the "if" to this "else" wouldn't catch the need to
387 * augment the frame menu.
389 if( ci->hwndChildMaximized )
390 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
393 WIN_ReleaseWndPtr(w);
394 return 0;
397 /**********************************************************************
398 * MDIRefreshMenu
400 static LRESULT MDIRefreshMenu( HWND hwnd, HMENU hmenuFrame,
401 HMENU hmenuWindow)
403 HWND hwndFrame = GetParent(hwnd);
404 HMENU oldFrameMenu = GetMenu(hwndFrame);
406 TRACE("%04x %04x %04x\n",
407 hwnd, hmenuFrame, hmenuWindow);
409 FIXME("partially function stub\n");
411 return oldFrameMenu;
415 /* ------------------ MDI child window functions ---------------------- */
418 /**********************************************************************
419 * MDICreateChild
421 static HWND MDICreateChild( WND *w, MDICLIENTINFO *ci, HWND parent,
422 LPMDICREATESTRUCTA cs )
424 POINT pos[2];
425 DWORD style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
426 HWND hwnd, hwndMax = 0;
427 WORD wIDmenu = ci->idFirstChild + ci->nActiveChildren;
428 char lpstrDef[]="junk!";
430 TRACE("origin %i,%i - dim %i,%i, style %08lx\n",
431 cs->x, cs->y, cs->cx, cs->cy, cs->style);
432 /* calculate placement */
433 MDI_CalcDefaultChildPos(w, ci->nTotalCreated++, pos, 0);
435 if (cs->cx == CW_USEDEFAULT || !cs->cx) cs->cx = pos[1].x;
436 if (cs->cy == CW_USEDEFAULT || !cs->cy) cs->cy = pos[1].y;
438 if( cs->x == CW_USEDEFAULT )
440 cs->x = pos[0].x;
441 cs->y = pos[0].y;
444 /* restore current maximized child */
445 if( (style & WS_VISIBLE) && ci->hwndChildMaximized )
447 TRACE("Restoring current maximized child %04x\n", ci->hwndChildMaximized);
448 if( style & WS_MAXIMIZE )
449 SendMessageA(w->hwndSelf, WM_SETREDRAW, FALSE, 0L );
450 hwndMax = ci->hwndChildMaximized;
451 ShowWindow( hwndMax, SW_SHOWNOACTIVATE );
452 if( style & WS_MAXIMIZE )
453 SendMessageA(w->hwndSelf, WM_SETREDRAW, TRUE, 0L );
456 if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
457 /* this menu is needed to set a check mark in MDI_ChildActivate */
458 if (ci->hWindowMenu != 0)
459 AppendMenuA(ci->hWindowMenu ,MF_STRING ,wIDmenu, lpstrDef );
461 ci->nActiveChildren++;
463 /* fix window style */
464 if( !(w->dwStyle & MDIS_ALLCHILDSTYLES) )
466 TRACE("MDIS_ALLCHILDSTYLES is missing, fixing window style\n");
467 style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE |
468 WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL );
469 style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW);
472 if( w->flags & WIN_ISWIN32 )
474 hwnd = CreateWindowA( cs->szClass, cs->szTitle, style,
475 cs->x, cs->y, cs->cx, cs->cy, parent,
476 (HMENU)wIDmenu, cs->hOwner, cs );
478 else
480 MDICREATESTRUCT16 *cs16;
481 LPSTR title, cls;
483 cs16 = SEGPTR_NEW(MDICREATESTRUCT16);
484 STRUCT32_MDICREATESTRUCT32Ato16( cs, cs16 );
485 title = SEGPTR_STRDUP( cs->szTitle );
486 cls = SEGPTR_STRDUP( cs->szClass );
487 cs16->szTitle = SEGPTR_GET(title);
488 cs16->szClass = SEGPTR_GET(cls);
490 hwnd = CreateWindow16( cs->szClass, cs->szTitle, style,
491 cs16->x, cs16->y, cs16->cx, cs16->cy, parent,
492 (HMENU)wIDmenu, cs16->hOwner,
493 (LPVOID)SEGPTR_GET(cs16) );
494 SEGPTR_FREE( title );
495 SEGPTR_FREE( cls );
496 SEGPTR_FREE( cs16 );
499 /* MDI windows are WS_CHILD so they won't be activated by CreateWindow */
501 if (hwnd)
503 WND* wnd = WIN_FindWndPtr( hwnd );
505 /* All MDI child windows have the WS_EX_MDICHILD style */
506 wnd->dwExStyle |= WS_EX_MDICHILD;
508 /* If we have more than 9 windows, we must insert the new one at the
509 * 9th position in order to see it in the "Windows" menu
511 if (ci->nActiveChildren > MDI_MOREWINDOWSLIMIT)
512 MDI_SwapMenuItems(wnd->parent, wnd->wIDmenu, ci->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
514 MDI_MenuModifyItem(w ,hwnd);
516 /* Have we hit the "More Windows..." limit? If so, we must
517 * add a "More Windows..." option
519 if (ci->nActiveChildren == MDI_MOREWINDOWSLIMIT + 1)
521 char szTmp[50];
522 LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
524 ModifyMenuA(ci->hWindowMenu,
525 ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
526 MF_BYCOMMAND | MF_STRING,
527 ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
528 szTmp);
531 if( (wnd->dwStyle & WS_MINIMIZE) && ci->hwndActiveChild )
533 TRACE("Minimizing created MDI child %04x\n", hwnd);
534 ShowWindow( hwnd, SW_SHOWMINNOACTIVE );
536 else
538 /* WS_VISIBLE is clear if a) the MDI client has
539 * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the
540 * MDICreateStruct. If so the created window is not shown nor
541 * activated.
543 if(wnd->dwStyle & WS_VISIBLE)
544 ShowWindow(hwnd, SW_SHOW);
546 WIN_ReleaseWndPtr(wnd);
547 TRACE("created child - %04x\n",hwnd);
549 else
551 ci->nActiveChildren--;
552 DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
553 if( IsWindow(hwndMax) )
554 ShowWindow(hwndMax, SW_SHOWMAXIMIZED);
557 return hwnd;
560 /**********************************************************************
561 * MDI_ChildGetMinMaxInfo
563 * Note: The rule here is that client rect of the maximized MDI child
564 * is equal to the client rect of the MDI client window.
566 static void MDI_ChildGetMinMaxInfo( WND* clientWnd, HWND hwnd,
567 MINMAXINFO16* lpMinMax )
569 WND* childWnd = WIN_FindWndPtr(hwnd);
570 RECT rect = clientWnd->rectClient;
572 MapWindowPoints( clientWnd->parent->hwndSelf,
573 ((MDICLIENTINFO*)clientWnd->wExtra)->self, (LPPOINT)&rect, 2);
574 AdjustWindowRectEx( &rect, childWnd->dwStyle, 0, childWnd->dwExStyle );
576 lpMinMax->ptMaxSize.x = rect.right -= rect.left;
577 lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
579 lpMinMax->ptMaxPosition.x = rect.left;
580 lpMinMax->ptMaxPosition.y = rect.top;
582 WIN_ReleaseWndPtr(childWnd);
584 TRACE("max rect (%i,%i - %i, %i)\n",
585 rect.left,rect.top,rect.right,rect.bottom);
589 /**********************************************************************
590 * MDI_SwitchActiveChild
592 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
593 * being activated
595 static void MDI_SwitchActiveChild( HWND clientHwnd, HWND childHwnd,
596 BOOL bNextWindow )
598 WND *w = WIN_FindWndPtr(clientHwnd);
599 HWND hwndTo = 0;
600 HWND hwndPrev = 0;
601 MDICLIENTINFO *ci;
603 hwndTo = MDI_GetWindow(w, childHwnd, bNextWindow, 0);
605 ci = (MDICLIENTINFO *) w->wExtra;
607 TRACE("from %04x, to %04x\n",childHwnd,hwndTo);
609 if ( !hwndTo ) goto END; /* no window to switch to */
611 hwndPrev = ci->hwndActiveChild;
613 if ( hwndTo != hwndPrev )
615 BOOL bOptimize = 0;
617 if( ci->hwndChildMaximized )
619 bOptimize = 1;
620 w->dwStyle &= ~WS_VISIBLE;
623 SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0,
624 SWP_NOMOVE | SWP_NOSIZE );
626 if( bNextWindow && hwndPrev )
627 SetWindowPos( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0,
628 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
629 if( bOptimize )
630 ShowWindow( clientHwnd, SW_SHOW );
632 END:
633 WIN_ReleaseWndPtr(w);
637 /**********************************************************************
638 * MDIDestroyChild
640 static LRESULT MDIDestroyChild( WND *w_parent, MDICLIENTINFO *ci,
641 HWND parent, HWND child,
642 BOOL flagDestroy )
644 WND *childPtr = WIN_FindWndPtr(child);
646 if( childPtr )
648 if( child == ci->hwndActiveChild )
650 MDI_SwitchActiveChild(parent, child, TRUE);
652 if( child == ci->hwndActiveChild )
654 ShowWindow( child, SW_HIDE);
655 if( child == ci->hwndChildMaximized )
657 MDI_RestoreFrameMenu(w_parent->parent, child);
658 ci->hwndChildMaximized = 0;
659 MDI_UpdateFrameText(w_parent->parent,parent,TRUE,NULL);
662 MDI_ChildActivate(w_parent, 0);
666 MDI_MenuDeleteItem(w_parent, child);
668 WIN_ReleaseWndPtr(childPtr);
670 ci->nActiveChildren--;
672 TRACE("child destroyed - %04x\n",child);
674 if (flagDestroy)
676 MDI_PostUpdate(GetParent(child), ci, SB_BOTH+1);
677 DestroyWindow(child);
681 return 0;
685 /**********************************************************************
686 * MDI_ChildActivate
688 * Note: hWndChild is NULL when last child is being destroyed
690 static LONG MDI_ChildActivate( WND *clientPtr, HWND hWndChild )
692 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientPtr->wExtra;
693 HWND prevActiveWnd = clientInfo->hwndActiveChild;
694 WND *wndPtr = WIN_FindWndPtr( hWndChild );
695 WND *wndPrev = WIN_FindWndPtr( prevActiveWnd );
696 BOOL isActiveFrameWnd = 0;
697 LONG retvalue;
699 if( wndPtr )
701 if( wndPtr->dwStyle & WS_DISABLED )
703 retvalue = 0L;
704 goto END;
708 /* Don't activate if it is already active. Might happen
709 since ShowWindow DOES activate MDI children */
710 if (clientInfo->hwndActiveChild == hWndChild)
712 retvalue = 0L;
713 goto END;
716 TRACE("%04x\n", hWndChild);
718 if( GetActiveWindow() == clientPtr->parent->hwndSelf )
719 isActiveFrameWnd = TRUE;
721 /* deactivate prev. active child */
722 if( wndPrev )
724 wndPrev->dwStyle |= WS_SYSMENU;
725 SendMessageA( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
726 SendMessageA( prevActiveWnd, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
727 (LPARAM)hWndChild);
728 /* uncheck menu item */
729 if( clientInfo->hWindowMenu )
731 WORD wPrevID = wndPrev->wIDmenu - clientInfo->idFirstChild;
733 if (wPrevID < MDI_MOREWINDOWSLIMIT)
734 CheckMenuItem( clientInfo->hWindowMenu,
735 wndPrev->wIDmenu, 0);
736 else
737 CheckMenuItem( clientInfo->hWindowMenu,
738 clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1, 0);
742 /* set appearance */
743 if( clientInfo->hwndChildMaximized )
745 if( clientInfo->hwndChildMaximized != hWndChild ) {
746 if( hWndChild ) {
747 clientInfo->hwndActiveChild = hWndChild;
748 ShowWindow( hWndChild, SW_SHOWMAXIMIZED);
749 } else
750 ShowWindow( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
754 clientInfo->hwndActiveChild = hWndChild;
756 /* check if we have any children left */
757 if( !hWndChild )
759 if( isActiveFrameWnd )
760 SetFocus( clientInfo->self );
761 retvalue = 0;
762 goto END;
765 /* check menu item */
766 if( clientInfo->hWindowMenu )
768 /* The window to be activated must be displayed in the "Windows" menu */
769 if (wndPtr->wIDmenu >= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
771 MDI_SwapMenuItems(wndPtr->parent, wndPtr->wIDmenu, clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
772 MDI_MenuModifyItem(wndPtr->parent ,wndPtr->hwndSelf);
775 CheckMenuItem(clientInfo->hWindowMenu, wndPtr->wIDmenu, MF_CHECKED);
777 /* bring active child to the top */
778 SetWindowPos( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
780 if( isActiveFrameWnd )
782 SendMessageA( hWndChild, WM_NCACTIVATE, TRUE, 0L);
783 if( GetFocus() == clientInfo->self )
784 SendMessageA( clientInfo->self, WM_SETFOCUS,
785 (WPARAM)clientInfo->self, 0L );
786 else
787 SetFocus( clientInfo->self );
789 SendMessageA( hWndChild, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
790 (LPARAM)hWndChild );
791 retvalue = 1;
792 END:
793 WIN_ReleaseWndPtr(wndPtr);
794 WIN_ReleaseWndPtr(wndPrev);
795 return retvalue;
798 /* -------------------- MDI client window functions ------------------- */
800 /**********************************************************************
801 * CreateMDIMenuBitmap
803 static HBITMAP16 CreateMDIMenuBitmap(void)
805 HDC hDCSrc = CreateCompatibleDC(0);
806 HDC hDCDest = CreateCompatibleDC(hDCSrc);
807 HBITMAP16 hbClose = LoadBitmap16(0, MAKEINTRESOURCE16(OBM_CLOSE) );
808 HBITMAP16 hbCopy;
809 HANDLE16 hobjSrc, hobjDest;
811 hobjSrc = SelectObject(hDCSrc, hbClose);
812 hbCopy = CreateCompatibleBitmap(hDCSrc,GetSystemMetrics(SM_CXSIZE),GetSystemMetrics(SM_CYSIZE));
813 hobjDest = SelectObject(hDCDest, hbCopy);
815 BitBlt(hDCDest, 0, 0, GetSystemMetrics(SM_CXSIZE), GetSystemMetrics(SM_CYSIZE),
816 hDCSrc, GetSystemMetrics(SM_CXSIZE), 0, SRCCOPY);
818 SelectObject(hDCSrc, hobjSrc);
819 DeleteObject(hbClose);
820 DeleteDC(hDCSrc);
822 hobjSrc = SelectObject( hDCDest, GetStockObject(BLACK_PEN) );
824 MoveToEx( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, 0, NULL );
825 LineTo( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, GetSystemMetrics(SM_CYSIZE) - 1);
827 SelectObject(hDCDest, hobjSrc );
828 SelectObject(hDCDest, hobjDest);
829 DeleteDC(hDCDest);
831 return hbCopy;
834 /**********************************************************************
835 * MDICascade
837 static LONG MDICascade(WND* clientWnd, MDICLIENTINFO *ci)
839 WND** ppWnd;
840 UINT total;
842 if (ci->hwndChildMaximized)
843 SendMessageA( clientWnd->hwndSelf, WM_MDIRESTORE,
844 (WPARAM)ci->hwndChildMaximized, 0);
846 if (ci->nActiveChildren == 0) return 0;
848 if ((ppWnd = WIN_BuildWinArray(clientWnd, BWA_SKIPHIDDEN | BWA_SKIPOWNED |
849 BWA_SKIPICONIC, &total)))
851 WND** heapPtr = ppWnd;
852 if( total )
854 INT delta = 0, n = 0;
855 POINT pos[2];
856 if( total < ci->nActiveChildren )
857 delta = GetSystemMetrics(SM_CYICONSPACING) +
858 GetSystemMetrics(SM_CYICON);
860 /* walk the list (backwards) and move windows */
861 while (*ppWnd) ppWnd++;
862 while (ppWnd != heapPtr)
864 ppWnd--;
865 TRACE("move %04x to (%ld,%ld) size [%ld,%ld]\n",
866 (*ppWnd)->hwndSelf, pos[0].x, pos[0].y, pos[1].x, pos[1].y);
868 MDI_CalcDefaultChildPos(clientWnd, n++, pos, delta);
869 SetWindowPos( (*ppWnd)->hwndSelf, 0, pos[0].x, pos[0].y,
870 pos[1].x, pos[1].y,
871 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
874 WIN_ReleaseWinArray(heapPtr);
877 if( total < ci->nActiveChildren )
878 ArrangeIconicWindows( clientWnd->hwndSelf );
879 return 0;
882 /**********************************************************************
883 * MDITile
885 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM wParam )
887 WND** ppWnd;
888 UINT total = 0;
890 if (ci->hwndChildMaximized)
891 SendMessageA( wndClient->hwndSelf, WM_MDIRESTORE,
892 (WPARAM)ci->hwndChildMaximized, 0);
894 if (ci->nActiveChildren == 0) return;
896 ppWnd = WIN_BuildWinArray(wndClient, BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
897 ((wParam & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
899 TRACE("%u windows to tile\n", total);
901 if( ppWnd )
903 WND** heapPtr = ppWnd;
905 if( total )
907 RECT rect;
908 int x, y, xsize, ysize;
909 int rows, columns, r, c, i;
911 GetClientRect(wndClient->hwndSelf,&rect);
912 rows = (int) sqrt((double)total);
913 columns = total / rows;
915 if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */
917 i = rows;
918 rows = columns; /* exchange r and c */
919 columns = i;
922 if( total != ci->nActiveChildren)
924 y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
925 rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
928 ysize = rect.bottom / rows;
929 xsize = rect.right / columns;
931 for (x = i = 0, c = 1; c <= columns && *ppWnd; c++)
933 if (c == columns)
935 rows = total - i;
936 ysize = rect.bottom / rows;
939 y = 0;
940 for (r = 1; r <= rows && *ppWnd; r++, i++)
942 SetWindowPos((*ppWnd)->hwndSelf, 0, x, y, xsize, ysize,
943 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
944 y += ysize;
945 ppWnd++;
947 x += xsize;
950 WIN_ReleaseWinArray(heapPtr);
953 if( total < ci->nActiveChildren ) ArrangeIconicWindows( wndClient->hwndSelf );
956 /* ----------------------- Frame window ---------------------------- */
959 /**********************************************************************
960 * MDI_AugmentFrameMenu
962 static BOOL MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
963 HWND hChild )
965 WND* child = WIN_FindWndPtr(hChild);
966 HMENU hSysPopup = 0;
967 HBITMAP hSysMenuBitmap = 0;
969 TRACE("frame %p,child %04x\n",frame,hChild);
971 if( !frame->wIDmenu || !child->hSysMenu )
973 WIN_ReleaseWndPtr(child);
974 return 0;
976 WIN_ReleaseWndPtr(child);
978 /* create a copy of sysmenu popup and insert it into frame menu bar */
980 if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
981 return 0;
983 TRACE("\tgot popup %04x in sysmenu %04x\n",
984 hSysPopup, child->hSysMenu);
986 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
987 SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
988 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
989 SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
991 /* In Win 95 look, the system menu is replaced by the child icon */
993 if(TWEAK_WineLook > WIN31_LOOK)
995 HICON hIcon = GetClassLongA(hChild, GCL_HICONSM);
996 if (!hIcon)
997 hIcon = GetClassLongA(hChild, GCL_HICON);
998 if (hIcon)
1000 HDC hMemDC;
1001 HBITMAP hBitmap, hOldBitmap;
1002 HBRUSH hBrush;
1003 HDC hdc = GetDC(hChild);
1005 if (hdc)
1007 int cx, cy;
1008 cx = GetSystemMetrics(SM_CXSMICON);
1009 cy = GetSystemMetrics(SM_CYSMICON);
1010 hMemDC = CreateCompatibleDC(hdc);
1011 hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
1012 hOldBitmap = SelectObject(hMemDC, hBitmap);
1013 SetMapMode(hMemDC, MM_TEXT);
1014 hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
1015 DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL);
1016 SelectObject (hMemDC, hOldBitmap);
1017 DeleteObject(hBrush);
1018 DeleteDC(hMemDC);
1019 ReleaseDC(hChild, hdc);
1020 hSysMenuBitmap = hBitmap;
1024 else
1025 hSysMenuBitmap = hBmpClose;
1027 if( !InsertMenuA(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
1028 hSysPopup, (LPSTR)(DWORD)hSysMenuBitmap))
1030 TRACE("not inserted\n");
1031 DestroyMenu(hSysPopup);
1032 return 0;
1035 /* The close button is only present in Win 95 look */
1036 if(TWEAK_WineLook > WIN31_LOOK)
1038 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
1039 SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
1042 EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
1043 EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
1044 EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
1045 SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE);
1047 /* redraw menu */
1048 DrawMenuBar(frame->hwndSelf);
1050 return 1;
1053 /**********************************************************************
1054 * MDI_RestoreFrameMenu
1056 static BOOL MDI_RestoreFrameMenu( WND *frameWnd, HWND hChild )
1058 MENUITEMINFOA menuInfo;
1059 INT nItems = GetMenuItemCount(frameWnd->wIDmenu) - 1;
1060 UINT iId = GetMenuItemID(frameWnd->wIDmenu,nItems) ;
1062 TRACE("frameWnd %p,(%04x),child %04x,nIt=%d,iId=%d\n",
1063 frameWnd,frameWnd->hwndSelf,hChild,nItems,iId);
1065 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
1066 return 0;
1069 * Remove the system menu, If that menu is the icon of the window
1070 * as it is in win95, we have to delete the bitmap.
1072 menuInfo.cbSize = sizeof(MENUITEMINFOA);
1073 menuInfo.fMask = MIIM_DATA | MIIM_TYPE;
1075 GetMenuItemInfoA(frameWnd->wIDmenu,
1077 TRUE,
1078 &menuInfo);
1080 RemoveMenu(frameWnd->wIDmenu,0,MF_BYPOSITION);
1082 if ( (menuInfo.fType & MFT_BITMAP) &&
1083 (LOWORD(menuInfo.dwTypeData)!=0) &&
1084 (LOWORD(menuInfo.dwTypeData)!=hBmpClose) )
1086 DeleteObject((HBITMAP)LOWORD(menuInfo.dwTypeData));
1089 if(TWEAK_WineLook > WIN31_LOOK)
1091 /* close */
1092 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1094 /* restore */
1095 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1096 /* minimize */
1097 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1099 DrawMenuBar(frameWnd->hwndSelf);
1101 return 1;
1105 /**********************************************************************
1106 * MDI_UpdateFrameText
1108 * used when child window is maximized/restored
1110 * Note: lpTitle can be NULL
1112 static void MDI_UpdateFrameText( WND *frameWnd, HWND hClient,
1113 BOOL repaint, LPCWSTR lpTitle )
1115 WCHAR lpBuffer[MDI_MAXTITLELENGTH+1];
1116 WND* clientWnd = WIN_FindWndPtr(hClient);
1117 MDICLIENTINFO *ci = (MDICLIENTINFO *) clientWnd->wExtra;
1119 TRACE("repaint %i, frameText %s\n", repaint, (lpTitle)?debugstr_w(lpTitle):"NULL");
1121 if (!clientWnd)
1122 return;
1124 if (!ci)
1126 WIN_ReleaseWndPtr(clientWnd);
1127 return;
1130 /* store new "default" title if lpTitle is not NULL */
1131 if (lpTitle)
1133 if (ci->frameTitle) HeapFree( SystemHeap, 0, ci->frameTitle );
1134 ci->frameTitle = HEAP_strdupW( SystemHeap, 0, lpTitle );
1137 if (ci->frameTitle)
1139 WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );
1141 if( childWnd && childWnd->text )
1143 /* combine frame title and child title if possible */
1145 static const WCHAR lpBracket[] = {' ','-',' ','[',0};
1146 static const WCHAR lpBracket2[] = {']',0};
1147 int i_frame_text_length = strlenW(ci->frameTitle);
1148 int i_child_text_length = strlenW(childWnd->text);
1150 lstrcpynW( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
1152 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
1154 strcatW( lpBuffer, lpBracket );
1156 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
1158 strcatW( lpBuffer, childWnd->text );
1159 strcatW( lpBuffer, lpBracket2 );
1161 else
1163 lstrcpynW( lpBuffer + i_frame_text_length + 4,
1164 childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
1165 strcatW( lpBuffer, lpBracket2 );
1169 else
1171 lstrcpynW(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH+1 );
1173 WIN_ReleaseWndPtr(childWnd);
1176 else
1177 lpBuffer[0] = '\0';
1179 DEFWND_SetTextW( frameWnd, lpBuffer );
1180 if( repaint == MDI_REPAINTFRAME)
1181 SetWindowPos( frameWnd->hwndSelf, 0,0,0,0,0, SWP_FRAMECHANGED |
1182 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
1184 WIN_ReleaseWndPtr(clientWnd);
1189 /* ----------------------------- Interface ---------------------------- */
1192 /**********************************************************************
1193 * MDIClientWndProc
1195 * This function handles all MDI requests.
1197 LRESULT WINAPI MDIClientWndProc( HWND hwnd, UINT message, WPARAM wParam,
1198 LPARAM lParam )
1200 LPCREATESTRUCTA cs;
1201 MDICLIENTINFO *ci;
1202 RECT rect;
1203 WND *w, *frameWnd;
1204 INT nItems;
1205 LRESULT retvalue;
1207 if ( ( w = WIN_FindWndPtr(hwnd) ) == NULL )
1208 return 0;
1210 if ( ( frameWnd = WIN_LockWndPtr(w->parent) ) == NULL ) {
1211 WIN_ReleaseWndPtr(w);
1212 return 0;
1215 ci = (MDICLIENTINFO *) w->wExtra;
1217 switch (message)
1219 case WM_CREATE:
1221 cs = (LPCREATESTRUCTA)lParam;
1223 /* Translation layer doesn't know what's in the cs->lpCreateParams
1224 * so we have to keep track of what environment we're in. */
1226 if( w->flags & WIN_ISWIN32 )
1228 #define ccs ((LPCLIENTCREATESTRUCT)cs->lpCreateParams)
1229 ci->hWindowMenu = ccs->hWindowMenu;
1230 ci->idFirstChild = ccs->idFirstChild;
1231 #undef ccs
1233 else
1235 LPCLIENTCREATESTRUCT16 ccs = (LPCLIENTCREATESTRUCT16)
1236 PTR_SEG_TO_LIN(cs->lpCreateParams);
1237 ci->hWindowMenu = ccs->hWindowMenu;
1238 ci->idFirstChild = ccs->idFirstChild;
1241 ci->hwndChildMaximized = 0;
1242 ci->nActiveChildren = 0;
1243 ci->nTotalCreated = 0;
1244 ci->frameTitle = NULL;
1245 ci->mdiFlags = 0;
1246 ci->self = hwnd;
1247 w->dwStyle |= WS_CLIPCHILDREN;
1249 if (!hBmpClose)
1251 hBmpClose = CreateMDIMenuBitmap();
1252 hBmpRestore = LoadBitmap16( 0, MAKEINTRESOURCE16(OBM_RESTORE) );
1254 MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
1256 if (ci->hWindowMenu != 0)
1257 AppendMenuA( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
1259 GetClientRect(frameWnd->hwndSelf, &rect);
1260 NC_HandleNCCalcSize( w, &rect );
1261 w->rectClient = rect;
1263 TRACE("Client created - hwnd = %04x, idFirst = %u\n",
1264 hwnd, ci->idFirstChild );
1266 retvalue = 0;
1267 goto END;
1269 case WM_DESTROY:
1270 if( ci->hwndChildMaximized )
1271 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized);
1272 if((ci->hWindowMenu != 0) &&
1273 (nItems = GetMenuItemCount(ci->hWindowMenu)) > 0)
1275 ci->idFirstChild = nItems - 1;
1276 ci->nActiveChildren++; /* to delete a separator */
1277 while( ci->nActiveChildren-- )
1278 DeleteMenu(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
1280 retvalue = 0;
1281 goto END;
1283 case WM_MDIACTIVATE:
1284 if( ci->hwndActiveChild != (HWND)wParam )
1285 SetWindowPos((HWND)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
1286 retvalue = 0;
1287 goto END;
1289 case WM_MDICASCADE:
1290 retvalue = MDICascade(w, ci);
1291 goto END;
1293 case WM_MDICREATE:
1294 if (lParam) retvalue = MDICreateChild( w, ci, hwnd,
1295 (MDICREATESTRUCTA*)lParam );
1296 else retvalue = 0;
1297 goto END;
1299 case WM_MDIDESTROY:
1300 retvalue = MDIDestroyChild( w, ci, hwnd, (HWND)wParam, TRUE );
1301 goto END;
1303 case WM_MDIGETACTIVE:
1304 if (lParam) *(BOOL *)lParam = (ci->hwndChildMaximized > 0);
1305 retvalue = ci->hwndActiveChild;
1306 goto END;
1308 case WM_MDIICONARRANGE:
1309 ci->mdiFlags |= MDIF_NEEDUPDATE;
1310 ArrangeIconicWindows(hwnd);
1311 ci->sbRecalc = SB_BOTH+1;
1312 SendMessageA(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
1313 retvalue = 0;
1314 goto END;
1316 case WM_MDIMAXIMIZE:
1317 ShowWindow( (HWND)wParam, SW_MAXIMIZE );
1318 retvalue = 0;
1319 goto END;
1321 case WM_MDINEXT: /* lParam != 0 means previous window */
1322 MDI_SwitchActiveChild(hwnd, (HWND)wParam, (lParam)? FALSE : TRUE );
1323 break;
1325 case WM_MDIRESTORE:
1326 SendMessageA( (HWND)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
1327 retvalue = 0;
1328 goto END;
1330 case WM_MDISETMENU:
1331 retvalue = MDISetMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1332 goto END;
1333 case WM_MDIREFRESHMENU:
1334 retvalue = MDIRefreshMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1335 goto END;
1337 case WM_MDITILE:
1338 ci->mdiFlags |= MDIF_NEEDUPDATE;
1339 ShowScrollBar(hwnd,SB_BOTH,FALSE);
1340 MDITile(w, ci, wParam);
1341 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1342 retvalue = 0;
1343 goto END;
1345 case WM_VSCROLL:
1346 case WM_HSCROLL:
1347 ci->mdiFlags |= MDIF_NEEDUPDATE;
1348 ScrollChildren(hwnd, message, wParam, lParam);
1349 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1350 retvalue = 0;
1351 goto END;
1353 case WM_SETFOCUS:
1354 if( ci->hwndActiveChild )
1356 WND* pw = WIN_FindWndPtr( ci->hwndActiveChild );
1357 if( !(pw->dwStyle & WS_MINIMIZE) )
1358 SetFocus( ci->hwndActiveChild );
1359 WIN_ReleaseWndPtr(pw);
1361 retvalue = 0;
1362 goto END;
1364 case WM_NCACTIVATE:
1365 if( ci->hwndActiveChild )
1366 SendMessageA(ci->hwndActiveChild, message, wParam, lParam);
1367 break;
1369 case WM_PARENTNOTIFY:
1370 if (LOWORD(wParam) == WM_LBUTTONDOWN)
1372 POINT16 pt = MAKEPOINT16(lParam);
1373 HWND16 child = ChildWindowFromPoint16(hwnd, pt);
1375 TRACE("notification from %04x (%i,%i)\n",child,pt.x,pt.y);
1377 if( child && child != hwnd && child != ci->hwndActiveChild )
1378 SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1380 retvalue = 0;
1381 goto END;
1383 case WM_SIZE:
1384 if( IsWindow(ci->hwndChildMaximized) )
1386 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1387 RECT rect;
1389 rect.left = 0;
1390 rect.top = 0;
1391 rect.right = LOWORD(lParam);
1392 rect.bottom = HIWORD(lParam);
1394 AdjustWindowRectEx(&rect, child->dwStyle, 0, child->dwExStyle);
1395 MoveWindow(ci->hwndChildMaximized, rect.left, rect.top,
1396 rect.right - rect.left, rect.bottom - rect.top, 1);
1397 WIN_ReleaseWndPtr(child);
1399 else
1400 MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1402 break;
1404 case WM_MDICALCCHILDSCROLL:
1405 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1407 CalcChildScroll16(hwnd, ci->sbRecalc-1);
1408 ci->sbRecalc = 0;
1409 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1411 retvalue = 0;
1412 goto END;
1415 retvalue = DefWindowProcA( hwnd, message, wParam, lParam );
1416 END:
1417 WIN_ReleaseWndPtr(w);
1418 WIN_ReleaseWndPtr(frameWnd);
1419 return retvalue;
1423 /***********************************************************************
1424 * DefFrameProc16 (USER.445)
1426 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1427 UINT16 message, WPARAM16 wParam, LPARAM lParam )
1429 HWND16 childHwnd;
1430 MDICLIENTINFO* ci;
1431 WND* wndPtr;
1433 if (hwndMDIClient)
1435 switch (message)
1437 case WM_COMMAND:
1438 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1440 if (!wndPtr) {
1441 ERR("null wndPtr for mdi window hwndMDIClient=%04x\n",
1442 hwndMDIClient);
1443 return 0;
1446 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1448 /* check for possible syscommands for maximized MDI child */
1449 WIN_ReleaseWndPtr(wndPtr);
1451 if( ci && (
1452 wParam < ci->idFirstChild ||
1453 wParam >= ci->idFirstChild + ci->nActiveChildren
1455 if( (wParam - 0xF000) & 0xF00F ) break;
1456 switch( wParam )
1458 case SC_SIZE:
1459 case SC_MOVE:
1460 case SC_MINIMIZE:
1461 case SC_MAXIMIZE:
1462 case SC_NEXTWINDOW:
1463 case SC_PREVWINDOW:
1464 case SC_CLOSE:
1465 case SC_RESTORE:
1466 if( ci->hwndChildMaximized )
1467 return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1468 wParam, lParam);
1471 else
1473 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1474 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1476 if (wParam - ci->idFirstChild == MDI_MOREWINDOWSLIMIT)
1477 /* User chose "More Windows..." */
1478 childHwnd = MDI_MoreWindowsDialog(wndPtr);
1479 else
1480 /* User chose one of the windows listed in the "Windows" menu */
1481 childHwnd = MDI_GetChildByID(wndPtr,wParam );
1483 WIN_ReleaseWndPtr(wndPtr);
1484 if( childHwnd )
1485 SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1486 (WPARAM16)childHwnd , 0L);
1488 break;
1490 case WM_NCACTIVATE:
1491 SendMessage16(hwndMDIClient, message, wParam, lParam);
1492 break;
1494 case WM_SETTEXT:
1496 LPWSTR text = HEAP_strdupAtoW( GetProcessHeap(), 0,
1497 (LPCSTR)PTR_SEG_TO_LIN(lParam) );
1498 wndPtr = WIN_FindWndPtr(hwnd);
1499 MDI_UpdateFrameText(wndPtr, hwndMDIClient,
1500 MDI_REPAINTFRAME, text );
1501 WIN_ReleaseWndPtr(wndPtr);
1502 HeapFree( GetProcessHeap(), 0, text );
1504 return 0;
1506 case WM_SETFOCUS:
1507 SetFocus(hwndMDIClient);
1508 break;
1510 case WM_SIZE:
1511 MoveWindow16(hwndMDIClient, 0, 0,
1512 LOWORD(lParam), HIWORD(lParam), TRUE);
1513 break;
1515 case WM_NEXTMENU:
1517 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1518 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1520 if( !(wndPtr->parent->dwStyle & WS_MINIMIZE)
1521 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1523 /* control menu is between the frame system menu and
1524 * the first entry of menu bar */
1526 if( (wParam == VK_LEFT &&
1527 wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1528 (wParam == VK_RIGHT &&
1529 GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1531 LRESULT retvalue;
1532 WIN_ReleaseWndPtr(wndPtr);
1533 wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1534 retvalue = MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1535 ci->hwndActiveChild);
1536 WIN_ReleaseWndPtr(wndPtr);
1537 return retvalue;
1540 WIN_ReleaseWndPtr(wndPtr);
1541 break;
1545 return DefWindowProc16(hwnd, message, wParam, lParam);
1549 /***********************************************************************
1550 * DefFrameProcA (USER32.122)
1552 LRESULT WINAPI DefFrameProcA( HWND hwnd, HWND hwndMDIClient,
1553 UINT message, WPARAM wParam, LPARAM lParam)
1555 if (hwndMDIClient)
1557 switch (message)
1559 case WM_COMMAND:
1560 return DefFrameProc16( hwnd, hwndMDIClient, message,
1561 (WPARAM16)wParam,
1562 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1564 case WM_NCACTIVATE:
1565 SendMessageA(hwndMDIClient, message, wParam, lParam);
1566 break;
1568 case WM_SETTEXT: {
1569 LRESULT ret;
1570 LPSTR segstr = SEGPTR_STRDUP((LPSTR)lParam);
1572 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1573 wParam, (LPARAM)SEGPTR_GET(segstr) );
1574 SEGPTR_FREE(segstr);
1575 return ret;
1578 case WM_NEXTMENU:
1579 case WM_SETFOCUS:
1580 case WM_SIZE:
1581 return DefFrameProc16( hwnd, hwndMDIClient, message,
1582 wParam, lParam );
1586 return DefWindowProcA(hwnd, message, wParam, lParam);
1590 /***********************************************************************
1591 * DefFrameProcW (USER32.123)
1593 LRESULT WINAPI DefFrameProcW( HWND hwnd, HWND hwndMDIClient,
1594 UINT message, WPARAM wParam, LPARAM lParam)
1596 if (hwndMDIClient)
1598 switch (message)
1600 case WM_COMMAND:
1601 return DefFrameProc16( hwnd, hwndMDIClient, message,
1602 (WPARAM16)wParam,
1603 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1605 case WM_NCACTIVATE:
1606 SendMessageW(hwndMDIClient, message, wParam, lParam);
1607 break;
1609 case WM_SETTEXT:
1611 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1612 LRESULT ret = DefFrameProcA( hwnd, hwndMDIClient, message,
1613 wParam, (DWORD)txt );
1614 HeapFree(GetProcessHeap(),0,txt);
1615 return ret;
1617 case WM_NEXTMENU:
1618 case WM_SETFOCUS:
1619 case WM_SIZE:
1620 return DefFrameProcA( hwnd, hwndMDIClient, message,
1621 wParam, lParam );
1625 return DefWindowProcW( hwnd, message, wParam, lParam );
1629 /***********************************************************************
1630 * DefMDIChildProc16 (USER.447)
1632 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1633 WPARAM16 wParam, LPARAM lParam )
1635 MDICLIENTINFO *ci;
1636 WND *clientWnd,*tmpWnd = 0;
1637 LRESULT retvalue;
1639 tmpWnd = WIN_FindWndPtr(hwnd);
1640 if (!tmpWnd) return 0;
1641 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1642 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1643 WIN_ReleaseWndPtr(tmpWnd);
1645 switch (message)
1647 case WM_SETTEXT:
1648 DefWindowProc16(hwnd, message, wParam, lParam);
1649 MDI_MenuModifyItem(clientWnd,hwnd);
1650 if( ci->hwndChildMaximized == hwnd )
1651 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1652 MDI_REPAINTFRAME, NULL );
1653 retvalue = 0;
1654 goto END;
1656 case WM_CLOSE:
1657 SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1658 retvalue = 0;
1659 goto END;
1661 case WM_SETFOCUS:
1662 if( ci->hwndActiveChild != hwnd )
1663 MDI_ChildActivate(clientWnd, hwnd);
1664 break;
1666 case WM_CHILDACTIVATE:
1667 MDI_ChildActivate(clientWnd, hwnd);
1668 retvalue = 0;
1669 goto END;
1671 case WM_NCPAINT:
1672 TRACE("WM_NCPAINT for %04x, active %04x\n",
1673 hwnd, ci->hwndActiveChild );
1674 break;
1676 case WM_SYSCOMMAND:
1677 switch( wParam )
1679 case SC_MOVE:
1680 if( ci->hwndChildMaximized == hwnd)
1682 retvalue = 0;
1683 goto END;
1685 break;
1686 case SC_RESTORE:
1687 case SC_MINIMIZE:
1688 tmpWnd = WIN_FindWndPtr(hwnd);
1689 tmpWnd->dwStyle |= WS_SYSMENU;
1690 WIN_ReleaseWndPtr(tmpWnd);
1691 break;
1692 case SC_MAXIMIZE:
1693 if( ci->hwndChildMaximized == hwnd)
1695 retvalue = SendMessage16( clientWnd->parent->hwndSelf,
1696 message, wParam, lParam);
1697 goto END;
1699 tmpWnd = WIN_FindWndPtr(hwnd);
1700 tmpWnd->dwStyle &= ~WS_SYSMENU;
1701 WIN_ReleaseWndPtr(tmpWnd);
1702 break;
1703 case SC_NEXTWINDOW:
1704 SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1705 retvalue = 0;
1706 goto END;
1707 case SC_PREVWINDOW:
1708 SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1709 retvalue = 0;
1710 goto END;
1712 break;
1714 case WM_GETMINMAXINFO:
1715 MDI_ChildGetMinMaxInfo(clientWnd, hwnd, (MINMAXINFO16*) PTR_SEG_TO_LIN(lParam));
1716 retvalue = 0;
1717 goto END;
1719 case WM_SETVISIBLE:
1720 if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1721 else
1722 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1723 break;
1725 case WM_SIZE:
1726 /* do not change */
1728 if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1730 ci->hwndChildMaximized = 0;
1732 MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1733 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1734 MDI_REPAINTFRAME, NULL );
1737 if( wParam == SIZE_MAXIMIZED )
1739 HWND16 hMaxChild = ci->hwndChildMaximized;
1741 if( hMaxChild == hwnd ) break;
1743 if( hMaxChild)
1745 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1747 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1748 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1750 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1753 TRACE("maximizing child %04x\n", hwnd );
1756 * Keep track of the maximized window.
1758 ci->hwndChildMaximized = hwnd; /* !!! */
1761 * The maximized window should also be the active window
1763 MDI_ChildActivate(clientWnd, hwnd);
1765 MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1766 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1767 MDI_REPAINTFRAME, NULL );
1770 if( wParam == SIZE_MINIMIZED )
1772 HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1774 if( switchTo )
1775 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1778 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1779 break;
1781 case WM_MENUCHAR:
1783 /* MDI children don't have menu bars */
1784 retvalue = 0x00010000L;
1785 goto END;
1787 case WM_NEXTMENU:
1789 if( wParam == VK_LEFT ) /* switch to frame system menu */
1791 retvalue = MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1792 clientWnd->parent->hwndSelf );
1793 goto END;
1795 if( wParam == VK_RIGHT ) /* to frame menu bar */
1797 retvalue = MAKELONG( clientWnd->parent->wIDmenu,
1798 clientWnd->parent->hwndSelf );
1799 goto END;
1802 break;
1804 case WM_SYSCHAR:
1805 if (wParam == '-')
1807 SendMessage16(hwnd,WM_SYSCOMMAND,
1808 (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1809 retvalue = 0;
1810 goto END;
1814 retvalue = DefWindowProc16(hwnd, message, wParam, lParam);
1815 END:
1816 WIN_ReleaseWndPtr(clientWnd);
1817 return retvalue;
1821 /***********************************************************************
1822 * DefMDIChildProcA (USER32.124)
1824 LRESULT WINAPI DefMDIChildProcA( HWND hwnd, UINT message,
1825 WPARAM wParam, LPARAM lParam )
1827 MDICLIENTINFO *ci;
1828 WND *clientWnd,*tmpWnd;
1829 LRESULT retvalue;
1831 tmpWnd = WIN_FindWndPtr(hwnd);
1832 if (!tmpWnd) return 0;
1833 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1834 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1835 WIN_ReleaseWndPtr(tmpWnd);
1837 switch (message)
1839 case WM_SETTEXT:
1840 DefWindowProcA(hwnd, message, wParam, lParam);
1841 MDI_MenuModifyItem(clientWnd,hwnd);
1842 if( ci->hwndChildMaximized == hwnd )
1843 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1844 MDI_REPAINTFRAME, NULL );
1845 retvalue = 0;
1846 goto END;
1848 case WM_GETMINMAXINFO:
1850 MINMAXINFO16 mmi;
1851 STRUCT32_MINMAXINFO32to16( (MINMAXINFO *)lParam, &mmi );
1852 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1853 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO *)lParam );
1855 retvalue = 0;
1856 goto END;
1858 case WM_MENUCHAR:
1860 /* MDI children don't have menu bars */
1861 retvalue = 0x00010000L;
1862 goto END;
1864 case WM_CLOSE:
1865 case WM_SETFOCUS:
1866 case WM_CHILDACTIVATE:
1867 case WM_NCPAINT:
1868 case WM_SYSCOMMAND:
1869 case WM_SETVISIBLE:
1870 case WM_SIZE:
1871 case WM_NEXTMENU:
1872 retvalue = DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1873 goto END;
1875 case WM_SYSCHAR:
1876 if (wParam == '-')
1878 SendMessageA(hwnd,WM_SYSCOMMAND,
1879 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1880 retvalue = 0;
1881 goto END;
1884 retvalue = DefWindowProcA(hwnd, message, wParam, lParam);
1885 END:
1886 WIN_ReleaseWndPtr(clientWnd);
1887 return retvalue;
1891 /***********************************************************************
1892 * DefMDIChildProcW (USER32.125)
1894 LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message,
1895 WPARAM wParam, LPARAM lParam )
1897 MDICLIENTINFO *ci;
1898 WND *clientWnd,*tmpWnd;
1899 LRESULT retvalue;
1901 tmpWnd = WIN_FindWndPtr(hwnd);
1902 if (!tmpWnd) return 0;
1903 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1904 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1905 WIN_ReleaseWndPtr(tmpWnd);
1907 switch (message)
1909 case WM_SETTEXT:
1910 DefWindowProcW(hwnd, message, wParam, lParam);
1911 MDI_MenuModifyItem(clientWnd,hwnd);
1912 if( ci->hwndChildMaximized == hwnd )
1913 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1914 MDI_REPAINTFRAME, NULL );
1915 retvalue = 0;
1916 goto END;
1918 case WM_GETMINMAXINFO:
1919 case WM_MENUCHAR:
1920 case WM_CLOSE:
1921 case WM_SETFOCUS:
1922 case WM_CHILDACTIVATE:
1923 case WM_NCPAINT:
1924 case WM_SYSCOMMAND:
1925 case WM_SETVISIBLE:
1926 case WM_SIZE:
1927 case WM_NEXTMENU:
1928 retvalue = DefMDIChildProcA( hwnd, message, (WPARAM16)wParam, lParam );
1929 goto END;
1931 case WM_SYSCHAR:
1932 if (wParam == '-')
1934 SendMessageW(hwnd,WM_SYSCOMMAND,
1935 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1936 retvalue = 0;
1937 goto END;
1940 retvalue = DefWindowProcW(hwnd, message, wParam, lParam);
1941 END:
1942 WIN_ReleaseWndPtr(clientWnd);
1943 return retvalue;
1948 /**********************************************************************
1949 * CreateMDIWindowA [USER32.79] Creates a MDI child in new thread
1950 * FIXME: its in the same thread now
1952 * RETURNS
1953 * Success: Handle to created window
1954 * Failure: NULL
1956 HWND WINAPI CreateMDIWindowA(
1957 LPCSTR lpClassName, /* [in] Pointer to registered child class name */
1958 LPCSTR lpWindowName, /* [in] Pointer to window name */
1959 DWORD dwStyle, /* [in] Window style */
1960 INT X, /* [in] Horizontal position of window */
1961 INT Y, /* [in] Vertical position of window */
1962 INT nWidth, /* [in] Width of window */
1963 INT nHeight, /* [in] Height of window */
1964 HWND hWndParent, /* [in] Handle to parent window */
1965 HINSTANCE hInstance, /* [in] Handle to application instance */
1966 LPARAM lParam) /* [in] Application-defined value */
1968 WARN("is only single threaded!\n");
1969 return MDI_CreateMDIWindowA(lpClassName, lpWindowName, dwStyle, X, Y,
1970 nWidth, nHeight, hWndParent, hInstance, lParam);
1973 /**********************************************************************
1974 * MDI_CreateMDIWindowA
1975 * single threaded version of CreateMDIWindowA
1976 * called by CreateWindowExA
1978 HWND MDI_CreateMDIWindowA(
1979 LPCSTR lpClassName,
1980 LPCSTR lpWindowName,
1981 DWORD dwStyle,
1982 INT X,
1983 INT Y,
1984 INT nWidth,
1985 INT nHeight,
1986 HWND hWndParent,
1987 HINSTANCE hInstance,
1988 LPARAM lParam)
1990 MDICLIENTINFO* pCi;
1991 MDICREATESTRUCTA cs;
1992 WND *pWnd=WIN_FindWndPtr(hWndParent);
1993 HWND retvalue;
1995 TRACE("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
1996 debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
1997 nWidth,nHeight,hWndParent,hInstance,lParam);
1999 if(!pWnd){
2000 ERR(" bad hwnd for MDI-client: %d\n",hWndParent);
2001 return 0;
2003 cs.szClass=lpClassName;
2004 cs.szTitle=lpWindowName;
2005 cs.hOwner=hInstance;
2006 cs.x=X;
2007 cs.y=Y;
2008 cs.cx=nWidth;
2009 cs.cy=nHeight;
2010 cs.style=dwStyle;
2011 cs.lParam=lParam;
2013 pCi=(MDICLIENTINFO *)pWnd->wExtra;
2015 retvalue = MDICreateChild(pWnd,pCi,hWndParent,&cs);
2016 WIN_ReleaseWndPtr(pWnd);
2017 return retvalue;
2020 /***********************************************************************
2021 * CreateMDIWindowW [USER32.80] Creates a MDI child in new thread
2023 * RETURNS
2024 * Success: Handle to created window
2025 * Failure: NULL
2027 HWND WINAPI CreateMDIWindowW(
2028 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
2029 LPCWSTR lpWindowName, /* [in] Pointer to window name */
2030 DWORD dwStyle, /* [in] Window style */
2031 INT X, /* [in] Horizontal position of window */
2032 INT Y, /* [in] Vertical position of window */
2033 INT nWidth, /* [in] Width of window */
2034 INT nHeight, /* [in] Height of window */
2035 HWND hWndParent, /* [in] Handle to parent window */
2036 HINSTANCE hInstance, /* [in] Handle to application instance */
2037 LPARAM lParam) /* [in] Application-defined value */
2039 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
2040 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
2041 nWidth,nHeight,hWndParent,hInstance,lParam);
2042 return (HWND)NULL;
2046 /******************************************************************************
2047 * CreateMDIWindowW [USER32.80] Creates a MDI child window
2048 * single threaded version of CreateMDIWindow
2049 * called by CreateWindowExW().
2051 HWND MDI_CreateMDIWindowW(
2052 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
2053 LPCWSTR lpWindowName, /* [in] Pointer to window name */
2054 DWORD dwStyle, /* [in] Window style */
2055 INT X, /* [in] Horizontal position of window */
2056 INT Y, /* [in] Vertical position of window */
2057 INT nWidth, /* [in] Width of window */
2058 INT nHeight, /* [in] Height of window */
2059 HWND hWndParent, /* [in] Handle to parent window */
2060 HINSTANCE hInstance, /* [in] Handle to application instance */
2061 LPARAM lParam) /* [in] Application-defined value */
2063 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
2064 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
2065 nWidth,nHeight,hWndParent,hInstance,lParam);
2066 return (HWND)NULL;
2070 /**********************************************************************
2071 * TranslateMDISysAccel (USER32.555)
2073 BOOL WINAPI TranslateMDISysAccel( HWND hwndClient, LPMSG msg )
2075 MSG16 msg16;
2077 STRUCT32_MSG32to16(msg,&msg16);
2078 /* MDICLIENTINFO is still the same for win32 and win16 ... */
2079 return TranslateMDISysAccel16(hwndClient,&msg16);
2083 /**********************************************************************
2084 * TranslateMDISysAccel16 (USER.451)
2086 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
2089 if( IsWindow(hwndClient) && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
2091 MDICLIENTINFO *ci = NULL;
2092 HWND wnd;
2093 WND *clientWnd = WIN_FindWndPtr(hwndClient);
2095 ci = (MDICLIENTINFO*) clientWnd->wExtra;
2096 wnd = ci->hwndActiveChild;
2098 WIN_ReleaseWndPtr(clientWnd);
2100 if( IsWindow(wnd) && !(GetWindowLongA(wnd,GWL_STYLE) & WS_DISABLED) )
2102 WPARAM16 wParam = 0;
2104 /* translate if the Ctrl key is down and Alt not. */
2106 if( (GetKeyState(VK_CONTROL) & 0x8000) &&
2107 !(GetKeyState(VK_MENU) & 0x8000))
2109 switch( msg->wParam )
2111 case VK_F6:
2112 case VK_TAB:
2113 wParam = ( GetKeyState(VK_SHIFT) & 0x8000 )
2114 ? SC_NEXTWINDOW : SC_PREVWINDOW;
2115 break;
2116 case VK_F4:
2117 case VK_RBUTTON:
2118 wParam = SC_CLOSE;
2119 break;
2120 default:
2121 return 0;
2123 TRACE("wParam = %04x\n", wParam);
2124 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
2125 wParam, (LPARAM)msg->wParam);
2126 return 1;
2130 return 0; /* failure */
2134 /***********************************************************************
2135 * CalcChildScroll (USER.462)
2137 void WINAPI CalcChildScroll16( HWND16 hwnd, WORD scroll )
2139 SCROLLINFO info;
2140 RECT childRect, clientRect;
2141 INT vmin, vmax, hmin, hmax, vpos, hpos;
2142 WND *pWnd, *Wnd;
2144 if (!(pWnd = WIN_FindWndPtr( hwnd ))) return;
2145 Wnd = WIN_FindWndPtr(hwnd);
2146 GetClientRect( hwnd, &clientRect );
2147 SetRectEmpty( &childRect );
2149 for ( WIN_UpdateWndPtr(&pWnd,pWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2151 if( pWnd->dwStyle & WS_MAXIMIZE )
2153 ShowScrollBar(hwnd, SB_BOTH, FALSE);
2154 WIN_ReleaseWndPtr(pWnd);
2155 WIN_ReleaseWndPtr(Wnd);
2156 return;
2158 UnionRect( &childRect, &pWnd->rectWindow, &childRect );
2160 WIN_ReleaseWndPtr(pWnd);
2161 UnionRect( &childRect, &clientRect, &childRect );
2163 hmin = childRect.left; hmax = childRect.right - clientRect.right;
2164 hpos = clientRect.left - childRect.left;
2165 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
2166 vpos = clientRect.top - childRect.top;
2168 switch( scroll )
2170 case SB_HORZ:
2171 vpos = hpos; vmin = hmin; vmax = hmax;
2172 case SB_VERT:
2173 info.cbSize = sizeof(info);
2174 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
2175 info.fMask = SIF_POS | SIF_RANGE;
2176 SetScrollInfo(hwnd, scroll, &info, TRUE);
2177 break;
2178 case SB_BOTH:
2179 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
2180 hmin, hmax, hpos);
2182 WIN_ReleaseWndPtr(Wnd);
2186 /***********************************************************************
2187 * ScrollChildren16 (USER.463)
2189 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
2191 ScrollChildren( hWnd, uMsg, wParam, lParam );
2195 /***********************************************************************
2196 * ScrollChildren (USER32.448)
2198 void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
2199 LPARAM lParam)
2201 WND *wndPtr = WIN_FindWndPtr(hWnd);
2202 INT newPos = -1;
2203 INT curPos, length, minPos, maxPos, shift;
2205 if( !wndPtr ) return;
2207 if( uMsg == WM_HSCROLL )
2209 GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
2210 curPos = GetScrollPos(hWnd,SB_HORZ);
2211 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
2212 shift = GetSystemMetrics(SM_CYHSCROLL);
2214 else if( uMsg == WM_VSCROLL )
2216 GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
2217 curPos = GetScrollPos(hWnd,SB_VERT);
2218 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
2219 shift = GetSystemMetrics(SM_CXVSCROLL);
2221 else
2223 WIN_ReleaseWndPtr(wndPtr);
2224 return;
2227 WIN_ReleaseWndPtr(wndPtr);
2228 switch( wParam )
2230 case SB_LINEUP:
2231 newPos = curPos - shift;
2232 break;
2233 case SB_LINEDOWN:
2234 newPos = curPos + shift;
2235 break;
2236 case SB_PAGEUP:
2237 newPos = curPos - length;
2238 break;
2239 case SB_PAGEDOWN:
2240 newPos = curPos + length;
2241 break;
2243 case SB_THUMBPOSITION:
2244 newPos = LOWORD(lParam);
2245 break;
2247 case SB_THUMBTRACK:
2248 return;
2250 case SB_TOP:
2251 newPos = minPos;
2252 break;
2253 case SB_BOTTOM:
2254 newPos = maxPos;
2255 break;
2256 case SB_ENDSCROLL:
2257 CalcChildScroll16(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
2258 return;
2261 if( newPos > maxPos )
2262 newPos = maxPos;
2263 else
2264 if( newPos < minPos )
2265 newPos = minPos;
2267 SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
2269 if( uMsg == WM_VSCROLL )
2270 ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
2271 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2272 else
2273 ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
2274 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2278 /******************************************************************************
2279 * CascadeWindows [USER32.21] Cascades MDI child windows
2281 * RETURNS
2282 * Success: Number of cascaded windows.
2283 * Failure: 0
2285 WORD WINAPI
2286 CascadeWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2287 UINT cKids, const HWND *lpKids)
2289 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2290 hwndParent, wFlags, cKids);
2292 return 0;
2296 /******************************************************************************
2297 * TileWindows [USER32.545] Tiles MDI child windows
2299 * RETURNS
2300 * Success: Number of tiled windows.
2301 * Failure: 0
2303 WORD WINAPI
2304 TileWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2305 UINT cKids, const HWND *lpKids)
2307 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2308 hwndParent, wFlags, cKids);
2310 return 0;
2313 /************************************************************************
2314 * "More Windows..." functionality
2317 /* MDI_MoreWindowsDlgProc
2319 * This function will process the messages sent to the "More Windows..."
2320 * dialog.
2321 * Return values: 0 = cancel pressed
2322 * HWND = ok pressed or double-click in the list...
2326 static BOOL WINAPI MDI_MoreWindowsDlgProc (HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
2328 switch (iMsg)
2330 case WM_INITDIALOG:
2332 WND *pWnd;
2333 UINT widest = 0;
2334 UINT length;
2335 UINT i;
2336 WND *pParentWnd = (WND *)lParam;
2337 MDICLIENTINFO *ci = (MDICLIENTINFO*)pParentWnd->wExtra;
2338 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2340 /* Fill the list, sorted by id... */
2341 for (i = 0; i < ci->nActiveChildren; i++)
2344 /* Find the window with the current ID */
2345 for (pWnd = WIN_LockWndPtr(pParentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd, pWnd->next))
2346 if (pWnd->wIDmenu == ci->idFirstChild + i)
2347 break;
2349 SendMessageW(hListBox, LB_ADDSTRING, 0, (LPARAM) pWnd->text);
2350 SendMessageA(hListBox, LB_SETITEMDATA, i, (LPARAM) pWnd);
2351 length = strlenW(pWnd->text);
2352 WIN_ReleaseWndPtr(pWnd);
2354 if (length > widest)
2355 widest = length;
2357 /* Make sure the horizontal scrollbar scrolls ok */
2358 SendMessageA(hListBox, LB_SETHORIZONTALEXTENT, widest * 6, 0);
2360 /* Set the current selection */
2361 SendMessageA(hListBox, LB_SETCURSEL, MDI_MOREWINDOWSLIMIT, 0);
2362 return TRUE;
2365 case WM_COMMAND:
2366 switch (LOWORD(wParam))
2368 case IDOK:
2370 /* windows are sorted by menu ID, so we must return the
2371 * window associated to the given id
2373 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2374 UINT index = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
2375 WND* pWnd = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
2377 EndDialog(hDlg, pWnd->hwndSelf);
2378 return TRUE;
2380 case IDCANCEL:
2381 EndDialog(hDlg, 0);
2382 return TRUE;
2384 default:
2385 switch (HIWORD(wParam))
2387 case LBN_DBLCLK:
2389 /* windows are sorted by menu ID, so we must return the
2390 * window associated to the given id
2392 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2393 UINT index = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
2394 WND* pWnd = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
2396 EndDialog(hDlg, pWnd->hwndSelf);
2397 return TRUE;
2400 break;
2402 break;
2404 return FALSE;
2409 * MDI_MoreWindowsDialog
2411 * Prompts the user with a listbox containing the opened
2412 * documents. The user can then choose a windows and click
2413 * on OK to set the current window to the one selected, or
2414 * CANCEL to cancel. The function returns a handle to the
2415 * selected window.
2418 static HWND MDI_MoreWindowsDialog(WND* wndPtr)
2420 LPCVOID template;
2421 HRSRC hRes;
2422 HANDLE hDlgTmpl;
2424 hRes = FindResourceA(GetModuleHandleA("USER32"), "MDI_MOREWINDOWS", RT_DIALOGA);
2426 if (hRes == 0)
2427 return 0;
2429 hDlgTmpl = LoadResource(GetModuleHandleA("USER32"), hRes );
2431 if (hDlgTmpl == 0)
2432 return 0;
2434 template = LockResource( hDlgTmpl );
2436 if (template == 0)
2437 return 0;
2439 return (HWND) DialogBoxIndirectParamA(GetModuleHandleA("USER32"),
2440 (LPDLGTEMPLATEA) template,
2441 wndPtr->hwndSelf,
2442 (DLGPROC) MDI_MoreWindowsDlgProc,
2443 (LPARAM) wndPtr);
2448 * MDI_SwapMenuItems
2450 * Will swap the menu IDs for the given 2 positions.
2451 * pos1 and pos2 are menu IDs
2456 static void MDI_SwapMenuItems(WND *parentWnd, UINT pos1, UINT pos2)
2458 WND *pWnd;
2460 for (pWnd = WIN_LockWndPtr(parentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2462 if (pWnd->wIDmenu == pos1)
2463 pWnd->wIDmenu = pos2;
2464 else
2465 if (pWnd->wIDmenu == pos2)
2466 pWnd->wIDmenu = pos1;
2469 WIN_ReleaseWndPtr(pWnd);