With some apps a fault was possible in ExtractAssociatedIcon.
[wine.git] / windows / mdi.c
blob3d5cabfbc45338099945c37c9938342c9f2ef779
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, LPCSTR);
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 char buffer[128];
132 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
133 WND *wndPtr = WIN_FindWndPtr(hWndChild);
134 UINT n = sprintf(buffer, "%d ",
135 wndPtr->wIDmenu - clientInfo->idFirstChild + 1);
136 BOOL bRet = 0;
138 if( !clientInfo->hWindowMenu )
140 bRet = FALSE;
141 goto END;
144 if (wndPtr->text) lstrcpynA(buffer + n, wndPtr->text, sizeof(buffer) - n );
146 n = GetMenuState(clientInfo->hWindowMenu,wndPtr->wIDmenu ,MF_BYCOMMAND);
147 bRet = ModifyMenuA(clientInfo->hWindowMenu , wndPtr->wIDmenu,
148 MF_BYCOMMAND | MF_STRING, wndPtr->wIDmenu, buffer );
149 CheckMenuItem(clientInfo->hWindowMenu ,wndPtr->wIDmenu , n & MF_CHECKED);
150 END:
151 WIN_ReleaseWndPtr(wndPtr);
152 return bRet;
155 /**********************************************************************
156 * MDI_MenuDeleteItem
158 static BOOL MDI_MenuDeleteItem(WND* clientWnd, HWND hWndChild )
160 char buffer[128];
161 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
162 WND *wndPtr = WIN_FindWndPtr(hWndChild);
163 UINT index = 0,id,n;
164 BOOL retvalue;
166 if( !clientInfo->nActiveChildren ||
167 !clientInfo->hWindowMenu )
169 retvalue = FALSE;
170 goto END;
173 id = wndPtr->wIDmenu;
174 DeleteMenu(clientInfo->hWindowMenu,id,MF_BYCOMMAND);
176 /* walk the rest of MDI children to prevent gaps in the id
177 * sequence and in the menu child list */
179 for( index = id+1; index <= clientInfo->nActiveChildren +
180 clientInfo->idFirstChild; index++ )
182 WND *tmpWnd = WIN_FindWndPtr(MDI_GetChildByID(clientWnd,index));
183 if( !tmpWnd )
185 TRACE("no window for id=%i\n",index);
186 WIN_ReleaseWndPtr(tmpWnd);
187 continue;
190 /* set correct id */
191 tmpWnd->wIDmenu--;
193 n = sprintf(buffer, "&%d ",index - clientInfo->idFirstChild);
194 if (tmpWnd->text)
195 lstrcpynA(buffer + n, tmpWnd->text, sizeof(buffer) - n );
197 /* change menu if the current child is to be shown in the
198 * "Windows" menu
200 if (index <= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
201 ModifyMenuA(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING,
202 index - 1 , buffer );
203 WIN_ReleaseWndPtr(tmpWnd);
206 /* We must restore the "More Windows..." option if there is enough child
208 if (clientInfo->nActiveChildren - 1 > MDI_MOREWINDOWSLIMIT)
210 char szTmp[50];
211 LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
213 AppendMenuA(clientInfo->hWindowMenu ,MF_STRING ,clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT, szTmp );
215 retvalue = TRUE;
216 END:
217 WIN_ReleaseWndPtr(wndPtr);
218 return retvalue;
221 /**********************************************************************
222 * MDI_GetWindow
224 * returns "activateable" child different from the current or zero
226 static HWND MDI_GetWindow(WND *clientWnd, HWND hWnd, BOOL bNext,
227 DWORD dwStyleMask )
229 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
230 WND *wndPtr, *pWnd, *pWndLast = NULL;
232 dwStyleMask |= WS_DISABLED | WS_VISIBLE;
233 if( !hWnd ) hWnd = clientInfo->hwndActiveChild;
235 if( !(wndPtr = WIN_FindWndPtr(hWnd)) ) return 0;
237 for ( pWnd = WIN_LockWndPtr(wndPtr->next); ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
239 if (!pWnd ) WIN_UpdateWndPtr(&pWnd,wndPtr->parent->child);
241 if ( pWnd == wndPtr ) break; /* went full circle */
243 if (!pWnd->owner && (pWnd->dwStyle & dwStyleMask) == WS_VISIBLE )
245 pWndLast = pWnd;
246 if ( bNext ) break;
249 WIN_ReleaseWndPtr(wndPtr);
250 WIN_ReleaseWndPtr(pWnd);
251 return pWndLast ? pWndLast->hwndSelf : 0;
254 /**********************************************************************
255 * MDI_CalcDefaultChildPos
257 * It seems that the default height is about 2/3 of the client rect
259 static void MDI_CalcDefaultChildPos( WND* w, WORD n, LPPOINT lpPos,
260 INT delta)
262 INT nstagger;
263 RECT rect = w->rectClient;
264 INT spacing = GetSystemMetrics(SM_CYCAPTION) +
265 GetSystemMetrics(SM_CYFRAME) - 1;
267 if( rect.bottom - rect.top - delta >= spacing )
268 rect.bottom -= delta;
270 nstagger = (rect.bottom - rect.top)/(3 * spacing);
271 lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
272 lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
273 lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
276 /**********************************************************************
277 * MDISetMenu
279 static LRESULT MDISetMenu( HWND hwnd, HMENU hmenuFrame,
280 HMENU hmenuWindow)
282 WND *w;
283 MDICLIENTINFO *ci;
284 HWND hwndFrame = GetParent(hwnd);
285 HMENU oldFrameMenu = GetMenu(hwndFrame);
287 TRACE("%04x %04x %04x\n",
288 hwnd, hmenuFrame, hmenuWindow);
290 if (hmenuFrame && !IsMenu(hmenuFrame))
292 WARN("hmenuFrame is not a menu handle\n");
293 return 0L;
296 if (hmenuWindow && !IsMenu(hmenuWindow))
298 WARN("hmenuWindow is not a menu handle\n");
299 return 0L;
302 w = WIN_FindWndPtr(hwnd);
303 ci = (MDICLIENTINFO *) w->wExtra;
305 if( ci->hwndChildMaximized && hmenuFrame && hmenuFrame!=oldFrameMenu )
306 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized );
308 if( hmenuWindow && ci->hWindowMenu && hmenuWindow!=ci->hWindowMenu )
310 /* delete menu items from ci->hWindowMenu
311 * and add them to hmenuWindow */
313 INT i = GetMenuItemCount(ci->hWindowMenu) - 1;
314 INT pos = GetMenuItemCount(hmenuWindow) + 1;
316 AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL);
318 if( ci->nActiveChildren )
320 INT j;
321 LPWSTR buffer = NULL;
322 MENUITEMINFOW mii;
323 INT nbWindowsMenuItems; /* num of documents shown + "More Windows..." if present */
325 if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
326 nbWindowsMenuItems = ci->nActiveChildren;
327 else
328 nbWindowsMenuItems = MDI_MOREWINDOWSLIMIT + 1;
330 j = i - nbWindowsMenuItems + 1;
332 for( ; i >= j ; i-- )
334 memset(&mii, 0, sizeof(mii));
335 mii.cbSize = sizeof(mii);
336 mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE
337 | MIIM_SUBMENU | MIIM_TYPE | MIIM_BITMAP;
339 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
340 if(mii.cch) { /* Menu is MFT_STRING */
341 mii.cch++; /* add room for '\0' */
342 buffer = HeapAlloc(GetProcessHeap(), 0,
343 mii.cch * sizeof(WCHAR));
344 mii.dwTypeData = buffer;
345 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
347 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
348 InsertMenuItemW(hmenuWindow, pos, TRUE, &mii);
349 if(buffer) {
350 HeapFree(GetProcessHeap(), 0, buffer);
351 buffer = NULL;
356 /* remove separator */
357 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
359 ci->hWindowMenu = hmenuWindow;
362 if (hmenuFrame)
364 SetMenu(hwndFrame, hmenuFrame);
365 if( hmenuFrame!=oldFrameMenu )
367 if( ci->hwndChildMaximized )
368 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
369 WIN_ReleaseWndPtr(w);
370 return oldFrameMenu;
373 WIN_ReleaseWndPtr(w);
374 return 0;
377 /**********************************************************************
378 * MDIRefreshMenu
380 static LRESULT MDIRefreshMenu( HWND hwnd, HMENU hmenuFrame,
381 HMENU hmenuWindow)
383 HWND hwndFrame = GetParent(hwnd);
384 HMENU oldFrameMenu = GetMenu(hwndFrame);
386 TRACE("%04x %04x %04x\n",
387 hwnd, hmenuFrame, hmenuWindow);
389 FIXME("partially function stub\n");
391 return oldFrameMenu;
395 /* ------------------ MDI child window functions ---------------------- */
398 /**********************************************************************
399 * MDICreateChild
401 static HWND MDICreateChild( WND *w, MDICLIENTINFO *ci, HWND parent,
402 LPMDICREATESTRUCTA cs )
404 POINT pos[2];
405 DWORD style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
406 HWND hwnd, hwndMax = 0;
407 WORD wIDmenu = ci->idFirstChild + ci->nActiveChildren;
408 char lpstrDef[]="junk!";
410 TRACE("origin %i,%i - dim %i,%i, style %08x\n",
411 cs->x, cs->y, cs->cx, cs->cy, (unsigned)cs->style);
412 /* calculate placement */
413 MDI_CalcDefaultChildPos(w, ci->nTotalCreated++, pos, 0);
415 if (cs->cx == CW_USEDEFAULT || !cs->cx) cs->cx = pos[1].x;
416 if (cs->cy == CW_USEDEFAULT || !cs->cy) cs->cy = pos[1].y;
418 if( cs->x == CW_USEDEFAULT )
420 cs->x = pos[0].x;
421 cs->y = pos[0].y;
424 /* restore current maximized child */
425 if( style & WS_VISIBLE && ci->hwndChildMaximized )
427 if( style & WS_MAXIMIZE )
428 SendMessageA(w->hwndSelf, WM_SETREDRAW, FALSE, 0L );
429 hwndMax = ci->hwndChildMaximized;
430 ShowWindow( hwndMax, SW_SHOWNOACTIVATE );
431 if( style & WS_MAXIMIZE )
432 SendMessageA(w->hwndSelf, WM_SETREDRAW, TRUE, 0L );
435 if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
436 /* this menu is needed to set a check mark in MDI_ChildActivate */
437 if (ci->hWindowMenu != 0)
438 AppendMenuA(ci->hWindowMenu ,MF_STRING ,wIDmenu, lpstrDef );
440 ci->nActiveChildren++;
442 /* fix window style */
443 if( !(w->dwStyle & MDIS_ALLCHILDSTYLES) )
445 style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE |
446 WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL );
447 style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW);
450 if( w->flags & WIN_ISWIN32 )
452 hwnd = CreateWindowA( cs->szClass, cs->szTitle, style,
453 cs->x, cs->y, cs->cx, cs->cy, parent,
454 (HMENU16)wIDmenu, cs->hOwner, cs );
456 else
458 MDICREATESTRUCT16 *cs16;
459 LPSTR title, cls;
461 cs16 = SEGPTR_NEW(MDICREATESTRUCT16);
462 STRUCT32_MDICREATESTRUCT32Ato16( cs, cs16 );
463 title = SEGPTR_STRDUP( cs->szTitle );
464 cls = SEGPTR_STRDUP( cs->szClass );
465 cs16->szTitle = SEGPTR_GET(title);
466 cs16->szClass = SEGPTR_GET(cls);
468 hwnd = CreateWindow16( cs->szClass, cs->szTitle, style,
469 cs16->x, cs16->y, cs16->cx, cs16->cy, parent,
470 (HMENU)wIDmenu, cs16->hOwner,
471 (LPVOID)SEGPTR_GET(cs16) );
472 SEGPTR_FREE( title );
473 SEGPTR_FREE( cls );
474 SEGPTR_FREE( cs16 );
477 /* MDI windows are WS_CHILD so they won't be activated by CreateWindow */
479 if (hwnd)
481 WND* wnd = WIN_FindWndPtr( hwnd );
483 /* All MDI child windows have the WS_EX_MDICHILD style */
484 wnd->dwExStyle |= WS_EX_MDICHILD;
486 /* If we have more than 9 windows, we must insert the new one at the
487 * 9th position in order to see it in the "Windows" menu
489 if (ci->nActiveChildren > MDI_MOREWINDOWSLIMIT)
490 MDI_SwapMenuItems(wnd->parent, wnd->wIDmenu, ci->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
492 MDI_MenuModifyItem(w ,hwnd);
494 /* Have we hit the "More Windows..." limit? If so, we must
495 * add a "More Windows..." option
497 if (ci->nActiveChildren == MDI_MOREWINDOWSLIMIT + 1)
499 char szTmp[50];
500 LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
502 ModifyMenuA(ci->hWindowMenu,
503 ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
504 MF_BYCOMMAND | MF_STRING,
505 ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
506 szTmp);
509 if( wnd->dwStyle & WS_MINIMIZE && ci->hwndActiveChild )
510 ShowWindow( hwnd, SW_SHOWMINNOACTIVE );
511 else
513 /* WS_VISIBLE is clear if a) the MDI client has
514 * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the
515 * MDICreateStruct. If so the created window is not shown nor
516 * activated.
518 int showflag=wnd->dwStyle & WS_VISIBLE;
519 /* clear visible flag, otherwise SetWindoPos32 ignores
520 * the SWP_SHOWWINDOW command.
522 wnd->dwStyle &= ~WS_VISIBLE;
523 if(showflag){
524 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE );
526 /* Set maximized state here in case hwnd didn't receive WM_SIZE
527 * during CreateWindow - bad!
530 if((wnd->dwStyle & WS_MAXIMIZE) && !ci->hwndChildMaximized )
532 ci->hwndChildMaximized = wnd->hwndSelf;
533 MDI_AugmentFrameMenu( ci, w->parent, hwnd );
534 MDI_UpdateFrameText( w->parent, ci->self, MDI_REPAINTFRAME, NULL );
536 }else
537 /* needed, harmless ? */
538 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE );
541 WIN_ReleaseWndPtr(wnd);
542 TRACE("created child - %04x\n",hwnd);
544 else
546 ci->nActiveChildren--;
547 DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
548 if( IsWindow(hwndMax) )
549 ShowWindow(hwndMax, SW_SHOWMAXIMIZED);
552 return hwnd;
555 /**********************************************************************
556 * MDI_ChildGetMinMaxInfo
558 * Note: The rule here is that client rect of the maximized MDI child
559 * is equal to the client rect of the MDI client window.
561 static void MDI_ChildGetMinMaxInfo( WND* clientWnd, HWND hwnd,
562 MINMAXINFO16* lpMinMax )
564 WND* childWnd = WIN_FindWndPtr(hwnd);
565 RECT rect = clientWnd->rectClient;
567 MapWindowPoints( clientWnd->parent->hwndSelf,
568 ((MDICLIENTINFO*)clientWnd->wExtra)->self, (LPPOINT)&rect, 2);
569 AdjustWindowRectEx( &rect, childWnd->dwStyle, 0, childWnd->dwExStyle );
571 lpMinMax->ptMaxSize.x = rect.right -= rect.left;
572 lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
574 lpMinMax->ptMaxPosition.x = rect.left;
575 lpMinMax->ptMaxPosition.y = rect.top;
577 WIN_ReleaseWndPtr(childWnd);
579 TRACE("max rect (%i,%i - %i, %i)\n",
580 rect.left,rect.top,rect.right,rect.bottom);
584 /**********************************************************************
585 * MDI_SwitchActiveChild
587 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
588 * being activated
590 static void MDI_SwitchActiveChild( HWND clientHwnd, HWND childHwnd,
591 BOOL bNextWindow )
593 WND *w = WIN_FindWndPtr(clientHwnd);
594 HWND hwndTo = 0;
595 HWND hwndPrev = 0;
596 MDICLIENTINFO *ci;
598 hwndTo = MDI_GetWindow(w, childHwnd, bNextWindow, 0);
600 ci = (MDICLIENTINFO *) w->wExtra;
602 TRACE("from %04x, to %04x\n",childHwnd,hwndTo);
604 if ( !hwndTo ) goto END; /* no window to switch to */
606 hwndPrev = ci->hwndActiveChild;
608 if ( hwndTo != hwndPrev )
610 BOOL bOptimize = 0;
612 if( ci->hwndChildMaximized )
614 bOptimize = 1;
615 w->dwStyle &= ~WS_VISIBLE;
618 SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0,
619 SWP_NOMOVE | SWP_NOSIZE );
621 if( bNextWindow && hwndPrev )
622 SetWindowPos( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0,
623 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
624 if( bOptimize )
625 ShowWindow( clientHwnd, SW_SHOW );
627 END:
628 WIN_ReleaseWndPtr(w);
632 /**********************************************************************
633 * MDIDestroyChild
635 static LRESULT MDIDestroyChild( WND *w_parent, MDICLIENTINFO *ci,
636 HWND parent, HWND child,
637 BOOL flagDestroy )
639 WND *childPtr = WIN_FindWndPtr(child);
641 if( childPtr )
643 MDI_MenuDeleteItem(w_parent, child);
645 if( child == ci->hwndActiveChild )
647 MDI_SwitchActiveChild(parent, child, TRUE);
649 if( child == ci->hwndActiveChild )
651 ShowWindow( child, SW_HIDE);
652 if( child == ci->hwndChildMaximized )
654 MDI_RestoreFrameMenu(w_parent->parent, child);
655 ci->hwndChildMaximized = 0;
656 MDI_UpdateFrameText(w_parent->parent,parent,TRUE,NULL);
659 MDI_ChildActivate(w_parent, 0);
663 WIN_ReleaseWndPtr(childPtr);
665 ci->nActiveChildren--;
667 TRACE("child destroyed - %04x\n",child);
669 if (flagDestroy)
671 MDI_PostUpdate(GetParent(child), ci, SB_BOTH+1);
672 DestroyWindow(child);
676 return 0;
680 /**********************************************************************
681 * MDI_ChildActivate
683 * Note: hWndChild is NULL when last child is being destroyed
685 static LONG MDI_ChildActivate( WND *clientPtr, HWND hWndChild )
687 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientPtr->wExtra;
688 HWND prevActiveWnd = clientInfo->hwndActiveChild;
689 WND *wndPtr = WIN_FindWndPtr( hWndChild );
690 WND *wndPrev = WIN_FindWndPtr( prevActiveWnd );
691 BOOL isActiveFrameWnd = 0;
692 LONG retvalue;
694 if( wndPtr )
696 if( wndPtr->dwStyle & WS_DISABLED )
698 retvalue = 0L;
699 goto END;
703 /* Don't activate if it is already active. Might happen
704 since ShowWindow DOES activate MDI children */
705 if (clientInfo->hwndActiveChild == hWndChild)
707 retvalue = 0L;
708 goto END;
711 TRACE("%04x\n", hWndChild);
713 if( GetActiveWindow() == clientPtr->parent->hwndSelf )
714 isActiveFrameWnd = TRUE;
716 /* deactivate prev. active child */
717 if( wndPrev )
719 wndPrev->dwStyle |= WS_SYSMENU;
720 SendMessageA( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
721 SendMessageA( prevActiveWnd, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
722 (LPARAM)hWndChild);
723 /* uncheck menu item */
724 if( clientInfo->hWindowMenu )
726 WORD wPrevID = wndPrev->wIDmenu - clientInfo->idFirstChild;
728 if (wPrevID < MDI_MOREWINDOWSLIMIT)
729 CheckMenuItem( clientInfo->hWindowMenu,
730 wndPrev->wIDmenu, 0);
731 else
732 CheckMenuItem( clientInfo->hWindowMenu,
733 clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1, 0);
737 /* set appearance */
738 if( clientInfo->hwndChildMaximized )
740 if( clientInfo->hwndChildMaximized != hWndChild ) {
741 if( hWndChild ) {
742 clientInfo->hwndActiveChild = hWndChild;
743 ShowWindow( hWndChild, SW_SHOWMAXIMIZED);
744 } else
745 ShowWindow( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
749 clientInfo->hwndActiveChild = hWndChild;
751 /* check if we have any children left */
752 if( !hWndChild )
754 if( isActiveFrameWnd )
755 SetFocus( clientInfo->self );
756 retvalue = 0;
757 goto END;
760 /* check menu item */
761 if( clientInfo->hWindowMenu )
763 /* The window to be activated must be displayed in the "Windows" menu */
764 if (wndPtr->wIDmenu >= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
766 MDI_SwapMenuItems(wndPtr->parent, wndPtr->wIDmenu, clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
767 MDI_MenuModifyItem(wndPtr->parent ,wndPtr->hwndSelf);
770 CheckMenuItem(clientInfo->hWindowMenu, wndPtr->wIDmenu, MF_CHECKED);
772 /* bring active child to the top */
773 SetWindowPos( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
775 if( isActiveFrameWnd )
777 SendMessageA( hWndChild, WM_NCACTIVATE, TRUE, 0L);
778 if( GetFocus() == clientInfo->self )
779 SendMessageA( clientInfo->self, WM_SETFOCUS,
780 (WPARAM)clientInfo->self, 0L );
781 else
782 SetFocus( clientInfo->self );
784 SendMessageA( hWndChild, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
785 (LPARAM)hWndChild );
786 retvalue = 1;
787 END:
788 WIN_ReleaseWndPtr(wndPtr);
789 WIN_ReleaseWndPtr(wndPrev);
790 return retvalue;
793 /* -------------------- MDI client window functions ------------------- */
795 /**********************************************************************
796 * CreateMDIMenuBitmap
798 static HBITMAP16 CreateMDIMenuBitmap(void)
800 HDC hDCSrc = CreateCompatibleDC(0);
801 HDC hDCDest = CreateCompatibleDC(hDCSrc);
802 HBITMAP16 hbClose = LoadBitmap16(0, MAKEINTRESOURCE16(OBM_CLOSE) );
803 HBITMAP16 hbCopy;
804 HANDLE16 hobjSrc, hobjDest;
806 hobjSrc = SelectObject(hDCSrc, hbClose);
807 hbCopy = CreateCompatibleBitmap(hDCSrc,GetSystemMetrics(SM_CXSIZE),GetSystemMetrics(SM_CYSIZE));
808 hobjDest = SelectObject(hDCDest, hbCopy);
810 BitBlt(hDCDest, 0, 0, GetSystemMetrics(SM_CXSIZE), GetSystemMetrics(SM_CYSIZE),
811 hDCSrc, GetSystemMetrics(SM_CXSIZE), 0, SRCCOPY);
813 SelectObject(hDCSrc, hobjSrc);
814 DeleteObject(hbClose);
815 DeleteDC(hDCSrc);
817 hobjSrc = SelectObject( hDCDest, GetStockObject(BLACK_PEN) );
819 MoveToEx( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, 0, NULL );
820 LineTo( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, GetSystemMetrics(SM_CYSIZE) - 1);
822 SelectObject(hDCDest, hobjSrc );
823 SelectObject(hDCDest, hobjDest);
824 DeleteDC(hDCDest);
826 return hbCopy;
829 /**********************************************************************
830 * MDICascade
832 static LONG MDICascade(WND* clientWnd, MDICLIENTINFO *ci)
834 WND** ppWnd;
835 UINT total;
837 if (ci->hwndChildMaximized)
838 SendMessageA( clientWnd->hwndSelf, WM_MDIRESTORE,
839 (WPARAM)ci->hwndChildMaximized, 0);
841 if (ci->nActiveChildren == 0) return 0;
843 if ((ppWnd = WIN_BuildWinArray(clientWnd, BWA_SKIPHIDDEN | BWA_SKIPOWNED |
844 BWA_SKIPICONIC, &total)))
846 WND** heapPtr = ppWnd;
847 if( total )
849 INT delta = 0, n = 0;
850 POINT pos[2];
851 if( total < ci->nActiveChildren )
852 delta = GetSystemMetrics(SM_CYICONSPACING) +
853 GetSystemMetrics(SM_CYICON);
855 /* walk the list (backwards) and move windows */
856 while (*ppWnd) ppWnd++;
857 while (ppWnd != heapPtr)
859 ppWnd--;
860 TRACE("move %04x to (%ld,%ld) size [%ld,%ld]\n",
861 (*ppWnd)->hwndSelf, pos[0].x, pos[0].y, pos[1].x, pos[1].y);
863 MDI_CalcDefaultChildPos(clientWnd, n++, pos, delta);
864 SetWindowPos( (*ppWnd)->hwndSelf, 0, pos[0].x, pos[0].y,
865 pos[1].x, pos[1].y,
866 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
869 WIN_ReleaseWinArray(heapPtr);
872 if( total < ci->nActiveChildren )
873 ArrangeIconicWindows( clientWnd->hwndSelf );
874 return 0;
877 /**********************************************************************
878 * MDITile
880 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM wParam )
882 WND** ppWnd;
883 UINT total = 0;
885 if (ci->hwndChildMaximized)
886 SendMessageA( wndClient->hwndSelf, WM_MDIRESTORE,
887 (WPARAM)ci->hwndChildMaximized, 0);
889 if (ci->nActiveChildren == 0) return;
891 ppWnd = WIN_BuildWinArray(wndClient, BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
892 ((wParam & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
894 TRACE("%u windows to tile\n", total);
896 if( ppWnd )
898 WND** heapPtr = ppWnd;
900 if( total )
902 RECT rect;
903 int x, y, xsize, ysize;
904 int rows, columns, r, c, i;
906 GetClientRect(wndClient->hwndSelf,&rect);
907 rows = (int) sqrt((double)total);
908 columns = total / rows;
910 if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */
912 i = rows;
913 rows = columns; /* exchange r and c */
914 columns = i;
917 if( total != ci->nActiveChildren)
919 y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
920 rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
923 ysize = rect.bottom / rows;
924 xsize = rect.right / columns;
926 for (x = i = 0, c = 1; c <= columns && *ppWnd; c++)
928 if (c == columns)
930 rows = total - i;
931 ysize = rect.bottom / rows;
934 y = 0;
935 for (r = 1; r <= rows && *ppWnd; r++, i++)
937 SetWindowPos((*ppWnd)->hwndSelf, 0, x, y, xsize, ysize,
938 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
939 y += ysize;
940 ppWnd++;
942 x += xsize;
945 WIN_ReleaseWinArray(heapPtr);
948 if( total < ci->nActiveChildren ) ArrangeIconicWindows( wndClient->hwndSelf );
951 /* ----------------------- Frame window ---------------------------- */
954 /**********************************************************************
955 * MDI_AugmentFrameMenu
957 static BOOL MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
958 HWND hChild )
960 WND* child = WIN_FindWndPtr(hChild);
961 HMENU hSysPopup = 0;
962 HBITMAP hSysMenuBitmap = 0;
964 TRACE("frame %p,child %04x\n",frame,hChild);
966 if( !frame->wIDmenu || !child->hSysMenu )
968 WIN_ReleaseWndPtr(child);
969 return 0;
971 WIN_ReleaseWndPtr(child);
973 /* create a copy of sysmenu popup and insert it into frame menu bar */
975 if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
976 return 0;
978 TRACE("\tgot popup %04x in sysmenu %04x\n",
979 hSysPopup, child->hSysMenu);
981 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
982 SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
983 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
984 SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
986 /* In Win 95 look, the system menu is replaced by the child icon */
988 if(TWEAK_WineLook > WIN31_LOOK)
990 HICON hIcon = GetClassLongA(hChild, GCL_HICONSM);
991 if (!hIcon)
992 hIcon = GetClassLongA(hChild, GCL_HICON);
993 if (hIcon)
995 HDC hMemDC;
996 HBITMAP hBitmap, hOldBitmap;
997 HBRUSH hBrush;
998 HDC hdc = GetDC(hChild);
1000 if (hdc)
1002 int cx, cy;
1003 cx = GetSystemMetrics(SM_CXSMICON);
1004 cy = GetSystemMetrics(SM_CYSMICON);
1005 hMemDC = CreateCompatibleDC(hdc);
1006 hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
1007 hOldBitmap = SelectObject(hMemDC, hBitmap);
1008 SetMapMode(hMemDC, MM_TEXT);
1009 hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
1010 DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL);
1011 SelectObject (hMemDC, hOldBitmap);
1012 DeleteObject(hBrush);
1013 DeleteDC(hMemDC);
1014 ReleaseDC(hChild, hdc);
1015 hSysMenuBitmap = hBitmap;
1019 else
1020 hSysMenuBitmap = hBmpClose;
1022 if( !InsertMenuA(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
1023 hSysPopup, (LPSTR)(DWORD)hSysMenuBitmap))
1025 TRACE("not inserted\n");
1026 DestroyMenu(hSysPopup);
1027 return 0;
1030 /* The close button is only present in Win 95 look */
1031 if(TWEAK_WineLook > WIN31_LOOK)
1033 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
1034 SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
1037 EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
1038 EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
1039 EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
1040 SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE);
1042 /* redraw menu */
1043 DrawMenuBar(frame->hwndSelf);
1045 return 1;
1048 /**********************************************************************
1049 * MDI_RestoreFrameMenu
1051 static BOOL MDI_RestoreFrameMenu( WND *frameWnd, HWND hChild )
1053 MENUITEMINFOA menuInfo;
1054 INT nItems = GetMenuItemCount(frameWnd->wIDmenu) - 1;
1055 UINT iId = GetMenuItemID(frameWnd->wIDmenu,nItems) ;
1057 TRACE("frameWnd %p,(%04x),child %04x,nIt=%d,iId=%d\n",
1058 frameWnd,frameWnd->hwndSelf,hChild,nItems,iId);
1060 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
1061 return 0;
1064 * Remove the system menu, If that menu is the icon of the window
1065 * as it is in win95, we have to delete the bitmap.
1067 menuInfo.cbSize = sizeof(MENUITEMINFOA);
1068 menuInfo.fMask = MIIM_DATA | MIIM_TYPE;
1070 GetMenuItemInfoA(frameWnd->wIDmenu,
1072 TRUE,
1073 &menuInfo);
1075 RemoveMenu(frameWnd->wIDmenu,0,MF_BYPOSITION);
1077 if ( (menuInfo.fType & MFT_BITMAP) &&
1078 (LOWORD(menuInfo.dwTypeData)!=0) &&
1079 (LOWORD(menuInfo.dwTypeData)!=hBmpClose) )
1081 DeleteObject((HBITMAP)LOWORD(menuInfo.dwTypeData));
1084 if(TWEAK_WineLook > WIN31_LOOK)
1086 /* close */
1087 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1089 /* restore */
1090 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1091 /* minimize */
1092 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1094 DrawMenuBar(frameWnd->hwndSelf);
1096 return 1;
1100 /**********************************************************************
1101 * MDI_UpdateFrameText
1103 * used when child window is maximized/restored
1105 * Note: lpTitle can be NULL
1107 static void MDI_UpdateFrameText( WND *frameWnd, HWND hClient,
1108 BOOL repaint, LPCSTR lpTitle )
1110 char lpBuffer[MDI_MAXTITLELENGTH+1];
1111 WND* clientWnd = WIN_FindWndPtr(hClient);
1112 MDICLIENTINFO *ci = (MDICLIENTINFO *) clientWnd->wExtra;
1114 TRACE("repaint %i, frameText %s\n", repaint, (lpTitle)?lpTitle:"NULL");
1116 if (!clientWnd)
1117 return;
1119 if (!ci)
1121 WIN_ReleaseWndPtr(clientWnd);
1122 return;
1125 /* store new "default" title if lpTitle is not NULL */
1126 if (lpTitle)
1128 if (ci->frameTitle) HeapFree( SystemHeap, 0, ci->frameTitle );
1129 ci->frameTitle = HEAP_strdupA( SystemHeap, 0, lpTitle );
1132 if (ci->frameTitle)
1134 WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );
1136 if( childWnd && childWnd->text )
1138 /* combine frame title and child title if possible */
1140 LPCSTR lpBracket = " - [";
1141 int i_frame_text_length = strlen(ci->frameTitle);
1142 int i_child_text_length = strlen(childWnd->text);
1144 lstrcpynA( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
1146 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
1148 strcat( lpBuffer, lpBracket );
1150 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
1152 strcat( lpBuffer, childWnd->text );
1153 strcat( lpBuffer, "]" );
1155 else
1157 lstrcpynA( lpBuffer + i_frame_text_length + 4,
1158 childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
1159 strcat( lpBuffer, "]" );
1163 else
1165 lstrcpynA(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH+1 );
1167 WIN_ReleaseWndPtr(childWnd);
1170 else
1171 lpBuffer[0] = '\0';
1173 DEFWND_SetText( frameWnd, lpBuffer );
1174 if( repaint == MDI_REPAINTFRAME)
1175 SetWindowPos( frameWnd->hwndSelf, 0,0,0,0,0, SWP_FRAMECHANGED |
1176 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
1178 WIN_ReleaseWndPtr(clientWnd);
1183 /* ----------------------------- Interface ---------------------------- */
1186 /**********************************************************************
1187 * MDIClientWndProc
1189 * This function handles all MDI requests.
1191 LRESULT WINAPI MDIClientWndProc( HWND hwnd, UINT message, WPARAM wParam,
1192 LPARAM lParam )
1194 LPCREATESTRUCTA cs;
1195 MDICLIENTINFO *ci;
1196 RECT rect;
1197 WND *w, *frameWnd;
1198 INT nItems;
1199 LRESULT retvalue;
1201 if ( ( w = WIN_FindWndPtr(hwnd) ) == NULL )
1202 return 0;
1204 if ( ( frameWnd = WIN_LockWndPtr(w->parent) ) == NULL ) {
1205 WIN_ReleaseWndPtr(w);
1206 return 0;
1209 ci = (MDICLIENTINFO *) w->wExtra;
1211 switch (message)
1213 case WM_CREATE:
1215 cs = (LPCREATESTRUCTA)lParam;
1217 /* Translation layer doesn't know what's in the cs->lpCreateParams
1218 * so we have to keep track of what environment we're in. */
1220 if( w->flags & WIN_ISWIN32 )
1222 #define ccs ((LPCLIENTCREATESTRUCT)cs->lpCreateParams)
1223 ci->hWindowMenu = ccs->hWindowMenu;
1224 ci->idFirstChild = ccs->idFirstChild;
1225 #undef ccs
1227 else
1229 LPCLIENTCREATESTRUCT16 ccs = (LPCLIENTCREATESTRUCT16)
1230 PTR_SEG_TO_LIN(cs->lpCreateParams);
1231 ci->hWindowMenu = ccs->hWindowMenu;
1232 ci->idFirstChild = ccs->idFirstChild;
1235 ci->hwndChildMaximized = 0;
1236 ci->nActiveChildren = 0;
1237 ci->nTotalCreated = 0;
1238 ci->frameTitle = NULL;
1239 ci->mdiFlags = 0;
1240 ci->self = hwnd;
1241 w->dwStyle |= WS_CLIPCHILDREN;
1243 if (!hBmpClose)
1245 hBmpClose = CreateMDIMenuBitmap();
1246 hBmpRestore = LoadBitmap16( 0, MAKEINTRESOURCE16(OBM_RESTORE) );
1248 MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
1250 if (ci->hWindowMenu != 0)
1251 AppendMenuA( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
1253 GetClientRect(frameWnd->hwndSelf, &rect);
1254 NC_HandleNCCalcSize( w, &rect );
1255 w->rectClient = rect;
1257 TRACE("Client created - hwnd = %04x, idFirst = %u\n",
1258 hwnd, ci->idFirstChild );
1260 retvalue = 0;
1261 goto END;
1263 case WM_DESTROY:
1264 if( ci->hwndChildMaximized )
1265 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized);
1266 if((ci->hWindowMenu != 0) &&
1267 (nItems = GetMenuItemCount(ci->hWindowMenu)) > 0)
1269 ci->idFirstChild = nItems - 1;
1270 ci->nActiveChildren++; /* to delete a separator */
1271 while( ci->nActiveChildren-- )
1272 DeleteMenu(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
1274 retvalue = 0;
1275 goto END;
1277 case WM_MDIACTIVATE:
1278 if( ci->hwndActiveChild != (HWND)wParam )
1279 SetWindowPos((HWND)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
1280 retvalue = 0;
1281 goto END;
1283 case WM_MDICASCADE:
1284 retvalue = MDICascade(w, ci);
1285 goto END;
1287 case WM_MDICREATE:
1288 if (lParam) retvalue = MDICreateChild( w, ci, hwnd,
1289 (MDICREATESTRUCTA*)lParam );
1290 else retvalue = 0;
1291 goto END;
1293 case WM_MDIDESTROY:
1294 retvalue = MDIDestroyChild( w, ci, hwnd, (HWND)wParam, TRUE );
1295 goto END;
1297 case WM_MDIGETACTIVE:
1298 if (lParam) *(BOOL *)lParam = (ci->hwndChildMaximized > 0);
1299 retvalue = ci->hwndActiveChild;
1300 goto END;
1302 case WM_MDIICONARRANGE:
1303 ci->mdiFlags |= MDIF_NEEDUPDATE;
1304 ArrangeIconicWindows(hwnd);
1305 ci->sbRecalc = SB_BOTH+1;
1306 SendMessageA(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
1307 retvalue = 0;
1308 goto END;
1310 case WM_MDIMAXIMIZE:
1311 ShowWindow( (HWND)wParam, SW_MAXIMIZE );
1312 retvalue = 0;
1313 goto END;
1315 case WM_MDINEXT: /* lParam != 0 means previous window */
1316 MDI_SwitchActiveChild(hwnd, (HWND)wParam, (lParam)? FALSE : TRUE );
1317 break;
1319 case WM_MDIRESTORE:
1320 SendMessageA( (HWND)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
1321 retvalue = 0;
1322 goto END;
1324 case WM_MDISETMENU:
1325 retvalue = MDISetMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1326 goto END;
1327 case WM_MDIREFRESHMENU:
1328 retvalue = MDIRefreshMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1329 goto END;
1331 case WM_MDITILE:
1332 ci->mdiFlags |= MDIF_NEEDUPDATE;
1333 ShowScrollBar(hwnd,SB_BOTH,FALSE);
1334 MDITile(w, ci, wParam);
1335 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1336 retvalue = 0;
1337 goto END;
1339 case WM_VSCROLL:
1340 case WM_HSCROLL:
1341 ci->mdiFlags |= MDIF_NEEDUPDATE;
1342 ScrollChildren(hwnd, message, wParam, lParam);
1343 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1344 retvalue = 0;
1345 goto END;
1347 case WM_SETFOCUS:
1348 if( ci->hwndActiveChild )
1350 WND* pw = WIN_FindWndPtr( ci->hwndActiveChild );
1351 if( !(pw->dwStyle & WS_MINIMIZE) )
1352 SetFocus( ci->hwndActiveChild );
1353 WIN_ReleaseWndPtr(pw);
1355 retvalue = 0;
1356 goto END;
1358 case WM_NCACTIVATE:
1359 if( ci->hwndActiveChild )
1360 SendMessageA(ci->hwndActiveChild, message, wParam, lParam);
1361 break;
1363 case WM_PARENTNOTIFY:
1364 if (LOWORD(wParam) == WM_LBUTTONDOWN)
1366 POINT16 pt = MAKEPOINT16(lParam);
1367 HWND16 child = ChildWindowFromPoint16(hwnd, pt);
1369 TRACE("notification from %04x (%i,%i)\n",child,pt.x,pt.y);
1371 if( child && child != hwnd && child != ci->hwndActiveChild )
1372 SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1374 retvalue = 0;
1375 goto END;
1377 case WM_SIZE:
1378 if( IsWindow(ci->hwndChildMaximized) )
1380 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1381 RECT rect;
1383 rect.left = 0;
1384 rect.top = 0;
1385 rect.right = LOWORD(lParam);
1386 rect.bottom = HIWORD(lParam);
1388 AdjustWindowRectEx(&rect, child->dwStyle, 0, child->dwExStyle);
1389 MoveWindow(ci->hwndChildMaximized, rect.left, rect.top,
1390 rect.right - rect.left, rect.bottom - rect.top, 1);
1391 WIN_ReleaseWndPtr(child);
1393 else
1394 MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1396 break;
1398 case WM_MDICALCCHILDSCROLL:
1399 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1401 CalcChildScroll16(hwnd, ci->sbRecalc-1);
1402 ci->sbRecalc = 0;
1403 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1405 retvalue = 0;
1406 goto END;
1409 retvalue = DefWindowProcA( hwnd, message, wParam, lParam );
1410 END:
1411 WIN_ReleaseWndPtr(w);
1412 WIN_ReleaseWndPtr(frameWnd);
1413 return retvalue;
1417 /***********************************************************************
1418 * DefFrameProc16 (USER.445)
1420 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1421 UINT16 message, WPARAM16 wParam, LPARAM lParam )
1423 HWND16 childHwnd;
1424 MDICLIENTINFO* ci;
1425 WND* wndPtr;
1427 if (hwndMDIClient)
1429 switch (message)
1431 case WM_COMMAND:
1432 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1434 if (!wndPtr) {
1435 ERR("null wndPtr for mdi window hwndMDIClient=%04x\n",
1436 hwndMDIClient);
1437 return 0;
1440 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1442 /* check for possible syscommands for maximized MDI child */
1443 WIN_ReleaseWndPtr(wndPtr);
1445 if( ci && (
1446 wParam < ci->idFirstChild ||
1447 wParam >= ci->idFirstChild + ci->nActiveChildren
1449 if( (wParam - 0xF000) & 0xF00F ) break;
1450 switch( wParam )
1452 case SC_SIZE:
1453 case SC_MOVE:
1454 case SC_MINIMIZE:
1455 case SC_MAXIMIZE:
1456 case SC_NEXTWINDOW:
1457 case SC_PREVWINDOW:
1458 case SC_CLOSE:
1459 case SC_RESTORE:
1460 if( ci->hwndChildMaximized )
1461 return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1462 wParam, lParam);
1465 else
1467 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1468 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1470 if (wParam - ci->idFirstChild == MDI_MOREWINDOWSLIMIT)
1471 /* User chose "More Windows..." */
1472 childHwnd = MDI_MoreWindowsDialog(wndPtr);
1473 else
1474 /* User chose one of the windows listed in the "Windows" menu */
1475 childHwnd = MDI_GetChildByID(wndPtr,wParam );
1477 WIN_ReleaseWndPtr(wndPtr);
1478 if( childHwnd )
1479 SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1480 (WPARAM16)childHwnd , 0L);
1482 break;
1484 case WM_NCACTIVATE:
1485 SendMessage16(hwndMDIClient, message, wParam, lParam);
1486 break;
1488 case WM_SETTEXT:
1489 wndPtr = WIN_FindWndPtr(hwnd);
1490 MDI_UpdateFrameText(wndPtr, hwndMDIClient,
1491 MDI_REPAINTFRAME,
1492 (LPCSTR)PTR_SEG_TO_LIN(lParam));
1493 WIN_ReleaseWndPtr(wndPtr);
1494 return 0;
1496 case WM_SETFOCUS:
1497 SetFocus(hwndMDIClient);
1498 break;
1500 case WM_SIZE:
1501 MoveWindow16(hwndMDIClient, 0, 0,
1502 LOWORD(lParam), HIWORD(lParam), TRUE);
1503 break;
1505 case WM_NEXTMENU:
1507 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1508 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1510 if( !(wndPtr->parent->dwStyle & WS_MINIMIZE)
1511 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1513 /* control menu is between the frame system menu and
1514 * the first entry of menu bar */
1516 if( (wParam == VK_LEFT &&
1517 wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1518 (wParam == VK_RIGHT &&
1519 GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1521 LRESULT retvalue;
1522 WIN_ReleaseWndPtr(wndPtr);
1523 wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1524 retvalue = MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1525 ci->hwndActiveChild);
1526 WIN_ReleaseWndPtr(wndPtr);
1527 return retvalue;
1530 WIN_ReleaseWndPtr(wndPtr);
1531 break;
1535 return DefWindowProc16(hwnd, message, wParam, lParam);
1539 /***********************************************************************
1540 * DefFrameProcA (USER32.122)
1542 LRESULT WINAPI DefFrameProcA( HWND hwnd, HWND hwndMDIClient,
1543 UINT message, WPARAM wParam, LPARAM lParam)
1545 if (hwndMDIClient)
1547 switch (message)
1549 case WM_COMMAND:
1550 return DefFrameProc16( hwnd, hwndMDIClient, message,
1551 (WPARAM16)wParam,
1552 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1554 case WM_NCACTIVATE:
1555 SendMessageA(hwndMDIClient, message, wParam, lParam);
1556 break;
1558 case WM_SETTEXT: {
1559 LRESULT ret;
1560 LPSTR segstr = SEGPTR_STRDUP((LPSTR)lParam);
1562 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1563 wParam, (LPARAM)SEGPTR_GET(segstr) );
1564 SEGPTR_FREE(segstr);
1565 return ret;
1568 case WM_NEXTMENU:
1569 case WM_SETFOCUS:
1570 case WM_SIZE:
1571 return DefFrameProc16( hwnd, hwndMDIClient, message,
1572 wParam, lParam );
1576 return DefWindowProcA(hwnd, message, wParam, lParam);
1580 /***********************************************************************
1581 * DefFrameProcW (USER32.123)
1583 LRESULT WINAPI DefFrameProcW( HWND hwnd, HWND hwndMDIClient,
1584 UINT message, WPARAM wParam, LPARAM lParam)
1586 if (hwndMDIClient)
1588 switch (message)
1590 case WM_COMMAND:
1591 return DefFrameProc16( hwnd, hwndMDIClient, message,
1592 (WPARAM16)wParam,
1593 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1595 case WM_NCACTIVATE:
1596 SendMessageW(hwndMDIClient, message, wParam, lParam);
1597 break;
1599 case WM_SETTEXT:
1601 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1602 LRESULT ret = DefFrameProcA( hwnd, hwndMDIClient, message,
1603 wParam, (DWORD)txt );
1604 HeapFree(GetProcessHeap(),0,txt);
1605 return ret;
1607 case WM_NEXTMENU:
1608 case WM_SETFOCUS:
1609 case WM_SIZE:
1610 return DefFrameProcA( hwnd, hwndMDIClient, message,
1611 wParam, lParam );
1615 return DefWindowProcW( hwnd, message, wParam, lParam );
1619 /***********************************************************************
1620 * DefMDIChildProc16 (USER.447)
1622 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1623 WPARAM16 wParam, LPARAM lParam )
1625 MDICLIENTINFO *ci;
1626 WND *clientWnd,*tmpWnd = 0;
1627 LRESULT retvalue;
1629 tmpWnd = WIN_FindWndPtr(hwnd);
1630 if (!tmpWnd) return 0;
1631 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1632 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1633 WIN_ReleaseWndPtr(tmpWnd);
1635 switch (message)
1637 case WM_SETTEXT:
1638 DefWindowProc16(hwnd, message, wParam, lParam);
1639 MDI_MenuModifyItem(clientWnd,hwnd);
1640 if( ci->hwndChildMaximized == hwnd )
1641 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1642 MDI_REPAINTFRAME, NULL );
1643 retvalue = 0;
1644 goto END;
1646 case WM_CLOSE:
1647 SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1648 retvalue = 0;
1649 goto END;
1651 case WM_SETFOCUS:
1652 if( ci->hwndActiveChild != hwnd )
1653 MDI_ChildActivate(clientWnd, hwnd);
1654 break;
1656 case WM_CHILDACTIVATE:
1657 MDI_ChildActivate(clientWnd, hwnd);
1658 retvalue = 0;
1659 goto END;
1661 case WM_NCPAINT:
1662 TRACE("WM_NCPAINT for %04x, active %04x\n",
1663 hwnd, ci->hwndActiveChild );
1664 break;
1666 case WM_SYSCOMMAND:
1667 switch( wParam )
1669 case SC_MOVE:
1670 if( ci->hwndChildMaximized == hwnd)
1672 retvalue = 0;
1673 goto END;
1675 break;
1676 case SC_RESTORE:
1677 case SC_MINIMIZE:
1678 tmpWnd = WIN_FindWndPtr(hwnd);
1679 tmpWnd->dwStyle |= WS_SYSMENU;
1680 WIN_ReleaseWndPtr(tmpWnd);
1681 break;
1682 case SC_MAXIMIZE:
1683 if( ci->hwndChildMaximized == hwnd)
1685 retvalue = SendMessage16( clientWnd->parent->hwndSelf,
1686 message, wParam, lParam);
1687 goto END;
1689 tmpWnd = WIN_FindWndPtr(hwnd);
1690 tmpWnd->dwStyle &= ~WS_SYSMENU;
1691 WIN_ReleaseWndPtr(tmpWnd);
1692 break;
1693 case SC_NEXTWINDOW:
1694 SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1695 retvalue = 0;
1696 goto END;
1697 case SC_PREVWINDOW:
1698 SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1699 retvalue = 0;
1700 goto END;
1702 break;
1704 case WM_GETMINMAXINFO:
1705 MDI_ChildGetMinMaxInfo(clientWnd, hwnd, (MINMAXINFO16*) PTR_SEG_TO_LIN(lParam));
1706 retvalue = 0;
1707 goto END;
1709 case WM_SETVISIBLE:
1710 if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1711 else
1712 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1713 break;
1715 case WM_SIZE:
1716 /* do not change */
1718 if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1720 ci->hwndChildMaximized = 0;
1722 MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1723 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1724 MDI_REPAINTFRAME, NULL );
1727 if( wParam == SIZE_MAXIMIZED )
1729 HWND16 hMaxChild = ci->hwndChildMaximized;
1731 if( hMaxChild == hwnd ) break;
1733 if( hMaxChild)
1735 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1737 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1738 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1740 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1743 TRACE("maximizing child %04x\n", hwnd );
1745 ci->hwndChildMaximized = hwnd; /* !!! */
1746 ci->hwndActiveChild = hwnd;
1748 MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1749 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1750 MDI_REPAINTFRAME, NULL );
1753 if( wParam == SIZE_MINIMIZED )
1755 HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1757 if( switchTo )
1758 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1761 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1762 break;
1764 case WM_MENUCHAR:
1766 /* MDI children don't have menu bars */
1767 retvalue = 0x00010000L;
1768 goto END;
1770 case WM_NEXTMENU:
1772 if( wParam == VK_LEFT ) /* switch to frame system menu */
1774 retvalue = MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1775 clientWnd->parent->hwndSelf );
1776 goto END;
1778 if( wParam == VK_RIGHT ) /* to frame menu bar */
1780 retvalue = MAKELONG( clientWnd->parent->wIDmenu,
1781 clientWnd->parent->hwndSelf );
1782 goto END;
1785 break;
1787 case WM_SYSCHAR:
1788 if (wParam == '-')
1790 SendMessage16(hwnd,WM_SYSCOMMAND,
1791 (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1792 retvalue = 0;
1793 goto END;
1797 retvalue = DefWindowProc16(hwnd, message, wParam, lParam);
1798 END:
1799 WIN_ReleaseWndPtr(clientWnd);
1800 return retvalue;
1804 /***********************************************************************
1805 * DefMDIChildProcA (USER32.124)
1807 LRESULT WINAPI DefMDIChildProcA( HWND hwnd, UINT message,
1808 WPARAM wParam, LPARAM lParam )
1810 MDICLIENTINFO *ci;
1811 WND *clientWnd,*tmpWnd;
1812 LRESULT retvalue;
1814 tmpWnd = WIN_FindWndPtr(hwnd);
1815 if (!tmpWnd) return 0;
1816 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1817 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1818 WIN_ReleaseWndPtr(tmpWnd);
1820 switch (message)
1822 case WM_SETTEXT:
1823 DefWindowProcA(hwnd, message, wParam, lParam);
1824 MDI_MenuModifyItem(clientWnd,hwnd);
1825 if( ci->hwndChildMaximized == hwnd )
1826 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1827 MDI_REPAINTFRAME, NULL );
1828 retvalue = 0;
1829 goto END;
1831 case WM_GETMINMAXINFO:
1833 MINMAXINFO16 mmi;
1834 STRUCT32_MINMAXINFO32to16( (MINMAXINFO *)lParam, &mmi );
1835 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1836 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO *)lParam );
1838 retvalue = 0;
1839 goto END;
1841 case WM_MENUCHAR:
1843 /* MDI children don't have menu bars */
1844 retvalue = 0x00010000L;
1845 goto END;
1847 case WM_CLOSE:
1848 case WM_SETFOCUS:
1849 case WM_CHILDACTIVATE:
1850 case WM_NCPAINT:
1851 case WM_SYSCOMMAND:
1852 case WM_SETVISIBLE:
1853 case WM_SIZE:
1854 case WM_NEXTMENU:
1855 retvalue = DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1856 goto END;
1858 case WM_SYSCHAR:
1859 if (wParam == '-')
1861 SendMessageA(hwnd,WM_SYSCOMMAND,
1862 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1863 retvalue = 0;
1864 goto END;
1867 retvalue = DefWindowProcA(hwnd, message, wParam, lParam);
1868 END:
1869 WIN_ReleaseWndPtr(clientWnd);
1870 return retvalue;
1874 /***********************************************************************
1875 * DefMDIChildProcW (USER32.125)
1877 LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message,
1878 WPARAM wParam, LPARAM lParam )
1880 MDICLIENTINFO *ci;
1881 WND *clientWnd,*tmpWnd;
1882 LRESULT retvalue;
1884 tmpWnd = WIN_FindWndPtr(hwnd);
1885 if (!tmpWnd) return 0;
1886 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1887 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1888 WIN_ReleaseWndPtr(tmpWnd);
1890 switch (message)
1892 case WM_SETTEXT:
1893 DefWindowProcW(hwnd, message, wParam, lParam);
1894 MDI_MenuModifyItem(clientWnd,hwnd);
1895 if( ci->hwndChildMaximized == hwnd )
1896 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1897 MDI_REPAINTFRAME, NULL );
1898 retvalue = 0;
1899 goto END;
1901 case WM_GETMINMAXINFO:
1902 case WM_MENUCHAR:
1903 case WM_CLOSE:
1904 case WM_SETFOCUS:
1905 case WM_CHILDACTIVATE:
1906 case WM_NCPAINT:
1907 case WM_SYSCOMMAND:
1908 case WM_SETVISIBLE:
1909 case WM_SIZE:
1910 case WM_NEXTMENU:
1911 retvalue = DefMDIChildProcA( hwnd, message, (WPARAM16)wParam, lParam );
1912 goto END;
1914 case WM_SYSCHAR:
1915 if (wParam == '-')
1917 SendMessageW(hwnd,WM_SYSCOMMAND,
1918 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1919 retvalue = 0;
1920 goto END;
1923 retvalue = DefWindowProcW(hwnd, message, wParam, lParam);
1924 END:
1925 WIN_ReleaseWndPtr(clientWnd);
1926 return retvalue;
1931 /**********************************************************************
1932 * CreateMDIWindowA [USER32.79] Creates a MDI child in new thread
1933 * FIXME: its in the same thread now
1935 * RETURNS
1936 * Success: Handle to created window
1937 * Failure: NULL
1939 HWND WINAPI CreateMDIWindowA(
1940 LPCSTR lpClassName, /* [in] Pointer to registered child class name */
1941 LPCSTR lpWindowName, /* [in] Pointer to window name */
1942 DWORD dwStyle, /* [in] Window style */
1943 INT X, /* [in] Horizontal position of window */
1944 INT Y, /* [in] Vertical position of window */
1945 INT nWidth, /* [in] Width of window */
1946 INT nHeight, /* [in] Height of window */
1947 HWND hWndParent, /* [in] Handle to parent window */
1948 HINSTANCE hInstance, /* [in] Handle to application instance */
1949 LPARAM lParam) /* [in] Application-defined value */
1951 WARN("is only single threaded!\n");
1952 return MDI_CreateMDIWindowA(lpClassName, lpWindowName, dwStyle, X, Y,
1953 nWidth, nHeight, hWndParent, hInstance, lParam);
1956 /**********************************************************************
1957 * MDI_CreateMDIWindowA
1958 * single threaded version of CreateMDIWindowA
1959 * called by CreateWindowExA
1961 HWND MDI_CreateMDIWindowA(
1962 LPCSTR lpClassName,
1963 LPCSTR lpWindowName,
1964 DWORD dwStyle,
1965 INT X,
1966 INT Y,
1967 INT nWidth,
1968 INT nHeight,
1969 HWND hWndParent,
1970 HINSTANCE hInstance,
1971 LPARAM lParam)
1973 MDICLIENTINFO* pCi;
1974 MDICREATESTRUCTA cs;
1975 WND *pWnd=WIN_FindWndPtr(hWndParent);
1976 HWND retvalue;
1978 TRACE("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
1979 debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
1980 nWidth,nHeight,hWndParent,hInstance,lParam);
1982 if(!pWnd){
1983 ERR(" bad hwnd for MDI-client: %d\n",hWndParent);
1984 return 0;
1986 cs.szClass=lpClassName;
1987 cs.szTitle=lpWindowName;
1988 cs.hOwner=hInstance;
1989 cs.x=X;
1990 cs.y=Y;
1991 cs.cx=nWidth;
1992 cs.cy=nHeight;
1993 cs.style=dwStyle;
1994 cs.lParam=lParam;
1996 pCi=(MDICLIENTINFO *)pWnd->wExtra;
1998 retvalue = MDICreateChild(pWnd,pCi,hWndParent,&cs);
1999 WIN_ReleaseWndPtr(pWnd);
2000 return retvalue;
2003 /***********************************************************************
2004 * CreateMDIWindowW [USER32.80] Creates a MDI child in new thread
2006 * RETURNS
2007 * Success: Handle to created window
2008 * Failure: NULL
2010 HWND WINAPI CreateMDIWindowW(
2011 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
2012 LPCWSTR lpWindowName, /* [in] Pointer to window name */
2013 DWORD dwStyle, /* [in] Window style */
2014 INT X, /* [in] Horizontal position of window */
2015 INT Y, /* [in] Vertical position of window */
2016 INT nWidth, /* [in] Width of window */
2017 INT nHeight, /* [in] Height of window */
2018 HWND hWndParent, /* [in] Handle to parent window */
2019 HINSTANCE hInstance, /* [in] Handle to application instance */
2020 LPARAM lParam) /* [in] Application-defined value */
2022 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
2023 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
2024 nWidth,nHeight,hWndParent,hInstance,lParam);
2025 return (HWND)NULL;
2029 /******************************************************************************
2030 * CreateMDIWindowW [USER32.80] Creates a MDI child window
2031 * single threaded version of CreateMDIWindow
2032 * called by CreateWindowExW().
2034 HWND MDI_CreateMDIWindowW(
2035 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
2036 LPCWSTR lpWindowName, /* [in] Pointer to window name */
2037 DWORD dwStyle, /* [in] Window style */
2038 INT X, /* [in] Horizontal position of window */
2039 INT Y, /* [in] Vertical position of window */
2040 INT nWidth, /* [in] Width of window */
2041 INT nHeight, /* [in] Height of window */
2042 HWND hWndParent, /* [in] Handle to parent window */
2043 HINSTANCE hInstance, /* [in] Handle to application instance */
2044 LPARAM lParam) /* [in] Application-defined value */
2046 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
2047 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
2048 nWidth,nHeight,hWndParent,hInstance,lParam);
2049 return (HWND)NULL;
2053 /**********************************************************************
2054 * TranslateMDISysAccel (USER32.555)
2056 BOOL WINAPI TranslateMDISysAccel( HWND hwndClient, LPMSG msg )
2058 MSG16 msg16;
2060 STRUCT32_MSG32to16(msg,&msg16);
2061 /* MDICLIENTINFO is still the same for win32 and win16 ... */
2062 return TranslateMDISysAccel16(hwndClient,&msg16);
2066 /**********************************************************************
2067 * TranslateMDISysAccel16 (USER.451)
2069 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
2072 if( IsWindow(hwndClient) && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
2074 MDICLIENTINFO *ci = NULL;
2075 HWND wnd;
2076 WND *clientWnd = WIN_FindWndPtr(hwndClient);
2078 ci = (MDICLIENTINFO*) clientWnd->wExtra;
2079 wnd = ci->hwndActiveChild;
2081 WIN_ReleaseWndPtr(clientWnd);
2083 if( IsWindow(wnd) && !(GetWindowLongA(wnd,GWL_STYLE) & WS_DISABLED) )
2085 WPARAM16 wParam = 0;
2087 /* translate if the Ctrl key is down and Alt not. */
2089 if( (GetKeyState(VK_CONTROL) & 0x8000) &&
2090 !(GetKeyState(VK_MENU) & 0x8000))
2092 switch( msg->wParam )
2094 case VK_F6:
2095 case VK_TAB:
2096 wParam = ( GetKeyState(VK_SHIFT) & 0x8000 )
2097 ? SC_NEXTWINDOW : SC_PREVWINDOW;
2098 break;
2099 case VK_F4:
2100 case VK_RBUTTON:
2101 wParam = SC_CLOSE;
2102 break;
2103 default:
2104 return 0;
2106 TRACE("wParam = %04x\n", wParam);
2107 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
2108 wParam, (LPARAM)msg->wParam);
2109 return 1;
2113 return 0; /* failure */
2117 /***********************************************************************
2118 * CalcChildScroll (USER.462)
2120 void WINAPI CalcChildScroll16( HWND16 hwnd, WORD scroll )
2122 SCROLLINFO info;
2123 RECT childRect, clientRect;
2124 INT vmin, vmax, hmin, hmax, vpos, hpos;
2125 WND *pWnd, *Wnd;
2127 if (!(pWnd = WIN_FindWndPtr( hwnd ))) return;
2128 Wnd = WIN_FindWndPtr(hwnd);
2129 GetClientRect( hwnd, &clientRect );
2130 SetRectEmpty( &childRect );
2132 for ( WIN_UpdateWndPtr(&pWnd,pWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2134 if( pWnd->dwStyle & WS_MAXIMIZE )
2136 ShowScrollBar(hwnd, SB_BOTH, FALSE);
2137 WIN_ReleaseWndPtr(pWnd);
2138 WIN_ReleaseWndPtr(Wnd);
2139 return;
2141 UnionRect( &childRect, &pWnd->rectWindow, &childRect );
2143 WIN_ReleaseWndPtr(pWnd);
2144 UnionRect( &childRect, &clientRect, &childRect );
2146 hmin = childRect.left; hmax = childRect.right - clientRect.right;
2147 hpos = clientRect.left - childRect.left;
2148 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
2149 vpos = clientRect.top - childRect.top;
2151 switch( scroll )
2153 case SB_HORZ:
2154 vpos = hpos; vmin = hmin; vmax = hmax;
2155 case SB_VERT:
2156 info.cbSize = sizeof(info);
2157 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
2158 info.fMask = SIF_POS | SIF_RANGE;
2159 SetScrollInfo(hwnd, scroll, &info, TRUE);
2160 break;
2161 case SB_BOTH:
2162 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
2163 hmin, hmax, hpos);
2165 WIN_ReleaseWndPtr(Wnd);
2169 /***********************************************************************
2170 * ScrollChildren16 (USER.463)
2172 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
2174 ScrollChildren( hWnd, uMsg, wParam, lParam );
2178 /***********************************************************************
2179 * ScrollChildren (USER32.448)
2181 void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
2182 LPARAM lParam)
2184 WND *wndPtr = WIN_FindWndPtr(hWnd);
2185 INT newPos = -1;
2186 INT curPos, length, minPos, maxPos, shift;
2188 if( !wndPtr ) return;
2190 if( uMsg == WM_HSCROLL )
2192 GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
2193 curPos = GetScrollPos(hWnd,SB_HORZ);
2194 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
2195 shift = GetSystemMetrics(SM_CYHSCROLL);
2197 else if( uMsg == WM_VSCROLL )
2199 GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
2200 curPos = GetScrollPos(hWnd,SB_VERT);
2201 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
2202 shift = GetSystemMetrics(SM_CXVSCROLL);
2204 else
2206 WIN_ReleaseWndPtr(wndPtr);
2207 return;
2210 WIN_ReleaseWndPtr(wndPtr);
2211 switch( wParam )
2213 case SB_LINEUP:
2214 newPos = curPos - shift;
2215 break;
2216 case SB_LINEDOWN:
2217 newPos = curPos + shift;
2218 break;
2219 case SB_PAGEUP:
2220 newPos = curPos - length;
2221 break;
2222 case SB_PAGEDOWN:
2223 newPos = curPos + length;
2224 break;
2226 case SB_THUMBPOSITION:
2227 newPos = LOWORD(lParam);
2228 break;
2230 case SB_THUMBTRACK:
2231 return;
2233 case SB_TOP:
2234 newPos = minPos;
2235 break;
2236 case SB_BOTTOM:
2237 newPos = maxPos;
2238 break;
2239 case SB_ENDSCROLL:
2240 CalcChildScroll16(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
2241 return;
2244 if( newPos > maxPos )
2245 newPos = maxPos;
2246 else
2247 if( newPos < minPos )
2248 newPos = minPos;
2250 SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
2252 if( uMsg == WM_VSCROLL )
2253 ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
2254 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2255 else
2256 ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
2257 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2261 /******************************************************************************
2262 * CascadeWindows [USER32.21] Cascades MDI child windows
2264 * RETURNS
2265 * Success: Number of cascaded windows.
2266 * Failure: 0
2268 WORD WINAPI
2269 CascadeWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2270 UINT cKids, const HWND *lpKids)
2272 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2273 hwndParent, wFlags, cKids);
2275 return 0;
2279 /******************************************************************************
2280 * TileWindows [USER32.545] Tiles MDI child windows
2282 * RETURNS
2283 * Success: Number of tiled windows.
2284 * Failure: 0
2286 WORD WINAPI
2287 TileWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2288 UINT cKids, const HWND *lpKids)
2290 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2291 hwndParent, wFlags, cKids);
2293 return 0;
2296 /************************************************************************
2297 * "More Windows..." functionality
2300 /* MDI_MoreWindowsDlgProc
2302 * This function will process the messages sent to the "More Windows..."
2303 * dialog.
2304 * Return values: 0 = cancel pressed
2305 * HWND = ok pressed or double-click in the list...
2309 static BOOL WINAPI MDI_MoreWindowsDlgProc (HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
2311 switch (iMsg)
2313 case WM_INITDIALOG:
2315 WND *pWnd;
2316 UINT widest = 0;
2317 UINT length;
2318 UINT i;
2319 WND *pParentWnd = (WND *)lParam;
2320 MDICLIENTINFO *ci = (MDICLIENTINFO*)pParentWnd->wExtra;
2321 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2323 /* Fill the list, sorted by id... */
2324 for (i = 0; i < ci->nActiveChildren; i++)
2327 /* Find the window with the current ID */
2328 for (pWnd = WIN_LockWndPtr(pParentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd, pWnd->next))
2329 if (pWnd->wIDmenu == ci->idFirstChild + i)
2330 break;
2332 SendMessageA(hListBox, LB_ADDSTRING, 0, (LPARAM) pWnd->text);
2333 SendMessageA(hListBox, LB_SETITEMDATA, i, (LPARAM) pWnd);
2334 length = strlen(pWnd->text);
2335 WIN_ReleaseWndPtr(pWnd);
2337 if (length > widest)
2338 widest = length;
2340 /* Make sure the horizontal scrollbar scrolls ok */
2341 SendMessageA(hListBox, LB_SETHORIZONTALEXTENT, widest * 6, 0);
2343 /* Set the current selection */
2344 SendMessageA(hListBox, LB_SETCURSEL, MDI_MOREWINDOWSLIMIT, 0);
2345 return TRUE;
2348 case WM_COMMAND:
2349 switch (LOWORD(wParam))
2351 case IDOK:
2353 /* windows are sorted by menu ID, so we must return the
2354 * window associated to the given id
2356 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2357 UINT index = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
2358 WND* pWnd = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
2360 EndDialog(hDlg, pWnd->hwndSelf);
2361 return TRUE;
2363 case IDCANCEL:
2364 EndDialog(hDlg, 0);
2365 return TRUE;
2367 default:
2368 switch (HIWORD(wParam))
2370 case LBN_DBLCLK:
2372 /* windows are sorted by menu ID, so we must return the
2373 * window associated to the given id
2375 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2376 UINT index = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
2377 WND* pWnd = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
2379 EndDialog(hDlg, pWnd->hwndSelf);
2380 return TRUE;
2383 break;
2385 break;
2387 return FALSE;
2392 * MDI_MoreWindowsDialog
2394 * Prompts the user with a listbox containing the opened
2395 * documents. The user can then choose a windows and click
2396 * on OK to set the current window to the one selected, or
2397 * CANCEL to cancel. The function returns a handle to the
2398 * selected window.
2401 static HWND MDI_MoreWindowsDialog(WND* wndPtr)
2403 LPCVOID template;
2404 HRSRC hRes;
2405 HANDLE hDlgTmpl;
2407 hRes = FindResourceA(GetModuleHandleA("USER32"), "MDI_MOREWINDOWS", RT_DIALOGA);
2409 if (hRes == 0)
2410 return 0;
2412 hDlgTmpl = LoadResource(GetModuleHandleA("USER32"), hRes );
2414 if (hDlgTmpl == 0)
2415 return 0;
2417 template = LockResource( hDlgTmpl );
2419 if (template == 0)
2420 return 0;
2422 return (HWND) DialogBoxIndirectParamA(GetModuleHandleA("USER32"),
2423 (LPDLGTEMPLATEA) template,
2424 wndPtr->hwndSelf,
2425 (DLGPROC) MDI_MoreWindowsDlgProc,
2426 (LPARAM) wndPtr);
2431 * MDI_SwapMenuItems
2433 * Will swap the menu IDs for the given 2 positions.
2434 * pos1 and pos2 are menu IDs
2439 static void MDI_SwapMenuItems(WND *parentWnd, UINT pos1, UINT pos2)
2441 WND *pWnd;
2443 for (pWnd = WIN_LockWndPtr(parentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2445 if (pWnd->wIDmenu == pos1)
2446 pWnd->wIDmenu = pos2;
2447 else
2448 if (pWnd->wIDmenu == pos2)
2449 pWnd->wIDmenu = pos1;
2452 WIN_ReleaseWndPtr(pWnd);