Replaced all lstr* calls from inside Wine code by their str* equivalent.
[wine/hacks.git] / windows / mdi.c
blob9150a7b125036e045dbdb1ed9a4a86fe38c9082e
1 /* MDI.C
3 * Copyright 1994, Bob Amstadt
4 * 1995,1996 Alex Korobka
6 * This file contains routines to support MDI (Multiple Document
7 * Interface) features .
9 * Notes: Fairly complete implementation.
10 * Also, Excel and WinWord do _not_ use MDI so if you're trying
11 * to fix them look elsewhere.
13 * Notes on how the "More Windows..." is implemented:
15 * When we have more than 9 opened windows, a "More Windows..."
16 * option appears in the "Windows" menu. Each child window has
17 * a WND* associated with it, accesible via the children list of
18 * the parent window. This WND* has a wIDmenu member, which reflects
19 * the position of the child in the window list. For example, with
20 * 9 child windows, we could have the following pattern:
24 * Name of the child window pWndChild->wIDmenu
25 * Doc1 5000
26 * Doc2 5001
27 * Doc3 5002
28 * Doc4 5003
29 * Doc5 5004
30 * Doc6 5005
31 * Doc7 5006
32 * Doc8 5007
33 * Doc9 5008
36 * The "Windows" menu, as the "More windows..." dialog, are constructed
37 * in this order. If we add a child, we would have the following list:
40 * Name of the child window pWndChild->wIDmenu
41 * Doc1 5000
42 * Doc2 5001
43 * Doc3 5002
44 * Doc4 5003
45 * Doc5 5004
46 * Doc6 5005
47 * Doc7 5006
48 * Doc8 5007
49 * Doc9 5008
50 * Doc10 5009
52 * But only 5000 to 5008 would be displayed in the "Windows" menu. We want
53 * the last created child to be in the menu, so we swap the last child with
54 * the 9th... Doc9 will be accessible via the "More Windows..." option.
56 * Doc1 5000
57 * Doc2 5001
58 * Doc3 5002
59 * Doc4 5003
60 * Doc5 5004
61 * Doc6 5005
62 * Doc7 5006
63 * Doc8 5007
64 * Doc9 5009
65 * Doc10 5008
69 #include <stdlib.h>
70 #include <stdio.h>
71 #include <string.h>
72 #include <math.h>
73 #include "windef.h"
74 #include "wingdi.h"
75 #include "winuser.h"
76 #include "wine/unicode.h"
77 #include "win.h"
78 #include "heap.h"
79 #include "nonclient.h"
80 #include "mdi.h"
81 #include "user.h"
82 #include "menu.h"
83 #include "scroll.h"
84 #include "struct32.h"
85 #include "tweak.h"
86 #include "debugtools.h"
87 #include "dlgs.h"
89 DEFAULT_DEBUG_CHANNEL(mdi);
91 #define MDIF_NEEDUPDATE 0x0001
93 static HBITMAP16 hBmpClose = 0;
94 static HBITMAP16 hBmpRestore = 0;
96 /* ----------------- declarations ----------------- */
97 static void MDI_UpdateFrameText(WND *, HWND, BOOL, LPCWSTR);
98 static BOOL MDI_AugmentFrameMenu(MDICLIENTINFO*, WND *, HWND);
99 static BOOL MDI_RestoreFrameMenu(WND *, HWND);
101 static LONG MDI_ChildActivate( WND*, HWND );
103 static HWND MDI_MoreWindowsDialog(WND*);
104 static void MDI_SwapMenuItems(WND *, UINT, UINT);
105 /* -------- Miscellaneous service functions ----------
107 * MDI_GetChildByID
110 static HWND MDI_GetChildByID(WND* wndPtr, INT id)
112 for (wndPtr = wndPtr->child; wndPtr; wndPtr = wndPtr->next)
113 if (wndPtr->wIDmenu == id) return wndPtr->hwndSelf;
114 return 0;
117 static void MDI_PostUpdate(HWND hwnd, MDICLIENTINFO* ci, WORD recalc)
119 if( !(ci->mdiFlags & MDIF_NEEDUPDATE) )
121 ci->mdiFlags |= MDIF_NEEDUPDATE;
122 PostMessageA( hwnd, WM_MDICALCCHILDSCROLL, 0, 0);
124 ci->sbRecalc = recalc;
127 /**********************************************************************
128 * MDI_MenuModifyItem
130 static BOOL MDI_MenuModifyItem(WND* clientWnd, HWND hWndChild )
132 WCHAR buffer[128];
133 static const WCHAR format[] = {'%','d',' ',0};
134 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
135 WND *wndPtr = WIN_FindWndPtr(hWndChild);
136 UINT n = wsprintfW(buffer, format,
137 wndPtr->wIDmenu - clientInfo->idFirstChild + 1);
138 BOOL bRet = 0;
140 if( !clientInfo->hWindowMenu )
142 bRet = FALSE;
143 goto END;
146 if (wndPtr->text) lstrcpynW(buffer + n, wndPtr->text, sizeof(buffer)/sizeof(WCHAR) - n );
148 n = GetMenuState(clientInfo->hWindowMenu,wndPtr->wIDmenu ,MF_BYCOMMAND);
149 bRet = ModifyMenuW(clientInfo->hWindowMenu , wndPtr->wIDmenu,
150 MF_BYCOMMAND | MF_STRING, wndPtr->wIDmenu, buffer );
151 CheckMenuItem(clientInfo->hWindowMenu ,wndPtr->wIDmenu , n & MF_CHECKED);
152 END:
153 WIN_ReleaseWndPtr(wndPtr);
154 return bRet;
157 /**********************************************************************
158 * MDI_MenuDeleteItem
160 static BOOL MDI_MenuDeleteItem(WND* clientWnd, HWND hWndChild )
162 WCHAR buffer[128];
163 static const WCHAR format[] = {'&','%','d',' ',0};
164 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
165 WND *wndPtr = WIN_FindWndPtr(hWndChild);
166 UINT index = 0,id,n;
167 BOOL retvalue;
169 if( !clientInfo->nActiveChildren ||
170 !clientInfo->hWindowMenu )
172 retvalue = FALSE;
173 goto END;
176 id = wndPtr->wIDmenu;
177 DeleteMenu(clientInfo->hWindowMenu,id,MF_BYCOMMAND);
179 /* walk the rest of MDI children to prevent gaps in the id
180 * sequence and in the menu child list */
182 for( index = id+1; index <= clientInfo->nActiveChildren +
183 clientInfo->idFirstChild; index++ )
185 WND *tmpWnd = WIN_FindWndPtr(MDI_GetChildByID(clientWnd,index));
186 if( !tmpWnd )
188 TRACE("no window for id=%i\n",index);
189 WIN_ReleaseWndPtr(tmpWnd);
190 continue;
193 /* set correct id */
194 tmpWnd->wIDmenu--;
196 n = wsprintfW(buffer, format ,index - clientInfo->idFirstChild);
197 if (tmpWnd->text)
198 lstrcpynW(buffer + n, tmpWnd->text, sizeof(buffer)/sizeof(WCHAR) - n );
200 /* change menu if the current child is to be shown in the
201 * "Windows" menu
203 if (index <= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
204 ModifyMenuW(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING,
205 index - 1 , buffer );
206 WIN_ReleaseWndPtr(tmpWnd);
209 /* We must restore the "More Windows..." option if there is enough child
211 if (clientInfo->nActiveChildren - 1 > MDI_MOREWINDOWSLIMIT)
213 char szTmp[50];
214 LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
216 AppendMenuA(clientInfo->hWindowMenu ,MF_STRING ,clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT, szTmp );
218 retvalue = TRUE;
219 END:
220 WIN_ReleaseWndPtr(wndPtr);
221 return retvalue;
224 /**********************************************************************
225 * MDI_GetWindow
227 * returns "activateable" child different from the current or zero
229 static HWND MDI_GetWindow(WND *clientWnd, HWND hWnd, BOOL bNext,
230 DWORD dwStyleMask )
232 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
233 WND *wndPtr, *pWnd, *pWndLast = NULL;
235 dwStyleMask |= WS_DISABLED | WS_VISIBLE;
236 if( !hWnd ) hWnd = clientInfo->hwndActiveChild;
238 if( !(wndPtr = WIN_FindWndPtr(hWnd)) ) return 0;
240 for ( pWnd = WIN_LockWndPtr(wndPtr->next); ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
242 if (!pWnd ) WIN_UpdateWndPtr(&pWnd,wndPtr->parent->child);
244 if ( pWnd == wndPtr ) break; /* went full circle */
246 if (!pWnd->owner && (pWnd->dwStyle & dwStyleMask) == WS_VISIBLE )
248 pWndLast = pWnd;
249 if ( bNext ) break;
252 WIN_ReleaseWndPtr(wndPtr);
253 WIN_ReleaseWndPtr(pWnd);
254 return pWndLast ? pWndLast->hwndSelf : 0;
257 /**********************************************************************
258 * MDI_CalcDefaultChildPos
260 * It seems that the default height is about 2/3 of the client rect
262 static void MDI_CalcDefaultChildPos( WND* w, WORD n, LPPOINT lpPos,
263 INT delta)
265 INT nstagger;
266 RECT rect = w->rectClient;
267 INT spacing = GetSystemMetrics(SM_CYCAPTION) +
268 GetSystemMetrics(SM_CYFRAME) - 1;
270 if( rect.bottom - rect.top - delta >= spacing )
271 rect.bottom -= delta;
273 nstagger = (rect.bottom - rect.top)/(3 * spacing);
274 lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
275 lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
276 lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
279 /**********************************************************************
280 * MDISetMenu
282 static LRESULT MDISetMenu( HWND hwnd, HMENU hmenuFrame,
283 HMENU hmenuWindow)
285 WND *w;
286 MDICLIENTINFO *ci;
287 HWND hwndFrame = GetParent(hwnd);
288 HMENU oldFrameMenu = GetMenu(hwndFrame);
290 TRACE("%04x %04x %04x\n",
291 hwnd, hmenuFrame, hmenuWindow);
293 if (hmenuFrame && !IsMenu(hmenuFrame))
295 WARN("hmenuFrame is not a menu handle\n");
296 return 0L;
299 if (hmenuWindow && !IsMenu(hmenuWindow))
301 WARN("hmenuWindow is not a menu handle\n");
302 return 0L;
305 w = WIN_FindWndPtr(hwnd);
306 ci = (MDICLIENTINFO *) w->wExtra;
308 if( ci->hwndChildMaximized && hmenuFrame && hmenuFrame!=oldFrameMenu )
309 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized );
311 if( hmenuWindow && ci->hWindowMenu && hmenuWindow!=ci->hWindowMenu )
313 /* delete menu items from ci->hWindowMenu
314 * and add them to hmenuWindow */
316 INT i = GetMenuItemCount(ci->hWindowMenu) - 1;
317 INT pos = GetMenuItemCount(hmenuWindow) + 1;
319 AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL);
321 if( ci->nActiveChildren )
323 INT j;
324 LPWSTR buffer = NULL;
325 MENUITEMINFOW mii;
326 INT nbWindowsMenuItems; /* num of documents shown + "More Windows..." if present */
328 if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
329 nbWindowsMenuItems = ci->nActiveChildren;
330 else
331 nbWindowsMenuItems = MDI_MOREWINDOWSLIMIT + 1;
333 j = i - nbWindowsMenuItems + 1;
335 for( ; i >= j ; i-- )
337 memset(&mii, 0, sizeof(mii));
338 mii.cbSize = sizeof(mii);
339 mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE
340 | MIIM_SUBMENU | MIIM_TYPE | MIIM_BITMAP;
342 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
343 if(mii.cch) { /* Menu is MFT_STRING */
344 mii.cch++; /* add room for '\0' */
345 buffer = HeapAlloc(GetProcessHeap(), 0,
346 mii.cch * sizeof(WCHAR));
347 mii.dwTypeData = buffer;
348 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
350 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
351 InsertMenuItemW(hmenuWindow, pos, TRUE, &mii);
352 if(buffer) {
353 HeapFree(GetProcessHeap(), 0, buffer);
354 buffer = NULL;
359 /* remove separator */
360 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
362 ci->hWindowMenu = hmenuWindow;
365 if (hmenuFrame)
367 SetMenu(hwndFrame, hmenuFrame);
368 if( hmenuFrame!=oldFrameMenu )
370 if( ci->hwndChildMaximized )
371 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
372 WIN_ReleaseWndPtr(w);
373 return oldFrameMenu;
376 WIN_ReleaseWndPtr(w);
377 return 0;
380 /**********************************************************************
381 * MDIRefreshMenu
383 static LRESULT MDIRefreshMenu( HWND hwnd, HMENU hmenuFrame,
384 HMENU hmenuWindow)
386 HWND hwndFrame = GetParent(hwnd);
387 HMENU oldFrameMenu = GetMenu(hwndFrame);
389 TRACE("%04x %04x %04x\n",
390 hwnd, hmenuFrame, hmenuWindow);
392 FIXME("partially function stub\n");
394 return oldFrameMenu;
398 /* ------------------ MDI child window functions ---------------------- */
401 /**********************************************************************
402 * MDICreateChild
404 static HWND MDICreateChild( WND *w, MDICLIENTINFO *ci, HWND parent,
405 LPMDICREATESTRUCTA cs )
407 POINT pos[2];
408 DWORD style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
409 HWND hwnd, hwndMax = 0;
410 WORD wIDmenu = ci->idFirstChild + ci->nActiveChildren;
411 char lpstrDef[]="junk!";
413 TRACE("origin %i,%i - dim %i,%i, style %08x\n",
414 cs->x, cs->y, cs->cx, cs->cy, (unsigned)cs->style);
415 /* calculate placement */
416 MDI_CalcDefaultChildPos(w, ci->nTotalCreated++, pos, 0);
418 if (cs->cx == CW_USEDEFAULT || !cs->cx) cs->cx = pos[1].x;
419 if (cs->cy == CW_USEDEFAULT || !cs->cy) cs->cy = pos[1].y;
421 if( cs->x == CW_USEDEFAULT )
423 cs->x = pos[0].x;
424 cs->y = pos[0].y;
427 /* restore current maximized child */
428 if( style & WS_VISIBLE && ci->hwndChildMaximized )
430 if( style & WS_MAXIMIZE )
431 SendMessageA(w->hwndSelf, WM_SETREDRAW, FALSE, 0L );
432 hwndMax = ci->hwndChildMaximized;
433 ShowWindow( hwndMax, SW_SHOWNOACTIVATE );
434 if( style & WS_MAXIMIZE )
435 SendMessageA(w->hwndSelf, WM_SETREDRAW, TRUE, 0L );
438 if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
439 /* this menu is needed to set a check mark in MDI_ChildActivate */
440 if (ci->hWindowMenu != 0)
441 AppendMenuA(ci->hWindowMenu ,MF_STRING ,wIDmenu, lpstrDef );
443 ci->nActiveChildren++;
445 /* fix window style */
446 if( !(w->dwStyle & MDIS_ALLCHILDSTYLES) )
448 style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE |
449 WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL );
450 style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW);
453 if( w->flags & WIN_ISWIN32 )
455 hwnd = CreateWindowA( cs->szClass, cs->szTitle, style,
456 cs->x, cs->y, cs->cx, cs->cy, parent,
457 (HMENU16)wIDmenu, cs->hOwner, cs );
459 else
461 MDICREATESTRUCT16 *cs16;
462 LPSTR title, cls;
464 cs16 = SEGPTR_NEW(MDICREATESTRUCT16);
465 STRUCT32_MDICREATESTRUCT32Ato16( cs, cs16 );
466 title = SEGPTR_STRDUP( cs->szTitle );
467 cls = SEGPTR_STRDUP( cs->szClass );
468 cs16->szTitle = SEGPTR_GET(title);
469 cs16->szClass = SEGPTR_GET(cls);
471 hwnd = CreateWindow16( cs->szClass, cs->szTitle, style,
472 cs16->x, cs16->y, cs16->cx, cs16->cy, parent,
473 (HMENU)wIDmenu, cs16->hOwner,
474 (LPVOID)SEGPTR_GET(cs16) );
475 SEGPTR_FREE( title );
476 SEGPTR_FREE( cls );
477 SEGPTR_FREE( cs16 );
480 /* MDI windows are WS_CHILD so they won't be activated by CreateWindow */
482 if (hwnd)
484 WND* wnd = WIN_FindWndPtr( hwnd );
486 /* All MDI child windows have the WS_EX_MDICHILD style */
487 wnd->dwExStyle |= WS_EX_MDICHILD;
489 /* If we have more than 9 windows, we must insert the new one at the
490 * 9th position in order to see it in the "Windows" menu
492 if (ci->nActiveChildren > MDI_MOREWINDOWSLIMIT)
493 MDI_SwapMenuItems(wnd->parent, wnd->wIDmenu, ci->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
495 MDI_MenuModifyItem(w ,hwnd);
497 /* Have we hit the "More Windows..." limit? If so, we must
498 * add a "More Windows..." option
500 if (ci->nActiveChildren == MDI_MOREWINDOWSLIMIT + 1)
502 char szTmp[50];
503 LoadStringA(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, 50);
505 ModifyMenuA(ci->hWindowMenu,
506 ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
507 MF_BYCOMMAND | MF_STRING,
508 ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
509 szTmp);
512 if( wnd->dwStyle & WS_MINIMIZE && ci->hwndActiveChild )
513 ShowWindow( hwnd, SW_SHOWMINNOACTIVE );
514 else
516 /* WS_VISIBLE is clear if a) the MDI client has
517 * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the
518 * MDICreateStruct. If so the created window is not shown nor
519 * activated.
521 int showflag=wnd->dwStyle & WS_VISIBLE;
522 /* clear visible flag, otherwise SetWindoPos32 ignores
523 * the SWP_SHOWWINDOW command.
525 wnd->dwStyle &= ~WS_VISIBLE;
526 if(showflag){
527 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE );
529 /* Set maximized state here in case hwnd didn't receive WM_SIZE
530 * during CreateWindow - bad!
533 if((wnd->dwStyle & WS_MAXIMIZE) && !ci->hwndChildMaximized )
535 ci->hwndChildMaximized = wnd->hwndSelf;
536 MDI_AugmentFrameMenu( ci, w->parent, hwnd );
537 MDI_UpdateFrameText( w->parent, ci->self, MDI_REPAINTFRAME, NULL );
539 }else
540 /* needed, harmless ? */
541 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE );
544 WIN_ReleaseWndPtr(wnd);
545 TRACE("created child - %04x\n",hwnd);
547 else
549 ci->nActiveChildren--;
550 DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
551 if( IsWindow(hwndMax) )
552 ShowWindow(hwndMax, SW_SHOWMAXIMIZED);
555 return hwnd;
558 /**********************************************************************
559 * MDI_ChildGetMinMaxInfo
561 * Note: The rule here is that client rect of the maximized MDI child
562 * is equal to the client rect of the MDI client window.
564 static void MDI_ChildGetMinMaxInfo( WND* clientWnd, HWND hwnd,
565 MINMAXINFO16* lpMinMax )
567 WND* childWnd = WIN_FindWndPtr(hwnd);
568 RECT rect = clientWnd->rectClient;
570 MapWindowPoints( clientWnd->parent->hwndSelf,
571 ((MDICLIENTINFO*)clientWnd->wExtra)->self, (LPPOINT)&rect, 2);
572 AdjustWindowRectEx( &rect, childWnd->dwStyle, 0, childWnd->dwExStyle );
574 lpMinMax->ptMaxSize.x = rect.right -= rect.left;
575 lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
577 lpMinMax->ptMaxPosition.x = rect.left;
578 lpMinMax->ptMaxPosition.y = rect.top;
580 WIN_ReleaseWndPtr(childWnd);
582 TRACE("max rect (%i,%i - %i, %i)\n",
583 rect.left,rect.top,rect.right,rect.bottom);
587 /**********************************************************************
588 * MDI_SwitchActiveChild
590 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
591 * being activated
593 static void MDI_SwitchActiveChild( HWND clientHwnd, HWND childHwnd,
594 BOOL bNextWindow )
596 WND *w = WIN_FindWndPtr(clientHwnd);
597 HWND hwndTo = 0;
598 HWND hwndPrev = 0;
599 MDICLIENTINFO *ci;
601 hwndTo = MDI_GetWindow(w, childHwnd, bNextWindow, 0);
603 ci = (MDICLIENTINFO *) w->wExtra;
605 TRACE("from %04x, to %04x\n",childHwnd,hwndTo);
607 if ( !hwndTo ) goto END; /* no window to switch to */
609 hwndPrev = ci->hwndActiveChild;
611 if ( hwndTo != hwndPrev )
613 BOOL bOptimize = 0;
615 if( ci->hwndChildMaximized )
617 bOptimize = 1;
618 w->dwStyle &= ~WS_VISIBLE;
621 SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0,
622 SWP_NOMOVE | SWP_NOSIZE );
624 if( bNextWindow && hwndPrev )
625 SetWindowPos( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0,
626 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
627 if( bOptimize )
628 ShowWindow( clientHwnd, SW_SHOW );
630 END:
631 WIN_ReleaseWndPtr(w);
635 /**********************************************************************
636 * MDIDestroyChild
638 static LRESULT MDIDestroyChild( WND *w_parent, MDICLIENTINFO *ci,
639 HWND parent, HWND child,
640 BOOL flagDestroy )
642 WND *childPtr = WIN_FindWndPtr(child);
644 if( childPtr )
646 MDI_MenuDeleteItem(w_parent, child);
648 if( child == ci->hwndActiveChild )
650 MDI_SwitchActiveChild(parent, child, TRUE);
652 if( child == ci->hwndActiveChild )
654 ShowWindow( child, SW_HIDE);
655 if( child == ci->hwndChildMaximized )
657 MDI_RestoreFrameMenu(w_parent->parent, child);
658 ci->hwndChildMaximized = 0;
659 MDI_UpdateFrameText(w_parent->parent,parent,TRUE,NULL);
662 MDI_ChildActivate(w_parent, 0);
666 WIN_ReleaseWndPtr(childPtr);
668 ci->nActiveChildren--;
670 TRACE("child destroyed - %04x\n",child);
672 if (flagDestroy)
674 MDI_PostUpdate(GetParent(child), ci, SB_BOTH+1);
675 DestroyWindow(child);
679 return 0;
683 /**********************************************************************
684 * MDI_ChildActivate
686 * Note: hWndChild is NULL when last child is being destroyed
688 static LONG MDI_ChildActivate( WND *clientPtr, HWND hWndChild )
690 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientPtr->wExtra;
691 HWND prevActiveWnd = clientInfo->hwndActiveChild;
692 WND *wndPtr = WIN_FindWndPtr( hWndChild );
693 WND *wndPrev = WIN_FindWndPtr( prevActiveWnd );
694 BOOL isActiveFrameWnd = 0;
695 LONG retvalue;
697 if( wndPtr )
699 if( wndPtr->dwStyle & WS_DISABLED )
701 retvalue = 0L;
702 goto END;
706 /* Don't activate if it is already active. Might happen
707 since ShowWindow DOES activate MDI children */
708 if (clientInfo->hwndActiveChild == hWndChild)
710 retvalue = 0L;
711 goto END;
714 TRACE("%04x\n", hWndChild);
716 if( GetActiveWindow() == clientPtr->parent->hwndSelf )
717 isActiveFrameWnd = TRUE;
719 /* deactivate prev. active child */
720 if( wndPrev )
722 wndPrev->dwStyle |= WS_SYSMENU;
723 SendMessageA( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
724 SendMessageA( prevActiveWnd, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
725 (LPARAM)hWndChild);
726 /* uncheck menu item */
727 if( clientInfo->hWindowMenu )
729 WORD wPrevID = wndPrev->wIDmenu - clientInfo->idFirstChild;
731 if (wPrevID < MDI_MOREWINDOWSLIMIT)
732 CheckMenuItem( clientInfo->hWindowMenu,
733 wndPrev->wIDmenu, 0);
734 else
735 CheckMenuItem( clientInfo->hWindowMenu,
736 clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1, 0);
740 /* set appearance */
741 if( clientInfo->hwndChildMaximized )
743 if( clientInfo->hwndChildMaximized != hWndChild ) {
744 if( hWndChild ) {
745 clientInfo->hwndActiveChild = hWndChild;
746 ShowWindow( hWndChild, SW_SHOWMAXIMIZED);
747 } else
748 ShowWindow( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
752 clientInfo->hwndActiveChild = hWndChild;
754 /* check if we have any children left */
755 if( !hWndChild )
757 if( isActiveFrameWnd )
758 SetFocus( clientInfo->self );
759 retvalue = 0;
760 goto END;
763 /* check menu item */
764 if( clientInfo->hWindowMenu )
766 /* The window to be activated must be displayed in the "Windows" menu */
767 if (wndPtr->wIDmenu >= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
769 MDI_SwapMenuItems(wndPtr->parent, wndPtr->wIDmenu, clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
770 MDI_MenuModifyItem(wndPtr->parent ,wndPtr->hwndSelf);
773 CheckMenuItem(clientInfo->hWindowMenu, wndPtr->wIDmenu, MF_CHECKED);
775 /* bring active child to the top */
776 SetWindowPos( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
778 if( isActiveFrameWnd )
780 SendMessageA( hWndChild, WM_NCACTIVATE, TRUE, 0L);
781 if( GetFocus() == clientInfo->self )
782 SendMessageA( clientInfo->self, WM_SETFOCUS,
783 (WPARAM)clientInfo->self, 0L );
784 else
785 SetFocus( clientInfo->self );
787 SendMessageA( hWndChild, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
788 (LPARAM)hWndChild );
789 retvalue = 1;
790 END:
791 WIN_ReleaseWndPtr(wndPtr);
792 WIN_ReleaseWndPtr(wndPrev);
793 return retvalue;
796 /* -------------------- MDI client window functions ------------------- */
798 /**********************************************************************
799 * CreateMDIMenuBitmap
801 static HBITMAP16 CreateMDIMenuBitmap(void)
803 HDC hDCSrc = CreateCompatibleDC(0);
804 HDC hDCDest = CreateCompatibleDC(hDCSrc);
805 HBITMAP16 hbClose = LoadBitmap16(0, MAKEINTRESOURCE16(OBM_CLOSE) );
806 HBITMAP16 hbCopy;
807 HANDLE16 hobjSrc, hobjDest;
809 hobjSrc = SelectObject(hDCSrc, hbClose);
810 hbCopy = CreateCompatibleBitmap(hDCSrc,GetSystemMetrics(SM_CXSIZE),GetSystemMetrics(SM_CYSIZE));
811 hobjDest = SelectObject(hDCDest, hbCopy);
813 BitBlt(hDCDest, 0, 0, GetSystemMetrics(SM_CXSIZE), GetSystemMetrics(SM_CYSIZE),
814 hDCSrc, GetSystemMetrics(SM_CXSIZE), 0, SRCCOPY);
816 SelectObject(hDCSrc, hobjSrc);
817 DeleteObject(hbClose);
818 DeleteDC(hDCSrc);
820 hobjSrc = SelectObject( hDCDest, GetStockObject(BLACK_PEN) );
822 MoveToEx( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, 0, NULL );
823 LineTo( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, GetSystemMetrics(SM_CYSIZE) - 1);
825 SelectObject(hDCDest, hobjSrc );
826 SelectObject(hDCDest, hobjDest);
827 DeleteDC(hDCDest);
829 return hbCopy;
832 /**********************************************************************
833 * MDICascade
835 static LONG MDICascade(WND* clientWnd, MDICLIENTINFO *ci)
837 WND** ppWnd;
838 UINT total;
840 if (ci->hwndChildMaximized)
841 SendMessageA( clientWnd->hwndSelf, WM_MDIRESTORE,
842 (WPARAM)ci->hwndChildMaximized, 0);
844 if (ci->nActiveChildren == 0) return 0;
846 if ((ppWnd = WIN_BuildWinArray(clientWnd, BWA_SKIPHIDDEN | BWA_SKIPOWNED |
847 BWA_SKIPICONIC, &total)))
849 WND** heapPtr = ppWnd;
850 if( total )
852 INT delta = 0, n = 0;
853 POINT pos[2];
854 if( total < ci->nActiveChildren )
855 delta = GetSystemMetrics(SM_CYICONSPACING) +
856 GetSystemMetrics(SM_CYICON);
858 /* walk the list (backwards) and move windows */
859 while (*ppWnd) ppWnd++;
860 while (ppWnd != heapPtr)
862 ppWnd--;
863 TRACE("move %04x to (%ld,%ld) size [%ld,%ld]\n",
864 (*ppWnd)->hwndSelf, pos[0].x, pos[0].y, pos[1].x, pos[1].y);
866 MDI_CalcDefaultChildPos(clientWnd, n++, pos, delta);
867 SetWindowPos( (*ppWnd)->hwndSelf, 0, pos[0].x, pos[0].y,
868 pos[1].x, pos[1].y,
869 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
872 WIN_ReleaseWinArray(heapPtr);
875 if( total < ci->nActiveChildren )
876 ArrangeIconicWindows( clientWnd->hwndSelf );
877 return 0;
880 /**********************************************************************
881 * MDITile
883 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM wParam )
885 WND** ppWnd;
886 UINT total = 0;
888 if (ci->hwndChildMaximized)
889 SendMessageA( wndClient->hwndSelf, WM_MDIRESTORE,
890 (WPARAM)ci->hwndChildMaximized, 0);
892 if (ci->nActiveChildren == 0) return;
894 ppWnd = WIN_BuildWinArray(wndClient, BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
895 ((wParam & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
897 TRACE("%u windows to tile\n", total);
899 if( ppWnd )
901 WND** heapPtr = ppWnd;
903 if( total )
905 RECT rect;
906 int x, y, xsize, ysize;
907 int rows, columns, r, c, i;
909 GetClientRect(wndClient->hwndSelf,&rect);
910 rows = (int) sqrt((double)total);
911 columns = total / rows;
913 if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */
915 i = rows;
916 rows = columns; /* exchange r and c */
917 columns = i;
920 if( total != ci->nActiveChildren)
922 y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
923 rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
926 ysize = rect.bottom / rows;
927 xsize = rect.right / columns;
929 for (x = i = 0, c = 1; c <= columns && *ppWnd; c++)
931 if (c == columns)
933 rows = total - i;
934 ysize = rect.bottom / rows;
937 y = 0;
938 for (r = 1; r <= rows && *ppWnd; r++, i++)
940 SetWindowPos((*ppWnd)->hwndSelf, 0, x, y, xsize, ysize,
941 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
942 y += ysize;
943 ppWnd++;
945 x += xsize;
948 WIN_ReleaseWinArray(heapPtr);
951 if( total < ci->nActiveChildren ) ArrangeIconicWindows( wndClient->hwndSelf );
954 /* ----------------------- Frame window ---------------------------- */
957 /**********************************************************************
958 * MDI_AugmentFrameMenu
960 static BOOL MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
961 HWND hChild )
963 WND* child = WIN_FindWndPtr(hChild);
964 HMENU hSysPopup = 0;
965 HBITMAP hSysMenuBitmap = 0;
967 TRACE("frame %p,child %04x\n",frame,hChild);
969 if( !frame->wIDmenu || !child->hSysMenu )
971 WIN_ReleaseWndPtr(child);
972 return 0;
974 WIN_ReleaseWndPtr(child);
976 /* create a copy of sysmenu popup and insert it into frame menu bar */
978 if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
979 return 0;
981 TRACE("\tgot popup %04x in sysmenu %04x\n",
982 hSysPopup, child->hSysMenu);
984 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
985 SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
986 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
987 SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
989 /* In Win 95 look, the system menu is replaced by the child icon */
991 if(TWEAK_WineLook > WIN31_LOOK)
993 HICON hIcon = GetClassLongA(hChild, GCL_HICONSM);
994 if (!hIcon)
995 hIcon = GetClassLongA(hChild, GCL_HICON);
996 if (hIcon)
998 HDC hMemDC;
999 HBITMAP hBitmap, hOldBitmap;
1000 HBRUSH hBrush;
1001 HDC hdc = GetDC(hChild);
1003 if (hdc)
1005 int cx, cy;
1006 cx = GetSystemMetrics(SM_CXSMICON);
1007 cy = GetSystemMetrics(SM_CYSMICON);
1008 hMemDC = CreateCompatibleDC(hdc);
1009 hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
1010 hOldBitmap = SelectObject(hMemDC, hBitmap);
1011 SetMapMode(hMemDC, MM_TEXT);
1012 hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
1013 DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL);
1014 SelectObject (hMemDC, hOldBitmap);
1015 DeleteObject(hBrush);
1016 DeleteDC(hMemDC);
1017 ReleaseDC(hChild, hdc);
1018 hSysMenuBitmap = hBitmap;
1022 else
1023 hSysMenuBitmap = hBmpClose;
1025 if( !InsertMenuA(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
1026 hSysPopup, (LPSTR)(DWORD)hSysMenuBitmap))
1028 TRACE("not inserted\n");
1029 DestroyMenu(hSysPopup);
1030 return 0;
1033 /* The close button is only present in Win 95 look */
1034 if(TWEAK_WineLook > WIN31_LOOK)
1036 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
1037 SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
1040 EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
1041 EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
1042 EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
1043 SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE);
1045 /* redraw menu */
1046 DrawMenuBar(frame->hwndSelf);
1048 return 1;
1051 /**********************************************************************
1052 * MDI_RestoreFrameMenu
1054 static BOOL MDI_RestoreFrameMenu( WND *frameWnd, HWND hChild )
1056 MENUITEMINFOA menuInfo;
1057 INT nItems = GetMenuItemCount(frameWnd->wIDmenu) - 1;
1058 UINT iId = GetMenuItemID(frameWnd->wIDmenu,nItems) ;
1060 TRACE("frameWnd %p,(%04x),child %04x,nIt=%d,iId=%d\n",
1061 frameWnd,frameWnd->hwndSelf,hChild,nItems,iId);
1063 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
1064 return 0;
1067 * Remove the system menu, If that menu is the icon of the window
1068 * as it is in win95, we have to delete the bitmap.
1070 menuInfo.cbSize = sizeof(MENUITEMINFOA);
1071 menuInfo.fMask = MIIM_DATA | MIIM_TYPE;
1073 GetMenuItemInfoA(frameWnd->wIDmenu,
1075 TRUE,
1076 &menuInfo);
1078 RemoveMenu(frameWnd->wIDmenu,0,MF_BYPOSITION);
1080 if ( (menuInfo.fType & MFT_BITMAP) &&
1081 (LOWORD(menuInfo.dwTypeData)!=0) &&
1082 (LOWORD(menuInfo.dwTypeData)!=hBmpClose) )
1084 DeleteObject((HBITMAP)LOWORD(menuInfo.dwTypeData));
1087 if(TWEAK_WineLook > WIN31_LOOK)
1089 /* close */
1090 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1092 /* restore */
1093 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1094 /* minimize */
1095 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
1097 DrawMenuBar(frameWnd->hwndSelf);
1099 return 1;
1103 /**********************************************************************
1104 * MDI_UpdateFrameText
1106 * used when child window is maximized/restored
1108 * Note: lpTitle can be NULL
1110 static void MDI_UpdateFrameText( WND *frameWnd, HWND hClient,
1111 BOOL repaint, LPCWSTR lpTitle )
1113 WCHAR lpBuffer[MDI_MAXTITLELENGTH+1];
1114 WND* clientWnd = WIN_FindWndPtr(hClient);
1115 MDICLIENTINFO *ci = (MDICLIENTINFO *) clientWnd->wExtra;
1117 TRACE("repaint %i, frameText %s\n", repaint, (lpTitle)?debugstr_w(lpTitle):"NULL");
1119 if (!clientWnd)
1120 return;
1122 if (!ci)
1124 WIN_ReleaseWndPtr(clientWnd);
1125 return;
1128 /* store new "default" title if lpTitle is not NULL */
1129 if (lpTitle)
1131 if (ci->frameTitle) HeapFree( SystemHeap, 0, ci->frameTitle );
1132 ci->frameTitle = HEAP_strdupW( SystemHeap, 0, lpTitle );
1135 if (ci->frameTitle)
1137 WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );
1139 if( childWnd && childWnd->text )
1141 /* combine frame title and child title if possible */
1143 static const WCHAR lpBracket[] = {' ','-',' ','[',0};
1144 static const WCHAR lpBracket2[] = {']',0};
1145 int i_frame_text_length = strlenW(ci->frameTitle);
1146 int i_child_text_length = strlenW(childWnd->text);
1148 lstrcpynW( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
1150 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
1152 strcatW( lpBuffer, lpBracket );
1154 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
1156 strcatW( lpBuffer, childWnd->text );
1157 strcatW( lpBuffer, lpBracket2 );
1159 else
1161 lstrcpynW( lpBuffer + i_frame_text_length + 4,
1162 childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
1163 strcatW( lpBuffer, lpBracket2 );
1167 else
1169 lstrcpynW(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH+1 );
1171 WIN_ReleaseWndPtr(childWnd);
1174 else
1175 lpBuffer[0] = '\0';
1177 DEFWND_SetTextW( frameWnd, lpBuffer );
1178 if( repaint == MDI_REPAINTFRAME)
1179 SetWindowPos( frameWnd->hwndSelf, 0,0,0,0,0, SWP_FRAMECHANGED |
1180 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
1182 WIN_ReleaseWndPtr(clientWnd);
1187 /* ----------------------------- Interface ---------------------------- */
1190 /**********************************************************************
1191 * MDIClientWndProc
1193 * This function handles all MDI requests.
1195 LRESULT WINAPI MDIClientWndProc( HWND hwnd, UINT message, WPARAM wParam,
1196 LPARAM lParam )
1198 LPCREATESTRUCTA cs;
1199 MDICLIENTINFO *ci;
1200 RECT rect;
1201 WND *w, *frameWnd;
1202 INT nItems;
1203 LRESULT retvalue;
1205 if ( ( w = WIN_FindWndPtr(hwnd) ) == NULL )
1206 return 0;
1208 if ( ( frameWnd = WIN_LockWndPtr(w->parent) ) == NULL ) {
1209 WIN_ReleaseWndPtr(w);
1210 return 0;
1213 ci = (MDICLIENTINFO *) w->wExtra;
1215 switch (message)
1217 case WM_CREATE:
1219 cs = (LPCREATESTRUCTA)lParam;
1221 /* Translation layer doesn't know what's in the cs->lpCreateParams
1222 * so we have to keep track of what environment we're in. */
1224 if( w->flags & WIN_ISWIN32 )
1226 #define ccs ((LPCLIENTCREATESTRUCT)cs->lpCreateParams)
1227 ci->hWindowMenu = ccs->hWindowMenu;
1228 ci->idFirstChild = ccs->idFirstChild;
1229 #undef ccs
1231 else
1233 LPCLIENTCREATESTRUCT16 ccs = (LPCLIENTCREATESTRUCT16)
1234 PTR_SEG_TO_LIN(cs->lpCreateParams);
1235 ci->hWindowMenu = ccs->hWindowMenu;
1236 ci->idFirstChild = ccs->idFirstChild;
1239 ci->hwndChildMaximized = 0;
1240 ci->nActiveChildren = 0;
1241 ci->nTotalCreated = 0;
1242 ci->frameTitle = NULL;
1243 ci->mdiFlags = 0;
1244 ci->self = hwnd;
1245 w->dwStyle |= WS_CLIPCHILDREN;
1247 if (!hBmpClose)
1249 hBmpClose = CreateMDIMenuBitmap();
1250 hBmpRestore = LoadBitmap16( 0, MAKEINTRESOURCE16(OBM_RESTORE) );
1252 MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
1254 if (ci->hWindowMenu != 0)
1255 AppendMenuA( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
1257 GetClientRect(frameWnd->hwndSelf, &rect);
1258 NC_HandleNCCalcSize( w, &rect );
1259 w->rectClient = rect;
1261 TRACE("Client created - hwnd = %04x, idFirst = %u\n",
1262 hwnd, ci->idFirstChild );
1264 retvalue = 0;
1265 goto END;
1267 case WM_DESTROY:
1268 if( ci->hwndChildMaximized )
1269 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized);
1270 if((ci->hWindowMenu != 0) &&
1271 (nItems = GetMenuItemCount(ci->hWindowMenu)) > 0)
1273 ci->idFirstChild = nItems - 1;
1274 ci->nActiveChildren++; /* to delete a separator */
1275 while( ci->nActiveChildren-- )
1276 DeleteMenu(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
1278 retvalue = 0;
1279 goto END;
1281 case WM_MDIACTIVATE:
1282 if( ci->hwndActiveChild != (HWND)wParam )
1283 SetWindowPos((HWND)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
1284 retvalue = 0;
1285 goto END;
1287 case WM_MDICASCADE:
1288 retvalue = MDICascade(w, ci);
1289 goto END;
1291 case WM_MDICREATE:
1292 if (lParam) retvalue = MDICreateChild( w, ci, hwnd,
1293 (MDICREATESTRUCTA*)lParam );
1294 else retvalue = 0;
1295 goto END;
1297 case WM_MDIDESTROY:
1298 retvalue = MDIDestroyChild( w, ci, hwnd, (HWND)wParam, TRUE );
1299 goto END;
1301 case WM_MDIGETACTIVE:
1302 if (lParam) *(BOOL *)lParam = (ci->hwndChildMaximized > 0);
1303 retvalue = ci->hwndActiveChild;
1304 goto END;
1306 case WM_MDIICONARRANGE:
1307 ci->mdiFlags |= MDIF_NEEDUPDATE;
1308 ArrangeIconicWindows(hwnd);
1309 ci->sbRecalc = SB_BOTH+1;
1310 SendMessageA(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
1311 retvalue = 0;
1312 goto END;
1314 case WM_MDIMAXIMIZE:
1315 ShowWindow( (HWND)wParam, SW_MAXIMIZE );
1316 retvalue = 0;
1317 goto END;
1319 case WM_MDINEXT: /* lParam != 0 means previous window */
1320 MDI_SwitchActiveChild(hwnd, (HWND)wParam, (lParam)? FALSE : TRUE );
1321 break;
1323 case WM_MDIRESTORE:
1324 SendMessageA( (HWND)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
1325 retvalue = 0;
1326 goto END;
1328 case WM_MDISETMENU:
1329 retvalue = MDISetMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1330 goto END;
1331 case WM_MDIREFRESHMENU:
1332 retvalue = MDIRefreshMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1333 goto END;
1335 case WM_MDITILE:
1336 ci->mdiFlags |= MDIF_NEEDUPDATE;
1337 ShowScrollBar(hwnd,SB_BOTH,FALSE);
1338 MDITile(w, ci, wParam);
1339 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1340 retvalue = 0;
1341 goto END;
1343 case WM_VSCROLL:
1344 case WM_HSCROLL:
1345 ci->mdiFlags |= MDIF_NEEDUPDATE;
1346 ScrollChildren(hwnd, message, wParam, lParam);
1347 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1348 retvalue = 0;
1349 goto END;
1351 case WM_SETFOCUS:
1352 if( ci->hwndActiveChild )
1354 WND* pw = WIN_FindWndPtr( ci->hwndActiveChild );
1355 if( !(pw->dwStyle & WS_MINIMIZE) )
1356 SetFocus( ci->hwndActiveChild );
1357 WIN_ReleaseWndPtr(pw);
1359 retvalue = 0;
1360 goto END;
1362 case WM_NCACTIVATE:
1363 if( ci->hwndActiveChild )
1364 SendMessageA(ci->hwndActiveChild, message, wParam, lParam);
1365 break;
1367 case WM_PARENTNOTIFY:
1368 if (LOWORD(wParam) == WM_LBUTTONDOWN)
1370 POINT16 pt = MAKEPOINT16(lParam);
1371 HWND16 child = ChildWindowFromPoint16(hwnd, pt);
1373 TRACE("notification from %04x (%i,%i)\n",child,pt.x,pt.y);
1375 if( child && child != hwnd && child != ci->hwndActiveChild )
1376 SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1378 retvalue = 0;
1379 goto END;
1381 case WM_SIZE:
1382 if( IsWindow(ci->hwndChildMaximized) )
1384 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1385 RECT rect;
1387 rect.left = 0;
1388 rect.top = 0;
1389 rect.right = LOWORD(lParam);
1390 rect.bottom = HIWORD(lParam);
1392 AdjustWindowRectEx(&rect, child->dwStyle, 0, child->dwExStyle);
1393 MoveWindow(ci->hwndChildMaximized, rect.left, rect.top,
1394 rect.right - rect.left, rect.bottom - rect.top, 1);
1395 WIN_ReleaseWndPtr(child);
1397 else
1398 MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1400 break;
1402 case WM_MDICALCCHILDSCROLL:
1403 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1405 CalcChildScroll16(hwnd, ci->sbRecalc-1);
1406 ci->sbRecalc = 0;
1407 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1409 retvalue = 0;
1410 goto END;
1413 retvalue = DefWindowProcA( hwnd, message, wParam, lParam );
1414 END:
1415 WIN_ReleaseWndPtr(w);
1416 WIN_ReleaseWndPtr(frameWnd);
1417 return retvalue;
1421 /***********************************************************************
1422 * DefFrameProc16 (USER.445)
1424 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1425 UINT16 message, WPARAM16 wParam, LPARAM lParam )
1427 HWND16 childHwnd;
1428 MDICLIENTINFO* ci;
1429 WND* wndPtr;
1431 if (hwndMDIClient)
1433 switch (message)
1435 case WM_COMMAND:
1436 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1438 if (!wndPtr) {
1439 ERR("null wndPtr for mdi window hwndMDIClient=%04x\n",
1440 hwndMDIClient);
1441 return 0;
1444 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1446 /* check for possible syscommands for maximized MDI child */
1447 WIN_ReleaseWndPtr(wndPtr);
1449 if( ci && (
1450 wParam < ci->idFirstChild ||
1451 wParam >= ci->idFirstChild + ci->nActiveChildren
1453 if( (wParam - 0xF000) & 0xF00F ) break;
1454 switch( wParam )
1456 case SC_SIZE:
1457 case SC_MOVE:
1458 case SC_MINIMIZE:
1459 case SC_MAXIMIZE:
1460 case SC_NEXTWINDOW:
1461 case SC_PREVWINDOW:
1462 case SC_CLOSE:
1463 case SC_RESTORE:
1464 if( ci->hwndChildMaximized )
1465 return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1466 wParam, lParam);
1469 else
1471 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1472 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1474 if (wParam - ci->idFirstChild == MDI_MOREWINDOWSLIMIT)
1475 /* User chose "More Windows..." */
1476 childHwnd = MDI_MoreWindowsDialog(wndPtr);
1477 else
1478 /* User chose one of the windows listed in the "Windows" menu */
1479 childHwnd = MDI_GetChildByID(wndPtr,wParam );
1481 WIN_ReleaseWndPtr(wndPtr);
1482 if( childHwnd )
1483 SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1484 (WPARAM16)childHwnd , 0L);
1486 break;
1488 case WM_NCACTIVATE:
1489 SendMessage16(hwndMDIClient, message, wParam, lParam);
1490 break;
1492 case WM_SETTEXT:
1494 LPWSTR text = HEAP_strdupAtoW( GetProcessHeap(), 0,
1495 (LPCSTR)PTR_SEG_TO_LIN(lParam) );
1496 wndPtr = WIN_FindWndPtr(hwnd);
1497 MDI_UpdateFrameText(wndPtr, hwndMDIClient,
1498 MDI_REPAINTFRAME, text );
1499 WIN_ReleaseWndPtr(wndPtr);
1500 HeapFree( GetProcessHeap(), 0, text );
1502 return 0;
1504 case WM_SETFOCUS:
1505 SetFocus(hwndMDIClient);
1506 break;
1508 case WM_SIZE:
1509 MoveWindow16(hwndMDIClient, 0, 0,
1510 LOWORD(lParam), HIWORD(lParam), TRUE);
1511 break;
1513 case WM_NEXTMENU:
1515 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1516 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1518 if( !(wndPtr->parent->dwStyle & WS_MINIMIZE)
1519 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1521 /* control menu is between the frame system menu and
1522 * the first entry of menu bar */
1524 if( (wParam == VK_LEFT &&
1525 wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1526 (wParam == VK_RIGHT &&
1527 GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1529 LRESULT retvalue;
1530 WIN_ReleaseWndPtr(wndPtr);
1531 wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1532 retvalue = MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1533 ci->hwndActiveChild);
1534 WIN_ReleaseWndPtr(wndPtr);
1535 return retvalue;
1538 WIN_ReleaseWndPtr(wndPtr);
1539 break;
1543 return DefWindowProc16(hwnd, message, wParam, lParam);
1547 /***********************************************************************
1548 * DefFrameProcA (USER32.122)
1550 LRESULT WINAPI DefFrameProcA( HWND hwnd, HWND hwndMDIClient,
1551 UINT message, WPARAM wParam, LPARAM lParam)
1553 if (hwndMDIClient)
1555 switch (message)
1557 case WM_COMMAND:
1558 return DefFrameProc16( hwnd, hwndMDIClient, message,
1559 (WPARAM16)wParam,
1560 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1562 case WM_NCACTIVATE:
1563 SendMessageA(hwndMDIClient, message, wParam, lParam);
1564 break;
1566 case WM_SETTEXT: {
1567 LRESULT ret;
1568 LPSTR segstr = SEGPTR_STRDUP((LPSTR)lParam);
1570 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1571 wParam, (LPARAM)SEGPTR_GET(segstr) );
1572 SEGPTR_FREE(segstr);
1573 return ret;
1576 case WM_NEXTMENU:
1577 case WM_SETFOCUS:
1578 case WM_SIZE:
1579 return DefFrameProc16( hwnd, hwndMDIClient, message,
1580 wParam, lParam );
1584 return DefWindowProcA(hwnd, message, wParam, lParam);
1588 /***********************************************************************
1589 * DefFrameProcW (USER32.123)
1591 LRESULT WINAPI DefFrameProcW( HWND hwnd, HWND hwndMDIClient,
1592 UINT message, WPARAM wParam, LPARAM lParam)
1594 if (hwndMDIClient)
1596 switch (message)
1598 case WM_COMMAND:
1599 return DefFrameProc16( hwnd, hwndMDIClient, message,
1600 (WPARAM16)wParam,
1601 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1603 case WM_NCACTIVATE:
1604 SendMessageW(hwndMDIClient, message, wParam, lParam);
1605 break;
1607 case WM_SETTEXT:
1609 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1610 LRESULT ret = DefFrameProcA( hwnd, hwndMDIClient, message,
1611 wParam, (DWORD)txt );
1612 HeapFree(GetProcessHeap(),0,txt);
1613 return ret;
1615 case WM_NEXTMENU:
1616 case WM_SETFOCUS:
1617 case WM_SIZE:
1618 return DefFrameProcA( hwnd, hwndMDIClient, message,
1619 wParam, lParam );
1623 return DefWindowProcW( hwnd, message, wParam, lParam );
1627 /***********************************************************************
1628 * DefMDIChildProc16 (USER.447)
1630 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1631 WPARAM16 wParam, LPARAM lParam )
1633 MDICLIENTINFO *ci;
1634 WND *clientWnd,*tmpWnd = 0;
1635 LRESULT retvalue;
1637 tmpWnd = WIN_FindWndPtr(hwnd);
1638 if (!tmpWnd) return 0;
1639 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1640 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1641 WIN_ReleaseWndPtr(tmpWnd);
1643 switch (message)
1645 case WM_SETTEXT:
1646 DefWindowProc16(hwnd, message, wParam, lParam);
1647 MDI_MenuModifyItem(clientWnd,hwnd);
1648 if( ci->hwndChildMaximized == hwnd )
1649 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1650 MDI_REPAINTFRAME, NULL );
1651 retvalue = 0;
1652 goto END;
1654 case WM_CLOSE:
1655 SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1656 retvalue = 0;
1657 goto END;
1659 case WM_SETFOCUS:
1660 if( ci->hwndActiveChild != hwnd )
1661 MDI_ChildActivate(clientWnd, hwnd);
1662 break;
1664 case WM_CHILDACTIVATE:
1665 MDI_ChildActivate(clientWnd, hwnd);
1666 retvalue = 0;
1667 goto END;
1669 case WM_NCPAINT:
1670 TRACE("WM_NCPAINT for %04x, active %04x\n",
1671 hwnd, ci->hwndActiveChild );
1672 break;
1674 case WM_SYSCOMMAND:
1675 switch( wParam )
1677 case SC_MOVE:
1678 if( ci->hwndChildMaximized == hwnd)
1680 retvalue = 0;
1681 goto END;
1683 break;
1684 case SC_RESTORE:
1685 case SC_MINIMIZE:
1686 tmpWnd = WIN_FindWndPtr(hwnd);
1687 tmpWnd->dwStyle |= WS_SYSMENU;
1688 WIN_ReleaseWndPtr(tmpWnd);
1689 break;
1690 case SC_MAXIMIZE:
1691 if( ci->hwndChildMaximized == hwnd)
1693 retvalue = SendMessage16( clientWnd->parent->hwndSelf,
1694 message, wParam, lParam);
1695 goto END;
1697 tmpWnd = WIN_FindWndPtr(hwnd);
1698 tmpWnd->dwStyle &= ~WS_SYSMENU;
1699 WIN_ReleaseWndPtr(tmpWnd);
1700 break;
1701 case SC_NEXTWINDOW:
1702 SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1703 retvalue = 0;
1704 goto END;
1705 case SC_PREVWINDOW:
1706 SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1707 retvalue = 0;
1708 goto END;
1710 break;
1712 case WM_GETMINMAXINFO:
1713 MDI_ChildGetMinMaxInfo(clientWnd, hwnd, (MINMAXINFO16*) PTR_SEG_TO_LIN(lParam));
1714 retvalue = 0;
1715 goto END;
1717 case WM_SETVISIBLE:
1718 if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1719 else
1720 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1721 break;
1723 case WM_SIZE:
1724 /* do not change */
1726 if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1728 ci->hwndChildMaximized = 0;
1730 MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1731 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1732 MDI_REPAINTFRAME, NULL );
1735 if( wParam == SIZE_MAXIMIZED )
1737 HWND16 hMaxChild = ci->hwndChildMaximized;
1739 if( hMaxChild == hwnd ) break;
1741 if( hMaxChild)
1743 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1745 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1746 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1748 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1751 TRACE("maximizing child %04x\n", hwnd );
1753 ci->hwndChildMaximized = hwnd; /* !!! */
1754 ci->hwndActiveChild = hwnd;
1756 MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1757 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1758 MDI_REPAINTFRAME, NULL );
1761 if( wParam == SIZE_MINIMIZED )
1763 HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1765 if( switchTo )
1766 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1769 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1770 break;
1772 case WM_MENUCHAR:
1774 /* MDI children don't have menu bars */
1775 retvalue = 0x00010000L;
1776 goto END;
1778 case WM_NEXTMENU:
1780 if( wParam == VK_LEFT ) /* switch to frame system menu */
1782 retvalue = MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1783 clientWnd->parent->hwndSelf );
1784 goto END;
1786 if( wParam == VK_RIGHT ) /* to frame menu bar */
1788 retvalue = MAKELONG( clientWnd->parent->wIDmenu,
1789 clientWnd->parent->hwndSelf );
1790 goto END;
1793 break;
1795 case WM_SYSCHAR:
1796 if (wParam == '-')
1798 SendMessage16(hwnd,WM_SYSCOMMAND,
1799 (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1800 retvalue = 0;
1801 goto END;
1805 retvalue = DefWindowProc16(hwnd, message, wParam, lParam);
1806 END:
1807 WIN_ReleaseWndPtr(clientWnd);
1808 return retvalue;
1812 /***********************************************************************
1813 * DefMDIChildProcA (USER32.124)
1815 LRESULT WINAPI DefMDIChildProcA( HWND hwnd, UINT message,
1816 WPARAM wParam, LPARAM lParam )
1818 MDICLIENTINFO *ci;
1819 WND *clientWnd,*tmpWnd;
1820 LRESULT retvalue;
1822 tmpWnd = WIN_FindWndPtr(hwnd);
1823 if (!tmpWnd) return 0;
1824 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1825 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1826 WIN_ReleaseWndPtr(tmpWnd);
1828 switch (message)
1830 case WM_SETTEXT:
1831 DefWindowProcA(hwnd, message, wParam, lParam);
1832 MDI_MenuModifyItem(clientWnd,hwnd);
1833 if( ci->hwndChildMaximized == hwnd )
1834 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1835 MDI_REPAINTFRAME, NULL );
1836 retvalue = 0;
1837 goto END;
1839 case WM_GETMINMAXINFO:
1841 MINMAXINFO16 mmi;
1842 STRUCT32_MINMAXINFO32to16( (MINMAXINFO *)lParam, &mmi );
1843 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1844 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO *)lParam );
1846 retvalue = 0;
1847 goto END;
1849 case WM_MENUCHAR:
1851 /* MDI children don't have menu bars */
1852 retvalue = 0x00010000L;
1853 goto END;
1855 case WM_CLOSE:
1856 case WM_SETFOCUS:
1857 case WM_CHILDACTIVATE:
1858 case WM_NCPAINT:
1859 case WM_SYSCOMMAND:
1860 case WM_SETVISIBLE:
1861 case WM_SIZE:
1862 case WM_NEXTMENU:
1863 retvalue = DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1864 goto END;
1866 case WM_SYSCHAR:
1867 if (wParam == '-')
1869 SendMessageA(hwnd,WM_SYSCOMMAND,
1870 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1871 retvalue = 0;
1872 goto END;
1875 retvalue = DefWindowProcA(hwnd, message, wParam, lParam);
1876 END:
1877 WIN_ReleaseWndPtr(clientWnd);
1878 return retvalue;
1882 /***********************************************************************
1883 * DefMDIChildProcW (USER32.125)
1885 LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message,
1886 WPARAM wParam, LPARAM lParam )
1888 MDICLIENTINFO *ci;
1889 WND *clientWnd,*tmpWnd;
1890 LRESULT retvalue;
1892 tmpWnd = WIN_FindWndPtr(hwnd);
1893 if (!tmpWnd) return 0;
1894 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1895 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1896 WIN_ReleaseWndPtr(tmpWnd);
1898 switch (message)
1900 case WM_SETTEXT:
1901 DefWindowProcW(hwnd, message, wParam, lParam);
1902 MDI_MenuModifyItem(clientWnd,hwnd);
1903 if( ci->hwndChildMaximized == hwnd )
1904 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1905 MDI_REPAINTFRAME, NULL );
1906 retvalue = 0;
1907 goto END;
1909 case WM_GETMINMAXINFO:
1910 case WM_MENUCHAR:
1911 case WM_CLOSE:
1912 case WM_SETFOCUS:
1913 case WM_CHILDACTIVATE:
1914 case WM_NCPAINT:
1915 case WM_SYSCOMMAND:
1916 case WM_SETVISIBLE:
1917 case WM_SIZE:
1918 case WM_NEXTMENU:
1919 retvalue = DefMDIChildProcA( hwnd, message, (WPARAM16)wParam, lParam );
1920 goto END;
1922 case WM_SYSCHAR:
1923 if (wParam == '-')
1925 SendMessageW(hwnd,WM_SYSCOMMAND,
1926 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1927 retvalue = 0;
1928 goto END;
1931 retvalue = DefWindowProcW(hwnd, message, wParam, lParam);
1932 END:
1933 WIN_ReleaseWndPtr(clientWnd);
1934 return retvalue;
1939 /**********************************************************************
1940 * CreateMDIWindowA [USER32.79] Creates a MDI child in new thread
1941 * FIXME: its in the same thread now
1943 * RETURNS
1944 * Success: Handle to created window
1945 * Failure: NULL
1947 HWND WINAPI CreateMDIWindowA(
1948 LPCSTR lpClassName, /* [in] Pointer to registered child class name */
1949 LPCSTR lpWindowName, /* [in] Pointer to window name */
1950 DWORD dwStyle, /* [in] Window style */
1951 INT X, /* [in] Horizontal position of window */
1952 INT Y, /* [in] Vertical position of window */
1953 INT nWidth, /* [in] Width of window */
1954 INT nHeight, /* [in] Height of window */
1955 HWND hWndParent, /* [in] Handle to parent window */
1956 HINSTANCE hInstance, /* [in] Handle to application instance */
1957 LPARAM lParam) /* [in] Application-defined value */
1959 WARN("is only single threaded!\n");
1960 return MDI_CreateMDIWindowA(lpClassName, lpWindowName, dwStyle, X, Y,
1961 nWidth, nHeight, hWndParent, hInstance, lParam);
1964 /**********************************************************************
1965 * MDI_CreateMDIWindowA
1966 * single threaded version of CreateMDIWindowA
1967 * called by CreateWindowExA
1969 HWND MDI_CreateMDIWindowA(
1970 LPCSTR lpClassName,
1971 LPCSTR lpWindowName,
1972 DWORD dwStyle,
1973 INT X,
1974 INT Y,
1975 INT nWidth,
1976 INT nHeight,
1977 HWND hWndParent,
1978 HINSTANCE hInstance,
1979 LPARAM lParam)
1981 MDICLIENTINFO* pCi;
1982 MDICREATESTRUCTA cs;
1983 WND *pWnd=WIN_FindWndPtr(hWndParent);
1984 HWND retvalue;
1986 TRACE("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
1987 debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
1988 nWidth,nHeight,hWndParent,hInstance,lParam);
1990 if(!pWnd){
1991 ERR(" bad hwnd for MDI-client: %d\n",hWndParent);
1992 return 0;
1994 cs.szClass=lpClassName;
1995 cs.szTitle=lpWindowName;
1996 cs.hOwner=hInstance;
1997 cs.x=X;
1998 cs.y=Y;
1999 cs.cx=nWidth;
2000 cs.cy=nHeight;
2001 cs.style=dwStyle;
2002 cs.lParam=lParam;
2004 pCi=(MDICLIENTINFO *)pWnd->wExtra;
2006 retvalue = MDICreateChild(pWnd,pCi,hWndParent,&cs);
2007 WIN_ReleaseWndPtr(pWnd);
2008 return retvalue;
2011 /***********************************************************************
2012 * CreateMDIWindowW [USER32.80] Creates a MDI child in new thread
2014 * RETURNS
2015 * Success: Handle to created window
2016 * Failure: NULL
2018 HWND WINAPI CreateMDIWindowW(
2019 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
2020 LPCWSTR lpWindowName, /* [in] Pointer to window name */
2021 DWORD dwStyle, /* [in] Window style */
2022 INT X, /* [in] Horizontal position of window */
2023 INT Y, /* [in] Vertical position of window */
2024 INT nWidth, /* [in] Width of window */
2025 INT nHeight, /* [in] Height of window */
2026 HWND hWndParent, /* [in] Handle to parent window */
2027 HINSTANCE hInstance, /* [in] Handle to application instance */
2028 LPARAM lParam) /* [in] Application-defined value */
2030 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
2031 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
2032 nWidth,nHeight,hWndParent,hInstance,lParam);
2033 return (HWND)NULL;
2037 /******************************************************************************
2038 * CreateMDIWindowW [USER32.80] Creates a MDI child window
2039 * single threaded version of CreateMDIWindow
2040 * called by CreateWindowExW().
2042 HWND MDI_CreateMDIWindowW(
2043 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
2044 LPCWSTR lpWindowName, /* [in] Pointer to window name */
2045 DWORD dwStyle, /* [in] Window style */
2046 INT X, /* [in] Horizontal position of window */
2047 INT Y, /* [in] Vertical position of window */
2048 INT nWidth, /* [in] Width of window */
2049 INT nHeight, /* [in] Height of window */
2050 HWND hWndParent, /* [in] Handle to parent window */
2051 HINSTANCE hInstance, /* [in] Handle to application instance */
2052 LPARAM lParam) /* [in] Application-defined value */
2054 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
2055 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
2056 nWidth,nHeight,hWndParent,hInstance,lParam);
2057 return (HWND)NULL;
2061 /**********************************************************************
2062 * TranslateMDISysAccel (USER32.555)
2064 BOOL WINAPI TranslateMDISysAccel( HWND hwndClient, LPMSG msg )
2066 MSG16 msg16;
2068 STRUCT32_MSG32to16(msg,&msg16);
2069 /* MDICLIENTINFO is still the same for win32 and win16 ... */
2070 return TranslateMDISysAccel16(hwndClient,&msg16);
2074 /**********************************************************************
2075 * TranslateMDISysAccel16 (USER.451)
2077 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
2080 if( IsWindow(hwndClient) && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
2082 MDICLIENTINFO *ci = NULL;
2083 HWND wnd;
2084 WND *clientWnd = WIN_FindWndPtr(hwndClient);
2086 ci = (MDICLIENTINFO*) clientWnd->wExtra;
2087 wnd = ci->hwndActiveChild;
2089 WIN_ReleaseWndPtr(clientWnd);
2091 if( IsWindow(wnd) && !(GetWindowLongA(wnd,GWL_STYLE) & WS_DISABLED) )
2093 WPARAM16 wParam = 0;
2095 /* translate if the Ctrl key is down and Alt not. */
2097 if( (GetKeyState(VK_CONTROL) & 0x8000) &&
2098 !(GetKeyState(VK_MENU) & 0x8000))
2100 switch( msg->wParam )
2102 case VK_F6:
2103 case VK_TAB:
2104 wParam = ( GetKeyState(VK_SHIFT) & 0x8000 )
2105 ? SC_NEXTWINDOW : SC_PREVWINDOW;
2106 break;
2107 case VK_F4:
2108 case VK_RBUTTON:
2109 wParam = SC_CLOSE;
2110 break;
2111 default:
2112 return 0;
2114 TRACE("wParam = %04x\n", wParam);
2115 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
2116 wParam, (LPARAM)msg->wParam);
2117 return 1;
2121 return 0; /* failure */
2125 /***********************************************************************
2126 * CalcChildScroll (USER.462)
2128 void WINAPI CalcChildScroll16( HWND16 hwnd, WORD scroll )
2130 SCROLLINFO info;
2131 RECT childRect, clientRect;
2132 INT vmin, vmax, hmin, hmax, vpos, hpos;
2133 WND *pWnd, *Wnd;
2135 if (!(pWnd = WIN_FindWndPtr( hwnd ))) return;
2136 Wnd = WIN_FindWndPtr(hwnd);
2137 GetClientRect( hwnd, &clientRect );
2138 SetRectEmpty( &childRect );
2140 for ( WIN_UpdateWndPtr(&pWnd,pWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2142 if( pWnd->dwStyle & WS_MAXIMIZE )
2144 ShowScrollBar(hwnd, SB_BOTH, FALSE);
2145 WIN_ReleaseWndPtr(pWnd);
2146 WIN_ReleaseWndPtr(Wnd);
2147 return;
2149 UnionRect( &childRect, &pWnd->rectWindow, &childRect );
2151 WIN_ReleaseWndPtr(pWnd);
2152 UnionRect( &childRect, &clientRect, &childRect );
2154 hmin = childRect.left; hmax = childRect.right - clientRect.right;
2155 hpos = clientRect.left - childRect.left;
2156 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
2157 vpos = clientRect.top - childRect.top;
2159 switch( scroll )
2161 case SB_HORZ:
2162 vpos = hpos; vmin = hmin; vmax = hmax;
2163 case SB_VERT:
2164 info.cbSize = sizeof(info);
2165 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
2166 info.fMask = SIF_POS | SIF_RANGE;
2167 SetScrollInfo(hwnd, scroll, &info, TRUE);
2168 break;
2169 case SB_BOTH:
2170 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
2171 hmin, hmax, hpos);
2173 WIN_ReleaseWndPtr(Wnd);
2177 /***********************************************************************
2178 * ScrollChildren16 (USER.463)
2180 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
2182 ScrollChildren( hWnd, uMsg, wParam, lParam );
2186 /***********************************************************************
2187 * ScrollChildren (USER32.448)
2189 void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
2190 LPARAM lParam)
2192 WND *wndPtr = WIN_FindWndPtr(hWnd);
2193 INT newPos = -1;
2194 INT curPos, length, minPos, maxPos, shift;
2196 if( !wndPtr ) return;
2198 if( uMsg == WM_HSCROLL )
2200 GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
2201 curPos = GetScrollPos(hWnd,SB_HORZ);
2202 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
2203 shift = GetSystemMetrics(SM_CYHSCROLL);
2205 else if( uMsg == WM_VSCROLL )
2207 GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
2208 curPos = GetScrollPos(hWnd,SB_VERT);
2209 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
2210 shift = GetSystemMetrics(SM_CXVSCROLL);
2212 else
2214 WIN_ReleaseWndPtr(wndPtr);
2215 return;
2218 WIN_ReleaseWndPtr(wndPtr);
2219 switch( wParam )
2221 case SB_LINEUP:
2222 newPos = curPos - shift;
2223 break;
2224 case SB_LINEDOWN:
2225 newPos = curPos + shift;
2226 break;
2227 case SB_PAGEUP:
2228 newPos = curPos - length;
2229 break;
2230 case SB_PAGEDOWN:
2231 newPos = curPos + length;
2232 break;
2234 case SB_THUMBPOSITION:
2235 newPos = LOWORD(lParam);
2236 break;
2238 case SB_THUMBTRACK:
2239 return;
2241 case SB_TOP:
2242 newPos = minPos;
2243 break;
2244 case SB_BOTTOM:
2245 newPos = maxPos;
2246 break;
2247 case SB_ENDSCROLL:
2248 CalcChildScroll16(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
2249 return;
2252 if( newPos > maxPos )
2253 newPos = maxPos;
2254 else
2255 if( newPos < minPos )
2256 newPos = minPos;
2258 SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
2260 if( uMsg == WM_VSCROLL )
2261 ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
2262 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2263 else
2264 ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
2265 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2269 /******************************************************************************
2270 * CascadeWindows [USER32.21] Cascades MDI child windows
2272 * RETURNS
2273 * Success: Number of cascaded windows.
2274 * Failure: 0
2276 WORD WINAPI
2277 CascadeWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2278 UINT cKids, const HWND *lpKids)
2280 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2281 hwndParent, wFlags, cKids);
2283 return 0;
2287 /******************************************************************************
2288 * TileWindows [USER32.545] Tiles MDI child windows
2290 * RETURNS
2291 * Success: Number of tiled windows.
2292 * Failure: 0
2294 WORD WINAPI
2295 TileWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2296 UINT cKids, const HWND *lpKids)
2298 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2299 hwndParent, wFlags, cKids);
2301 return 0;
2304 /************************************************************************
2305 * "More Windows..." functionality
2308 /* MDI_MoreWindowsDlgProc
2310 * This function will process the messages sent to the "More Windows..."
2311 * dialog.
2312 * Return values: 0 = cancel pressed
2313 * HWND = ok pressed or double-click in the list...
2317 static BOOL WINAPI MDI_MoreWindowsDlgProc (HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
2319 switch (iMsg)
2321 case WM_INITDIALOG:
2323 WND *pWnd;
2324 UINT widest = 0;
2325 UINT length;
2326 UINT i;
2327 WND *pParentWnd = (WND *)lParam;
2328 MDICLIENTINFO *ci = (MDICLIENTINFO*)pParentWnd->wExtra;
2329 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2331 /* Fill the list, sorted by id... */
2332 for (i = 0; i < ci->nActiveChildren; i++)
2335 /* Find the window with the current ID */
2336 for (pWnd = WIN_LockWndPtr(pParentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd, pWnd->next))
2337 if (pWnd->wIDmenu == ci->idFirstChild + i)
2338 break;
2340 SendMessageW(hListBox, LB_ADDSTRING, 0, (LPARAM) pWnd->text);
2341 SendMessageA(hListBox, LB_SETITEMDATA, i, (LPARAM) pWnd);
2342 length = strlenW(pWnd->text);
2343 WIN_ReleaseWndPtr(pWnd);
2345 if (length > widest)
2346 widest = length;
2348 /* Make sure the horizontal scrollbar scrolls ok */
2349 SendMessageA(hListBox, LB_SETHORIZONTALEXTENT, widest * 6, 0);
2351 /* Set the current selection */
2352 SendMessageA(hListBox, LB_SETCURSEL, MDI_MOREWINDOWSLIMIT, 0);
2353 return TRUE;
2356 case WM_COMMAND:
2357 switch (LOWORD(wParam))
2359 case IDOK:
2361 /* windows are sorted by menu ID, so we must return the
2362 * window associated to the given id
2364 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2365 UINT index = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
2366 WND* pWnd = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
2368 EndDialog(hDlg, pWnd->hwndSelf);
2369 return TRUE;
2371 case IDCANCEL:
2372 EndDialog(hDlg, 0);
2373 return TRUE;
2375 default:
2376 switch (HIWORD(wParam))
2378 case LBN_DBLCLK:
2380 /* windows are sorted by menu ID, so we must return the
2381 * window associated to the given id
2383 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2384 UINT index = SendMessageA(hListBox, LB_GETCURSEL, 0, 0);
2385 WND* pWnd = (WND*) SendMessageA(hListBox, LB_GETITEMDATA, index, 0);
2387 EndDialog(hDlg, pWnd->hwndSelf);
2388 return TRUE;
2391 break;
2393 break;
2395 return FALSE;
2400 * MDI_MoreWindowsDialog
2402 * Prompts the user with a listbox containing the opened
2403 * documents. The user can then choose a windows and click
2404 * on OK to set the current window to the one selected, or
2405 * CANCEL to cancel. The function returns a handle to the
2406 * selected window.
2409 static HWND MDI_MoreWindowsDialog(WND* wndPtr)
2411 LPCVOID template;
2412 HRSRC hRes;
2413 HANDLE hDlgTmpl;
2415 hRes = FindResourceA(GetModuleHandleA("USER32"), "MDI_MOREWINDOWS", RT_DIALOGA);
2417 if (hRes == 0)
2418 return 0;
2420 hDlgTmpl = LoadResource(GetModuleHandleA("USER32"), hRes );
2422 if (hDlgTmpl == 0)
2423 return 0;
2425 template = LockResource( hDlgTmpl );
2427 if (template == 0)
2428 return 0;
2430 return (HWND) DialogBoxIndirectParamA(GetModuleHandleA("USER32"),
2431 (LPDLGTEMPLATEA) template,
2432 wndPtr->hwndSelf,
2433 (DLGPROC) MDI_MoreWindowsDlgProc,
2434 (LPARAM) wndPtr);
2439 * MDI_SwapMenuItems
2441 * Will swap the menu IDs for the given 2 positions.
2442 * pos1 and pos2 are menu IDs
2447 static void MDI_SwapMenuItems(WND *parentWnd, UINT pos1, UINT pos2)
2449 WND *pWnd;
2451 for (pWnd = WIN_LockWndPtr(parentWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2453 if (pWnd->wIDmenu == pos1)
2454 pWnd->wIDmenu = pos2;
2455 else
2456 if (pWnd->wIDmenu == pos2)
2457 pWnd->wIDmenu = pos1;
2460 WIN_ReleaseWndPtr(pWnd);