Made exception_event_request non-blocking, and added
[wine.git] / windows / mdi.c
blob13a43dcbb6c816d8b20d6e6815a4b5dc7657e0d0
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 "debugtools.h"
86 #include "dlgs.h"
88 DEFAULT_DEBUG_CHANNEL(mdi);
90 #define MDI_MAXLISTLENGTH 0x40
91 #define MDI_MAXTITLELENGTH 0xa1
93 #define MDI_NOFRAMEREPAINT 0
94 #define MDI_REPAINTFRAMENOW 1
95 #define MDI_REPAINTFRAME 2
97 #define WM_MDICALCCHILDSCROLL 0x10ac /* this is exactly what Windows uses */
99 /* "More Windows..." definitions */
100 #define MDI_MOREWINDOWSLIMIT 9 /* after this number of windows, a "More Windows..."
101 option will appear under the Windows menu */
102 #define MDI_IDC_LISTBOX 100
103 #define MDI_IDS_MOREWINDOWS 13
105 #define MDIF_NEEDUPDATE 0x0001
107 typedef struct
109 UINT nActiveChildren;
110 HWND hwndChildMaximized;
111 HWND hwndActiveChild;
112 HMENU hWindowMenu;
113 UINT idFirstChild;
114 LPWSTR frameTitle;
115 UINT nTotalCreated;
116 UINT mdiFlags;
117 UINT sbRecalc; /* SB_xxx flags for scrollbar fixup */
118 HWND self;
119 } MDICLIENTINFO;
121 static HBITMAP16 hBmpClose = 0;
122 static HBITMAP16 hBmpRestore = 0;
124 /* ----------------- declarations ----------------- */
125 static void MDI_UpdateFrameText(WND *, HWND, BOOL, LPCWSTR);
126 static BOOL MDI_AugmentFrameMenu(MDICLIENTINFO*, WND *, HWND);
127 static BOOL MDI_RestoreFrameMenu(WND *, HWND);
129 static LONG MDI_ChildActivate( WND*, HWND );
131 static HWND MDI_MoreWindowsDialog(WND*);
132 static void MDI_SwapMenuItems(WND *, UINT, UINT);
133 static LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
134 /* -------- Miscellaneous service functions ----------
136 * MDI_GetChildByID
139 static HWND MDI_GetChildByID(WND* wndPtr, INT id)
141 for (wndPtr = wndPtr->child; wndPtr; wndPtr = wndPtr->next)
142 if (wndPtr->wIDmenu == id) return wndPtr->hwndSelf;
143 return 0;
146 static void MDI_PostUpdate(HWND hwnd, MDICLIENTINFO* ci, WORD recalc)
148 if( !(ci->mdiFlags & MDIF_NEEDUPDATE) )
150 ci->mdiFlags |= MDIF_NEEDUPDATE;
151 PostMessageA( hwnd, WM_MDICALCCHILDSCROLL, 0, 0);
153 ci->sbRecalc = recalc;
157 /*********************************************************************
158 * MDIClient class descriptor
160 const struct builtin_class_descr MDICLIENT_builtin_class =
162 "MDIClient", /* name */
163 CS_GLOBALCLASS, /* style */
164 MDIClientWndProcA, /* procA */
165 NULL, /* procW (FIXME) */
166 sizeof(MDICLIENTINFO), /* extra */
167 IDC_ARROWA, /* cursor */
168 COLOR_APPWORKSPACE+1 /* brush */
172 /**********************************************************************
173 * MDI_MenuModifyItem
175 static BOOL MDI_MenuModifyItem(WND* clientWnd, HWND hWndChild )
177 WCHAR buffer[128];
178 static const WCHAR format[] = {'%','d',' ',0};
179 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
180 WND *wndPtr = WIN_FindWndPtr(hWndChild);
181 UINT n = wsprintfW(buffer, format,
182 wndPtr->wIDmenu - clientInfo->idFirstChild + 1);
183 BOOL bRet = 0;
185 if( !clientInfo->hWindowMenu )
187 bRet = FALSE;
188 goto END;
191 if (wndPtr->text) lstrcpynW(buffer + n, wndPtr->text, sizeof(buffer)/sizeof(WCHAR) - n );
193 n = GetMenuState(clientInfo->hWindowMenu,wndPtr->wIDmenu ,MF_BYCOMMAND);
194 bRet = ModifyMenuW(clientInfo->hWindowMenu , wndPtr->wIDmenu,
195 MF_BYCOMMAND | MF_STRING, wndPtr->wIDmenu, buffer );
196 CheckMenuItem(clientInfo->hWindowMenu ,wndPtr->wIDmenu , n & MF_CHECKED);
197 END:
198 WIN_ReleaseWndPtr(wndPtr);
199 return bRet;
202 /**********************************************************************
203 * MDI_MenuDeleteItem
205 static BOOL MDI_MenuDeleteItem(WND* clientWnd, HWND hWndChild )
207 WCHAR buffer[128];
208 static const WCHAR format[] = {'&','%','d',' ',0};
209 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
210 WND *wndPtr = WIN_FindWndPtr(hWndChild);
211 UINT index = 0,id,n;
212 BOOL retvalue;
214 if( !clientInfo->nActiveChildren ||
215 !clientInfo->hWindowMenu )
217 retvalue = FALSE;
218 goto END;
221 id = wndPtr->wIDmenu;
222 DeleteMenu(clientInfo->hWindowMenu,id,MF_BYCOMMAND);
224 /* walk the rest of MDI children to prevent gaps in the id
225 * sequence and in the menu child list */
227 for( index = id+1; index <= clientInfo->nActiveChildren +
228 clientInfo->idFirstChild; index++ )
230 WND *tmpWnd = WIN_FindWndPtr(MDI_GetChildByID(clientWnd,index));
231 if( !tmpWnd )
233 TRACE("no window for id=%i\n",index);
234 WIN_ReleaseWndPtr(tmpWnd);
235 continue;
238 /* set correct id */
239 tmpWnd->wIDmenu--;
241 n = wsprintfW(buffer, format ,index - clientInfo->idFirstChild);
242 if (tmpWnd->text)
243 lstrcpynW(buffer + n, tmpWnd->text, sizeof(buffer)/sizeof(WCHAR) - n );
245 /* change menu if the current child is to be shown in the
246 * "Windows" menu
248 if (index <= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
249 ModifyMenuW(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING,
250 index - 1 , buffer );
251 WIN_ReleaseWndPtr(tmpWnd);
254 /* We must restore the "More Windows..." option if there is enough child
256 if (clientInfo->nActiveChildren - 1 > MDI_MOREWINDOWSLIMIT)
258 char szTmp[50];
259 LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
261 AppendMenuA(clientInfo->hWindowMenu ,MF_STRING ,clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT, szTmp );
263 retvalue = TRUE;
264 END:
265 WIN_ReleaseWndPtr(wndPtr);
266 return retvalue;
269 /**********************************************************************
270 * MDI_GetWindow
272 * returns "activateable" child different from the current or zero
274 static HWND MDI_GetWindow(WND *clientWnd, HWND hWnd, BOOL bNext,
275 DWORD dwStyleMask )
277 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
278 WND *wndPtr, *pWnd, *pWndLast = NULL;
280 dwStyleMask |= WS_DISABLED | WS_VISIBLE;
281 if( !hWnd ) hWnd = clientInfo->hwndActiveChild;
283 if( !(wndPtr = WIN_FindWndPtr(hWnd)) ) return 0;
285 for ( pWnd = WIN_LockWndPtr(wndPtr->next); ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
287 if (!pWnd ) WIN_UpdateWndPtr(&pWnd,wndPtr->parent->child);
289 if ( pWnd == wndPtr ) break; /* went full circle */
291 if (!pWnd->owner && (pWnd->dwStyle & dwStyleMask) == WS_VISIBLE )
293 pWndLast = pWnd;
294 if ( bNext ) break;
297 WIN_ReleaseWndPtr(wndPtr);
298 WIN_ReleaseWndPtr(pWnd);
299 return pWndLast ? pWndLast->hwndSelf : 0;
302 /**********************************************************************
303 * MDI_CalcDefaultChildPos
305 * It seems that the default height is about 2/3 of the client rect
307 static void MDI_CalcDefaultChildPos( WND* w, WORD n, LPPOINT lpPos,
308 INT delta)
310 INT nstagger;
311 RECT rect = w->rectClient;
312 INT spacing = GetSystemMetrics(SM_CYCAPTION) +
313 GetSystemMetrics(SM_CYFRAME) - 1;
315 if( rect.bottom - rect.top - delta >= spacing )
316 rect.bottom -= delta;
318 nstagger = (rect.bottom - rect.top)/(3 * spacing);
319 lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
320 lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
321 lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
324 /**********************************************************************
325 * MDISetMenu
327 static LRESULT MDISetMenu( HWND hwnd, HMENU hmenuFrame,
328 HMENU hmenuWindow)
330 WND *w;
331 MDICLIENTINFO *ci;
332 HWND hwndFrame = GetParent(hwnd);
333 HMENU oldFrameMenu = GetMenu(hwndFrame);
335 TRACE("%04x %04x %04x\n",
336 hwnd, hmenuFrame, hmenuWindow);
338 if (hmenuFrame && !IsMenu(hmenuFrame))
340 WARN("hmenuFrame is not a menu handle\n");
341 return 0L;
344 if (hmenuWindow && !IsMenu(hmenuWindow))
346 WARN("hmenuWindow is not a menu handle\n");
347 return 0L;
350 w = WIN_FindWndPtr(hwnd);
351 ci = (MDICLIENTINFO *) w->wExtra;
353 if( ci->hwndChildMaximized && hmenuFrame && hmenuFrame!=oldFrameMenu )
354 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized );
356 if( hmenuWindow && ci->hWindowMenu && hmenuWindow!=ci->hWindowMenu )
358 /* delete menu items from ci->hWindowMenu
359 * and add them to hmenuWindow */
361 INT i = GetMenuItemCount(ci->hWindowMenu) - 1;
362 INT pos = GetMenuItemCount(hmenuWindow) + 1;
364 AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL);
366 if( ci->nActiveChildren )
368 INT j;
369 LPWSTR buffer = NULL;
370 MENUITEMINFOW mii;
371 INT nbWindowsMenuItems; /* num of documents shown + "More Windows..." if present */
373 if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
374 nbWindowsMenuItems = ci->nActiveChildren;
375 else
376 nbWindowsMenuItems = MDI_MOREWINDOWSLIMIT + 1;
378 j = i - nbWindowsMenuItems + 1;
380 for( ; i >= j ; i-- )
382 memset(&mii, 0, sizeof(mii));
383 mii.cbSize = sizeof(mii);
384 mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE
385 | MIIM_SUBMENU | MIIM_TYPE | MIIM_BITMAP;
387 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
388 if(mii.cch) { /* Menu is MFT_STRING */
389 mii.cch++; /* add room for '\0' */
390 buffer = HeapAlloc(GetProcessHeap(), 0,
391 mii.cch * sizeof(WCHAR));
392 mii.dwTypeData = buffer;
393 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
395 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
396 InsertMenuItemW(hmenuWindow, pos, TRUE, &mii);
397 if(buffer) {
398 HeapFree(GetProcessHeap(), 0, buffer);
399 buffer = NULL;
404 /* remove separator */
405 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
407 ci->hWindowMenu = hmenuWindow;
410 if (hmenuFrame)
412 SetMenu(hwndFrame, hmenuFrame);
413 if( hmenuFrame!=oldFrameMenu )
415 if( ci->hwndChildMaximized )
416 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
417 WIN_ReleaseWndPtr(w);
418 return oldFrameMenu;
421 else
423 INT nItems = GetMenuItemCount(w->parent->wIDmenu) - 1;
424 UINT iId = GetMenuItemID(w->parent->wIDmenu,nItems) ;
426 if( !(iId == SC_RESTORE || iId == SC_CLOSE) )
428 /* SetMenu() may already have been called, meaning that this window
429 * already has its menu. But they may have done a SetMenu() on
430 * an MDI window, and called MDISetMenu() after the fact, meaning
431 * that the "if" to this "else" wouldn't catch the need to
432 * augment the frame menu.
434 if( ci->hwndChildMaximized )
435 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
438 WIN_ReleaseWndPtr(w);
439 return 0;
442 /**********************************************************************
443 * MDIRefreshMenu
445 static LRESULT MDIRefreshMenu( HWND hwnd, HMENU hmenuFrame,
446 HMENU hmenuWindow)
448 HWND hwndFrame = GetParent(hwnd);
449 HMENU oldFrameMenu = GetMenu(hwndFrame);
451 TRACE("%04x %04x %04x\n",
452 hwnd, hmenuFrame, hmenuWindow);
454 FIXME("partially function stub\n");
456 return oldFrameMenu;
460 /* ------------------ MDI child window functions ---------------------- */
463 /**********************************************************************
464 * MDICreateChild
466 static HWND MDICreateChild( WND *w, MDICLIENTINFO *ci, HWND parent,
467 LPMDICREATESTRUCTA cs )
469 POINT pos[2];
470 DWORD style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
471 HWND hwnd, hwndMax = 0;
472 WORD wIDmenu = ci->idFirstChild + ci->nActiveChildren;
473 char lpstrDef[]="junk!";
475 TRACE("origin %i,%i - dim %i,%i, style %08lx\n",
476 cs->x, cs->y, cs->cx, cs->cy, cs->style);
477 /* calculate placement */
478 MDI_CalcDefaultChildPos(w, ci->nTotalCreated++, pos, 0);
480 if (cs->cx == CW_USEDEFAULT || !cs->cx) cs->cx = pos[1].x;
481 if (cs->cy == CW_USEDEFAULT || !cs->cy) cs->cy = pos[1].y;
483 if( cs->x == CW_USEDEFAULT )
485 cs->x = pos[0].x;
486 cs->y = pos[0].y;
489 /* restore current maximized child */
490 if( (style & WS_VISIBLE) && ci->hwndChildMaximized )
492 TRACE("Restoring current maximized child %04x\n", ci->hwndChildMaximized);
493 if( style & WS_MAXIMIZE )
494 SendMessageA(w->hwndSelf, WM_SETREDRAW, FALSE, 0L );
495 hwndMax = ci->hwndChildMaximized;
496 ShowWindow( hwndMax, SW_SHOWNOACTIVATE );
497 if( style & WS_MAXIMIZE )
498 SendMessageA(w->hwndSelf, WM_SETREDRAW, TRUE, 0L );
501 if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
502 /* this menu is needed to set a check mark in MDI_ChildActivate */
503 if (ci->hWindowMenu != 0)
504 AppendMenuA(ci->hWindowMenu ,MF_STRING ,wIDmenu, lpstrDef );
506 ci->nActiveChildren++;
508 /* fix window style */
509 if( !(w->dwStyle & MDIS_ALLCHILDSTYLES) )
511 TRACE("MDIS_ALLCHILDSTYLES is missing, fixing window style\n");
512 style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE |
513 WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL );
514 style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW);
517 if( w->flags & WIN_ISWIN32 )
519 hwnd = CreateWindowA( cs->szClass, cs->szTitle, style,
520 cs->x, cs->y, cs->cx, cs->cy, parent,
521 (HMENU)wIDmenu, cs->hOwner, cs );
523 else
525 MDICREATESTRUCT16 *cs16;
526 LPSTR title, cls;
528 cs16 = SEGPTR_NEW(MDICREATESTRUCT16);
529 STRUCT32_MDICREATESTRUCT32Ato16( cs, cs16 );
530 title = SEGPTR_STRDUP( cs->szTitle );
531 cls = SEGPTR_STRDUP( cs->szClass );
532 cs16->szTitle = SEGPTR_GET(title);
533 cs16->szClass = SEGPTR_GET(cls);
535 hwnd = CreateWindow16( cs->szClass, cs->szTitle, style,
536 cs16->x, cs16->y, cs16->cx, cs16->cy, parent,
537 (HMENU)wIDmenu, cs16->hOwner,
538 (LPVOID)SEGPTR_GET(cs16) );
539 SEGPTR_FREE( title );
540 SEGPTR_FREE( cls );
541 SEGPTR_FREE( cs16 );
544 /* MDI windows are WS_CHILD so they won't be activated by CreateWindow */
546 if (hwnd)
548 WND* wnd = WIN_FindWndPtr( hwnd );
550 /* All MDI child windows have the WS_EX_MDICHILD style */
551 wnd->dwExStyle |= WS_EX_MDICHILD;
553 /* If we have more than 9 windows, we must insert the new one at the
554 * 9th position in order to see it in the "Windows" menu
556 if (ci->nActiveChildren > MDI_MOREWINDOWSLIMIT)
557 MDI_SwapMenuItems(wnd->parent, wnd->wIDmenu, ci->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
559 MDI_MenuModifyItem(w ,hwnd);
561 /* Have we hit the "More Windows..." limit? If so, we must
562 * add a "More Windows..." option
564 if (ci->nActiveChildren == MDI_MOREWINDOWSLIMIT + 1)
566 char szTmp[50];
567 LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
569 ModifyMenuA(ci->hWindowMenu,
570 ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
571 MF_BYCOMMAND | MF_STRING,
572 ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
573 szTmp);
576 if( (wnd->dwStyle & WS_MINIMIZE) && ci->hwndActiveChild )
578 TRACE("Minimizing created MDI child %04x\n", hwnd);
579 ShowWindow( hwnd, SW_SHOWMINNOACTIVE );
581 else
583 /* WS_VISIBLE is clear if a) the MDI client has
584 * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the
585 * MDICreateStruct. If so the created window is not shown nor
586 * activated.
588 if(wnd->dwStyle & WS_VISIBLE)
589 ShowWindow(hwnd, SW_SHOW);
591 WIN_ReleaseWndPtr(wnd);
592 TRACE("created child - %04x\n",hwnd);
594 else
596 ci->nActiveChildren--;
597 DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
598 if( IsWindow(hwndMax) )
599 ShowWindow(hwndMax, SW_SHOWMAXIMIZED);
602 return hwnd;
605 /**********************************************************************
606 * MDI_ChildGetMinMaxInfo
608 * Note: The rule here is that client rect of the maximized MDI child
609 * is equal to the client rect of the MDI client window.
611 static void MDI_ChildGetMinMaxInfo( WND* clientWnd, HWND hwnd,
612 MINMAXINFO16* lpMinMax )
614 WND* childWnd = WIN_FindWndPtr(hwnd);
615 RECT rect = clientWnd->rectClient;
617 MapWindowPoints( clientWnd->parent->hwndSelf,
618 ((MDICLIENTINFO*)clientWnd->wExtra)->self, (LPPOINT)&rect, 2);
619 AdjustWindowRectEx( &rect, childWnd->dwStyle, 0, childWnd->dwExStyle );
621 lpMinMax->ptMaxSize.x = rect.right -= rect.left;
622 lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
624 lpMinMax->ptMaxPosition.x = rect.left;
625 lpMinMax->ptMaxPosition.y = rect.top;
627 WIN_ReleaseWndPtr(childWnd);
629 TRACE("max rect (%i,%i - %i, %i)\n",
630 rect.left,rect.top,rect.right,rect.bottom);
634 /**********************************************************************
635 * MDI_SwitchActiveChild
637 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
638 * being activated
640 static void MDI_SwitchActiveChild( HWND clientHwnd, HWND childHwnd,
641 BOOL bNextWindow )
643 WND *w = WIN_FindWndPtr(clientHwnd);
644 HWND hwndTo = 0;
645 HWND hwndPrev = 0;
646 MDICLIENTINFO *ci;
648 hwndTo = MDI_GetWindow(w, childHwnd, bNextWindow, 0);
650 ci = (MDICLIENTINFO *) w->wExtra;
652 TRACE("from %04x, to %04x\n",childHwnd,hwndTo);
654 if ( !hwndTo ) goto END; /* no window to switch to */
656 hwndPrev = ci->hwndActiveChild;
658 if ( hwndTo != hwndPrev )
660 BOOL bOptimize = 0;
662 if( ci->hwndChildMaximized )
664 bOptimize = 1;
665 w->dwStyle &= ~WS_VISIBLE;
668 SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0,
669 SWP_NOMOVE | SWP_NOSIZE );
671 if( bNextWindow && hwndPrev )
672 SetWindowPos( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0,
673 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
674 if( bOptimize )
675 ShowWindow( clientHwnd, SW_SHOW );
677 END:
678 WIN_ReleaseWndPtr(w);
682 /**********************************************************************
683 * MDIDestroyChild
685 static LRESULT MDIDestroyChild( WND *w_parent, MDICLIENTINFO *ci,
686 HWND parent, HWND child,
687 BOOL flagDestroy )
689 WND *childPtr = WIN_FindWndPtr(child);
691 if( childPtr )
693 if( child == ci->hwndActiveChild )
695 MDI_SwitchActiveChild(parent, child, TRUE);
697 if( child == ci->hwndActiveChild )
699 ShowWindow( child, SW_HIDE);
700 if( child == ci->hwndChildMaximized )
702 MDI_RestoreFrameMenu(w_parent->parent, child);
703 ci->hwndChildMaximized = 0;
704 MDI_UpdateFrameText(w_parent->parent,parent,TRUE,NULL);
707 MDI_ChildActivate(w_parent, 0);
711 MDI_MenuDeleteItem(w_parent, child);
713 WIN_ReleaseWndPtr(childPtr);
715 ci->nActiveChildren--;
717 TRACE("child destroyed - %04x\n",child);
719 if (flagDestroy)
721 MDI_PostUpdate(GetParent(child), ci, SB_BOTH+1);
722 DestroyWindow(child);
726 return 0;
730 /**********************************************************************
731 * MDI_ChildActivate
733 * Note: hWndChild is NULL when last child is being destroyed
735 static LONG MDI_ChildActivate( WND *clientPtr, HWND hWndChild )
737 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientPtr->wExtra;
738 HWND prevActiveWnd = clientInfo->hwndActiveChild;
739 WND *wndPtr = WIN_FindWndPtr( hWndChild );
740 WND *wndPrev = WIN_FindWndPtr( prevActiveWnd );
741 BOOL isActiveFrameWnd = 0;
742 LONG retvalue;
744 if( wndPtr )
746 if( wndPtr->dwStyle & WS_DISABLED )
748 retvalue = 0L;
749 goto END;
753 /* Don't activate if it is already active. Might happen
754 since ShowWindow DOES activate MDI children */
755 if (clientInfo->hwndActiveChild == hWndChild)
757 retvalue = 0L;
758 goto END;
761 TRACE("%04x\n", hWndChild);
763 if( GetActiveWindow() == clientPtr->parent->hwndSelf )
764 isActiveFrameWnd = TRUE;
766 /* deactivate prev. active child */
767 if( wndPrev )
769 wndPrev->dwStyle |= WS_SYSMENU;
770 SendMessageA( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
771 SendMessageA( prevActiveWnd, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
772 (LPARAM)hWndChild);
773 /* uncheck menu item */
774 if( clientInfo->hWindowMenu )
776 WORD wPrevID = wndPrev->wIDmenu - clientInfo->idFirstChild;
778 if (wPrevID < MDI_MOREWINDOWSLIMIT)
779 CheckMenuItem( clientInfo->hWindowMenu,
780 wndPrev->wIDmenu, 0);
781 else
782 CheckMenuItem( clientInfo->hWindowMenu,
783 clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1, 0);
787 /* set appearance */
788 if( clientInfo->hwndChildMaximized )
790 if( clientInfo->hwndChildMaximized != hWndChild ) {
791 if( hWndChild ) {
792 clientInfo->hwndActiveChild = hWndChild;
793 ShowWindow( hWndChild, SW_SHOWMAXIMIZED);
794 } else
795 ShowWindow( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
799 clientInfo->hwndActiveChild = hWndChild;
801 /* check if we have any children left */
802 if( !hWndChild )
804 if( isActiveFrameWnd )
805 SetFocus( clientInfo->self );
806 retvalue = 0;
807 goto END;
810 /* check menu item */
811 if( clientInfo->hWindowMenu )
813 /* The window to be activated must be displayed in the "Windows" menu */
814 if (wndPtr->wIDmenu >= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
816 MDI_SwapMenuItems(wndPtr->parent, wndPtr->wIDmenu, clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
817 MDI_MenuModifyItem(wndPtr->parent ,wndPtr->hwndSelf);
820 CheckMenuItem(clientInfo->hWindowMenu, wndPtr->wIDmenu, MF_CHECKED);
822 /* bring active child to the top */
823 SetWindowPos( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
825 if( isActiveFrameWnd )
827 SendMessageA( hWndChild, WM_NCACTIVATE, TRUE, 0L);
828 if( GetFocus() == clientInfo->self )
829 SendMessageA( clientInfo->self, WM_SETFOCUS,
830 (WPARAM)clientInfo->self, 0L );
831 else
832 SetFocus( clientInfo->self );
834 SendMessageA( hWndChild, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
835 (LPARAM)hWndChild );
836 retvalue = 1;
837 END:
838 WIN_ReleaseWndPtr(wndPtr);
839 WIN_ReleaseWndPtr(wndPrev);
840 return retvalue;
843 /* -------------------- MDI client window functions ------------------- */
845 /**********************************************************************
846 * CreateMDIMenuBitmap
848 static HBITMAP16 CreateMDIMenuBitmap(void)
850 HDC hDCSrc = CreateCompatibleDC(0);
851 HDC hDCDest = CreateCompatibleDC(hDCSrc);
852 HBITMAP16 hbClose = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CLOSE) );
853 HBITMAP16 hbCopy;
854 HANDLE16 hobjSrc, hobjDest;
856 hobjSrc = SelectObject(hDCSrc, hbClose);
857 hbCopy = CreateCompatibleBitmap(hDCSrc,GetSystemMetrics(SM_CXSIZE),GetSystemMetrics(SM_CYSIZE));
858 hobjDest = SelectObject(hDCDest, hbCopy);
860 BitBlt(hDCDest, 0, 0, GetSystemMetrics(SM_CXSIZE), GetSystemMetrics(SM_CYSIZE),
861 hDCSrc, GetSystemMetrics(SM_CXSIZE), 0, SRCCOPY);
863 SelectObject(hDCSrc, hobjSrc);
864 DeleteObject(hbClose);
865 DeleteDC(hDCSrc);
867 hobjSrc = SelectObject( hDCDest, GetStockObject(BLACK_PEN) );
869 MoveToEx( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, 0, NULL );
870 LineTo( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, GetSystemMetrics(SM_CYSIZE) - 1);
872 SelectObject(hDCDest, hobjSrc );
873 SelectObject(hDCDest, hobjDest);
874 DeleteDC(hDCDest);
876 return hbCopy;
879 /**********************************************************************
880 * MDICascade
882 static LONG MDICascade(WND* clientWnd, MDICLIENTINFO *ci)
884 WND** ppWnd;
885 UINT total;
887 if (ci->hwndChildMaximized)
888 SendMessageA( clientWnd->hwndSelf, WM_MDIRESTORE,
889 (WPARAM)ci->hwndChildMaximized, 0);
891 if (ci->nActiveChildren == 0) return 0;
893 if ((ppWnd = WIN_BuildWinArray(clientWnd, BWA_SKIPHIDDEN | BWA_SKIPOWNED |
894 BWA_SKIPICONIC, &total)))
896 WND** heapPtr = ppWnd;
897 if( total )
899 INT delta = 0, n = 0;
900 POINT pos[2];
901 if( total < ci->nActiveChildren )
902 delta = GetSystemMetrics(SM_CYICONSPACING) +
903 GetSystemMetrics(SM_CYICON);
905 /* walk the list (backwards) and move windows */
906 while (*ppWnd) ppWnd++;
907 while (ppWnd != heapPtr)
909 ppWnd--;
910 TRACE("move %04x to (%ld,%ld) size [%ld,%ld]\n",
911 (*ppWnd)->hwndSelf, pos[0].x, pos[0].y, pos[1].x, pos[1].y);
913 MDI_CalcDefaultChildPos(clientWnd, n++, pos, delta);
914 SetWindowPos( (*ppWnd)->hwndSelf, 0, pos[0].x, pos[0].y,
915 pos[1].x, pos[1].y,
916 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
919 WIN_ReleaseWinArray(heapPtr);
922 if( total < ci->nActiveChildren )
923 ArrangeIconicWindows( clientWnd->hwndSelf );
924 return 0;
927 /**********************************************************************
928 * MDITile
930 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM wParam )
932 WND** ppWnd;
933 UINT total = 0;
935 if (ci->hwndChildMaximized)
936 SendMessageA( wndClient->hwndSelf, WM_MDIRESTORE,
937 (WPARAM)ci->hwndChildMaximized, 0);
939 if (ci->nActiveChildren == 0) return;
941 ppWnd = WIN_BuildWinArray(wndClient, BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
942 ((wParam & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
944 TRACE("%u windows to tile\n", total);
946 if( ppWnd )
948 WND** heapPtr = ppWnd;
950 if( total )
952 RECT rect;
953 int x, y, xsize, ysize;
954 int rows, columns, r, c, i;
956 GetClientRect(wndClient->hwndSelf,&rect);
957 rows = (int) sqrt((double)total);
958 columns = total / rows;
960 if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */
962 i = rows;
963 rows = columns; /* exchange r and c */
964 columns = i;
967 if( total != ci->nActiveChildren)
969 y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
970 rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
973 ysize = rect.bottom / rows;
974 xsize = rect.right / columns;
976 for (x = i = 0, c = 1; c <= columns && *ppWnd; c++)
978 if (c == columns)
980 rows = total - i;
981 ysize = rect.bottom / rows;
984 y = 0;
985 for (r = 1; r <= rows && *ppWnd; r++, i++)
987 SetWindowPos((*ppWnd)->hwndSelf, 0, x, y, xsize, ysize,
988 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
989 y += ysize;
990 ppWnd++;
992 x += xsize;
995 WIN_ReleaseWinArray(heapPtr);
998 if( total < ci->nActiveChildren ) ArrangeIconicWindows( wndClient->hwndSelf );
1001 /* ----------------------- Frame window ---------------------------- */
1004 /**********************************************************************
1005 * MDI_AugmentFrameMenu
1007 static BOOL MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
1008 HWND hChild )
1010 WND* child = WIN_FindWndPtr(hChild);
1011 HMENU hSysPopup = 0;
1012 HBITMAP hSysMenuBitmap = 0;
1014 TRACE("frame %p,child %04x\n",frame,hChild);
1016 if( !frame->wIDmenu || !child->hSysMenu )
1018 WIN_ReleaseWndPtr(child);
1019 return 0;
1021 WIN_ReleaseWndPtr(child);
1023 /* create a copy of sysmenu popup and insert it into frame menu bar */
1025 if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
1026 return 0;
1028 TRACE("\tgot popup %04x in sysmenu %04x\n",
1029 hSysPopup, child->hSysMenu);
1031 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
1032 SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
1033 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
1034 SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
1036 /* In Win 95 look, the system menu is replaced by the child icon */
1038 if(TWEAK_WineLook > WIN31_LOOK)
1040 HICON hIcon = GetClassLongA(hChild, GCL_HICONSM);
1041 if (!hIcon)
1042 hIcon = GetClassLongA(hChild, GCL_HICON);
1043 if (hIcon)
1045 HDC hMemDC;
1046 HBITMAP hBitmap, hOldBitmap;
1047 HBRUSH hBrush;
1048 HDC hdc = GetDC(hChild);
1050 if (hdc)
1052 int cx, cy;
1053 cx = GetSystemMetrics(SM_CXSMICON);
1054 cy = GetSystemMetrics(SM_CYSMICON);
1055 hMemDC = CreateCompatibleDC(hdc);
1056 hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
1057 hOldBitmap = SelectObject(hMemDC, hBitmap);
1058 SetMapMode(hMemDC, MM_TEXT);
1059 hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
1060 DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL);
1061 SelectObject (hMemDC, hOldBitmap);
1062 DeleteObject(hBrush);
1063 DeleteDC(hMemDC);
1064 ReleaseDC(hChild, hdc);
1065 hSysMenuBitmap = hBitmap;
1069 else
1070 hSysMenuBitmap = hBmpClose;
1072 if( !InsertMenuA(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
1073 hSysPopup, (LPSTR)(DWORD)hSysMenuBitmap))
1075 TRACE("not inserted\n");
1076 DestroyMenu(hSysPopup);
1077 return 0;
1080 /* The close button is only present in Win 95 look */
1081 if(TWEAK_WineLook > WIN31_LOOK)
1083 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
1084 SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
1087 EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
1088 EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
1089 EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
1090 SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE);
1092 /* redraw menu */
1093 DrawMenuBar(frame->hwndSelf);
1095 return 1;
1098 /**********************************************************************
1099 * MDI_RestoreFrameMenu
1101 static BOOL MDI_RestoreFrameMenu( WND *frameWnd, HWND hChild )
1103 MENUITEMINFOW menuInfo;
1104 INT nItems = GetMenuItemCount(frameWnd->wIDmenu) - 1;
1105 UINT iId = GetMenuItemID(frameWnd->wIDmenu,nItems) ;
1107 TRACE("frameWnd %p,(%04x),child %04x,nIt=%d,iId=%d\n",
1108 frameWnd,frameWnd->hwndSelf,hChild,nItems,iId);
1110 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
1111 return 0;
1114 * Remove the system menu, If that menu is the icon of the window
1115 * as it is in win95, we have to delete the bitmap.
1117 memset(&menuInfo, 0, sizeof(menuInfo));
1118 menuInfo.cbSize = sizeof(menuInfo);
1119 menuInfo.fMask = MIIM_DATA | MIIM_TYPE;
1121 GetMenuItemInfoW(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);