Moved some macros like NULL, FALSE to winnt.h
[wine.git] / windows / mdi.c
blobca96da60caf9ef3fe55a6371fa928fba7be0b0a0
1 /* MDI.C
3 * Copyright 1994, Bob Amstadt
4 * 1995,1996 Alex Korobka
6 * This file contains routines to support MDI (Multiple Document
7 * Interface) features .
9 * Notes: Fairly complete implementation.
10 * Also, Excel and WinWord do _not_ use MDI so if you're trying
11 * to fix them look elsewhere.
13 * Notes on how the "More Windows..." is implemented:
15 * When we have more than 9 opened windows, a "More Windows..."
16 * option appears in the "Windows" menu. Each child window has
17 * a WND* associated with it, accesible via the children list of
18 * the parent window. This WND* has a wIDmenu member, which reflects
19 * the position of the child in the window list. For example, with
20 * 9 child windows, we could have the following pattern:
24 * Name of the child window pWndChild->wIDmenu
25 * Doc1 5000
26 * Doc2 5001
27 * Doc3 5002
28 * Doc4 5003
29 * Doc5 5004
30 * Doc6 5005
31 * Doc7 5006
32 * Doc8 5007
33 * Doc9 5008
36 * The "Windows" menu, as the "More windows..." dialog, are constructed
37 * in this order. If we add a child, we would have the following list:
40 * Name of the child window pWndChild->wIDmenu
41 * Doc1 5000
42 * Doc2 5001
43 * Doc3 5002
44 * Doc4 5003
45 * Doc5 5004
46 * Doc6 5005
47 * Doc7 5006
48 * Doc8 5007
49 * Doc9 5008
50 * Doc10 5009
52 * But only 5000 to 5008 would be displayed in the "Windows" menu. We want
53 * the last created child to be in the menu, so we swap the last child with
54 * the 9th... Doc9 will be accessible via the "More Windows..." option.
56 * Doc1 5000
57 * Doc2 5001
58 * Doc3 5002
59 * Doc4 5003
60 * Doc5 5004
61 * Doc6 5005
62 * Doc7 5006
63 * Doc8 5007
64 * Doc9 5009
65 * Doc10 5008
69 #include <stdlib.h>
70 #include <stdio.h>
71 #include <string.h>
72 #include <math.h>
73 #include "windef.h"
74 #include "wingdi.h"
75 #include "winuser.h"
76 #include "wine/unicode.h"
77 #include "win.h"
78 #include "heap.h"
79 #include "nonclient.h"
80 #include "controls.h"
81 #include "user.h"
82 #include "struct32.h"
83 #include "tweak.h"
84 #include "debugtools.h"
85 #include "dlgs.h"
87 DEFAULT_DEBUG_CHANNEL(mdi);
89 #define MDI_MAXLISTLENGTH 0x40
90 #define MDI_MAXTITLELENGTH 0xa1
92 #define MDI_NOFRAMEREPAINT 0
93 #define MDI_REPAINTFRAMENOW 1
94 #define MDI_REPAINTFRAME 2
96 #define WM_MDICALCCHILDSCROLL 0x10ac /* this is exactly what Windows uses */
98 /* "More Windows..." definitions */
99 #define MDI_MOREWINDOWSLIMIT 9 /* after this number of windows, a "More Windows..."
100 option will appear under the Windows menu */
101 #define MDI_IDC_LISTBOX 100
102 #define MDI_IDS_MOREWINDOWS 13
104 #define MDIF_NEEDUPDATE 0x0001
106 typedef struct
108 UINT nActiveChildren;
109 HWND hwndChildMaximized;
110 HWND hwndActiveChild;
111 HMENU hWindowMenu;
112 UINT idFirstChild;
113 LPWSTR frameTitle;
114 UINT nTotalCreated;
115 UINT mdiFlags;
116 UINT sbRecalc; /* SB_xxx flags for scrollbar fixup */
117 HWND self;
118 } MDICLIENTINFO;
120 static HBITMAP16 hBmpClose = 0;
121 static HBITMAP16 hBmpRestore = 0;
123 /* ----------------- declarations ----------------- */
124 static void MDI_UpdateFrameText(WND *, HWND, BOOL, LPCWSTR);
125 static BOOL MDI_AugmentFrameMenu(MDICLIENTINFO*, WND *, HWND);
126 static BOOL MDI_RestoreFrameMenu(WND *, HWND);
128 static LONG MDI_ChildActivate( WND*, HWND );
130 static HWND MDI_MoreWindowsDialog(WND*);
131 static void MDI_SwapMenuItems(WND *, UINT, UINT);
132 static LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
133 /* -------- Miscellaneous service functions ----------
135 * MDI_GetChildByID
138 static HWND MDI_GetChildByID(WND* wndPtr, INT id)
140 for (wndPtr = wndPtr->child; wndPtr; wndPtr = wndPtr->next)
141 if (wndPtr->wIDmenu == id) return wndPtr->hwndSelf;
142 return 0;
145 static void MDI_PostUpdate(HWND hwnd, MDICLIENTINFO* ci, WORD recalc)
147 if( !(ci->mdiFlags & MDIF_NEEDUPDATE) )
149 ci->mdiFlags |= MDIF_NEEDUPDATE;
150 PostMessageA( hwnd, WM_MDICALCCHILDSCROLL, 0, 0);
152 ci->sbRecalc = recalc;
156 /*********************************************************************
157 * MDIClient class descriptor
159 const struct builtin_class_descr MDICLIENT_builtin_class =
161 "MDIClient", /* name */
162 CS_GLOBALCLASS, /* style */
163 MDIClientWndProcA, /* procA */
164 NULL, /* procW (FIXME) */
165 sizeof(MDICLIENTINFO), /* extra */
166 IDC_ARROWA, /* cursor */
167 COLOR_APPWORKSPACE+1 /* brush */
171 /**********************************************************************
172 * MDI_MenuModifyItem
174 static BOOL MDI_MenuModifyItem(WND* clientWnd, HWND hWndChild )
176 WCHAR buffer[128];
177 static const WCHAR format[] = {'%','d',' ',0};
178 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
179 WND *wndPtr = WIN_FindWndPtr(hWndChild);
180 UINT n = wsprintfW(buffer, format,
181 wndPtr->wIDmenu - clientInfo->idFirstChild + 1);
182 BOOL bRet = 0;
184 if( !clientInfo->hWindowMenu )
186 bRet = FALSE;
187 goto END;
190 if (wndPtr->text) lstrcpynW(buffer + n, wndPtr->text, sizeof(buffer)/sizeof(WCHAR) - n );
192 n = GetMenuState(clientInfo->hWindowMenu,wndPtr->wIDmenu ,MF_BYCOMMAND);
193 bRet = ModifyMenuW(clientInfo->hWindowMenu , wndPtr->wIDmenu,
194 MF_BYCOMMAND | MF_STRING, wndPtr->wIDmenu, buffer );
195 CheckMenuItem(clientInfo->hWindowMenu ,wndPtr->wIDmenu , n & MF_CHECKED);
196 END:
197 WIN_ReleaseWndPtr(wndPtr);
198 return bRet;
201 /**********************************************************************
202 * MDI_MenuDeleteItem
204 static BOOL MDI_MenuDeleteItem(WND* clientWnd, HWND hWndChild )
206 WCHAR buffer[128];
207 static const WCHAR format[] = {'&','%','d',' ',0};
208 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
209 WND *wndPtr = WIN_FindWndPtr(hWndChild);
210 UINT index = 0,id,n;
211 BOOL retvalue;
213 if( !clientInfo->nActiveChildren ||
214 !clientInfo->hWindowMenu )
216 retvalue = FALSE;
217 goto END;
220 id = wndPtr->wIDmenu;
221 DeleteMenu(clientInfo->hWindowMenu,id,MF_BYCOMMAND);
223 /* walk the rest of MDI children to prevent gaps in the id
224 * sequence and in the menu child list */
226 for( index = id+1; index <= clientInfo->nActiveChildren +
227 clientInfo->idFirstChild; index++ )
229 WND *tmpWnd = WIN_FindWndPtr(MDI_GetChildByID(clientWnd,index));
230 if( !tmpWnd )
232 TRACE("no window for id=%i\n",index);
233 WIN_ReleaseWndPtr(tmpWnd);
234 continue;
237 /* set correct id */
238 tmpWnd->wIDmenu--;
240 n = wsprintfW(buffer, format ,index - clientInfo->idFirstChild);
241 if (tmpWnd->text)
242 lstrcpynW(buffer + n, tmpWnd->text, sizeof(buffer)/sizeof(WCHAR) - n );
244 /* change menu if the current child is to be shown in the
245 * "Windows" menu
247 if (index <= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
248 ModifyMenuW(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING,
249 index - 1 , buffer );
250 WIN_ReleaseWndPtr(tmpWnd);
253 /* We must restore the "More Windows..." option if there is enough child
255 if (clientInfo->nActiveChildren - 1 > MDI_MOREWINDOWSLIMIT)
257 char szTmp[50];
258 LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
260 AppendMenuA(clientInfo->hWindowMenu ,MF_STRING ,clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT, szTmp );
262 retvalue = TRUE;
263 END:
264 WIN_ReleaseWndPtr(wndPtr);
265 return retvalue;
268 /**********************************************************************
269 * MDI_GetWindow
271 * returns "activateable" child different from the current or zero
273 static HWND MDI_GetWindow(WND *clientWnd, HWND hWnd, BOOL bNext,
274 DWORD dwStyleMask )
276 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
277 WND *wndPtr, *pWnd, *pWndLast = NULL;
279 dwStyleMask |= WS_DISABLED | WS_VISIBLE;
280 if( !hWnd ) hWnd = clientInfo->hwndActiveChild;
282 if( !(wndPtr = WIN_FindWndPtr(hWnd)) ) return 0;
284 for ( pWnd = WIN_LockWndPtr(wndPtr->next); ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
286 if (!pWnd ) WIN_UpdateWndPtr(&pWnd,wndPtr->parent->child);
288 if ( pWnd == wndPtr ) break; /* went full circle */
290 if (!pWnd->owner && (pWnd->dwStyle & dwStyleMask) == WS_VISIBLE )
292 pWndLast = pWnd;
293 if ( bNext ) break;
296 WIN_ReleaseWndPtr(wndPtr);
297 WIN_ReleaseWndPtr(pWnd);
298 return pWndLast ? pWndLast->hwndSelf : 0;
301 /**********************************************************************
302 * MDI_CalcDefaultChildPos
304 * It seems that the default height is about 2/3 of the client rect
306 static void MDI_CalcDefaultChildPos( WND* w, WORD n, LPPOINT lpPos,
307 INT delta)
309 INT nstagger;
310 RECT rect = w->rectClient;
311 INT spacing = GetSystemMetrics(SM_CYCAPTION) +
312 GetSystemMetrics(SM_CYFRAME) - 1;
314 if( rect.bottom - rect.top - delta >= spacing )
315 rect.bottom -= delta;
317 nstagger = (rect.bottom - rect.top)/(3 * spacing);
318 lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
319 lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
320 lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
323 /**********************************************************************
324 * MDISetMenu
326 static LRESULT MDISetMenu( HWND hwnd, HMENU hmenuFrame,
327 HMENU hmenuWindow)
329 WND *w;
330 MDICLIENTINFO *ci;
331 HWND hwndFrame = GetParent(hwnd);
332 HMENU oldFrameMenu = GetMenu(hwndFrame);
334 TRACE("%04x %04x %04x\n",
335 hwnd, hmenuFrame, hmenuWindow);
337 if (hmenuFrame && !IsMenu(hmenuFrame))
339 WARN("hmenuFrame is not a menu handle\n");
340 return 0L;
343 if (hmenuWindow && !IsMenu(hmenuWindow))
345 WARN("hmenuWindow is not a menu handle\n");
346 return 0L;
349 w = WIN_FindWndPtr(hwnd);
350 ci = (MDICLIENTINFO *) w->wExtra;
352 if( ci->hwndChildMaximized && hmenuFrame && hmenuFrame!=oldFrameMenu )
353 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized );
355 if( hmenuWindow && ci->hWindowMenu && hmenuWindow!=ci->hWindowMenu )
357 /* delete menu items from ci->hWindowMenu
358 * and add them to hmenuWindow */
360 INT i = GetMenuItemCount(ci->hWindowMenu) - 1;
361 INT pos = GetMenuItemCount(hmenuWindow) + 1;
363 AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL);
365 if( ci->nActiveChildren )
367 INT j;
368 LPWSTR buffer = NULL;
369 MENUITEMINFOW mii;
370 INT nbWindowsMenuItems; /* num of documents shown + "More Windows..." if present */
372 if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
373 nbWindowsMenuItems = ci->nActiveChildren;
374 else
375 nbWindowsMenuItems = MDI_MOREWINDOWSLIMIT + 1;
377 j = i - nbWindowsMenuItems + 1;
379 for( ; i >= j ; i-- )
381 memset(&mii, 0, sizeof(mii));
382 mii.cbSize = sizeof(mii);
383 mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE
384 | MIIM_SUBMENU | MIIM_TYPE | MIIM_BITMAP;
386 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
387 if(mii.cch) { /* Menu is MFT_STRING */
388 mii.cch++; /* add room for '\0' */
389 buffer = HeapAlloc(GetProcessHeap(), 0,
390 mii.cch * sizeof(WCHAR));
391 mii.dwTypeData = buffer;
392 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
394 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
395 InsertMenuItemW(hmenuWindow, pos, TRUE, &mii);
396 if(buffer) {
397 HeapFree(GetProcessHeap(), 0, buffer);
398 buffer = NULL;
403 /* remove separator */
404 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
406 ci->hWindowMenu = hmenuWindow;
409 if (hmenuFrame)
411 SetMenu(hwndFrame, hmenuFrame);
412 if( hmenuFrame!=oldFrameMenu )
414 if( ci->hwndChildMaximized )
415 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
416 WIN_ReleaseWndPtr(w);
417 return oldFrameMenu;
420 else
422 INT nItems = GetMenuItemCount(w->parent->wIDmenu) - 1;
423 UINT iId = GetMenuItemID(w->parent->wIDmenu,nItems) ;
425 if( !(iId == SC_RESTORE || iId == SC_CLOSE) )
427 /* SetMenu() may already have been called, meaning that this window
428 * already has its menu. But they may have done a SetMenu() on
429 * an MDI window, and called MDISetMenu() after the fact, meaning
430 * that the "if" to this "else" wouldn't catch the need to
431 * augment the frame menu.
433 if( ci->hwndChildMaximized )
434 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
437 WIN_ReleaseWndPtr(w);
438 return 0;
441 /**********************************************************************
442 * MDIRefreshMenu
444 static LRESULT MDIRefreshMenu( HWND hwnd, HMENU hmenuFrame,
445 HMENU hmenuWindow)
447 HWND hwndFrame = GetParent(hwnd);
448 HMENU oldFrameMenu = GetMenu(hwndFrame);
450 TRACE("%04x %04x %04x\n",
451 hwnd, hmenuFrame, hmenuWindow);
453 FIXME("partially function stub\n");
455 return oldFrameMenu;
459 /* ------------------ MDI child window functions ---------------------- */
462 /**********************************************************************
463 * MDICreateChild
465 static HWND MDICreateChild( WND *w, MDICLIENTINFO *ci, HWND parent,
466 LPMDICREATESTRUCTA cs )
468 POINT pos[2];
469 DWORD style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
470 HWND hwnd, hwndMax = 0;
471 WORD wIDmenu = ci->idFirstChild + ci->nActiveChildren;
472 char lpstrDef[]="junk!";
474 TRACE("origin %i,%i - dim %i,%i, style %08lx\n",
475 cs->x, cs->y, cs->cx, cs->cy, cs->style);
476 /* calculate placement */
477 MDI_CalcDefaultChildPos(w, ci->nTotalCreated++, pos, 0);
479 if (cs->cx == CW_USEDEFAULT || !cs->cx) cs->cx = pos[1].x;
480 if (cs->cy == CW_USEDEFAULT || !cs->cy) cs->cy = pos[1].y;
482 if( cs->x == CW_USEDEFAULT )
484 cs->x = pos[0].x;
485 cs->y = pos[0].y;
488 /* restore current maximized child */
489 if( (style & WS_VISIBLE) && ci->hwndChildMaximized )
491 TRACE("Restoring current maximized child %04x\n", ci->hwndChildMaximized);
492 if( style & WS_MAXIMIZE )
493 SendMessageA(w->hwndSelf, WM_SETREDRAW, FALSE, 0L );
494 hwndMax = ci->hwndChildMaximized;
495 ShowWindow( hwndMax, SW_SHOWNOACTIVATE );
496 if( style & WS_MAXIMIZE )
497 SendMessageA(w->hwndSelf, WM_SETREDRAW, TRUE, 0L );
500 if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
501 /* this menu is needed to set a check mark in MDI_ChildActivate */
502 if (ci->hWindowMenu != 0)
503 AppendMenuA(ci->hWindowMenu ,MF_STRING ,wIDmenu, lpstrDef );
505 ci->nActiveChildren++;
507 /* fix window style */
508 if( !(w->dwStyle & MDIS_ALLCHILDSTYLES) )
510 TRACE("MDIS_ALLCHILDSTYLES is missing, fixing window style\n");
511 style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE |
512 WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL );
513 style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW);
516 if( w->flags & WIN_ISWIN32 )
518 hwnd = CreateWindowA( cs->szClass, cs->szTitle, style,
519 cs->x, cs->y, cs->cx, cs->cy, parent,
520 (HMENU)wIDmenu, cs->hOwner, cs );
522 else
524 MDICREATESTRUCT16 *cs16;
525 LPSTR title, cls;
527 cs16 = SEGPTR_NEW(MDICREATESTRUCT16);
528 STRUCT32_MDICREATESTRUCT32Ato16( cs, cs16 );
529 title = SEGPTR_STRDUP( cs->szTitle );
530 cls = SEGPTR_STRDUP( cs->szClass );
531 cs16->szTitle = SEGPTR_GET(title);
532 cs16->szClass = SEGPTR_GET(cls);
534 hwnd = CreateWindow16( cs->szClass, cs->szTitle, style,
535 cs16->x, cs16->y, cs16->cx, cs16->cy, parent,
536 (HMENU)wIDmenu, cs16->hOwner,
537 (LPVOID)SEGPTR_GET(cs16) );
538 SEGPTR_FREE( title );
539 SEGPTR_FREE( cls );
540 SEGPTR_FREE( cs16 );
543 /* MDI windows are WS_CHILD so they won't be activated by CreateWindow */
545 if (hwnd)
547 WND* wnd = WIN_FindWndPtr( hwnd );
549 /* All MDI child windows have the WS_EX_MDICHILD style */
550 wnd->dwExStyle |= WS_EX_MDICHILD;
552 /* If we have more than 9 windows, we must insert the new one at the
553 * 9th position in order to see it in the "Windows" menu
555 if (ci->nActiveChildren > MDI_MOREWINDOWSLIMIT)
556 MDI_SwapMenuItems(wnd->parent, wnd->wIDmenu, ci->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
558 MDI_MenuModifyItem(w ,hwnd);
560 /* Have we hit the "More Windows..." limit? If so, we must
561 * add a "More Windows..." option
563 if (ci->nActiveChildren == MDI_MOREWINDOWSLIMIT + 1)
565 char szTmp[50];
566 LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
568 ModifyMenuA(ci->hWindowMenu,
569 ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
570 MF_BYCOMMAND | MF_STRING,
571 ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
572 szTmp);
575 if( (wnd->dwStyle & WS_MINIMIZE) && ci->hwndActiveChild )
577 TRACE("Minimizing created MDI child %04x\n", hwnd);
578 ShowWindow( hwnd, SW_SHOWMINNOACTIVE );
580 else
582 /* WS_VISIBLE is clear if a) the MDI client has
583 * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the
584 * MDICreateStruct. If so the created window is not shown nor
585 * activated.
587 if(wnd->dwStyle & WS_VISIBLE)
588 ShowWindow(hwnd, SW_SHOW);
590 WIN_ReleaseWndPtr(wnd);
591 TRACE("created child - %04x\n",hwnd);
593 else
595 ci->nActiveChildren--;
596 DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
597 if( IsWindow(hwndMax) )
598 ShowWindow(hwndMax, SW_SHOWMAXIMIZED);
601 return hwnd;
604 /**********************************************************************
605 * MDI_ChildGetMinMaxInfo
607 * Note: The rule here is that client rect of the maximized MDI child
608 * is equal to the client rect of the MDI client window.
610 static void MDI_ChildGetMinMaxInfo( WND* clientWnd, HWND hwnd,
611 MINMAXINFO16* lpMinMax )
613 WND* childWnd = WIN_FindWndPtr(hwnd);
614 RECT rect = clientWnd->rectClient;
616 MapWindowPoints( clientWnd->parent->hwndSelf,
617 ((MDICLIENTINFO*)clientWnd->wExtra)->self, (LPPOINT)&rect, 2);
618 AdjustWindowRectEx( &rect, childWnd->dwStyle, 0, childWnd->dwExStyle );
620 lpMinMax->ptMaxSize.x = rect.right -= rect.left;
621 lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
623 lpMinMax->ptMaxPosition.x = rect.left;
624 lpMinMax->ptMaxPosition.y = rect.top;
626 WIN_ReleaseWndPtr(childWnd);
628 TRACE("max rect (%i,%i - %i, %i)\n",
629 rect.left,rect.top,rect.right,rect.bottom);
633 /**********************************************************************
634 * MDI_SwitchActiveChild
636 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
637 * being activated
639 static void MDI_SwitchActiveChild( HWND clientHwnd, HWND childHwnd,
640 BOOL bNextWindow )
642 WND *w = WIN_FindWndPtr(clientHwnd);
643 HWND hwndTo = 0;
644 HWND hwndPrev = 0;
645 MDICLIENTINFO *ci;
647 hwndTo = MDI_GetWindow(w, childHwnd, bNextWindow, 0);
649 ci = (MDICLIENTINFO *) w->wExtra;
651 TRACE("from %04x, to %04x\n",childHwnd,hwndTo);
653 if ( !hwndTo ) goto END; /* no window to switch to */
655 hwndPrev = ci->hwndActiveChild;
657 if ( hwndTo != hwndPrev )
659 BOOL bOptimize = 0;
661 if( ci->hwndChildMaximized )
663 bOptimize = 1;
664 w->dwStyle &= ~WS_VISIBLE;
667 SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0,
668 SWP_NOMOVE | SWP_NOSIZE );
670 if( bNextWindow && hwndPrev )
671 SetWindowPos( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0,
672 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
673 if( bOptimize )
674 ShowWindow( clientHwnd, SW_SHOW );
676 END:
677 WIN_ReleaseWndPtr(w);
681 /**********************************************************************
682 * MDIDestroyChild
684 static LRESULT MDIDestroyChild( WND *w_parent, MDICLIENTINFO *ci,
685 HWND parent, HWND child,
686 BOOL flagDestroy )
688 WND *childPtr = WIN_FindWndPtr(child);
690 if( childPtr )
692 if( child == ci->hwndActiveChild )
694 MDI_SwitchActiveChild(parent, child, TRUE);
696 if( child == ci->hwndActiveChild )
698 ShowWindow( child, SW_HIDE);
699 if( child == ci->hwndChildMaximized )
701 MDI_RestoreFrameMenu(w_parent->parent, child);
702 ci->hwndChildMaximized = 0;
703 MDI_UpdateFrameText(w_parent->parent,parent,TRUE,NULL);
706 MDI_ChildActivate(w_parent, 0);
710 MDI_MenuDeleteItem(w_parent, child);
712 WIN_ReleaseWndPtr(childPtr);
714 ci->nActiveChildren--;
716 TRACE("child destroyed - %04x\n",child);
718 if (flagDestroy)
720 MDI_PostUpdate(GetParent(child), ci, SB_BOTH+1);
721 DestroyWindow(child);
725 return 0;
729 /**********************************************************************
730 * MDI_ChildActivate
732 * Note: hWndChild is NULL when last child is being destroyed
734 static LONG MDI_ChildActivate( WND *clientPtr, HWND hWndChild )
736 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientPtr->wExtra;
737 HWND prevActiveWnd = clientInfo->hwndActiveChild;
738 WND *wndPtr = WIN_FindWndPtr( hWndChild );
739 WND *wndPrev = WIN_FindWndPtr( prevActiveWnd );
740 BOOL isActiveFrameWnd = 0;
741 LONG retvalue;
743 if( wndPtr )
745 if( wndPtr->dwStyle & WS_DISABLED )
747 retvalue = 0L;
748 goto END;
752 /* Don't activate if it is already active. Might happen
753 since ShowWindow DOES activate MDI children */
754 if (clientInfo->hwndActiveChild == hWndChild)
756 retvalue = 0L;
757 goto END;
760 TRACE("%04x\n", hWndChild);
762 if( GetActiveWindow() == clientPtr->parent->hwndSelf )
763 isActiveFrameWnd = TRUE;
765 /* deactivate prev. active child */
766 if( wndPrev )
768 wndPrev->dwStyle |= WS_SYSMENU;
769 SendMessageA( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
770 SendMessageA( prevActiveWnd, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
771 (LPARAM)hWndChild);
772 /* uncheck menu item */
773 if( clientInfo->hWindowMenu )
775 WORD wPrevID = wndPrev->wIDmenu - clientInfo->idFirstChild;
777 if (wPrevID < MDI_MOREWINDOWSLIMIT)
778 CheckMenuItem( clientInfo->hWindowMenu,
779 wndPrev->wIDmenu, 0);
780 else
781 CheckMenuItem( clientInfo->hWindowMenu,
782 clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1, 0);
786 /* set appearance */
787 if( clientInfo->hwndChildMaximized )
789 if( clientInfo->hwndChildMaximized != hWndChild ) {
790 if( hWndChild ) {
791 clientInfo->hwndActiveChild = hWndChild;
792 ShowWindow( hWndChild, SW_SHOWMAXIMIZED);
793 } else
794 ShowWindow( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
798 clientInfo->hwndActiveChild = hWndChild;
800 /* check if we have any children left */
801 if( !hWndChild )
803 if( isActiveFrameWnd )
804 SetFocus( clientInfo->self );
805 retvalue = 0;
806 goto END;
809 /* check menu item */
810 if( clientInfo->hWindowMenu )
812 /* The window to be activated must be displayed in the "Windows" menu */
813 if (wndPtr->wIDmenu >= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
815 MDI_SwapMenuItems(wndPtr->parent, wndPtr->wIDmenu, clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
816 MDI_MenuModifyItem(wndPtr->parent ,wndPtr->hwndSelf);
819 CheckMenuItem(clientInfo->hWindowMenu, wndPtr->wIDmenu, MF_CHECKED);
821 /* bring active child to the top */
822 SetWindowPos( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
824 if( isActiveFrameWnd )
826 SendMessageA( hWndChild, WM_NCACTIVATE, TRUE, 0L);
827 if( GetFocus() == clientInfo->self )
828 SendMessageA( clientInfo->self, WM_SETFOCUS,
829 (WPARAM)clientInfo->self, 0L );
830 else
831 SetFocus( clientInfo->self );
833 SendMessageA( hWndChild, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
834 (LPARAM)hWndChild );
835 retvalue = 1;
836 END:
837 WIN_ReleaseWndPtr(wndPtr);
838 WIN_ReleaseWndPtr(wndPrev);
839 return retvalue;
842 /* -------------------- MDI client window functions ------------------- */
844 /**********************************************************************
845 * CreateMDIMenuBitmap
847 static HBITMAP16 CreateMDIMenuBitmap(void)
849 HDC hDCSrc = CreateCompatibleDC(0);
850 HDC hDCDest = CreateCompatibleDC(hDCSrc);
851 HBITMAP16 hbClose = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_CLOSE) );
852 HBITMAP16 hbCopy;
853 HANDLE16 hobjSrc, hobjDest;
855 hobjSrc = SelectObject(hDCSrc, hbClose);
856 hbCopy = CreateCompatibleBitmap(hDCSrc,GetSystemMetrics(SM_CXSIZE),GetSystemMetrics(SM_CYSIZE));
857 hobjDest = SelectObject(hDCDest, hbCopy);
859 BitBlt(hDCDest, 0, 0, GetSystemMetrics(SM_CXSIZE), GetSystemMetrics(SM_CYSIZE),
860 hDCSrc, GetSystemMetrics(SM_CXSIZE), 0, SRCCOPY);
862 SelectObject(hDCSrc, hobjSrc);
863 DeleteObject(hbClose);
864 DeleteDC(hDCSrc);
866 hobjSrc = SelectObject( hDCDest, GetStockObject(BLACK_PEN) );
868 MoveToEx( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, 0, NULL );
869 LineTo( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, GetSystemMetrics(SM_CYSIZE) - 1);
871 SelectObject(hDCDest, hobjSrc );
872 SelectObject(hDCDest, hobjDest);
873 DeleteDC(hDCDest);
875 return hbCopy;
878 /**********************************************************************
879 * MDICascade
881 static LONG MDICascade(WND* clientWnd, MDICLIENTINFO *ci)
883 WND** ppWnd;
884 UINT total;
886 if (ci->hwndChildMaximized)
887 SendMessageA( clientWnd->hwndSelf, WM_MDIRESTORE,
888 (WPARAM)ci->hwndChildMaximized, 0);
890 if (ci->nActiveChildren == 0) return 0;
892 if ((ppWnd = WIN_BuildWinArray(clientWnd, BWA_SKIPHIDDEN | BWA_SKIPOWNED |
893 BWA_SKIPICONIC, &total)))
895 WND** heapPtr = ppWnd;
896 if( total )
898 INT delta = 0, n = 0;
899 POINT pos[2];
900 if( total < ci->nActiveChildren )
901 delta = GetSystemMetrics(SM_CYICONSPACING) +
902 GetSystemMetrics(SM_CYICON);
904 /* walk the list (backwards) and move windows */
905 while (*ppWnd) ppWnd++;
906 while (ppWnd != heapPtr)
908 ppWnd--;
909 TRACE("move %04x to (%ld,%ld) size [%ld,%ld]\n",
910 (*ppWnd)->hwndSelf, pos[0].x, pos[0].y, pos[1].x, pos[1].y);
912 MDI_CalcDefaultChildPos(clientWnd, n++, pos, delta);
913 SetWindowPos( (*ppWnd)->hwndSelf, 0, pos[0].x, pos[0].y,
914 pos[1].x, pos[1].y,
915 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
918 WIN_ReleaseWinArray(heapPtr);
921 if( total < ci->nActiveChildren )
922 ArrangeIconicWindows( clientWnd->hwndSelf );
923 return 0;
926 /**********************************************************************
927 * MDITile
929 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM wParam )
931 WND** ppWnd;
932 UINT total = 0;
934 if (ci->hwndChildMaximized)
935 SendMessageA( wndClient->hwndSelf, WM_MDIRESTORE,
936 (WPARAM)ci->hwndChildMaximized, 0);
938 if (ci->nActiveChildren == 0) return;
940 ppWnd = WIN_BuildWinArray(wndClient, BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
941 ((wParam & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
943 TRACE("%u windows to tile\n", total);
945 if( ppWnd )
947 WND** heapPtr = ppWnd;
949 if( total )
951 RECT rect;
952 int x, y, xsize, ysize;
953 int rows, columns, r, c, i;
955 GetClientRect(wndClient->hwndSelf,&rect);
956 rows = (int) sqrt((double)total);
957 columns = total / rows;
959 if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */
961 i = rows;
962 rows = columns; /* exchange r and c */
963 columns = i;
966 if( total != ci->nActiveChildren)
968 y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
969 rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
972 ysize = rect.bottom / rows;
973 xsize = rect.right / columns;
975 for (x = i = 0, c = 1; c <= columns && *ppWnd; c++)
977 if (c == columns)
979 rows = total - i;
980 ysize = rect.bottom / rows;
983 y = 0;
984 for (r = 1; r <= rows && *ppWnd; r++, i++)
986 SetWindowPos((*ppWnd)->hwndSelf, 0, x, y, xsize, ysize,
987 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
988 y += ysize;
989 ppWnd++;
991 x += xsize;
994 WIN_ReleaseWinArray(heapPtr);
997 if( total < ci->nActiveChildren ) ArrangeIconicWindows( wndClient->hwndSelf );
1000 /* ----------------------- Frame window ---------------------------- */
1003 /**********************************************************************
1004 * MDI_AugmentFrameMenu
1006 static BOOL MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
1007 HWND hChild )
1009 WND* child = WIN_FindWndPtr(hChild);
1010 HMENU hSysPopup = 0;
1011 HBITMAP hSysMenuBitmap = 0;
1013 TRACE("frame %p,child %04x\n",frame,hChild);
1015 if( !frame->wIDmenu || !child->hSysMenu )
1017 WIN_ReleaseWndPtr(child);
1018 return 0;
1020 WIN_ReleaseWndPtr(child);
1022 /* create a copy of sysmenu popup and insert it into frame menu bar */
1024 if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
1025 return 0;
1027 TRACE("\tgot popup %04x in sysmenu %04x\n",
1028 hSysPopup, child->hSysMenu);
1030 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
1031 SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
1032 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
1033 SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
1035 /* In Win 95 look, the system menu is replaced by the child icon */
1037 if(TWEAK_WineLook > WIN31_LOOK)
1039 HICON hIcon = GetClassLongA(hChild, GCL_HICONSM);
1040 if (!hIcon)
1041 hIcon = GetClassLongA(hChild, GCL_HICON);
1042 if (hIcon)
1044 HDC hMemDC;
1045 HBITMAP hBitmap, hOldBitmap;
1046 HBRUSH hBrush;
1047 HDC hdc = GetDC(hChild);
1049 if (hdc)
1051 int cx, cy;
1052 cx = GetSystemMetrics(SM_CXSMICON);
1053 cy = GetSystemMetrics(SM_CYSMICON);
1054 hMemDC = CreateCompatibleDC(hdc);
1055 hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
1056 hOldBitmap = SelectObject(hMemDC, hBitmap);
1057 SetMapMode(hMemDC, MM_TEXT);
1058 hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
1059 DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL);
1060 SelectObject (hMemDC, hOldBitmap);
1061 DeleteObject(hBrush);
1062 DeleteDC(hMemDC);
1063 ReleaseDC(hChild, hdc);
1064 hSysMenuBitmap = hBitmap;
1068 else
1069 hSysMenuBitmap = hBmpClose;
1071 if( !InsertMenuA(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
1072 hSysPopup, (LPSTR)(DWORD)hSysMenuBitmap))
1074 TRACE("not inserted\n");
1075 DestroyMenu(hSysPopup);
1076 return 0;
1079 /* The close button is only present in Win 95 look */
1080 if(TWEAK_WineLook > WIN31_LOOK)
1082 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
1083 SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
1086 EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
1087 EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
1088 EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
1089 SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE);
1091 /* redraw menu */
1092 DrawMenuBar(frame->hwndSelf);
1094 return 1;
1097 /**********************************************************************
1098 * MDI_RestoreFrameMenu
1100 static BOOL MDI_RestoreFrameMenu( WND *frameWnd, HWND hChild )
1102 MENUITEMINFOA menuInfo;
1103 INT nItems = GetMenuItemCount(frameWnd->wIDmenu) - 1;
1104 UINT iId = GetMenuItemID(frameWnd->wIDmenu,nItems) ;
1106 TRACE("frameWnd %p,(%04x),child %04x,nIt=%d,iId=%d\n",
1107 frameWnd,frameWnd->hwndSelf,hChild,nItems,iId);
1109 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
1110 return 0;
1113 * Remove the system menu, If that menu is the icon of the window
1114 * as it is in win95, we have to delete the bitmap.
1116 menuInfo.cbSize = sizeof(MENUITEMINFOA);
1117 menuInfo.fMask = MIIM_DATA | MIIM_TYPE;
1119 GetMenuItemInfoA(frameWnd->wIDmenu,
1121 TRUE,
1122 &menuInfo);
1124 RemoveMenu(frameWnd->wIDmenu,0,MF_BYPOSITION);
1126 if ( (menuInfo.fType & MFT_BITMAP) &&
1127 (LOWORD(menuInfo.dwTypeData)!=0) &&
1128 (LOWORD(menuInfo.dwTypeData)!=hBmpClose) )
1130 DeleteObject((HBITMAP)LOWORD(menuInfo.dwTypeData));
1133 if(TWEAK_WineLook > WIN31_LOOK)
1135 /* close */
1136 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1138 /* restore */
1139 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1140 /* minimize */
1141 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1143 DrawMenuBar(frameWnd->hwndSelf);
1145 return 1;
1149 /**********************************************************************
1150 * MDI_UpdateFrameText
1152 * used when child window is maximized/restored
1154 * Note: lpTitle can be NULL
1156 static void MDI_UpdateFrameText( WND *frameWnd, HWND hClient,
1157 BOOL repaint, LPCWSTR lpTitle )
1159 WCHAR lpBuffer[MDI_MAXTITLELENGTH+1];
1160 WND* clientWnd = WIN_FindWndPtr(hClient);
1161 MDICLIENTINFO *ci = (MDICLIENTINFO *) clientWnd->wExtra;
1163 TRACE("repaint %i, frameText %s\n", repaint, (lpTitle)?debugstr_w(lpTitle):"NULL");
1165 if (!clientWnd)
1166 return;
1168 if (!ci)
1170 WIN_ReleaseWndPtr(clientWnd);
1171 return;
1174 /* store new "default" title if lpTitle is not NULL */
1175 if (lpTitle)
1177 if (ci->frameTitle) HeapFree( SystemHeap, 0, ci->frameTitle );
1178 ci->frameTitle = HEAP_strdupW( SystemHeap, 0, lpTitle );
1181 if (ci->frameTitle)
1183 WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );
1185 if( childWnd && childWnd->text )
1187 /* combine frame title and child title if possible */
1189 static const WCHAR lpBracket[] = {' ','-',' ','[',0};
1190 static const WCHAR lpBracket2[] = {']',0};
1191 int i_frame_text_length = strlenW(ci->frameTitle);
1192 int i_child_text_length = strlenW(childWnd->text);
1194 lstrcpynW( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
1196 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
1198 strcatW( lpBuffer, lpBracket );
1200 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
1202 strcatW( lpBuffer, childWnd->text );
1203 strcatW( lpBuffer, lpBracket2 );
1205 else
1207 lstrcpynW( lpBuffer + i_frame_text_length + 4,
1208 childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
1209 strcatW( lpBuffer, lpBracket2 );
1213 else
1215 lstrcpynW(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH+1 );
1217 WIN_ReleaseWndPtr(childWnd);
1220 else
1221 lpBuffer[0] = '\0';
1223 DEFWND_SetTextW( frameWnd, lpBuffer );
1224 if( repaint == MDI_REPAINTFRAME)
1225 SetWindowPos( frameWnd->hwndSelf, 0,0,0,0,0, SWP_FRAMECHANGED |
1226 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
1228 WIN_ReleaseWndPtr(clientWnd);
1233 /* ----------------------------- Interface ---------------------------- */
1236 /**********************************************************************
1237 * MDIClientWndProcA
1239 * This function handles all MDI requests.
1241 static LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
1243 LPCREATESTRUCTA cs;
1244 MDICLIENTINFO *ci;
1245 RECT rect;
1246 WND *w, *frameWnd;
1247 INT nItems;
1248 LRESULT retvalue;
1250 if ( ( w = WIN_FindWndPtr(hwnd) ) == NULL )
1251 return 0;
1253 if ( ( frameWnd = WIN_LockWndPtr(w->parent) ) == NULL ) {
1254 WIN_ReleaseWndPtr(w);
1255 return 0;
1258 ci = (MDICLIENTINFO *) w->wExtra;
1260 switch (message)
1262 case WM_CREATE:
1264 cs = (LPCREATESTRUCTA)lParam;
1266 /* Translation layer doesn't know what's in the cs->lpCreateParams
1267 * so we have to keep track of what environment we're in. */
1269 if( w->flags & WIN_ISWIN32 )
1271 #define ccs ((LPCLIENTCREATESTRUCT)cs->lpCreateParams)
1272 ci->hWindowMenu = ccs->hWindowMenu;
1273 ci->idFirstChild = ccs->idFirstChild;
1274 #undef ccs
1276 else
1278 LPCLIENTCREATESTRUCT16 ccs = MapSL((SEGPTR)cs->lpCreateParams);
1279 ci->hWindowMenu = ccs->hWindowMenu;
1280 ci->idFirstChild = ccs->idFirstChild;
1283 ci->hwndChildMaximized = 0;
1284 ci->nActiveChildren = 0;
1285 ci->nTotalCreated = 0;
1286 ci->frameTitle = NULL;
1287 ci->mdiFlags = 0;
1288 ci->self = hwnd;
1289 w->dwStyle |= WS_CLIPCHILDREN;
1291 if (!hBmpClose)
1293 hBmpClose = CreateMDIMenuBitmap();
1294 hBmpRestore = LoadBitmapA( 0, MAKEINTRESOURCEA(OBM_RESTORE) );
1296 MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
1298 if (ci->hWindowMenu != 0)
1299 AppendMenuA( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
1301 GetClientRect(frameWnd->hwndSelf, &rect);
1302 NC_HandleNCCalcSize( w, &rect );
1303 w->rectClient = rect;
1305 TRACE("Client created - hwnd = %04x, idFirst = %u\n",
1306 hwnd, ci->idFirstChild );
1308 retvalue = 0;
1309 goto END;
1311 case WM_DESTROY:
1312 if( ci->hwndChildMaximized )
1313 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized);
1314 if((ci->hWindowMenu != 0) &&
1315 (nItems = GetMenuItemCount(ci->hWindowMenu)) > 0)
1317 ci->idFirstChild = nItems - 1;
1318 ci->nActiveChildren++; /* to delete a separator */
1319 while( ci->nActiveChildren-- )
1320 DeleteMenu(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
1322 retvalue = 0;
1323 goto END;
1325 case WM_MDIACTIVATE:
1326 if( ci->hwndActiveChild != (HWND)wParam )
1327 SetWindowPos((HWND)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
1328 retvalue = 0;
1329 goto END;
1331 case WM_MDICASCADE:
1332 retvalue = MDICascade(w, ci);
1333 goto END;
1335 case WM_MDICREATE:
1336 if (lParam) retvalue = MDICreateChild( w, ci, hwnd,
1337 (MDICREATESTRUCTA*)lParam );
1338 else retvalue = 0;
1339 goto END;
1341 case WM_MDIDESTROY:
1342 retvalue = MDIDestroyChild( w, ci, hwnd, (HWND)wParam, TRUE );
1343 goto END;
1345 case WM_MDIGETACTIVE:
1346 if (lParam) *(BOOL *)lParam = (ci->hwndChildMaximized > 0);
1347 retvalue = ci->hwndActiveChild;
1348 goto END;
1350 case WM_MDIICONARRANGE:
1351 ci->mdiFlags |= MDIF_NEEDUPDATE;
1352 ArrangeIconicWindows(hwnd);
1353 ci->sbRecalc = SB_BOTH+1;
1354 SendMessageA(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
1355 retvalue = 0;
1356 goto END;
1358 case WM_MDIMAXIMIZE:
1359 ShowWindow( (HWND)wParam, SW_MAXIMIZE );
1360 retvalue = 0;
1361 goto END;
1363 case WM_MDINEXT: /* lParam != 0 means previous window */
1364 MDI_SwitchActiveChild(hwnd, (HWND)wParam, (lParam)? FALSE : TRUE );
1365 break;
1367 case WM_MDIRESTORE:
1368 SendMessageA( (HWND)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
1369 retvalue = 0;
1370 goto END;
1372 case WM_MDISETMENU:
1373 retvalue = MDISetMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1374 goto END;
1375 case WM_MDIREFRESHMENU:
1376 retvalue = MDIRefreshMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1377 goto END;
1379 case WM_MDITILE:
1380 ci->mdiFlags |= MDIF_NEEDUPDATE;
1381 ShowScrollBar(hwnd,SB_BOTH,FALSE);
1382 MDITile(w, ci, wParam);
1383 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1384 retvalue = 0;
1385 goto END;
1387 case WM_VSCROLL:
1388 case WM_HSCROLL:
1389 ci->mdiFlags |= MDIF_NEEDUPDATE;
1390 ScrollChildren(hwnd, message, wParam, lParam);
1391 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1392 retvalue = 0;
1393 goto END;
1395 case WM_SETFOCUS:
1396 if( ci->hwndActiveChild )
1398 WND* pw = WIN_FindWndPtr( ci->hwndActiveChild );
1399 if( !(pw->dwStyle & WS_MINIMIZE) )
1400 SetFocus( ci->hwndActiveChild );
1401 WIN_ReleaseWndPtr(pw);
1403 retvalue = 0;
1404 goto END;
1406 case WM_NCACTIVATE:
1407 if( ci->hwndActiveChild )
1408 SendMessageA(ci->hwndActiveChild, message, wParam, lParam);
1409 break;
1411 case WM_PARENTNOTIFY:
1412 if (LOWORD(wParam) == WM_LBUTTONDOWN)
1414 HWND child;
1415 POINT pt;
1416 pt.x = SLOWORD(lParam);
1417 pt.y = SHIWORD(lParam);
1418 child = ChildWindowFromPoint(hwnd, pt);
1420 TRACE("notification from %04x (%li,%li)\n",child,pt.x,pt.y);
1422 if( child && child != hwnd && child != ci->hwndActiveChild )
1423 SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1425 retvalue = 0;
1426 goto END;
1428 case WM_SIZE:
1429 if( IsWindow(ci->hwndChildMaximized) )
1431 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1432 RECT rect;
1434 rect.left = 0;
1435 rect.top = 0;
1436 rect.right = LOWORD(lParam);
1437 rect.bottom = HIWORD(lParam);
1439 AdjustWindowRectEx(&rect, child->dwStyle, 0, child->dwExStyle);
1440 MoveWindow(ci->hwndChildMaximized, rect.left, rect.top,
1441 rect.right - rect.left, rect.bottom - rect.top, 1);
1442 WIN_ReleaseWndPtr(child);
1444 else
1445 MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1447 break;
1449 case WM_MDICALCCHILDSCROLL:
1450 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1452 CalcChildScroll16(hwnd, ci->sbRecalc-1);
1453 ci->sbRecalc = 0;
1454 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1456 retvalue = 0;
1457 goto END;
1460 retvalue = DefWindowProcA( hwnd, message, wParam, lParam );
1461 END:
1462 WIN_ReleaseWndPtr(w);
1463 WIN_ReleaseWndPtr(frameWnd);
1464 return retvalue;
1468 /***********************************************************************
1469 * DefFrameProc16 (USER.445)
1471 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1472 UINT16 message, WPARAM16 wParam, LPARAM lParam )
1474 HWND16 childHwnd;
1475 MDICLIENTINFO* ci;
1476 WND* wndPtr;
1478 if (hwndMDIClient)
1480 switch (message)
1482 case WM_COMMAND:
1483 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1485 if (!wndPtr) {
1486 ERR("null wndPtr for mdi window hwndMDIClient=%04x\n",
1487 hwndMDIClient);
1488 return 0;
1491 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1493 /* check for possible syscommands for maximized MDI child */
1494 WIN_ReleaseWndPtr(wndPtr);
1496 if( ci && (
1497 wParam < ci->idFirstChild ||
1498 wParam >= ci->idFirstChild + ci->nActiveChildren
1500 if( (wParam - 0xF000) & 0xF00F ) break;
1501 switch( wParam )
1503 case SC_SIZE:
1504 case SC_MOVE:
1505 case SC_MINIMIZE:
1506 case SC_MAXIMIZE:
1507 case SC_NEXTWINDOW:
1508 case SC_PREVWINDOW:
1509 case SC_CLOSE:
1510 case SC_RESTORE:
1511 if( ci->hwndChildMaximized )
1512 return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1513 wParam, lParam);
1516 else
1518 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1519 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1521 if (wParam - ci->idFirstChild == MDI_MOREWINDOWSLIMIT)
1522 /* User chose "More Windows..." */
1523 childHwnd = MDI_MoreWindowsDialog(wndPtr);
1524 else
1525 /* User chose one of the windows listed in the "Windows" menu */
1526 childHwnd = MDI_GetChildByID(wndPtr,wParam );
1528 WIN_ReleaseWndPtr(wndPtr);
1529 if( childHwnd )
1530 SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1531 (WPARAM16)childHwnd , 0L);
1533 break;
1535 case WM_NCACTIVATE:
1536 SendMessage16(hwndMDIClient, message, wParam, lParam);
1537 break;
1539 case WM_SETTEXT:
1541 LPWSTR text = HEAP_strdupAtoW( GetProcessHeap(), 0, MapSL(lParam) );
1542 wndPtr = WIN_FindWndPtr(hwnd);
1543 MDI_UpdateFrameText(wndPtr, hwndMDIClient,
1544 MDI_REPAINTFRAME, text );
1545 WIN_ReleaseWndPtr(wndPtr);
1546 HeapFree( GetProcessHeap(), 0, text );
1548 return 1; /* success. FIXME: check text length */
1550 case WM_SETFOCUS:
1551 SetFocus(hwndMDIClient);
1552 break;
1554 case WM_SIZE:
1555 MoveWindow16(hwndMDIClient, 0, 0,
1556 LOWORD(lParam), HIWORD(lParam), TRUE);
1557 break;
1559 case WM_NEXTMENU:
1561 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1562 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1564 if( !(wndPtr->parent->dwStyle & WS_MINIMIZE)
1565 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1567 /* control menu is between the frame system menu and
1568 * the first entry of menu bar */
1570 if( (wParam == VK_LEFT &&
1571 wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1572 (wParam == VK_RIGHT &&
1573 GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1575 LRESULT retvalue;
1576 WIN_ReleaseWndPtr(wndPtr);
1577 wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1578 retvalue = MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1579 ci->hwndActiveChild);
1580 WIN_ReleaseWndPtr(wndPtr);
1581 return retvalue;
1584 WIN_ReleaseWndPtr(wndPtr);
1585 break;
1589 return DefWindowProc16(hwnd, message, wParam, lParam);
1593 /***********************************************************************
1594 * DefFrameProcA (USER32.122)
1596 LRESULT WINAPI DefFrameProcA( HWND hwnd, HWND hwndMDIClient,
1597 UINT message, WPARAM wParam, LPARAM lParam)
1599 if (hwndMDIClient)
1601 switch (message)
1603 case WM_COMMAND:
1604 return DefFrameProc16( hwnd, hwndMDIClient, message,
1605 (WPARAM16)wParam,
1606 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1608 case WM_NCACTIVATE:
1609 SendMessageA(hwndMDIClient, message, wParam, lParam);
1610 break;
1612 case WM_SETTEXT: {
1613 LRESULT ret;
1614 LPSTR segstr = SEGPTR_STRDUP((LPSTR)lParam);
1616 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1617 wParam, (LPARAM)SEGPTR_GET(segstr) );
1618 SEGPTR_FREE(segstr);
1619 return ret;
1622 case WM_NEXTMENU:
1623 case WM_SETFOCUS:
1624 case WM_SIZE:
1625 return DefFrameProc16( hwnd, hwndMDIClient, message,
1626 wParam, lParam );
1630 return DefWindowProcA(hwnd, message, wParam, lParam);
1634 /***********************************************************************
1635 * DefFrameProcW (USER32.123)
1637 LRESULT WINAPI DefFrameProcW( HWND hwnd, HWND hwndMDIClient,
1638 UINT message, WPARAM wParam, LPARAM lParam)
1640 if (hwndMDIClient)
1642 switch (message)
1644 case WM_COMMAND:
1645 return DefFrameProc16( hwnd, hwndMDIClient, message,
1646 (WPARAM16)wParam,
1647 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1649 case WM_NCACTIVATE:
1650 SendMessageW(hwndMDIClient, message, wParam, lParam);
1651 break;
1653 case WM_SETTEXT:
1655 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1656 LRESULT ret = DefFrameProcA( hwnd, hwndMDIClient, message,
1657 wParam, (DWORD)txt );
1658 HeapFree(GetProcessHeap(),0,txt);
1659 return ret;
1661 case WM_NEXTMENU:
1662 case WM_SETFOCUS:
1663 case WM_SIZE:
1664 return DefFrameProcA( hwnd, hwndMDIClient, message,
1665 wParam, lParam );
1669 return DefWindowProcW( hwnd, message, wParam, lParam );
1673 /***********************************************************************
1674 * DefMDIChildProc16 (USER.447)
1676 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1677 WPARAM16 wParam, LPARAM lParam )
1679 MDICLIENTINFO *ci;
1680 WND *clientWnd,*tmpWnd = 0;
1681 LRESULT retvalue;
1683 tmpWnd = WIN_FindWndPtr(hwnd);
1684 if (!tmpWnd) return 0;
1685 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1686 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1687 WIN_ReleaseWndPtr(tmpWnd);
1689 /* Sanity check */
1690 if (clientWnd->cbWndExtra < sizeof(MDICLIENTINFO))
1692 WARN("called on non-MDI child window %x\n", hwnd);
1693 WIN_ReleaseWndPtr(clientWnd);
1694 return DefWindowProc16(hwnd, message, wParam, lParam);
1697 switch (message)
1699 case WM_SETTEXT:
1700 DefWindowProc16(hwnd, message, wParam, lParam);
1701 MDI_MenuModifyItem(clientWnd,hwnd);
1702 if( ci->hwndChildMaximized == hwnd )
1703 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1704 MDI_REPAINTFRAME, NULL );
1705 retvalue = 1; /* success. FIXME: check text length */
1706 goto END;
1708 case WM_CLOSE:
1709 SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1710 retvalue = 0;
1711 goto END;
1713 case WM_SETFOCUS:
1714 if( ci->hwndActiveChild != hwnd )
1715 MDI_ChildActivate(clientWnd, hwnd);
1716 break;
1718 case WM_CHILDACTIVATE:
1719 MDI_ChildActivate(clientWnd, hwnd);
1720 retvalue = 0;
1721 goto END;
1723 case WM_NCPAINT:
1724 TRACE("WM_NCPAINT for %04x, active %04x\n",
1725 hwnd, ci->hwndActiveChild );
1726 break;
1728 case WM_SYSCOMMAND:
1729 switch( wParam )
1731 case SC_MOVE:
1732 if( ci->hwndChildMaximized == hwnd)
1734 retvalue = 0;
1735 goto END;
1737 break;
1738 case SC_RESTORE:
1739 case SC_MINIMIZE:
1740 tmpWnd = WIN_FindWndPtr(hwnd);
1741 tmpWnd->dwStyle |= WS_SYSMENU;
1742 WIN_ReleaseWndPtr(tmpWnd);
1743 break;
1744 case SC_MAXIMIZE:
1745 if( ci->hwndChildMaximized == hwnd)
1747 retvalue = SendMessage16( clientWnd->parent->hwndSelf,
1748 message, wParam, lParam);
1749 goto END;
1751 tmpWnd = WIN_FindWndPtr(hwnd);
1752 tmpWnd->dwStyle &= ~WS_SYSMENU;
1753 WIN_ReleaseWndPtr(tmpWnd);
1754 break;
1755 case SC_NEXTWINDOW:
1756 SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1757 retvalue = 0;
1758 goto END;
1759 case SC_PREVWINDOW:
1760 SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1761 retvalue = 0;
1762 goto END;
1764 break;
1766 case WM_GETMINMAXINFO:
1767 MDI_ChildGetMinMaxInfo(clientWnd, hwnd, MapSL(lParam));
1768 retvalue = 0;
1769 goto END;
1771 case WM_SETVISIBLE:
1772 if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1773 else
1774 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1775 break;
1777 case WM_SIZE:
1778 /* do not change */
1780 if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1782 ci->hwndChildMaximized = 0;
1784 MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1785 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1786 MDI_REPAINTFRAME, NULL );
1789 if( wParam == SIZE_MAXIMIZED )
1791 HWND16 hMaxChild = ci->hwndChildMaximized;
1793 if( hMaxChild == hwnd ) break;
1795 if( hMaxChild)
1797 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1799 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1800 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1802 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1805 TRACE("maximizing child %04x\n", hwnd );
1808 * Keep track of the maximized window.
1810 ci->hwndChildMaximized = hwnd; /* !!! */
1813 * The maximized window should also be the active window
1815 MDI_ChildActivate(clientWnd, hwnd);
1817 MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1818 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1819 MDI_REPAINTFRAME, NULL );
1822 if( wParam == SIZE_MINIMIZED )
1824 HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1826 if( switchTo )
1827 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1830 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1831 break;
1833 case WM_MENUCHAR:
1835 /* MDI children don't have menu bars */
1836 retvalue = 0x00010000L;
1837 goto END;
1839 case WM_NEXTMENU:
1841 if( wParam == VK_LEFT ) /* switch to frame system menu */
1843 retvalue = MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1844 clientWnd->parent->hwndSelf );
1845 goto END;
1847 if( wParam == VK_RIGHT ) /* to frame menu bar */
1849 retvalue = MAKELONG( clientWnd->parent->wIDmenu,
1850 clientWnd->parent->hwndSelf );
1851 goto END;
1854 break;
1856 case WM_SYSCHAR:
1857 if (wParam == '-')
1859 SendMessage16(hwnd,WM_SYSCOMMAND,
1860 (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1861 retvalue = 0;
1862 goto END;
1866 retvalue = DefWindowProc16(hwnd, message, wParam, lParam);
1867 END:
1868 WIN_ReleaseWndPtr(clientWnd);
1869 return retvalue;
1873 /***********************************************************************
1874 * DefMDIChildProcA (USER32.124)
1876 LRESULT WINAPI DefMDIChildProcA( HWND hwnd, UINT message,
1877 WPARAM wParam, LPARAM lParam )
1879 MDICLIENTINFO *ci;
1880 WND *clientWnd,*tmpWnd;
1881 LRESULT retvalue;
1883 tmpWnd = WIN_FindWndPtr(hwnd);
1884 if (!tmpWnd) return 0;
1885 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1886 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1887 WIN_ReleaseWndPtr(tmpWnd);
1889 /* Sanity check */
1890 if (clientWnd->cbWndExtra < sizeof(MDICLIENTINFO))
1892 WARN("called on non-MDI child window %x\n", hwnd);
1893 WIN_ReleaseWndPtr(clientWnd);
1894 return DefWindowProcA(hwnd, message, wParam, lParam);
1897 switch (message)
1899 case WM_SETTEXT:
1900 DefWindowProcA(hwnd, message, wParam, lParam);
1901 MDI_MenuModifyItem(clientWnd,hwnd);
1902 if( ci->hwndChildMaximized == hwnd )
1903 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1904 MDI_REPAINTFRAME, NULL );
1905 retvalue = 1; /* success. FIXME: check text length */
1906 goto END;
1908 case WM_GETMINMAXINFO:
1910 MINMAXINFO16 mmi;
1911 STRUCT32_MINMAXINFO32to16( (MINMAXINFO *)lParam, &mmi );
1912 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1913 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO *)lParam );
1915 retvalue = 0;
1916 goto END;
1918 case WM_MENUCHAR:
1920 /* MDI children don't have menu bars */
1921 retvalue = 0x00010000L;
1922 goto END;
1924 case WM_CLOSE:
1925 case WM_SETFOCUS:
1926 case WM_CHILDACTIVATE:
1927 case WM_NCPAINT:
1928 case WM_SYSCOMMAND:
1929 case WM_SETVISIBLE:
1930 case WM_SIZE:
1931 case WM_NEXTMENU:
1932 retvalue = DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1933 goto END;
1935 case WM_SYSCHAR:
1936 if (wParam == '-')
1938 SendMessageA(hwnd,WM_SYSCOMMAND,
1939 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1940 retvalue = 0;
1941 goto END;
1944 retvalue = DefWindowProcA(hwnd, message, wParam, lParam);
1945 END:
1946 WIN_ReleaseWndPtr(clientWnd);
1947 return retvalue;
1951 /***********************************************************************
1952 * DefMDIChildProcW (USER32.125)
1954 LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message,
1955 WPARAM wParam, LPARAM lParam )
1957 MDICLIENTINFO *ci;
1958 WND *clientWnd,*tmpWnd;
1959 LRESULT retvalue;
1961 tmpWnd = WIN_FindWndPtr(hwnd);
1962 if (!tmpWnd) return 0;
1963 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1964 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1965 WIN_ReleaseWndPtr(tmpWnd);
1967 /* Sanity check */
1968 if (clientWnd->cbWndExtra < sizeof(MDICLIENTINFO))
1970 WARN("called on non-MDI child window %x\n", hwnd);
1971 WIN_ReleaseWndPtr(clientWnd);
1972 return DefWindowProcW(hwnd, message, wParam, lParam);
1975 switch (message)
1977 case WM_SETTEXT:
1978 DefWindowProcW(hwnd, message, wParam, lParam);
1979 MDI_MenuModifyItem(clientWnd,hwnd);
1980 if( ci->hwndChildMaximized == hwnd )
1981 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1982 MDI_REPAINTFRAME, NULL );
1983 retvalue = 1; /* success. FIXME: check text length */
1984 goto END;
1986 case WM_GETMINMAXINFO:
1987 case WM_MENUCHAR:
1988 case WM_CLOSE:
1989 case WM_SETFOCUS:
1990 case WM_CHILDACTIVATE:
1991 case WM_NCPAINT:
1992 case WM_SYSCOMMAND:
1993 case WM_SETVISIBLE:
1994 case WM_SIZE:
1995 case WM_NEXTMENU:
1996 retvalue = DefMDIChildProcA( hwnd, message, (WPARAM16)wParam, lParam );
1997 goto END;
1999 case WM_SYSCHAR:
2000 if (wParam == '-')
2002 SendMessageW(hwnd,WM_SYSCOMMAND,
2003 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
2004 retvalue = 0;
2005 goto END;
2008 retvalue = DefWindowProcW(hwnd, message, wParam, lParam);
2009 END:
2010 WIN_ReleaseWndPtr(clientWnd);
2011 return retvalue;
2016 /**********************************************************************
2017 * CreateMDIWindowA [USER32.79] Creates a MDI child in new thread
2018 * FIXME: its in the same thread now
2020 * RETURNS
2021 * Success: Handle to created window
2022 * Failure: NULL
2024 HWND WINAPI CreateMDIWindowA(
2025 LPCSTR lpClassName, /* [in] Pointer to registered child class name */
2026 LPCSTR lpWindowName, /* [in] Pointer to window name */
2027 DWORD dwStyle, /* [in] Window style */
2028 INT X, /* [in] Horizontal position of window */
2029 INT Y, /* [in] Vertical position of window */
2030 INT nWidth, /* [in] Width of window */
2031 INT nHeight, /* [in] Height of window */
2032 HWND hWndParent, /* [in] Handle to parent window */
2033 HINSTANCE hInstance, /* [in] Handle to application instance */
2034 LPARAM lParam) /* [in] Application-defined value */
2036 WARN("is only single threaded!\n");
2037 return MDI_CreateMDIWindowA(lpClassName, lpWindowName, dwStyle, X, Y,
2038 nWidth, nHeight, hWndParent, hInstance, lParam);
2041 /**********************************************************************
2042 * MDI_CreateMDIWindowA
2043 * single threaded version of CreateMDIWindowA
2044 * called by CreateWindowExA
2046 HWND MDI_CreateMDIWindowA(
2047 LPCSTR lpClassName,
2048 LPCSTR lpWindowName,
2049 DWORD dwStyle,
2050 INT X,
2051 INT Y,
2052 INT nWidth,
2053 INT nHeight,
2054 HWND hWndParent,
2055 HINSTANCE hInstance,
2056 LPARAM lParam)
2058 MDICLIENTINFO* pCi;
2059 MDICREATESTRUCTA cs;
2060 WND *pWnd=WIN_FindWndPtr(hWndParent);
2061 HWND retvalue;
2063 TRACE("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
2064 debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
2065 nWidth,nHeight,hWndParent,hInstance,lParam);
2067 if(!pWnd){
2068 ERR(" bad hwnd for MDI-client: %d\n",hWndParent);
2069 return 0;
2071 cs.szClass=lpClassName;
2072 cs.szTitle=lpWindowName;
2073 cs.hOwner=hInstance;
2074 cs.x=X;
2075 cs.y=Y;
2076 cs.cx=nWidth;
2077 cs.cy=nHeight;
2078 cs.style=dwStyle;
2079 cs.lParam=lParam;
2081 pCi=(MDICLIENTINFO *)pWnd->wExtra;
2083 retvalue = MDICreateChild(pWnd,pCi,hWndParent,&cs);
2084 WIN_ReleaseWndPtr(pWnd);
2085 return retvalue;
2088 /***********************************************************************
2089 * CreateMDIWindowW [USER32.80] Creates a MDI child in new thread
2091 * RETURNS
2092 * Success: Handle to created window
2093 * Failure: NULL
2095 HWND WINAPI CreateMDIWindowW(
2096 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
2097 LPCWSTR lpWindowName, /* [in] Pointer to window name */
2098 DWORD dwStyle, /* [in] Window style */
2099 INT X, /* [in] Horizontal position of window */
2100 INT Y, /* [in] Vertical position of window */
2101 INT nWidth, /* [in] Width of window */
2102 INT nHeight, /* [in] Height of window */
2103 HWND hWndParent, /* [in] Handle to parent window */
2104 HINSTANCE hInstance, /* [in] Handle to application instance */
2105 LPARAM lParam) /* [in] Application-defined value */
2107 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
2108 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
2109 nWidth,nHeight,hWndParent,hInstance,lParam);
2110 return (HWND)NULL;
2114 /******************************************************************************
2115 * CreateMDIWindowW [USER32.80] Creates a MDI child window
2116 * single threaded version of CreateMDIWindow
2117 * called by CreateWindowExW().
2119 HWND MDI_CreateMDIWindowW(
2120 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
2121 LPCWSTR lpWindowName, /* [in] Pointer to window name */
2122 DWORD dwStyle, /* [in] Window style */
2123 INT X, /* [in] Horizontal position of window */
2124 INT Y, /* [in] Vertical position of window */
2125 INT nWidth, /* [in] Width of window */
2126 INT nHeight, /* [in] Height of window */
2127 HWND hWndParent, /* [in] Handle to parent window */
2128 HINSTANCE hInstance, /* [in] Handle to application instance */
2129 LPARAM lParam) /* [in] Application-defined value */
2131 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
2132 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
2133 nWidth,nHeight,hWndParent,hInstance,lParam);
2134 return (HWND)NULL;
2138 /**********************************************************************
2139 * TranslateMDISysAccel (USER32.555)
2141 BOOL WINAPI TranslateMDISysAccel( HWND hwndClient, LPMSG msg )
2143 MSG16 msg16;
2145 STRUCT32_MSG32to16(msg,&msg16);
2146 /* MDICLIENTINFO is still the same for win32 and win16 ... */
2147 return TranslateMDISysAccel16(hwndClient,&msg16);
2151 /**********************************************************************
2152 * TranslateMDISysAccel16 (USER.451)
2154 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
2157 if( IsWindow(hwndClient) && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
2159 MDICLIENTINFO *ci = NULL;
2160 HWND wnd;
2161 WND *clientWnd = WIN_FindWndPtr(hwndClient);
2163 ci = (MDICLIENTINFO*) clientWnd->wExtra;
2164 wnd = ci->hwndActiveChild;
2166 WIN_ReleaseWndPtr(clientWnd);
2168 if( IsWindow(wnd) && !(GetWindowLongA(wnd,GWL_STYLE) & WS_DISABLED) )
2170 WPARAM16 wParam = 0;
2172 /* translate if the Ctrl key is down and Alt not. */
2174 if( (GetKeyState(VK_CONTROL) & 0x8000) &&
2175 !(GetKeyState(VK_MENU) & 0x8000))
2177 switch( msg->wParam )
2179 case VK_F6:
2180 case VK_TAB:
2181 wParam = ( GetKeyState(VK_SHIFT) & 0x8000 )
2182 ? SC_NEXTWINDOW : SC_PREVWINDOW;
2183 break;
2184 case VK_F4:
2185 case VK_RBUTTON:
2186 wParam = SC_CLOSE;
2187 break;
2188 default:
2189 return 0;
2191 TRACE("wParam = %04x\n", wParam);
2192 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
2193 wParam, (LPARAM)msg->wParam);
2194 return 1;
2198 return 0; /* failure */
2202 /***********************************************************************
2203 * CalcChildScroll (USER.462)
2205 void WINAPI CalcChildScroll16( HWND16 hwnd, WORD scroll )
2207 SCROLLINFO info;
2208 RECT childRect, clientRect;
2209 INT vmin, vmax, hmin, hmax, vpos, hpos;
2210 WND *pWnd, *Wnd;
2212 if (!(pWnd = WIN_FindWndPtr( hwnd ))) return;
2213 Wnd = WIN_FindWndPtr(hwnd);
2214 GetClientRect( hwnd, &clientRect );
2215 SetRectEmpty( &childRect );
2217 for ( WIN_UpdateWndPtr(&pWnd,pWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2219 if( pWnd->dwStyle & WS_MAXIMIZE )
2221 ShowScrollBar(hwnd, SB_BOTH, FALSE);
2222 WIN_ReleaseWndPtr(pWnd);
2223 WIN_ReleaseWndPtr(Wnd);
2224 return;
2226 UnionRect( &childRect, &pWnd->rectWindow, &childRect );
2228 WIN_ReleaseWndPtr(pWnd);
2229 UnionRect( &childRect, &clientRect, &childRect );
2231 hmin = childRect.left; hmax = childRect.right - clientRect.right;
2232 hpos = clientRect.left - childRect.left;
2233 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
2234 vpos = clientRect.top - childRect.top;
2236 switch( scroll )
2238 case SB_HORZ:
2239 vpos = hpos; vmin = hmin; vmax = hmax;
2240 case SB_VERT:
2241 info.cbSize = sizeof(info);
2242 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
2243 info.fMask = SIF_POS | SIF_RANGE;
2244 SetScrollInfo(hwnd, scroll, &info, TRUE);
2245 break;
2246 case SB_BOTH:
2247 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
2248 hmin, hmax, hpos);
2250 WIN_ReleaseWndPtr(Wnd);
2254 /***********************************************************************
2255 * ScrollChildren16 (USER.463)
2257 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
2259 ScrollChildren( hWnd, uMsg, wParam, lParam );
2263 /***********************************************************************
2264 * ScrollChildren (USER32.448)
2266 void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
2267 LPARAM lParam)
2269 WND *wndPtr = WIN_FindWndPtr(hWnd);
2270 INT newPos = -1;
2271 INT curPos, length, minPos, maxPos, shift;
2273 if( !wndPtr ) return;
2275 if( uMsg == WM_HSCROLL )
2277 GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
2278 curPos = GetScrollPos(hWnd,SB_HORZ);
2279 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
2280 shift = GetSystemMetrics(SM_CYHSCROLL);
2282 else if( uMsg == WM_VSCROLL )
2284 GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
2285 curPos = GetScrollPos(hWnd,SB_VERT);
2286 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
2287 shift = GetSystemMetrics(SM_CXVSCROLL);
2289 else
2291 WIN_ReleaseWndPtr(wndPtr);
2292 return;
2295 WIN_ReleaseWndPtr(wndPtr);
2296 switch( wParam )
2298 case SB_LINEUP:
2299 newPos = curPos - shift;
2300 break;
2301 case SB_LINEDOWN:
2302 newPos = curPos + shift;
2303 break;
2304 case SB_PAGEUP:
2305 newPos = curPos - length;
2306 break;
2307 case SB_PAGEDOWN:
2308 newPos = curPos + length;
2309 break;
2311 case SB_THUMBPOSITION:
2312 newPos = LOWORD(lParam);
2313 break;
2315 case SB_THUMBTRACK:
2316 return;
2318 case SB_TOP:
2319 newPos = minPos;
2320 break;
2321 case SB_BOTTOM:
2322 newPos = maxPos;
2323 break;
2324 case SB_ENDSCROLL:
2325 CalcChildScroll16(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
2326 return;
2329 if( newPos > maxPos )
2330 newPos = maxPos;
2331 else
2332 if( newPos < minPos )
2333 newPos = minPos;
2335 SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
2337 if( uMsg == WM_VSCROLL )
2338 ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
2339 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2340 else
2341 ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
2342 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2346 /******************************************************************************
2347 * CascadeWindows [USER32.21] Cascades MDI child windows
2349 * RETURNS
2350 * Success: Number of cascaded windows.
2351 * Failure: 0
2353 WORD WINAPI
2354 CascadeWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2355 UINT cKids, const HWND *lpKids)
2357 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2358 hwndParent, wFlags, cKids);
2360 return 0;
2364 /******************************************************************************
2365 * TileWindows [USER32.545] Tiles MDI child windows
2367 * RETURNS
2368 * Success: Number of tiled windows.
2369 * Failure: 0
2371 WORD WINAPI
2372 TileWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2373 UINT cKids, const HWND *lpKids)
2375 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2376 hwndParent, wFlags, cKids);
2378 return 0;
2381 /************************************************************************
2382 * "More Windows..." functionality
2385 /* MDI_MoreWindowsDlgProc
2387 * This function will process the messages sent to the "More Windows..."
2388 * dialog.
2389 * Return values: 0 = cancel pressed
2390 * HWND = ok pressed or double-click in the list...
2394 static BOOL WINAPI MDI_MoreWindowsDlgProc (HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
2396 switch (iMsg)
2398 case WM_INITDIALOG:
2400 WND *pWnd;
2401 UINT widest = 0;
2402 UINT length;
2403 UINT i;
2404 WND *pParentWnd = (WND *)lParam;
2405 MDICLIENTINFO *ci = (MDICLIENTINFO*)pParentWnd->wExtra;
2406 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2408 /* Fill the list, sorted by id... */
2409 for (i = 0; i < ci->nActiveChildren; i++)
2412 /* Find the window with the current ID */
2413 for (pWnd = WIN_LockWndPtr(pParentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd, pWnd->next))
2414 if (pWnd->wIDmenu == ci->idFirstChild + i)
2415 break;
2417 SendMessageW(hListBox, LB_ADDSTRING, 0, (LPARAM) pWnd->text);
2418 SendMessageA(hListBox, LB_SETITEMDATA, i, (LPARAM) pWnd);
2419 length = strlenW(pWnd->text);
2420 WIN_ReleaseWndPtr(pWnd);
2422 if (length > widest)
2423 widest = length;
2425 /* Make sure the horizontal scrollbar scrolls ok */
2426 SendMessageA(hListBox, LB_SETHORIZONTALEXTENT, widest * 6, 0);
2428 /* Set the current selection */
2429 SendMessageA(hListBox, LB_SETCURSEL, MDI_MOREWINDOWSLIMIT, 0);
2430 return TRUE;
2433 case WM_COMMAND:
2434 switch (LOWORD(wParam))
2436 case IDOK:
2438 /* windows are sorted by menu ID, so we must return the
2439 * window associated to the given id
2441 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2442 UINT index = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
2443 WND* pWnd = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
2445 EndDialog(hDlg, pWnd->hwndSelf);
2446 return TRUE;
2448 case IDCANCEL:
2449 EndDialog(hDlg, 0);
2450 return TRUE;
2452 default:
2453 switch (HIWORD(wParam))
2455 case LBN_DBLCLK:
2457 /* windows are sorted by menu ID, so we must return the
2458 * window associated to the given id
2460 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2461 UINT index = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
2462 WND* pWnd = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
2464 EndDialog(hDlg, pWnd->hwndSelf);
2465 return TRUE;
2468 break;
2470 break;
2472 return FALSE;
2477 * MDI_MoreWindowsDialog
2479 * Prompts the user with a listbox containing the opened
2480 * documents. The user can then choose a windows and click
2481 * on OK to set the current window to the one selected, or
2482 * CANCEL to cancel. The function returns a handle to the
2483 * selected window.
2486 static HWND MDI_MoreWindowsDialog(WND* wndPtr)
2488 LPCVOID template;
2489 HRSRC hRes;
2490 HANDLE hDlgTmpl;
2492 hRes = FindResourceA(GetModuleHandleA("USER32"), "MDI_MOREWINDOWS", RT_DIALOGA);
2494 if (hRes == 0)
2495 return 0;
2497 hDlgTmpl = LoadResource(GetModuleHandleA("USER32"), hRes );
2499 if (hDlgTmpl == 0)
2500 return 0;
2502 template = LockResource( hDlgTmpl );
2504 if (template == 0)
2505 return 0;
2507 return (HWND) DialogBoxIndirectParamA(GetModuleHandleA("USER32"),
2508 (LPDLGTEMPLATEA) template,
2509 wndPtr->hwndSelf,
2510 (DLGPROC) MDI_MoreWindowsDlgProc,
2511 (LPARAM) wndPtr);
2516 * MDI_SwapMenuItems
2518 * Will swap the menu IDs for the given 2 positions.
2519 * pos1 and pos2 are menu IDs
2524 static void MDI_SwapMenuItems(WND *parentWnd, UINT pos1, UINT pos2)
2526 WND *pWnd;
2528 for (pWnd = WIN_LockWndPtr(parentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2530 if (pWnd->wIDmenu == pos1)
2531 pWnd->wIDmenu = pos2;
2532 else
2533 if (pWnd->wIDmenu == pos2)
2534 pWnd->wIDmenu = pos1;
2537 WIN_ReleaseWndPtr(pWnd);