Removed SUBDIRS in winmm Makefile.
[wine/multimedia.git] / windows / mdi.c
blob1e262ed8745c72b023a9706807a4bfef4851e5e5
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 "class.h"
79 #include "heap.h"
80 #include "nonclient.h"
81 #include "mdi.h"
82 #include "user.h"
83 #include "menu.h"
84 #include "scroll.h"
85 #include "struct32.h"
86 #include "tweak.h"
87 #include "debugtools.h"
88 #include "dlgs.h"
90 DEFAULT_DEBUG_CHANNEL(mdi);
92 #define MDIF_NEEDUPDATE 0x0001
94 static HBITMAP16 hBmpClose = 0;
95 static HBITMAP16 hBmpRestore = 0;
97 /* ----------------- declarations ----------------- */
98 static void MDI_UpdateFrameText(WND *, HWND, BOOL, LPCWSTR);
99 static BOOL MDI_AugmentFrameMenu(MDICLIENTINFO*, WND *, HWND);
100 static BOOL MDI_RestoreFrameMenu(WND *, HWND);
102 static LONG MDI_ChildActivate( WND*, HWND );
104 static HWND MDI_MoreWindowsDialog(WND*);
105 static void MDI_SwapMenuItems(WND *, UINT, UINT);
106 /* -------- Miscellaneous service functions ----------
108 * MDI_GetChildByID
111 static HWND MDI_GetChildByID(WND* wndPtr, INT id)
113 for (wndPtr = wndPtr->child; wndPtr; wndPtr = wndPtr->next)
114 if (wndPtr->wIDmenu == id) return wndPtr->hwndSelf;
115 return 0;
118 static void MDI_PostUpdate(HWND hwnd, MDICLIENTINFO* ci, WORD recalc)
120 if( !(ci->mdiFlags & MDIF_NEEDUPDATE) )
122 ci->mdiFlags |= MDIF_NEEDUPDATE;
123 PostMessageA( hwnd, WM_MDICALCCHILDSCROLL, 0, 0);
125 ci->sbRecalc = recalc;
128 /**********************************************************************
129 * MDI_MenuModifyItem
131 static BOOL MDI_MenuModifyItem(WND* clientWnd, HWND hWndChild )
133 WCHAR buffer[128];
134 static const WCHAR format[] = {'%','d',' ',0};
135 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
136 WND *wndPtr = WIN_FindWndPtr(hWndChild);
137 UINT n = wsprintfW(buffer, format,
138 wndPtr->wIDmenu - clientInfo->idFirstChild + 1);
139 BOOL bRet = 0;
141 if( !clientInfo->hWindowMenu )
143 bRet = FALSE;
144 goto END;
147 if (wndPtr->text) lstrcpynW(buffer + n, wndPtr->text, sizeof(buffer)/sizeof(WCHAR) - n );
149 n = GetMenuState(clientInfo->hWindowMenu,wndPtr->wIDmenu ,MF_BYCOMMAND);
150 bRet = ModifyMenuW(clientInfo->hWindowMenu , wndPtr->wIDmenu,
151 MF_BYCOMMAND | MF_STRING, wndPtr->wIDmenu, buffer );
152 CheckMenuItem(clientInfo->hWindowMenu ,wndPtr->wIDmenu , n & MF_CHECKED);
153 END:
154 WIN_ReleaseWndPtr(wndPtr);
155 return bRet;
158 /**********************************************************************
159 * MDI_MenuDeleteItem
161 static BOOL MDI_MenuDeleteItem(WND* clientWnd, HWND hWndChild )
163 WCHAR buffer[128];
164 static const WCHAR format[] = {'&','%','d',' ',0};
165 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
166 WND *wndPtr = WIN_FindWndPtr(hWndChild);
167 UINT index = 0,id,n;
168 BOOL retvalue;
170 if( !clientInfo->nActiveChildren ||
171 !clientInfo->hWindowMenu )
173 retvalue = FALSE;
174 goto END;
177 id = wndPtr->wIDmenu;
178 DeleteMenu(clientInfo->hWindowMenu,id,MF_BYCOMMAND);
180 /* walk the rest of MDI children to prevent gaps in the id
181 * sequence and in the menu child list */
183 for( index = id+1; index <= clientInfo->nActiveChildren +
184 clientInfo->idFirstChild; index++ )
186 WND *tmpWnd = WIN_FindWndPtr(MDI_GetChildByID(clientWnd,index));
187 if( !tmpWnd )
189 TRACE("no window for id=%i\n",index);
190 WIN_ReleaseWndPtr(tmpWnd);
191 continue;
194 /* set correct id */
195 tmpWnd->wIDmenu--;
197 n = wsprintfW(buffer, format ,index - clientInfo->idFirstChild);
198 if (tmpWnd->text)
199 lstrcpynW(buffer + n, tmpWnd->text, sizeof(buffer)/sizeof(WCHAR) - n );
201 /* change menu if the current child is to be shown in the
202 * "Windows" menu
204 if (index <= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
205 ModifyMenuW(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING,
206 index - 1 , buffer );
207 WIN_ReleaseWndPtr(tmpWnd);
210 /* We must restore the "More Windows..." option if there is enough child
212 if (clientInfo->nActiveChildren - 1 > MDI_MOREWINDOWSLIMIT)
214 char szTmp[50];
215 LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
217 AppendMenuA(clientInfo->hWindowMenu ,MF_STRING ,clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT, szTmp );
219 retvalue = TRUE;
220 END:
221 WIN_ReleaseWndPtr(wndPtr);
222 return retvalue;
225 /**********************************************************************
226 * MDI_GetWindow
228 * returns "activateable" child different from the current or zero
230 static HWND MDI_GetWindow(WND *clientWnd, HWND hWnd, BOOL bNext,
231 DWORD dwStyleMask )
233 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
234 WND *wndPtr, *pWnd, *pWndLast = NULL;
236 dwStyleMask |= WS_DISABLED | WS_VISIBLE;
237 if( !hWnd ) hWnd = clientInfo->hwndActiveChild;
239 if( !(wndPtr = WIN_FindWndPtr(hWnd)) ) return 0;
241 for ( pWnd = WIN_LockWndPtr(wndPtr->next); ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
243 if (!pWnd ) WIN_UpdateWndPtr(&pWnd,wndPtr->parent->child);
245 if ( pWnd == wndPtr ) break; /* went full circle */
247 if (!pWnd->owner && (pWnd->dwStyle & dwStyleMask) == WS_VISIBLE )
249 pWndLast = pWnd;
250 if ( bNext ) break;
253 WIN_ReleaseWndPtr(wndPtr);
254 WIN_ReleaseWndPtr(pWnd);
255 return pWndLast ? pWndLast->hwndSelf : 0;
258 /**********************************************************************
259 * MDI_CalcDefaultChildPos
261 * It seems that the default height is about 2/3 of the client rect
263 static void MDI_CalcDefaultChildPos( WND* w, WORD n, LPPOINT lpPos,
264 INT delta)
266 INT nstagger;
267 RECT rect = w->rectClient;
268 INT spacing = GetSystemMetrics(SM_CYCAPTION) +
269 GetSystemMetrics(SM_CYFRAME) - 1;
271 if( rect.bottom - rect.top - delta >= spacing )
272 rect.bottom -= delta;
274 nstagger = (rect.bottom - rect.top)/(3 * spacing);
275 lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
276 lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
277 lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
280 /**********************************************************************
281 * MDISetMenu
283 static LRESULT MDISetMenu( HWND hwnd, HMENU hmenuFrame,
284 HMENU hmenuWindow)
286 WND *w;
287 MDICLIENTINFO *ci;
288 HWND hwndFrame = GetParent(hwnd);
289 HMENU oldFrameMenu = GetMenu(hwndFrame);
291 TRACE("%04x %04x %04x\n",
292 hwnd, hmenuFrame, hmenuWindow);
294 if (hmenuFrame && !IsMenu(hmenuFrame))
296 WARN("hmenuFrame is not a menu handle\n");
297 return 0L;
300 if (hmenuWindow && !IsMenu(hmenuWindow))
302 WARN("hmenuWindow is not a menu handle\n");
303 return 0L;
306 w = WIN_FindWndPtr(hwnd);
307 ci = (MDICLIENTINFO *) w->wExtra;
309 if( ci->hwndChildMaximized && hmenuFrame && hmenuFrame!=oldFrameMenu )
310 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized );
312 if( hmenuWindow && ci->hWindowMenu && hmenuWindow!=ci->hWindowMenu )
314 /* delete menu items from ci->hWindowMenu
315 * and add them to hmenuWindow */
317 INT i = GetMenuItemCount(ci->hWindowMenu) - 1;
318 INT pos = GetMenuItemCount(hmenuWindow) + 1;
320 AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL);
322 if( ci->nActiveChildren )
324 INT j;
325 LPWSTR buffer = NULL;
326 MENUITEMINFOW mii;
327 INT nbWindowsMenuItems; /* num of documents shown + "More Windows..." if present */
329 if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
330 nbWindowsMenuItems = ci->nActiveChildren;
331 else
332 nbWindowsMenuItems = MDI_MOREWINDOWSLIMIT + 1;
334 j = i - nbWindowsMenuItems + 1;
336 for( ; i >= j ; i-- )
338 memset(&mii, 0, sizeof(mii));
339 mii.cbSize = sizeof(mii);
340 mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE
341 | MIIM_SUBMENU | MIIM_TYPE | MIIM_BITMAP;
343 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
344 if(mii.cch) { /* Menu is MFT_STRING */
345 mii.cch++; /* add room for '\0' */
346 buffer = HeapAlloc(GetProcessHeap(), 0,
347 mii.cch * sizeof(WCHAR));
348 mii.dwTypeData = buffer;
349 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
351 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
352 InsertMenuItemW(hmenuWindow, pos, TRUE, &mii);
353 if(buffer) {
354 HeapFree(GetProcessHeap(), 0, buffer);
355 buffer = NULL;
360 /* remove separator */
361 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
363 ci->hWindowMenu = hmenuWindow;
366 if (hmenuFrame)
368 SetMenu(hwndFrame, hmenuFrame);
369 if( hmenuFrame!=oldFrameMenu )
371 if( ci->hwndChildMaximized )
372 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
373 WIN_ReleaseWndPtr(w);
374 return oldFrameMenu;
377 else
379 INT nItems = GetMenuItemCount(w->parent->wIDmenu) - 1;
380 UINT iId = GetMenuItemID(w->parent->wIDmenu,nItems) ;
382 if( !(iId == SC_RESTORE || iId == SC_CLOSE) )
384 /* SetMenu() may already have been called, meaning that this window
385 * already has its menu. But they may have done a SetMenu() on
386 * an MDI window, and called MDISetMenu() after the fact, meaning
387 * that the "if" to this "else" wouldn't catch the need to
388 * augment the frame menu.
390 if( ci->hwndChildMaximized )
391 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
394 WIN_ReleaseWndPtr(w);
395 return 0;
398 /**********************************************************************
399 * MDIRefreshMenu
401 static LRESULT MDIRefreshMenu( HWND hwnd, HMENU hmenuFrame,
402 HMENU hmenuWindow)
404 HWND hwndFrame = GetParent(hwnd);
405 HMENU oldFrameMenu = GetMenu(hwndFrame);
407 TRACE("%04x %04x %04x\n",
408 hwnd, hmenuFrame, hmenuWindow);
410 FIXME("partially function stub\n");
412 return oldFrameMenu;
416 /* ------------------ MDI child window functions ---------------------- */
419 /**********************************************************************
420 * MDICreateChild
422 static HWND MDICreateChild( WND *w, MDICLIENTINFO *ci, HWND parent,
423 LPMDICREATESTRUCTA cs )
425 POINT pos[2];
426 DWORD style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
427 HWND hwnd, hwndMax = 0;
428 WORD wIDmenu = ci->idFirstChild + ci->nActiveChildren;
429 char lpstrDef[]="junk!";
431 TRACE("origin %i,%i - dim %i,%i, style %08lx\n",
432 cs->x, cs->y, cs->cx, cs->cy, cs->style);
433 /* calculate placement */
434 MDI_CalcDefaultChildPos(w, ci->nTotalCreated++, pos, 0);
436 if (cs->cx == CW_USEDEFAULT || !cs->cx) cs->cx = pos[1].x;
437 if (cs->cy == CW_USEDEFAULT || !cs->cy) cs->cy = pos[1].y;
439 if( cs->x == CW_USEDEFAULT )
441 cs->x = pos[0].x;
442 cs->y = pos[0].y;
445 /* restore current maximized child */
446 if( (style & WS_VISIBLE) && ci->hwndChildMaximized )
448 TRACE("Restoring current maximized child %04x\n", ci->hwndChildMaximized);
449 if( style & WS_MAXIMIZE )
450 SendMessageA(w->hwndSelf, WM_SETREDRAW, FALSE, 0L );
451 hwndMax = ci->hwndChildMaximized;
452 ShowWindow( hwndMax, SW_SHOWNOACTIVATE );
453 if( style & WS_MAXIMIZE )
454 SendMessageA(w->hwndSelf, WM_SETREDRAW, TRUE, 0L );
457 if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
458 /* this menu is needed to set a check mark in MDI_ChildActivate */
459 if (ci->hWindowMenu != 0)
460 AppendMenuA(ci->hWindowMenu ,MF_STRING ,wIDmenu, lpstrDef );
462 ci->nActiveChildren++;
464 /* fix window style */
465 if( !(w->dwStyle & MDIS_ALLCHILDSTYLES) )
467 TRACE("MDIS_ALLCHILDSTYLES is missing, fixing window style\n");
468 style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE |
469 WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL );
470 style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW);
473 if( w->flags & WIN_ISWIN32 )
475 hwnd = CreateWindowA( cs->szClass, cs->szTitle, style,
476 cs->x, cs->y, cs->cx, cs->cy, parent,
477 (HMENU)wIDmenu, cs->hOwner, cs );
479 else
481 MDICREATESTRUCT16 *cs16;
482 LPSTR title, cls;
484 cs16 = SEGPTR_NEW(MDICREATESTRUCT16);
485 STRUCT32_MDICREATESTRUCT32Ato16( cs, cs16 );
486 title = SEGPTR_STRDUP( cs->szTitle );
487 cls = SEGPTR_STRDUP( cs->szClass );
488 cs16->szTitle = SEGPTR_GET(title);
489 cs16->szClass = SEGPTR_GET(cls);
491 hwnd = CreateWindow16( cs->szClass, cs->szTitle, style,
492 cs16->x, cs16->y, cs16->cx, cs16->cy, parent,
493 (HMENU)wIDmenu, cs16->hOwner,
494 (LPVOID)SEGPTR_GET(cs16) );
495 SEGPTR_FREE( title );
496 SEGPTR_FREE( cls );
497 SEGPTR_FREE( cs16 );
500 /* MDI windows are WS_CHILD so they won't be activated by CreateWindow */
502 if (hwnd)
504 WND* wnd = WIN_FindWndPtr( hwnd );
506 /* All MDI child windows have the WS_EX_MDICHILD style */
507 wnd->dwExStyle |= WS_EX_MDICHILD;
509 /* If we have more than 9 windows, we must insert the new one at the
510 * 9th position in order to see it in the "Windows" menu
512 if (ci->nActiveChildren > MDI_MOREWINDOWSLIMIT)
513 MDI_SwapMenuItems(wnd->parent, wnd->wIDmenu, ci->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
515 MDI_MenuModifyItem(w ,hwnd);
517 /* Have we hit the "More Windows..." limit? If so, we must
518 * add a "More Windows..." option
520 if (ci->nActiveChildren == MDI_MOREWINDOWSLIMIT + 1)
522 char szTmp[50];
523 LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
525 ModifyMenuA(ci->hWindowMenu,
526 ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
527 MF_BYCOMMAND | MF_STRING,
528 ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
529 szTmp);
532 if( (wnd->dwStyle & WS_MINIMIZE) && ci->hwndActiveChild )
534 TRACE("Minimizing created MDI child %04x\n", hwnd);
535 ShowWindow( hwnd, SW_SHOWMINNOACTIVE );
537 else
539 /* WS_VISIBLE is clear if a) the MDI client has
540 * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the
541 * MDICreateStruct. If so the created window is not shown nor
542 * activated.
544 if(wnd->dwStyle & WS_VISIBLE)
545 ShowWindow(hwnd, SW_SHOW);
547 WIN_ReleaseWndPtr(wnd);
548 TRACE("created child - %04x\n",hwnd);
550 else
552 ci->nActiveChildren--;
553 DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
554 if( IsWindow(hwndMax) )
555 ShowWindow(hwndMax, SW_SHOWMAXIMIZED);
558 return hwnd;
561 /**********************************************************************
562 * MDI_ChildGetMinMaxInfo
564 * Note: The rule here is that client rect of the maximized MDI child
565 * is equal to the client rect of the MDI client window.
567 static void MDI_ChildGetMinMaxInfo( WND* clientWnd, HWND hwnd,
568 MINMAXINFO16* lpMinMax )
570 WND* childWnd = WIN_FindWndPtr(hwnd);
571 RECT rect = clientWnd->rectClient;
573 MapWindowPoints( clientWnd->parent->hwndSelf,
574 ((MDICLIENTINFO*)clientWnd->wExtra)->self, (LPPOINT)&rect, 2);
575 AdjustWindowRectEx( &rect, childWnd->dwStyle, 0, childWnd->dwExStyle );
577 lpMinMax->ptMaxSize.x = rect.right -= rect.left;
578 lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
580 lpMinMax->ptMaxPosition.x = rect.left;
581 lpMinMax->ptMaxPosition.y = rect.top;
583 WIN_ReleaseWndPtr(childWnd);
585 TRACE("max rect (%i,%i - %i, %i)\n",
586 rect.left,rect.top,rect.right,rect.bottom);
590 /**********************************************************************
591 * MDI_SwitchActiveChild
593 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
594 * being activated
596 static void MDI_SwitchActiveChild( HWND clientHwnd, HWND childHwnd,
597 BOOL bNextWindow )
599 WND *w = WIN_FindWndPtr(clientHwnd);
600 HWND hwndTo = 0;
601 HWND hwndPrev = 0;
602 MDICLIENTINFO *ci;
604 hwndTo = MDI_GetWindow(w, childHwnd, bNextWindow, 0);
606 ci = (MDICLIENTINFO *) w->wExtra;
608 TRACE("from %04x, to %04x\n",childHwnd,hwndTo);
610 if ( !hwndTo ) goto END; /* no window to switch to */
612 hwndPrev = ci->hwndActiveChild;
614 if ( hwndTo != hwndPrev )
616 BOOL bOptimize = 0;
618 if( ci->hwndChildMaximized )
620 bOptimize = 1;
621 w->dwStyle &= ~WS_VISIBLE;
624 SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0,
625 SWP_NOMOVE | SWP_NOSIZE );
627 if( bNextWindow && hwndPrev )
628 SetWindowPos( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0,
629 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
630 if( bOptimize )
631 ShowWindow( clientHwnd, SW_SHOW );
633 END:
634 WIN_ReleaseWndPtr(w);
638 /**********************************************************************
639 * MDIDestroyChild
641 static LRESULT MDIDestroyChild( WND *w_parent, MDICLIENTINFO *ci,
642 HWND parent, HWND child,
643 BOOL flagDestroy )
645 WND *childPtr = WIN_FindWndPtr(child);
647 if( childPtr )
649 if( child == ci->hwndActiveChild )
651 MDI_SwitchActiveChild(parent, child, TRUE);
653 if( child == ci->hwndActiveChild )
655 ShowWindow( child, SW_HIDE);
656 if( child == ci->hwndChildMaximized )
658 MDI_RestoreFrameMenu(w_parent->parent, child);
659 ci->hwndChildMaximized = 0;
660 MDI_UpdateFrameText(w_parent->parent,parent,TRUE,NULL);
663 MDI_ChildActivate(w_parent, 0);
667 MDI_MenuDeleteItem(w_parent, child);
669 WIN_ReleaseWndPtr(childPtr);
671 ci->nActiveChildren--;
673 TRACE("child destroyed - %04x\n",child);
675 if (flagDestroy)
677 MDI_PostUpdate(GetParent(child), ci, SB_BOTH+1);
678 DestroyWindow(child);
682 return 0;
686 /**********************************************************************
687 * MDI_ChildActivate
689 * Note: hWndChild is NULL when last child is being destroyed
691 static LONG MDI_ChildActivate( WND *clientPtr, HWND hWndChild )
693 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientPtr->wExtra;
694 HWND prevActiveWnd = clientInfo->hwndActiveChild;
695 WND *wndPtr = WIN_FindWndPtr( hWndChild );
696 WND *wndPrev = WIN_FindWndPtr( prevActiveWnd );
697 BOOL isActiveFrameWnd = 0;
698 LONG retvalue;
700 if( wndPtr )
702 if( wndPtr->dwStyle & WS_DISABLED )
704 retvalue = 0L;
705 goto END;
709 /* Don't activate if it is already active. Might happen
710 since ShowWindow DOES activate MDI children */
711 if (clientInfo->hwndActiveChild == hWndChild)
713 retvalue = 0L;
714 goto END;
717 TRACE("%04x\n", hWndChild);
719 if( GetActiveWindow() == clientPtr->parent->hwndSelf )
720 isActiveFrameWnd = TRUE;
722 /* deactivate prev. active child */
723 if( wndPrev )
725 wndPrev->dwStyle |= WS_SYSMENU;
726 SendMessageA( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
727 SendMessageA( prevActiveWnd, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
728 (LPARAM)hWndChild);
729 /* uncheck menu item */
730 if( clientInfo->hWindowMenu )
732 WORD wPrevID = wndPrev->wIDmenu - clientInfo->idFirstChild;
734 if (wPrevID < MDI_MOREWINDOWSLIMIT)
735 CheckMenuItem( clientInfo->hWindowMenu,
736 wndPrev->wIDmenu, 0);
737 else
738 CheckMenuItem( clientInfo->hWindowMenu,
739 clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1, 0);
743 /* set appearance */
744 if( clientInfo->hwndChildMaximized )
746 if( clientInfo->hwndChildMaximized != hWndChild ) {
747 if( hWndChild ) {
748 clientInfo->hwndActiveChild = hWndChild;
749 ShowWindow( hWndChild, SW_SHOWMAXIMIZED);
750 } else
751 ShowWindow( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
755 clientInfo->hwndActiveChild = hWndChild;
757 /* check if we have any children left */
758 if( !hWndChild )
760 if( isActiveFrameWnd )
761 SetFocus( clientInfo->self );
762 retvalue = 0;
763 goto END;
766 /* check menu item */
767 if( clientInfo->hWindowMenu )
769 /* The window to be activated must be displayed in the "Windows" menu */
770 if (wndPtr->wIDmenu >= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
772 MDI_SwapMenuItems(wndPtr->parent, wndPtr->wIDmenu, clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
773 MDI_MenuModifyItem(wndPtr->parent ,wndPtr->hwndSelf);
776 CheckMenuItem(clientInfo->hWindowMenu, wndPtr->wIDmenu, MF_CHECKED);
778 /* bring active child to the top */
779 SetWindowPos( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
781 if( isActiveFrameWnd )
783 SendMessageA( hWndChild, WM_NCACTIVATE, TRUE, 0L);
784 if( GetFocus() == clientInfo->self )
785 SendMessageA( clientInfo->self, WM_SETFOCUS,
786 (WPARAM)clientInfo->self, 0L );
787 else
788 SetFocus( clientInfo->self );
790 SendMessageA( hWndChild, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
791 (LPARAM)hWndChild );
792 retvalue = 1;
793 END:
794 WIN_ReleaseWndPtr(wndPtr);
795 WIN_ReleaseWndPtr(wndPrev);
796 return retvalue;
799 /* -------------------- MDI client window functions ------------------- */
801 /**********************************************************************
802 * CreateMDIMenuBitmap
804 static HBITMAP16 CreateMDIMenuBitmap(void)
806 HDC hDCSrc = CreateCompatibleDC(0);
807 HDC hDCDest = CreateCompatibleDC(hDCSrc);
808 HBITMAP16 hbClose = LoadBitmap16(0, MAKEINTRESOURCE16(OBM_CLOSE) );
809 HBITMAP16 hbCopy;
810 HANDLE16 hobjSrc, hobjDest;
812 hobjSrc = SelectObject(hDCSrc, hbClose);
813 hbCopy = CreateCompatibleBitmap(hDCSrc,GetSystemMetrics(SM_CXSIZE),GetSystemMetrics(SM_CYSIZE));
814 hobjDest = SelectObject(hDCDest, hbCopy);
816 BitBlt(hDCDest, 0, 0, GetSystemMetrics(SM_CXSIZE), GetSystemMetrics(SM_CYSIZE),
817 hDCSrc, GetSystemMetrics(SM_CXSIZE), 0, SRCCOPY);
819 SelectObject(hDCSrc, hobjSrc);
820 DeleteObject(hbClose);
821 DeleteDC(hDCSrc);
823 hobjSrc = SelectObject( hDCDest, GetStockObject(BLACK_PEN) );
825 MoveToEx( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, 0, NULL );
826 LineTo( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, GetSystemMetrics(SM_CYSIZE) - 1);
828 SelectObject(hDCDest, hobjSrc );
829 SelectObject(hDCDest, hobjDest);
830 DeleteDC(hDCDest);
832 return hbCopy;
835 /**********************************************************************
836 * MDICascade
838 static LONG MDICascade(WND* clientWnd, MDICLIENTINFO *ci)
840 WND** ppWnd;
841 UINT total;
843 if (ci->hwndChildMaximized)
844 SendMessageA( clientWnd->hwndSelf, WM_MDIRESTORE,
845 (WPARAM)ci->hwndChildMaximized, 0);
847 if (ci->nActiveChildren == 0) return 0;
849 if ((ppWnd = WIN_BuildWinArray(clientWnd, BWA_SKIPHIDDEN | BWA_SKIPOWNED |
850 BWA_SKIPICONIC, &total)))
852 WND** heapPtr = ppWnd;
853 if( total )
855 INT delta = 0, n = 0;
856 POINT pos[2];
857 if( total < ci->nActiveChildren )
858 delta = GetSystemMetrics(SM_CYICONSPACING) +
859 GetSystemMetrics(SM_CYICON);
861 /* walk the list (backwards) and move windows */
862 while (*ppWnd) ppWnd++;
863 while (ppWnd != heapPtr)
865 ppWnd--;
866 TRACE("move %04x to (%ld,%ld) size [%ld,%ld]\n",
867 (*ppWnd)->hwndSelf, pos[0].x, pos[0].y, pos[1].x, pos[1].y);
869 MDI_CalcDefaultChildPos(clientWnd, n++, pos, delta);
870 SetWindowPos( (*ppWnd)->hwndSelf, 0, pos[0].x, pos[0].y,
871 pos[1].x, pos[1].y,
872 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
875 WIN_ReleaseWinArray(heapPtr);
878 if( total < ci->nActiveChildren )
879 ArrangeIconicWindows( clientWnd->hwndSelf );
880 return 0;
883 /**********************************************************************
884 * MDITile
886 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM wParam )
888 WND** ppWnd;
889 UINT total = 0;
891 if (ci->hwndChildMaximized)
892 SendMessageA( wndClient->hwndSelf, WM_MDIRESTORE,
893 (WPARAM)ci->hwndChildMaximized, 0);
895 if (ci->nActiveChildren == 0) return;
897 ppWnd = WIN_BuildWinArray(wndClient, BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
898 ((wParam & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
900 TRACE("%u windows to tile\n", total);
902 if( ppWnd )
904 WND** heapPtr = ppWnd;
906 if( total )
908 RECT rect;
909 int x, y, xsize, ysize;
910 int rows, columns, r, c, i;
912 GetClientRect(wndClient->hwndSelf,&rect);
913 rows = (int) sqrt((double)total);
914 columns = total / rows;
916 if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */
918 i = rows;
919 rows = columns; /* exchange r and c */
920 columns = i;
923 if( total != ci->nActiveChildren)
925 y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
926 rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
929 ysize = rect.bottom / rows;
930 xsize = rect.right / columns;
932 for (x = i = 0, c = 1; c <= columns && *ppWnd; c++)
934 if (c == columns)
936 rows = total - i;
937 ysize = rect.bottom / rows;
940 y = 0;
941 for (r = 1; r <= rows && *ppWnd; r++, i++)
943 SetWindowPos((*ppWnd)->hwndSelf, 0, x, y, xsize, ysize,
944 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
945 y += ysize;
946 ppWnd++;
948 x += xsize;
951 WIN_ReleaseWinArray(heapPtr);
954 if( total < ci->nActiveChildren ) ArrangeIconicWindows( wndClient->hwndSelf );
957 /* ----------------------- Frame window ---------------------------- */
960 /**********************************************************************
961 * MDI_AugmentFrameMenu
963 static BOOL MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
964 HWND hChild )
966 WND* child = WIN_FindWndPtr(hChild);
967 HMENU hSysPopup = 0;
968 HBITMAP hSysMenuBitmap = 0;
970 TRACE("frame %p,child %04x\n",frame,hChild);
972 if( !frame->wIDmenu || !child->hSysMenu )
974 WIN_ReleaseWndPtr(child);
975 return 0;
977 WIN_ReleaseWndPtr(child);
979 /* create a copy of sysmenu popup and insert it into frame menu bar */
981 if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
982 return 0;
984 TRACE("\tgot popup %04x in sysmenu %04x\n",
985 hSysPopup, child->hSysMenu);
987 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
988 SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
989 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
990 SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
992 /* In Win 95 look, the system menu is replaced by the child icon */
994 if(TWEAK_WineLook > WIN31_LOOK)
996 HICON hIcon = GetClassLongA(hChild, GCL_HICONSM);
997 if (!hIcon)
998 hIcon = GetClassLongA(hChild, GCL_HICON);
999 if (hIcon)
1001 HDC hMemDC;
1002 HBITMAP hBitmap, hOldBitmap;
1003 HBRUSH hBrush;
1004 HDC hdc = GetDC(hChild);
1006 if (hdc)
1008 int cx, cy;
1009 cx = GetSystemMetrics(SM_CXSMICON);
1010 cy = GetSystemMetrics(SM_CYSMICON);
1011 hMemDC = CreateCompatibleDC(hdc);
1012 hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
1013 hOldBitmap = SelectObject(hMemDC, hBitmap);
1014 SetMapMode(hMemDC, MM_TEXT);
1015 hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
1016 DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL);
1017 SelectObject (hMemDC, hOldBitmap);
1018 DeleteObject(hBrush);
1019 DeleteDC(hMemDC);
1020 ReleaseDC(hChild, hdc);
1021 hSysMenuBitmap = hBitmap;
1025 else
1026 hSysMenuBitmap = hBmpClose;
1028 if( !InsertMenuA(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
1029 hSysPopup, (LPSTR)(DWORD)hSysMenuBitmap))
1031 TRACE("not inserted\n");
1032 DestroyMenu(hSysPopup);
1033 return 0;
1036 /* The close button is only present in Win 95 look */
1037 if(TWEAK_WineLook > WIN31_LOOK)
1039 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
1040 SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
1043 EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
1044 EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
1045 EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
1046 SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE);
1048 /* redraw menu */
1049 DrawMenuBar(frame->hwndSelf);
1051 return 1;
1054 /**********************************************************************
1055 * MDI_RestoreFrameMenu
1057 static BOOL MDI_RestoreFrameMenu( WND *frameWnd, HWND hChild )
1059 MENUITEMINFOA menuInfo;
1060 INT nItems = GetMenuItemCount(frameWnd->wIDmenu) - 1;
1061 UINT iId = GetMenuItemID(frameWnd->wIDmenu,nItems) ;
1063 TRACE("frameWnd %p,(%04x),child %04x,nIt=%d,iId=%d\n",
1064 frameWnd,frameWnd->hwndSelf,hChild,nItems,iId);
1066 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
1067 return 0;
1070 * Remove the system menu, If that menu is the icon of the window
1071 * as it is in win95, we have to delete the bitmap.
1073 menuInfo.cbSize = sizeof(MENUITEMINFOA);
1074 menuInfo.fMask = MIIM_DATA | MIIM_TYPE;
1076 GetMenuItemInfoA(frameWnd->wIDmenu,
1078 TRUE,
1079 &menuInfo);
1081 RemoveMenu(frameWnd->wIDmenu,0,MF_BYPOSITION);
1083 if ( (menuInfo.fType & MFT_BITMAP) &&
1084 (LOWORD(menuInfo.dwTypeData)!=0) &&
1085 (LOWORD(menuInfo.dwTypeData)!=hBmpClose) )
1087 DeleteObject((HBITMAP)LOWORD(menuInfo.dwTypeData));
1090 if(TWEAK_WineLook > WIN31_LOOK)
1092 /* close */
1093 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1095 /* restore */
1096 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1097 /* minimize */
1098 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1100 DrawMenuBar(frameWnd->hwndSelf);
1102 return 1;
1106 /**********************************************************************
1107 * MDI_UpdateFrameText
1109 * used when child window is maximized/restored
1111 * Note: lpTitle can be NULL
1113 static void MDI_UpdateFrameText( WND *frameWnd, HWND hClient,
1114 BOOL repaint, LPCWSTR lpTitle )
1116 WCHAR lpBuffer[MDI_MAXTITLELENGTH+1];
1117 WND* clientWnd = WIN_FindWndPtr(hClient);
1118 MDICLIENTINFO *ci = (MDICLIENTINFO *) clientWnd->wExtra;
1120 TRACE("repaint %i, frameText %s\n", repaint, (lpTitle)?debugstr_w(lpTitle):"NULL");
1122 if (!clientWnd)
1123 return;
1125 if (!ci)
1127 WIN_ReleaseWndPtr(clientWnd);
1128 return;
1131 /* store new "default" title if lpTitle is not NULL */
1132 if (lpTitle)
1134 if (ci->frameTitle) HeapFree( SystemHeap, 0, ci->frameTitle );
1135 ci->frameTitle = HEAP_strdupW( SystemHeap, 0, lpTitle );
1138 if (ci->frameTitle)
1140 WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );
1142 if( childWnd && childWnd->text )
1144 /* combine frame title and child title if possible */
1146 static const WCHAR lpBracket[] = {' ','-',' ','[',0};
1147 static const WCHAR lpBracket2[] = {']',0};
1148 int i_frame_text_length = strlenW(ci->frameTitle);
1149 int i_child_text_length = strlenW(childWnd->text);
1151 lstrcpynW( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
1153 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
1155 strcatW( lpBuffer, lpBracket );
1157 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
1159 strcatW( lpBuffer, childWnd->text );
1160 strcatW( lpBuffer, lpBracket2 );
1162 else
1164 lstrcpynW( lpBuffer + i_frame_text_length + 4,
1165 childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
1166 strcatW( lpBuffer, lpBracket2 );
1170 else
1172 lstrcpynW(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH+1 );
1174 WIN_ReleaseWndPtr(childWnd);
1177 else
1178 lpBuffer[0] = '\0';
1180 DEFWND_SetTextW( frameWnd, lpBuffer );
1181 if( repaint == MDI_REPAINTFRAME)
1182 SetWindowPos( frameWnd->hwndSelf, 0,0,0,0,0, SWP_FRAMECHANGED |
1183 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
1185 WIN_ReleaseWndPtr(clientWnd);
1190 /* ----------------------------- Interface ---------------------------- */
1193 /**********************************************************************
1194 * MDIClientWndProc
1196 * This function handles all MDI requests.
1198 LRESULT WINAPI MDIClientWndProc( HWND hwnd, UINT message, WPARAM wParam,
1199 LPARAM lParam )
1201 LPCREATESTRUCTA cs;
1202 MDICLIENTINFO *ci;
1203 RECT rect;
1204 WND *w, *frameWnd;
1205 INT nItems;
1206 LRESULT retvalue;
1208 if ( ( w = WIN_FindWndPtr(hwnd) ) == NULL )
1209 return 0;
1211 if ( ( frameWnd = WIN_LockWndPtr(w->parent) ) == NULL ) {
1212 WIN_ReleaseWndPtr(w);
1213 return 0;
1216 ci = (MDICLIENTINFO *) w->wExtra;
1218 switch (message)
1220 case WM_CREATE:
1222 cs = (LPCREATESTRUCTA)lParam;
1224 /* Translation layer doesn't know what's in the cs->lpCreateParams
1225 * so we have to keep track of what environment we're in. */
1227 if( w->flags & WIN_ISWIN32 )
1229 #define ccs ((LPCLIENTCREATESTRUCT)cs->lpCreateParams)
1230 ci->hWindowMenu = ccs->hWindowMenu;
1231 ci->idFirstChild = ccs->idFirstChild;
1232 #undef ccs
1234 else
1236 LPCLIENTCREATESTRUCT16 ccs = (LPCLIENTCREATESTRUCT16)
1237 PTR_SEG_TO_LIN(cs->lpCreateParams);
1238 ci->hWindowMenu = ccs->hWindowMenu;
1239 ci->idFirstChild = ccs->idFirstChild;
1242 ci->hwndChildMaximized = 0;
1243 ci->nActiveChildren = 0;
1244 ci->nTotalCreated = 0;
1245 ci->frameTitle = NULL;
1246 ci->mdiFlags = 0;
1247 ci->self = hwnd;
1248 w->dwStyle |= WS_CLIPCHILDREN;
1250 if (!hBmpClose)
1252 hBmpClose = CreateMDIMenuBitmap();
1253 hBmpRestore = LoadBitmap16( 0, MAKEINTRESOURCE16(OBM_RESTORE) );
1255 MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
1257 if (ci->hWindowMenu != 0)
1258 AppendMenuA( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
1260 GetClientRect(frameWnd->hwndSelf, &rect);
1261 NC_HandleNCCalcSize( w, &rect );
1262 w->rectClient = rect;
1264 TRACE("Client created - hwnd = %04x, idFirst = %u\n",
1265 hwnd, ci->idFirstChild );
1267 retvalue = 0;
1268 goto END;
1270 case WM_DESTROY:
1271 if( ci->hwndChildMaximized )
1272 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized);
1273 if((ci->hWindowMenu != 0) &&
1274 (nItems = GetMenuItemCount(ci->hWindowMenu)) > 0)
1276 ci->idFirstChild = nItems - 1;
1277 ci->nActiveChildren++; /* to delete a separator */
1278 while( ci->nActiveChildren-- )
1279 DeleteMenu(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
1281 retvalue = 0;
1282 goto END;
1284 case WM_MDIACTIVATE:
1285 if( ci->hwndActiveChild != (HWND)wParam )
1286 SetWindowPos((HWND)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
1287 retvalue = 0;
1288 goto END;
1290 case WM_MDICASCADE:
1291 retvalue = MDICascade(w, ci);
1292 goto END;
1294 case WM_MDICREATE:
1295 if (lParam) retvalue = MDICreateChild( w, ci, hwnd,
1296 (MDICREATESTRUCTA*)lParam );
1297 else retvalue = 0;
1298 goto END;
1300 case WM_MDIDESTROY:
1301 retvalue = MDIDestroyChild( w, ci, hwnd, (HWND)wParam, TRUE );
1302 goto END;
1304 case WM_MDIGETACTIVE:
1305 if (lParam) *(BOOL *)lParam = (ci->hwndChildMaximized > 0);
1306 retvalue = ci->hwndActiveChild;
1307 goto END;
1309 case WM_MDIICONARRANGE:
1310 ci->mdiFlags |= MDIF_NEEDUPDATE;
1311 ArrangeIconicWindows(hwnd);
1312 ci->sbRecalc = SB_BOTH+1;
1313 SendMessageA(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
1314 retvalue = 0;
1315 goto END;
1317 case WM_MDIMAXIMIZE:
1318 ShowWindow( (HWND)wParam, SW_MAXIMIZE );
1319 retvalue = 0;
1320 goto END;
1322 case WM_MDINEXT: /* lParam != 0 means previous window */
1323 MDI_SwitchActiveChild(hwnd, (HWND)wParam, (lParam)? FALSE : TRUE );
1324 break;
1326 case WM_MDIRESTORE:
1327 SendMessageA( (HWND)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
1328 retvalue = 0;
1329 goto END;
1331 case WM_MDISETMENU:
1332 retvalue = MDISetMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1333 goto END;
1334 case WM_MDIREFRESHMENU:
1335 retvalue = MDIRefreshMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1336 goto END;
1338 case WM_MDITILE:
1339 ci->mdiFlags |= MDIF_NEEDUPDATE;
1340 ShowScrollBar(hwnd,SB_BOTH,FALSE);
1341 MDITile(w, ci, wParam);
1342 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1343 retvalue = 0;
1344 goto END;
1346 case WM_VSCROLL:
1347 case WM_HSCROLL:
1348 ci->mdiFlags |= MDIF_NEEDUPDATE;
1349 ScrollChildren(hwnd, message, wParam, lParam);
1350 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1351 retvalue = 0;
1352 goto END;
1354 case WM_SETFOCUS:
1355 if( ci->hwndActiveChild )
1357 WND* pw = WIN_FindWndPtr( ci->hwndActiveChild );
1358 if( !(pw->dwStyle & WS_MINIMIZE) )
1359 SetFocus( ci->hwndActiveChild );
1360 WIN_ReleaseWndPtr(pw);
1362 retvalue = 0;
1363 goto END;
1365 case WM_NCACTIVATE:
1366 if( ci->hwndActiveChild )
1367 SendMessageA(ci->hwndActiveChild, message, wParam, lParam);
1368 break;
1370 case WM_PARENTNOTIFY:
1371 if (LOWORD(wParam) == WM_LBUTTONDOWN)
1373 HWND child;
1374 POINT pt;
1375 pt.x = SLOWORD(lParam);
1376 pt.y = SHIWORD(lParam);
1377 child = ChildWindowFromPoint(hwnd, pt);
1379 TRACE("notification from %04x (%li,%li)\n",child,pt.x,pt.y);
1381 if( child && child != hwnd && child != ci->hwndActiveChild )
1382 SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1384 retvalue = 0;
1385 goto END;
1387 case WM_SIZE:
1388 if( IsWindow(ci->hwndChildMaximized) )
1390 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1391 RECT rect;
1393 rect.left = 0;
1394 rect.top = 0;
1395 rect.right = LOWORD(lParam);
1396 rect.bottom = HIWORD(lParam);
1398 AdjustWindowRectEx(&rect, child->dwStyle, 0, child->dwExStyle);
1399 MoveWindow(ci->hwndChildMaximized, rect.left, rect.top,
1400 rect.right - rect.left, rect.bottom - rect.top, 1);
1401 WIN_ReleaseWndPtr(child);
1403 else
1404 MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1406 break;
1408 case WM_MDICALCCHILDSCROLL:
1409 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1411 CalcChildScroll16(hwnd, ci->sbRecalc-1);
1412 ci->sbRecalc = 0;
1413 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1415 retvalue = 0;
1416 goto END;
1419 retvalue = DefWindowProcA( hwnd, message, wParam, lParam );
1420 END:
1421 WIN_ReleaseWndPtr(w);
1422 WIN_ReleaseWndPtr(frameWnd);
1423 return retvalue;
1427 /***********************************************************************
1428 * DefFrameProc16 (USER.445)
1430 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1431 UINT16 message, WPARAM16 wParam, LPARAM lParam )
1433 HWND16 childHwnd;
1434 MDICLIENTINFO* ci;
1435 WND* wndPtr;
1437 if (hwndMDIClient)
1439 switch (message)
1441 case WM_COMMAND:
1442 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1444 if (!wndPtr) {
1445 ERR("null wndPtr for mdi window hwndMDIClient=%04x\n",
1446 hwndMDIClient);
1447 return 0;
1450 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1452 /* check for possible syscommands for maximized MDI child */
1453 WIN_ReleaseWndPtr(wndPtr);
1455 if( ci && (
1456 wParam < ci->idFirstChild ||
1457 wParam >= ci->idFirstChild + ci->nActiveChildren
1459 if( (wParam - 0xF000) & 0xF00F ) break;
1460 switch( wParam )
1462 case SC_SIZE:
1463 case SC_MOVE:
1464 case SC_MINIMIZE:
1465 case SC_MAXIMIZE:
1466 case SC_NEXTWINDOW:
1467 case SC_PREVWINDOW:
1468 case SC_CLOSE:
1469 case SC_RESTORE:
1470 if( ci->hwndChildMaximized )
1471 return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1472 wParam, lParam);
1475 else
1477 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1478 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1480 if (wParam - ci->idFirstChild == MDI_MOREWINDOWSLIMIT)
1481 /* User chose "More Windows..." */
1482 childHwnd = MDI_MoreWindowsDialog(wndPtr);
1483 else
1484 /* User chose one of the windows listed in the "Windows" menu */
1485 childHwnd = MDI_GetChildByID(wndPtr,wParam );
1487 WIN_ReleaseWndPtr(wndPtr);
1488 if( childHwnd )
1489 SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1490 (WPARAM16)childHwnd , 0L);
1492 break;
1494 case WM_NCACTIVATE:
1495 SendMessage16(hwndMDIClient, message, wParam, lParam);
1496 break;
1498 case WM_SETTEXT:
1500 LPWSTR text = HEAP_strdupAtoW( GetProcessHeap(), 0,
1501 (LPCSTR)PTR_SEG_TO_LIN(lParam) );
1502 wndPtr = WIN_FindWndPtr(hwnd);
1503 MDI_UpdateFrameText(wndPtr, hwndMDIClient,
1504 MDI_REPAINTFRAME, text );
1505 WIN_ReleaseWndPtr(wndPtr);
1506 HeapFree( GetProcessHeap(), 0, text );
1508 return 0;
1510 case WM_SETFOCUS:
1511 SetFocus(hwndMDIClient);
1512 break;
1514 case WM_SIZE:
1515 MoveWindow16(hwndMDIClient, 0, 0,
1516 LOWORD(lParam), HIWORD(lParam), TRUE);
1517 break;
1519 case WM_NEXTMENU:
1521 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1522 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1524 if( !(wndPtr->parent->dwStyle & WS_MINIMIZE)
1525 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1527 /* control menu is between the frame system menu and
1528 * the first entry of menu bar */
1530 if( (wParam == VK_LEFT &&
1531 wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1532 (wParam == VK_RIGHT &&
1533 GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1535 LRESULT retvalue;
1536 WIN_ReleaseWndPtr(wndPtr);
1537 wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1538 retvalue = MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1539 ci->hwndActiveChild);
1540 WIN_ReleaseWndPtr(wndPtr);
1541 return retvalue;
1544 WIN_ReleaseWndPtr(wndPtr);
1545 break;
1549 return DefWindowProc16(hwnd, message, wParam, lParam);
1553 /***********************************************************************
1554 * DefFrameProcA (USER32.122)
1556 LRESULT WINAPI DefFrameProcA( HWND hwnd, HWND hwndMDIClient,
1557 UINT message, WPARAM wParam, LPARAM lParam)
1559 if (hwndMDIClient)
1561 switch (message)
1563 case WM_COMMAND:
1564 return DefFrameProc16( hwnd, hwndMDIClient, message,
1565 (WPARAM16)wParam,
1566 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1568 case WM_NCACTIVATE:
1569 SendMessageA(hwndMDIClient, message, wParam, lParam);
1570 break;
1572 case WM_SETTEXT: {
1573 LRESULT ret;
1574 LPSTR segstr = SEGPTR_STRDUP((LPSTR)lParam);
1576 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1577 wParam, (LPARAM)SEGPTR_GET(segstr) );
1578 SEGPTR_FREE(segstr);
1579 return ret;
1582 case WM_NEXTMENU:
1583 case WM_SETFOCUS:
1584 case WM_SIZE:
1585 return DefFrameProc16( hwnd, hwndMDIClient, message,
1586 wParam, lParam );
1590 return DefWindowProcA(hwnd, message, wParam, lParam);
1594 /***********************************************************************
1595 * DefFrameProcW (USER32.123)
1597 LRESULT WINAPI DefFrameProcW( HWND hwnd, HWND hwndMDIClient,
1598 UINT message, WPARAM wParam, LPARAM lParam)
1600 if (hwndMDIClient)
1602 switch (message)
1604 case WM_COMMAND:
1605 return DefFrameProc16( hwnd, hwndMDIClient, message,
1606 (WPARAM16)wParam,
1607 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1609 case WM_NCACTIVATE:
1610 SendMessageW(hwndMDIClient, message, wParam, lParam);
1611 break;
1613 case WM_SETTEXT:
1615 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1616 LRESULT ret = DefFrameProcA( hwnd, hwndMDIClient, message,
1617 wParam, (DWORD)txt );
1618 HeapFree(GetProcessHeap(),0,txt);
1619 return ret;
1621 case WM_NEXTMENU:
1622 case WM_SETFOCUS:
1623 case WM_SIZE:
1624 return DefFrameProcA( hwnd, hwndMDIClient, message,
1625 wParam, lParam );
1629 return DefWindowProcW( hwnd, message, wParam, lParam );
1633 /***********************************************************************
1634 * DefMDIChildProc16 (USER.447)
1636 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1637 WPARAM16 wParam, LPARAM lParam )
1639 MDICLIENTINFO *ci;
1640 WND *clientWnd,*tmpWnd = 0;
1641 LRESULT retvalue;
1643 tmpWnd = WIN_FindWndPtr(hwnd);
1644 if (!tmpWnd) return 0;
1645 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1646 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1647 WIN_ReleaseWndPtr(tmpWnd);
1649 /* Sanity check */
1650 if (clientWnd->class->cbWndExtra < sizeof(MDICLIENTINFO))
1652 WARN("called on non-MDI child window %x\n", hwnd);
1653 WIN_ReleaseWndPtr(clientWnd);
1654 return DefWindowProc16(hwnd, message, wParam, lParam);
1657 switch (message)
1659 case WM_SETTEXT:
1660 DefWindowProc16(hwnd, message, wParam, lParam);
1661 MDI_MenuModifyItem(clientWnd,hwnd);
1662 if( ci->hwndChildMaximized == hwnd )
1663 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1664 MDI_REPAINTFRAME, NULL );
1665 retvalue = 0;
1666 goto END;
1668 case WM_CLOSE:
1669 SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1670 retvalue = 0;
1671 goto END;
1673 case WM_SETFOCUS:
1674 if( ci->hwndActiveChild != hwnd )
1675 MDI_ChildActivate(clientWnd, hwnd);
1676 break;
1678 case WM_CHILDACTIVATE:
1679 MDI_ChildActivate(clientWnd, hwnd);
1680 retvalue = 0;
1681 goto END;
1683 case WM_NCPAINT:
1684 TRACE("WM_NCPAINT for %04x, active %04x\n",
1685 hwnd, ci->hwndActiveChild );
1686 break;
1688 case WM_SYSCOMMAND:
1689 switch( wParam )
1691 case SC_MOVE:
1692 if( ci->hwndChildMaximized == hwnd)
1694 retvalue = 0;
1695 goto END;
1697 break;
1698 case SC_RESTORE:
1699 case SC_MINIMIZE:
1700 tmpWnd = WIN_FindWndPtr(hwnd);
1701 tmpWnd->dwStyle |= WS_SYSMENU;
1702 WIN_ReleaseWndPtr(tmpWnd);
1703 break;
1704 case SC_MAXIMIZE:
1705 if( ci->hwndChildMaximized == hwnd)
1707 retvalue = SendMessage16( clientWnd->parent->hwndSelf,
1708 message, wParam, lParam);
1709 goto END;
1711 tmpWnd = WIN_FindWndPtr(hwnd);
1712 tmpWnd->dwStyle &= ~WS_SYSMENU;
1713 WIN_ReleaseWndPtr(tmpWnd);
1714 break;
1715 case SC_NEXTWINDOW:
1716 SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1717 retvalue = 0;
1718 goto END;
1719 case SC_PREVWINDOW:
1720 SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1721 retvalue = 0;
1722 goto END;
1724 break;
1726 case WM_GETMINMAXINFO:
1727 MDI_ChildGetMinMaxInfo(clientWnd, hwnd, (MINMAXINFO16*) PTR_SEG_TO_LIN(lParam));
1728 retvalue = 0;
1729 goto END;
1731 case WM_SETVISIBLE:
1732 if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1733 else
1734 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1735 break;
1737 case WM_SIZE:
1738 /* do not change */
1740 if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1742 ci->hwndChildMaximized = 0;
1744 MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1745 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1746 MDI_REPAINTFRAME, NULL );
1749 if( wParam == SIZE_MAXIMIZED )
1751 HWND16 hMaxChild = ci->hwndChildMaximized;
1753 if( hMaxChild == hwnd ) break;
1755 if( hMaxChild)
1757 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1759 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1760 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1762 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1765 TRACE("maximizing child %04x\n", hwnd );
1768 * Keep track of the maximized window.
1770 ci->hwndChildMaximized = hwnd; /* !!! */
1773 * The maximized window should also be the active window
1775 MDI_ChildActivate(clientWnd, hwnd);
1777 MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1778 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1779 MDI_REPAINTFRAME, NULL );
1782 if( wParam == SIZE_MINIMIZED )
1784 HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1786 if( switchTo )
1787 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1790 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1791 break;
1793 case WM_MENUCHAR:
1795 /* MDI children don't have menu bars */
1796 retvalue = 0x00010000L;
1797 goto END;
1799 case WM_NEXTMENU:
1801 if( wParam == VK_LEFT ) /* switch to frame system menu */
1803 retvalue = MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1804 clientWnd->parent->hwndSelf );
1805 goto END;
1807 if( wParam == VK_RIGHT ) /* to frame menu bar */
1809 retvalue = MAKELONG( clientWnd->parent->wIDmenu,
1810 clientWnd->parent->hwndSelf );
1811 goto END;
1814 break;
1816 case WM_SYSCHAR:
1817 if (wParam == '-')
1819 SendMessage16(hwnd,WM_SYSCOMMAND,
1820 (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1821 retvalue = 0;
1822 goto END;
1826 retvalue = DefWindowProc16(hwnd, message, wParam, lParam);
1827 END:
1828 WIN_ReleaseWndPtr(clientWnd);
1829 return retvalue;
1833 /***********************************************************************
1834 * DefMDIChildProcA (USER32.124)
1836 LRESULT WINAPI DefMDIChildProcA( HWND hwnd, UINT message,
1837 WPARAM wParam, LPARAM lParam )
1839 MDICLIENTINFO *ci;
1840 WND *clientWnd,*tmpWnd;
1841 LRESULT retvalue;
1843 tmpWnd = WIN_FindWndPtr(hwnd);
1844 if (!tmpWnd) return 0;
1845 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1846 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1847 WIN_ReleaseWndPtr(tmpWnd);
1849 /* Sanity check */
1850 if (clientWnd->class->cbWndExtra < sizeof(MDICLIENTINFO))
1852 WARN("called on non-MDI child window %x\n", hwnd);
1853 WIN_ReleaseWndPtr(clientWnd);
1854 return DefWindowProcA(hwnd, message, wParam, lParam);
1857 switch (message)
1859 case WM_SETTEXT:
1860 DefWindowProcA(hwnd, message, wParam, lParam);
1861 MDI_MenuModifyItem(clientWnd,hwnd);
1862 if( ci->hwndChildMaximized == hwnd )
1863 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1864 MDI_REPAINTFRAME, NULL );
1865 retvalue = 0;
1866 goto END;
1868 case WM_GETMINMAXINFO:
1870 MINMAXINFO16 mmi;
1871 STRUCT32_MINMAXINFO32to16( (MINMAXINFO *)lParam, &mmi );
1872 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1873 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO *)lParam );
1875 retvalue = 0;
1876 goto END;
1878 case WM_MENUCHAR:
1880 /* MDI children don't have menu bars */
1881 retvalue = 0x00010000L;
1882 goto END;
1884 case WM_CLOSE:
1885 case WM_SETFOCUS:
1886 case WM_CHILDACTIVATE:
1887 case WM_NCPAINT:
1888 case WM_SYSCOMMAND:
1889 case WM_SETVISIBLE:
1890 case WM_SIZE:
1891 case WM_NEXTMENU:
1892 retvalue = DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1893 goto END;
1895 case WM_SYSCHAR:
1896 if (wParam == '-')
1898 SendMessageA(hwnd,WM_SYSCOMMAND,
1899 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1900 retvalue = 0;
1901 goto END;
1904 retvalue = DefWindowProcA(hwnd, message, wParam, lParam);
1905 END:
1906 WIN_ReleaseWndPtr(clientWnd);
1907 return retvalue;
1911 /***********************************************************************
1912 * DefMDIChildProcW (USER32.125)
1914 LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message,
1915 WPARAM wParam, LPARAM lParam )
1917 MDICLIENTINFO *ci;
1918 WND *clientWnd,*tmpWnd;
1919 LRESULT retvalue;
1921 tmpWnd = WIN_FindWndPtr(hwnd);
1922 if (!tmpWnd) return 0;
1923 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1924 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1925 WIN_ReleaseWndPtr(tmpWnd);
1927 /* Sanity check */
1928 if (clientWnd->class->cbWndExtra < sizeof(MDICLIENTINFO))
1930 WARN("called on non-MDI child window %x\n", hwnd);
1931 WIN_ReleaseWndPtr(clientWnd);
1932 return DefWindowProcW(hwnd, message, wParam, lParam);
1935 switch (message)
1937 case WM_SETTEXT:
1938 DefWindowProcW(hwnd, message, wParam, lParam);
1939 MDI_MenuModifyItem(clientWnd,hwnd);
1940 if( ci->hwndChildMaximized == hwnd )
1941 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1942 MDI_REPAINTFRAME, NULL );
1943 retvalue = 0;
1944 goto END;
1946 case WM_GETMINMAXINFO:
1947 case WM_MENUCHAR:
1948 case WM_CLOSE:
1949 case WM_SETFOCUS:
1950 case WM_CHILDACTIVATE:
1951 case WM_NCPAINT:
1952 case WM_SYSCOMMAND:
1953 case WM_SETVISIBLE:
1954 case WM_SIZE:
1955 case WM_NEXTMENU:
1956 retvalue = DefMDIChildProcA( hwnd, message, (WPARAM16)wParam, lParam );
1957 goto END;
1959 case WM_SYSCHAR:
1960 if (wParam == '-')
1962 SendMessageW(hwnd,WM_SYSCOMMAND,
1963 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1964 retvalue = 0;
1965 goto END;
1968 retvalue = DefWindowProcW(hwnd, message, wParam, lParam);
1969 END:
1970 WIN_ReleaseWndPtr(clientWnd);
1971 return retvalue;
1976 /**********************************************************************
1977 * CreateMDIWindowA [USER32.79] Creates a MDI child in new thread
1978 * FIXME: its in the same thread now
1980 * RETURNS
1981 * Success: Handle to created window
1982 * Failure: NULL
1984 HWND WINAPI CreateMDIWindowA(
1985 LPCSTR lpClassName, /* [in] Pointer to registered child class name */
1986 LPCSTR lpWindowName, /* [in] Pointer to window name */
1987 DWORD dwStyle, /* [in] Window style */
1988 INT X, /* [in] Horizontal position of window */
1989 INT Y, /* [in] Vertical position of window */
1990 INT nWidth, /* [in] Width of window */
1991 INT nHeight, /* [in] Height of window */
1992 HWND hWndParent, /* [in] Handle to parent window */
1993 HINSTANCE hInstance, /* [in] Handle to application instance */
1994 LPARAM lParam) /* [in] Application-defined value */
1996 WARN("is only single threaded!\n");
1997 return MDI_CreateMDIWindowA(lpClassName, lpWindowName, dwStyle, X, Y,
1998 nWidth, nHeight, hWndParent, hInstance, lParam);
2001 /**********************************************************************
2002 * MDI_CreateMDIWindowA
2003 * single threaded version of CreateMDIWindowA
2004 * called by CreateWindowExA
2006 HWND MDI_CreateMDIWindowA(
2007 LPCSTR lpClassName,
2008 LPCSTR lpWindowName,
2009 DWORD dwStyle,
2010 INT X,
2011 INT Y,
2012 INT nWidth,
2013 INT nHeight,
2014 HWND hWndParent,
2015 HINSTANCE hInstance,
2016 LPARAM lParam)
2018 MDICLIENTINFO* pCi;
2019 MDICREATESTRUCTA cs;
2020 WND *pWnd=WIN_FindWndPtr(hWndParent);
2021 HWND retvalue;
2023 TRACE("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
2024 debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
2025 nWidth,nHeight,hWndParent,hInstance,lParam);
2027 if(!pWnd){
2028 ERR(" bad hwnd for MDI-client: %d\n",hWndParent);
2029 return 0;
2031 cs.szClass=lpClassName;
2032 cs.szTitle=lpWindowName;
2033 cs.hOwner=hInstance;
2034 cs.x=X;
2035 cs.y=Y;
2036 cs.cx=nWidth;
2037 cs.cy=nHeight;
2038 cs.style=dwStyle;
2039 cs.lParam=lParam;
2041 pCi=(MDICLIENTINFO *)pWnd->wExtra;
2043 retvalue = MDICreateChild(pWnd,pCi,hWndParent,&cs);
2044 WIN_ReleaseWndPtr(pWnd);
2045 return retvalue;
2048 /***********************************************************************
2049 * CreateMDIWindowW [USER32.80] Creates a MDI child in new thread
2051 * RETURNS
2052 * Success: Handle to created window
2053 * Failure: NULL
2055 HWND WINAPI CreateMDIWindowW(
2056 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
2057 LPCWSTR lpWindowName, /* [in] Pointer to window name */
2058 DWORD dwStyle, /* [in] Window style */
2059 INT X, /* [in] Horizontal position of window */
2060 INT Y, /* [in] Vertical position of window */
2061 INT nWidth, /* [in] Width of window */
2062 INT nHeight, /* [in] Height of window */
2063 HWND hWndParent, /* [in] Handle to parent window */
2064 HINSTANCE hInstance, /* [in] Handle to application instance */
2065 LPARAM lParam) /* [in] Application-defined value */
2067 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
2068 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
2069 nWidth,nHeight,hWndParent,hInstance,lParam);
2070 return (HWND)NULL;
2074 /******************************************************************************
2075 * CreateMDIWindowW [USER32.80] Creates a MDI child window
2076 * single threaded version of CreateMDIWindow
2077 * called by CreateWindowExW().
2079 HWND MDI_CreateMDIWindowW(
2080 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
2081 LPCWSTR lpWindowName, /* [in] Pointer to window name */
2082 DWORD dwStyle, /* [in] Window style */
2083 INT X, /* [in] Horizontal position of window */
2084 INT Y, /* [in] Vertical position of window */
2085 INT nWidth, /* [in] Width of window */
2086 INT nHeight, /* [in] Height of window */
2087 HWND hWndParent, /* [in] Handle to parent window */
2088 HINSTANCE hInstance, /* [in] Handle to application instance */
2089 LPARAM lParam) /* [in] Application-defined value */
2091 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
2092 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
2093 nWidth,nHeight,hWndParent,hInstance,lParam);
2094 return (HWND)NULL;
2098 /**********************************************************************
2099 * TranslateMDISysAccel (USER32.555)
2101 BOOL WINAPI TranslateMDISysAccel( HWND hwndClient, LPMSG msg )
2103 MSG16 msg16;
2105 STRUCT32_MSG32to16(msg,&msg16);
2106 /* MDICLIENTINFO is still the same for win32 and win16 ... */
2107 return TranslateMDISysAccel16(hwndClient,&msg16);
2111 /**********************************************************************
2112 * TranslateMDISysAccel16 (USER.451)
2114 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
2117 if( IsWindow(hwndClient) && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
2119 MDICLIENTINFO *ci = NULL;
2120 HWND wnd;
2121 WND *clientWnd = WIN_FindWndPtr(hwndClient);
2123 ci = (MDICLIENTINFO*) clientWnd->wExtra;
2124 wnd = ci->hwndActiveChild;
2126 WIN_ReleaseWndPtr(clientWnd);
2128 if( IsWindow(wnd) && !(GetWindowLongA(wnd,GWL_STYLE) & WS_DISABLED) )
2130 WPARAM16 wParam = 0;
2132 /* translate if the Ctrl key is down and Alt not. */
2134 if( (GetKeyState(VK_CONTROL) & 0x8000) &&
2135 !(GetKeyState(VK_MENU) & 0x8000))
2137 switch( msg->wParam )
2139 case VK_F6:
2140 case VK_TAB:
2141 wParam = ( GetKeyState(VK_SHIFT) & 0x8000 )
2142 ? SC_NEXTWINDOW : SC_PREVWINDOW;
2143 break;
2144 case VK_F4:
2145 case VK_RBUTTON:
2146 wParam = SC_CLOSE;
2147 break;
2148 default:
2149 return 0;
2151 TRACE("wParam = %04x\n", wParam);
2152 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
2153 wParam, (LPARAM)msg->wParam);
2154 return 1;
2158 return 0; /* failure */
2162 /***********************************************************************
2163 * CalcChildScroll (USER.462)
2165 void WINAPI CalcChildScroll16( HWND16 hwnd, WORD scroll )
2167 SCROLLINFO info;
2168 RECT childRect, clientRect;
2169 INT vmin, vmax, hmin, hmax, vpos, hpos;
2170 WND *pWnd, *Wnd;
2172 if (!(pWnd = WIN_FindWndPtr( hwnd ))) return;
2173 Wnd = WIN_FindWndPtr(hwnd);
2174 GetClientRect( hwnd, &clientRect );
2175 SetRectEmpty( &childRect );
2177 for ( WIN_UpdateWndPtr(&pWnd,pWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2179 if( pWnd->dwStyle & WS_MAXIMIZE )
2181 ShowScrollBar(hwnd, SB_BOTH, FALSE);
2182 WIN_ReleaseWndPtr(pWnd);
2183 WIN_ReleaseWndPtr(Wnd);
2184 return;
2186 UnionRect( &childRect, &pWnd->rectWindow, &childRect );
2188 WIN_ReleaseWndPtr(pWnd);
2189 UnionRect( &childRect, &clientRect, &childRect );
2191 hmin = childRect.left; hmax = childRect.right - clientRect.right;
2192 hpos = clientRect.left - childRect.left;
2193 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
2194 vpos = clientRect.top - childRect.top;
2196 switch( scroll )
2198 case SB_HORZ:
2199 vpos = hpos; vmin = hmin; vmax = hmax;
2200 case SB_VERT:
2201 info.cbSize = sizeof(info);
2202 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
2203 info.fMask = SIF_POS | SIF_RANGE;
2204 SetScrollInfo(hwnd, scroll, &info, TRUE);
2205 break;
2206 case SB_BOTH:
2207 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
2208 hmin, hmax, hpos);
2210 WIN_ReleaseWndPtr(Wnd);
2214 /***********************************************************************
2215 * ScrollChildren16 (USER.463)
2217 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
2219 ScrollChildren( hWnd, uMsg, wParam, lParam );
2223 /***********************************************************************
2224 * ScrollChildren (USER32.448)
2226 void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
2227 LPARAM lParam)
2229 WND *wndPtr = WIN_FindWndPtr(hWnd);
2230 INT newPos = -1;
2231 INT curPos, length, minPos, maxPos, shift;
2233 if( !wndPtr ) return;
2235 if( uMsg == WM_HSCROLL )
2237 GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
2238 curPos = GetScrollPos(hWnd,SB_HORZ);
2239 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
2240 shift = GetSystemMetrics(SM_CYHSCROLL);
2242 else if( uMsg == WM_VSCROLL )
2244 GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
2245 curPos = GetScrollPos(hWnd,SB_VERT);
2246 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
2247 shift = GetSystemMetrics(SM_CXVSCROLL);
2249 else
2251 WIN_ReleaseWndPtr(wndPtr);
2252 return;
2255 WIN_ReleaseWndPtr(wndPtr);
2256 switch( wParam )
2258 case SB_LINEUP:
2259 newPos = curPos - shift;
2260 break;
2261 case SB_LINEDOWN:
2262 newPos = curPos + shift;
2263 break;
2264 case SB_PAGEUP:
2265 newPos = curPos - length;
2266 break;
2267 case SB_PAGEDOWN:
2268 newPos = curPos + length;
2269 break;
2271 case SB_THUMBPOSITION:
2272 newPos = LOWORD(lParam);
2273 break;
2275 case SB_THUMBTRACK:
2276 return;
2278 case SB_TOP:
2279 newPos = minPos;
2280 break;
2281 case SB_BOTTOM:
2282 newPos = maxPos;
2283 break;
2284 case SB_ENDSCROLL:
2285 CalcChildScroll16(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
2286 return;
2289 if( newPos > maxPos )
2290 newPos = maxPos;
2291 else
2292 if( newPos < minPos )
2293 newPos = minPos;
2295 SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
2297 if( uMsg == WM_VSCROLL )
2298 ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
2299 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2300 else
2301 ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
2302 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2306 /******************************************************************************
2307 * CascadeWindows [USER32.21] Cascades MDI child windows
2309 * RETURNS
2310 * Success: Number of cascaded windows.
2311 * Failure: 0
2313 WORD WINAPI
2314 CascadeWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2315 UINT cKids, const HWND *lpKids)
2317 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2318 hwndParent, wFlags, cKids);
2320 return 0;
2324 /******************************************************************************
2325 * TileWindows [USER32.545] Tiles MDI child windows
2327 * RETURNS
2328 * Success: Number of tiled windows.
2329 * Failure: 0
2331 WORD WINAPI
2332 TileWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2333 UINT cKids, const HWND *lpKids)
2335 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2336 hwndParent, wFlags, cKids);
2338 return 0;
2341 /************************************************************************
2342 * "More Windows..." functionality
2345 /* MDI_MoreWindowsDlgProc
2347 * This function will process the messages sent to the "More Windows..."
2348 * dialog.
2349 * Return values: 0 = cancel pressed
2350 * HWND = ok pressed or double-click in the list...
2354 static BOOL WINAPI MDI_MoreWindowsDlgProc (HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
2356 switch (iMsg)
2358 case WM_INITDIALOG:
2360 WND *pWnd;
2361 UINT widest = 0;
2362 UINT length;
2363 UINT i;
2364 WND *pParentWnd = (WND *)lParam;
2365 MDICLIENTINFO *ci = (MDICLIENTINFO*)pParentWnd->wExtra;
2366 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2368 /* Fill the list, sorted by id... */
2369 for (i = 0; i < ci->nActiveChildren; i++)
2372 /* Find the window with the current ID */
2373 for (pWnd = WIN_LockWndPtr(pParentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd, pWnd->next))
2374 if (pWnd->wIDmenu == ci->idFirstChild + i)
2375 break;
2377 SendMessageW(hListBox, LB_ADDSTRING, 0, (LPARAM) pWnd->text);
2378 SendMessageA(hListBox, LB_SETITEMDATA, i, (LPARAM) pWnd);
2379 length = strlenW(pWnd->text);
2380 WIN_ReleaseWndPtr(pWnd);
2382 if (length > widest)
2383 widest = length;
2385 /* Make sure the horizontal scrollbar scrolls ok */
2386 SendMessageA(hListBox, LB_SETHORIZONTALEXTENT, widest * 6, 0);
2388 /* Set the current selection */
2389 SendMessageA(hListBox, LB_SETCURSEL, MDI_MOREWINDOWSLIMIT, 0);
2390 return TRUE;
2393 case WM_COMMAND:
2394 switch (LOWORD(wParam))
2396 case IDOK:
2398 /* windows are sorted by menu ID, so we must return the
2399 * window associated to the given id
2401 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2402 UINT index = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
2403 WND* pWnd = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
2405 EndDialog(hDlg, pWnd->hwndSelf);
2406 return TRUE;
2408 case IDCANCEL:
2409 EndDialog(hDlg, 0);
2410 return TRUE;
2412 default:
2413 switch (HIWORD(wParam))
2415 case LBN_DBLCLK:
2417 /* windows are sorted by menu ID, so we must return the
2418 * window associated to the given id
2420 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2421 UINT index = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
2422 WND* pWnd = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
2424 EndDialog(hDlg, pWnd->hwndSelf);
2425 return TRUE;
2428 break;
2430 break;
2432 return FALSE;
2437 * MDI_MoreWindowsDialog
2439 * Prompts the user with a listbox containing the opened
2440 * documents. The user can then choose a windows and click
2441 * on OK to set the current window to the one selected, or
2442 * CANCEL to cancel. The function returns a handle to the
2443 * selected window.
2446 static HWND MDI_MoreWindowsDialog(WND* wndPtr)
2448 LPCVOID template;
2449 HRSRC hRes;
2450 HANDLE hDlgTmpl;
2452 hRes = FindResourceA(GetModuleHandleA("USER32"), "MDI_MOREWINDOWS", RT_DIALOGA);
2454 if (hRes == 0)
2455 return 0;
2457 hDlgTmpl = LoadResource(GetModuleHandleA("USER32"), hRes );
2459 if (hDlgTmpl == 0)
2460 return 0;
2462 template = LockResource( hDlgTmpl );
2464 if (template == 0)
2465 return 0;
2467 return (HWND) DialogBoxIndirectParamA(GetModuleHandleA("USER32"),
2468 (LPDLGTEMPLATEA) template,
2469 wndPtr->hwndSelf,
2470 (DLGPROC) MDI_MoreWindowsDlgProc,
2471 (LPARAM) wndPtr);
2476 * MDI_SwapMenuItems
2478 * Will swap the menu IDs for the given 2 positions.
2479 * pos1 and pos2 are menu IDs
2484 static void MDI_SwapMenuItems(WND *parentWnd, UINT pos1, UINT pos2)
2486 WND *pWnd;
2488 for (pWnd = WIN_LockWndPtr(parentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2490 if (pWnd->wIDmenu == pos1)
2491 pWnd->wIDmenu = pos2;
2492 else
2493 if (pWnd->wIDmenu == pos2)
2494 pWnd->wIDmenu = pos1;
2497 WIN_ReleaseWndPtr(pWnd);