Removed duplicate field in internal structure.
[wine.git] / windows / mdi.c
blob209e9cb84715a2caaa5e4ff2b9f2c72c2124dfc3
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>
74 #include "windef.h"
75 #include "winbase.h"
76 #include "wingdi.h"
77 #include "winuser.h"
78 #include "wine/unicode.h"
79 #include "win.h"
80 #include "heap.h"
81 #include "nonclient.h"
82 #include "controls.h"
83 #include "user.h"
84 #include "struct32.h"
85 #include "tweak.h"
86 #include "debugtools.h"
87 #include "dlgs.h"
89 DEFAULT_DEBUG_CHANNEL(mdi);
91 #define MDI_MAXLISTLENGTH 0x40
92 #define MDI_MAXTITLELENGTH 0xa1
94 #define MDI_NOFRAMEREPAINT 0
95 #define MDI_REPAINTFRAMENOW 1
96 #define MDI_REPAINTFRAME 2
98 #define WM_MDICALCCHILDSCROLL 0x10ac /* this is exactly what Windows uses */
100 /* "More Windows..." definitions */
101 #define MDI_MOREWINDOWSLIMIT 9 /* after this number of windows, a "More Windows..."
102 option will appear under the Windows menu */
103 #define MDI_IDC_LISTBOX 100
104 #define MDI_IDS_MOREWINDOWS 13
106 #define MDIF_NEEDUPDATE 0x0001
108 typedef struct
110 UINT nActiveChildren;
111 HWND hwndChildMaximized;
112 HWND hwndActiveChild;
113 HMENU hWindowMenu;
114 UINT idFirstChild;
115 LPWSTR frameTitle;
116 UINT nTotalCreated;
117 UINT mdiFlags;
118 UINT sbRecalc; /* SB_xxx flags for scrollbar fixup */
119 HWND self;
120 } MDICLIENTINFO;
122 static HBITMAP16 hBmpClose = 0;
123 static HBITMAP16 hBmpRestore = 0;
125 /* ----------------- declarations ----------------- */
126 static void MDI_UpdateFrameText(WND *, HWND, BOOL, LPCWSTR);
127 static BOOL MDI_AugmentFrameMenu(MDICLIENTINFO*, WND *, HWND);
128 static BOOL MDI_RestoreFrameMenu(WND *, HWND);
130 static LONG MDI_ChildActivate( WND*, HWND );
132 static HWND MDI_MoreWindowsDialog(WND*);
133 static void MDI_SwapMenuItems(WND *, UINT, UINT);
134 static LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
135 /* -------- Miscellaneous service functions ----------
137 * MDI_GetChildByID
140 static HWND MDI_GetChildByID(WND* wndPtr, INT id)
142 for (wndPtr = wndPtr->child; wndPtr; wndPtr = wndPtr->next)
143 if (wndPtr->wIDmenu == id) return wndPtr->hwndSelf;
144 return 0;
147 static void MDI_PostUpdate(HWND hwnd, MDICLIENTINFO* ci, WORD recalc)
149 if( !(ci->mdiFlags & MDIF_NEEDUPDATE) )
151 ci->mdiFlags |= MDIF_NEEDUPDATE;
152 PostMessageA( hwnd, WM_MDICALCCHILDSCROLL, 0, 0);
154 ci->sbRecalc = recalc;
158 /*********************************************************************
159 * MDIClient class descriptor
161 const struct builtin_class_descr MDICLIENT_builtin_class =
163 "MDIClient", /* name */
164 CS_GLOBALCLASS, /* style */
165 MDIClientWndProcA, /* procA */
166 NULL, /* procW (FIXME) */
167 sizeof(MDICLIENTINFO), /* extra */
168 IDC_ARROWA, /* cursor */
169 COLOR_APPWORKSPACE+1 /* brush */
173 /**********************************************************************
174 * MDI_MenuModifyItem
176 static BOOL MDI_MenuModifyItem(WND* clientWnd, HWND hWndChild )
178 WCHAR buffer[128];
179 static const WCHAR format[] = {'%','d',' ',0};
180 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
181 WND *wndPtr = WIN_FindWndPtr(hWndChild);
182 UINT n = wsprintfW(buffer, format,
183 wndPtr->wIDmenu - clientInfo->idFirstChild + 1);
184 BOOL bRet = 0;
186 if( !clientInfo->hWindowMenu )
188 bRet = FALSE;
189 goto END;
192 if (wndPtr->text) lstrcpynW(buffer + n, wndPtr->text, sizeof(buffer)/sizeof(WCHAR) - n );
194 n = GetMenuState(clientInfo->hWindowMenu,wndPtr->wIDmenu ,MF_BYCOMMAND);
195 bRet = ModifyMenuW(clientInfo->hWindowMenu , wndPtr->wIDmenu,
196 MF_BYCOMMAND | MF_STRING, wndPtr->wIDmenu, buffer );
197 CheckMenuItem(clientInfo->hWindowMenu ,wndPtr->wIDmenu , n & MF_CHECKED);
198 END:
199 WIN_ReleaseWndPtr(wndPtr);
200 return bRet;
203 /**********************************************************************
204 * MDI_MenuDeleteItem
206 static BOOL MDI_MenuDeleteItem(WND* clientWnd, HWND hWndChild )
208 WCHAR buffer[128];
209 static const WCHAR format[] = {'&','%','d',' ',0};
210 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
211 WND *wndPtr = WIN_FindWndPtr(hWndChild);
212 UINT index = 0,id,n;
213 BOOL retvalue;
215 if( !clientInfo->nActiveChildren ||
216 !clientInfo->hWindowMenu )
218 retvalue = FALSE;
219 goto END;
222 id = wndPtr->wIDmenu;
223 DeleteMenu(clientInfo->hWindowMenu,id,MF_BYCOMMAND);
225 /* walk the rest of MDI children to prevent gaps in the id
226 * sequence and in the menu child list */
228 for( index = id+1; index <= clientInfo->nActiveChildren +
229 clientInfo->idFirstChild; index++ )
231 WND *tmpWnd = WIN_FindWndPtr(MDI_GetChildByID(clientWnd,index));
232 if( !tmpWnd )
234 TRACE("no window for id=%i\n",index);
235 WIN_ReleaseWndPtr(tmpWnd);
236 continue;
239 /* set correct id */
240 tmpWnd->wIDmenu--;
242 n = wsprintfW(buffer, format ,index - clientInfo->idFirstChild);
243 if (tmpWnd->text)
244 lstrcpynW(buffer + n, tmpWnd->text, sizeof(buffer)/sizeof(WCHAR) - n );
246 /* change menu if the current child is to be shown in the
247 * "Windows" menu
249 if (index <= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
250 ModifyMenuW(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING,
251 index - 1 , buffer );
252 WIN_ReleaseWndPtr(tmpWnd);
255 /* We must restore the "More Windows..." option if there is enough child
257 if (clientInfo->nActiveChildren - 1 > MDI_MOREWINDOWSLIMIT)
259 char szTmp[50];
260 LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
262 AppendMenuA(clientInfo->hWindowMenu ,MF_STRING ,clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT, szTmp );
264 retvalue = TRUE;
265 END:
266 WIN_ReleaseWndPtr(wndPtr);
267 return retvalue;
270 /**********************************************************************
271 * MDI_GetWindow
273 * returns "activateable" child different from the current or zero
275 static HWND MDI_GetWindow(WND *clientWnd, HWND hWnd, BOOL bNext,
276 DWORD dwStyleMask )
278 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
279 WND *wndPtr, *pWnd, *pWndLast = NULL;
281 dwStyleMask |= WS_DISABLED | WS_VISIBLE;
282 if( !hWnd ) hWnd = clientInfo->hwndActiveChild;
284 if( !(wndPtr = WIN_FindWndPtr(hWnd)) ) return 0;
286 for ( pWnd = WIN_LockWndPtr(wndPtr->next); ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
288 if (!pWnd ) WIN_UpdateWndPtr(&pWnd,wndPtr->parent->child);
290 if ( pWnd == wndPtr ) break; /* went full circle */
292 if (!pWnd->owner && (pWnd->dwStyle & dwStyleMask) == WS_VISIBLE )
294 pWndLast = pWnd;
295 if ( bNext ) break;
298 WIN_ReleaseWndPtr(wndPtr);
299 WIN_ReleaseWndPtr(pWnd);
300 return pWndLast ? pWndLast->hwndSelf : 0;
303 /**********************************************************************
304 * MDI_CalcDefaultChildPos
306 * It seems that the default height is about 2/3 of the client rect
308 static void MDI_CalcDefaultChildPos( WND* w, WORD n, LPPOINT lpPos,
309 INT delta)
311 INT nstagger;
312 RECT rect = w->rectClient;
313 INT spacing = GetSystemMetrics(SM_CYCAPTION) +
314 GetSystemMetrics(SM_CYFRAME) - 1;
316 if( rect.bottom - rect.top - delta >= spacing )
317 rect.bottom -= delta;
319 nstagger = (rect.bottom - rect.top)/(3 * spacing);
320 lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
321 lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
322 lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
325 /**********************************************************************
326 * MDISetMenu
328 static LRESULT MDISetMenu( HWND hwnd, HMENU hmenuFrame,
329 HMENU hmenuWindow)
331 WND *w;
332 MDICLIENTINFO *ci;
333 HWND hwndFrame = GetParent(hwnd);
334 HMENU oldFrameMenu = GetMenu(hwndFrame);
336 TRACE("%04x %04x %04x\n",
337 hwnd, hmenuFrame, hmenuWindow);
339 if (hmenuFrame && !IsMenu(hmenuFrame))
341 WARN("hmenuFrame is not a menu handle\n");
342 return 0L;
345 if (hmenuWindow && !IsMenu(hmenuWindow))
347 WARN("hmenuWindow is not a menu handle\n");
348 return 0L;
351 w = WIN_FindWndPtr(hwnd);
352 ci = (MDICLIENTINFO *) w->wExtra;
354 if( ci->hwndChildMaximized && hmenuFrame && hmenuFrame!=oldFrameMenu )
355 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized );
357 if( hmenuWindow && ci->hWindowMenu && hmenuWindow!=ci->hWindowMenu )
359 /* delete menu items from ci->hWindowMenu
360 * and add them to hmenuWindow */
362 INT i = GetMenuItemCount(ci->hWindowMenu) - 1;
363 INT pos = GetMenuItemCount(hmenuWindow) + 1;
365 AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL);
367 if( ci->nActiveChildren )
369 INT j;
370 LPWSTR buffer = NULL;
371 MENUITEMINFOW mii;
372 INT nbWindowsMenuItems; /* num of documents shown + "More Windows..." if present */
374 if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
375 nbWindowsMenuItems = ci->nActiveChildren;
376 else
377 nbWindowsMenuItems = MDI_MOREWINDOWSLIMIT + 1;
379 j = i - nbWindowsMenuItems + 1;
381 for( ; i >= j ; i-- )
383 memset(&mii, 0, sizeof(mii));
384 mii.cbSize = sizeof(mii);
385 mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE
386 | MIIM_SUBMENU | MIIM_TYPE | MIIM_BITMAP;
388 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
389 if(mii.cch) { /* Menu is MFT_STRING */
390 mii.cch++; /* add room for '\0' */
391 buffer = HeapAlloc(GetProcessHeap(), 0,
392 mii.cch * sizeof(WCHAR));
393 mii.dwTypeData = buffer;
394 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
396 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
397 InsertMenuItemW(hmenuWindow, pos, TRUE, &mii);
398 if(buffer) {
399 HeapFree(GetProcessHeap(), 0, buffer);
400 buffer = NULL;
405 /* remove separator */
406 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
408 ci->hWindowMenu = hmenuWindow;
411 if (hmenuFrame)
413 SetMenu(hwndFrame, hmenuFrame);
414 if( hmenuFrame!=oldFrameMenu )
416 if( ci->hwndChildMaximized )
417 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
418 WIN_ReleaseWndPtr(w);
419 return oldFrameMenu;
422 else
424 INT nItems = GetMenuItemCount(w->parent->wIDmenu) - 1;
425 UINT iId = GetMenuItemID(w->parent->wIDmenu,nItems) ;
427 if( !(iId == SC_RESTORE || iId == SC_CLOSE) )
429 /* SetMenu() may already have been called, meaning that this window
430 * already has its menu. But they may have done a SetMenu() on
431 * an MDI window, and called MDISetMenu() after the fact, meaning
432 * that the "if" to this "else" wouldn't catch the need to
433 * augment the frame menu.
435 if( ci->hwndChildMaximized )
436 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
439 WIN_ReleaseWndPtr(w);
440 return 0;
443 /**********************************************************************
444 * MDIRefreshMenu
446 static LRESULT MDIRefreshMenu( HWND hwnd, HMENU hmenuFrame,
447 HMENU hmenuWindow)
449 HWND hwndFrame = GetParent(hwnd);
450 HMENU oldFrameMenu = GetMenu(hwndFrame);
452 TRACE("%04x %04x %04x\n",
453 hwnd, hmenuFrame, hmenuWindow);
455 FIXME("partially function stub\n");
457 return oldFrameMenu;
461 /* ------------------ MDI child window functions ---------------------- */
464 /**********************************************************************
465 * MDICreateChild
467 static HWND MDICreateChild( WND *w, MDICLIENTINFO *ci, HWND parent,
468 LPMDICREATESTRUCTA cs )
470 POINT pos[2];
471 DWORD style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
472 HWND hwnd, hwndMax = 0;
473 WORD wIDmenu = ci->idFirstChild + ci->nActiveChildren;
474 char lpstrDef[]="junk!";
476 TRACE("origin %i,%i - dim %i,%i, style %08lx\n",
477 cs->x, cs->y, cs->cx, cs->cy, cs->style);
478 /* calculate placement */
479 MDI_CalcDefaultChildPos(w, ci->nTotalCreated++, pos, 0);
481 if (cs->cx == CW_USEDEFAULT || !cs->cx) cs->cx = pos[1].x;
482 if (cs->cy == CW_USEDEFAULT || !cs->cy) cs->cy = pos[1].y;
484 if( cs->x == CW_USEDEFAULT )
486 cs->x = pos[0].x;
487 cs->y = pos[0].y;
490 /* restore current maximized child */
491 if( (style & WS_VISIBLE) && ci->hwndChildMaximized )
493 TRACE("Restoring current maximized child %04x\n", ci->hwndChildMaximized);
494 if( style & WS_MAXIMIZE )
495 SendMessageA(w->hwndSelf, WM_SETREDRAW, FALSE, 0L );
496 hwndMax = ci->hwndChildMaximized;
497 ShowWindow( hwndMax, SW_SHOWNOACTIVATE );
498 if( style & WS_MAXIMIZE )
499 SendMessageA(w->hwndSelf, WM_SETREDRAW, TRUE, 0L );
502 if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
503 /* this menu is needed to set a check mark in MDI_ChildActivate */
504 if (ci->hWindowMenu != 0)
505 AppendMenuA(ci->hWindowMenu ,MF_STRING ,wIDmenu, lpstrDef );
507 ci->nActiveChildren++;
509 /* fix window style */
510 if( !(w->dwStyle & MDIS_ALLCHILDSTYLES) )
512 TRACE("MDIS_ALLCHILDSTYLES is missing, fixing window style\n");
513 style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE |
514 WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL );
515 style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW);
518 if( w->flags & WIN_ISWIN32 )
520 hwnd = CreateWindowA( cs->szClass, cs->szTitle, style,
521 cs->x, cs->y, cs->cx, cs->cy, parent,
522 (HMENU)wIDmenu, cs->hOwner, cs );
524 else
526 MDICREATESTRUCT16 *cs16;
527 LPSTR title, cls;
529 cs16 = SEGPTR_NEW(MDICREATESTRUCT16);
530 STRUCT32_MDICREATESTRUCT32Ato16( cs, cs16 );
531 title = SEGPTR_STRDUP( cs->szTitle );
532 cls = SEGPTR_STRDUP( cs->szClass );
533 cs16->szTitle = SEGPTR_GET(title);
534 cs16->szClass = SEGPTR_GET(cls);
536 hwnd = CreateWindow16( cs->szClass, cs->szTitle, style,
537 cs16->x, cs16->y, cs16->cx, cs16->cy, parent,
538 (HMENU)wIDmenu, cs16->hOwner,
539 (LPVOID)SEGPTR_GET(cs16) );
540 SEGPTR_FREE( title );
541 SEGPTR_FREE( cls );
542 SEGPTR_FREE( cs16 );
545 /* MDI windows are WS_CHILD so they won't be activated by CreateWindow */
547 if (hwnd)
549 WND* wnd = WIN_FindWndPtr( hwnd );
551 /* All MDI child windows have the WS_EX_MDICHILD style */
552 wnd->dwExStyle |= WS_EX_MDICHILD;
554 /* If we have more than 9 windows, we must insert the new one at the
555 * 9th position in order to see it in the "Windows" menu
557 if (ci->nActiveChildren > MDI_MOREWINDOWSLIMIT)
558 MDI_SwapMenuItems(wnd->parent, wnd->wIDmenu, ci->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
560 MDI_MenuModifyItem(w ,hwnd);
562 /* Have we hit the "More Windows..." limit? If so, we must
563 * add a "More Windows..." option
565 if (ci->nActiveChildren == MDI_MOREWINDOWSLIMIT + 1)
567 char szTmp[50];
568 LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
570 ModifyMenuA(ci->hWindowMenu,
571 ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
572 MF_BYCOMMAND | MF_STRING,
573 ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
574 szTmp);
577 if( (wnd->dwStyle & WS_MINIMIZE) && ci->hwndActiveChild )
579 TRACE("Minimizing created MDI child %04x\n", hwnd);
580 ShowWindow( hwnd, SW_SHOWMINNOACTIVE );
582 else
584 /* WS_VISIBLE is clear if a) the MDI client has
585 * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the
586 * MDICreateStruct. If so the created window is not shown nor
587 * activated.
589 if(wnd->dwStyle & WS_VISIBLE)
590 ShowWindow(hwnd, SW_SHOW);
592 WIN_ReleaseWndPtr(wnd);
593 TRACE("created child - %04x\n",hwnd);
595 else
597 ci->nActiveChildren--;
598 DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
599 if( IsWindow(hwndMax) )
600 ShowWindow(hwndMax, SW_SHOWMAXIMIZED);
603 return hwnd;
606 /**********************************************************************
607 * MDI_ChildGetMinMaxInfo
609 * Note: The rule here is that client rect of the maximized MDI child
610 * is equal to the client rect of the MDI client window.
612 static void MDI_ChildGetMinMaxInfo( WND* clientWnd, HWND hwnd,
613 MINMAXINFO16* lpMinMax )
615 WND* childWnd = WIN_FindWndPtr(hwnd);
616 RECT rect = clientWnd->rectClient;
618 MapWindowPoints( clientWnd->parent->hwndSelf,
619 ((MDICLIENTINFO*)clientWnd->wExtra)->self, (LPPOINT)&rect, 2);
620 AdjustWindowRectEx( &rect, childWnd->dwStyle, 0, childWnd->dwExStyle );
622 lpMinMax->ptMaxSize.x = rect.right -= rect.left;
623 lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
625 lpMinMax->ptMaxPosition.x = rect.left;
626 lpMinMax->ptMaxPosition.y = rect.top;
628 WIN_ReleaseWndPtr(childWnd);
630 TRACE("max rect (%i,%i - %i, %i)\n",
631 rect.left,rect.top,rect.right,rect.bottom);
635 /**********************************************************************
636 * MDI_SwitchActiveChild
638 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
639 * being activated
641 static void MDI_SwitchActiveChild( HWND clientHwnd, HWND childHwnd,
642 BOOL bNextWindow )
644 WND *w = WIN_FindWndPtr(clientHwnd);
645 HWND hwndTo = 0;
646 HWND hwndPrev = 0;
647 MDICLIENTINFO *ci;
649 hwndTo = MDI_GetWindow(w, childHwnd, bNextWindow, 0);
651 ci = (MDICLIENTINFO *) w->wExtra;
653 TRACE("from %04x, to %04x\n",childHwnd,hwndTo);
655 if ( !hwndTo ) goto END; /* no window to switch to */
657 hwndPrev = ci->hwndActiveChild;
659 if ( hwndTo != hwndPrev )
661 BOOL bOptimize = 0;
663 if( ci->hwndChildMaximized )
665 bOptimize = 1;
666 w->dwStyle &= ~WS_VISIBLE;
669 SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0,
670 SWP_NOMOVE | SWP_NOSIZE );
672 if( bNextWindow && hwndPrev )
673 SetWindowPos( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0,
674 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
675 if( bOptimize )
676 ShowWindow( clientHwnd, SW_SHOW );
678 END:
679 WIN_ReleaseWndPtr(w);
683 /**********************************************************************
684 * MDIDestroyChild
686 static LRESULT MDIDestroyChild( WND *w_parent, MDICLIENTINFO *ci,
687 HWND parent, HWND child,
688 BOOL flagDestroy )
690 WND *childPtr = WIN_FindWndPtr(child);
692 if( childPtr )
694 if( child == ci->hwndActiveChild )
696 MDI_SwitchActiveChild(parent, child, TRUE);
698 if( child == ci->hwndActiveChild )
700 ShowWindow( child, SW_HIDE);
701 if( child == ci->hwndChildMaximized )
703 MDI_RestoreFrameMenu(w_parent->parent, child);
704 ci->hwndChildMaximized = 0;
705 MDI_UpdateFrameText(w_parent->parent,parent,TRUE,NULL);
708 MDI_ChildActivate(w_parent, 0);
712 MDI_MenuDeleteItem(w_parent, child);
714 WIN_ReleaseWndPtr(childPtr);
716 ci->nActiveChildren--;
718 TRACE("child destroyed - %04x\n",child);
720 if (flagDestroy)
722 MDI_PostUpdate(GetParent(child), ci, SB_BOTH+1);
723 DestroyWindow(child);
727 return 0;
731 /**********************************************************************
732 * MDI_ChildActivate
734 * Note: hWndChild is NULL when last child is being destroyed
736 static LONG MDI_ChildActivate( WND *clientPtr, HWND hWndChild )
738 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientPtr->wExtra;
739 HWND prevActiveWnd = clientInfo->hwndActiveChild;
740 WND *wndPtr = WIN_FindWndPtr( hWndChild );
741 WND *wndPrev = WIN_FindWndPtr( prevActiveWnd );
742 BOOL isActiveFrameWnd = 0;
743 LONG retvalue;
745 if( wndPtr )
747 if( wndPtr->dwStyle & WS_DISABLED )
749 retvalue = 0L;
750 goto END;
754 /* Don't activate if it is already active. Might happen
755 since ShowWindow DOES activate MDI children */
756 if (clientInfo->hwndActiveChild == hWndChild)
758 retvalue = 0L;
759 goto END;
762 TRACE("%04x\n", hWndChild);
764 if( GetActiveWindow() == clientPtr->parent->hwndSelf )
765 isActiveFrameWnd = TRUE;
767 /* deactivate prev. active child */
768 if( wndPrev )
770 wndPrev->dwStyle |= WS_SYSMENU;
771 SendMessageA( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
772 SendMessageA( prevActiveWnd, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
773 (LPARAM)hWndChild);
774 /* uncheck menu item */
775 if( clientInfo->hWindowMenu )
777 WORD wPrevID = wndPrev->wIDmenu - clientInfo->idFirstChild;
779 if (wPrevID < MDI_MOREWINDOWSLIMIT)
780 CheckMenuItem( clientInfo->hWindowMenu,
781 wndPrev->wIDmenu, 0);
782 else
783 CheckMenuItem( clientInfo->hWindowMenu,
784 clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1, 0);
788 /* set appearance */
789 if( clientInfo->hwndChildMaximized )
791 if( clientInfo->hwndChildMaximized != hWndChild ) {
792 if( hWndChild ) {
793 clientInfo->hwndActiveChild = hWndChild;
794 ShowWindow( hWndChild, SW_SHOWMAXIMIZED);
795 } else
796 ShowWindow( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
800 clientInfo->hwndActiveChild = hWndChild;
802 /* check if we have any children left */
803 if( !hWndChild )
805 if( isActiveFrameWnd )
806 SetFocus( clientInfo->self );
807 retvalue = 0;
808 goto END;
811 /* check menu item */
812 if( clientInfo->hWindowMenu )
814 /* The window to be activated must be displayed in the "Windows" menu */
815 if (wndPtr->wIDmenu >= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
817 MDI_SwapMenuItems(wndPtr->parent, wndPtr->wIDmenu, clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
818 MDI_MenuModifyItem(wndPtr->parent ,wndPtr->hwndSelf);
821 CheckMenuItem(clientInfo->hWindowMenu, wndPtr->wIDmenu, MF_CHECKED);
823 /* bring active child to the top */
824 SetWindowPos( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
826 if( isActiveFrameWnd )
828 SendMessageA( hWndChild, WM_NCACTIVATE, TRUE, 0L);
829 if( GetFocus() == clientInfo->self )
830 SendMessageA( clientInfo->self, WM_SETFOCUS,
831 (WPARAM)clientInfo->self, 0L );
832 else
833 SetFocus( clientInfo->self );
835 SendMessageA( hWndChild, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
836 (LPARAM)hWndChild );
837 retvalue = 1;
838 END:
839 WIN_ReleaseWndPtr(wndPtr);
840 WIN_ReleaseWndPtr(wndPrev);
841 return retvalue;
844 /* -------------------- MDI client window functions ------------------- */
846 /**********************************************************************
847 * CreateMDIMenuBitmap
849 static HBITMAP16 CreateMDIMenuBitmap(void)
851 HDC hDCSrc = CreateCompatibleDC(0);
852 HDC hDCDest = CreateCompatibleDC(hDCSrc);
853 HBITMAP16 hbClose = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CLOSE) );
854 HBITMAP16 hbCopy;
855 HANDLE16 hobjSrc, hobjDest;
857 hobjSrc = SelectObject(hDCSrc, hbClose);
858 hbCopy = CreateCompatibleBitmap(hDCSrc,GetSystemMetrics(SM_CXSIZE),GetSystemMetrics(SM_CYSIZE));
859 hobjDest = SelectObject(hDCDest, hbCopy);
861 BitBlt(hDCDest, 0, 0, GetSystemMetrics(SM_CXSIZE), GetSystemMetrics(SM_CYSIZE),
862 hDCSrc, GetSystemMetrics(SM_CXSIZE), 0, SRCCOPY);
864 SelectObject(hDCSrc, hobjSrc);
865 DeleteObject(hbClose);
866 DeleteDC(hDCSrc);
868 hobjSrc = SelectObject( hDCDest, GetStockObject(BLACK_PEN) );
870 MoveToEx( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, 0, NULL );
871 LineTo( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, GetSystemMetrics(SM_CYSIZE) - 1);
873 SelectObject(hDCDest, hobjSrc );
874 SelectObject(hDCDest, hobjDest);
875 DeleteDC(hDCDest);
877 return hbCopy;
880 /**********************************************************************
881 * MDICascade
883 static LONG MDICascade(WND* clientWnd, MDICLIENTINFO *ci)
885 WND** ppWnd;
886 UINT total;
888 if (ci->hwndChildMaximized)
889 SendMessageA( clientWnd->hwndSelf, WM_MDIRESTORE,
890 (WPARAM)ci->hwndChildMaximized, 0);
892 if (ci->nActiveChildren == 0) return 0;
894 if ((ppWnd = WIN_BuildWinArray(clientWnd, BWA_SKIPHIDDEN | BWA_SKIPOWNED |
895 BWA_SKIPICONIC, &total)))
897 WND** heapPtr = ppWnd;
898 if( total )
900 INT delta = 0, n = 0;
901 POINT pos[2];
902 if( total < ci->nActiveChildren )
903 delta = GetSystemMetrics(SM_CYICONSPACING) +
904 GetSystemMetrics(SM_CYICON);
906 /* walk the list (backwards) and move windows */
907 while (*ppWnd) ppWnd++;
908 while (ppWnd != heapPtr)
910 ppWnd--;
911 TRACE("move %04x to (%ld,%ld) size [%ld,%ld]\n",
912 (*ppWnd)->hwndSelf, pos[0].x, pos[0].y, pos[1].x, pos[1].y);
914 MDI_CalcDefaultChildPos(clientWnd, n++, pos, delta);
915 SetWindowPos( (*ppWnd)->hwndSelf, 0, pos[0].x, pos[0].y,
916 pos[1].x, pos[1].y,
917 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
920 WIN_ReleaseWinArray(heapPtr);
923 if( total < ci->nActiveChildren )
924 ArrangeIconicWindows( clientWnd->hwndSelf );
925 return 0;
928 /**********************************************************************
929 * MDITile
931 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM wParam )
933 WND** ppWnd;
934 UINT total = 0;
936 if (ci->hwndChildMaximized)
937 SendMessageA( wndClient->hwndSelf, WM_MDIRESTORE,
938 (WPARAM)ci->hwndChildMaximized, 0);
940 if (ci->nActiveChildren == 0) return;
942 ppWnd = WIN_BuildWinArray(wndClient, BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
943 ((wParam & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
945 TRACE("%u windows to tile\n", total);
947 if( ppWnd )
949 WND** heapPtr = ppWnd;
951 if( total )
953 RECT rect;
954 int x, y, xsize, ysize;
955 int rows, columns, r, c, i;
957 GetClientRect(wndClient->hwndSelf,&rect);
958 rows = (int) sqrt((double)total);
959 columns = total / rows;
961 if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */
963 i = rows;
964 rows = columns; /* exchange r and c */
965 columns = i;
968 if( total != ci->nActiveChildren)
970 y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
971 rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
974 ysize = rect.bottom / rows;
975 xsize = rect.right / columns;
977 for (x = i = 0, c = 1; c <= columns && *ppWnd; c++)
979 if (c == columns)
981 rows = total - i;
982 ysize = rect.bottom / rows;
985 y = 0;
986 for (r = 1; r <= rows && *ppWnd; r++, i++)
988 SetWindowPos((*ppWnd)->hwndSelf, 0, x, y, xsize, ysize,
989 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
990 y += ysize;
991 ppWnd++;
993 x += xsize;
996 WIN_ReleaseWinArray(heapPtr);
999 if( total < ci->nActiveChildren ) ArrangeIconicWindows( wndClient->hwndSelf );
1002 /* ----------------------- Frame window ---------------------------- */
1005 /**********************************************************************
1006 * MDI_AugmentFrameMenu
1008 static BOOL MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
1009 HWND hChild )
1011 WND* child = WIN_FindWndPtr(hChild);
1012 HMENU hSysPopup = 0;
1013 HBITMAP hSysMenuBitmap = 0;
1015 TRACE("frame %p,child %04x\n",frame,hChild);
1017 if( !frame->wIDmenu || !child->hSysMenu )
1019 WIN_ReleaseWndPtr(child);
1020 return 0;
1022 WIN_ReleaseWndPtr(child);
1024 /* create a copy of sysmenu popup and insert it into frame menu bar */
1026 if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
1027 return 0;
1029 TRACE("\tgot popup %04x in sysmenu %04x\n",
1030 hSysPopup, child->hSysMenu);
1032 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
1033 SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
1034 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
1035 SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
1037 /* In Win 95 look, the system menu is replaced by the child icon */
1039 if(TWEAK_WineLook > WIN31_LOOK)
1041 HICON hIcon = GetClassLongA(hChild, GCL_HICONSM);
1042 if (!hIcon)
1043 hIcon = GetClassLongA(hChild, GCL_HICON);
1044 if (hIcon)
1046 HDC hMemDC;
1047 HBITMAP hBitmap, hOldBitmap;
1048 HBRUSH hBrush;
1049 HDC hdc = GetDC(hChild);
1051 if (hdc)
1053 int cx, cy;
1054 cx = GetSystemMetrics(SM_CXSMICON);
1055 cy = GetSystemMetrics(SM_CYSMICON);
1056 hMemDC = CreateCompatibleDC(hdc);
1057 hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
1058 hOldBitmap = SelectObject(hMemDC, hBitmap);
1059 SetMapMode(hMemDC, MM_TEXT);
1060 hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
1061 DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL);
1062 SelectObject (hMemDC, hOldBitmap);
1063 DeleteObject(hBrush);
1064 DeleteDC(hMemDC);
1065 ReleaseDC(hChild, hdc);
1066 hSysMenuBitmap = hBitmap;
1070 else
1071 hSysMenuBitmap = hBmpClose;
1073 if( !InsertMenuA(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
1074 hSysPopup, (LPSTR)(DWORD)hSysMenuBitmap))
1076 TRACE("not inserted\n");
1077 DestroyMenu(hSysPopup);
1078 return 0;
1081 /* The close button is only present in Win 95 look */
1082 if(TWEAK_WineLook > WIN31_LOOK)
1084 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
1085 SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
1088 EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
1089 EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
1090 EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
1091 SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE);
1093 /* redraw menu */
1094 DrawMenuBar(frame->hwndSelf);
1096 return 1;
1099 /**********************************************************************
1100 * MDI_RestoreFrameMenu
1102 static BOOL MDI_RestoreFrameMenu( WND *frameWnd, HWND hChild )
1104 MENUITEMINFOA menuInfo;
1105 INT nItems = GetMenuItemCount(frameWnd->wIDmenu) - 1;
1106 UINT iId = GetMenuItemID(frameWnd->wIDmenu,nItems) ;
1108 TRACE("frameWnd %p,(%04x),child %04x,nIt=%d,iId=%d\n",
1109 frameWnd,frameWnd->hwndSelf,hChild,nItems,iId);
1111 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
1112 return 0;
1115 * Remove the system menu, If that menu is the icon of the window
1116 * as it is in win95, we have to delete the bitmap.
1118 menuInfo.cbSize = sizeof(MENUITEMINFOA);
1119 menuInfo.fMask = MIIM_DATA | MIIM_TYPE;
1121 GetMenuItemInfoA(frameWnd->wIDmenu,
1123 TRUE,
1124 &menuInfo);
1126 RemoveMenu(frameWnd->wIDmenu,0,MF_BYPOSITION);
1128 if ( (menuInfo.fType & MFT_BITMAP) &&
1129 (LOWORD(menuInfo.dwTypeData)!=0) &&
1130 (LOWORD(menuInfo.dwTypeData)!=hBmpClose) )
1132 DeleteObject((HBITMAP)LOWORD(menuInfo.dwTypeData));
1135 if(TWEAK_WineLook > WIN31_LOOK)
1137 /* close */
1138 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1140 /* restore */
1141 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1142 /* minimize */
1143 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1145 DrawMenuBar(frameWnd->hwndSelf);
1147 return 1;
1151 /**********************************************************************
1152 * MDI_UpdateFrameText
1154 * used when child window is maximized/restored
1156 * Note: lpTitle can be NULL
1158 static void MDI_UpdateFrameText( WND *frameWnd, HWND hClient,
1159 BOOL repaint, LPCWSTR lpTitle )
1161 WCHAR lpBuffer[MDI_MAXTITLELENGTH+1];
1162 WND* clientWnd = WIN_FindWndPtr(hClient);
1163 MDICLIENTINFO *ci = (MDICLIENTINFO *) clientWnd->wExtra;
1165 TRACE("repaint %i, frameText %s\n", repaint, (lpTitle)?debugstr_w(lpTitle):"NULL");
1167 if (!clientWnd)
1168 return;
1170 if (!ci)
1172 WIN_ReleaseWndPtr(clientWnd);
1173 return;
1176 /* store new "default" title if lpTitle is not NULL */
1177 if (lpTitle)
1179 if (ci->frameTitle) HeapFree( SystemHeap, 0, ci->frameTitle );
1180 ci->frameTitle = HEAP_strdupW( SystemHeap, 0, lpTitle );
1183 if (ci->frameTitle)
1185 WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );
1187 if( childWnd && childWnd->text )
1189 /* combine frame title and child title if possible */
1191 static const WCHAR lpBracket[] = {' ','-',' ','[',0};
1192 static const WCHAR lpBracket2[] = {']',0};
1193 int i_frame_text_length = strlenW(ci->frameTitle);
1194 int i_child_text_length = strlenW(childWnd->text);
1196 lstrcpynW( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
1198 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
1200 strcatW( lpBuffer, lpBracket );
1202 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
1204 strcatW( lpBuffer, childWnd->text );
1205 strcatW( lpBuffer, lpBracket2 );
1207 else
1209 lstrcpynW( lpBuffer + i_frame_text_length + 4,
1210 childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
1211 strcatW( lpBuffer, lpBracket2 );
1215 else
1217 lstrcpynW(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH+1 );
1219 WIN_ReleaseWndPtr(childWnd);
1222 else
1223 lpBuffer[0] = '\0';
1225 DEFWND_SetTextW( frameWnd, lpBuffer );
1226 if( repaint == MDI_REPAINTFRAME)
1227 SetWindowPos( frameWnd->hwndSelf, 0,0,0,0,0, SWP_FRAMECHANGED |
1228 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
1230 WIN_ReleaseWndPtr(clientWnd);
1235 /* ----------------------------- Interface ---------------------------- */
1238 /**********************************************************************
1239 * MDIClientWndProcA
1241 * This function handles all MDI requests.
1243 static LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
1245 LPCREATESTRUCTA cs;
1246 MDICLIENTINFO *ci;
1247 RECT rect;
1248 WND *w, *frameWnd;
1249 INT nItems;
1250 LRESULT retvalue;
1252 if ( ( w = WIN_FindWndPtr(hwnd) ) == NULL )
1253 return 0;
1255 if ( ( frameWnd = WIN_LockWndPtr(w->parent) ) == NULL ) {
1256 WIN_ReleaseWndPtr(w);
1257 return 0;
1260 ci = (MDICLIENTINFO *) w->wExtra;
1262 switch (message)
1264 case WM_CREATE:
1266 cs = (LPCREATESTRUCTA)lParam;
1268 /* Translation layer doesn't know what's in the cs->lpCreateParams
1269 * so we have to keep track of what environment we're in. */
1271 if( w->flags & WIN_ISWIN32 )
1273 #define ccs ((LPCLIENTCREATESTRUCT)cs->lpCreateParams)
1274 ci->hWindowMenu = ccs->hWindowMenu;
1275 ci->idFirstChild = ccs->idFirstChild;
1276 #undef ccs
1278 else
1280 LPCLIENTCREATESTRUCT16 ccs = MapSL((SEGPTR)cs->lpCreateParams);
1281 ci->hWindowMenu = ccs->hWindowMenu;
1282 ci->idFirstChild = ccs->idFirstChild;
1285 ci->hwndChildMaximized = 0;
1286 ci->nActiveChildren = 0;
1287 ci->nTotalCreated = 0;
1288 ci->frameTitle = NULL;
1289 ci->mdiFlags = 0;
1290 ci->self = hwnd;
1291 w->dwStyle |= WS_CLIPCHILDREN;
1293 if (!hBmpClose)
1295 hBmpClose = CreateMDIMenuBitmap();
1296 hBmpRestore = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_RESTORE) );
1298 MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
1300 if (ci->hWindowMenu != 0)
1301 AppendMenuA( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
1303 GetClientRect(frameWnd->hwndSelf, &rect);
1304 NC_HandleNCCalcSize( w, &rect );
1305 w->rectClient = rect;
1307 TRACE("Client created - hwnd = %04x, idFirst = %u\n",
1308 hwnd, ci->idFirstChild );
1310 retvalue = 0;
1311 goto END;
1313 case WM_DESTROY:
1314 if( ci->hwndChildMaximized )
1315 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized);
1316 if((ci->hWindowMenu != 0) &&
1317 (nItems = GetMenuItemCount(ci->hWindowMenu)) > 0)
1319 ci->idFirstChild = nItems - 1;
1320 ci->nActiveChildren++; /* to delete a separator */
1321 while( ci->nActiveChildren-- )
1322 DeleteMenu(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
1324 retvalue = 0;
1325 goto END;
1327 case WM_MDIACTIVATE:
1328 if( ci->hwndActiveChild != (HWND)wParam )
1329 SetWindowPos((HWND)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
1330 retvalue = 0;
1331 goto END;
1333 case WM_MDICASCADE:
1334 retvalue = MDICascade(w, ci);
1335 goto END;
1337 case WM_MDICREATE:
1338 if (lParam) retvalue = MDICreateChild( w, ci, hwnd,
1339 (MDICREATESTRUCTA*)lParam );
1340 else retvalue = 0;
1341 goto END;
1343 case WM_MDIDESTROY:
1344 retvalue = MDIDestroyChild( w, ci, hwnd, (HWND)wParam, TRUE );
1345 goto END;
1347 case WM_MDIGETACTIVE:
1348 if (lParam) *(BOOL *)lParam = (ci->hwndChildMaximized > 0);
1349 retvalue = ci->hwndActiveChild;
1350 goto END;
1352 case WM_MDIICONARRANGE:
1353 ci->mdiFlags |= MDIF_NEEDUPDATE;
1354 ArrangeIconicWindows(hwnd);
1355 ci->sbRecalc = SB_BOTH+1;
1356 SendMessageA(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
1357 retvalue = 0;
1358 goto END;
1360 case WM_MDIMAXIMIZE:
1361 ShowWindow( (HWND)wParam, SW_MAXIMIZE );
1362 retvalue = 0;
1363 goto END;
1365 case WM_MDINEXT: /* lParam != 0 means previous window */
1366 MDI_SwitchActiveChild(hwnd, (HWND)wParam, (lParam)? FALSE : TRUE );
1367 break;
1369 case WM_MDIRESTORE:
1370 SendMessageA( (HWND)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
1371 retvalue = 0;
1372 goto END;
1374 case WM_MDISETMENU:
1375 retvalue = MDISetMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1376 goto END;
1377 case WM_MDIREFRESHMENU:
1378 retvalue = MDIRefreshMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1379 goto END;
1381 case WM_MDITILE:
1382 ci->mdiFlags |= MDIF_NEEDUPDATE;
1383 ShowScrollBar(hwnd,SB_BOTH,FALSE);
1384 MDITile(w, ci, wParam);
1385 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1386 retvalue = 0;
1387 goto END;
1389 case WM_VSCROLL:
1390 case WM_HSCROLL:
1391 ci->mdiFlags |= MDIF_NEEDUPDATE;
1392 ScrollChildren(hwnd, message, wParam, lParam);
1393 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1394 retvalue = 0;
1395 goto END;
1397 case WM_SETFOCUS:
1398 if( ci->hwndActiveChild )
1400 WND* pw = WIN_FindWndPtr( ci->hwndActiveChild );
1401 if( !(pw->dwStyle & WS_MINIMIZE) )
1402 SetFocus( ci->hwndActiveChild );
1403 WIN_ReleaseWndPtr(pw);
1405 retvalue = 0;
1406 goto END;
1408 case WM_NCACTIVATE:
1409 if( ci->hwndActiveChild )
1410 SendMessageA(ci->hwndActiveChild, message, wParam, lParam);
1411 break;
1413 case WM_PARENTNOTIFY:
1414 if (LOWORD(wParam) == WM_LBUTTONDOWN)
1416 HWND child;
1417 POINT pt;
1418 pt.x = SLOWORD(lParam);
1419 pt.y = SHIWORD(lParam);
1420 child = ChildWindowFromPoint(hwnd, pt);
1422 TRACE("notification from %04x (%li,%li)\n",child,pt.x,pt.y);
1424 if( child && child != hwnd && child != ci->hwndActiveChild )
1425 SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1427 retvalue = 0;
1428 goto END;
1430 case WM_SIZE:
1431 if( IsWindow(ci->hwndChildMaximized) )
1433 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1434 RECT rect;
1436 rect.left = 0;
1437 rect.top = 0;
1438 rect.right = LOWORD(lParam);
1439 rect.bottom = HIWORD(lParam);
1441 AdjustWindowRectEx(&rect, child->dwStyle, 0, child->dwExStyle);
1442 MoveWindow(ci->hwndChildMaximized, rect.left, rect.top,
1443 rect.right - rect.left, rect.bottom - rect.top, 1);
1444 WIN_ReleaseWndPtr(child);
1446 else
1447 MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1449 break;
1451 case WM_MDICALCCHILDSCROLL:
1452 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1454 CalcChildScroll16(hwnd, ci->sbRecalc-1);
1455 ci->sbRecalc = 0;
1456 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1458 retvalue = 0;
1459 goto END;
1462 retvalue = DefWindowProcA( hwnd, message, wParam, lParam );
1463 END:
1464 WIN_ReleaseWndPtr(w);
1465 WIN_ReleaseWndPtr(frameWnd);
1466 return retvalue;
1470 /***********************************************************************
1471 * DefFrameProc (USER.445)
1473 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1474 UINT16 message, WPARAM16 wParam, LPARAM lParam )
1476 HWND16 childHwnd;
1477 MDICLIENTINFO* ci;
1478 WND* wndPtr;
1480 if (hwndMDIClient)
1482 switch (message)
1484 case WM_COMMAND:
1485 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1487 if (!wndPtr) {
1488 ERR("null wndPtr for mdi window hwndMDIClient=%04x\n",
1489 hwndMDIClient);
1490 return 0;
1493 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1495 /* check for possible syscommands for maximized MDI child */
1496 WIN_ReleaseWndPtr(wndPtr);
1498 if( ci && (
1499 wParam < ci->idFirstChild ||
1500 wParam >= ci->idFirstChild + ci->nActiveChildren
1502 if( (wParam - 0xF000) & 0xF00F ) break;
1503 switch( wParam )
1505 case SC_SIZE:
1506 case SC_MOVE:
1507 case SC_MINIMIZE:
1508 case SC_MAXIMIZE:
1509 case SC_NEXTWINDOW:
1510 case SC_PREVWINDOW:
1511 case SC_CLOSE:
1512 case SC_RESTORE:
1513 if( ci->hwndChildMaximized )
1514 return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1515 wParam, lParam);
1518 else
1520 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1521 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1523 if (wParam - ci->idFirstChild == MDI_MOREWINDOWSLIMIT)
1524 /* User chose "More Windows..." */
1525 childHwnd = MDI_MoreWindowsDialog(wndPtr);
1526 else
1527 /* User chose one of the windows listed in the "Windows" menu */
1528 childHwnd = MDI_GetChildByID(wndPtr,wParam );
1530 WIN_ReleaseWndPtr(wndPtr);
1531 if( childHwnd )
1532 SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1533 (WPARAM16)childHwnd , 0L);
1535 break;
1537 case WM_NCACTIVATE:
1538 SendMessage16(hwndMDIClient, message, wParam, lParam);
1539 break;
1541 case WM_SETTEXT:
1543 LPWSTR text = HEAP_strdupAtoW( GetProcessHeap(), 0, MapSL(lParam) );
1544 wndPtr = WIN_FindWndPtr(hwnd);
1545 MDI_UpdateFrameText(wndPtr, hwndMDIClient,
1546 MDI_REPAINTFRAME, text );
1547 WIN_ReleaseWndPtr(wndPtr);
1548 HeapFree( GetProcessHeap(), 0, text );
1550 return 1; /* success. FIXME: check text length */
1552 case WM_SETFOCUS:
1553 SetFocus(hwndMDIClient);
1554 break;
1556 case WM_SIZE:
1557 MoveWindow16(hwndMDIClient, 0, 0,
1558 LOWORD(lParam), HIWORD(lParam), TRUE);
1559 break;
1561 case WM_NEXTMENU:
1563 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1564 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1566 if( !(wndPtr->parent->dwStyle & WS_MINIMIZE)
1567 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1569 /* control menu is between the frame system menu and
1570 * the first entry of menu bar */
1572 if( (wParam == VK_LEFT &&
1573 wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1574 (wParam == VK_RIGHT &&
1575 GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1577 LRESULT retvalue;
1578 WIN_ReleaseWndPtr(wndPtr);
1579 wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1580 retvalue = MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1581 ci->hwndActiveChild);
1582 WIN_ReleaseWndPtr(wndPtr);
1583 return retvalue;
1586 WIN_ReleaseWndPtr(wndPtr);
1587 break;
1591 return DefWindowProc16(hwnd, message, wParam, lParam);
1595 /***********************************************************************
1596 * DefFrameProcA (USER32.@)
1598 LRESULT WINAPI DefFrameProcA( HWND hwnd, HWND hwndMDIClient,
1599 UINT message, WPARAM wParam, LPARAM lParam)
1601 if (hwndMDIClient)
1603 switch (message)
1605 case WM_COMMAND:
1606 return DefFrameProc16( hwnd, hwndMDIClient, message,
1607 (WPARAM16)wParam,
1608 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1610 case WM_NCACTIVATE:
1611 SendMessageA(hwndMDIClient, message, wParam, lParam);
1612 break;
1614 case WM_SETTEXT: {
1615 LRESULT ret;
1616 LPSTR segstr = SEGPTR_STRDUP((LPSTR)lParam);
1618 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1619 wParam, (LPARAM)SEGPTR_GET(segstr) );
1620 SEGPTR_FREE(segstr);
1621 return ret;
1624 case WM_NEXTMENU:
1625 case WM_SETFOCUS:
1626 case WM_SIZE:
1627 return DefFrameProc16( hwnd, hwndMDIClient, message,
1628 wParam, lParam );
1632 return DefWindowProcA(hwnd, message, wParam, lParam);
1636 /***********************************************************************
1637 * DefFrameProcW (USER32.@)
1639 LRESULT WINAPI DefFrameProcW( HWND hwnd, HWND hwndMDIClient,
1640 UINT message, WPARAM wParam, LPARAM lParam)
1642 if (hwndMDIClient)
1644 switch (message)
1646 case WM_COMMAND:
1647 return DefFrameProc16( hwnd, hwndMDIClient, message,
1648 (WPARAM16)wParam,
1649 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1651 case WM_NCACTIVATE:
1652 SendMessageW(hwndMDIClient, message, wParam, lParam);
1653 break;
1655 case WM_SETTEXT:
1657 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1658 LRESULT ret = DefFrameProcA( hwnd, hwndMDIClient, message,
1659 wParam, (DWORD)txt );
1660 HeapFree(GetProcessHeap(),0,txt);
1661 return ret;
1663 case WM_NEXTMENU:
1664 case WM_SETFOCUS:
1665 case WM_SIZE:
1666 return DefFrameProcA( hwnd, hwndMDIClient, message,
1667 wParam, lParam );
1671 return DefWindowProcW( hwnd, message, wParam, lParam );
1675 /***********************************************************************
1676 * DefMDIChildProc (USER.447)
1678 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1679 WPARAM16 wParam, LPARAM lParam )
1681 MDICLIENTINFO *ci;
1682 WND *clientWnd,*tmpWnd = 0;
1683 LRESULT retvalue;
1685 tmpWnd = WIN_FindWndPtr(hwnd);
1686 if (!tmpWnd) return 0;
1687 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1688 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1689 WIN_ReleaseWndPtr(tmpWnd);
1691 /* Sanity check */
1692 if (clientWnd->cbWndExtra < sizeof(MDICLIENTINFO))
1694 WARN("called on non-MDI child window %x\n", hwnd);
1695 WIN_ReleaseWndPtr(clientWnd);
1696 return DefWindowProc16(hwnd, message, wParam, lParam);
1699 switch (message)
1701 case WM_SETTEXT:
1702 DefWindowProc16(hwnd, message, wParam, lParam);
1703 MDI_MenuModifyItem(clientWnd,hwnd);
1704 if( ci->hwndChildMaximized == hwnd )
1705 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1706 MDI_REPAINTFRAME, NULL );
1707 retvalue = 1; /* success. FIXME: check text length */
1708 goto END;
1710 case WM_CLOSE:
1711 SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1712 retvalue = 0;
1713 goto END;
1715 case WM_SETFOCUS:
1716 if( ci->hwndActiveChild != hwnd )
1717 MDI_ChildActivate(clientWnd, hwnd);
1718 break;
1720 case WM_CHILDACTIVATE:
1721 MDI_ChildActivate(clientWnd, hwnd);
1722 retvalue = 0;
1723 goto END;
1725 case WM_NCPAINT:
1726 TRACE("WM_NCPAINT for %04x, active %04x\n",
1727 hwnd, ci->hwndActiveChild );
1728 break;
1730 case WM_SYSCOMMAND:
1731 switch( wParam )
1733 case SC_MOVE:
1734 if( ci->hwndChildMaximized == hwnd)
1736 retvalue = 0;
1737 goto END;
1739 break;
1740 case SC_RESTORE:
1741 case SC_MINIMIZE:
1742 tmpWnd = WIN_FindWndPtr(hwnd);
1743 tmpWnd->dwStyle |= WS_SYSMENU;
1744 WIN_ReleaseWndPtr(tmpWnd);
1745 break;
1746 case SC_MAXIMIZE:
1747 if( ci->hwndChildMaximized == hwnd)
1749 retvalue = SendMessage16( clientWnd->parent->hwndSelf,
1750 message, wParam, lParam);
1751 goto END;
1753 tmpWnd = WIN_FindWndPtr(hwnd);
1754 tmpWnd->dwStyle &= ~WS_SYSMENU;
1755 WIN_ReleaseWndPtr(tmpWnd);
1756 break;
1757 case SC_NEXTWINDOW:
1758 SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1759 retvalue = 0;
1760 goto END;
1761 case SC_PREVWINDOW:
1762 SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1763 retvalue = 0;
1764 goto END;
1766 break;
1768 case WM_GETMINMAXINFO:
1769 MDI_ChildGetMinMaxInfo(clientWnd, hwnd, MapSL(lParam));
1770 retvalue = 0;
1771 goto END;
1773 case WM_SETVISIBLE:
1774 if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1775 else
1776 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1777 break;
1779 case WM_SIZE:
1780 /* do not change */
1782 if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1784 ci->hwndChildMaximized = 0;
1786 MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1787 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1788 MDI_REPAINTFRAME, NULL );
1791 if( wParam == SIZE_MAXIMIZED )
1793 HWND16 hMaxChild = ci->hwndChildMaximized;
1795 if( hMaxChild == hwnd ) break;
1797 if( hMaxChild)
1799 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1801 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1802 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1804 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1807 TRACE("maximizing child %04x\n", hwnd );
1810 * Keep track of the maximized window.
1812 ci->hwndChildMaximized = hwnd; /* !!! */
1815 * The maximized window should also be the active window
1817 MDI_ChildActivate(clientWnd, hwnd);
1819 MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1820 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1821 MDI_REPAINTFRAME, NULL );
1824 if( wParam == SIZE_MINIMIZED )
1826 HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1828 if( switchTo )
1829 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1832 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1833 break;
1835 case WM_MENUCHAR:
1837 /* MDI children don't have menu bars */
1838 retvalue = 0x00010000L;
1839 goto END;
1841 case WM_NEXTMENU:
1843 if( wParam == VK_LEFT ) /* switch to frame system menu */
1845 retvalue = MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1846 clientWnd->parent->hwndSelf );
1847 goto END;
1849 if( wParam == VK_RIGHT ) /* to frame menu bar */
1851 retvalue = MAKELONG( clientWnd->parent->wIDmenu,
1852 clientWnd->parent->hwndSelf );
1853 goto END;
1856 break;
1858 case WM_SYSCHAR:
1859 if (wParam == '-')
1861 SendMessage16(hwnd,WM_SYSCOMMAND,
1862 (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1863 retvalue = 0;
1864 goto END;
1868 retvalue = DefWindowProc16(hwnd, message, wParam, lParam);
1869 END:
1870 WIN_ReleaseWndPtr(clientWnd);
1871 return retvalue;
1875 /***********************************************************************
1876 * DefMDIChildProcA (USER32.@)
1878 LRESULT WINAPI DefMDIChildProcA( HWND hwnd, UINT message,
1879 WPARAM wParam, LPARAM lParam )
1881 MDICLIENTINFO *ci;
1882 WND *clientWnd,*tmpWnd;
1883 LRESULT retvalue;
1885 tmpWnd = WIN_FindWndPtr(hwnd);
1886 if (!tmpWnd) return 0;
1887 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1888 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1889 WIN_ReleaseWndPtr(tmpWnd);
1891 /* Sanity check */
1892 if (clientWnd->cbWndExtra < sizeof(MDICLIENTINFO))
1894 WARN("called on non-MDI child window %x\n", hwnd);
1895 WIN_ReleaseWndPtr(clientWnd);
1896 return DefWindowProcA(hwnd, message, wParam, lParam);
1899 switch (message)
1901 case WM_SETTEXT:
1902 DefWindowProcA(hwnd, message, wParam, lParam);
1903 MDI_MenuModifyItem(clientWnd,hwnd);
1904 if( ci->hwndChildMaximized == hwnd )
1905 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1906 MDI_REPAINTFRAME, NULL );
1907 retvalue = 1; /* success. FIXME: check text length */
1908 goto END;
1910 case WM_GETMINMAXINFO:
1912 MINMAXINFO16 mmi;
1913 STRUCT32_MINMAXINFO32to16( (MINMAXINFO *)lParam, &mmi );
1914 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1915 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO *)lParam );
1917 retvalue = 0;
1918 goto END;
1920 case WM_MENUCHAR:
1922 /* MDI children don't have menu bars */
1923 retvalue = 0x00010000L;
1924 goto END;
1926 case WM_CLOSE:
1927 case WM_SETFOCUS:
1928 case WM_CHILDACTIVATE:
1929 case WM_NCPAINT:
1930 case WM_SYSCOMMAND:
1931 case WM_SETVISIBLE:
1932 case WM_SIZE:
1933 case WM_NEXTMENU:
1934 retvalue = DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1935 goto END;
1937 case WM_SYSCHAR:
1938 if (wParam == '-')
1940 SendMessageA(hwnd,WM_SYSCOMMAND,
1941 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1942 retvalue = 0;
1943 goto END;
1946 retvalue = DefWindowProcA(hwnd, message, wParam, lParam);
1947 END:
1948 WIN_ReleaseWndPtr(clientWnd);
1949 return retvalue;
1953 /***********************************************************************
1954 * DefMDIChildProcW (USER32.@)
1956 LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message,
1957 WPARAM wParam, LPARAM lParam )
1959 MDICLIENTINFO *ci;
1960 WND *clientWnd,*tmpWnd;
1961 LRESULT retvalue;
1963 tmpWnd = WIN_FindWndPtr(hwnd);
1964 if (!tmpWnd) return 0;
1965 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1966 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1967 WIN_ReleaseWndPtr(tmpWnd);
1969 /* Sanity check */
1970 if (clientWnd->cbWndExtra < sizeof(MDICLIENTINFO))
1972 WARN("called on non-MDI child window %x\n", hwnd);
1973 WIN_ReleaseWndPtr(clientWnd);
1974 return DefWindowProcW(hwnd, message, wParam, lParam);
1977 switch (message)
1979 case WM_SETTEXT:
1980 DefWindowProcW(hwnd, message, wParam, lParam);
1981 MDI_MenuModifyItem(clientWnd,hwnd);
1982 if( ci->hwndChildMaximized == hwnd )
1983 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1984 MDI_REPAINTFRAME, NULL );
1985 retvalue = 1; /* success. FIXME: check text length */
1986 goto END;
1988 case WM_GETMINMAXINFO:
1989 case WM_MENUCHAR:
1990 case WM_CLOSE:
1991 case WM_SETFOCUS:
1992 case WM_CHILDACTIVATE:
1993 case WM_NCPAINT:
1994 case WM_SYSCOMMAND:
1995 case WM_SETVISIBLE:
1996 case WM_SIZE:
1997 case WM_NEXTMENU:
1998 retvalue = DefMDIChildProcA( hwnd, message, (WPARAM16)wParam, lParam );
1999 goto END;
2001 case WM_SYSCHAR:
2002 if (wParam == '-')
2004 SendMessageW(hwnd,WM_SYSCOMMAND,
2005 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
2006 retvalue = 0;
2007 goto END;
2010 retvalue = DefWindowProcW(hwnd, message, wParam, lParam);
2011 END:
2012 WIN_ReleaseWndPtr(clientWnd);
2013 return retvalue;
2018 /**********************************************************************
2019 * CreateMDIWindowA (USER32.@) Creates a MDI child in new thread
2020 * FIXME: its in the same thread now
2022 * RETURNS
2023 * Success: Handle to created window
2024 * Failure: NULL
2026 HWND WINAPI CreateMDIWindowA(
2027 LPCSTR lpClassName, /* [in] Pointer to registered child class name */
2028 LPCSTR lpWindowName, /* [in] Pointer to window name */
2029 DWORD dwStyle, /* [in] Window style */
2030 INT X, /* [in] Horizontal position of window */
2031 INT Y, /* [in] Vertical position of window */
2032 INT nWidth, /* [in] Width of window */
2033 INT nHeight, /* [in] Height of window */
2034 HWND hWndParent, /* [in] Handle to parent window */
2035 HINSTANCE hInstance, /* [in] Handle to application instance */
2036 LPARAM lParam) /* [in] Application-defined value */
2038 WARN("is only single threaded!\n");
2039 return MDI_CreateMDIWindowA(lpClassName, lpWindowName, dwStyle, X, Y,
2040 nWidth, nHeight, hWndParent, hInstance, lParam);
2043 /**********************************************************************
2044 * MDI_CreateMDIWindowA
2045 * single threaded version of CreateMDIWindowA
2046 * called by CreateWindowExA
2048 HWND MDI_CreateMDIWindowA(
2049 LPCSTR lpClassName,
2050 LPCSTR lpWindowName,
2051 DWORD dwStyle,
2052 INT X,
2053 INT Y,
2054 INT nWidth,
2055 INT nHeight,
2056 HWND hWndParent,
2057 HINSTANCE hInstance,
2058 LPARAM lParam)
2060 MDICLIENTINFO* pCi;
2061 MDICREATESTRUCTA cs;
2062 WND *pWnd=WIN_FindWndPtr(hWndParent);
2063 HWND retvalue;
2065 TRACE("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
2066 debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
2067 nWidth,nHeight,hWndParent,hInstance,lParam);
2069 if(!pWnd){
2070 ERR(" bad hwnd for MDI-client: %d\n",hWndParent);
2071 return 0;
2073 cs.szClass=lpClassName;
2074 cs.szTitle=lpWindowName;
2075 cs.hOwner=hInstance;
2076 cs.x=X;
2077 cs.y=Y;
2078 cs.cx=nWidth;
2079 cs.cy=nHeight;
2080 cs.style=dwStyle;
2081 cs.lParam=lParam;
2083 pCi=(MDICLIENTINFO *)pWnd->wExtra;
2085 retvalue = MDICreateChild(pWnd,pCi,hWndParent,&cs);
2086 WIN_ReleaseWndPtr(pWnd);
2087 return retvalue;
2090 /***********************************************************************
2091 * CreateMDIWindowW (USER32.@) Creates a MDI child in new thread
2093 * RETURNS
2094 * Success: Handle to created window
2095 * Failure: NULL
2097 HWND WINAPI CreateMDIWindowW(
2098 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
2099 LPCWSTR lpWindowName, /* [in] Pointer to window name */
2100 DWORD dwStyle, /* [in] Window style */
2101 INT X, /* [in] Horizontal position of window */
2102 INT Y, /* [in] Vertical position of window */
2103 INT nWidth, /* [in] Width of window */
2104 INT nHeight, /* [in] Height of window */
2105 HWND hWndParent, /* [in] Handle to parent window */
2106 HINSTANCE hInstance, /* [in] Handle to application instance */
2107 LPARAM lParam) /* [in] Application-defined value */
2109 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
2110 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
2111 nWidth,nHeight,hWndParent,hInstance,lParam);
2112 return (HWND)NULL;
2116 /******************************************************************************
2117 * CreateMDIWindowW (USER32.80) Creates a MDI child window
2118 * single threaded version of CreateMDIWindow
2119 * called by CreateWindowExW().
2121 HWND MDI_CreateMDIWindowW(
2122 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
2123 LPCWSTR lpWindowName, /* [in] Pointer to window name */
2124 DWORD dwStyle, /* [in] Window style */
2125 INT X, /* [in] Horizontal position of window */
2126 INT Y, /* [in] Vertical position of window */
2127 INT nWidth, /* [in] Width of window */
2128 INT nHeight, /* [in] Height of window */
2129 HWND hWndParent, /* [in] Handle to parent window */
2130 HINSTANCE hInstance, /* [in] Handle to application instance */
2131 LPARAM lParam) /* [in] Application-defined value */
2133 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
2134 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
2135 nWidth,nHeight,hWndParent,hInstance,lParam);
2136 return (HWND)NULL;
2140 /**********************************************************************
2141 * TranslateMDISysAccel (USER32.@)
2143 BOOL WINAPI TranslateMDISysAccel( HWND hwndClient, LPMSG msg )
2145 MSG16 msg16;
2147 STRUCT32_MSG32to16(msg,&msg16);
2148 /* MDICLIENTINFO is still the same for win32 and win16 ... */
2149 return TranslateMDISysAccel16(hwndClient,&msg16);
2153 /**********************************************************************
2154 * TranslateMDISysAccel (USER.451)
2156 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
2159 if( IsWindow(hwndClient) && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
2161 MDICLIENTINFO *ci = NULL;
2162 HWND wnd;
2163 WND *clientWnd = WIN_FindWndPtr(hwndClient);
2165 ci = (MDICLIENTINFO*) clientWnd->wExtra;
2166 wnd = ci->hwndActiveChild;
2168 WIN_ReleaseWndPtr(clientWnd);
2170 if( IsWindow(wnd) && !(GetWindowLongA(wnd,GWL_STYLE) & WS_DISABLED) )
2172 WPARAM16 wParam = 0;
2174 /* translate if the Ctrl key is down and Alt not. */
2176 if( (GetKeyState(VK_CONTROL) & 0x8000) &&
2177 !(GetKeyState(VK_MENU) & 0x8000))
2179 switch( msg->wParam )
2181 case VK_F6:
2182 case VK_TAB:
2183 wParam = ( GetKeyState(VK_SHIFT) & 0x8000 )
2184 ? SC_NEXTWINDOW : SC_PREVWINDOW;
2185 break;
2186 case VK_F4:
2187 case VK_RBUTTON:
2188 wParam = SC_CLOSE;
2189 break;
2190 default:
2191 return 0;
2193 TRACE("wParam = %04x\n", wParam);
2194 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
2195 wParam, (LPARAM)msg->wParam);
2196 return 1;
2200 return 0; /* failure */
2204 /***********************************************************************
2205 * CalcChildScroll (USER.462)
2207 void WINAPI CalcChildScroll16( HWND16 hwnd, WORD scroll )
2209 SCROLLINFO info;
2210 RECT childRect, clientRect;
2211 INT vmin, vmax, hmin, hmax, vpos, hpos;
2212 WND *pWnd, *Wnd;
2214 if (!(pWnd = WIN_FindWndPtr( hwnd ))) return;
2215 Wnd = WIN_FindWndPtr(hwnd);
2216 GetClientRect( hwnd, &clientRect );
2217 SetRectEmpty( &childRect );
2219 for ( WIN_UpdateWndPtr(&pWnd,pWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2221 if( pWnd->dwStyle & WS_MAXIMIZE )
2223 ShowScrollBar(hwnd, SB_BOTH, FALSE);
2224 WIN_ReleaseWndPtr(pWnd);
2225 WIN_ReleaseWndPtr(Wnd);
2226 return;
2228 UnionRect( &childRect, &pWnd->rectWindow, &childRect );
2230 WIN_ReleaseWndPtr(pWnd);
2231 UnionRect( &childRect, &clientRect, &childRect );
2233 hmin = childRect.left; hmax = childRect.right - clientRect.right;
2234 hpos = clientRect.left - childRect.left;
2235 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
2236 vpos = clientRect.top - childRect.top;
2238 switch( scroll )
2240 case SB_HORZ:
2241 vpos = hpos; vmin = hmin; vmax = hmax;
2242 case SB_VERT:
2243 info.cbSize = sizeof(info);
2244 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
2245 info.fMask = SIF_POS | SIF_RANGE;
2246 SetScrollInfo(hwnd, scroll, &info, TRUE);
2247 break;
2248 case SB_BOTH:
2249 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
2250 hmin, hmax, hpos);
2252 WIN_ReleaseWndPtr(Wnd);
2256 /***********************************************************************
2257 * ScrollChildren (USER.463)
2259 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
2261 ScrollChildren( hWnd, uMsg, wParam, lParam );
2265 /***********************************************************************
2266 * ScrollChildren (USER32.@)
2268 void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
2269 LPARAM lParam)
2271 WND *wndPtr = WIN_FindWndPtr(hWnd);
2272 INT newPos = -1;
2273 INT curPos, length, minPos, maxPos, shift;
2275 if( !wndPtr ) return;
2277 if( uMsg == WM_HSCROLL )
2279 GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
2280 curPos = GetScrollPos(hWnd,SB_HORZ);
2281 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
2282 shift = GetSystemMetrics(SM_CYHSCROLL);
2284 else if( uMsg == WM_VSCROLL )
2286 GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
2287 curPos = GetScrollPos(hWnd,SB_VERT);
2288 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
2289 shift = GetSystemMetrics(SM_CXVSCROLL);
2291 else
2293 WIN_ReleaseWndPtr(wndPtr);
2294 return;
2297 WIN_ReleaseWndPtr(wndPtr);
2298 switch( wParam )
2300 case SB_LINEUP:
2301 newPos = curPos - shift;
2302 break;
2303 case SB_LINEDOWN:
2304 newPos = curPos + shift;
2305 break;
2306 case SB_PAGEUP:
2307 newPos = curPos - length;
2308 break;
2309 case SB_PAGEDOWN:
2310 newPos = curPos + length;
2311 break;
2313 case SB_THUMBPOSITION:
2314 newPos = LOWORD(lParam);
2315 break;
2317 case SB_THUMBTRACK:
2318 return;
2320 case SB_TOP:
2321 newPos = minPos;
2322 break;
2323 case SB_BOTTOM:
2324 newPos = maxPos;
2325 break;
2326 case SB_ENDSCROLL:
2327 CalcChildScroll16(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
2328 return;
2331 if( newPos > maxPos )
2332 newPos = maxPos;
2333 else
2334 if( newPos < minPos )
2335 newPos = minPos;
2337 SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
2339 if( uMsg == WM_VSCROLL )
2340 ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
2341 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2342 else
2343 ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
2344 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2348 /******************************************************************************
2349 * CascadeWindows (USER32.@) Cascades MDI child windows
2351 * RETURNS
2352 * Success: Number of cascaded windows.
2353 * Failure: 0
2355 WORD WINAPI
2356 CascadeWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2357 UINT cKids, const HWND *lpKids)
2359 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2360 hwndParent, wFlags, cKids);
2362 return 0;
2366 /******************************************************************************
2367 * TileWindows (USER32.@) Tiles MDI child windows
2369 * RETURNS
2370 * Success: Number of tiled windows.
2371 * Failure: 0
2373 WORD WINAPI
2374 TileWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2375 UINT cKids, const HWND *lpKids)
2377 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2378 hwndParent, wFlags, cKids);
2380 return 0;
2383 /************************************************************************
2384 * "More Windows..." functionality
2387 /* MDI_MoreWindowsDlgProc
2389 * This function will process the messages sent to the "More Windows..."
2390 * dialog.
2391 * Return values: 0 = cancel pressed
2392 * HWND = ok pressed or double-click in the list...
2396 static BOOL WINAPI MDI_MoreWindowsDlgProc (HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
2398 switch (iMsg)
2400 case WM_INITDIALOG:
2402 WND *pWnd;
2403 UINT widest = 0;
2404 UINT length;
2405 UINT i;
2406 WND *pParentWnd = (WND *)lParam;
2407 MDICLIENTINFO *ci = (MDICLIENTINFO*)pParentWnd->wExtra;
2408 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2410 /* Fill the list, sorted by id... */
2411 for (i = 0; i < ci->nActiveChildren; i++)
2414 /* Find the window with the current ID */
2415 for (pWnd = WIN_LockWndPtr(pParentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd, pWnd->next))
2416 if (pWnd->wIDmenu == ci->idFirstChild + i)
2417 break;
2419 SendMessageW(hListBox, LB_ADDSTRING, 0, (LPARAM) pWnd->text);
2420 SendMessageA(hListBox, LB_SETITEMDATA, i, (LPARAM) pWnd);
2421 length = strlenW(pWnd->text);
2422 WIN_ReleaseWndPtr(pWnd);
2424 if (length > widest)
2425 widest = length;
2427 /* Make sure the horizontal scrollbar scrolls ok */
2428 SendMessageA(hListBox, LB_SETHORIZONTALEXTENT, widest * 6, 0);
2430 /* Set the current selection */
2431 SendMessageA(hListBox, LB_SETCURSEL, MDI_MOREWINDOWSLIMIT, 0);
2432 return TRUE;
2435 case WM_COMMAND:
2436 switch (LOWORD(wParam))
2438 case IDOK:
2440 /* windows are sorted by menu ID, so we must return the
2441 * window associated to the given id
2443 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2444 UINT index = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
2445 WND* pWnd = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
2447 EndDialog(hDlg, pWnd->hwndSelf);
2448 return TRUE;
2450 case IDCANCEL:
2451 EndDialog(hDlg, 0);
2452 return TRUE;
2454 default:
2455 switch (HIWORD(wParam))
2457 case LBN_DBLCLK:
2459 /* windows are sorted by menu ID, so we must return the
2460 * window associated to the given id
2462 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2463 UINT index = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
2464 WND* pWnd = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
2466 EndDialog(hDlg, pWnd->hwndSelf);
2467 return TRUE;
2470 break;
2472 break;
2474 return FALSE;
2479 * MDI_MoreWindowsDialog
2481 * Prompts the user with a listbox containing the opened
2482 * documents. The user can then choose a windows and click
2483 * on OK to set the current window to the one selected, or
2484 * CANCEL to cancel. The function returns a handle to the
2485 * selected window.
2488 static HWND MDI_MoreWindowsDialog(WND* wndPtr)
2490 LPCVOID template;
2491 HRSRC hRes;
2492 HANDLE hDlgTmpl;
2494 hRes = FindResourceA(GetModuleHandleA("USER32"), "MDI_MOREWINDOWS", RT_DIALOGA);
2496 if (hRes == 0)
2497 return 0;
2499 hDlgTmpl = LoadResource(GetModuleHandleA("USER32"), hRes );
2501 if (hDlgTmpl == 0)
2502 return 0;
2504 template = LockResource( hDlgTmpl );
2506 if (template == 0)
2507 return 0;
2509 return (HWND) DialogBoxIndirectParamA(GetModuleHandleA("USER32"),
2510 (LPDLGTEMPLATEA) template,
2511 wndPtr->hwndSelf,
2512 (DLGPROC) MDI_MoreWindowsDlgProc,
2513 (LPARAM) wndPtr);
2518 * MDI_SwapMenuItems
2520 * Will swap the menu IDs for the given 2 positions.
2521 * pos1 and pos2 are menu IDs
2526 static void MDI_SwapMenuItems(WND *parentWnd, UINT pos1, UINT pos2)
2528 WND *pWnd;
2530 for (pWnd = WIN_LockWndPtr(parentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2532 if (pWnd->wIDmenu == pos1)
2533 pWnd->wIDmenu = pos2;
2534 else
2535 if (pWnd->wIDmenu == pos2)
2536 pWnd->wIDmenu = pos1;
2539 WIN_ReleaseWndPtr(pWnd);