Change xterm mouse tracking mode to BTN_EVENT_MOUSE (track if pressed).
[wine.git] / windows / mdi.c
blobd482e48c8e680ea3e87aa34d24388c9d080688f3
1 /* MDI.C
3 * Copyright 1994, Bob Amstadt
4 * 1995,1996 Alex Korobka
6 * This file contains routines to support MDI (Multiple Document
7 * Interface) features .
9 * Notes: Fairly complete implementation.
10 * Also, Excel and WinWord do _not_ use MDI so if you're trying
11 * to fix them look elsewhere.
13 * Notes on how the "More Windows..." is implemented:
15 * When we have more than 9 opened windows, a "More Windows..."
16 * option appears in the "Windows" menu. Each child window has
17 * a WND* associated with it, accesible via the children list of
18 * the parent window. This WND* has a wIDmenu member, which reflects
19 * the position of the child in the window list. For example, with
20 * 9 child windows, we could have the following pattern:
24 * Name of the child window pWndChild->wIDmenu
25 * Doc1 5000
26 * Doc2 5001
27 * Doc3 5002
28 * Doc4 5003
29 * Doc5 5004
30 * Doc6 5005
31 * Doc7 5006
32 * Doc8 5007
33 * Doc9 5008
36 * The "Windows" menu, as the "More windows..." dialog, are constructed
37 * in this order. If we add a child, we would have the following list:
40 * Name of the child window pWndChild->wIDmenu
41 * Doc1 5000
42 * Doc2 5001
43 * Doc3 5002
44 * Doc4 5003
45 * Doc5 5004
46 * Doc6 5005
47 * Doc7 5006
48 * Doc8 5007
49 * Doc9 5008
50 * Doc10 5009
52 * But only 5000 to 5008 would be displayed in the "Windows" menu. We want
53 * the last created child to be in the menu, so we swap the last child with
54 * the 9th... Doc9 will be accessible via the "More Windows..." option.
56 * Doc1 5000
57 * Doc2 5001
58 * Doc3 5002
59 * Doc4 5003
60 * Doc5 5004
61 * Doc6 5005
62 * Doc7 5006
63 * Doc8 5007
64 * Doc9 5009
65 * Doc10 5008
69 #include <stdlib.h>
70 #include <stdio.h>
71 #include <string.h>
72 #include <math.h>
73 #include "windef.h"
74 #include "wingdi.h"
75 #include "winuser.h"
76 #include "wine/unicode.h"
77 #include "win.h"
78 #include "heap.h"
79 #include "nonclient.h"
80 #include "mdi.h"
81 #include "user.h"
82 #include "menu.h"
83 #include "scroll.h"
84 #include "struct32.h"
85 #include "tweak.h"
86 #include "debugtools.h"
87 #include "dlgs.h"
89 DEFAULT_DEBUG_CHANNEL(mdi);
91 #define MDIF_NEEDUPDATE 0x0001
93 static HBITMAP16 hBmpClose = 0;
94 static HBITMAP16 hBmpRestore = 0;
96 /* ----------------- declarations ----------------- */
97 static void MDI_UpdateFrameText(WND *, HWND, BOOL, LPCWSTR);
98 static BOOL MDI_AugmentFrameMenu(MDICLIENTINFO*, WND *, HWND);
99 static BOOL MDI_RestoreFrameMenu(WND *, HWND);
101 static LONG MDI_ChildActivate( WND*, HWND );
103 static HWND MDI_MoreWindowsDialog(WND*);
104 static void MDI_SwapMenuItems(WND *, UINT, UINT);
105 /* -------- Miscellaneous service functions ----------
107 * MDI_GetChildByID
110 static HWND MDI_GetChildByID(WND* wndPtr, INT id)
112 for (wndPtr = wndPtr->child; wndPtr; wndPtr = wndPtr->next)
113 if (wndPtr->wIDmenu == id) return wndPtr->hwndSelf;
114 return 0;
117 static void MDI_PostUpdate(HWND hwnd, MDICLIENTINFO* ci, WORD recalc)
119 if( !(ci->mdiFlags & MDIF_NEEDUPDATE) )
121 ci->mdiFlags |= MDIF_NEEDUPDATE;
122 PostMessageA( hwnd, WM_MDICALCCHILDSCROLL, 0, 0);
124 ci->sbRecalc = recalc;
127 /**********************************************************************
128 * MDI_MenuModifyItem
130 static BOOL MDI_MenuModifyItem(WND* clientWnd, HWND hWndChild )
132 WCHAR buffer[128];
133 static const WCHAR format[] = {'%','d',' ',0};
134 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
135 WND *wndPtr = WIN_FindWndPtr(hWndChild);
136 UINT n = wsprintfW(buffer, format,
137 wndPtr->wIDmenu - clientInfo->idFirstChild + 1);
138 BOOL bRet = 0;
140 if( !clientInfo->hWindowMenu )
142 bRet = FALSE;
143 goto END;
146 if (wndPtr->text) lstrcpynW(buffer + n, wndPtr->text, sizeof(buffer)/sizeof(WCHAR) - n );
148 n = GetMenuState(clientInfo->hWindowMenu,wndPtr->wIDmenu ,MF_BYCOMMAND);
149 bRet = ModifyMenuW(clientInfo->hWindowMenu , wndPtr->wIDmenu,
150 MF_BYCOMMAND | MF_STRING, wndPtr->wIDmenu, buffer );
151 CheckMenuItem(clientInfo->hWindowMenu ,wndPtr->wIDmenu , n & MF_CHECKED);
152 END:
153 WIN_ReleaseWndPtr(wndPtr);
154 return bRet;
157 /**********************************************************************
158 * MDI_MenuDeleteItem
160 static BOOL MDI_MenuDeleteItem(WND* clientWnd, HWND hWndChild )
162 WCHAR buffer[128];
163 static const WCHAR format[] = {'&','%','d',' ',0};
164 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
165 WND *wndPtr = WIN_FindWndPtr(hWndChild);
166 UINT index = 0,id,n;
167 BOOL retvalue;
169 if( !clientInfo->nActiveChildren ||
170 !clientInfo->hWindowMenu )
172 retvalue = FALSE;
173 goto END;
176 id = wndPtr->wIDmenu;
177 DeleteMenu(clientInfo->hWindowMenu,id,MF_BYCOMMAND);
179 /* walk the rest of MDI children to prevent gaps in the id
180 * sequence and in the menu child list */
182 for( index = id+1; index <= clientInfo->nActiveChildren +
183 clientInfo->idFirstChild; index++ )
185 WND *tmpWnd = WIN_FindWndPtr(MDI_GetChildByID(clientWnd,index));
186 if( !tmpWnd )
188 TRACE("no window for id=%i\n",index);
189 WIN_ReleaseWndPtr(tmpWnd);
190 continue;
193 /* set correct id */
194 tmpWnd->wIDmenu--;
196 n = wsprintfW(buffer, format ,index - clientInfo->idFirstChild);
197 if (tmpWnd->text)
198 lstrcpynW(buffer + n, tmpWnd->text, sizeof(buffer)/sizeof(WCHAR) - n );
200 /* change menu if the current child is to be shown in the
201 * "Windows" menu
203 if (index <= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
204 ModifyMenuW(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING,
205 index - 1 , buffer );
206 WIN_ReleaseWndPtr(tmpWnd);
209 /* We must restore the "More Windows..." option if there is enough child
211 if (clientInfo->nActiveChildren - 1 > MDI_MOREWINDOWSLIMIT)
213 char szTmp[50];
214 LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
216 AppendMenuA(clientInfo->hWindowMenu ,MF_STRING ,clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT, szTmp );
218 retvalue = TRUE;
219 END:
220 WIN_ReleaseWndPtr(wndPtr);
221 return retvalue;
224 /**********************************************************************
225 * MDI_GetWindow
227 * returns "activateable" child different from the current or zero
229 static HWND MDI_GetWindow(WND *clientWnd, HWND hWnd, BOOL bNext,
230 DWORD dwStyleMask )
232 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
233 WND *wndPtr, *pWnd, *pWndLast = NULL;
235 dwStyleMask |= WS_DISABLED | WS_VISIBLE;
236 if( !hWnd ) hWnd = clientInfo->hwndActiveChild;
238 if( !(wndPtr = WIN_FindWndPtr(hWnd)) ) return 0;
240 for ( pWnd = WIN_LockWndPtr(wndPtr->next); ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
242 if (!pWnd ) WIN_UpdateWndPtr(&pWnd,wndPtr->parent->child);
244 if ( pWnd == wndPtr ) break; /* went full circle */
246 if (!pWnd->owner && (pWnd->dwStyle & dwStyleMask) == WS_VISIBLE )
248 pWndLast = pWnd;
249 if ( bNext ) break;
252 WIN_ReleaseWndPtr(wndPtr);
253 WIN_ReleaseWndPtr(pWnd);
254 return pWndLast ? pWndLast->hwndSelf : 0;
257 /**********************************************************************
258 * MDI_CalcDefaultChildPos
260 * It seems that the default height is about 2/3 of the client rect
262 static void MDI_CalcDefaultChildPos( WND* w, WORD n, LPPOINT lpPos,
263 INT delta)
265 INT nstagger;
266 RECT rect = w->rectClient;
267 INT spacing = GetSystemMetrics(SM_CYCAPTION) +
268 GetSystemMetrics(SM_CYFRAME) - 1;
270 if( rect.bottom - rect.top - delta >= spacing )
271 rect.bottom -= delta;
273 nstagger = (rect.bottom - rect.top)/(3 * spacing);
274 lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
275 lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
276 lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
279 /**********************************************************************
280 * MDISetMenu
282 static LRESULT MDISetMenu( HWND hwnd, HMENU hmenuFrame,
283 HMENU hmenuWindow)
285 WND *w;
286 MDICLIENTINFO *ci;
287 HWND hwndFrame = GetParent(hwnd);
288 HMENU oldFrameMenu = GetMenu(hwndFrame);
290 TRACE("%04x %04x %04x\n",
291 hwnd, hmenuFrame, hmenuWindow);
293 if (hmenuFrame && !IsMenu(hmenuFrame))
295 WARN("hmenuFrame is not a menu handle\n");
296 return 0L;
299 if (hmenuWindow && !IsMenu(hmenuWindow))
301 WARN("hmenuWindow is not a menu handle\n");
302 return 0L;
305 w = WIN_FindWndPtr(hwnd);
306 ci = (MDICLIENTINFO *) w->wExtra;
308 if( ci->hwndChildMaximized && hmenuFrame && hmenuFrame!=oldFrameMenu )
309 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized );
311 if( hmenuWindow && ci->hWindowMenu && hmenuWindow!=ci->hWindowMenu )
313 /* delete menu items from ci->hWindowMenu
314 * and add them to hmenuWindow */
316 INT i = GetMenuItemCount(ci->hWindowMenu) - 1;
317 INT pos = GetMenuItemCount(hmenuWindow) + 1;
319 AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL);
321 if( ci->nActiveChildren )
323 INT j;
324 LPWSTR buffer = NULL;
325 MENUITEMINFOW mii;
326 INT nbWindowsMenuItems; /* num of documents shown + "More Windows..." if present */
328 if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
329 nbWindowsMenuItems = ci->nActiveChildren;
330 else
331 nbWindowsMenuItems = MDI_MOREWINDOWSLIMIT + 1;
333 j = i - nbWindowsMenuItems + 1;
335 for( ; i >= j ; i-- )
337 memset(&mii, 0, sizeof(mii));
338 mii.cbSize = sizeof(mii);
339 mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE
340 | MIIM_SUBMENU | MIIM_TYPE | MIIM_BITMAP;
342 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
343 if(mii.cch) { /* Menu is MFT_STRING */
344 mii.cch++; /* add room for '\0' */
345 buffer = HeapAlloc(GetProcessHeap(), 0,
346 mii.cch * sizeof(WCHAR));
347 mii.dwTypeData = buffer;
348 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
350 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
351 InsertMenuItemW(hmenuWindow, pos, TRUE, &mii);
352 if(buffer) {
353 HeapFree(GetProcessHeap(), 0, buffer);
354 buffer = NULL;
359 /* remove separator */
360 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
362 ci->hWindowMenu = hmenuWindow;
365 if (hmenuFrame)
367 SetMenu(hwndFrame, hmenuFrame);
368 if( hmenuFrame!=oldFrameMenu )
370 if( ci->hwndChildMaximized )
371 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
372 WIN_ReleaseWndPtr(w);
373 return oldFrameMenu;
376 else
378 INT nItems = GetMenuItemCount(w->parent->wIDmenu) - 1;
379 UINT iId = GetMenuItemID(w->parent->wIDmenu,nItems) ;
381 if( !(iId == SC_RESTORE || iId == SC_CLOSE) )
383 /* SetMenu() may already have been called, meaning that this window
384 * already has its menu. But they may have done a SetMenu() on
385 * an MDI window, and called MDISetMenu() after the fact, meaning
386 * that the "if" to this "else" wouldn't catch the need to
387 * augment the frame menu.
389 if( ci->hwndChildMaximized )
390 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
393 WIN_ReleaseWndPtr(w);
394 return 0;
397 /**********************************************************************
398 * MDIRefreshMenu
400 static LRESULT MDIRefreshMenu( HWND hwnd, HMENU hmenuFrame,
401 HMENU hmenuWindow)
403 HWND hwndFrame = GetParent(hwnd);
404 HMENU oldFrameMenu = GetMenu(hwndFrame);
406 TRACE("%04x %04x %04x\n",
407 hwnd, hmenuFrame, hmenuWindow);
409 FIXME("partially function stub\n");
411 return oldFrameMenu;
415 /* ------------------ MDI child window functions ---------------------- */
418 /**********************************************************************
419 * MDICreateChild
421 static HWND MDICreateChild( WND *w, MDICLIENTINFO *ci, HWND parent,
422 LPMDICREATESTRUCTA cs )
424 POINT pos[2];
425 DWORD style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
426 HWND hwnd, hwndMax = 0;
427 WORD wIDmenu = ci->idFirstChild + ci->nActiveChildren;
428 char lpstrDef[]="junk!";
430 TRACE("origin %i,%i - dim %i,%i, style %08x\n",
431 cs->x, cs->y, cs->cx, cs->cy, (unsigned)cs->style);
432 /* calculate placement */
433 MDI_CalcDefaultChildPos(w, ci->nTotalCreated++, pos, 0);
435 if (cs->cx == CW_USEDEFAULT || !cs->cx) cs->cx = pos[1].x;
436 if (cs->cy == CW_USEDEFAULT || !cs->cy) cs->cy = pos[1].y;
438 if( cs->x == CW_USEDEFAULT )
440 cs->x = pos[0].x;
441 cs->y = pos[0].y;
444 /* restore current maximized child */
445 if( style & WS_VISIBLE && ci->hwndChildMaximized )
447 if( style & WS_MAXIMIZE )
448 SendMessageA(w->hwndSelf, WM_SETREDRAW, FALSE, 0L );
449 hwndMax = ci->hwndChildMaximized;
450 ShowWindow( hwndMax, SW_SHOWNOACTIVATE );
451 if( style & WS_MAXIMIZE )
452 SendMessageA(w->hwndSelf, WM_SETREDRAW, TRUE, 0L );
455 if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
456 /* this menu is needed to set a check mark in MDI_ChildActivate */
457 if (ci->hWindowMenu != 0)
458 AppendMenuA(ci->hWindowMenu ,MF_STRING ,wIDmenu, lpstrDef );
460 ci->nActiveChildren++;
462 /* fix window style */
463 if( !(w->dwStyle & MDIS_ALLCHILDSTYLES) )
465 style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE |
466 WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL );
467 style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW);
470 if( w->flags & WIN_ISWIN32 )
472 hwnd = CreateWindowA( cs->szClass, cs->szTitle, style,
473 cs->x, cs->y, cs->cx, cs->cy, parent,
474 (HMENU16)wIDmenu, cs->hOwner, cs );
476 else
478 MDICREATESTRUCT16 *cs16;
479 LPSTR title, cls;
481 cs16 = SEGPTR_NEW(MDICREATESTRUCT16);
482 STRUCT32_MDICREATESTRUCT32Ato16( cs, cs16 );
483 title = SEGPTR_STRDUP( cs->szTitle );
484 cls = SEGPTR_STRDUP( cs->szClass );
485 cs16->szTitle = SEGPTR_GET(title);
486 cs16->szClass = SEGPTR_GET(cls);
488 hwnd = CreateWindow16( cs->szClass, cs->szTitle, style,
489 cs16->x, cs16->y, cs16->cx, cs16->cy, parent,
490 (HMENU)wIDmenu, cs16->hOwner,
491 (LPVOID)SEGPTR_GET(cs16) );
492 SEGPTR_FREE( title );
493 SEGPTR_FREE( cls );
494 SEGPTR_FREE( cs16 );
497 /* MDI windows are WS_CHILD so they won't be activated by CreateWindow */
499 if (hwnd)
501 WND* wnd = WIN_FindWndPtr( hwnd );
503 /* All MDI child windows have the WS_EX_MDICHILD style */
504 wnd->dwExStyle |= WS_EX_MDICHILD;
506 /* If we have more than 9 windows, we must insert the new one at the
507 * 9th position in order to see it in the "Windows" menu
509 if (ci->nActiveChildren > MDI_MOREWINDOWSLIMIT)
510 MDI_SwapMenuItems(wnd->parent, wnd->wIDmenu, ci->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
512 MDI_MenuModifyItem(w ,hwnd);
514 /* Have we hit the "More Windows..." limit? If so, we must
515 * add a "More Windows..." option
517 if (ci->nActiveChildren == MDI_MOREWINDOWSLIMIT + 1)
519 char szTmp[50];
520 LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
522 ModifyMenuA(ci->hWindowMenu,
523 ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
524 MF_BYCOMMAND | MF_STRING,
525 ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
526 szTmp);
529 if( wnd->dwStyle & WS_MINIMIZE && ci->hwndActiveChild )
530 ShowWindow( hwnd, SW_SHOWMINNOACTIVE );
531 else
533 /* WS_VISIBLE is clear if a) the MDI client has
534 * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the
535 * MDICreateStruct. If so the created window is not shown nor
536 * activated.
538 int showflag=wnd->dwStyle & WS_VISIBLE;
539 /* clear visible flag, otherwise SetWindoPos32 ignores
540 * the SWP_SHOWWINDOW command.
542 wnd->dwStyle &= ~WS_VISIBLE;
543 if(showflag){
544 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE );
546 /* Set maximized state here in case hwnd didn't receive WM_SIZE
547 * during CreateWindow - bad!
550 if((wnd->dwStyle & WS_MAXIMIZE) && !ci->hwndChildMaximized )
552 ci->hwndChildMaximized = wnd->hwndSelf;
553 MDI_AugmentFrameMenu( ci, w->parent, hwnd );
554 MDI_UpdateFrameText( w->parent, ci->self, MDI_REPAINTFRAME, NULL );
556 }else
557 /* needed, harmless ? */
558 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE );
561 WIN_ReleaseWndPtr(wnd);
562 TRACE("created child - %04x\n",hwnd);
564 else
566 ci->nActiveChildren--;
567 DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
568 if( IsWindow(hwndMax) )
569 ShowWindow(hwndMax, SW_SHOWMAXIMIZED);
572 return hwnd;
575 /**********************************************************************
576 * MDI_ChildGetMinMaxInfo
578 * Note: The rule here is that client rect of the maximized MDI child
579 * is equal to the client rect of the MDI client window.
581 static void MDI_ChildGetMinMaxInfo( WND* clientWnd, HWND hwnd,
582 MINMAXINFO16* lpMinMax )
584 WND* childWnd = WIN_FindWndPtr(hwnd);
585 RECT rect = clientWnd->rectClient;
587 MapWindowPoints( clientWnd->parent->hwndSelf,
588 ((MDICLIENTINFO*)clientWnd->wExtra)->self, (LPPOINT)&rect, 2);
589 AdjustWindowRectEx( &rect, childWnd->dwStyle, 0, childWnd->dwExStyle );
591 lpMinMax->ptMaxSize.x = rect.right -= rect.left;
592 lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
594 lpMinMax->ptMaxPosition.x = rect.left;
595 lpMinMax->ptMaxPosition.y = rect.top;
597 WIN_ReleaseWndPtr(childWnd);
599 TRACE("max rect (%i,%i - %i, %i)\n",
600 rect.left,rect.top,rect.right,rect.bottom);
604 /**********************************************************************
605 * MDI_SwitchActiveChild
607 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
608 * being activated
610 static void MDI_SwitchActiveChild( HWND clientHwnd, HWND childHwnd,
611 BOOL bNextWindow )
613 WND *w = WIN_FindWndPtr(clientHwnd);
614 HWND hwndTo = 0;
615 HWND hwndPrev = 0;
616 MDICLIENTINFO *ci;
618 hwndTo = MDI_GetWindow(w, childHwnd, bNextWindow, 0);
620 ci = (MDICLIENTINFO *) w->wExtra;
622 TRACE("from %04x, to %04x\n",childHwnd,hwndTo);
624 if ( !hwndTo ) goto END; /* no window to switch to */
626 hwndPrev = ci->hwndActiveChild;
628 if ( hwndTo != hwndPrev )
630 BOOL bOptimize = 0;
632 if( ci->hwndChildMaximized )
634 bOptimize = 1;
635 w->dwStyle &= ~WS_VISIBLE;
638 SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0,
639 SWP_NOMOVE | SWP_NOSIZE );
641 if( bNextWindow && hwndPrev )
642 SetWindowPos( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0,
643 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
644 if( bOptimize )
645 ShowWindow( clientHwnd, SW_SHOW );
647 END:
648 WIN_ReleaseWndPtr(w);
652 /**********************************************************************
653 * MDIDestroyChild
655 static LRESULT MDIDestroyChild( WND *w_parent, MDICLIENTINFO *ci,
656 HWND parent, HWND child,
657 BOOL flagDestroy )
659 WND *childPtr = WIN_FindWndPtr(child);
661 if( childPtr )
663 MDI_MenuDeleteItem(w_parent, child);
665 if( child == ci->hwndActiveChild )
667 MDI_SwitchActiveChild(parent, child, TRUE);
669 if( child == ci->hwndActiveChild )
671 ShowWindow( child, SW_HIDE);
672 if( child == ci->hwndChildMaximized )
674 MDI_RestoreFrameMenu(w_parent->parent, child);
675 ci->hwndChildMaximized = 0;
676 MDI_UpdateFrameText(w_parent->parent,parent,TRUE,NULL);
679 MDI_ChildActivate(w_parent, 0);
683 WIN_ReleaseWndPtr(childPtr);
685 ci->nActiveChildren--;
687 TRACE("child destroyed - %04x\n",child);
689 if (flagDestroy)
691 MDI_PostUpdate(GetParent(child), ci, SB_BOTH+1);
692 DestroyWindow(child);
696 return 0;
700 /**********************************************************************
701 * MDI_ChildActivate
703 * Note: hWndChild is NULL when last child is being destroyed
705 static LONG MDI_ChildActivate( WND *clientPtr, HWND hWndChild )
707 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientPtr->wExtra;
708 HWND prevActiveWnd = clientInfo->hwndActiveChild;
709 WND *wndPtr = WIN_FindWndPtr( hWndChild );
710 WND *wndPrev = WIN_FindWndPtr( prevActiveWnd );
711 BOOL isActiveFrameWnd = 0;
712 LONG retvalue;
714 if( wndPtr )
716 if( wndPtr->dwStyle & WS_DISABLED )
718 retvalue = 0L;
719 goto END;
723 /* Don't activate if it is already active. Might happen
724 since ShowWindow DOES activate MDI children */
725 if (clientInfo->hwndActiveChild == hWndChild)
727 retvalue = 0L;
728 goto END;
731 TRACE("%04x\n", hWndChild);
733 if( GetActiveWindow() == clientPtr->parent->hwndSelf )
734 isActiveFrameWnd = TRUE;
736 /* deactivate prev. active child */
737 if( wndPrev )
739 wndPrev->dwStyle |= WS_SYSMENU;
740 SendMessageA( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
741 SendMessageA( prevActiveWnd, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
742 (LPARAM)hWndChild);
743 /* uncheck menu item */
744 if( clientInfo->hWindowMenu )
746 WORD wPrevID = wndPrev->wIDmenu - clientInfo->idFirstChild;
748 if (wPrevID < MDI_MOREWINDOWSLIMIT)
749 CheckMenuItem( clientInfo->hWindowMenu,
750 wndPrev->wIDmenu, 0);
751 else
752 CheckMenuItem( clientInfo->hWindowMenu,
753 clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1, 0);
757 /* set appearance */
758 if( clientInfo->hwndChildMaximized )
760 if( clientInfo->hwndChildMaximized != hWndChild ) {
761 if( hWndChild ) {
762 clientInfo->hwndActiveChild = hWndChild;
763 ShowWindow( hWndChild, SW_SHOWMAXIMIZED);
764 } else
765 ShowWindow( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
769 clientInfo->hwndActiveChild = hWndChild;
771 /* check if we have any children left */
772 if( !hWndChild )
774 if( isActiveFrameWnd )
775 SetFocus( clientInfo->self );
776 retvalue = 0;
777 goto END;
780 /* check menu item */
781 if( clientInfo->hWindowMenu )
783 /* The window to be activated must be displayed in the "Windows" menu */
784 if (wndPtr->wIDmenu >= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
786 MDI_SwapMenuItems(wndPtr->parent, wndPtr->wIDmenu, clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
787 MDI_MenuModifyItem(wndPtr->parent ,wndPtr->hwndSelf);
790 CheckMenuItem(clientInfo->hWindowMenu, wndPtr->wIDmenu, MF_CHECKED);
792 /* bring active child to the top */
793 SetWindowPos( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
795 if( isActiveFrameWnd )
797 SendMessageA( hWndChild, WM_NCACTIVATE, TRUE, 0L);
798 if( GetFocus() == clientInfo->self )
799 SendMessageA( clientInfo->self, WM_SETFOCUS,
800 (WPARAM)clientInfo->self, 0L );
801 else
802 SetFocus( clientInfo->self );
804 SendMessageA( hWndChild, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
805 (LPARAM)hWndChild );
806 retvalue = 1;
807 END:
808 WIN_ReleaseWndPtr(wndPtr);
809 WIN_ReleaseWndPtr(wndPrev);
810 return retvalue;
813 /* -------------------- MDI client window functions ------------------- */
815 /**********************************************************************
816 * CreateMDIMenuBitmap
818 static HBITMAP16 CreateMDIMenuBitmap(void)
820 HDC hDCSrc = CreateCompatibleDC(0);
821 HDC hDCDest = CreateCompatibleDC(hDCSrc);
822 HBITMAP16 hbClose = LoadBitmap16(0, MAKEINTRESOURCE16(OBM_CLOSE) );
823 HBITMAP16 hbCopy;
824 HANDLE16 hobjSrc, hobjDest;
826 hobjSrc = SelectObject(hDCSrc, hbClose);
827 hbCopy = CreateCompatibleBitmap(hDCSrc,GetSystemMetrics(SM_CXSIZE),GetSystemMetrics(SM_CYSIZE));
828 hobjDest = SelectObject(hDCDest, hbCopy);
830 BitBlt(hDCDest, 0, 0, GetSystemMetrics(SM_CXSIZE), GetSystemMetrics(SM_CYSIZE),
831 hDCSrc, GetSystemMetrics(SM_CXSIZE), 0, SRCCOPY);
833 SelectObject(hDCSrc, hobjSrc);
834 DeleteObject(hbClose);
835 DeleteDC(hDCSrc);
837 hobjSrc = SelectObject( hDCDest, GetStockObject(BLACK_PEN) );
839 MoveToEx( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, 0, NULL );
840 LineTo( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, GetSystemMetrics(SM_CYSIZE) - 1);
842 SelectObject(hDCDest, hobjSrc );
843 SelectObject(hDCDest, hobjDest);
844 DeleteDC(hDCDest);
846 return hbCopy;
849 /**********************************************************************
850 * MDICascade
852 static LONG MDICascade(WND* clientWnd, MDICLIENTINFO *ci)
854 WND** ppWnd;
855 UINT total;
857 if (ci->hwndChildMaximized)
858 SendMessageA( clientWnd->hwndSelf, WM_MDIRESTORE,
859 (WPARAM)ci->hwndChildMaximized, 0);
861 if (ci->nActiveChildren == 0) return 0;
863 if ((ppWnd = WIN_BuildWinArray(clientWnd, BWA_SKIPHIDDEN | BWA_SKIPOWNED |
864 BWA_SKIPICONIC, &total)))
866 WND** heapPtr = ppWnd;
867 if( total )
869 INT delta = 0, n = 0;
870 POINT pos[2];
871 if( total < ci->nActiveChildren )
872 delta = GetSystemMetrics(SM_CYICONSPACING) +
873 GetSystemMetrics(SM_CYICON);
875 /* walk the list (backwards) and move windows */
876 while (*ppWnd) ppWnd++;
877 while (ppWnd != heapPtr)
879 ppWnd--;
880 TRACE("move %04x to (%ld,%ld) size [%ld,%ld]\n",
881 (*ppWnd)->hwndSelf, pos[0].x, pos[0].y, pos[1].x, pos[1].y);
883 MDI_CalcDefaultChildPos(clientWnd, n++, pos, delta);
884 SetWindowPos( (*ppWnd)->hwndSelf, 0, pos[0].x, pos[0].y,
885 pos[1].x, pos[1].y,
886 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
889 WIN_ReleaseWinArray(heapPtr);
892 if( total < ci->nActiveChildren )
893 ArrangeIconicWindows( clientWnd->hwndSelf );
894 return 0;
897 /**********************************************************************
898 * MDITile
900 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM wParam )
902 WND** ppWnd;
903 UINT total = 0;
905 if (ci->hwndChildMaximized)
906 SendMessageA( wndClient->hwndSelf, WM_MDIRESTORE,
907 (WPARAM)ci->hwndChildMaximized, 0);
909 if (ci->nActiveChildren == 0) return;
911 ppWnd = WIN_BuildWinArray(wndClient, BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
912 ((wParam & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
914 TRACE("%u windows to tile\n", total);
916 if( ppWnd )
918 WND** heapPtr = ppWnd;
920 if( total )
922 RECT rect;
923 int x, y, xsize, ysize;
924 int rows, columns, r, c, i;
926 GetClientRect(wndClient->hwndSelf,&rect);
927 rows = (int) sqrt((double)total);
928 columns = total / rows;
930 if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */
932 i = rows;
933 rows = columns; /* exchange r and c */
934 columns = i;
937 if( total != ci->nActiveChildren)
939 y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
940 rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
943 ysize = rect.bottom / rows;
944 xsize = rect.right / columns;
946 for (x = i = 0, c = 1; c <= columns && *ppWnd; c++)
948 if (c == columns)
950 rows = total - i;
951 ysize = rect.bottom / rows;
954 y = 0;
955 for (r = 1; r <= rows && *ppWnd; r++, i++)
957 SetWindowPos((*ppWnd)->hwndSelf, 0, x, y, xsize, ysize,
958 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
959 y += ysize;
960 ppWnd++;
962 x += xsize;
965 WIN_ReleaseWinArray(heapPtr);
968 if( total < ci->nActiveChildren ) ArrangeIconicWindows( wndClient->hwndSelf );
971 /* ----------------------- Frame window ---------------------------- */
974 /**********************************************************************
975 * MDI_AugmentFrameMenu
977 static BOOL MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
978 HWND hChild )
980 WND* child = WIN_FindWndPtr(hChild);
981 HMENU hSysPopup = 0;
982 HBITMAP hSysMenuBitmap = 0;
984 TRACE("frame %p,child %04x\n",frame,hChild);
986 if( !frame->wIDmenu || !child->hSysMenu )
988 WIN_ReleaseWndPtr(child);
989 return 0;
991 WIN_ReleaseWndPtr(child);
993 /* create a copy of sysmenu popup and insert it into frame menu bar */
995 if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
996 return 0;
998 TRACE("\tgot popup %04x in sysmenu %04x\n",
999 hSysPopup, child->hSysMenu);
1001 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
1002 SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
1003 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
1004 SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
1006 /* In Win 95 look, the system menu is replaced by the child icon */
1008 if(TWEAK_WineLook > WIN31_LOOK)
1010 HICON hIcon = GetClassLongA(hChild, GCL_HICONSM);
1011 if (!hIcon)
1012 hIcon = GetClassLongA(hChild, GCL_HICON);
1013 if (hIcon)
1015 HDC hMemDC;
1016 HBITMAP hBitmap, hOldBitmap;
1017 HBRUSH hBrush;
1018 HDC hdc = GetDC(hChild);
1020 if (hdc)
1022 int cx, cy;
1023 cx = GetSystemMetrics(SM_CXSMICON);
1024 cy = GetSystemMetrics(SM_CYSMICON);
1025 hMemDC = CreateCompatibleDC(hdc);
1026 hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
1027 hOldBitmap = SelectObject(hMemDC, hBitmap);
1028 SetMapMode(hMemDC, MM_TEXT);
1029 hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
1030 DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL);
1031 SelectObject (hMemDC, hOldBitmap);
1032 DeleteObject(hBrush);
1033 DeleteDC(hMemDC);
1034 ReleaseDC(hChild, hdc);
1035 hSysMenuBitmap = hBitmap;
1039 else
1040 hSysMenuBitmap = hBmpClose;
1042 if( !InsertMenuA(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
1043 hSysPopup, (LPSTR)(DWORD)hSysMenuBitmap))
1045 TRACE("not inserted\n");
1046 DestroyMenu(hSysPopup);
1047 return 0;
1050 /* The close button is only present in Win 95 look */
1051 if(TWEAK_WineLook > WIN31_LOOK)
1053 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
1054 SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
1057 EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
1058 EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
1059 EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
1060 SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE);
1062 /* redraw menu */
1063 DrawMenuBar(frame->hwndSelf);
1065 return 1;
1068 /**********************************************************************
1069 * MDI_RestoreFrameMenu
1071 static BOOL MDI_RestoreFrameMenu( WND *frameWnd, HWND hChild )
1073 MENUITEMINFOA menuInfo;
1074 INT nItems = GetMenuItemCount(frameWnd->wIDmenu) - 1;
1075 UINT iId = GetMenuItemID(frameWnd->wIDmenu,nItems) ;
1077 TRACE("frameWnd %p,(%04x),child %04x,nIt=%d,iId=%d\n",
1078 frameWnd,frameWnd->hwndSelf,hChild,nItems,iId);
1080 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
1081 return 0;
1084 * Remove the system menu, If that menu is the icon of the window
1085 * as it is in win95, we have to delete the bitmap.
1087 menuInfo.cbSize = sizeof(MENUITEMINFOA);
1088 menuInfo.fMask = MIIM_DATA | MIIM_TYPE;
1090 GetMenuItemInfoA(frameWnd->wIDmenu,
1092 TRUE,
1093 &menuInfo);
1095 RemoveMenu(frameWnd->wIDmenu,0,MF_BYPOSITION);
1097 if ( (menuInfo.fType & MFT_BITMAP) &&
1098 (LOWORD(menuInfo.dwTypeData)!=0) &&
1099 (LOWORD(menuInfo.dwTypeData)!=hBmpClose) )
1101 DeleteObject((HBITMAP)LOWORD(menuInfo.dwTypeData));
1104 if(TWEAK_WineLook > WIN31_LOOK)
1106 /* close */
1107 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1109 /* restore */
1110 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1111 /* minimize */
1112 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1114 DrawMenuBar(frameWnd->hwndSelf);
1116 return 1;
1120 /**********************************************************************
1121 * MDI_UpdateFrameText
1123 * used when child window is maximized/restored
1125 * Note: lpTitle can be NULL
1127 static void MDI_UpdateFrameText( WND *frameWnd, HWND hClient,
1128 BOOL repaint, LPCWSTR lpTitle )
1130 WCHAR lpBuffer[MDI_MAXTITLELENGTH+1];
1131 WND* clientWnd = WIN_FindWndPtr(hClient);
1132 MDICLIENTINFO *ci = (MDICLIENTINFO *) clientWnd->wExtra;
1134 TRACE("repaint %i, frameText %s\n", repaint, (lpTitle)?debugstr_w(lpTitle):"NULL");
1136 if (!clientWnd)
1137 return;
1139 if (!ci)
1141 WIN_ReleaseWndPtr(clientWnd);
1142 return;
1145 /* store new "default" title if lpTitle is not NULL */
1146 if (lpTitle)
1148 if (ci->frameTitle) HeapFree( SystemHeap, 0, ci->frameTitle );
1149 ci->frameTitle = HEAP_strdupW( SystemHeap, 0, lpTitle );
1152 if (ci->frameTitle)
1154 WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );
1156 if( childWnd && childWnd->text )
1158 /* combine frame title and child title if possible */
1160 static const WCHAR lpBracket[] = {' ','-',' ','[',0};
1161 static const WCHAR lpBracket2[] = {']',0};
1162 int i_frame_text_length = strlenW(ci->frameTitle);
1163 int i_child_text_length = strlenW(childWnd->text);
1165 lstrcpynW( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
1167 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
1169 strcatW( lpBuffer, lpBracket );
1171 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
1173 strcatW( lpBuffer, childWnd->text );
1174 strcatW( lpBuffer, lpBracket2 );
1176 else
1178 lstrcpynW( lpBuffer + i_frame_text_length + 4,
1179 childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
1180 strcatW( lpBuffer, lpBracket2 );
1184 else
1186 lstrcpynW(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH+1 );
1188 WIN_ReleaseWndPtr(childWnd);
1191 else
1192 lpBuffer[0] = '\0';
1194 DEFWND_SetTextW( frameWnd, lpBuffer );
1195 if( repaint == MDI_REPAINTFRAME)
1196 SetWindowPos( frameWnd->hwndSelf, 0,0,0,0,0, SWP_FRAMECHANGED |
1197 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
1199 WIN_ReleaseWndPtr(clientWnd);
1204 /* ----------------------------- Interface ---------------------------- */
1207 /**********************************************************************
1208 * MDIClientWndProc
1210 * This function handles all MDI requests.
1212 LRESULT WINAPI MDIClientWndProc( HWND hwnd, UINT message, WPARAM wParam,
1213 LPARAM lParam )
1215 LPCREATESTRUCTA cs;
1216 MDICLIENTINFO *ci;
1217 RECT rect;
1218 WND *w, *frameWnd;
1219 INT nItems;
1220 LRESULT retvalue;
1222 if ( ( w = WIN_FindWndPtr(hwnd) ) == NULL )
1223 return 0;
1225 if ( ( frameWnd = WIN_LockWndPtr(w->parent) ) == NULL ) {
1226 WIN_ReleaseWndPtr(w);
1227 return 0;
1230 ci = (MDICLIENTINFO *) w->wExtra;
1232 switch (message)
1234 case WM_CREATE:
1236 cs = (LPCREATESTRUCTA)lParam;
1238 /* Translation layer doesn't know what's in the cs->lpCreateParams
1239 * so we have to keep track of what environment we're in. */
1241 if( w->flags & WIN_ISWIN32 )
1243 #define ccs ((LPCLIENTCREATESTRUCT)cs->lpCreateParams)
1244 ci->hWindowMenu = ccs->hWindowMenu;
1245 ci->idFirstChild = ccs->idFirstChild;
1246 #undef ccs
1248 else
1250 LPCLIENTCREATESTRUCT16 ccs = (LPCLIENTCREATESTRUCT16)
1251 PTR_SEG_TO_LIN(cs->lpCreateParams);
1252 ci->hWindowMenu = ccs->hWindowMenu;
1253 ci->idFirstChild = ccs->idFirstChild;
1256 ci->hwndChildMaximized = 0;
1257 ci->nActiveChildren = 0;
1258 ci->nTotalCreated = 0;
1259 ci->frameTitle = NULL;
1260 ci->mdiFlags = 0;
1261 ci->self = hwnd;
1262 w->dwStyle |= WS_CLIPCHILDREN;
1264 if (!hBmpClose)
1266 hBmpClose = CreateMDIMenuBitmap();
1267 hBmpRestore = LoadBitmap16( 0, MAKEINTRESOURCE16(OBM_RESTORE) );
1269 MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
1271 if (ci->hWindowMenu != 0)
1272 AppendMenuA( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
1274 GetClientRect(frameWnd->hwndSelf, &rect);
1275 NC_HandleNCCalcSize( w, &rect );
1276 w->rectClient = rect;
1278 TRACE("Client created - hwnd = %04x, idFirst = %u\n",
1279 hwnd, ci->idFirstChild );
1281 retvalue = 0;
1282 goto END;
1284 case WM_DESTROY:
1285 if( ci->hwndChildMaximized )
1286 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized);
1287 if((ci->hWindowMenu != 0) &&
1288 (nItems = GetMenuItemCount(ci->hWindowMenu)) > 0)
1290 ci->idFirstChild = nItems - 1;
1291 ci->nActiveChildren++; /* to delete a separator */
1292 while( ci->nActiveChildren-- )
1293 DeleteMenu(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
1295 retvalue = 0;
1296 goto END;
1298 case WM_MDIACTIVATE:
1299 if( ci->hwndActiveChild != (HWND)wParam )
1300 SetWindowPos((HWND)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
1301 retvalue = 0;
1302 goto END;
1304 case WM_MDICASCADE:
1305 retvalue = MDICascade(w, ci);
1306 goto END;
1308 case WM_MDICREATE:
1309 if (lParam) retvalue = MDICreateChild( w, ci, hwnd,
1310 (MDICREATESTRUCTA*)lParam );
1311 else retvalue = 0;
1312 goto END;
1314 case WM_MDIDESTROY:
1315 retvalue = MDIDestroyChild( w, ci, hwnd, (HWND)wParam, TRUE );
1316 goto END;
1318 case WM_MDIGETACTIVE:
1319 if (lParam) *(BOOL *)lParam = (ci->hwndChildMaximized > 0);
1320 retvalue = ci->hwndActiveChild;
1321 goto END;
1323 case WM_MDIICONARRANGE:
1324 ci->mdiFlags |= MDIF_NEEDUPDATE;
1325 ArrangeIconicWindows(hwnd);
1326 ci->sbRecalc = SB_BOTH+1;
1327 SendMessageA(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
1328 retvalue = 0;
1329 goto END;
1331 case WM_MDIMAXIMIZE:
1332 ShowWindow( (HWND)wParam, SW_MAXIMIZE );
1333 retvalue = 0;
1334 goto END;
1336 case WM_MDINEXT: /* lParam != 0 means previous window */
1337 MDI_SwitchActiveChild(hwnd, (HWND)wParam, (lParam)? FALSE : TRUE );
1338 break;
1340 case WM_MDIRESTORE:
1341 SendMessageA( (HWND)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
1342 retvalue = 0;
1343 goto END;
1345 case WM_MDISETMENU:
1346 retvalue = MDISetMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1347 goto END;
1348 case WM_MDIREFRESHMENU:
1349 retvalue = MDIRefreshMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1350 goto END;
1352 case WM_MDITILE:
1353 ci->mdiFlags |= MDIF_NEEDUPDATE;
1354 ShowScrollBar(hwnd,SB_BOTH,FALSE);
1355 MDITile(w, ci, wParam);
1356 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1357 retvalue = 0;
1358 goto END;
1360 case WM_VSCROLL:
1361 case WM_HSCROLL:
1362 ci->mdiFlags |= MDIF_NEEDUPDATE;
1363 ScrollChildren(hwnd, message, wParam, lParam);
1364 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1365 retvalue = 0;
1366 goto END;
1368 case WM_SETFOCUS:
1369 if( ci->hwndActiveChild )
1371 WND* pw = WIN_FindWndPtr( ci->hwndActiveChild );
1372 if( !(pw->dwStyle & WS_MINIMIZE) )
1373 SetFocus( ci->hwndActiveChild );
1374 WIN_ReleaseWndPtr(pw);
1376 retvalue = 0;
1377 goto END;
1379 case WM_NCACTIVATE:
1380 if( ci->hwndActiveChild )
1381 SendMessageA(ci->hwndActiveChild, message, wParam, lParam);
1382 break;
1384 case WM_PARENTNOTIFY:
1385 if (LOWORD(wParam) == WM_LBUTTONDOWN)
1387 POINT16 pt = MAKEPOINT16(lParam);
1388 HWND16 child = ChildWindowFromPoint16(hwnd, pt);
1390 TRACE("notification from %04x (%i,%i)\n",child,pt.x,pt.y);
1392 if( child && child != hwnd && child != ci->hwndActiveChild )
1393 SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1395 retvalue = 0;
1396 goto END;
1398 case WM_SIZE:
1399 if( IsWindow(ci->hwndChildMaximized) )
1401 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1402 RECT rect;
1404 rect.left = 0;
1405 rect.top = 0;
1406 rect.right = LOWORD(lParam);
1407 rect.bottom = HIWORD(lParam);
1409 AdjustWindowRectEx(&rect, child->dwStyle, 0, child->dwExStyle);
1410 MoveWindow(ci->hwndChildMaximized, rect.left, rect.top,
1411 rect.right - rect.left, rect.bottom - rect.top, 1);
1412 WIN_ReleaseWndPtr(child);
1414 else
1415 MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1417 break;
1419 case WM_MDICALCCHILDSCROLL:
1420 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1422 CalcChildScroll16(hwnd, ci->sbRecalc-1);
1423 ci->sbRecalc = 0;
1424 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1426 retvalue = 0;
1427 goto END;
1430 retvalue = DefWindowProcA( hwnd, message, wParam, lParam );
1431 END:
1432 WIN_ReleaseWndPtr(w);
1433 WIN_ReleaseWndPtr(frameWnd);
1434 return retvalue;
1438 /***********************************************************************
1439 * DefFrameProc16 (USER.445)
1441 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1442 UINT16 message, WPARAM16 wParam, LPARAM lParam )
1444 HWND16 childHwnd;
1445 MDICLIENTINFO* ci;
1446 WND* wndPtr;
1448 if (hwndMDIClient)
1450 switch (message)
1452 case WM_COMMAND:
1453 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1455 if (!wndPtr) {
1456 ERR("null wndPtr for mdi window hwndMDIClient=%04x\n",
1457 hwndMDIClient);
1458 return 0;
1461 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1463 /* check for possible syscommands for maximized MDI child */
1464 WIN_ReleaseWndPtr(wndPtr);
1466 if( ci && (
1467 wParam < ci->idFirstChild ||
1468 wParam >= ci->idFirstChild + ci->nActiveChildren
1470 if( (wParam - 0xF000) & 0xF00F ) break;
1471 switch( wParam )
1473 case SC_SIZE:
1474 case SC_MOVE:
1475 case SC_MINIMIZE:
1476 case SC_MAXIMIZE:
1477 case SC_NEXTWINDOW:
1478 case SC_PREVWINDOW:
1479 case SC_CLOSE:
1480 case SC_RESTORE:
1481 if( ci->hwndChildMaximized )
1482 return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1483 wParam, lParam);
1486 else
1488 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1489 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1491 if (wParam - ci->idFirstChild == MDI_MOREWINDOWSLIMIT)
1492 /* User chose "More Windows..." */
1493 childHwnd = MDI_MoreWindowsDialog(wndPtr);
1494 else
1495 /* User chose one of the windows listed in the "Windows" menu */
1496 childHwnd = MDI_GetChildByID(wndPtr,wParam );
1498 WIN_ReleaseWndPtr(wndPtr);
1499 if( childHwnd )
1500 SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1501 (WPARAM16)childHwnd , 0L);
1503 break;
1505 case WM_NCACTIVATE:
1506 SendMessage16(hwndMDIClient, message, wParam, lParam);
1507 break;
1509 case WM_SETTEXT:
1511 LPWSTR text = HEAP_strdupAtoW( GetProcessHeap(), 0,
1512 (LPCSTR)PTR_SEG_TO_LIN(lParam) );
1513 wndPtr = WIN_FindWndPtr(hwnd);
1514 MDI_UpdateFrameText(wndPtr, hwndMDIClient,
1515 MDI_REPAINTFRAME, text );
1516 WIN_ReleaseWndPtr(wndPtr);
1517 HeapFree( GetProcessHeap(), 0, text );
1519 return 0;
1521 case WM_SETFOCUS:
1522 SetFocus(hwndMDIClient);
1523 break;
1525 case WM_SIZE:
1526 MoveWindow16(hwndMDIClient, 0, 0,
1527 LOWORD(lParam), HIWORD(lParam), TRUE);
1528 break;
1530 case WM_NEXTMENU:
1532 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1533 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1535 if( !(wndPtr->parent->dwStyle & WS_MINIMIZE)
1536 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1538 /* control menu is between the frame system menu and
1539 * the first entry of menu bar */
1541 if( (wParam == VK_LEFT &&
1542 wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1543 (wParam == VK_RIGHT &&
1544 GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1546 LRESULT retvalue;
1547 WIN_ReleaseWndPtr(wndPtr);
1548 wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1549 retvalue = MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1550 ci->hwndActiveChild);
1551 WIN_ReleaseWndPtr(wndPtr);
1552 return retvalue;
1555 WIN_ReleaseWndPtr(wndPtr);
1556 break;
1560 return DefWindowProc16(hwnd, message, wParam, lParam);
1564 /***********************************************************************
1565 * DefFrameProcA (USER32.122)
1567 LRESULT WINAPI DefFrameProcA( HWND hwnd, HWND hwndMDIClient,
1568 UINT message, WPARAM wParam, LPARAM lParam)
1570 if (hwndMDIClient)
1572 switch (message)
1574 case WM_COMMAND:
1575 return DefFrameProc16( hwnd, hwndMDIClient, message,
1576 (WPARAM16)wParam,
1577 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1579 case WM_NCACTIVATE:
1580 SendMessageA(hwndMDIClient, message, wParam, lParam);
1581 break;
1583 case WM_SETTEXT: {
1584 LRESULT ret;
1585 LPSTR segstr = SEGPTR_STRDUP((LPSTR)lParam);
1587 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1588 wParam, (LPARAM)SEGPTR_GET(segstr) );
1589 SEGPTR_FREE(segstr);
1590 return ret;
1593 case WM_NEXTMENU:
1594 case WM_SETFOCUS:
1595 case WM_SIZE:
1596 return DefFrameProc16( hwnd, hwndMDIClient, message,
1597 wParam, lParam );
1601 return DefWindowProcA(hwnd, message, wParam, lParam);
1605 /***********************************************************************
1606 * DefFrameProcW (USER32.123)
1608 LRESULT WINAPI DefFrameProcW( HWND hwnd, HWND hwndMDIClient,
1609 UINT message, WPARAM wParam, LPARAM lParam)
1611 if (hwndMDIClient)
1613 switch (message)
1615 case WM_COMMAND:
1616 return DefFrameProc16( hwnd, hwndMDIClient, message,
1617 (WPARAM16)wParam,
1618 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1620 case WM_NCACTIVATE:
1621 SendMessageW(hwndMDIClient, message, wParam, lParam);
1622 break;
1624 case WM_SETTEXT:
1626 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1627 LRESULT ret = DefFrameProcA( hwnd, hwndMDIClient, message,
1628 wParam, (DWORD)txt );
1629 HeapFree(GetProcessHeap(),0,txt);
1630 return ret;
1632 case WM_NEXTMENU:
1633 case WM_SETFOCUS:
1634 case WM_SIZE:
1635 return DefFrameProcA( hwnd, hwndMDIClient, message,
1636 wParam, lParam );
1640 return DefWindowProcW( hwnd, message, wParam, lParam );
1644 /***********************************************************************
1645 * DefMDIChildProc16 (USER.447)
1647 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1648 WPARAM16 wParam, LPARAM lParam )
1650 MDICLIENTINFO *ci;
1651 WND *clientWnd,*tmpWnd = 0;
1652 LRESULT retvalue;
1654 tmpWnd = WIN_FindWndPtr(hwnd);
1655 if (!tmpWnd) return 0;
1656 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1657 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1658 WIN_ReleaseWndPtr(tmpWnd);
1660 switch (message)
1662 case WM_SETTEXT:
1663 DefWindowProc16(hwnd, message, wParam, lParam);
1664 MDI_MenuModifyItem(clientWnd,hwnd);
1665 if( ci->hwndChildMaximized == hwnd )
1666 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1667 MDI_REPAINTFRAME, NULL );
1668 retvalue = 0;
1669 goto END;
1671 case WM_CLOSE:
1672 SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1673 retvalue = 0;
1674 goto END;
1676 case WM_SETFOCUS:
1677 if( ci->hwndActiveChild != hwnd )
1678 MDI_ChildActivate(clientWnd, hwnd);
1679 break;
1681 case WM_CHILDACTIVATE:
1682 MDI_ChildActivate(clientWnd, hwnd);
1683 retvalue = 0;
1684 goto END;
1686 case WM_NCPAINT:
1687 TRACE("WM_NCPAINT for %04x, active %04x\n",
1688 hwnd, ci->hwndActiveChild );
1689 break;
1691 case WM_SYSCOMMAND:
1692 switch( wParam )
1694 case SC_MOVE:
1695 if( ci->hwndChildMaximized == hwnd)
1697 retvalue = 0;
1698 goto END;
1700 break;
1701 case SC_RESTORE:
1702 case SC_MINIMIZE:
1703 tmpWnd = WIN_FindWndPtr(hwnd);
1704 tmpWnd->dwStyle |= WS_SYSMENU;
1705 WIN_ReleaseWndPtr(tmpWnd);
1706 break;
1707 case SC_MAXIMIZE:
1708 if( ci->hwndChildMaximized == hwnd)
1710 retvalue = SendMessage16( clientWnd->parent->hwndSelf,
1711 message, wParam, lParam);
1712 goto END;
1714 tmpWnd = WIN_FindWndPtr(hwnd);
1715 tmpWnd->dwStyle &= ~WS_SYSMENU;
1716 WIN_ReleaseWndPtr(tmpWnd);
1717 break;
1718 case SC_NEXTWINDOW:
1719 SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1720 retvalue = 0;
1721 goto END;
1722 case SC_PREVWINDOW:
1723 SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1724 retvalue = 0;
1725 goto END;
1727 break;
1729 case WM_GETMINMAXINFO:
1730 MDI_ChildGetMinMaxInfo(clientWnd, hwnd, (MINMAXINFO16*) PTR_SEG_TO_LIN(lParam));
1731 retvalue = 0;
1732 goto END;
1734 case WM_SETVISIBLE:
1735 if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1736 else
1737 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1738 break;
1740 case WM_SIZE:
1741 /* do not change */
1743 if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1745 ci->hwndChildMaximized = 0;
1747 MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1748 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1749 MDI_REPAINTFRAME, NULL );
1752 if( wParam == SIZE_MAXIMIZED )
1754 HWND16 hMaxChild = ci->hwndChildMaximized;
1756 if( hMaxChild == hwnd ) break;
1758 if( hMaxChild)
1760 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1762 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1763 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1765 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1768 TRACE("maximizing child %04x\n", hwnd );
1771 * Keep track of the maximized window.
1773 ci->hwndChildMaximized = hwnd; /* !!! */
1776 * The maximized window should also be the active window
1778 MDI_ChildActivate(clientWnd, hwnd);
1780 MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1781 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1782 MDI_REPAINTFRAME, NULL );
1785 if( wParam == SIZE_MINIMIZED )
1787 HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1789 if( switchTo )
1790 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1793 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1794 break;
1796 case WM_MENUCHAR:
1798 /* MDI children don't have menu bars */
1799 retvalue = 0x00010000L;
1800 goto END;
1802 case WM_NEXTMENU:
1804 if( wParam == VK_LEFT ) /* switch to frame system menu */
1806 retvalue = MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1807 clientWnd->parent->hwndSelf );
1808 goto END;
1810 if( wParam == VK_RIGHT ) /* to frame menu bar */
1812 retvalue = MAKELONG( clientWnd->parent->wIDmenu,
1813 clientWnd->parent->hwndSelf );
1814 goto END;
1817 break;
1819 case WM_SYSCHAR:
1820 if (wParam == '-')
1822 SendMessage16(hwnd,WM_SYSCOMMAND,
1823 (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1824 retvalue = 0;
1825 goto END;
1829 retvalue = DefWindowProc16(hwnd, message, wParam, lParam);
1830 END:
1831 WIN_ReleaseWndPtr(clientWnd);
1832 return retvalue;
1836 /***********************************************************************
1837 * DefMDIChildProcA (USER32.124)
1839 LRESULT WINAPI DefMDIChildProcA( HWND hwnd, UINT message,
1840 WPARAM wParam, LPARAM lParam )
1842 MDICLIENTINFO *ci;
1843 WND *clientWnd,*tmpWnd;
1844 LRESULT retvalue;
1846 tmpWnd = WIN_FindWndPtr(hwnd);
1847 if (!tmpWnd) return 0;
1848 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1849 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1850 WIN_ReleaseWndPtr(tmpWnd);
1852 switch (message)
1854 case WM_SETTEXT:
1855 DefWindowProcA(hwnd, message, wParam, lParam);
1856 MDI_MenuModifyItem(clientWnd,hwnd);
1857 if( ci->hwndChildMaximized == hwnd )
1858 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1859 MDI_REPAINTFRAME, NULL );
1860 retvalue = 0;
1861 goto END;
1863 case WM_GETMINMAXINFO:
1865 MINMAXINFO16 mmi;
1866 STRUCT32_MINMAXINFO32to16( (MINMAXINFO *)lParam, &mmi );
1867 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1868 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO *)lParam );
1870 retvalue = 0;
1871 goto END;
1873 case WM_MENUCHAR:
1875 /* MDI children don't have menu bars */
1876 retvalue = 0x00010000L;
1877 goto END;
1879 case WM_CLOSE:
1880 case WM_SETFOCUS:
1881 case WM_CHILDACTIVATE:
1882 case WM_NCPAINT:
1883 case WM_SYSCOMMAND:
1884 case WM_SETVISIBLE:
1885 case WM_SIZE:
1886 case WM_NEXTMENU:
1887 retvalue = DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1888 goto END;
1890 case WM_SYSCHAR:
1891 if (wParam == '-')
1893 SendMessageA(hwnd,WM_SYSCOMMAND,
1894 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1895 retvalue = 0;
1896 goto END;
1899 retvalue = DefWindowProcA(hwnd, message, wParam, lParam);
1900 END:
1901 WIN_ReleaseWndPtr(clientWnd);
1902 return retvalue;
1906 /***********************************************************************
1907 * DefMDIChildProcW (USER32.125)
1909 LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message,
1910 WPARAM wParam, LPARAM lParam )
1912 MDICLIENTINFO *ci;
1913 WND *clientWnd,*tmpWnd;
1914 LRESULT retvalue;
1916 tmpWnd = WIN_FindWndPtr(hwnd);
1917 if (!tmpWnd) return 0;
1918 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1919 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1920 WIN_ReleaseWndPtr(tmpWnd);
1922 switch (message)
1924 case WM_SETTEXT:
1925 DefWindowProcW(hwnd, message, wParam, lParam);
1926 MDI_MenuModifyItem(clientWnd,hwnd);
1927 if( ci->hwndChildMaximized == hwnd )
1928 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1929 MDI_REPAINTFRAME, NULL );
1930 retvalue = 0;
1931 goto END;
1933 case WM_GETMINMAXINFO:
1934 case WM_MENUCHAR:
1935 case WM_CLOSE:
1936 case WM_SETFOCUS:
1937 case WM_CHILDACTIVATE:
1938 case WM_NCPAINT:
1939 case WM_SYSCOMMAND:
1940 case WM_SETVISIBLE:
1941 case WM_SIZE:
1942 case WM_NEXTMENU:
1943 retvalue = DefMDIChildProcA( hwnd, message, (WPARAM16)wParam, lParam );
1944 goto END;
1946 case WM_SYSCHAR:
1947 if (wParam == '-')
1949 SendMessageW(hwnd,WM_SYSCOMMAND,
1950 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1951 retvalue = 0;
1952 goto END;
1955 retvalue = DefWindowProcW(hwnd, message, wParam, lParam);
1956 END:
1957 WIN_ReleaseWndPtr(clientWnd);
1958 return retvalue;
1963 /**********************************************************************
1964 * CreateMDIWindowA [USER32.79] Creates a MDI child in new thread
1965 * FIXME: its in the same thread now
1967 * RETURNS
1968 * Success: Handle to created window
1969 * Failure: NULL
1971 HWND WINAPI CreateMDIWindowA(
1972 LPCSTR lpClassName, /* [in] Pointer to registered child class name */
1973 LPCSTR lpWindowName, /* [in] Pointer to window name */
1974 DWORD dwStyle, /* [in] Window style */
1975 INT X, /* [in] Horizontal position of window */
1976 INT Y, /* [in] Vertical position of window */
1977 INT nWidth, /* [in] Width of window */
1978 INT nHeight, /* [in] Height of window */
1979 HWND hWndParent, /* [in] Handle to parent window */
1980 HINSTANCE hInstance, /* [in] Handle to application instance */
1981 LPARAM lParam) /* [in] Application-defined value */
1983 WARN("is only single threaded!\n");
1984 return MDI_CreateMDIWindowA(lpClassName, lpWindowName, dwStyle, X, Y,
1985 nWidth, nHeight, hWndParent, hInstance, lParam);
1988 /**********************************************************************
1989 * MDI_CreateMDIWindowA
1990 * single threaded version of CreateMDIWindowA
1991 * called by CreateWindowExA
1993 HWND MDI_CreateMDIWindowA(
1994 LPCSTR lpClassName,
1995 LPCSTR lpWindowName,
1996 DWORD dwStyle,
1997 INT X,
1998 INT Y,
1999 INT nWidth,
2000 INT nHeight,
2001 HWND hWndParent,
2002 HINSTANCE hInstance,
2003 LPARAM lParam)
2005 MDICLIENTINFO* pCi;
2006 MDICREATESTRUCTA cs;
2007 WND *pWnd=WIN_FindWndPtr(hWndParent);
2008 HWND retvalue;
2010 TRACE("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
2011 debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
2012 nWidth,nHeight,hWndParent,hInstance,lParam);
2014 if(!pWnd){
2015 ERR(" bad hwnd for MDI-client: %d\n",hWndParent);
2016 return 0;
2018 cs.szClass=lpClassName;
2019 cs.szTitle=lpWindowName;
2020 cs.hOwner=hInstance;
2021 cs.x=X;
2022 cs.y=Y;
2023 cs.cx=nWidth;
2024 cs.cy=nHeight;
2025 cs.style=dwStyle;
2026 cs.lParam=lParam;
2028 pCi=(MDICLIENTINFO *)pWnd->wExtra;
2030 retvalue = MDICreateChild(pWnd,pCi,hWndParent,&cs);
2031 WIN_ReleaseWndPtr(pWnd);
2032 return retvalue;
2035 /***********************************************************************
2036 * CreateMDIWindowW [USER32.80] Creates a MDI child in new thread
2038 * RETURNS
2039 * Success: Handle to created window
2040 * Failure: NULL
2042 HWND WINAPI CreateMDIWindowW(
2043 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
2044 LPCWSTR lpWindowName, /* [in] Pointer to window name */
2045 DWORD dwStyle, /* [in] Window style */
2046 INT X, /* [in] Horizontal position of window */
2047 INT Y, /* [in] Vertical position of window */
2048 INT nWidth, /* [in] Width of window */
2049 INT nHeight, /* [in] Height of window */
2050 HWND hWndParent, /* [in] Handle to parent window */
2051 HINSTANCE hInstance, /* [in] Handle to application instance */
2052 LPARAM lParam) /* [in] Application-defined value */
2054 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
2055 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
2056 nWidth,nHeight,hWndParent,hInstance,lParam);
2057 return (HWND)NULL;
2061 /******************************************************************************
2062 * CreateMDIWindowW [USER32.80] Creates a MDI child window
2063 * single threaded version of CreateMDIWindow
2064 * called by CreateWindowExW().
2066 HWND MDI_CreateMDIWindowW(
2067 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
2068 LPCWSTR lpWindowName, /* [in] Pointer to window name */
2069 DWORD dwStyle, /* [in] Window style */
2070 INT X, /* [in] Horizontal position of window */
2071 INT Y, /* [in] Vertical position of window */
2072 INT nWidth, /* [in] Width of window */
2073 INT nHeight, /* [in] Height of window */
2074 HWND hWndParent, /* [in] Handle to parent window */
2075 HINSTANCE hInstance, /* [in] Handle to application instance */
2076 LPARAM lParam) /* [in] Application-defined value */
2078 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
2079 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
2080 nWidth,nHeight,hWndParent,hInstance,lParam);
2081 return (HWND)NULL;
2085 /**********************************************************************
2086 * TranslateMDISysAccel (USER32.555)
2088 BOOL WINAPI TranslateMDISysAccel( HWND hwndClient, LPMSG msg )
2090 MSG16 msg16;
2092 STRUCT32_MSG32to16(msg,&msg16);
2093 /* MDICLIENTINFO is still the same for win32 and win16 ... */
2094 return TranslateMDISysAccel16(hwndClient,&msg16);
2098 /**********************************************************************
2099 * TranslateMDISysAccel16 (USER.451)
2101 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
2104 if( IsWindow(hwndClient) && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
2106 MDICLIENTINFO *ci = NULL;
2107 HWND wnd;
2108 WND *clientWnd = WIN_FindWndPtr(hwndClient);
2110 ci = (MDICLIENTINFO*) clientWnd->wExtra;
2111 wnd = ci->hwndActiveChild;
2113 WIN_ReleaseWndPtr(clientWnd);
2115 if( IsWindow(wnd) && !(GetWindowLongA(wnd,GWL_STYLE) & WS_DISABLED) )
2117 WPARAM16 wParam = 0;
2119 /* translate if the Ctrl key is down and Alt not. */
2121 if( (GetKeyState(VK_CONTROL) & 0x8000) &&
2122 !(GetKeyState(VK_MENU) & 0x8000))
2124 switch( msg->wParam )
2126 case VK_F6:
2127 case VK_TAB:
2128 wParam = ( GetKeyState(VK_SHIFT) & 0x8000 )
2129 ? SC_NEXTWINDOW : SC_PREVWINDOW;
2130 break;
2131 case VK_F4:
2132 case VK_RBUTTON:
2133 wParam = SC_CLOSE;
2134 break;
2135 default:
2136 return 0;
2138 TRACE("wParam = %04x\n", wParam);
2139 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
2140 wParam, (LPARAM)msg->wParam);
2141 return 1;
2145 return 0; /* failure */
2149 /***********************************************************************
2150 * CalcChildScroll (USER.462)
2152 void WINAPI CalcChildScroll16( HWND16 hwnd, WORD scroll )
2154 SCROLLINFO info;
2155 RECT childRect, clientRect;
2156 INT vmin, vmax, hmin, hmax, vpos, hpos;
2157 WND *pWnd, *Wnd;
2159 if (!(pWnd = WIN_FindWndPtr( hwnd ))) return;
2160 Wnd = WIN_FindWndPtr(hwnd);
2161 GetClientRect( hwnd, &clientRect );
2162 SetRectEmpty( &childRect );
2164 for ( WIN_UpdateWndPtr(&pWnd,pWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2166 if( pWnd->dwStyle & WS_MAXIMIZE )
2168 ShowScrollBar(hwnd, SB_BOTH, FALSE);
2169 WIN_ReleaseWndPtr(pWnd);
2170 WIN_ReleaseWndPtr(Wnd);
2171 return;
2173 UnionRect( &childRect, &pWnd->rectWindow, &childRect );
2175 WIN_ReleaseWndPtr(pWnd);
2176 UnionRect( &childRect, &clientRect, &childRect );
2178 hmin = childRect.left; hmax = childRect.right - clientRect.right;
2179 hpos = clientRect.left - childRect.left;
2180 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
2181 vpos = clientRect.top - childRect.top;
2183 switch( scroll )
2185 case SB_HORZ:
2186 vpos = hpos; vmin = hmin; vmax = hmax;
2187 case SB_VERT:
2188 info.cbSize = sizeof(info);
2189 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
2190 info.fMask = SIF_POS | SIF_RANGE;
2191 SetScrollInfo(hwnd, scroll, &info, TRUE);
2192 break;
2193 case SB_BOTH:
2194 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
2195 hmin, hmax, hpos);
2197 WIN_ReleaseWndPtr(Wnd);
2201 /***********************************************************************
2202 * ScrollChildren16 (USER.463)
2204 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
2206 ScrollChildren( hWnd, uMsg, wParam, lParam );
2210 /***********************************************************************
2211 * ScrollChildren (USER32.448)
2213 void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
2214 LPARAM lParam)
2216 WND *wndPtr = WIN_FindWndPtr(hWnd);
2217 INT newPos = -1;
2218 INT curPos, length, minPos, maxPos, shift;
2220 if( !wndPtr ) return;
2222 if( uMsg == WM_HSCROLL )
2224 GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
2225 curPos = GetScrollPos(hWnd,SB_HORZ);
2226 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
2227 shift = GetSystemMetrics(SM_CYHSCROLL);
2229 else if( uMsg == WM_VSCROLL )
2231 GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
2232 curPos = GetScrollPos(hWnd,SB_VERT);
2233 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
2234 shift = GetSystemMetrics(SM_CXVSCROLL);
2236 else
2238 WIN_ReleaseWndPtr(wndPtr);
2239 return;
2242 WIN_ReleaseWndPtr(wndPtr);
2243 switch( wParam )
2245 case SB_LINEUP:
2246 newPos = curPos - shift;
2247 break;
2248 case SB_LINEDOWN:
2249 newPos = curPos + shift;
2250 break;
2251 case SB_PAGEUP:
2252 newPos = curPos - length;
2253 break;
2254 case SB_PAGEDOWN:
2255 newPos = curPos + length;
2256 break;
2258 case SB_THUMBPOSITION:
2259 newPos = LOWORD(lParam);
2260 break;
2262 case SB_THUMBTRACK:
2263 return;
2265 case SB_TOP:
2266 newPos = minPos;
2267 break;
2268 case SB_BOTTOM:
2269 newPos = maxPos;
2270 break;
2271 case SB_ENDSCROLL:
2272 CalcChildScroll16(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
2273 return;
2276 if( newPos > maxPos )
2277 newPos = maxPos;
2278 else
2279 if( newPos < minPos )
2280 newPos = minPos;
2282 SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
2284 if( uMsg == WM_VSCROLL )
2285 ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
2286 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2287 else
2288 ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
2289 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2293 /******************************************************************************
2294 * CascadeWindows [USER32.21] Cascades MDI child windows
2296 * RETURNS
2297 * Success: Number of cascaded windows.
2298 * Failure: 0
2300 WORD WINAPI
2301 CascadeWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2302 UINT cKids, const HWND *lpKids)
2304 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2305 hwndParent, wFlags, cKids);
2307 return 0;
2311 /******************************************************************************
2312 * TileWindows [USER32.545] Tiles MDI child windows
2314 * RETURNS
2315 * Success: Number of tiled windows.
2316 * Failure: 0
2318 WORD WINAPI
2319 TileWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2320 UINT cKids, const HWND *lpKids)
2322 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2323 hwndParent, wFlags, cKids);
2325 return 0;
2328 /************************************************************************
2329 * "More Windows..." functionality
2332 /* MDI_MoreWindowsDlgProc
2334 * This function will process the messages sent to the "More Windows..."
2335 * dialog.
2336 * Return values: 0 = cancel pressed
2337 * HWND = ok pressed or double-click in the list...
2341 static BOOL WINAPI MDI_MoreWindowsDlgProc (HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
2343 switch (iMsg)
2345 case WM_INITDIALOG:
2347 WND *pWnd;
2348 UINT widest = 0;
2349 UINT length;
2350 UINT i;
2351 WND *pParentWnd = (WND *)lParam;
2352 MDICLIENTINFO *ci = (MDICLIENTINFO*)pParentWnd->wExtra;
2353 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2355 /* Fill the list, sorted by id... */
2356 for (i = 0; i < ci->nActiveChildren; i++)
2359 /* Find the window with the current ID */
2360 for (pWnd = WIN_LockWndPtr(pParentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd, pWnd->next))
2361 if (pWnd->wIDmenu == ci->idFirstChild + i)
2362 break;
2364 SendMessageW(hListBox, LB_ADDSTRING, 0, (LPARAM) pWnd->text);
2365 SendMessageA(hListBox, LB_SETITEMDATA, i, (LPARAM) pWnd);
2366 length = strlenW(pWnd->text);
2367 WIN_ReleaseWndPtr(pWnd);
2369 if (length > widest)
2370 widest = length;
2372 /* Make sure the horizontal scrollbar scrolls ok */
2373 SendMessageA(hListBox, LB_SETHORIZONTALEXTENT, widest * 6, 0);
2375 /* Set the current selection */
2376 SendMessageA(hListBox, LB_SETCURSEL, MDI_MOREWINDOWSLIMIT, 0);
2377 return TRUE;
2380 case WM_COMMAND:
2381 switch (LOWORD(wParam))
2383 case IDOK:
2385 /* windows are sorted by menu ID, so we must return the
2386 * window associated to the given id
2388 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2389 UINT index = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
2390 WND* pWnd = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
2392 EndDialog(hDlg, pWnd->hwndSelf);
2393 return TRUE;
2395 case IDCANCEL:
2396 EndDialog(hDlg, 0);
2397 return TRUE;
2399 default:
2400 switch (HIWORD(wParam))
2402 case LBN_DBLCLK:
2404 /* windows are sorted by menu ID, so we must return the
2405 * window associated to the given id
2407 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2408 UINT index = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
2409 WND* pWnd = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
2411 EndDialog(hDlg, pWnd->hwndSelf);
2412 return TRUE;
2415 break;
2417 break;
2419 return FALSE;
2424 * MDI_MoreWindowsDialog
2426 * Prompts the user with a listbox containing the opened
2427 * documents. The user can then choose a windows and click
2428 * on OK to set the current window to the one selected, or
2429 * CANCEL to cancel. The function returns a handle to the
2430 * selected window.
2433 static HWND MDI_MoreWindowsDialog(WND* wndPtr)
2435 LPCVOID template;
2436 HRSRC hRes;
2437 HANDLE hDlgTmpl;
2439 hRes = FindResourceA(GetModuleHandleA("USER32"), "MDI_MOREWINDOWS", RT_DIALOGA);
2441 if (hRes == 0)
2442 return 0;
2444 hDlgTmpl = LoadResource(GetModuleHandleA("USER32"), hRes );
2446 if (hDlgTmpl == 0)
2447 return 0;
2449 template = LockResource( hDlgTmpl );
2451 if (template == 0)
2452 return 0;
2454 return (HWND) DialogBoxIndirectParamA(GetModuleHandleA("USER32"),
2455 (LPDLGTEMPLATEA) template,
2456 wndPtr->hwndSelf,
2457 (DLGPROC) MDI_MoreWindowsDlgProc,
2458 (LPARAM) wndPtr);
2463 * MDI_SwapMenuItems
2465 * Will swap the menu IDs for the given 2 positions.
2466 * pos1 and pos2 are menu IDs
2471 static void MDI_SwapMenuItems(WND *parentWnd, UINT pos1, UINT pos2)
2473 WND *pWnd;
2475 for (pWnd = WIN_LockWndPtr(parentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2477 if (pWnd->wIDmenu == pos1)
2478 pWnd->wIDmenu = pos2;
2479 else
2480 if (pWnd->wIDmenu == pos2)
2481 pWnd->wIDmenu = pos1;
2484 WIN_ReleaseWndPtr(pWnd);