Get full path of argv[0] before we change directories.
[wine.git] / windows / mdi.c
blobed196497d20e544f7243b6084cbbba262df2ced2
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 "win.h"
77 #include "heap.h"
78 #include "nonclient.h"
79 #include "mdi.h"
80 #include "user.h"
81 #include "menu.h"
82 #include "scroll.h"
83 #include "struct32.h"
84 #include "tweak.h"
85 #include "debugtools.h"
86 #include "dlgs.h"
88 DEFAULT_DEBUG_CHANNEL(mdi);
90 #define MDIF_NEEDUPDATE 0x0001
92 static HBITMAP16 hBmpClose = 0;
93 static HBITMAP16 hBmpRestore = 0;
95 /* ----------------- declarations ----------------- */
96 static void MDI_UpdateFrameText(WND *, HWND, BOOL, LPCWSTR);
97 static BOOL MDI_AugmentFrameMenu(MDICLIENTINFO*, WND *, HWND);
98 static BOOL MDI_RestoreFrameMenu(WND *, HWND);
100 static LONG MDI_ChildActivate( WND*, HWND );
102 static HWND MDI_MoreWindowsDialog(WND*);
103 static void MDI_SwapMenuItems(WND *, UINT, UINT);
104 /* -------- Miscellaneous service functions ----------
106 * MDI_GetChildByID
109 static HWND MDI_GetChildByID(WND* wndPtr, INT id)
111 for (wndPtr = wndPtr->child; wndPtr; wndPtr = wndPtr->next)
112 if (wndPtr->wIDmenu == id) return wndPtr->hwndSelf;
113 return 0;
116 static void MDI_PostUpdate(HWND hwnd, MDICLIENTINFO* ci, WORD recalc)
118 if( !(ci->mdiFlags & MDIF_NEEDUPDATE) )
120 ci->mdiFlags |= MDIF_NEEDUPDATE;
121 PostMessageA( hwnd, WM_MDICALCCHILDSCROLL, 0, 0);
123 ci->sbRecalc = recalc;
126 /**********************************************************************
127 * MDI_MenuModifyItem
129 static BOOL MDI_MenuModifyItem(WND* clientWnd, HWND hWndChild )
131 WCHAR buffer[128];
132 static const WCHAR format[] = {'%','d',' ',0};
133 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
134 WND *wndPtr = WIN_FindWndPtr(hWndChild);
135 UINT n = wsprintfW(buffer, format,
136 wndPtr->wIDmenu - clientInfo->idFirstChild + 1);
137 BOOL bRet = 0;
139 if( !clientInfo->hWindowMenu )
141 bRet = FALSE;
142 goto END;
145 if (wndPtr->text) lstrcpynW(buffer + n, wndPtr->text, sizeof(buffer)/sizeof(WCHAR) - n );
147 n = GetMenuState(clientInfo->hWindowMenu,wndPtr->wIDmenu ,MF_BYCOMMAND);
148 bRet = ModifyMenuW(clientInfo->hWindowMenu , wndPtr->wIDmenu,
149 MF_BYCOMMAND | MF_STRING, wndPtr->wIDmenu, buffer );
150 CheckMenuItem(clientInfo->hWindowMenu ,wndPtr->wIDmenu , n & MF_CHECKED);
151 END:
152 WIN_ReleaseWndPtr(wndPtr);
153 return bRet;
156 /**********************************************************************
157 * MDI_MenuDeleteItem
159 static BOOL MDI_MenuDeleteItem(WND* clientWnd, HWND hWndChild )
161 WCHAR buffer[128];
162 static const WCHAR format[] = {'&','%','d',' ',0};
163 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
164 WND *wndPtr = WIN_FindWndPtr(hWndChild);
165 UINT index = 0,id,n;
166 BOOL retvalue;
168 if( !clientInfo->nActiveChildren ||
169 !clientInfo->hWindowMenu )
171 retvalue = FALSE;
172 goto END;
175 id = wndPtr->wIDmenu;
176 DeleteMenu(clientInfo->hWindowMenu,id,MF_BYCOMMAND);
178 /* walk the rest of MDI children to prevent gaps in the id
179 * sequence and in the menu child list */
181 for( index = id+1; index <= clientInfo->nActiveChildren +
182 clientInfo->idFirstChild; index++ )
184 WND *tmpWnd = WIN_FindWndPtr(MDI_GetChildByID(clientWnd,index));
185 if( !tmpWnd )
187 TRACE("no window for id=%i\n",index);
188 WIN_ReleaseWndPtr(tmpWnd);
189 continue;
192 /* set correct id */
193 tmpWnd->wIDmenu--;
195 n = wsprintfW(buffer, format ,index - clientInfo->idFirstChild);
196 if (tmpWnd->text)
197 lstrcpynW(buffer + n, tmpWnd->text, sizeof(buffer)/sizeof(WCHAR) - n );
199 /* change menu if the current child is to be shown in the
200 * "Windows" menu
202 if (index <= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
203 ModifyMenuW(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING,
204 index - 1 , buffer );
205 WIN_ReleaseWndPtr(tmpWnd);
208 /* We must restore the "More Windows..." option if there is enough child
210 if (clientInfo->nActiveChildren - 1 > MDI_MOREWINDOWSLIMIT)
212 char szTmp[50];
213 LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
215 AppendMenuA(clientInfo->hWindowMenu ,MF_STRING ,clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT, szTmp );
217 retvalue = TRUE;
218 END:
219 WIN_ReleaseWndPtr(wndPtr);
220 return retvalue;
223 /**********************************************************************
224 * MDI_GetWindow
226 * returns "activateable" child different from the current or zero
228 static HWND MDI_GetWindow(WND *clientWnd, HWND hWnd, BOOL bNext,
229 DWORD dwStyleMask )
231 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
232 WND *wndPtr, *pWnd, *pWndLast = NULL;
234 dwStyleMask |= WS_DISABLED | WS_VISIBLE;
235 if( !hWnd ) hWnd = clientInfo->hwndActiveChild;
237 if( !(wndPtr = WIN_FindWndPtr(hWnd)) ) return 0;
239 for ( pWnd = WIN_LockWndPtr(wndPtr->next); ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
241 if (!pWnd ) WIN_UpdateWndPtr(&pWnd,wndPtr->parent->child);
243 if ( pWnd == wndPtr ) break; /* went full circle */
245 if (!pWnd->owner && (pWnd->dwStyle & dwStyleMask) == WS_VISIBLE )
247 pWndLast = pWnd;
248 if ( bNext ) break;
251 WIN_ReleaseWndPtr(wndPtr);
252 WIN_ReleaseWndPtr(pWnd);
253 return pWndLast ? pWndLast->hwndSelf : 0;
256 /**********************************************************************
257 * MDI_CalcDefaultChildPos
259 * It seems that the default height is about 2/3 of the client rect
261 static void MDI_CalcDefaultChildPos( WND* w, WORD n, LPPOINT lpPos,
262 INT delta)
264 INT nstagger;
265 RECT rect = w->rectClient;
266 INT spacing = GetSystemMetrics(SM_CYCAPTION) +
267 GetSystemMetrics(SM_CYFRAME) - 1;
269 if( rect.bottom - rect.top - delta >= spacing )
270 rect.bottom -= delta;
272 nstagger = (rect.bottom - rect.top)/(3 * spacing);
273 lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
274 lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
275 lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
278 /**********************************************************************
279 * MDISetMenu
281 static LRESULT MDISetMenu( HWND hwnd, HMENU hmenuFrame,
282 HMENU hmenuWindow)
284 WND *w;
285 MDICLIENTINFO *ci;
286 HWND hwndFrame = GetParent(hwnd);
287 HMENU oldFrameMenu = GetMenu(hwndFrame);
289 TRACE("%04x %04x %04x\n",
290 hwnd, hmenuFrame, hmenuWindow);
292 if (hmenuFrame && !IsMenu(hmenuFrame))
294 WARN("hmenuFrame is not a menu handle\n");
295 return 0L;
298 if (hmenuWindow && !IsMenu(hmenuWindow))
300 WARN("hmenuWindow is not a menu handle\n");
301 return 0L;
304 w = WIN_FindWndPtr(hwnd);
305 ci = (MDICLIENTINFO *) w->wExtra;
307 if( ci->hwndChildMaximized && hmenuFrame && hmenuFrame!=oldFrameMenu )
308 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized );
310 if( hmenuWindow && ci->hWindowMenu && hmenuWindow!=ci->hWindowMenu )
312 /* delete menu items from ci->hWindowMenu
313 * and add them to hmenuWindow */
315 INT i = GetMenuItemCount(ci->hWindowMenu) - 1;
316 INT pos = GetMenuItemCount(hmenuWindow) + 1;
318 AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL);
320 if( ci->nActiveChildren )
322 INT j;
323 LPWSTR buffer = NULL;
324 MENUITEMINFOW mii;
325 INT nbWindowsMenuItems; /* num of documents shown + "More Windows..." if present */
327 if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
328 nbWindowsMenuItems = ci->nActiveChildren;
329 else
330 nbWindowsMenuItems = MDI_MOREWINDOWSLIMIT + 1;
332 j = i - nbWindowsMenuItems + 1;
334 for( ; i >= j ; i-- )
336 memset(&mii, 0, sizeof(mii));
337 mii.cbSize = sizeof(mii);
338 mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE
339 | MIIM_SUBMENU | MIIM_TYPE | MIIM_BITMAP;
341 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
342 if(mii.cch) { /* Menu is MFT_STRING */
343 mii.cch++; /* add room for '\0' */
344 buffer = HeapAlloc(GetProcessHeap(), 0,
345 mii.cch * sizeof(WCHAR));
346 mii.dwTypeData = buffer;
347 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
349 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
350 InsertMenuItemW(hmenuWindow, pos, TRUE, &mii);
351 if(buffer) {
352 HeapFree(GetProcessHeap(), 0, buffer);
353 buffer = NULL;
358 /* remove separator */
359 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
361 ci->hWindowMenu = hmenuWindow;
364 if (hmenuFrame)
366 SetMenu(hwndFrame, hmenuFrame);
367 if( hmenuFrame!=oldFrameMenu )
369 if( ci->hwndChildMaximized )
370 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
371 WIN_ReleaseWndPtr(w);
372 return oldFrameMenu;
375 WIN_ReleaseWndPtr(w);
376 return 0;
379 /**********************************************************************
380 * MDIRefreshMenu
382 static LRESULT MDIRefreshMenu( HWND hwnd, HMENU hmenuFrame,
383 HMENU hmenuWindow)
385 HWND hwndFrame = GetParent(hwnd);
386 HMENU oldFrameMenu = GetMenu(hwndFrame);
388 TRACE("%04x %04x %04x\n",
389 hwnd, hmenuFrame, hmenuWindow);
391 FIXME("partially function stub\n");
393 return oldFrameMenu;
397 /* ------------------ MDI child window functions ---------------------- */
400 /**********************************************************************
401 * MDICreateChild
403 static HWND MDICreateChild( WND *w, MDICLIENTINFO *ci, HWND parent,
404 LPMDICREATESTRUCTA cs )
406 POINT pos[2];
407 DWORD style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
408 HWND hwnd, hwndMax = 0;
409 WORD wIDmenu = ci->idFirstChild + ci->nActiveChildren;
410 char lpstrDef[]="junk!";
412 TRACE("origin %i,%i - dim %i,%i, style %08x\n",
413 cs->x, cs->y, cs->cx, cs->cy, (unsigned)cs->style);
414 /* calculate placement */
415 MDI_CalcDefaultChildPos(w, ci->nTotalCreated++, pos, 0);
417 if (cs->cx == CW_USEDEFAULT || !cs->cx) cs->cx = pos[1].x;
418 if (cs->cy == CW_USEDEFAULT || !cs->cy) cs->cy = pos[1].y;
420 if( cs->x == CW_USEDEFAULT )
422 cs->x = pos[0].x;
423 cs->y = pos[0].y;
426 /* restore current maximized child */
427 if( style & WS_VISIBLE && ci->hwndChildMaximized )
429 if( style & WS_MAXIMIZE )
430 SendMessageA(w->hwndSelf, WM_SETREDRAW, FALSE, 0L );
431 hwndMax = ci->hwndChildMaximized;
432 ShowWindow( hwndMax, SW_SHOWNOACTIVATE );
433 if( style & WS_MAXIMIZE )
434 SendMessageA(w->hwndSelf, WM_SETREDRAW, TRUE, 0L );
437 if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
438 /* this menu is needed to set a check mark in MDI_ChildActivate */
439 if (ci->hWindowMenu != 0)
440 AppendMenuA(ci->hWindowMenu ,MF_STRING ,wIDmenu, lpstrDef );
442 ci->nActiveChildren++;
444 /* fix window style */
445 if( !(w->dwStyle & MDIS_ALLCHILDSTYLES) )
447 style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE |
448 WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL );
449 style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW);
452 if( w->flags & WIN_ISWIN32 )
454 hwnd = CreateWindowA( cs->szClass, cs->szTitle, style,
455 cs->x, cs->y, cs->cx, cs->cy, parent,
456 (HMENU16)wIDmenu, cs->hOwner, cs );
458 else
460 MDICREATESTRUCT16 *cs16;
461 LPSTR title, cls;
463 cs16 = SEGPTR_NEW(MDICREATESTRUCT16);
464 STRUCT32_MDICREATESTRUCT32Ato16( cs, cs16 );
465 title = SEGPTR_STRDUP( cs->szTitle );
466 cls = SEGPTR_STRDUP( cs->szClass );
467 cs16->szTitle = SEGPTR_GET(title);
468 cs16->szClass = SEGPTR_GET(cls);
470 hwnd = CreateWindow16( cs->szClass, cs->szTitle, style,
471 cs16->x, cs16->y, cs16->cx, cs16->cy, parent,
472 (HMENU)wIDmenu, cs16->hOwner,
473 (LPVOID)SEGPTR_GET(cs16) );
474 SEGPTR_FREE( title );
475 SEGPTR_FREE( cls );
476 SEGPTR_FREE( cs16 );
479 /* MDI windows are WS_CHILD so they won't be activated by CreateWindow */
481 if (hwnd)
483 WND* wnd = WIN_FindWndPtr( hwnd );
485 /* All MDI child windows have the WS_EX_MDICHILD style */
486 wnd->dwExStyle |= WS_EX_MDICHILD;
488 /* If we have more than 9 windows, we must insert the new one at the
489 * 9th position in order to see it in the "Windows" menu
491 if (ci->nActiveChildren > MDI_MOREWINDOWSLIMIT)
492 MDI_SwapMenuItems(wnd->parent, wnd->wIDmenu, ci->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
494 MDI_MenuModifyItem(w ,hwnd);
496 /* Have we hit the "More Windows..." limit? If so, we must
497 * add a "More Windows..." option
499 if (ci->nActiveChildren == MDI_MOREWINDOWSLIMIT + 1)
501 char szTmp[50];
502 LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
504 ModifyMenuA(ci->hWindowMenu,
505 ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
506 MF_BYCOMMAND | MF_STRING,
507 ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
508 szTmp);
511 if( wnd->dwStyle & WS_MINIMIZE && ci->hwndActiveChild )
512 ShowWindow( hwnd, SW_SHOWMINNOACTIVE );
513 else
515 /* WS_VISIBLE is clear if a) the MDI client has
516 * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the
517 * MDICreateStruct. If so the created window is not shown nor
518 * activated.
520 int showflag=wnd->dwStyle & WS_VISIBLE;
521 /* clear visible flag, otherwise SetWindoPos32 ignores
522 * the SWP_SHOWWINDOW command.
524 wnd->dwStyle &= ~WS_VISIBLE;
525 if(showflag){
526 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE );
528 /* Set maximized state here in case hwnd didn't receive WM_SIZE
529 * during CreateWindow - bad!
532 if((wnd->dwStyle & WS_MAXIMIZE) && !ci->hwndChildMaximized )
534 ci->hwndChildMaximized = wnd->hwndSelf;
535 MDI_AugmentFrameMenu( ci, w->parent, hwnd );
536 MDI_UpdateFrameText( w->parent, ci->self, MDI_REPAINTFRAME, NULL );
538 }else
539 /* needed, harmless ? */
540 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE );
543 WIN_ReleaseWndPtr(wnd);
544 TRACE("created child - %04x\n",hwnd);
546 else
548 ci->nActiveChildren--;
549 DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
550 if( IsWindow(hwndMax) )
551 ShowWindow(hwndMax, SW_SHOWMAXIMIZED);
554 return hwnd;
557 /**********************************************************************
558 * MDI_ChildGetMinMaxInfo
560 * Note: The rule here is that client rect of the maximized MDI child
561 * is equal to the client rect of the MDI client window.
563 static void MDI_ChildGetMinMaxInfo( WND* clientWnd, HWND hwnd,
564 MINMAXINFO16* lpMinMax )
566 WND* childWnd = WIN_FindWndPtr(hwnd);
567 RECT rect = clientWnd->rectClient;
569 MapWindowPoints( clientWnd->parent->hwndSelf,
570 ((MDICLIENTINFO*)clientWnd->wExtra)->self, (LPPOINT)&rect, 2);
571 AdjustWindowRectEx( &rect, childWnd->dwStyle, 0, childWnd->dwExStyle );
573 lpMinMax->ptMaxSize.x = rect.right -= rect.left;
574 lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
576 lpMinMax->ptMaxPosition.x = rect.left;
577 lpMinMax->ptMaxPosition.y = rect.top;
579 WIN_ReleaseWndPtr(childWnd);
581 TRACE("max rect (%i,%i - %i, %i)\n",
582 rect.left,rect.top,rect.right,rect.bottom);
586 /**********************************************************************
587 * MDI_SwitchActiveChild
589 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
590 * being activated
592 static void MDI_SwitchActiveChild( HWND clientHwnd, HWND childHwnd,
593 BOOL bNextWindow )
595 WND *w = WIN_FindWndPtr(clientHwnd);
596 HWND hwndTo = 0;
597 HWND hwndPrev = 0;
598 MDICLIENTINFO *ci;
600 hwndTo = MDI_GetWindow(w, childHwnd, bNextWindow, 0);
602 ci = (MDICLIENTINFO *) w->wExtra;
604 TRACE("from %04x, to %04x\n",childHwnd,hwndTo);
606 if ( !hwndTo ) goto END; /* no window to switch to */
608 hwndPrev = ci->hwndActiveChild;
610 if ( hwndTo != hwndPrev )
612 BOOL bOptimize = 0;
614 if( ci->hwndChildMaximized )
616 bOptimize = 1;
617 w->dwStyle &= ~WS_VISIBLE;
620 SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0,
621 SWP_NOMOVE | SWP_NOSIZE );
623 if( bNextWindow && hwndPrev )
624 SetWindowPos( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0,
625 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
626 if( bOptimize )
627 ShowWindow( clientHwnd, SW_SHOW );
629 END:
630 WIN_ReleaseWndPtr(w);
634 /**********************************************************************
635 * MDIDestroyChild
637 static LRESULT MDIDestroyChild( WND *w_parent, MDICLIENTINFO *ci,
638 HWND parent, HWND child,
639 BOOL flagDestroy )
641 WND *childPtr = WIN_FindWndPtr(child);
643 if( childPtr )
645 MDI_MenuDeleteItem(w_parent, child);
647 if( child == ci->hwndActiveChild )
649 MDI_SwitchActiveChild(parent, child, TRUE);
651 if( child == ci->hwndActiveChild )
653 ShowWindow( child, SW_HIDE);
654 if( child == ci->hwndChildMaximized )
656 MDI_RestoreFrameMenu(w_parent->parent, child);
657 ci->hwndChildMaximized = 0;
658 MDI_UpdateFrameText(w_parent->parent,parent,TRUE,NULL);
661 MDI_ChildActivate(w_parent, 0);
665 WIN_ReleaseWndPtr(childPtr);
667 ci->nActiveChildren--;
669 TRACE("child destroyed - %04x\n",child);
671 if (flagDestroy)
673 MDI_PostUpdate(GetParent(child), ci, SB_BOTH+1);
674 DestroyWindow(child);
678 return 0;
682 /**********************************************************************
683 * MDI_ChildActivate
685 * Note: hWndChild is NULL when last child is being destroyed
687 static LONG MDI_ChildActivate( WND *clientPtr, HWND hWndChild )
689 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientPtr->wExtra;
690 HWND prevActiveWnd = clientInfo->hwndActiveChild;
691 WND *wndPtr = WIN_FindWndPtr( hWndChild );
692 WND *wndPrev = WIN_FindWndPtr( prevActiveWnd );
693 BOOL isActiveFrameWnd = 0;
694 LONG retvalue;
696 if( wndPtr )
698 if( wndPtr->dwStyle & WS_DISABLED )
700 retvalue = 0L;
701 goto END;
705 /* Don't activate if it is already active. Might happen
706 since ShowWindow DOES activate MDI children */
707 if (clientInfo->hwndActiveChild == hWndChild)
709 retvalue = 0L;
710 goto END;
713 TRACE("%04x\n", hWndChild);
715 if( GetActiveWindow() == clientPtr->parent->hwndSelf )
716 isActiveFrameWnd = TRUE;
718 /* deactivate prev. active child */
719 if( wndPrev )
721 wndPrev->dwStyle |= WS_SYSMENU;
722 SendMessageA( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
723 SendMessageA( prevActiveWnd, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
724 (LPARAM)hWndChild);
725 /* uncheck menu item */
726 if( clientInfo->hWindowMenu )
728 WORD wPrevID = wndPrev->wIDmenu - clientInfo->idFirstChild;
730 if (wPrevID < MDI_MOREWINDOWSLIMIT)
731 CheckMenuItem( clientInfo->hWindowMenu,
732 wndPrev->wIDmenu, 0);
733 else
734 CheckMenuItem( clientInfo->hWindowMenu,
735 clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1, 0);
739 /* set appearance */
740 if( clientInfo->hwndChildMaximized )
742 if( clientInfo->hwndChildMaximized != hWndChild ) {
743 if( hWndChild ) {
744 clientInfo->hwndActiveChild = hWndChild;
745 ShowWindow( hWndChild, SW_SHOWMAXIMIZED);
746 } else
747 ShowWindow( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
751 clientInfo->hwndActiveChild = hWndChild;
753 /* check if we have any children left */
754 if( !hWndChild )
756 if( isActiveFrameWnd )
757 SetFocus( clientInfo->self );
758 retvalue = 0;
759 goto END;
762 /* check menu item */
763 if( clientInfo->hWindowMenu )
765 /* The window to be activated must be displayed in the "Windows" menu */
766 if (wndPtr->wIDmenu >= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
768 MDI_SwapMenuItems(wndPtr->parent, wndPtr->wIDmenu, clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
769 MDI_MenuModifyItem(wndPtr->parent ,wndPtr->hwndSelf);
772 CheckMenuItem(clientInfo->hWindowMenu, wndPtr->wIDmenu, MF_CHECKED);
774 /* bring active child to the top */
775 SetWindowPos( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
777 if( isActiveFrameWnd )
779 SendMessageA( hWndChild, WM_NCACTIVATE, TRUE, 0L);
780 if( GetFocus() == clientInfo->self )
781 SendMessageA( clientInfo->self, WM_SETFOCUS,
782 (WPARAM)clientInfo->self, 0L );
783 else
784 SetFocus( clientInfo->self );
786 SendMessageA( hWndChild, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
787 (LPARAM)hWndChild );
788 retvalue = 1;
789 END:
790 WIN_ReleaseWndPtr(wndPtr);
791 WIN_ReleaseWndPtr(wndPrev);
792 return retvalue;
795 /* -------------------- MDI client window functions ------------------- */
797 /**********************************************************************
798 * CreateMDIMenuBitmap
800 static HBITMAP16 CreateMDIMenuBitmap(void)
802 HDC hDCSrc = CreateCompatibleDC(0);
803 HDC hDCDest = CreateCompatibleDC(hDCSrc);
804 HBITMAP16 hbClose = LoadBitmap16(0, MAKEINTRESOURCE16(OBM_CLOSE) );
805 HBITMAP16 hbCopy;
806 HANDLE16 hobjSrc, hobjDest;
808 hobjSrc = SelectObject(hDCSrc, hbClose);
809 hbCopy = CreateCompatibleBitmap(hDCSrc,GetSystemMetrics(SM_CXSIZE),GetSystemMetrics(SM_CYSIZE));
810 hobjDest = SelectObject(hDCDest, hbCopy);
812 BitBlt(hDCDest, 0, 0, GetSystemMetrics(SM_CXSIZE), GetSystemMetrics(SM_CYSIZE),
813 hDCSrc, GetSystemMetrics(SM_CXSIZE), 0, SRCCOPY);
815 SelectObject(hDCSrc, hobjSrc);
816 DeleteObject(hbClose);
817 DeleteDC(hDCSrc);
819 hobjSrc = SelectObject( hDCDest, GetStockObject(BLACK_PEN) );
821 MoveToEx( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, 0, NULL );
822 LineTo( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, GetSystemMetrics(SM_CYSIZE) - 1);
824 SelectObject(hDCDest, hobjSrc );
825 SelectObject(hDCDest, hobjDest);
826 DeleteDC(hDCDest);
828 return hbCopy;
831 /**********************************************************************
832 * MDICascade
834 static LONG MDICascade(WND* clientWnd, MDICLIENTINFO *ci)
836 WND** ppWnd;
837 UINT total;
839 if (ci->hwndChildMaximized)
840 SendMessageA( clientWnd->hwndSelf, WM_MDIRESTORE,
841 (WPARAM)ci->hwndChildMaximized, 0);
843 if (ci->nActiveChildren == 0) return 0;
845 if ((ppWnd = WIN_BuildWinArray(clientWnd, BWA_SKIPHIDDEN | BWA_SKIPOWNED |
846 BWA_SKIPICONIC, &total)))
848 WND** heapPtr = ppWnd;
849 if( total )
851 INT delta = 0, n = 0;
852 POINT pos[2];
853 if( total < ci->nActiveChildren )
854 delta = GetSystemMetrics(SM_CYICONSPACING) +
855 GetSystemMetrics(SM_CYICON);
857 /* walk the list (backwards) and move windows */
858 while (*ppWnd) ppWnd++;
859 while (ppWnd != heapPtr)
861 ppWnd--;
862 TRACE("move %04x to (%ld,%ld) size [%ld,%ld]\n",
863 (*ppWnd)->hwndSelf, pos[0].x, pos[0].y, pos[1].x, pos[1].y);
865 MDI_CalcDefaultChildPos(clientWnd, n++, pos, delta);
866 SetWindowPos( (*ppWnd)->hwndSelf, 0, pos[0].x, pos[0].y,
867 pos[1].x, pos[1].y,
868 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
871 WIN_ReleaseWinArray(heapPtr);
874 if( total < ci->nActiveChildren )
875 ArrangeIconicWindows( clientWnd->hwndSelf );
876 return 0;
879 /**********************************************************************
880 * MDITile
882 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM wParam )
884 WND** ppWnd;
885 UINT total = 0;
887 if (ci->hwndChildMaximized)
888 SendMessageA( wndClient->hwndSelf, WM_MDIRESTORE,
889 (WPARAM)ci->hwndChildMaximized, 0);
891 if (ci->nActiveChildren == 0) return;
893 ppWnd = WIN_BuildWinArray(wndClient, BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
894 ((wParam & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
896 TRACE("%u windows to tile\n", total);
898 if( ppWnd )
900 WND** heapPtr = ppWnd;
902 if( total )
904 RECT rect;
905 int x, y, xsize, ysize;
906 int rows, columns, r, c, i;
908 GetClientRect(wndClient->hwndSelf,&rect);
909 rows = (int) sqrt((double)total);
910 columns = total / rows;
912 if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */
914 i = rows;
915 rows = columns; /* exchange r and c */
916 columns = i;
919 if( total != ci->nActiveChildren)
921 y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
922 rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
925 ysize = rect.bottom / rows;
926 xsize = rect.right / columns;
928 for (x = i = 0, c = 1; c <= columns && *ppWnd; c++)
930 if (c == columns)
932 rows = total - i;
933 ysize = rect.bottom / rows;
936 y = 0;
937 for (r = 1; r <= rows && *ppWnd; r++, i++)
939 SetWindowPos((*ppWnd)->hwndSelf, 0, x, y, xsize, ysize,
940 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
941 y += ysize;
942 ppWnd++;
944 x += xsize;
947 WIN_ReleaseWinArray(heapPtr);
950 if( total < ci->nActiveChildren ) ArrangeIconicWindows( wndClient->hwndSelf );
953 /* ----------------------- Frame window ---------------------------- */
956 /**********************************************************************
957 * MDI_AugmentFrameMenu
959 static BOOL MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
960 HWND hChild )
962 WND* child = WIN_FindWndPtr(hChild);
963 HMENU hSysPopup = 0;
964 HBITMAP hSysMenuBitmap = 0;
966 TRACE("frame %p,child %04x\n",frame,hChild);
968 if( !frame->wIDmenu || !child->hSysMenu )
970 WIN_ReleaseWndPtr(child);
971 return 0;
973 WIN_ReleaseWndPtr(child);
975 /* create a copy of sysmenu popup and insert it into frame menu bar */
977 if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
978 return 0;
980 TRACE("\tgot popup %04x in sysmenu %04x\n",
981 hSysPopup, child->hSysMenu);
983 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
984 SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
985 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
986 SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
988 /* In Win 95 look, the system menu is replaced by the child icon */
990 if(TWEAK_WineLook > WIN31_LOOK)
992 HICON hIcon = GetClassLongA(hChild, GCL_HICONSM);
993 if (!hIcon)
994 hIcon = GetClassLongA(hChild, GCL_HICON);
995 if (hIcon)
997 HDC hMemDC;
998 HBITMAP hBitmap, hOldBitmap;
999 HBRUSH hBrush;
1000 HDC hdc = GetDC(hChild);
1002 if (hdc)
1004 int cx, cy;
1005 cx = GetSystemMetrics(SM_CXSMICON);
1006 cy = GetSystemMetrics(SM_CYSMICON);
1007 hMemDC = CreateCompatibleDC(hdc);
1008 hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
1009 hOldBitmap = SelectObject(hMemDC, hBitmap);
1010 SetMapMode(hMemDC, MM_TEXT);
1011 hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
1012 DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL);
1013 SelectObject (hMemDC, hOldBitmap);
1014 DeleteObject(hBrush);
1015 DeleteDC(hMemDC);
1016 ReleaseDC(hChild, hdc);
1017 hSysMenuBitmap = hBitmap;
1021 else
1022 hSysMenuBitmap = hBmpClose;
1024 if( !InsertMenuA(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
1025 hSysPopup, (LPSTR)(DWORD)hSysMenuBitmap))
1027 TRACE("not inserted\n");
1028 DestroyMenu(hSysPopup);
1029 return 0;
1032 /* The close button is only present in Win 95 look */
1033 if(TWEAK_WineLook > WIN31_LOOK)
1035 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
1036 SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
1039 EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
1040 EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
1041 EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
1042 SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE);
1044 /* redraw menu */
1045 DrawMenuBar(frame->hwndSelf);
1047 return 1;
1050 /**********************************************************************
1051 * MDI_RestoreFrameMenu
1053 static BOOL MDI_RestoreFrameMenu( WND *frameWnd, HWND hChild )
1055 MENUITEMINFOA menuInfo;
1056 INT nItems = GetMenuItemCount(frameWnd->wIDmenu) - 1;
1057 UINT iId = GetMenuItemID(frameWnd->wIDmenu,nItems) ;
1059 TRACE("frameWnd %p,(%04x),child %04x,nIt=%d,iId=%d\n",
1060 frameWnd,frameWnd->hwndSelf,hChild,nItems,iId);
1062 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
1063 return 0;
1066 * Remove the system menu, If that menu is the icon of the window
1067 * as it is in win95, we have to delete the bitmap.
1069 menuInfo.cbSize = sizeof(MENUITEMINFOA);
1070 menuInfo.fMask = MIIM_DATA | MIIM_TYPE;
1072 GetMenuItemInfoA(frameWnd->wIDmenu,
1074 TRUE,
1075 &menuInfo);
1077 RemoveMenu(frameWnd->wIDmenu,0,MF_BYPOSITION);
1079 if ( (menuInfo.fType & MFT_BITMAP) &&
1080 (LOWORD(menuInfo.dwTypeData)!=0) &&
1081 (LOWORD(menuInfo.dwTypeData)!=hBmpClose) )
1083 DeleteObject((HBITMAP)LOWORD(menuInfo.dwTypeData));
1086 if(TWEAK_WineLook > WIN31_LOOK)
1088 /* close */
1089 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1091 /* restore */
1092 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1093 /* minimize */
1094 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1096 DrawMenuBar(frameWnd->hwndSelf);
1098 return 1;
1102 /**********************************************************************
1103 * MDI_UpdateFrameText
1105 * used when child window is maximized/restored
1107 * Note: lpTitle can be NULL
1109 static void MDI_UpdateFrameText( WND *frameWnd, HWND hClient,
1110 BOOL repaint, LPCWSTR lpTitle )
1112 WCHAR lpBuffer[MDI_MAXTITLELENGTH+1];
1113 WND* clientWnd = WIN_FindWndPtr(hClient);
1114 MDICLIENTINFO *ci = (MDICLIENTINFO *) clientWnd->wExtra;
1116 TRACE("repaint %i, frameText %s\n", repaint, (lpTitle)?debugstr_w(lpTitle):"NULL");
1118 if (!clientWnd)
1119 return;
1121 if (!ci)
1123 WIN_ReleaseWndPtr(clientWnd);
1124 return;
1127 /* store new "default" title if lpTitle is not NULL */
1128 if (lpTitle)
1130 if (ci->frameTitle) HeapFree( SystemHeap, 0, ci->frameTitle );
1131 ci->frameTitle = HEAP_strdupW( SystemHeap, 0, lpTitle );
1134 if (ci->frameTitle)
1136 WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );
1138 if( childWnd && childWnd->text )
1140 /* combine frame title and child title if possible */
1142 static const WCHAR lpBracket[] = {' ','-',' ','[',0};
1143 static const WCHAR lpBracket2[] = {']',0};
1144 int i_frame_text_length = lstrlenW(ci->frameTitle);
1145 int i_child_text_length = lstrlenW(childWnd->text);
1147 lstrcpynW( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
1149 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
1151 lstrcatW( lpBuffer, lpBracket );
1153 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
1155 lstrcatW( lpBuffer, childWnd->text );
1156 lstrcatW( lpBuffer, lpBracket2 );
1158 else
1160 lstrcpynW( lpBuffer + i_frame_text_length + 4,
1161 childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
1162 lstrcatW( lpBuffer, lpBracket2 );
1166 else
1168 lstrcpynW(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH+1 );
1170 WIN_ReleaseWndPtr(childWnd);
1173 else
1174 lpBuffer[0] = '\0';
1176 DEFWND_SetTextW( frameWnd, lpBuffer );
1177 if( repaint == MDI_REPAINTFRAME)
1178 SetWindowPos( frameWnd->hwndSelf, 0,0,0,0,0, SWP_FRAMECHANGED |
1179 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
1181 WIN_ReleaseWndPtr(clientWnd);
1186 /* ----------------------------- Interface ---------------------------- */
1189 /**********************************************************************
1190 * MDIClientWndProc
1192 * This function handles all MDI requests.
1194 LRESULT WINAPI MDIClientWndProc( HWND hwnd, UINT message, WPARAM wParam,
1195 LPARAM lParam )
1197 LPCREATESTRUCTA cs;
1198 MDICLIENTINFO *ci;
1199 RECT rect;
1200 WND *w, *frameWnd;
1201 INT nItems;
1202 LRESULT retvalue;
1204 if ( ( w = WIN_FindWndPtr(hwnd) ) == NULL )
1205 return 0;
1207 if ( ( frameWnd = WIN_LockWndPtr(w->parent) ) == NULL ) {
1208 WIN_ReleaseWndPtr(w);
1209 return 0;
1212 ci = (MDICLIENTINFO *) w->wExtra;
1214 switch (message)
1216 case WM_CREATE:
1218 cs = (LPCREATESTRUCTA)lParam;
1220 /* Translation layer doesn't know what's in the cs->lpCreateParams
1221 * so we have to keep track of what environment we're in. */
1223 if( w->flags & WIN_ISWIN32 )
1225 #define ccs ((LPCLIENTCREATESTRUCT)cs->lpCreateParams)
1226 ci->hWindowMenu = ccs->hWindowMenu;
1227 ci->idFirstChild = ccs->idFirstChild;
1228 #undef ccs
1230 else
1232 LPCLIENTCREATESTRUCT16 ccs = (LPCLIENTCREATESTRUCT16)
1233 PTR_SEG_TO_LIN(cs->lpCreateParams);
1234 ci->hWindowMenu = ccs->hWindowMenu;
1235 ci->idFirstChild = ccs->idFirstChild;
1238 ci->hwndChildMaximized = 0;
1239 ci->nActiveChildren = 0;
1240 ci->nTotalCreated = 0;
1241 ci->frameTitle = NULL;
1242 ci->mdiFlags = 0;
1243 ci->self = hwnd;
1244 w->dwStyle |= WS_CLIPCHILDREN;
1246 if (!hBmpClose)
1248 hBmpClose = CreateMDIMenuBitmap();
1249 hBmpRestore = LoadBitmap16( 0, MAKEINTRESOURCE16(OBM_RESTORE) );
1251 MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
1253 if (ci->hWindowMenu != 0)
1254 AppendMenuA( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
1256 GetClientRect(frameWnd->hwndSelf, &rect);
1257 NC_HandleNCCalcSize( w, &rect );
1258 w->rectClient = rect;
1260 TRACE("Client created - hwnd = %04x, idFirst = %u\n",
1261 hwnd, ci->idFirstChild );
1263 retvalue = 0;
1264 goto END;
1266 case WM_DESTROY:
1267 if( ci->hwndChildMaximized )
1268 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized);
1269 if((ci->hWindowMenu != 0) &&
1270 (nItems = GetMenuItemCount(ci->hWindowMenu)) > 0)
1272 ci->idFirstChild = nItems - 1;
1273 ci->nActiveChildren++; /* to delete a separator */
1274 while( ci->nActiveChildren-- )
1275 DeleteMenu(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
1277 retvalue = 0;
1278 goto END;
1280 case WM_MDIACTIVATE:
1281 if( ci->hwndActiveChild != (HWND)wParam )
1282 SetWindowPos((HWND)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
1283 retvalue = 0;
1284 goto END;
1286 case WM_MDICASCADE:
1287 retvalue = MDICascade(w, ci);
1288 goto END;
1290 case WM_MDICREATE:
1291 if (lParam) retvalue = MDICreateChild( w, ci, hwnd,
1292 (MDICREATESTRUCTA*)lParam );
1293 else retvalue = 0;
1294 goto END;
1296 case WM_MDIDESTROY:
1297 retvalue = MDIDestroyChild( w, ci, hwnd, (HWND)wParam, TRUE );
1298 goto END;
1300 case WM_MDIGETACTIVE:
1301 if (lParam) *(BOOL *)lParam = (ci->hwndChildMaximized > 0);
1302 retvalue = ci->hwndActiveChild;
1303 goto END;
1305 case WM_MDIICONARRANGE:
1306 ci->mdiFlags |= MDIF_NEEDUPDATE;
1307 ArrangeIconicWindows(hwnd);
1308 ci->sbRecalc = SB_BOTH+1;
1309 SendMessageA(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
1310 retvalue = 0;
1311 goto END;
1313 case WM_MDIMAXIMIZE:
1314 ShowWindow( (HWND)wParam, SW_MAXIMIZE );
1315 retvalue = 0;
1316 goto END;
1318 case WM_MDINEXT: /* lParam != 0 means previous window */
1319 MDI_SwitchActiveChild(hwnd, (HWND)wParam, (lParam)? FALSE : TRUE );
1320 break;
1322 case WM_MDIRESTORE:
1323 SendMessageA( (HWND)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
1324 retvalue = 0;
1325 goto END;
1327 case WM_MDISETMENU:
1328 retvalue = MDISetMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1329 goto END;
1330 case WM_MDIREFRESHMENU:
1331 retvalue = MDIRefreshMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1332 goto END;
1334 case WM_MDITILE:
1335 ci->mdiFlags |= MDIF_NEEDUPDATE;
1336 ShowScrollBar(hwnd,SB_BOTH,FALSE);
1337 MDITile(w, ci, wParam);
1338 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1339 retvalue = 0;
1340 goto END;
1342 case WM_VSCROLL:
1343 case WM_HSCROLL:
1344 ci->mdiFlags |= MDIF_NEEDUPDATE;
1345 ScrollChildren(hwnd, message, wParam, lParam);
1346 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1347 retvalue = 0;
1348 goto END;
1350 case WM_SETFOCUS:
1351 if( ci->hwndActiveChild )
1353 WND* pw = WIN_FindWndPtr( ci->hwndActiveChild );
1354 if( !(pw->dwStyle & WS_MINIMIZE) )
1355 SetFocus( ci->hwndActiveChild );
1356 WIN_ReleaseWndPtr(pw);
1358 retvalue = 0;
1359 goto END;
1361 case WM_NCACTIVATE:
1362 if( ci->hwndActiveChild )
1363 SendMessageA(ci->hwndActiveChild, message, wParam, lParam);
1364 break;
1366 case WM_PARENTNOTIFY:
1367 if (LOWORD(wParam) == WM_LBUTTONDOWN)
1369 POINT16 pt = MAKEPOINT16(lParam);
1370 HWND16 child = ChildWindowFromPoint16(hwnd, pt);
1372 TRACE("notification from %04x (%i,%i)\n",child,pt.x,pt.y);
1374 if( child && child != hwnd && child != ci->hwndActiveChild )
1375 SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1377 retvalue = 0;
1378 goto END;
1380 case WM_SIZE:
1381 if( IsWindow(ci->hwndChildMaximized) )
1383 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1384 RECT rect;
1386 rect.left = 0;
1387 rect.top = 0;
1388 rect.right = LOWORD(lParam);
1389 rect.bottom = HIWORD(lParam);
1391 AdjustWindowRectEx(&rect, child->dwStyle, 0, child->dwExStyle);
1392 MoveWindow(ci->hwndChildMaximized, rect.left, rect.top,
1393 rect.right - rect.left, rect.bottom - rect.top, 1);
1394 WIN_ReleaseWndPtr(child);
1396 else
1397 MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1399 break;
1401 case WM_MDICALCCHILDSCROLL:
1402 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1404 CalcChildScroll16(hwnd, ci->sbRecalc-1);
1405 ci->sbRecalc = 0;
1406 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1408 retvalue = 0;
1409 goto END;
1412 retvalue = DefWindowProcA( hwnd, message, wParam, lParam );
1413 END:
1414 WIN_ReleaseWndPtr(w);
1415 WIN_ReleaseWndPtr(frameWnd);
1416 return retvalue;
1420 /***********************************************************************
1421 * DefFrameProc16 (USER.445)
1423 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1424 UINT16 message, WPARAM16 wParam, LPARAM lParam )
1426 HWND16 childHwnd;
1427 MDICLIENTINFO* ci;
1428 WND* wndPtr;
1430 if (hwndMDIClient)
1432 switch (message)
1434 case WM_COMMAND:
1435 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1437 if (!wndPtr) {
1438 ERR("null wndPtr for mdi window hwndMDIClient=%04x\n",
1439 hwndMDIClient);
1440 return 0;
1443 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1445 /* check for possible syscommands for maximized MDI child */
1446 WIN_ReleaseWndPtr(wndPtr);
1448 if( ci && (
1449 wParam < ci->idFirstChild ||
1450 wParam >= ci->idFirstChild + ci->nActiveChildren
1452 if( (wParam - 0xF000) & 0xF00F ) break;
1453 switch( wParam )
1455 case SC_SIZE:
1456 case SC_MOVE:
1457 case SC_MINIMIZE:
1458 case SC_MAXIMIZE:
1459 case SC_NEXTWINDOW:
1460 case SC_PREVWINDOW:
1461 case SC_CLOSE:
1462 case SC_RESTORE:
1463 if( ci->hwndChildMaximized )
1464 return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1465 wParam, lParam);
1468 else
1470 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1471 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1473 if (wParam - ci->idFirstChild == MDI_MOREWINDOWSLIMIT)
1474 /* User chose "More Windows..." */
1475 childHwnd = MDI_MoreWindowsDialog(wndPtr);
1476 else
1477 /* User chose one of the windows listed in the "Windows" menu */
1478 childHwnd = MDI_GetChildByID(wndPtr,wParam );
1480 WIN_ReleaseWndPtr(wndPtr);
1481 if( childHwnd )
1482 SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1483 (WPARAM16)childHwnd , 0L);
1485 break;
1487 case WM_NCACTIVATE:
1488 SendMessage16(hwndMDIClient, message, wParam, lParam);
1489 break;
1491 case WM_SETTEXT:
1493 LPWSTR text = HEAP_strdupAtoW( GetProcessHeap(), 0,
1494 (LPCSTR)PTR_SEG_TO_LIN(lParam) );
1495 wndPtr = WIN_FindWndPtr(hwnd);
1496 MDI_UpdateFrameText(wndPtr, hwndMDIClient,
1497 MDI_REPAINTFRAME, text );
1498 WIN_ReleaseWndPtr(wndPtr);
1499 HeapFree( GetProcessHeap(), 0, text );
1501 return 0;
1503 case WM_SETFOCUS:
1504 SetFocus(hwndMDIClient);
1505 break;
1507 case WM_SIZE:
1508 MoveWindow16(hwndMDIClient, 0, 0,
1509 LOWORD(lParam), HIWORD(lParam), TRUE);
1510 break;
1512 case WM_NEXTMENU:
1514 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1515 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1517 if( !(wndPtr->parent->dwStyle & WS_MINIMIZE)
1518 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1520 /* control menu is between the frame system menu and
1521 * the first entry of menu bar */
1523 if( (wParam == VK_LEFT &&
1524 wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1525 (wParam == VK_RIGHT &&
1526 GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1528 LRESULT retvalue;
1529 WIN_ReleaseWndPtr(wndPtr);
1530 wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1531 retvalue = MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1532 ci->hwndActiveChild);
1533 WIN_ReleaseWndPtr(wndPtr);
1534 return retvalue;
1537 WIN_ReleaseWndPtr(wndPtr);
1538 break;
1542 return DefWindowProc16(hwnd, message, wParam, lParam);
1546 /***********************************************************************
1547 * DefFrameProcA (USER32.122)
1549 LRESULT WINAPI DefFrameProcA( HWND hwnd, HWND hwndMDIClient,
1550 UINT message, WPARAM wParam, LPARAM lParam)
1552 if (hwndMDIClient)
1554 switch (message)
1556 case WM_COMMAND:
1557 return DefFrameProc16( hwnd, hwndMDIClient, message,
1558 (WPARAM16)wParam,
1559 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1561 case WM_NCACTIVATE:
1562 SendMessageA(hwndMDIClient, message, wParam, lParam);
1563 break;
1565 case WM_SETTEXT: {
1566 LRESULT ret;
1567 LPSTR segstr = SEGPTR_STRDUP((LPSTR)lParam);
1569 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1570 wParam, (LPARAM)SEGPTR_GET(segstr) );
1571 SEGPTR_FREE(segstr);
1572 return ret;
1575 case WM_NEXTMENU:
1576 case WM_SETFOCUS:
1577 case WM_SIZE:
1578 return DefFrameProc16( hwnd, hwndMDIClient, message,
1579 wParam, lParam );
1583 return DefWindowProcA(hwnd, message, wParam, lParam);
1587 /***********************************************************************
1588 * DefFrameProcW (USER32.123)
1590 LRESULT WINAPI DefFrameProcW( HWND hwnd, HWND hwndMDIClient,
1591 UINT message, WPARAM wParam, LPARAM lParam)
1593 if (hwndMDIClient)
1595 switch (message)
1597 case WM_COMMAND:
1598 return DefFrameProc16( hwnd, hwndMDIClient, message,
1599 (WPARAM16)wParam,
1600 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1602 case WM_NCACTIVATE:
1603 SendMessageW(hwndMDIClient, message, wParam, lParam);
1604 break;
1606 case WM_SETTEXT:
1608 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1609 LRESULT ret = DefFrameProcA( hwnd, hwndMDIClient, message,
1610 wParam, (DWORD)txt );
1611 HeapFree(GetProcessHeap(),0,txt);
1612 return ret;
1614 case WM_NEXTMENU:
1615 case WM_SETFOCUS:
1616 case WM_SIZE:
1617 return DefFrameProcA( hwnd, hwndMDIClient, message,
1618 wParam, lParam );
1622 return DefWindowProcW( hwnd, message, wParam, lParam );
1626 /***********************************************************************
1627 * DefMDIChildProc16 (USER.447)
1629 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1630 WPARAM16 wParam, LPARAM lParam )
1632 MDICLIENTINFO *ci;
1633 WND *clientWnd,*tmpWnd = 0;
1634 LRESULT retvalue;
1636 tmpWnd = WIN_FindWndPtr(hwnd);
1637 if (!tmpWnd) return 0;
1638 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1639 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1640 WIN_ReleaseWndPtr(tmpWnd);
1642 switch (message)
1644 case WM_SETTEXT:
1645 DefWindowProc16(hwnd, message, wParam, lParam);
1646 MDI_MenuModifyItem(clientWnd,hwnd);
1647 if( ci->hwndChildMaximized == hwnd )
1648 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1649 MDI_REPAINTFRAME, NULL );
1650 retvalue = 0;
1651 goto END;
1653 case WM_CLOSE:
1654 SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1655 retvalue = 0;
1656 goto END;
1658 case WM_SETFOCUS:
1659 if( ci->hwndActiveChild != hwnd )
1660 MDI_ChildActivate(clientWnd, hwnd);
1661 break;
1663 case WM_CHILDACTIVATE:
1664 MDI_ChildActivate(clientWnd, hwnd);
1665 retvalue = 0;
1666 goto END;
1668 case WM_NCPAINT:
1669 TRACE("WM_NCPAINT for %04x, active %04x\n",
1670 hwnd, ci->hwndActiveChild );
1671 break;
1673 case WM_SYSCOMMAND:
1674 switch( wParam )
1676 case SC_MOVE:
1677 if( ci->hwndChildMaximized == hwnd)
1679 retvalue = 0;
1680 goto END;
1682 break;
1683 case SC_RESTORE:
1684 case SC_MINIMIZE:
1685 tmpWnd = WIN_FindWndPtr(hwnd);
1686 tmpWnd->dwStyle |= WS_SYSMENU;
1687 WIN_ReleaseWndPtr(tmpWnd);
1688 break;
1689 case SC_MAXIMIZE:
1690 if( ci->hwndChildMaximized == hwnd)
1692 retvalue = SendMessage16( clientWnd->parent->hwndSelf,
1693 message, wParam, lParam);
1694 goto END;
1696 tmpWnd = WIN_FindWndPtr(hwnd);
1697 tmpWnd->dwStyle &= ~WS_SYSMENU;
1698 WIN_ReleaseWndPtr(tmpWnd);
1699 break;
1700 case SC_NEXTWINDOW:
1701 SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1702 retvalue = 0;
1703 goto END;
1704 case SC_PREVWINDOW:
1705 SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1706 retvalue = 0;
1707 goto END;
1709 break;
1711 case WM_GETMINMAXINFO:
1712 MDI_ChildGetMinMaxInfo(clientWnd, hwnd, (MINMAXINFO16*) PTR_SEG_TO_LIN(lParam));
1713 retvalue = 0;
1714 goto END;
1716 case WM_SETVISIBLE:
1717 if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1718 else
1719 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1720 break;
1722 case WM_SIZE:
1723 /* do not change */
1725 if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1727 ci->hwndChildMaximized = 0;
1729 MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1730 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1731 MDI_REPAINTFRAME, NULL );
1734 if( wParam == SIZE_MAXIMIZED )
1736 HWND16 hMaxChild = ci->hwndChildMaximized;
1738 if( hMaxChild == hwnd ) break;
1740 if( hMaxChild)
1742 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1744 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1745 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1747 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1750 TRACE("maximizing child %04x\n", hwnd );
1752 ci->hwndChildMaximized = hwnd; /* !!! */
1753 ci->hwndActiveChild = hwnd;
1755 MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1756 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1757 MDI_REPAINTFRAME, NULL );
1760 if( wParam == SIZE_MINIMIZED )
1762 HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1764 if( switchTo )
1765 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1768 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1769 break;
1771 case WM_MENUCHAR:
1773 /* MDI children don't have menu bars */
1774 retvalue = 0x00010000L;
1775 goto END;
1777 case WM_NEXTMENU:
1779 if( wParam == VK_LEFT ) /* switch to frame system menu */
1781 retvalue = MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1782 clientWnd->parent->hwndSelf );
1783 goto END;
1785 if( wParam == VK_RIGHT ) /* to frame menu bar */
1787 retvalue = MAKELONG( clientWnd->parent->wIDmenu,
1788 clientWnd->parent->hwndSelf );
1789 goto END;
1792 break;
1794 case WM_SYSCHAR:
1795 if (wParam == '-')
1797 SendMessage16(hwnd,WM_SYSCOMMAND,
1798 (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1799 retvalue = 0;
1800 goto END;
1804 retvalue = DefWindowProc16(hwnd, message, wParam, lParam);
1805 END:
1806 WIN_ReleaseWndPtr(clientWnd);
1807 return retvalue;
1811 /***********************************************************************
1812 * DefMDIChildProcA (USER32.124)
1814 LRESULT WINAPI DefMDIChildProcA( HWND hwnd, UINT message,
1815 WPARAM wParam, LPARAM lParam )
1817 MDICLIENTINFO *ci;
1818 WND *clientWnd,*tmpWnd;
1819 LRESULT retvalue;
1821 tmpWnd = WIN_FindWndPtr(hwnd);
1822 if (!tmpWnd) return 0;
1823 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1824 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1825 WIN_ReleaseWndPtr(tmpWnd);
1827 switch (message)
1829 case WM_SETTEXT:
1830 DefWindowProcA(hwnd, message, wParam, lParam);
1831 MDI_MenuModifyItem(clientWnd,hwnd);
1832 if( ci->hwndChildMaximized == hwnd )
1833 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1834 MDI_REPAINTFRAME, NULL );
1835 retvalue = 0;
1836 goto END;
1838 case WM_GETMINMAXINFO:
1840 MINMAXINFO16 mmi;
1841 STRUCT32_MINMAXINFO32to16( (MINMAXINFO *)lParam, &mmi );
1842 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1843 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO *)lParam );
1845 retvalue = 0;
1846 goto END;
1848 case WM_MENUCHAR:
1850 /* MDI children don't have menu bars */
1851 retvalue = 0x00010000L;
1852 goto END;
1854 case WM_CLOSE:
1855 case WM_SETFOCUS:
1856 case WM_CHILDACTIVATE:
1857 case WM_NCPAINT:
1858 case WM_SYSCOMMAND:
1859 case WM_SETVISIBLE:
1860 case WM_SIZE:
1861 case WM_NEXTMENU:
1862 retvalue = DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1863 goto END;
1865 case WM_SYSCHAR:
1866 if (wParam == '-')
1868 SendMessageA(hwnd,WM_SYSCOMMAND,
1869 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1870 retvalue = 0;
1871 goto END;
1874 retvalue = DefWindowProcA(hwnd, message, wParam, lParam);
1875 END:
1876 WIN_ReleaseWndPtr(clientWnd);
1877 return retvalue;
1881 /***********************************************************************
1882 * DefMDIChildProcW (USER32.125)
1884 LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message,
1885 WPARAM wParam, LPARAM lParam )
1887 MDICLIENTINFO *ci;
1888 WND *clientWnd,*tmpWnd;
1889 LRESULT retvalue;
1891 tmpWnd = WIN_FindWndPtr(hwnd);
1892 if (!tmpWnd) return 0;
1893 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1894 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1895 WIN_ReleaseWndPtr(tmpWnd);
1897 switch (message)
1899 case WM_SETTEXT:
1900 DefWindowProcW(hwnd, message, wParam, lParam);
1901 MDI_MenuModifyItem(clientWnd,hwnd);
1902 if( ci->hwndChildMaximized == hwnd )
1903 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1904 MDI_REPAINTFRAME, NULL );
1905 retvalue = 0;
1906 goto END;
1908 case WM_GETMINMAXINFO:
1909 case WM_MENUCHAR:
1910 case WM_CLOSE:
1911 case WM_SETFOCUS:
1912 case WM_CHILDACTIVATE:
1913 case WM_NCPAINT:
1914 case WM_SYSCOMMAND:
1915 case WM_SETVISIBLE:
1916 case WM_SIZE:
1917 case WM_NEXTMENU:
1918 retvalue = DefMDIChildProcA( hwnd, message, (WPARAM16)wParam, lParam );
1919 goto END;
1921 case WM_SYSCHAR:
1922 if (wParam == '-')
1924 SendMessageW(hwnd,WM_SYSCOMMAND,
1925 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1926 retvalue = 0;
1927 goto END;
1930 retvalue = DefWindowProcW(hwnd, message, wParam, lParam);
1931 END:
1932 WIN_ReleaseWndPtr(clientWnd);
1933 return retvalue;
1938 /**********************************************************************
1939 * CreateMDIWindowA [USER32.79] Creates a MDI child in new thread
1940 * FIXME: its in the same thread now
1942 * RETURNS
1943 * Success: Handle to created window
1944 * Failure: NULL
1946 HWND WINAPI CreateMDIWindowA(
1947 LPCSTR lpClassName, /* [in] Pointer to registered child class name */
1948 LPCSTR lpWindowName, /* [in] Pointer to window name */
1949 DWORD dwStyle, /* [in] Window style */
1950 INT X, /* [in] Horizontal position of window */
1951 INT Y, /* [in] Vertical position of window */
1952 INT nWidth, /* [in] Width of window */
1953 INT nHeight, /* [in] Height of window */
1954 HWND hWndParent, /* [in] Handle to parent window */
1955 HINSTANCE hInstance, /* [in] Handle to application instance */
1956 LPARAM lParam) /* [in] Application-defined value */
1958 WARN("is only single threaded!\n");
1959 return MDI_CreateMDIWindowA(lpClassName, lpWindowName, dwStyle, X, Y,
1960 nWidth, nHeight, hWndParent, hInstance, lParam);
1963 /**********************************************************************
1964 * MDI_CreateMDIWindowA
1965 * single threaded version of CreateMDIWindowA
1966 * called by CreateWindowExA
1968 HWND MDI_CreateMDIWindowA(
1969 LPCSTR lpClassName,
1970 LPCSTR lpWindowName,
1971 DWORD dwStyle,
1972 INT X,
1973 INT Y,
1974 INT nWidth,
1975 INT nHeight,
1976 HWND hWndParent,
1977 HINSTANCE hInstance,
1978 LPARAM lParam)
1980 MDICLIENTINFO* pCi;
1981 MDICREATESTRUCTA cs;
1982 WND *pWnd=WIN_FindWndPtr(hWndParent);
1983 HWND retvalue;
1985 TRACE("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
1986 debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
1987 nWidth,nHeight,hWndParent,hInstance,lParam);
1989 if(!pWnd){
1990 ERR(" bad hwnd for MDI-client: %d\n",hWndParent);
1991 return 0;
1993 cs.szClass=lpClassName;
1994 cs.szTitle=lpWindowName;
1995 cs.hOwner=hInstance;
1996 cs.x=X;
1997 cs.y=Y;
1998 cs.cx=nWidth;
1999 cs.cy=nHeight;
2000 cs.style=dwStyle;
2001 cs.lParam=lParam;
2003 pCi=(MDICLIENTINFO *)pWnd->wExtra;
2005 retvalue = MDICreateChild(pWnd,pCi,hWndParent,&cs);
2006 WIN_ReleaseWndPtr(pWnd);
2007 return retvalue;
2010 /***********************************************************************
2011 * CreateMDIWindowW [USER32.80] Creates a MDI child in new thread
2013 * RETURNS
2014 * Success: Handle to created window
2015 * Failure: NULL
2017 HWND WINAPI CreateMDIWindowW(
2018 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
2019 LPCWSTR lpWindowName, /* [in] Pointer to window name */
2020 DWORD dwStyle, /* [in] Window style */
2021 INT X, /* [in] Horizontal position of window */
2022 INT Y, /* [in] Vertical position of window */
2023 INT nWidth, /* [in] Width of window */
2024 INT nHeight, /* [in] Height of window */
2025 HWND hWndParent, /* [in] Handle to parent window */
2026 HINSTANCE hInstance, /* [in] Handle to application instance */
2027 LPARAM lParam) /* [in] Application-defined value */
2029 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
2030 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
2031 nWidth,nHeight,hWndParent,hInstance,lParam);
2032 return (HWND)NULL;
2036 /******************************************************************************
2037 * CreateMDIWindowW [USER32.80] Creates a MDI child window
2038 * single threaded version of CreateMDIWindow
2039 * called by CreateWindowExW().
2041 HWND MDI_CreateMDIWindowW(
2042 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
2043 LPCWSTR lpWindowName, /* [in] Pointer to window name */
2044 DWORD dwStyle, /* [in] Window style */
2045 INT X, /* [in] Horizontal position of window */
2046 INT Y, /* [in] Vertical position of window */
2047 INT nWidth, /* [in] Width of window */
2048 INT nHeight, /* [in] Height of window */
2049 HWND hWndParent, /* [in] Handle to parent window */
2050 HINSTANCE hInstance, /* [in] Handle to application instance */
2051 LPARAM lParam) /* [in] Application-defined value */
2053 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
2054 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
2055 nWidth,nHeight,hWndParent,hInstance,lParam);
2056 return (HWND)NULL;
2060 /**********************************************************************
2061 * TranslateMDISysAccel (USER32.555)
2063 BOOL WINAPI TranslateMDISysAccel( HWND hwndClient, LPMSG msg )
2065 MSG16 msg16;
2067 STRUCT32_MSG32to16(msg,&msg16);
2068 /* MDICLIENTINFO is still the same for win32 and win16 ... */
2069 return TranslateMDISysAccel16(hwndClient,&msg16);
2073 /**********************************************************************
2074 * TranslateMDISysAccel16 (USER.451)
2076 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
2079 if( IsWindow(hwndClient) && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
2081 MDICLIENTINFO *ci = NULL;
2082 HWND wnd;
2083 WND *clientWnd = WIN_FindWndPtr(hwndClient);
2085 ci = (MDICLIENTINFO*) clientWnd->wExtra;
2086 wnd = ci->hwndActiveChild;
2088 WIN_ReleaseWndPtr(clientWnd);
2090 if( IsWindow(wnd) && !(GetWindowLongA(wnd,GWL_STYLE) & WS_DISABLED) )
2092 WPARAM16 wParam = 0;
2094 /* translate if the Ctrl key is down and Alt not. */
2096 if( (GetKeyState(VK_CONTROL) & 0x8000) &&
2097 !(GetKeyState(VK_MENU) & 0x8000))
2099 switch( msg->wParam )
2101 case VK_F6:
2102 case VK_TAB:
2103 wParam = ( GetKeyState(VK_SHIFT) & 0x8000 )
2104 ? SC_NEXTWINDOW : SC_PREVWINDOW;
2105 break;
2106 case VK_F4:
2107 case VK_RBUTTON:
2108 wParam = SC_CLOSE;
2109 break;
2110 default:
2111 return 0;
2113 TRACE("wParam = %04x\n", wParam);
2114 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
2115 wParam, (LPARAM)msg->wParam);
2116 return 1;
2120 return 0; /* failure */
2124 /***********************************************************************
2125 * CalcChildScroll (USER.462)
2127 void WINAPI CalcChildScroll16( HWND16 hwnd, WORD scroll )
2129 SCROLLINFO info;
2130 RECT childRect, clientRect;
2131 INT vmin, vmax, hmin, hmax, vpos, hpos;
2132 WND *pWnd, *Wnd;
2134 if (!(pWnd = WIN_FindWndPtr( hwnd ))) return;
2135 Wnd = WIN_FindWndPtr(hwnd);
2136 GetClientRect( hwnd, &clientRect );
2137 SetRectEmpty( &childRect );
2139 for ( WIN_UpdateWndPtr(&pWnd,pWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2141 if( pWnd->dwStyle & WS_MAXIMIZE )
2143 ShowScrollBar(hwnd, SB_BOTH, FALSE);
2144 WIN_ReleaseWndPtr(pWnd);
2145 WIN_ReleaseWndPtr(Wnd);
2146 return;
2148 UnionRect( &childRect, &pWnd->rectWindow, &childRect );
2150 WIN_ReleaseWndPtr(pWnd);
2151 UnionRect( &childRect, &clientRect, &childRect );
2153 hmin = childRect.left; hmax = childRect.right - clientRect.right;
2154 hpos = clientRect.left - childRect.left;
2155 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
2156 vpos = clientRect.top - childRect.top;
2158 switch( scroll )
2160 case SB_HORZ:
2161 vpos = hpos; vmin = hmin; vmax = hmax;
2162 case SB_VERT:
2163 info.cbSize = sizeof(info);
2164 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
2165 info.fMask = SIF_POS | SIF_RANGE;
2166 SetScrollInfo(hwnd, scroll, &info, TRUE);
2167 break;
2168 case SB_BOTH:
2169 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
2170 hmin, hmax, hpos);
2172 WIN_ReleaseWndPtr(Wnd);
2176 /***********************************************************************
2177 * ScrollChildren16 (USER.463)
2179 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
2181 ScrollChildren( hWnd, uMsg, wParam, lParam );
2185 /***********************************************************************
2186 * ScrollChildren (USER32.448)
2188 void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
2189 LPARAM lParam)
2191 WND *wndPtr = WIN_FindWndPtr(hWnd);
2192 INT newPos = -1;
2193 INT curPos, length, minPos, maxPos, shift;
2195 if( !wndPtr ) return;
2197 if( uMsg == WM_HSCROLL )
2199 GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
2200 curPos = GetScrollPos(hWnd,SB_HORZ);
2201 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
2202 shift = GetSystemMetrics(SM_CYHSCROLL);
2204 else if( uMsg == WM_VSCROLL )
2206 GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
2207 curPos = GetScrollPos(hWnd,SB_VERT);
2208 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
2209 shift = GetSystemMetrics(SM_CXVSCROLL);
2211 else
2213 WIN_ReleaseWndPtr(wndPtr);
2214 return;
2217 WIN_ReleaseWndPtr(wndPtr);
2218 switch( wParam )
2220 case SB_LINEUP:
2221 newPos = curPos - shift;
2222 break;
2223 case SB_LINEDOWN:
2224 newPos = curPos + shift;
2225 break;
2226 case SB_PAGEUP:
2227 newPos = curPos - length;
2228 break;
2229 case SB_PAGEDOWN:
2230 newPos = curPos + length;
2231 break;
2233 case SB_THUMBPOSITION:
2234 newPos = LOWORD(lParam);
2235 break;
2237 case SB_THUMBTRACK:
2238 return;
2240 case SB_TOP:
2241 newPos = minPos;
2242 break;
2243 case SB_BOTTOM:
2244 newPos = maxPos;
2245 break;
2246 case SB_ENDSCROLL:
2247 CalcChildScroll16(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
2248 return;
2251 if( newPos > maxPos )
2252 newPos = maxPos;
2253 else
2254 if( newPos < minPos )
2255 newPos = minPos;
2257 SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
2259 if( uMsg == WM_VSCROLL )
2260 ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
2261 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2262 else
2263 ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
2264 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2268 /******************************************************************************
2269 * CascadeWindows [USER32.21] Cascades MDI child windows
2271 * RETURNS
2272 * Success: Number of cascaded windows.
2273 * Failure: 0
2275 WORD WINAPI
2276 CascadeWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2277 UINT cKids, const HWND *lpKids)
2279 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2280 hwndParent, wFlags, cKids);
2282 return 0;
2286 /******************************************************************************
2287 * TileWindows [USER32.545] Tiles MDI child windows
2289 * RETURNS
2290 * Success: Number of tiled windows.
2291 * Failure: 0
2293 WORD WINAPI
2294 TileWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2295 UINT cKids, const HWND *lpKids)
2297 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2298 hwndParent, wFlags, cKids);
2300 return 0;
2303 /************************************************************************
2304 * "More Windows..." functionality
2307 /* MDI_MoreWindowsDlgProc
2309 * This function will process the messages sent to the "More Windows..."
2310 * dialog.
2311 * Return values: 0 = cancel pressed
2312 * HWND = ok pressed or double-click in the list...
2316 static BOOL WINAPI MDI_MoreWindowsDlgProc (HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
2318 switch (iMsg)
2320 case WM_INITDIALOG:
2322 WND *pWnd;
2323 UINT widest = 0;
2324 UINT length;
2325 UINT i;
2326 WND *pParentWnd = (WND *)lParam;
2327 MDICLIENTINFO *ci = (MDICLIENTINFO*)pParentWnd->wExtra;
2328 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2330 /* Fill the list, sorted by id... */
2331 for (i = 0; i < ci->nActiveChildren; i++)
2334 /* Find the window with the current ID */
2335 for (pWnd = WIN_LockWndPtr(pParentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd, pWnd->next))
2336 if (pWnd->wIDmenu == ci->idFirstChild + i)
2337 break;
2339 SendMessageW(hListBox, LB_ADDSTRING, 0, (LPARAM) pWnd->text);
2340 SendMessageA(hListBox, LB_SETITEMDATA, i, (LPARAM) pWnd);
2341 length = lstrlenW(pWnd->text);
2342 WIN_ReleaseWndPtr(pWnd);
2344 if (length > widest)
2345 widest = length;
2347 /* Make sure the horizontal scrollbar scrolls ok */
2348 SendMessageA(hListBox, LB_SETHORIZONTALEXTENT, widest * 6, 0);
2350 /* Set the current selection */
2351 SendMessageA(hListBox, LB_SETCURSEL, MDI_MOREWINDOWSLIMIT, 0);
2352 return TRUE;
2355 case WM_COMMAND:
2356 switch (LOWORD(wParam))
2358 case IDOK:
2360 /* windows are sorted by menu ID, so we must return the
2361 * window associated to the given id
2363 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2364 UINT index = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
2365 WND* pWnd = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
2367 EndDialog(hDlg, pWnd->hwndSelf);
2368 return TRUE;
2370 case IDCANCEL:
2371 EndDialog(hDlg, 0);
2372 return TRUE;
2374 default:
2375 switch (HIWORD(wParam))
2377 case LBN_DBLCLK:
2379 /* windows are sorted by menu ID, so we must return the
2380 * window associated to the given id
2382 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2383 UINT index = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
2384 WND* pWnd = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
2386 EndDialog(hDlg, pWnd->hwndSelf);
2387 return TRUE;
2390 break;
2392 break;
2394 return FALSE;
2399 * MDI_MoreWindowsDialog
2401 * Prompts the user with a listbox containing the opened
2402 * documents. The user can then choose a windows and click
2403 * on OK to set the current window to the one selected, or
2404 * CANCEL to cancel. The function returns a handle to the
2405 * selected window.
2408 static HWND MDI_MoreWindowsDialog(WND* wndPtr)
2410 LPCVOID template;
2411 HRSRC hRes;
2412 HANDLE hDlgTmpl;
2414 hRes = FindResourceA(GetModuleHandleA("USER32"), "MDI_MOREWINDOWS", RT_DIALOGA);
2416 if (hRes == 0)
2417 return 0;
2419 hDlgTmpl = LoadResource(GetModuleHandleA("USER32"), hRes );
2421 if (hDlgTmpl == 0)
2422 return 0;
2424 template = LockResource( hDlgTmpl );
2426 if (template == 0)
2427 return 0;
2429 return (HWND) DialogBoxIndirectParamA(GetModuleHandleA("USER32"),
2430 (LPDLGTEMPLATEA) template,
2431 wndPtr->hwndSelf,
2432 (DLGPROC) MDI_MoreWindowsDlgProc,
2433 (LPARAM) wndPtr);
2438 * MDI_SwapMenuItems
2440 * Will swap the menu IDs for the given 2 positions.
2441 * pos1 and pos2 are menu IDs
2446 static void MDI_SwapMenuItems(WND *parentWnd, UINT pos1, UINT pos2)
2448 WND *pWnd;
2450 for (pWnd = WIN_LockWndPtr(parentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2452 if (pWnd->wIDmenu == pos1)
2453 pWnd->wIDmenu = pos2;
2454 else
2455 if (pWnd->wIDmenu == pos2)
2456 pWnd->wIDmenu = pos1;
2459 WIN_ReleaseWndPtr(pWnd);