Moved all Win16 definitions out of the standard Windows headers.
[wine.git] / windows / mdi.c
blob3d9aec2394e89adcd521a03a1daff6ea07fc430c
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 HWND child;
1373 POINT pt;
1374 pt.x = SLOWORD(lParam);
1375 pt.y = SHIWORD(lParam);
1376 child = ChildWindowFromPoint(hwnd, pt);
1378 TRACE("notification from %04x (%li,%li)\n",child,pt.x,pt.y);
1380 if( child && child != hwnd && child != ci->hwndActiveChild )
1381 SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1383 retvalue = 0;
1384 goto END;
1386 case WM_SIZE:
1387 if( IsWindow(ci->hwndChildMaximized) )
1389 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1390 RECT rect;
1392 rect.left = 0;
1393 rect.top = 0;
1394 rect.right = LOWORD(lParam);
1395 rect.bottom = HIWORD(lParam);
1397 AdjustWindowRectEx(&rect, child->dwStyle, 0, child->dwExStyle);
1398 MoveWindow(ci->hwndChildMaximized, rect.left, rect.top,
1399 rect.right - rect.left, rect.bottom - rect.top, 1);
1400 WIN_ReleaseWndPtr(child);
1402 else
1403 MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1405 break;
1407 case WM_MDICALCCHILDSCROLL:
1408 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1410 CalcChildScroll16(hwnd, ci->sbRecalc-1);
1411 ci->sbRecalc = 0;
1412 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1414 retvalue = 0;
1415 goto END;
1418 retvalue = DefWindowProcA( hwnd, message, wParam, lParam );
1419 END:
1420 WIN_ReleaseWndPtr(w);
1421 WIN_ReleaseWndPtr(frameWnd);
1422 return retvalue;
1426 /***********************************************************************
1427 * DefFrameProc16 (USER.445)
1429 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1430 UINT16 message, WPARAM16 wParam, LPARAM lParam )
1432 HWND16 childHwnd;
1433 MDICLIENTINFO* ci;
1434 WND* wndPtr;
1436 if (hwndMDIClient)
1438 switch (message)
1440 case WM_COMMAND:
1441 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1443 if (!wndPtr) {
1444 ERR("null wndPtr for mdi window hwndMDIClient=%04x\n",
1445 hwndMDIClient);
1446 return 0;
1449 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1451 /* check for possible syscommands for maximized MDI child */
1452 WIN_ReleaseWndPtr(wndPtr);
1454 if( ci && (
1455 wParam < ci->idFirstChild ||
1456 wParam >= ci->idFirstChild + ci->nActiveChildren
1458 if( (wParam - 0xF000) & 0xF00F ) break;
1459 switch( wParam )
1461 case SC_SIZE:
1462 case SC_MOVE:
1463 case SC_MINIMIZE:
1464 case SC_MAXIMIZE:
1465 case SC_NEXTWINDOW:
1466 case SC_PREVWINDOW:
1467 case SC_CLOSE:
1468 case SC_RESTORE:
1469 if( ci->hwndChildMaximized )
1470 return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1471 wParam, lParam);
1474 else
1476 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1477 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1479 if (wParam - ci->idFirstChild == MDI_MOREWINDOWSLIMIT)
1480 /* User chose "More Windows..." */
1481 childHwnd = MDI_MoreWindowsDialog(wndPtr);
1482 else
1483 /* User chose one of the windows listed in the "Windows" menu */
1484 childHwnd = MDI_GetChildByID(wndPtr,wParam );
1486 WIN_ReleaseWndPtr(wndPtr);
1487 if( childHwnd )
1488 SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1489 (WPARAM16)childHwnd , 0L);
1491 break;
1493 case WM_NCACTIVATE:
1494 SendMessage16(hwndMDIClient, message, wParam, lParam);
1495 break;
1497 case WM_SETTEXT:
1499 LPWSTR text = HEAP_strdupAtoW( GetProcessHeap(), 0,
1500 (LPCSTR)PTR_SEG_TO_LIN(lParam) );
1501 wndPtr = WIN_FindWndPtr(hwnd);
1502 MDI_UpdateFrameText(wndPtr, hwndMDIClient,
1503 MDI_REPAINTFRAME, text );
1504 WIN_ReleaseWndPtr(wndPtr);
1505 HeapFree( GetProcessHeap(), 0, text );
1507 return 0;
1509 case WM_SETFOCUS:
1510 SetFocus(hwndMDIClient);
1511 break;
1513 case WM_SIZE:
1514 MoveWindow16(hwndMDIClient, 0, 0,
1515 LOWORD(lParam), HIWORD(lParam), TRUE);
1516 break;
1518 case WM_NEXTMENU:
1520 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1521 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1523 if( !(wndPtr->parent->dwStyle & WS_MINIMIZE)
1524 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1526 /* control menu is between the frame system menu and
1527 * the first entry of menu bar */
1529 if( (wParam == VK_LEFT &&
1530 wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1531 (wParam == VK_RIGHT &&
1532 GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1534 LRESULT retvalue;
1535 WIN_ReleaseWndPtr(wndPtr);
1536 wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1537 retvalue = MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1538 ci->hwndActiveChild);
1539 WIN_ReleaseWndPtr(wndPtr);
1540 return retvalue;
1543 WIN_ReleaseWndPtr(wndPtr);
1544 break;
1548 return DefWindowProc16(hwnd, message, wParam, lParam);
1552 /***********************************************************************
1553 * DefFrameProcA (USER32.122)
1555 LRESULT WINAPI DefFrameProcA( HWND hwnd, HWND hwndMDIClient,
1556 UINT message, WPARAM wParam, LPARAM lParam)
1558 if (hwndMDIClient)
1560 switch (message)
1562 case WM_COMMAND:
1563 return DefFrameProc16( hwnd, hwndMDIClient, message,
1564 (WPARAM16)wParam,
1565 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1567 case WM_NCACTIVATE:
1568 SendMessageA(hwndMDIClient, message, wParam, lParam);
1569 break;
1571 case WM_SETTEXT: {
1572 LRESULT ret;
1573 LPSTR segstr = SEGPTR_STRDUP((LPSTR)lParam);
1575 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1576 wParam, (LPARAM)SEGPTR_GET(segstr) );
1577 SEGPTR_FREE(segstr);
1578 return ret;
1581 case WM_NEXTMENU:
1582 case WM_SETFOCUS:
1583 case WM_SIZE:
1584 return DefFrameProc16( hwnd, hwndMDIClient, message,
1585 wParam, lParam );
1589 return DefWindowProcA(hwnd, message, wParam, lParam);
1593 /***********************************************************************
1594 * DefFrameProcW (USER32.123)
1596 LRESULT WINAPI DefFrameProcW( HWND hwnd, HWND hwndMDIClient,
1597 UINT message, WPARAM wParam, LPARAM lParam)
1599 if (hwndMDIClient)
1601 switch (message)
1603 case WM_COMMAND:
1604 return DefFrameProc16( hwnd, hwndMDIClient, message,
1605 (WPARAM16)wParam,
1606 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1608 case WM_NCACTIVATE:
1609 SendMessageW(hwndMDIClient, message, wParam, lParam);
1610 break;
1612 case WM_SETTEXT:
1614 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1615 LRESULT ret = DefFrameProcA( hwnd, hwndMDIClient, message,
1616 wParam, (DWORD)txt );
1617 HeapFree(GetProcessHeap(),0,txt);
1618 return ret;
1620 case WM_NEXTMENU:
1621 case WM_SETFOCUS:
1622 case WM_SIZE:
1623 return DefFrameProcA( hwnd, hwndMDIClient, message,
1624 wParam, lParam );
1628 return DefWindowProcW( hwnd, message, wParam, lParam );
1632 /***********************************************************************
1633 * DefMDIChildProc16 (USER.447)
1635 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1636 WPARAM16 wParam, LPARAM lParam )
1638 MDICLIENTINFO *ci;
1639 WND *clientWnd,*tmpWnd = 0;
1640 LRESULT retvalue;
1642 tmpWnd = WIN_FindWndPtr(hwnd);
1643 if (!tmpWnd) return 0;
1644 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1645 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1646 WIN_ReleaseWndPtr(tmpWnd);
1648 switch (message)
1650 case WM_SETTEXT:
1651 DefWindowProc16(hwnd, message, wParam, lParam);
1652 MDI_MenuModifyItem(clientWnd,hwnd);
1653 if( ci->hwndChildMaximized == hwnd )
1654 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1655 MDI_REPAINTFRAME, NULL );
1656 retvalue = 0;
1657 goto END;
1659 case WM_CLOSE:
1660 SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1661 retvalue = 0;
1662 goto END;
1664 case WM_SETFOCUS:
1665 if( ci->hwndActiveChild != hwnd )
1666 MDI_ChildActivate(clientWnd, hwnd);
1667 break;
1669 case WM_CHILDACTIVATE:
1670 MDI_ChildActivate(clientWnd, hwnd);
1671 retvalue = 0;
1672 goto END;
1674 case WM_NCPAINT:
1675 TRACE("WM_NCPAINT for %04x, active %04x\n",
1676 hwnd, ci->hwndActiveChild );
1677 break;
1679 case WM_SYSCOMMAND:
1680 switch( wParam )
1682 case SC_MOVE:
1683 if( ci->hwndChildMaximized == hwnd)
1685 retvalue = 0;
1686 goto END;
1688 break;
1689 case SC_RESTORE:
1690 case SC_MINIMIZE:
1691 tmpWnd = WIN_FindWndPtr(hwnd);
1692 tmpWnd->dwStyle |= WS_SYSMENU;
1693 WIN_ReleaseWndPtr(tmpWnd);
1694 break;
1695 case SC_MAXIMIZE:
1696 if( ci->hwndChildMaximized == hwnd)
1698 retvalue = SendMessage16( clientWnd->parent->hwndSelf,
1699 message, wParam, lParam);
1700 goto END;
1702 tmpWnd = WIN_FindWndPtr(hwnd);
1703 tmpWnd->dwStyle &= ~WS_SYSMENU;
1704 WIN_ReleaseWndPtr(tmpWnd);
1705 break;
1706 case SC_NEXTWINDOW:
1707 SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1708 retvalue = 0;
1709 goto END;
1710 case SC_PREVWINDOW:
1711 SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1712 retvalue = 0;
1713 goto END;
1715 break;
1717 case WM_GETMINMAXINFO:
1718 MDI_ChildGetMinMaxInfo(clientWnd, hwnd, (MINMAXINFO16*) PTR_SEG_TO_LIN(lParam));
1719 retvalue = 0;
1720 goto END;
1722 case WM_SETVISIBLE:
1723 if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1724 else
1725 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1726 break;
1728 case WM_SIZE:
1729 /* do not change */
1731 if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1733 ci->hwndChildMaximized = 0;
1735 MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1736 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1737 MDI_REPAINTFRAME, NULL );
1740 if( wParam == SIZE_MAXIMIZED )
1742 HWND16 hMaxChild = ci->hwndChildMaximized;
1744 if( hMaxChild == hwnd ) break;
1746 if( hMaxChild)
1748 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1750 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1751 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1753 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1756 TRACE("maximizing child %04x\n", hwnd );
1759 * Keep track of the maximized window.
1761 ci->hwndChildMaximized = hwnd; /* !!! */
1764 * The maximized window should also be the active window
1766 MDI_ChildActivate(clientWnd, hwnd);
1768 MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1769 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1770 MDI_REPAINTFRAME, NULL );
1773 if( wParam == SIZE_MINIMIZED )
1775 HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1777 if( switchTo )
1778 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1781 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1782 break;
1784 case WM_MENUCHAR:
1786 /* MDI children don't have menu bars */
1787 retvalue = 0x00010000L;
1788 goto END;
1790 case WM_NEXTMENU:
1792 if( wParam == VK_LEFT ) /* switch to frame system menu */
1794 retvalue = MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1795 clientWnd->parent->hwndSelf );
1796 goto END;
1798 if( wParam == VK_RIGHT ) /* to frame menu bar */
1800 retvalue = MAKELONG( clientWnd->parent->wIDmenu,
1801 clientWnd->parent->hwndSelf );
1802 goto END;
1805 break;
1807 case WM_SYSCHAR:
1808 if (wParam == '-')
1810 SendMessage16(hwnd,WM_SYSCOMMAND,
1811 (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1812 retvalue = 0;
1813 goto END;
1817 retvalue = DefWindowProc16(hwnd, message, wParam, lParam);
1818 END:
1819 WIN_ReleaseWndPtr(clientWnd);
1820 return retvalue;
1824 /***********************************************************************
1825 * DefMDIChildProcA (USER32.124)
1827 LRESULT WINAPI DefMDIChildProcA( HWND hwnd, UINT message,
1828 WPARAM wParam, LPARAM lParam )
1830 MDICLIENTINFO *ci;
1831 WND *clientWnd,*tmpWnd;
1832 LRESULT retvalue;
1834 tmpWnd = WIN_FindWndPtr(hwnd);
1835 if (!tmpWnd) return 0;
1836 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1837 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1838 WIN_ReleaseWndPtr(tmpWnd);
1840 switch (message)
1842 case WM_SETTEXT:
1843 DefWindowProcA(hwnd, message, wParam, lParam);
1844 MDI_MenuModifyItem(clientWnd,hwnd);
1845 if( ci->hwndChildMaximized == hwnd )
1846 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1847 MDI_REPAINTFRAME, NULL );
1848 retvalue = 0;
1849 goto END;
1851 case WM_GETMINMAXINFO:
1853 MINMAXINFO16 mmi;
1854 STRUCT32_MINMAXINFO32to16( (MINMAXINFO *)lParam, &mmi );
1855 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1856 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO *)lParam );
1858 retvalue = 0;
1859 goto END;
1861 case WM_MENUCHAR:
1863 /* MDI children don't have menu bars */
1864 retvalue = 0x00010000L;
1865 goto END;
1867 case WM_CLOSE:
1868 case WM_SETFOCUS:
1869 case WM_CHILDACTIVATE:
1870 case WM_NCPAINT:
1871 case WM_SYSCOMMAND:
1872 case WM_SETVISIBLE:
1873 case WM_SIZE:
1874 case WM_NEXTMENU:
1875 retvalue = DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1876 goto END;
1878 case WM_SYSCHAR:
1879 if (wParam == '-')
1881 SendMessageA(hwnd,WM_SYSCOMMAND,
1882 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1883 retvalue = 0;
1884 goto END;
1887 retvalue = DefWindowProcA(hwnd, message, wParam, lParam);
1888 END:
1889 WIN_ReleaseWndPtr(clientWnd);
1890 return retvalue;
1894 /***********************************************************************
1895 * DefMDIChildProcW (USER32.125)
1897 LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message,
1898 WPARAM wParam, LPARAM lParam )
1900 MDICLIENTINFO *ci;
1901 WND *clientWnd,*tmpWnd;
1902 LRESULT retvalue;
1904 tmpWnd = WIN_FindWndPtr(hwnd);
1905 if (!tmpWnd) return 0;
1906 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1907 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1908 WIN_ReleaseWndPtr(tmpWnd);
1910 switch (message)
1912 case WM_SETTEXT:
1913 DefWindowProcW(hwnd, message, wParam, lParam);
1914 MDI_MenuModifyItem(clientWnd,hwnd);
1915 if( ci->hwndChildMaximized == hwnd )
1916 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1917 MDI_REPAINTFRAME, NULL );
1918 retvalue = 0;
1919 goto END;
1921 case WM_GETMINMAXINFO:
1922 case WM_MENUCHAR:
1923 case WM_CLOSE:
1924 case WM_SETFOCUS:
1925 case WM_CHILDACTIVATE:
1926 case WM_NCPAINT:
1927 case WM_SYSCOMMAND:
1928 case WM_SETVISIBLE:
1929 case WM_SIZE:
1930 case WM_NEXTMENU:
1931 retvalue = DefMDIChildProcA( hwnd, message, (WPARAM16)wParam, lParam );
1932 goto END;
1934 case WM_SYSCHAR:
1935 if (wParam == '-')
1937 SendMessageW(hwnd,WM_SYSCOMMAND,
1938 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1939 retvalue = 0;
1940 goto END;
1943 retvalue = DefWindowProcW(hwnd, message, wParam, lParam);
1944 END:
1945 WIN_ReleaseWndPtr(clientWnd);
1946 return retvalue;
1951 /**********************************************************************
1952 * CreateMDIWindowA [USER32.79] Creates a MDI child in new thread
1953 * FIXME: its in the same thread now
1955 * RETURNS
1956 * Success: Handle to created window
1957 * Failure: NULL
1959 HWND WINAPI CreateMDIWindowA(
1960 LPCSTR lpClassName, /* [in] Pointer to registered child class name */
1961 LPCSTR lpWindowName, /* [in] Pointer to window name */
1962 DWORD dwStyle, /* [in] Window style */
1963 INT X, /* [in] Horizontal position of window */
1964 INT Y, /* [in] Vertical position of window */
1965 INT nWidth, /* [in] Width of window */
1966 INT nHeight, /* [in] Height of window */
1967 HWND hWndParent, /* [in] Handle to parent window */
1968 HINSTANCE hInstance, /* [in] Handle to application instance */
1969 LPARAM lParam) /* [in] Application-defined value */
1971 WARN("is only single threaded!\n");
1972 return MDI_CreateMDIWindowA(lpClassName, lpWindowName, dwStyle, X, Y,
1973 nWidth, nHeight, hWndParent, hInstance, lParam);
1976 /**********************************************************************
1977 * MDI_CreateMDIWindowA
1978 * single threaded version of CreateMDIWindowA
1979 * called by CreateWindowExA
1981 HWND MDI_CreateMDIWindowA(
1982 LPCSTR lpClassName,
1983 LPCSTR lpWindowName,
1984 DWORD dwStyle,
1985 INT X,
1986 INT Y,
1987 INT nWidth,
1988 INT nHeight,
1989 HWND hWndParent,
1990 HINSTANCE hInstance,
1991 LPARAM lParam)
1993 MDICLIENTINFO* pCi;
1994 MDICREATESTRUCTA cs;
1995 WND *pWnd=WIN_FindWndPtr(hWndParent);
1996 HWND retvalue;
1998 TRACE("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
1999 debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
2000 nWidth,nHeight,hWndParent,hInstance,lParam);
2002 if(!pWnd){
2003 ERR(" bad hwnd for MDI-client: %d\n",hWndParent);
2004 return 0;
2006 cs.szClass=lpClassName;
2007 cs.szTitle=lpWindowName;
2008 cs.hOwner=hInstance;
2009 cs.x=X;
2010 cs.y=Y;
2011 cs.cx=nWidth;
2012 cs.cy=nHeight;
2013 cs.style=dwStyle;
2014 cs.lParam=lParam;
2016 pCi=(MDICLIENTINFO *)pWnd->wExtra;
2018 retvalue = MDICreateChild(pWnd,pCi,hWndParent,&cs);
2019 WIN_ReleaseWndPtr(pWnd);
2020 return retvalue;
2023 /***********************************************************************
2024 * CreateMDIWindowW [USER32.80] Creates a MDI child in new thread
2026 * RETURNS
2027 * Success: Handle to created window
2028 * Failure: NULL
2030 HWND WINAPI CreateMDIWindowW(
2031 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
2032 LPCWSTR lpWindowName, /* [in] Pointer to window name */
2033 DWORD dwStyle, /* [in] Window style */
2034 INT X, /* [in] Horizontal position of window */
2035 INT Y, /* [in] Vertical position of window */
2036 INT nWidth, /* [in] Width of window */
2037 INT nHeight, /* [in] Height of window */
2038 HWND hWndParent, /* [in] Handle to parent window */
2039 HINSTANCE hInstance, /* [in] Handle to application instance */
2040 LPARAM lParam) /* [in] Application-defined value */
2042 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
2043 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
2044 nWidth,nHeight,hWndParent,hInstance,lParam);
2045 return (HWND)NULL;
2049 /******************************************************************************
2050 * CreateMDIWindowW [USER32.80] Creates a MDI child window
2051 * single threaded version of CreateMDIWindow
2052 * called by CreateWindowExW().
2054 HWND MDI_CreateMDIWindowW(
2055 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
2056 LPCWSTR lpWindowName, /* [in] Pointer to window name */
2057 DWORD dwStyle, /* [in] Window style */
2058 INT X, /* [in] Horizontal position of window */
2059 INT Y, /* [in] Vertical position of window */
2060 INT nWidth, /* [in] Width of window */
2061 INT nHeight, /* [in] Height of window */
2062 HWND hWndParent, /* [in] Handle to parent window */
2063 HINSTANCE hInstance, /* [in] Handle to application instance */
2064 LPARAM lParam) /* [in] Application-defined value */
2066 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
2067 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
2068 nWidth,nHeight,hWndParent,hInstance,lParam);
2069 return (HWND)NULL;
2073 /**********************************************************************
2074 * TranslateMDISysAccel (USER32.555)
2076 BOOL WINAPI TranslateMDISysAccel( HWND hwndClient, LPMSG msg )
2078 MSG16 msg16;
2080 STRUCT32_MSG32to16(msg,&msg16);
2081 /* MDICLIENTINFO is still the same for win32 and win16 ... */
2082 return TranslateMDISysAccel16(hwndClient,&msg16);
2086 /**********************************************************************
2087 * TranslateMDISysAccel16 (USER.451)
2089 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
2092 if( IsWindow(hwndClient) && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
2094 MDICLIENTINFO *ci = NULL;
2095 HWND wnd;
2096 WND *clientWnd = WIN_FindWndPtr(hwndClient);
2098 ci = (MDICLIENTINFO*) clientWnd->wExtra;
2099 wnd = ci->hwndActiveChild;
2101 WIN_ReleaseWndPtr(clientWnd);
2103 if( IsWindow(wnd) && !(GetWindowLongA(wnd,GWL_STYLE) & WS_DISABLED) )
2105 WPARAM16 wParam = 0;
2107 /* translate if the Ctrl key is down and Alt not. */
2109 if( (GetKeyState(VK_CONTROL) & 0x8000) &&
2110 !(GetKeyState(VK_MENU) & 0x8000))
2112 switch( msg->wParam )
2114 case VK_F6:
2115 case VK_TAB:
2116 wParam = ( GetKeyState(VK_SHIFT) & 0x8000 )
2117 ? SC_NEXTWINDOW : SC_PREVWINDOW;
2118 break;
2119 case VK_F4:
2120 case VK_RBUTTON:
2121 wParam = SC_CLOSE;
2122 break;
2123 default:
2124 return 0;
2126 TRACE("wParam = %04x\n", wParam);
2127 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
2128 wParam, (LPARAM)msg->wParam);
2129 return 1;
2133 return 0; /* failure */
2137 /***********************************************************************
2138 * CalcChildScroll (USER.462)
2140 void WINAPI CalcChildScroll16( HWND16 hwnd, WORD scroll )
2142 SCROLLINFO info;
2143 RECT childRect, clientRect;
2144 INT vmin, vmax, hmin, hmax, vpos, hpos;
2145 WND *pWnd, *Wnd;
2147 if (!(pWnd = WIN_FindWndPtr( hwnd ))) return;
2148 Wnd = WIN_FindWndPtr(hwnd);
2149 GetClientRect( hwnd, &clientRect );
2150 SetRectEmpty( &childRect );
2152 for ( WIN_UpdateWndPtr(&pWnd,pWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2154 if( pWnd->dwStyle & WS_MAXIMIZE )
2156 ShowScrollBar(hwnd, SB_BOTH, FALSE);
2157 WIN_ReleaseWndPtr(pWnd);
2158 WIN_ReleaseWndPtr(Wnd);
2159 return;
2161 UnionRect( &childRect, &pWnd->rectWindow, &childRect );
2163 WIN_ReleaseWndPtr(pWnd);
2164 UnionRect( &childRect, &clientRect, &childRect );
2166 hmin = childRect.left; hmax = childRect.right - clientRect.right;
2167 hpos = clientRect.left - childRect.left;
2168 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
2169 vpos = clientRect.top - childRect.top;
2171 switch( scroll )
2173 case SB_HORZ:
2174 vpos = hpos; vmin = hmin; vmax = hmax;
2175 case SB_VERT:
2176 info.cbSize = sizeof(info);
2177 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
2178 info.fMask = SIF_POS | SIF_RANGE;
2179 SetScrollInfo(hwnd, scroll, &info, TRUE);
2180 break;
2181 case SB_BOTH:
2182 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
2183 hmin, hmax, hpos);
2185 WIN_ReleaseWndPtr(Wnd);
2189 /***********************************************************************
2190 * ScrollChildren16 (USER.463)
2192 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
2194 ScrollChildren( hWnd, uMsg, wParam, lParam );
2198 /***********************************************************************
2199 * ScrollChildren (USER32.448)
2201 void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
2202 LPARAM lParam)
2204 WND *wndPtr = WIN_FindWndPtr(hWnd);
2205 INT newPos = -1;
2206 INT curPos, length, minPos, maxPos, shift;
2208 if( !wndPtr ) return;
2210 if( uMsg == WM_HSCROLL )
2212 GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
2213 curPos = GetScrollPos(hWnd,SB_HORZ);
2214 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
2215 shift = GetSystemMetrics(SM_CYHSCROLL);
2217 else if( uMsg == WM_VSCROLL )
2219 GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
2220 curPos = GetScrollPos(hWnd,SB_VERT);
2221 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
2222 shift = GetSystemMetrics(SM_CXVSCROLL);
2224 else
2226 WIN_ReleaseWndPtr(wndPtr);
2227 return;
2230 WIN_ReleaseWndPtr(wndPtr);
2231 switch( wParam )
2233 case SB_LINEUP:
2234 newPos = curPos - shift;
2235 break;
2236 case SB_LINEDOWN:
2237 newPos = curPos + shift;
2238 break;
2239 case SB_PAGEUP:
2240 newPos = curPos - length;
2241 break;
2242 case SB_PAGEDOWN:
2243 newPos = curPos + length;
2244 break;
2246 case SB_THUMBPOSITION:
2247 newPos = LOWORD(lParam);
2248 break;
2250 case SB_THUMBTRACK:
2251 return;
2253 case SB_TOP:
2254 newPos = minPos;
2255 break;
2256 case SB_BOTTOM:
2257 newPos = maxPos;
2258 break;
2259 case SB_ENDSCROLL:
2260 CalcChildScroll16(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
2261 return;
2264 if( newPos > maxPos )
2265 newPos = maxPos;
2266 else
2267 if( newPos < minPos )
2268 newPos = minPos;
2270 SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
2272 if( uMsg == WM_VSCROLL )
2273 ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
2274 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2275 else
2276 ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
2277 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2281 /******************************************************************************
2282 * CascadeWindows [USER32.21] Cascades MDI child windows
2284 * RETURNS
2285 * Success: Number of cascaded windows.
2286 * Failure: 0
2288 WORD WINAPI
2289 CascadeWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2290 UINT cKids, const HWND *lpKids)
2292 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2293 hwndParent, wFlags, cKids);
2295 return 0;
2299 /******************************************************************************
2300 * TileWindows [USER32.545] Tiles MDI child windows
2302 * RETURNS
2303 * Success: Number of tiled windows.
2304 * Failure: 0
2306 WORD WINAPI
2307 TileWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2308 UINT cKids, const HWND *lpKids)
2310 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2311 hwndParent, wFlags, cKids);
2313 return 0;
2316 /************************************************************************
2317 * "More Windows..." functionality
2320 /* MDI_MoreWindowsDlgProc
2322 * This function will process the messages sent to the "More Windows..."
2323 * dialog.
2324 * Return values: 0 = cancel pressed
2325 * HWND = ok pressed or double-click in the list...
2329 static BOOL WINAPI MDI_MoreWindowsDlgProc (HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
2331 switch (iMsg)
2333 case WM_INITDIALOG:
2335 WND *pWnd;
2336 UINT widest = 0;
2337 UINT length;
2338 UINT i;
2339 WND *pParentWnd = (WND *)lParam;
2340 MDICLIENTINFO *ci = (MDICLIENTINFO*)pParentWnd->wExtra;
2341 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2343 /* Fill the list, sorted by id... */
2344 for (i = 0; i < ci->nActiveChildren; i++)
2347 /* Find the window with the current ID */
2348 for (pWnd = WIN_LockWndPtr(pParentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd, pWnd->next))
2349 if (pWnd->wIDmenu == ci->idFirstChild + i)
2350 break;
2352 SendMessageW(hListBox, LB_ADDSTRING, 0, (LPARAM) pWnd->text);
2353 SendMessageA(hListBox, LB_SETITEMDATA, i, (LPARAM) pWnd);
2354 length = strlenW(pWnd->text);
2355 WIN_ReleaseWndPtr(pWnd);
2357 if (length > widest)
2358 widest = length;
2360 /* Make sure the horizontal scrollbar scrolls ok */
2361 SendMessageA(hListBox, LB_SETHORIZONTALEXTENT, widest * 6, 0);
2363 /* Set the current selection */
2364 SendMessageA(hListBox, LB_SETCURSEL, MDI_MOREWINDOWSLIMIT, 0);
2365 return TRUE;
2368 case WM_COMMAND:
2369 switch (LOWORD(wParam))
2371 case IDOK:
2373 /* windows are sorted by menu ID, so we must return the
2374 * window associated to the given id
2376 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2377 UINT index = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
2378 WND* pWnd = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
2380 EndDialog(hDlg, pWnd->hwndSelf);
2381 return TRUE;
2383 case IDCANCEL:
2384 EndDialog(hDlg, 0);
2385 return TRUE;
2387 default:
2388 switch (HIWORD(wParam))
2390 case LBN_DBLCLK:
2392 /* windows are sorted by menu ID, so we must return the
2393 * window associated to the given id
2395 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2396 UINT index = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
2397 WND* pWnd = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
2399 EndDialog(hDlg, pWnd->hwndSelf);
2400 return TRUE;
2403 break;
2405 break;
2407 return FALSE;
2412 * MDI_MoreWindowsDialog
2414 * Prompts the user with a listbox containing the opened
2415 * documents. The user can then choose a windows and click
2416 * on OK to set the current window to the one selected, or
2417 * CANCEL to cancel. The function returns a handle to the
2418 * selected window.
2421 static HWND MDI_MoreWindowsDialog(WND* wndPtr)
2423 LPCVOID template;
2424 HRSRC hRes;
2425 HANDLE hDlgTmpl;
2427 hRes = FindResourceA(GetModuleHandleA("USER32"), "MDI_MOREWINDOWS", RT_DIALOGA);
2429 if (hRes == 0)
2430 return 0;
2432 hDlgTmpl = LoadResource(GetModuleHandleA("USER32"), hRes );
2434 if (hDlgTmpl == 0)
2435 return 0;
2437 template = LockResource( hDlgTmpl );
2439 if (template == 0)
2440 return 0;
2442 return (HWND) DialogBoxIndirectParamA(GetModuleHandleA("USER32"),
2443 (LPDLGTEMPLATEA) template,
2444 wndPtr->hwndSelf,
2445 (DLGPROC) MDI_MoreWindowsDlgProc,
2446 (LPARAM) wndPtr);
2451 * MDI_SwapMenuItems
2453 * Will swap the menu IDs for the given 2 positions.
2454 * pos1 and pos2 are menu IDs
2459 static void MDI_SwapMenuItems(WND *parentWnd, UINT pos1, UINT pos2)
2461 WND *pWnd;
2463 for (pWnd = WIN_LockWndPtr(parentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2465 if (pWnd->wIDmenu == pos1)
2466 pWnd->wIDmenu = pos2;
2467 else
2468 if (pWnd->wIDmenu == pos2)
2469 pWnd->wIDmenu = pos1;
2472 WIN_ReleaseWndPtr(pWnd);