3 * Copyright 1994, Bob Amstadt
4 * 1995,1996 Alex Korobka
6 * This file contains routines to support MDI features.
8 * Notes: Fairly complete implementation. Any volunteers for
9 * "More windows..." stuff?
11 * Also, Excel and WinWord do _not_ use MDI so if you're trying
12 * to fix them look elsewhere.
21 #include "nonclient.h"
28 #include "debugtools.h"
30 DEFAULT_DEBUG_CHANNEL(mdi)
32 #define MDIF_NEEDUPDATE 0x0001
34 static HBITMAP16 hBmpClose = 0;
35 static HBITMAP16 hBmpRestore = 0;
37 /* ----------------- declarations ----------------- */
38 static void MDI_UpdateFrameText(WND *, HWND, BOOL, LPCSTR);
39 static BOOL MDI_AugmentFrameMenu(MDICLIENTINFO*, WND *, HWND);
40 static BOOL MDI_RestoreFrameMenu(WND *, HWND);
42 static LONG MDI_ChildActivate( WND*, HWND );
44 /* -------- Miscellaneous service functions ----------
49 static HWND MDI_GetChildByID(WND* wndPtr, INT id)
51 for (wndPtr = wndPtr->child; wndPtr; wndPtr = wndPtr->next)
52 if (wndPtr->wIDmenu == id) return wndPtr->hwndSelf;
56 static void MDI_PostUpdate(HWND hwnd, MDICLIENTINFO* ci, WORD recalc)
58 if( !(ci->mdiFlags & MDIF_NEEDUPDATE) )
60 ci->mdiFlags |= MDIF_NEEDUPDATE;
61 PostMessageA( hwnd, WM_MDICALCCHILDSCROLL, 0, 0);
63 ci->sbRecalc = recalc;
66 /**********************************************************************
69 static BOOL MDI_MenuModifyItem(WND* clientWnd, HWND hWndChild )
72 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
73 WND *wndPtr = WIN_FindWndPtr(hWndChild);
74 UINT n = sprintf(buffer, "%d ",
75 wndPtr->wIDmenu - clientInfo->idFirstChild + 1);
78 if( !clientInfo->hWindowMenu )
84 if (wndPtr->text) lstrcpynA(buffer + n, wndPtr->text, sizeof(buffer) - n );
86 n = GetMenuState(clientInfo->hWindowMenu,wndPtr->wIDmenu ,MF_BYCOMMAND);
87 bRet = ModifyMenuA(clientInfo->hWindowMenu , wndPtr->wIDmenu,
88 MF_BYCOMMAND | MF_STRING, wndPtr->wIDmenu, buffer );
89 CheckMenuItem(clientInfo->hWindowMenu ,wndPtr->wIDmenu , n & MF_CHECKED);
91 WIN_ReleaseWndPtr(wndPtr);
95 /**********************************************************************
98 static BOOL MDI_MenuDeleteItem(WND* clientWnd, HWND hWndChild )
101 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
102 WND *wndPtr = WIN_FindWndPtr(hWndChild);
106 if( !clientInfo->nActiveChildren ||
107 !clientInfo->hWindowMenu )
113 id = wndPtr->wIDmenu;
114 DeleteMenu(clientInfo->hWindowMenu,id,MF_BYCOMMAND);
116 /* walk the rest of MDI children to prevent gaps in the id
117 * sequence and in the menu child list */
119 for( index = id+1; index <= clientInfo->nActiveChildren +
120 clientInfo->idFirstChild; index++ )
122 WND *tmpWnd = WIN_FindWndPtr(MDI_GetChildByID(clientWnd,index));
125 TRACE("no window for id=%i\n",index);
126 WIN_ReleaseWndPtr(tmpWnd);
133 n = sprintf(buffer, "%d ",index - clientInfo->idFirstChild);
135 lstrcpynA(buffer + n, tmpWnd->text, sizeof(buffer) - n );
138 ModifyMenuA(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING,
139 index - 1 , buffer );
140 WIN_ReleaseWndPtr(tmpWnd);
144 WIN_ReleaseWndPtr(wndPtr);
148 /**********************************************************************
151 * returns "activateable" child different from the current or zero
153 static HWND MDI_GetWindow(WND *clientWnd, HWND hWnd, BOOL bNext,
156 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
157 WND *wndPtr, *pWnd, *pWndLast = NULL;
159 dwStyleMask |= WS_DISABLED | WS_VISIBLE;
160 if( !hWnd ) hWnd = clientInfo->hwndActiveChild;
162 if( !(wndPtr = WIN_FindWndPtr(hWnd)) ) return 0;
164 for ( pWnd = WIN_LockWndPtr(wndPtr->next); ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
166 if (!pWnd ) WIN_UpdateWndPtr(&pWnd,wndPtr->parent->child);
168 if ( pWnd == wndPtr ) break; /* went full circle */
170 if (!pWnd->owner && (pWnd->dwStyle & dwStyleMask) == WS_VISIBLE )
176 WIN_ReleaseWndPtr(wndPtr);
177 WIN_ReleaseWndPtr(pWnd);
178 return pWndLast ? pWndLast->hwndSelf : 0;
181 /**********************************************************************
182 * MDI_CalcDefaultChildPos
184 * It seems that the default height is about 2/3 of the client rect
186 static void MDI_CalcDefaultChildPos( WND* w, WORD n, LPPOINT lpPos,
190 RECT rect = w->rectClient;
191 INT spacing = GetSystemMetrics(SM_CYCAPTION) +
192 GetSystemMetrics(SM_CYFRAME) - 1;
194 if( rect.bottom - rect.top - delta >= spacing )
195 rect.bottom -= delta;
197 nstagger = (rect.bottom - rect.top)/(3 * spacing);
198 lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
199 lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
200 lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
203 /**********************************************************************
206 static LRESULT MDISetMenu( HWND hwnd, HMENU hmenuFrame,
211 HWND hwndFrame = GetParent(hwnd);
212 HMENU oldFrameMenu = GetMenu(hwndFrame);
214 TRACE("%04x %04x %04x\n",
215 hwnd, hmenuFrame, hmenuWindow);
217 if (hmenuFrame && !IsMenu(hmenuFrame))
219 WARN("hmenuFrame is not a menu handle\n");
223 if (hmenuWindow && !IsMenu(hmenuWindow))
225 WARN("hmenuWindow is not a menu handle\n");
229 w = WIN_FindWndPtr(hwnd);
230 ci = (MDICLIENTINFO *) w->wExtra;
232 if( ci->hwndChildMaximized && hmenuFrame && hmenuFrame!=oldFrameMenu )
233 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized );
235 if( hmenuWindow && hmenuWindow!=ci->hWindowMenu )
237 /* delete menu items from ci->hWindowMenu
238 * and add them to hmenuWindow */
240 INT i = GetMenuItemCount(ci->hWindowMenu) - 1;
241 INT pos = GetMenuItemCount(hmenuWindow) + 1;
243 AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL);
245 if( ci->nActiveChildren )
247 INT j = i - ci->nActiveChildren + 1;
251 for( ; i >= j ; i-- )
253 id = GetMenuItemID(ci->hWindowMenu,i );
254 state = GetMenuState(ci->hWindowMenu,i,MF_BYPOSITION);
256 GetMenuStringA(ci->hWindowMenu, i, buffer, 100, MF_BYPOSITION);
258 DeleteMenu(ci->hWindowMenu, i , MF_BYPOSITION);
259 InsertMenuA(hmenuWindow, pos, MF_BYPOSITION | MF_STRING,
261 CheckMenuItem(hmenuWindow ,pos , MF_BYPOSITION | (state & MF_CHECKED));
265 /* remove separator */
266 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
268 ci->hWindowMenu = hmenuWindow;
271 if( hmenuFrame && hmenuFrame!=oldFrameMenu)
273 SetMenu(hwndFrame, hmenuFrame);
274 if( ci->hwndChildMaximized )
275 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
276 WIN_ReleaseWndPtr(w);
279 WIN_ReleaseWndPtr(w);
283 /**********************************************************************
286 static LRESULT MDIRefreshMenu( HWND hwnd, HMENU hmenuFrame,
289 HWND hwndFrame = GetParent(hwnd);
290 HMENU oldFrameMenu = GetMenu(hwndFrame);
292 TRACE("%04x %04x %04x\n",
293 hwnd, hmenuFrame, hmenuWindow);
295 FIXME("partially function stub\n");
301 /* ------------------ MDI child window functions ---------------------- */
304 /**********************************************************************
307 static HWND MDICreateChild( WND *w, MDICLIENTINFO *ci, HWND parent,
308 LPMDICREATESTRUCTA cs )
311 DWORD style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
312 HWND hwnd, hwndMax = 0;
313 WORD wIDmenu = ci->idFirstChild + ci->nActiveChildren;
314 char lpstrDef[]="junk!";
316 TRACE("origin %i,%i - dim %i,%i, style %08x\n",
317 cs->x, cs->y, cs->cx, cs->cy, (unsigned)cs->style);
318 /* calculate placement */
319 MDI_CalcDefaultChildPos(w, ci->nTotalCreated++, pos, 0);
321 if (cs->cx == CW_USEDEFAULT || !cs->cx) cs->cx = pos[1].x;
322 if (cs->cy == CW_USEDEFAULT || !cs->cy) cs->cy = pos[1].y;
324 if( cs->x == CW_USEDEFAULT )
330 /* restore current maximized child */
331 if( style & WS_VISIBLE && ci->hwndChildMaximized )
333 if( style & WS_MAXIMIZE )
334 SendMessageA(w->hwndSelf, WM_SETREDRAW, FALSE, 0L );
335 hwndMax = ci->hwndChildMaximized;
336 ShowWindow( hwndMax, SW_SHOWNOACTIVATE );
337 if( style & WS_MAXIMIZE )
338 SendMessageA(w->hwndSelf, WM_SETREDRAW, TRUE, 0L );
341 /* this menu is needed to set a check mark in MDI_ChildActivate */
342 AppendMenuA(ci->hWindowMenu ,MF_STRING ,wIDmenu, lpstrDef );
344 ci->nActiveChildren++;
346 /* fix window style */
347 if( !(w->dwStyle & MDIS_ALLCHILDSTYLES) )
349 style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE |
350 WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL );
351 style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW);
354 if( w->flags & WIN_ISWIN32 )
356 hwnd = CreateWindowA( cs->szClass, cs->szTitle, style,
357 cs->x, cs->y, cs->cx, cs->cy, parent,
358 (HMENU16)wIDmenu, cs->hOwner, cs );
362 MDICREATESTRUCT16 *cs16;
365 cs16 = SEGPTR_NEW(MDICREATESTRUCT16);
366 STRUCT32_MDICREATESTRUCT32Ato16( cs, cs16 );
367 title = SEGPTR_STRDUP( cs->szTitle );
368 cls = SEGPTR_STRDUP( cs->szClass );
369 cs16->szTitle = SEGPTR_GET(title);
370 cs16->szClass = SEGPTR_GET(cls);
372 hwnd = CreateWindow16( cs->szClass, cs->szTitle, style,
373 cs16->x, cs16->y, cs16->cx, cs16->cy, parent,
374 (HMENU)wIDmenu, cs16->hOwner,
375 (LPVOID)SEGPTR_GET(cs16) );
376 SEGPTR_FREE( title );
381 /* MDI windows are WS_CHILD so they won't be activated by CreateWindow */
385 WND* wnd = WIN_FindWndPtr( hwnd );
387 /* All MDI child windows have the WS_EX_MDICHILD style */
388 wnd->dwExStyle |= WS_EX_MDICHILD;
390 MDI_MenuModifyItem(w ,hwnd);
391 if( wnd->dwStyle & WS_MINIMIZE && ci->hwndActiveChild )
392 ShowWindow( hwnd, SW_SHOWMINNOACTIVE );
395 /* WS_VISIBLE is clear if a) the MDI client has
396 * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the
397 * MDICreateStruct. If so the created window is not shown nor
400 int showflag=wnd->dwStyle & WS_VISIBLE;
401 /* clear visible flag, otherwise SetWindoPos32 ignores
402 * the SWP_SHOWWINDOW command.
404 wnd->dwStyle &= ~WS_VISIBLE;
406 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE );
408 /* Set maximized state here in case hwnd didn't receive WM_SIZE
409 * during CreateWindow - bad!
412 if((wnd->dwStyle & WS_MAXIMIZE) && !ci->hwndChildMaximized )
414 ci->hwndChildMaximized = wnd->hwndSelf;
415 MDI_AugmentFrameMenu( ci, w->parent, hwnd );
416 MDI_UpdateFrameText( w->parent, ci->self, MDI_REPAINTFRAME, NULL );
419 /* needed, harmless ? */
420 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE );
423 WIN_ReleaseWndPtr(wnd);
424 TRACE("created child - %04x\n",hwnd);
428 ci->nActiveChildren--;
429 DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
430 if( IsWindow(hwndMax) )
431 ShowWindow(hwndMax, SW_SHOWMAXIMIZED);
437 /**********************************************************************
438 * MDI_ChildGetMinMaxInfo
440 * Note: The rule here is that client rect of the maximized MDI child
441 * is equal to the client rect of the MDI client window.
443 static void MDI_ChildGetMinMaxInfo( WND* clientWnd, HWND hwnd,
444 MINMAXINFO16* lpMinMax )
446 WND* childWnd = WIN_FindWndPtr(hwnd);
447 RECT rect = clientWnd->rectClient;
449 MapWindowPoints( clientWnd->parent->hwndSelf,
450 ((MDICLIENTINFO*)clientWnd->wExtra)->self, (LPPOINT)&rect, 2);
451 AdjustWindowRectEx( &rect, childWnd->dwStyle, 0, childWnd->dwExStyle );
453 lpMinMax->ptMaxSize.x = rect.right -= rect.left;
454 lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
456 lpMinMax->ptMaxPosition.x = rect.left;
457 lpMinMax->ptMaxPosition.y = rect.top;
459 WIN_ReleaseWndPtr(childWnd);
461 TRACE("max rect (%i,%i - %i, %i)\n",
462 rect.left,rect.top,rect.right,rect.bottom);
466 /**********************************************************************
467 * MDI_SwitchActiveChild
469 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
472 static void MDI_SwitchActiveChild( HWND clientHwnd, HWND childHwnd,
475 WND *w = WIN_FindWndPtr(clientHwnd);
480 hwndTo = MDI_GetWindow(w, childHwnd, bNextWindow, 0);
482 ci = (MDICLIENTINFO *) w->wExtra;
484 TRACE("from %04x, to %04x\n",childHwnd,hwndTo);
486 if ( !hwndTo ) goto END; /* no window to switch to */
488 hwndPrev = ci->hwndActiveChild;
490 if ( hwndTo != hwndPrev )
494 if( ci->hwndChildMaximized )
497 w->dwStyle &= ~WS_VISIBLE;
500 SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0,
501 SWP_NOMOVE | SWP_NOSIZE );
503 if( bNextWindow && hwndPrev )
504 SetWindowPos( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0,
505 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
507 ShowWindow( clientHwnd, SW_SHOW );
510 WIN_ReleaseWndPtr(w);
514 /**********************************************************************
517 static LRESULT MDIDestroyChild( WND *w_parent, MDICLIENTINFO *ci,
518 HWND parent, HWND child,
521 WND *childPtr = WIN_FindWndPtr(child);
525 if( child == ci->hwndActiveChild )
527 MDI_SwitchActiveChild(parent, child, TRUE);
529 if( child == ci->hwndActiveChild )
531 ShowWindow( child, SW_HIDE);
532 if( child == ci->hwndChildMaximized )
534 MDI_RestoreFrameMenu(w_parent->parent, child);
535 ci->hwndChildMaximized = 0;
536 MDI_UpdateFrameText(w_parent->parent,parent,TRUE,NULL);
539 MDI_ChildActivate(w_parent, 0);
542 MDI_MenuDeleteItem(w_parent, child);
544 WIN_ReleaseWndPtr(childPtr);
546 ci->nActiveChildren--;
548 TRACE("child destroyed - %04x\n",child);
552 MDI_PostUpdate(GetParent(child), ci, SB_BOTH+1);
553 DestroyWindow(child);
561 /**********************************************************************
564 * Note: hWndChild is NULL when last child is being destroyed
566 static LONG MDI_ChildActivate( WND *clientPtr, HWND hWndChild )
568 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientPtr->wExtra;
569 HWND prevActiveWnd = clientInfo->hwndActiveChild;
570 WND *wndPtr = WIN_FindWndPtr( hWndChild );
571 WND *wndPrev = WIN_FindWndPtr( prevActiveWnd );
572 BOOL isActiveFrameWnd = 0;
577 if( wndPtr->dwStyle & WS_DISABLED )
584 /* Don't activate if it is already active. Might happen
585 since ShowWindow DOES activate MDI children */
586 if (clientInfo->hwndActiveChild == hWndChild)
592 TRACE("%04x\n", hWndChild);
594 if( GetActiveWindow() == clientPtr->parent->hwndSelf )
595 isActiveFrameWnd = TRUE;
597 /* deactivate prev. active child */
600 wndPrev->dwStyle |= WS_SYSMENU;
601 SendMessageA( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
602 SendMessageA( prevActiveWnd, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
604 /* uncheck menu item */
605 if( clientInfo->hWindowMenu )
606 CheckMenuItem( clientInfo->hWindowMenu,
607 wndPrev->wIDmenu, 0);
611 if( clientInfo->hwndChildMaximized )
613 if( clientInfo->hwndChildMaximized != hWndChild ) {
615 clientInfo->hwndActiveChild = hWndChild;
616 ShowWindow( hWndChild, SW_SHOWMAXIMIZED);
618 ShowWindow( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
622 clientInfo->hwndActiveChild = hWndChild;
624 /* check if we have any children left */
627 if( isActiveFrameWnd )
628 SetFocus( clientInfo->self );
633 /* check menu item */
634 if( clientInfo->hWindowMenu )
635 CheckMenuItem( clientInfo->hWindowMenu,
636 wndPtr->wIDmenu, MF_CHECKED);
638 /* bring active child to the top */
639 SetWindowPos( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
641 if( isActiveFrameWnd )
643 SendMessageA( hWndChild, WM_NCACTIVATE, TRUE, 0L);
644 if( GetFocus() == clientInfo->self )
645 SendMessageA( clientInfo->self, WM_SETFOCUS,
646 (WPARAM)clientInfo->self, 0L );
648 SetFocus( clientInfo->self );
650 SendMessageA( hWndChild, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
654 WIN_ReleaseWndPtr(wndPtr);
655 WIN_ReleaseWndPtr(wndPrev);
659 /* -------------------- MDI client window functions ------------------- */
661 /**********************************************************************
662 * CreateMDIMenuBitmap
664 static HBITMAP16 CreateMDIMenuBitmap(void)
666 HDC hDCSrc = CreateCompatibleDC(0);
667 HDC hDCDest = CreateCompatibleDC(hDCSrc);
668 HBITMAP16 hbClose = LoadBitmap16(0, MAKEINTRESOURCE16(OBM_CLOSE) );
670 HANDLE16 hobjSrc, hobjDest;
672 hobjSrc = SelectObject(hDCSrc, hbClose);
673 hbCopy = CreateCompatibleBitmap(hDCSrc,GetSystemMetrics(SM_CXSIZE),GetSystemMetrics(SM_CYSIZE));
674 hobjDest = SelectObject(hDCDest, hbCopy);
676 BitBlt(hDCDest, 0, 0, GetSystemMetrics(SM_CXSIZE), GetSystemMetrics(SM_CYSIZE),
677 hDCSrc, GetSystemMetrics(SM_CXSIZE), 0, SRCCOPY);
679 SelectObject(hDCSrc, hobjSrc);
680 DeleteObject(hbClose);
683 hobjSrc = SelectObject( hDCDest, GetStockObject(BLACK_PEN) );
685 MoveToEx( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, 0, NULL );
686 LineTo( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, GetSystemMetrics(SM_CYSIZE) - 1);
688 SelectObject(hDCDest, hobjSrc );
689 SelectObject(hDCDest, hobjDest);
695 /**********************************************************************
698 static LONG MDICascade(WND* clientWnd, MDICLIENTINFO *ci)
703 if (ci->hwndChildMaximized)
704 SendMessageA( clientWnd->hwndSelf, WM_MDIRESTORE,
705 (WPARAM)ci->hwndChildMaximized, 0);
707 if (ci->nActiveChildren == 0) return 0;
709 if ((ppWnd = WIN_BuildWinArray(clientWnd, BWA_SKIPHIDDEN | BWA_SKIPOWNED |
710 BWA_SKIPICONIC, &total)))
712 WND** heapPtr = ppWnd;
715 INT delta = 0, n = 0;
717 if( total < ci->nActiveChildren )
718 delta = GetSystemMetrics(SM_CYICONSPACING) +
719 GetSystemMetrics(SM_CYICON);
721 /* walk the list (backwards) and move windows */
722 while (*ppWnd) ppWnd++;
723 while (ppWnd != heapPtr)
726 TRACE("move %04x to (%ld,%ld) size [%ld,%ld]\n",
727 (*ppWnd)->hwndSelf, pos[0].x, pos[0].y, pos[1].x, pos[1].y);
729 MDI_CalcDefaultChildPos(clientWnd, n++, pos, delta);
730 SetWindowPos( (*ppWnd)->hwndSelf, 0, pos[0].x, pos[0].y,
732 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
735 WIN_ReleaseWinArray(heapPtr);
738 if( total < ci->nActiveChildren )
739 ArrangeIconicWindows( clientWnd->hwndSelf );
743 /**********************************************************************
746 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM wParam )
751 if (ci->hwndChildMaximized)
752 SendMessageA( wndClient->hwndSelf, WM_MDIRESTORE,
753 (WPARAM)ci->hwndChildMaximized, 0);
755 if (ci->nActiveChildren == 0) return;
757 ppWnd = WIN_BuildWinArray(wndClient, BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
758 ((wParam & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
760 TRACE("%u windows to tile\n", total);
764 WND** heapPtr = ppWnd;
769 int x, y, xsize, ysize;
770 int rows, columns, r, c, i;
772 GetClientRect(wndClient->hwndSelf,&rect);
773 rows = (int) sqrt((double)total);
774 columns = total / rows;
776 if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */
779 rows = columns; /* exchange r and c */
783 if( total != ci->nActiveChildren)
785 y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
786 rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
789 ysize = rect.bottom / rows;
790 xsize = rect.right / columns;
792 for (x = i = 0, c = 1; c <= columns && *ppWnd; c++)
797 ysize = rect.bottom / rows;
801 for (r = 1; r <= rows && *ppWnd; r++, i++)
803 SetWindowPos((*ppWnd)->hwndSelf, 0, x, y, xsize, ysize,
804 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
811 WIN_ReleaseWinArray(heapPtr);
814 if( total < ci->nActiveChildren ) ArrangeIconicWindows( wndClient->hwndSelf );
817 /* ----------------------- Frame window ---------------------------- */
820 /**********************************************************************
821 * MDI_AugmentFrameMenu
823 static BOOL MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
826 WND* child = WIN_FindWndPtr(hChild);
828 HBITMAP hSysMenuBitmap = 0;
830 TRACE("frame %p,child %04x\n",frame,hChild);
832 if( !frame->wIDmenu || !child->hSysMenu )
834 WIN_ReleaseWndPtr(child);
837 WIN_ReleaseWndPtr(child);
839 /* create a copy of sysmenu popup and insert it into frame menu bar */
841 if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
844 TRACE("\tgot popup %04x in sysmenu %04x\n",
845 hSysPopup, child->hSysMenu);
847 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
848 SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
849 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
850 SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
852 /* In Win 95 look, the system menu is replaced by the child icon */
854 if(TWEAK_WineLook > WIN31_LOOK)
856 HICON hIcon = GetClassLongA(hChild, GCL_HICONSM);
858 hIcon = GetClassLongA(hChild, GCL_HICON);
862 HBITMAP hBitmap, hOldBitmap;
864 HDC hdc = GetDC(hChild);
869 cx = GetSystemMetrics(SM_CXSMICON);
870 cy = GetSystemMetrics(SM_CYSMICON);
871 hMemDC = CreateCompatibleDC(hdc);
872 hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
873 hOldBitmap = SelectObject(hMemDC, hBitmap);
874 SetMapMode(hMemDC, MM_TEXT);
875 hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
876 DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL);
877 SelectObject (hMemDC, hOldBitmap);
878 DeleteObject(hBrush);
880 ReleaseDC(hChild, hdc);
881 hSysMenuBitmap = hBitmap;
886 hSysMenuBitmap = hBmpClose;
888 if( !InsertMenuA(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
889 hSysPopup, (LPSTR)(DWORD)hSysMenuBitmap))
891 TRACE("not inserted\n");
892 DestroyMenu(hSysPopup);
896 /* The close button is only present in Win 95 look */
897 if(TWEAK_WineLook > WIN31_LOOK)
899 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
900 SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
903 EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
904 EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
905 EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
906 SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE);
909 DrawMenuBar(frame->hwndSelf);
914 /**********************************************************************
915 * MDI_RestoreFrameMenu
917 static BOOL MDI_RestoreFrameMenu( WND *frameWnd, HWND hChild )
919 MENUITEMINFOA menuInfo;
920 INT nItems = GetMenuItemCount(frameWnd->wIDmenu) - 1;
921 UINT iId = GetMenuItemID(frameWnd->wIDmenu,nItems) ;
923 TRACE("frameWnd %p,(%04x),child %04x,nIt=%d,iId=%d\n",
924 frameWnd,frameWnd->hwndSelf,hChild,nItems,iId);
926 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
930 * Remove the system menu, If that menu is the icon of the window
931 * as it is in win95, we have to delete the bitmap.
933 menuInfo.cbSize = sizeof(MENUITEMINFOA);
934 menuInfo.fMask = MIIM_DATA | MIIM_TYPE;
936 GetMenuItemInfoA(frameWnd->wIDmenu,
941 RemoveMenu(frameWnd->wIDmenu,0,MF_BYPOSITION);
943 if ( (menuInfo.fType & MFT_BITMAP) &&
944 (LOWORD(menuInfo.dwTypeData)!=0) &&
945 (LOWORD(menuInfo.dwTypeData)!=hBmpClose) )
947 DeleteObject((HBITMAP)LOWORD(menuInfo.dwTypeData));
950 if(TWEAK_WineLook > WIN31_LOOK)
953 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
956 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
958 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
960 DrawMenuBar(frameWnd->hwndSelf);
966 /**********************************************************************
967 * MDI_UpdateFrameText
969 * used when child window is maximized/restored
971 * Note: lpTitle can be NULL
973 static void MDI_UpdateFrameText( WND *frameWnd, HWND hClient,
974 BOOL repaint, LPCSTR lpTitle )
976 char lpBuffer[MDI_MAXTITLELENGTH+1];
977 WND* clientWnd = WIN_FindWndPtr(hClient);
978 MDICLIENTINFO *ci = (MDICLIENTINFO *) clientWnd->wExtra;
980 TRACE("repaint %i, frameText %s\n", repaint, (lpTitle)?lpTitle:"NULL");
987 WIN_ReleaseWndPtr(clientWnd);
991 /* store new "default" title if lpTitle is not NULL */
994 if (ci->frameTitle) HeapFree( SystemHeap, 0, ci->frameTitle );
995 ci->frameTitle = HEAP_strdupA( SystemHeap, 0, lpTitle );
1000 WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );
1002 if( childWnd && childWnd->text )
1004 /* combine frame title and child title if possible */
1006 LPCSTR lpBracket = " - [";
1007 int i_frame_text_length = strlen(ci->frameTitle);
1008 int i_child_text_length = strlen(childWnd->text);
1010 lstrcpynA( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
1012 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
1014 strcat( lpBuffer, lpBracket );
1016 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
1018 strcat( lpBuffer, childWnd->text );
1019 strcat( lpBuffer, "]" );
1023 lstrcpynA( lpBuffer + i_frame_text_length + 4,
1024 childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
1025 strcat( lpBuffer, "]" );
1031 lstrcpynA(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH+1 );
1033 WIN_ReleaseWndPtr(childWnd);
1039 DEFWND_SetText( frameWnd, lpBuffer );
1040 if( repaint == MDI_REPAINTFRAME)
1041 SetWindowPos( frameWnd->hwndSelf, 0,0,0,0,0, SWP_FRAMECHANGED |
1042 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
1044 WIN_ReleaseWndPtr(clientWnd);
1049 /* ----------------------------- Interface ---------------------------- */
1052 /**********************************************************************
1055 * This function handles all MDI requests.
1057 LRESULT WINAPI MDIClientWndProc( HWND hwnd, UINT message, WPARAM wParam,
1067 if ( ( w = WIN_FindWndPtr(hwnd) ) == NULL )
1070 if ( ( frameWnd = WIN_LockWndPtr(w->parent) ) == NULL ) {
1071 WIN_ReleaseWndPtr(w);
1075 ci = (MDICLIENTINFO *) w->wExtra;
1081 cs = (LPCREATESTRUCTA)lParam;
1083 /* Translation layer doesn't know what's in the cs->lpCreateParams
1084 * so we have to keep track of what environment we're in. */
1086 if( w->flags & WIN_ISWIN32 )
1088 #define ccs ((LPCLIENTCREATESTRUCT)cs->lpCreateParams)
1089 ci->hWindowMenu = ccs->hWindowMenu;
1090 ci->idFirstChild = ccs->idFirstChild;
1095 LPCLIENTCREATESTRUCT16 ccs = (LPCLIENTCREATESTRUCT16)
1096 PTR_SEG_TO_LIN(cs->lpCreateParams);
1097 ci->hWindowMenu = ccs->hWindowMenu;
1098 ci->idFirstChild = ccs->idFirstChild;
1101 ci->hwndChildMaximized = 0;
1102 ci->nActiveChildren = 0;
1103 ci->nTotalCreated = 0;
1104 ci->frameTitle = NULL;
1107 w->dwStyle |= WS_CLIPCHILDREN;
1111 hBmpClose = CreateMDIMenuBitmap();
1112 hBmpRestore = LoadBitmap16( 0, MAKEINTRESOURCE16(OBM_RESTORE) );
1114 MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
1116 AppendMenuA( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
1118 GetClientRect(frameWnd->hwndSelf, &rect);
1119 NC_HandleNCCalcSize( w, &rect );
1120 w->rectClient = rect;
1122 TRACE("Client created - hwnd = %04x, idFirst = %u\n",
1123 hwnd, ci->idFirstChild );
1129 if( ci->hwndChildMaximized )
1130 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized);
1131 if((nItems = GetMenuItemCount(ci->hWindowMenu)) > 0)
1133 ci->idFirstChild = nItems - 1;
1134 ci->nActiveChildren++; /* to delete a separator */
1135 while( ci->nActiveChildren-- )
1136 DeleteMenu(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
1141 case WM_MDIACTIVATE:
1142 if( ci->hwndActiveChild != (HWND)wParam )
1143 SetWindowPos((HWND)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
1148 retvalue = MDICascade(w, ci);
1152 if (lParam) retvalue = MDICreateChild( w, ci, hwnd,
1153 (MDICREATESTRUCTA*)lParam );
1158 retvalue = MDIDestroyChild( w, ci, hwnd, (HWND)wParam, TRUE );
1161 case WM_MDIGETACTIVE:
1162 if (lParam) *(BOOL *)lParam = (ci->hwndChildMaximized > 0);
1163 retvalue = ci->hwndActiveChild;
1166 case WM_MDIICONARRANGE:
1167 ci->mdiFlags |= MDIF_NEEDUPDATE;
1168 ArrangeIconicWindows(hwnd);
1169 ci->sbRecalc = SB_BOTH+1;
1170 SendMessageA(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
1174 case WM_MDIMAXIMIZE:
1175 ShowWindow( (HWND)wParam, SW_MAXIMIZE );
1179 case WM_MDINEXT: /* lParam != 0 means previous window */
1180 MDI_SwitchActiveChild(hwnd, (HWND)wParam, (lParam)? FALSE : TRUE );
1184 SendMessageA( (HWND)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
1189 retvalue = MDISetMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1191 case WM_MDIREFRESHMENU:
1192 retvalue = MDIRefreshMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1196 ci->mdiFlags |= MDIF_NEEDUPDATE;
1197 ShowScrollBar(hwnd,SB_BOTH,FALSE);
1198 MDITile(w, ci, wParam);
1199 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1205 ci->mdiFlags |= MDIF_NEEDUPDATE;
1206 ScrollChildren(hwnd, message, wParam, lParam);
1207 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1212 if( ci->hwndActiveChild )
1214 WND* pw = WIN_FindWndPtr( ci->hwndActiveChild );
1215 if( !(pw->dwStyle & WS_MINIMIZE) )
1216 SetFocus( ci->hwndActiveChild );
1217 WIN_ReleaseWndPtr(pw);
1223 if( ci->hwndActiveChild )
1224 SendMessageA(ci->hwndActiveChild, message, wParam, lParam);
1227 case WM_PARENTNOTIFY:
1228 if (LOWORD(wParam) == WM_LBUTTONDOWN)
1230 POINT16 pt = MAKEPOINT16(lParam);
1231 HWND16 child = ChildWindowFromPoint16(hwnd, pt);
1233 TRACE("notification from %04x (%i,%i)\n",child,pt.x,pt.y);
1235 if( child && child != hwnd && child != ci->hwndActiveChild )
1236 SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1242 if( IsWindow(ci->hwndChildMaximized) )
1244 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1249 rect.right = LOWORD(lParam);
1250 rect.bottom = HIWORD(lParam);
1252 AdjustWindowRectEx(&rect, child->dwStyle, 0, child->dwExStyle);
1253 MoveWindow(ci->hwndChildMaximized, rect.left, rect.top,
1254 rect.right - rect.left, rect.bottom - rect.top, 1);
1255 WIN_ReleaseWndPtr(child);
1258 MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1262 case WM_MDICALCCHILDSCROLL:
1263 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1265 CalcChildScroll16(hwnd, ci->sbRecalc-1);
1267 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1273 retvalue = DefWindowProcA( hwnd, message, wParam, lParam );
1275 WIN_ReleaseWndPtr(w);
1276 WIN_ReleaseWndPtr(frameWnd);
1281 /***********************************************************************
1282 * DefFrameProc16 (USER.445)
1284 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1285 UINT16 message, WPARAM16 wParam, LPARAM lParam )
1296 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1299 ERR("null wndPtr for mdi window hwndMDIClient=%04x\n",
1304 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1306 /* check for possible syscommands for maximized MDI child */
1307 WIN_ReleaseWndPtr(wndPtr);
1310 wParam < ci->idFirstChild ||
1311 wParam >= ci->idFirstChild + ci->nActiveChildren
1313 if( (wParam - 0xF000) & 0xF00F ) break;
1324 if( ci->hwndChildMaximized )
1325 return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1331 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1332 childHwnd = MDI_GetChildByID(wndPtr,wParam );
1333 WIN_ReleaseWndPtr(wndPtr);
1336 SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1337 (WPARAM16)childHwnd , 0L);
1342 SendMessage16(hwndMDIClient, message, wParam, lParam);
1346 wndPtr = WIN_FindWndPtr(hwnd);
1347 MDI_UpdateFrameText(wndPtr, hwndMDIClient,
1349 (LPCSTR)PTR_SEG_TO_LIN(lParam));
1350 WIN_ReleaseWndPtr(wndPtr);
1354 SetFocus(hwndMDIClient);
1358 MoveWindow16(hwndMDIClient, 0, 0,
1359 LOWORD(lParam), HIWORD(lParam), TRUE);
1364 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1365 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1367 if( !(wndPtr->parent->dwStyle & WS_MINIMIZE)
1368 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1370 /* control menu is between the frame system menu and
1371 * the first entry of menu bar */
1373 if( (wParam == VK_LEFT &&
1374 wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1375 (wParam == VK_RIGHT &&
1376 GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1379 WIN_ReleaseWndPtr(wndPtr);
1380 wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1381 retvalue = MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1382 ci->hwndActiveChild);
1383 WIN_ReleaseWndPtr(wndPtr);
1387 WIN_ReleaseWndPtr(wndPtr);
1392 return DefWindowProc16(hwnd, message, wParam, lParam);
1396 /***********************************************************************
1397 * DefFrameProc32A (USER32.122)
1399 LRESULT WINAPI DefFrameProcA( HWND hwnd, HWND hwndMDIClient,
1400 UINT message, WPARAM wParam, LPARAM lParam)
1407 return DefFrameProc16( hwnd, hwndMDIClient, message,
1409 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1412 SendMessageA(hwndMDIClient, message, wParam, lParam);
1417 LPSTR segstr = SEGPTR_STRDUP((LPSTR)lParam);
1419 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1420 wParam, (LPARAM)SEGPTR_GET(segstr) );
1421 SEGPTR_FREE(segstr);
1428 return DefFrameProc16( hwnd, hwndMDIClient, message,
1433 return DefWindowProcA(hwnd, message, wParam, lParam);
1437 /***********************************************************************
1438 * DefFrameProc32W (USER32.123)
1440 LRESULT WINAPI DefFrameProcW( HWND hwnd, HWND hwndMDIClient,
1441 UINT message, WPARAM wParam, LPARAM lParam)
1448 return DefFrameProc16( hwnd, hwndMDIClient, message,
1450 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1453 SendMessageW(hwndMDIClient, message, wParam, lParam);
1458 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1459 LRESULT ret = DefFrameProcA( hwnd, hwndMDIClient, message,
1460 wParam, (DWORD)txt );
1461 HeapFree(GetProcessHeap(),0,txt);
1467 return DefFrameProcA( hwnd, hwndMDIClient, message,
1472 return DefWindowProcW( hwnd, message, wParam, lParam );
1476 /***********************************************************************
1477 * DefMDIChildProc16 (USER.447)
1479 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1480 WPARAM16 wParam, LPARAM lParam )
1483 WND *clientWnd,*tmpWnd = 0;
1486 tmpWnd = WIN_FindWndPtr(hwnd);
1487 if (!tmpWnd) return 0;
1488 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1489 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1490 WIN_ReleaseWndPtr(tmpWnd);
1495 DefWindowProc16(hwnd, message, wParam, lParam);
1496 MDI_MenuModifyItem(clientWnd,hwnd);
1497 if( ci->hwndChildMaximized == hwnd )
1498 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1499 MDI_REPAINTFRAME, NULL );
1504 SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1509 if( ci->hwndActiveChild != hwnd )
1510 MDI_ChildActivate(clientWnd, hwnd);
1513 case WM_CHILDACTIVATE:
1514 MDI_ChildActivate(clientWnd, hwnd);
1519 TRACE("WM_NCPAINT for %04x, active %04x\n",
1520 hwnd, ci->hwndActiveChild );
1527 if( ci->hwndChildMaximized == hwnd)
1535 tmpWnd = WIN_FindWndPtr(hwnd);
1536 tmpWnd->dwStyle |= WS_SYSMENU;
1537 WIN_ReleaseWndPtr(tmpWnd);
1540 if( ci->hwndChildMaximized == hwnd)
1542 retvalue = SendMessage16( clientWnd->parent->hwndSelf,
1543 message, wParam, lParam);
1546 tmpWnd = WIN_FindWndPtr(hwnd);
1547 tmpWnd->dwStyle &= ~WS_SYSMENU;
1548 WIN_ReleaseWndPtr(tmpWnd);
1551 SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1555 SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1561 case WM_GETMINMAXINFO:
1562 MDI_ChildGetMinMaxInfo(clientWnd, hwnd, (MINMAXINFO16*) PTR_SEG_TO_LIN(lParam));
1567 if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1569 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1575 if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1577 ci->hwndChildMaximized = 0;
1579 MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1580 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1581 MDI_REPAINTFRAME, NULL );
1584 if( wParam == SIZE_MAXIMIZED )
1586 HWND16 hMaxChild = ci->hwndChildMaximized;
1588 if( hMaxChild == hwnd ) break;
1592 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1594 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1595 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1597 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1600 TRACE("maximizing child %04x\n", hwnd );
1602 ci->hwndChildMaximized = hwnd; /* !!! */
1603 ci->hwndActiveChild = hwnd;
1605 MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1606 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1607 MDI_REPAINTFRAME, NULL );
1610 if( wParam == SIZE_MINIMIZED )
1612 HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1615 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1618 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1623 /* MDI children don't have menu bars */
1624 retvalue = 0x00010000L;
1629 if( wParam == VK_LEFT ) /* switch to frame system menu */
1631 retvalue = MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1632 clientWnd->parent->hwndSelf );
1635 if( wParam == VK_RIGHT ) /* to frame menu bar */
1637 retvalue = MAKELONG( clientWnd->parent->wIDmenu,
1638 clientWnd->parent->hwndSelf );
1647 SendMessage16(hwnd,WM_SYSCOMMAND,
1648 (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1654 retvalue = DefWindowProc16(hwnd, message, wParam, lParam);
1656 WIN_ReleaseWndPtr(clientWnd);
1661 /***********************************************************************
1662 * DefMDIChildProc32A (USER32.124)
1664 LRESULT WINAPI DefMDIChildProcA( HWND hwnd, UINT message,
1665 WPARAM wParam, LPARAM lParam )
1668 WND *clientWnd,*tmpWnd;
1671 tmpWnd = WIN_FindWndPtr(hwnd);
1672 if (!tmpWnd) return 0;
1673 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1674 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1675 WIN_ReleaseWndPtr(tmpWnd);
1680 DefWindowProcA(hwnd, message, wParam, lParam);
1681 MDI_MenuModifyItem(clientWnd,hwnd);
1682 if( ci->hwndChildMaximized == hwnd )
1683 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1684 MDI_REPAINTFRAME, NULL );
1688 case WM_GETMINMAXINFO:
1691 STRUCT32_MINMAXINFO32to16( (MINMAXINFO *)lParam, &mmi );
1692 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1693 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO *)lParam );
1700 /* MDI children don't have menu bars */
1701 retvalue = 0x00010000L;
1706 case WM_CHILDACTIVATE:
1712 retvalue = DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1718 SendMessageA(hwnd,WM_SYSCOMMAND,
1719 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1724 retvalue = DefWindowProcA(hwnd, message, wParam, lParam);
1726 WIN_ReleaseWndPtr(clientWnd);
1731 /***********************************************************************
1732 * DefMDIChildProc32W (USER32.125)
1734 LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message,
1735 WPARAM wParam, LPARAM lParam )
1738 WND *clientWnd,*tmpWnd;
1741 tmpWnd = WIN_FindWndPtr(hwnd);
1742 if (!tmpWnd) return 0;
1743 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1744 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1745 WIN_ReleaseWndPtr(tmpWnd);
1750 DefWindowProcW(hwnd, message, wParam, lParam);
1751 MDI_MenuModifyItem(clientWnd,hwnd);
1752 if( ci->hwndChildMaximized == hwnd )
1753 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1754 MDI_REPAINTFRAME, NULL );
1758 case WM_GETMINMAXINFO:
1762 case WM_CHILDACTIVATE:
1768 retvalue = DefMDIChildProcA( hwnd, message, (WPARAM16)wParam, lParam );
1774 SendMessageW(hwnd,WM_SYSCOMMAND,
1775 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1780 retvalue = DefWindowProcW(hwnd, message, wParam, lParam);
1782 WIN_ReleaseWndPtr(clientWnd);
1788 /**********************************************************************
1789 * CreateMDIWindowA [USER32.79] Creates a MDI child in new thread
1790 * FIXME: its in the same thread now
1793 * Success: Handle to created window
1796 HWND WINAPI CreateMDIWindowA(
1797 LPCSTR lpClassName, /* [in] Pointer to registered child class name */
1798 LPCSTR lpWindowName, /* [in] Pointer to window name */
1799 DWORD dwStyle, /* [in] Window style */
1800 INT X, /* [in] Horizontal position of window */
1801 INT Y, /* [in] Vertical position of window */
1802 INT nWidth, /* [in] Width of window */
1803 INT nHeight, /* [in] Height of window */
1804 HWND hWndParent, /* [in] Handle to parent window */
1805 HINSTANCE hInstance, /* [in] Handle to application instance */
1806 LPARAM lParam) /* [in] Application-defined value */
1808 WARN("is only single threaded!\n");
1809 return MDI_CreateMDIWindowA(lpClassName, lpWindowName, dwStyle, X, Y,
1810 nWidth, nHeight, hWndParent, hInstance, lParam);
1813 /**********************************************************************
1814 * MDI_CreateMDIWindowA
1815 * single threaded version of CreateMDIWindowA
1816 * called by CreateWindowEx32A
1818 HWND MDI_CreateMDIWindowA(
1820 LPCSTR lpWindowName,
1827 HINSTANCE hInstance,
1831 MDICREATESTRUCTA cs;
1832 WND *pWnd=WIN_FindWndPtr(hWndParent);
1835 TRACE("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
1836 debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
1837 nWidth,nHeight,hWndParent,hInstance,lParam);
1840 ERR(" bad hwnd for MDI-client: %d\n",hWndParent);
1843 cs.szClass=lpClassName;
1844 cs.szTitle=lpWindowName;
1845 cs.hOwner=hInstance;
1853 pCi=(MDICLIENTINFO *)pWnd->wExtra;
1855 retvalue = MDICreateChild(pWnd,pCi,hWndParent,&cs);
1856 WIN_ReleaseWndPtr(pWnd);
1860 /***************************************
1861 * CreateMDIWindow32W [USER32.80] Creates a MDI child in new thread
1864 * Success: Handle to created window
1867 HWND WINAPI CreateMDIWindowW(
1868 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1869 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1870 DWORD dwStyle, /* [in] Window style */
1871 INT X, /* [in] Horizontal position of window */
1872 INT Y, /* [in] Vertical position of window */
1873 INT nWidth, /* [in] Width of window */
1874 INT nHeight, /* [in] Height of window */
1875 HWND hWndParent, /* [in] Handle to parent window */
1876 HINSTANCE hInstance, /* [in] Handle to application instance */
1877 LPARAM lParam) /* [in] Application-defined value */
1879 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1880 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1881 nWidth,nHeight,hWndParent,hInstance,lParam);
1886 /******************************************************************************
1887 * CreateMDIWindow32W [USER32.80] Creates a MDI child window
1888 * single threaded version of CreateMDIWindow
1889 * called by CreateWindowEx32W().
1891 HWND MDI_CreateMDIWindowW(
1892 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1893 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1894 DWORD dwStyle, /* [in] Window style */
1895 INT X, /* [in] Horizontal position of window */
1896 INT Y, /* [in] Vertical position of window */
1897 INT nWidth, /* [in] Width of window */
1898 INT nHeight, /* [in] Height of window */
1899 HWND hWndParent, /* [in] Handle to parent window */
1900 HINSTANCE hInstance, /* [in] Handle to application instance */
1901 LPARAM lParam) /* [in] Application-defined value */
1903 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1904 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1905 nWidth,nHeight,hWndParent,hInstance,lParam);
1910 /**********************************************************************
1911 * TranslateMDISysAccel32 (USER32.555)
1913 BOOL WINAPI TranslateMDISysAccel( HWND hwndClient, LPMSG msg )
1917 STRUCT32_MSG32to16(msg,&msg16);
1918 /* MDICLIENTINFO is still the same for win32 and win16 ... */
1919 return TranslateMDISysAccel16(hwndClient,&msg16);
1923 /**********************************************************************
1924 * TranslateMDISysAccel16 (USER.451)
1926 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
1929 if( IsWindow(hwndClient) && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
1931 MDICLIENTINFO *ci = NULL;
1933 WND *clientWnd = WIN_FindWndPtr(hwndClient);
1935 ci = (MDICLIENTINFO*) clientWnd->wExtra;
1936 wnd = ci->hwndActiveChild;
1938 WIN_ReleaseWndPtr(clientWnd);
1940 if( IsWindow(wnd) && !(GetWindowLongA(wnd,GWL_STYLE) & WS_DISABLED) )
1942 WPARAM16 wParam = 0;
1944 /* translate if the Ctrl key is down and Alt not. */
1946 if( (GetKeyState(VK_CONTROL) & 0x8000) &&
1947 !(GetKeyState(VK_MENU) & 0x8000))
1949 switch( msg->wParam )
1953 wParam = ( GetKeyState(VK_SHIFT) & 0x8000 )
1954 ? SC_NEXTWINDOW : SC_PREVWINDOW;
1963 TRACE("wParam = %04x\n", wParam);
1964 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
1965 wParam, (LPARAM)msg->wParam);
1970 return 0; /* failure */
1974 /***********************************************************************
1975 * CalcChildScroll (USER.462)
1977 void WINAPI CalcChildScroll16( HWND16 hwnd, WORD scroll )
1980 RECT childRect, clientRect;
1981 INT vmin, vmax, hmin, hmax, vpos, hpos;
1984 if (!(pWnd = WIN_FindWndPtr( hwnd ))) return;
1985 Wnd = WIN_FindWndPtr(hwnd);
1986 GetClientRect( hwnd, &clientRect );
1987 SetRectEmpty( &childRect );
1989 for ( WIN_UpdateWndPtr(&pWnd,pWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
1991 if( pWnd->dwStyle & WS_MAXIMIZE )
1993 ShowScrollBar(hwnd, SB_BOTH, FALSE);
1994 WIN_ReleaseWndPtr(pWnd);
1995 WIN_ReleaseWndPtr(Wnd);
1998 UnionRect( &childRect, &pWnd->rectWindow, &childRect );
2000 WIN_ReleaseWndPtr(pWnd);
2001 UnionRect( &childRect, &clientRect, &childRect );
2003 hmin = childRect.left; hmax = childRect.right - clientRect.right;
2004 hpos = clientRect.left - childRect.left;
2005 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
2006 vpos = clientRect.top - childRect.top;
2011 vpos = hpos; vmin = hmin; vmax = hmax;
2013 info.cbSize = sizeof(info);
2014 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
2015 info.fMask = SIF_POS | SIF_RANGE;
2016 SetScrollInfo(hwnd, scroll, &info, TRUE);
2019 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
2022 WIN_ReleaseWndPtr(Wnd);
2026 /***********************************************************************
2027 * ScrollChildren16 (USER.463)
2029 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
2031 ScrollChildren( hWnd, uMsg, wParam, lParam );
2035 /***********************************************************************
2036 * ScrollChildren32 (USER32.448)
2038 void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
2041 WND *wndPtr = WIN_FindWndPtr(hWnd);
2043 INT curPos, length, minPos, maxPos, shift;
2045 if( !wndPtr ) return;
2047 if( uMsg == WM_HSCROLL )
2049 GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
2050 curPos = GetScrollPos(hWnd,SB_HORZ);
2051 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
2052 shift = GetSystemMetrics(SM_CYHSCROLL);
2054 else if( uMsg == WM_VSCROLL )
2056 GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
2057 curPos = GetScrollPos(hWnd,SB_VERT);
2058 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
2059 shift = GetSystemMetrics(SM_CXVSCROLL);
2063 WIN_ReleaseWndPtr(wndPtr);
2067 WIN_ReleaseWndPtr(wndPtr);
2071 newPos = curPos - shift;
2074 newPos = curPos + shift;
2077 newPos = curPos - length;
2080 newPos = curPos + length;
2083 case SB_THUMBPOSITION:
2084 newPos = LOWORD(lParam);
2097 CalcChildScroll16(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
2101 if( newPos > maxPos )
2104 if( newPos < minPos )
2107 SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
2109 if( uMsg == WM_VSCROLL )
2110 ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
2111 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2113 ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
2114 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2118 /******************************************************************************
2119 * CascadeWindows [USER32.21] Cascades MDI child windows
2122 * Success: Number of cascaded windows.
2126 CascadeWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2127 UINT cKids, const HWND *lpKids)
2129 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2130 hwndParent, wFlags, cKids);
2136 /******************************************************************************
2137 * TileWindows [USER32.545] Tiles MDI child windows
2140 * Success: Number of tiled windows.
2144 TileWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2145 UINT cKids, const HWND *lpKids)
2147 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2148 hwndParent, wFlags, cKids);