Implementation of the new monitor abstraction.
[wine.git] / windows / mdi.c
blobbe889b8bd567ef8b8f431f083f07ac21262ddad7
1 /* MDI.C
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.
15 #include <stdlib.h>
16 #include <string.h>
17 #include <math.h>
18 #include "windows.h"
19 #include "win.h"
20 #include "heap.h"
21 #include "nonclient.h"
22 #include "mdi.h"
23 #include "user.h"
24 #include "menu.h"
25 #include "resource.h"
26 #include "struct32.h"
27 #include "sysmetrics.h"
28 #include "debug.h"
30 #define MDIF_NEEDUPDATE 0x0001
32 static HBITMAP16 hBmpClose = 0;
33 static HBITMAP16 hBmpRestore = 0;
35 INT32 SCROLL_SetNCSbState(WND*,int,int,int,int,int,int);
37 /* ----------------- declarations ----------------- */
38 static void MDI_UpdateFrameText(WND *, HWND32, BOOL32, LPCSTR);
39 static BOOL32 MDI_AugmentFrameMenu(MDICLIENTINFO*, WND *, HWND32);
40 static BOOL32 MDI_RestoreFrameMenu(WND *, HWND32);
42 static LONG MDI_ChildActivate( WND*, HWND32 );
44 /* -------- Miscellaneous service functions ----------
46 * MDI_GetChildByID
49 static HWND32 MDI_GetChildByID(WND* wndPtr, INT32 id)
51 for (wndPtr = wndPtr->child; wndPtr; wndPtr = wndPtr->next)
52 if (wndPtr->wIDmenu == id) return wndPtr->hwndSelf;
53 return 0;
56 static void MDI_PostUpdate(HWND32 hwnd, MDICLIENTINFO* ci, WORD recalc)
58 if( !(ci->mdiFlags & MDIF_NEEDUPDATE) )
60 ci->mdiFlags |= MDIF_NEEDUPDATE;
61 PostMessage32A( hwnd, WM_MDICALCCHILDSCROLL, 0, 0);
63 ci->sbRecalc = recalc;
66 /**********************************************************************
67 * MDI_MenuModifyItem
69 static BOOL32 MDI_MenuModifyItem(WND* clientWnd, HWND32 hWndChild )
71 char buffer[128];
72 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
73 WND *wndPtr = WIN_FindWndPtr(hWndChild);
74 UINT32 n = sprintf(buffer, "%d ",
75 wndPtr->wIDmenu - clientInfo->idFirstChild + 1);
76 BOOL32 bRet = 0;
78 if( !clientInfo->hWindowMenu ) return 0;
80 if (wndPtr->text) lstrcpyn32A(buffer + n, wndPtr->text, sizeof(buffer) - n );
82 n = GetMenuState32(clientInfo->hWindowMenu,wndPtr->wIDmenu ,MF_BYCOMMAND);
83 bRet = ModifyMenu32A(clientInfo->hWindowMenu , wndPtr->wIDmenu,
84 MF_BYCOMMAND | MF_STRING, wndPtr->wIDmenu, buffer );
85 CheckMenuItem32(clientInfo->hWindowMenu ,wndPtr->wIDmenu , n & MF_CHECKED);
86 return bRet;
89 /**********************************************************************
90 * MDI_MenuDeleteItem
92 static BOOL32 MDI_MenuDeleteItem(WND* clientWnd, HWND32 hWndChild )
94 char buffer[128];
95 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
96 WND *wndPtr = WIN_FindWndPtr(hWndChild);
97 UINT32 index = 0,id,n;
99 if( !clientInfo->nActiveChildren ||
100 !clientInfo->hWindowMenu ) return 0;
102 id = wndPtr->wIDmenu;
103 DeleteMenu32(clientInfo->hWindowMenu,id,MF_BYCOMMAND);
105 /* walk the rest of MDI children to prevent gaps in the id
106 * sequence and in the menu child list */
108 for( index = id+1; index <= clientInfo->nActiveChildren +
109 clientInfo->idFirstChild; index++ )
111 wndPtr = WIN_FindWndPtr(MDI_GetChildByID(clientWnd,index));
112 if( !wndPtr )
114 TRACE(mdi,"no window for id=%i\n",index);
115 continue;
118 /* set correct id */
119 wndPtr->wIDmenu--;
121 n = sprintf(buffer, "%d ",index - clientInfo->idFirstChild);
122 if (wndPtr->text)
123 lstrcpyn32A(buffer + n, wndPtr->text, sizeof(buffer) - n );
125 /* change menu */
126 ModifyMenu32A(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING,
127 index - 1 , buffer );
129 return 1;
132 /**********************************************************************
133 * MDI_GetWindow
135 * returns "activateable" child different from the current or zero
137 static HWND32 MDI_GetWindow(WND *clientWnd, HWND32 hWnd, BOOL32 bNext,
138 DWORD dwStyleMask )
140 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
141 WND *wndPtr, *pWnd, *pWndLast = NULL;
143 dwStyleMask |= WS_DISABLED | WS_VISIBLE;
144 if( !hWnd ) hWnd = clientInfo->hwndActiveChild;
146 if( !(wndPtr = WIN_FindWndPtr(hWnd)) ) return 0;
148 for ( pWnd = wndPtr->next; ; pWnd = pWnd->next )
150 if (!pWnd ) pWnd = wndPtr->parent->child;
152 if ( pWnd == wndPtr ) break; /* went full circle */
154 if (!pWnd->owner && (pWnd->dwStyle & dwStyleMask) == WS_VISIBLE )
156 pWndLast = pWnd;
157 if ( bNext ) break;
160 return pWndLast ? pWndLast->hwndSelf : 0;
163 /**********************************************************************
164 * MDI_CalcDefaultChildPos
166 * It seems that the default height is about 2/3 of the client rect
168 static void MDI_CalcDefaultChildPos( WND* w, WORD n, LPPOINT32 lpPos,
169 INT32 delta)
171 INT32 nstagger;
172 RECT32 rect = w->rectClient;
173 INT32 spacing = GetSystemMetrics32(SM_CYCAPTION) +
174 GetSystemMetrics32(SM_CYFRAME) - 1;
176 if( rect.bottom - rect.top - delta >= spacing )
177 rect.bottom -= delta;
179 nstagger = (rect.bottom - rect.top)/(3 * spacing);
180 lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
181 lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
182 lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
185 /**********************************************************************
186 * MDISetMenu
188 static LRESULT MDISetMenu( HWND32 hwnd, HMENU32 hmenuFrame,
189 HMENU32 hmenuWindow)
191 WND *w = WIN_FindWndPtr(hwnd);
192 MDICLIENTINFO *ci;
193 HWND32 hwndFrame = GetParent32(hwnd);
194 HMENU32 oldFrameMenu = GetMenu32(hwndFrame);
196 TRACE(mdi, "%04x %04x %04x\n",
197 hwnd, hmenuFrame, hmenuWindow);
199 ci = (MDICLIENTINFO *) w->wExtra;
201 if( ci->hwndChildMaximized && hmenuFrame && hmenuFrame!=oldFrameMenu )
202 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized );
204 if( hmenuWindow && hmenuWindow!=ci->hWindowMenu )
206 /* delete menu items from ci->hWindowMenu
207 * and add them to hmenuWindow */
209 INT32 i = GetMenuItemCount32(ci->hWindowMenu) - 1;
210 INT32 pos = GetMenuItemCount32(hmenuWindow) + 1;
212 AppendMenu32A( hmenuWindow, MF_SEPARATOR, 0, NULL);
214 if( ci->nActiveChildren )
216 INT32 j = i - ci->nActiveChildren + 1;
217 char buffer[100];
218 UINT32 id,state;
220 for( ; i >= j ; i-- )
222 id = GetMenuItemID32(ci->hWindowMenu,i );
223 state = GetMenuState32(ci->hWindowMenu,i,MF_BYPOSITION);
225 GetMenuString32A(ci->hWindowMenu, i, buffer, 100, MF_BYPOSITION);
227 DeleteMenu32(ci->hWindowMenu, i , MF_BYPOSITION);
228 InsertMenu32A(hmenuWindow, pos, MF_BYPOSITION | MF_STRING,
229 id, buffer);
230 CheckMenuItem32(hmenuWindow ,pos , MF_BYPOSITION | (state & MF_CHECKED));
234 /* remove separator */
235 DeleteMenu32(ci->hWindowMenu, i, MF_BYPOSITION);
237 ci->hWindowMenu = hmenuWindow;
240 if( hmenuFrame && hmenuFrame!=oldFrameMenu)
242 SetMenu32(hwndFrame, hmenuFrame);
243 if( ci->hwndChildMaximized )
244 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
245 return oldFrameMenu;
247 return 0;
250 /**********************************************************************
251 * MDIRefreshMenu
253 static LRESULT MDIRefreshMenu( HWND32 hwnd, HMENU32 hmenuFrame,
254 HMENU32 hmenuWindow)
256 HWND32 hwndFrame = GetParent32(hwnd);
257 HMENU32 oldFrameMenu = GetMenu32(hwndFrame);
259 TRACE(mdi, "%04x %04x %04x\n",
260 hwnd, hmenuFrame, hmenuWindow);
262 FIXME(mdi,"partially function stub\n");
264 return oldFrameMenu;
268 /* ------------------ MDI child window functions ---------------------- */
271 /**********************************************************************
272 * MDICreateChild
274 static HWND32 MDICreateChild( WND *w, MDICLIENTINFO *ci, HWND32 parent,
275 LPMDICREATESTRUCT32A cs )
277 POINT32 pos[2];
278 DWORD style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
279 HWND32 hwnd, hwndMax = 0;
280 WORD wIDmenu = ci->idFirstChild + ci->nActiveChildren;
281 char lpstrDef[]="junk!";
283 TRACE(mdi, "origin %i,%i - dim %i,%i, style %08x\n",
284 cs->x, cs->y, cs->cx, cs->cy, (unsigned)cs->style);
285 /* calculate placement */
286 MDI_CalcDefaultChildPos(w, ci->nTotalCreated++, pos, 0);
288 if (cs->cx == CW_USEDEFAULT32 || !cs->cx) cs->cx = pos[1].x;
289 if (cs->cy == CW_USEDEFAULT32 || !cs->cy) cs->cy = pos[1].y;
291 if( cs->x == CW_USEDEFAULT32 )
293 cs->x = pos[0].x;
294 cs->y = pos[0].y;
297 /* restore current maximized child */
298 if( style & WS_VISIBLE && ci->hwndChildMaximized )
300 if( style & WS_MAXIMIZE )
301 SendMessage32A(w->hwndSelf, WM_SETREDRAW, FALSE, 0L );
302 hwndMax = ci->hwndChildMaximized;
303 ShowWindow32( hwndMax, SW_SHOWNOACTIVATE );
304 if( style & WS_MAXIMIZE )
305 SendMessage32A(w->hwndSelf, WM_SETREDRAW, TRUE, 0L );
308 /* this menu is needed to set a check mark in MDI_ChildActivate */
309 AppendMenu32A(ci->hWindowMenu ,MF_STRING ,wIDmenu, lpstrDef );
311 ci->nActiveChildren++;
313 /* fix window style */
314 if( !(w->dwStyle & MDIS_ALLCHILDSTYLES) )
316 style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE |
317 WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL );
318 style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW);
321 if( w->flags & WIN_ISWIN32 )
323 hwnd = CreateWindow32A( cs->szClass, cs->szTitle, style,
324 cs->x, cs->y, cs->cx, cs->cy, parent,
325 (HMENU16)wIDmenu, cs->hOwner, cs );
327 else
329 MDICREATESTRUCT16 *cs16;
330 LPSTR title, cls;
332 cs16 = SEGPTR_NEW(MDICREATESTRUCT16);
333 STRUCT32_MDICREATESTRUCT32Ato16( cs, cs16 );
334 title = SEGPTR_STRDUP( cs->szTitle );
335 cls = SEGPTR_STRDUP( cs->szClass );
336 cs16->szTitle = SEGPTR_GET(title);
337 cs16->szClass = SEGPTR_GET(cls);
339 hwnd = CreateWindow16( cs->szClass, cs->szTitle, style,
340 cs16->x, cs16->y, cs16->cx, cs16->cy, parent,
341 (HMENU32)wIDmenu, cs16->hOwner,
342 (LPVOID)SEGPTR_GET(cs16) );
343 SEGPTR_FREE( title );
344 SEGPTR_FREE( cls );
345 SEGPTR_FREE( cs16 );
348 /* MDI windows are WS_CHILD so they won't be activated by CreateWindow */
350 if (hwnd)
352 WND* wnd = WIN_FindWndPtr( hwnd );
354 MDI_MenuModifyItem(w ,hwnd);
355 if( wnd->dwStyle & WS_MINIMIZE && ci->hwndActiveChild )
356 ShowWindow32( hwnd, SW_SHOWMINNOACTIVE );
357 else
359 /* WS_VISIBLE is clear if a) the MDI client has
360 * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the
361 * MDICreateStruct. If so the created window is not shown nor
362 * activated.
364 int showflag=wnd->dwStyle & WS_VISIBLE;
365 /* clear visible flag, otherwise SetWindoPos32 ignores
366 * the SWP_SHOWWINDOW command.
368 wnd->dwStyle &= ~WS_VISIBLE;
369 if(showflag){
370 SetWindowPos32( hwnd, 0, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE );
372 /* Set maximized state here in case hwnd didn't receive WM_SIZE
373 * during CreateWindow - bad!
376 if((wnd->dwStyle & WS_MAXIMIZE) && !ci->hwndChildMaximized )
378 ci->hwndChildMaximized = wnd->hwndSelf;
379 MDI_AugmentFrameMenu( ci, w->parent, hwnd );
380 MDI_UpdateFrameText( w->parent, ci->self, MDI_REPAINTFRAME, NULL );
382 }else
383 /* needed, harmless ? */
384 SetWindowPos32( hwnd, 0, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE );
387 TRACE(mdi, "created child - %04x\n",hwnd);
389 else
391 ci->nActiveChildren--;
392 DeleteMenu32(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
393 if( IsWindow32(hwndMax) )
394 ShowWindow32(hwndMax, SW_SHOWMAXIMIZED);
397 return hwnd;
400 /**********************************************************************
401 * MDI_ChildGetMinMaxInfo
403 * Note: The rule here is that client rect of the maximized MDI child
404 * is equal to the client rect of the MDI client window.
406 static void MDI_ChildGetMinMaxInfo( WND* clientWnd, HWND32 hwnd,
407 MINMAXINFO16* lpMinMax )
409 WND* childWnd = WIN_FindWndPtr(hwnd);
410 RECT32 rect = clientWnd->rectClient;
412 MapWindowPoints32( clientWnd->parent->hwndSelf,
413 ((MDICLIENTINFO*)clientWnd->wExtra)->self, (LPPOINT32)&rect, 2);
414 AdjustWindowRectEx32( &rect, childWnd->dwStyle, 0, childWnd->dwExStyle );
416 lpMinMax->ptMaxSize.x = rect.right -= rect.left;
417 lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
419 lpMinMax->ptMaxPosition.x = rect.left;
420 lpMinMax->ptMaxPosition.y = rect.top;
422 TRACE(mdi,"max rect (%i,%i - %i, %i)\n",
423 rect.left,rect.top,rect.right,rect.bottom);
426 /**********************************************************************
427 * MDI_SwitchActiveChild
429 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
430 * being activated
432 static void MDI_SwitchActiveChild( HWND32 clientHwnd, HWND32 childHwnd,
433 BOOL32 bNextWindow )
435 WND *w = WIN_FindWndPtr(clientHwnd);
436 HWND32 hwndTo = 0;
437 HWND32 hwndPrev = 0;
438 MDICLIENTINFO *ci;
440 hwndTo = MDI_GetWindow(w, childHwnd, bNextWindow, 0);
442 ci = (MDICLIENTINFO *) w->wExtra;
444 TRACE(mdi, "from %04x, to %04x\n",childHwnd,hwndTo);
446 if ( !hwndTo ) return; /* no window to switch to */
448 hwndPrev = ci->hwndActiveChild;
450 if ( hwndTo != hwndPrev )
452 BOOL32 bOptimize = 0;
454 if( ci->hwndChildMaximized )
456 bOptimize = 1;
457 w->dwStyle &= ~WS_VISIBLE;
460 SetWindowPos32( hwndTo, HWND_TOP, 0, 0, 0, 0,
461 SWP_NOMOVE | SWP_NOSIZE );
463 if( bNextWindow && hwndPrev )
464 SetWindowPos32( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0,
465 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
466 if( bOptimize )
467 ShowWindow32( clientHwnd, SW_SHOW );
472 /**********************************************************************
473 * MDIDestroyChild
475 static LRESULT MDIDestroyChild( WND *w_parent, MDICLIENTINFO *ci,
476 HWND32 parent, HWND32 child,
477 BOOL32 flagDestroy )
479 WND *childPtr = WIN_FindWndPtr(child);
481 if( childPtr )
483 if( child == ci->hwndActiveChild )
485 MDI_SwitchActiveChild(parent, child, TRUE);
487 if( child == ci->hwndActiveChild )
489 ShowWindow32( child, SW_HIDE);
490 if( child == ci->hwndChildMaximized )
492 MDI_RestoreFrameMenu(w_parent->parent, child);
493 ci->hwndChildMaximized = 0;
494 MDI_UpdateFrameText(w_parent->parent,parent,TRUE,NULL);
497 MDI_ChildActivate(w_parent, 0);
499 MDI_MenuDeleteItem(w_parent, child);
502 ci->nActiveChildren--;
504 TRACE(mdi,"child destroyed - %04x\n",child);
506 if (flagDestroy)
508 MDI_PostUpdate(GetParent32(child), ci, SB_BOTH+1);
509 DestroyWindow32(child);
513 return 0;
517 /**********************************************************************
518 * MDI_ChildActivate
520 * Note: hWndChild is NULL when last child is being destroyed
522 static LONG MDI_ChildActivate( WND *clientPtr, HWND32 hWndChild )
524 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientPtr->wExtra;
525 HWND32 prevActiveWnd = clientInfo->hwndActiveChild;
526 WND *wndPtr = WIN_FindWndPtr( hWndChild );
527 WND *wndPrev = WIN_FindWndPtr( prevActiveWnd );
528 BOOL32 isActiveFrameWnd = 0;
530 if( hWndChild == prevActiveWnd ) return 0L;
532 if( wndPtr )
533 if( wndPtr->dwStyle & WS_DISABLED ) return 0L;
535 TRACE(mdi,"%04x\n", hWndChild);
537 if( GetActiveWindow32() == clientPtr->parent->hwndSelf )
538 isActiveFrameWnd = TRUE;
540 /* deactivate prev. active child */
541 if( wndPrev )
543 wndPrev->dwStyle |= WS_SYSMENU;
544 SendMessage32A( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
545 SendMessage32A( prevActiveWnd, WM_MDIACTIVATE, (WPARAM32)prevActiveWnd,
546 (LPARAM)hWndChild);
547 /* uncheck menu item */
548 if( clientInfo->hWindowMenu )
549 CheckMenuItem32( clientInfo->hWindowMenu,
550 wndPrev->wIDmenu, 0);
553 /* set appearance */
554 if( clientInfo->hwndChildMaximized )
556 if( clientInfo->hwndChildMaximized != hWndChild ) {
557 if( hWndChild ) {
558 clientInfo->hwndActiveChild = hWndChild;
559 ShowWindow32( hWndChild, SW_SHOWMAXIMIZED);
560 } else
561 ShowWindow32( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
565 clientInfo->hwndActiveChild = hWndChild;
567 /* check if we have any children left */
568 if( !hWndChild )
570 if( isActiveFrameWnd )
571 SetFocus32( clientInfo->self );
572 return 0;
575 /* check menu item */
576 if( clientInfo->hWindowMenu )
577 CheckMenuItem32( clientInfo->hWindowMenu,
578 wndPtr->wIDmenu, MF_CHECKED);
580 /* bring active child to the top */
581 SetWindowPos32( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
583 if( isActiveFrameWnd )
585 SendMessage32A( hWndChild, WM_NCACTIVATE, TRUE, 0L);
586 if( GetFocus32() == clientInfo->self )
587 SendMessage32A( clientInfo->self, WM_SETFOCUS,
588 (WPARAM32)clientInfo->self, 0L );
589 else
590 SetFocus32( clientInfo->self );
592 SendMessage32A( hWndChild, WM_MDIACTIVATE, (WPARAM32)prevActiveWnd,
593 (LPARAM)hWndChild );
594 return 1;
597 /* -------------------- MDI client window functions ------------------- */
599 /**********************************************************************
600 * CreateMDIMenuBitmap
602 static HBITMAP16 CreateMDIMenuBitmap(void)
604 HDC32 hDCSrc = CreateCompatibleDC32(0);
605 HDC32 hDCDest = CreateCompatibleDC32(hDCSrc);
606 HBITMAP16 hbClose = LoadBitmap16(0, MAKEINTRESOURCE16(OBM_CLOSE) );
607 HBITMAP16 hbCopy;
608 HANDLE16 hobjSrc, hobjDest;
610 hobjSrc = SelectObject32(hDCSrc, hbClose);
611 hbCopy = CreateCompatibleBitmap32(hDCSrc,SYSMETRICS_CXSIZE,SYSMETRICS_CYSIZE);
612 hobjDest = SelectObject32(hDCDest, hbCopy);
614 BitBlt32(hDCDest, 0, 0, SYSMETRICS_CXSIZE, SYSMETRICS_CYSIZE,
615 hDCSrc, SYSMETRICS_CXSIZE, 0, SRCCOPY);
617 SelectObject32(hDCSrc, hobjSrc);
618 DeleteObject32(hbClose);
619 DeleteDC32(hDCSrc);
621 hobjSrc = SelectObject32( hDCDest, GetStockObject32(BLACK_PEN) );
623 MoveToEx32( hDCDest, SYSMETRICS_CXSIZE - 1, 0, NULL );
624 LineTo32( hDCDest, SYSMETRICS_CXSIZE - 1, SYSMETRICS_CYSIZE - 1);
626 SelectObject32(hDCDest, hobjSrc );
627 SelectObject32(hDCDest, hobjDest);
628 DeleteDC32(hDCDest);
630 return hbCopy;
633 /**********************************************************************
634 * MDICascade
636 static LONG MDICascade(WND* clientWnd, MDICLIENTINFO *ci)
638 WND** ppWnd;
639 UINT32 total;
641 if (ci->hwndChildMaximized)
642 SendMessage32A( clientWnd->hwndSelf, WM_MDIRESTORE,
643 (WPARAM32)ci->hwndChildMaximized, 0);
645 if (ci->nActiveChildren == 0) return 0;
647 if ((ppWnd = WIN_BuildWinArray(clientWnd, BWA_SKIPHIDDEN | BWA_SKIPOWNED |
648 BWA_SKIPICONIC, &total)))
650 WND** heapPtr = ppWnd;
651 if( total )
653 INT32 delta = 0, n = 0;
654 POINT32 pos[2];
655 if( total < ci->nActiveChildren )
656 delta = SYSMETRICS_CYICONSPACING + SYSMETRICS_CYICON;
658 /* walk the list (backwards) and move windows */
659 while (*ppWnd) ppWnd++;
660 while (ppWnd != heapPtr)
662 ppWnd--;
663 TRACE(mdi, "move %04x to (%d,%d) size [%d,%d]\n",
664 (*ppWnd)->hwndSelf, pos[0].x, pos[0].y, pos[1].x, pos[1].y);
666 MDI_CalcDefaultChildPos(clientWnd, n++, pos, delta);
667 SetWindowPos32( (*ppWnd)->hwndSelf, 0, pos[0].x, pos[0].y,
668 pos[1].x, pos[1].y,
669 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
672 HeapFree( SystemHeap, 0, heapPtr );
675 if( total < ci->nActiveChildren )
676 ArrangeIconicWindows32( clientWnd->hwndSelf );
677 return 0;
680 /**********************************************************************
681 * MDITile
683 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM32 wParam )
685 WND** ppWnd;
686 UINT32 total = 0;
688 if (ci->hwndChildMaximized)
689 SendMessage32A( wndClient->hwndSelf, WM_MDIRESTORE,
690 (WPARAM32)ci->hwndChildMaximized, 0);
692 if (ci->nActiveChildren == 0) return;
694 ppWnd = WIN_BuildWinArray(wndClient, BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
695 ((wParam & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
697 TRACE(mdi,"%u windows to tile\n", total);
699 if( ppWnd )
701 WND** heapPtr = ppWnd;
703 if( total )
705 RECT32 rect;
706 int x, y, xsize, ysize;
707 int rows, columns, r, c, i;
709 rect = wndClient->rectClient;
710 rows = (int) sqrt((double)total);
711 columns = total / rows;
713 if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */
715 i = rows;
716 rows = columns; /* exchange r and c */
717 columns = i;
720 if( total != ci->nActiveChildren)
722 y = rect.bottom - 2 * SYSMETRICS_CYICONSPACING - SYSMETRICS_CYICON;
723 rect.bottom = ( y - SYSMETRICS_CYICON < rect.top )? rect.bottom: y;
726 ysize = rect.bottom / rows;
727 xsize = rect.right / columns;
729 for (x = i = 0, c = 1; c <= columns && *ppWnd; c++)
731 if (c == columns)
733 rows = total - i;
734 ysize = rect.bottom / rows;
737 y = 0;
738 for (r = 1; r <= rows && *ppWnd; r++, i++)
740 SetWindowPos32((*ppWnd)->hwndSelf, 0, x, y, xsize, ysize,
741 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
742 y += ysize;
743 ppWnd++;
745 x += xsize;
748 HeapFree( SystemHeap, 0, heapPtr );
751 if( total < ci->nActiveChildren ) ArrangeIconicWindows32( wndClient->hwndSelf );
754 /* ----------------------- Frame window ---------------------------- */
757 /**********************************************************************
758 * MDI_AugmentFrameMenu
760 static BOOL32 MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
761 HWND32 hChild )
763 WND* child = WIN_FindWndPtr(hChild);
764 HMENU32 hSysPopup = 0;
766 TRACE(mdi,"frame %p,child %04x\n",frame,hChild);
768 if( !frame->wIDmenu || !child->hSysMenu ) return 0;
770 /* create a copy of sysmenu popup and insert it into frame menu bar */
772 if (!(hSysPopup = LoadMenuIndirect32A(SYSRES_GetResPtr(SYSRES_MENU_SYSMENU))))
773 return 0;
775 TRACE(mdi,"\tgot popup %04x in sysmenu %04x\n",
776 hSysPopup, child->hSysMenu);
778 if( !InsertMenu32A(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
779 hSysPopup, (LPSTR)(DWORD)hBmpClose ))
781 DestroyMenu32(hSysPopup);
782 return 0;
785 if( !AppendMenu32A(frame->wIDmenu,MF_HELP | MF_BITMAP,
786 SC_RESTORE, (LPSTR)(DWORD)hBmpRestore ))
788 RemoveMenu32(frame->wIDmenu,0,MF_BYPOSITION);
789 return 0;
792 EnableMenuItem32(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
793 EnableMenuItem32(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
794 EnableMenuItem32(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
796 /* redraw menu */
797 DrawMenuBar32(frame->hwndSelf);
799 return 1;
802 /**********************************************************************
803 * MDI_RestoreFrameMenu
805 static BOOL32 MDI_RestoreFrameMenu( WND *frameWnd, HWND32 hChild )
807 INT32 nItems = GetMenuItemCount32(frameWnd->wIDmenu) - 1;
809 TRACE(mdi,"for child %04x\n",hChild);
811 if( GetMenuItemID32(frameWnd->wIDmenu,nItems) != SC_RESTORE )
812 return 0;
814 RemoveMenu32(frameWnd->wIDmenu,0,MF_BYPOSITION);
815 DeleteMenu32(frameWnd->wIDmenu,nItems-1,MF_BYPOSITION);
817 DrawMenuBar32(frameWnd->hwndSelf);
819 return 1;
822 /**********************************************************************
823 * MDI_UpdateFrameText
825 * used when child window is maximized/restored
827 * Note: lpTitle can be NULL
829 static void MDI_UpdateFrameText( WND *frameWnd, HWND32 hClient,
830 BOOL32 repaint, LPCSTR lpTitle )
832 char lpBuffer[MDI_MAXTITLELENGTH+1];
833 WND* clientWnd = WIN_FindWndPtr(hClient);
834 MDICLIENTINFO *ci = (MDICLIENTINFO *) clientWnd->wExtra;
836 TRACE(mdi, "repaint %i, frameText %s\n", repaint, (lpTitle)?lpTitle:"NULL");
838 if (!clientWnd)
839 return;
841 if (!ci)
842 return;
844 /* store new "default" title if lpTitle is not NULL */
845 if (lpTitle)
847 if (ci->frameTitle) HeapFree( SystemHeap, 0, ci->frameTitle );
848 ci->frameTitle = HEAP_strdupA( SystemHeap, 0, lpTitle );
851 if (ci->frameTitle)
853 WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );
855 if( childWnd && childWnd->text )
857 /* combine frame title and child title if possible */
859 LPCSTR lpBracket = " - [";
860 int i_frame_text_length = strlen(ci->frameTitle);
861 int i_child_text_length = strlen(childWnd->text);
863 lstrcpyn32A( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
865 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
867 strcat( lpBuffer, lpBracket );
869 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
871 strcat( lpBuffer, childWnd->text );
872 strcat( lpBuffer, "]" );
874 else
876 lstrcpyn32A( lpBuffer + i_frame_text_length + 4,
877 childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
878 strcat( lpBuffer, "]" );
882 else
884 strncpy(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH );
885 lpBuffer[MDI_MAXTITLELENGTH]='\0';
888 else
889 lpBuffer[0] = '\0';
891 DEFWND_SetText( frameWnd, lpBuffer );
892 if( repaint == MDI_REPAINTFRAME)
893 SetWindowPos32( frameWnd->hwndSelf, 0,0,0,0,0, SWP_FRAMECHANGED |
894 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
898 /* ----------------------------- Interface ---------------------------- */
901 /**********************************************************************
902 * MDIClientWndProc
904 * This function handles all MDI requests.
906 LRESULT WINAPI MDIClientWndProc( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
907 LPARAM lParam )
909 LPCREATESTRUCT32A cs;
910 MDICLIENTINFO *ci;
911 RECT32 rect;
912 WND *w = WIN_FindWndPtr(hwnd);
913 WND *frameWnd = w->parent;
914 INT32 nItems;
916 ci = (MDICLIENTINFO *) w->wExtra;
918 switch (message)
920 case WM_CREATE:
922 cs = (LPCREATESTRUCT32A)lParam;
924 /* Translation layer doesn't know what's in the cs->lpCreateParams
925 * so we have to keep track of what environment we're in. */
927 if( w->flags & WIN_ISWIN32 )
929 #define ccs ((LPCLIENTCREATESTRUCT32)cs->lpCreateParams)
930 ci->hWindowMenu = ccs->hWindowMenu;
931 ci->idFirstChild = ccs->idFirstChild;
932 #undef ccs
934 else
936 LPCLIENTCREATESTRUCT16 ccs = (LPCLIENTCREATESTRUCT16)
937 PTR_SEG_TO_LIN(cs->lpCreateParams);
938 ci->hWindowMenu = ccs->hWindowMenu;
939 ci->idFirstChild = ccs->idFirstChild;
942 ci->hwndChildMaximized = 0;
943 ci->nActiveChildren = 0;
944 ci->nTotalCreated = 0;
945 ci->frameTitle = NULL;
946 ci->mdiFlags = 0;
947 ci->self = hwnd;
948 w->dwStyle |= WS_CLIPCHILDREN;
950 if (!hBmpClose)
952 hBmpClose = CreateMDIMenuBitmap();
953 hBmpRestore = LoadBitmap16( 0, MAKEINTRESOURCE16(OBM_RESTORE) );
955 MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
957 AppendMenu32A( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
959 GetClientRect32(frameWnd->hwndSelf, &rect);
960 NC_HandleNCCalcSize( w, &rect );
961 w->rectClient = rect;
963 TRACE(mdi,"Client created - hwnd = %04x, idFirst = %u\n",
964 hwnd, ci->idFirstChild );
966 return 0;
968 case WM_DESTROY:
969 if( ci->hwndChildMaximized ) MDI_RestoreFrameMenu(w, frameWnd->hwndSelf);
970 if((nItems = GetMenuItemCount32(ci->hWindowMenu)) > 0)
972 ci->idFirstChild = nItems - 1;
973 ci->nActiveChildren++; /* to delete a separator */
974 while( ci->nActiveChildren-- )
975 DeleteMenu32(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
977 return 0;
979 case WM_MDIACTIVATE:
980 if( ci->hwndActiveChild != (HWND32)wParam )
981 SetWindowPos32((HWND32)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
982 return 0;
984 case WM_MDICASCADE:
985 return MDICascade(w, ci);
987 case WM_MDICREATE:
988 if (lParam) return MDICreateChild( w, ci, hwnd,
989 (MDICREATESTRUCT32A*)lParam );
990 return 0;
992 case WM_MDIDESTROY:
993 return MDIDestroyChild( w, ci, hwnd, (HWND32)wParam, TRUE );
995 case WM_MDIGETACTIVE:
996 if (lParam) *(BOOL32 *)lParam = (ci->hwndChildMaximized > 0);
997 return ci->hwndActiveChild;
999 case WM_MDIICONARRANGE:
1000 ci->mdiFlags |= MDIF_NEEDUPDATE;
1001 ArrangeIconicWindows32(hwnd);
1002 ci->sbRecalc = SB_BOTH+1;
1003 SendMessage32A(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
1004 return 0;
1006 case WM_MDIMAXIMIZE:
1007 ShowWindow32( (HWND32)wParam, SW_MAXIMIZE );
1008 return 0;
1010 case WM_MDINEXT: /* lParam != 0 means previous window */
1011 MDI_SwitchActiveChild(hwnd, (HWND32)wParam, (lParam)? FALSE : TRUE );
1012 break;
1014 case WM_MDIRESTORE:
1015 SendMessage32A( (HWND32)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
1016 return 0;
1018 case WM_MDISETMENU:
1019 return MDISetMenu( hwnd, (HMENU32)wParam, (HMENU32)lParam );
1021 case WM_MDIREFRESHMENU:
1022 return MDIRefreshMenu( hwnd, (HMENU32)wParam, (HMENU32)lParam );
1024 case WM_MDITILE:
1025 ci->mdiFlags |= MDIF_NEEDUPDATE;
1026 ShowScrollBar32(hwnd,SB_BOTH,FALSE);
1027 MDITile(w, ci, wParam);
1028 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1029 return 0;
1031 case WM_VSCROLL:
1032 case WM_HSCROLL:
1033 ci->mdiFlags |= MDIF_NEEDUPDATE;
1034 ScrollChildren32(hwnd, message, wParam, lParam);
1035 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1036 return 0;
1038 case WM_SETFOCUS:
1039 if( ci->hwndActiveChild )
1041 w = WIN_FindWndPtr( ci->hwndActiveChild );
1042 if( !(w->dwStyle & WS_MINIMIZE) )
1043 SetFocus32( ci->hwndActiveChild );
1045 return 0;
1047 case WM_NCACTIVATE:
1048 if( ci->hwndActiveChild )
1049 SendMessage32A(ci->hwndActiveChild, message, wParam, lParam);
1050 break;
1052 case WM_PARENTNOTIFY:
1053 if (LOWORD(wParam) == WM_LBUTTONDOWN)
1055 POINT16 pt = MAKEPOINT16(lParam);
1056 HWND16 child = ChildWindowFromPoint16(hwnd, pt);
1058 TRACE(mdi,"notification from %04x (%i,%i)\n",child,pt.x,pt.y);
1060 if( child && child != hwnd && child != ci->hwndActiveChild )
1061 SetWindowPos32(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1063 return 0;
1065 case WM_SIZE:
1066 if( IsWindow32(ci->hwndChildMaximized) )
1068 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1069 RECT32 rect = { 0, 0, LOWORD(lParam), HIWORD(lParam) };
1071 AdjustWindowRectEx32(&rect, child->dwStyle, 0, child->dwExStyle);
1072 MoveWindow32(ci->hwndChildMaximized, rect.left, rect.top,
1073 rect.right - rect.left, rect.bottom - rect.top, 1);
1075 else
1076 MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1078 break;
1080 case WM_MDICALCCHILDSCROLL:
1081 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1083 CalcChildScroll(hwnd, ci->sbRecalc-1);
1084 ci->sbRecalc = 0;
1085 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1087 return 0;
1090 return DefWindowProc32A( hwnd, message, wParam, lParam );
1094 /***********************************************************************
1095 * DefFrameProc16 (USER.445)
1097 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1098 UINT16 message, WPARAM16 wParam, LPARAM lParam )
1100 HWND16 childHwnd;
1101 MDICLIENTINFO* ci;
1102 WND* wndPtr;
1104 if (hwndMDIClient)
1106 switch (message)
1108 case WM_COMMAND:
1109 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1110 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1112 /* check for possible syscommands for maximized MDI child */
1114 if( ci && (
1115 wParam < ci->idFirstChild ||
1116 wParam >= ci->idFirstChild + ci->nActiveChildren
1118 if( (wParam - 0xF000) & 0xF00F ) break;
1119 switch( wParam )
1121 case SC_SIZE:
1122 case SC_MOVE:
1123 case SC_MINIMIZE:
1124 case SC_MAXIMIZE:
1125 case SC_NEXTWINDOW:
1126 case SC_PREVWINDOW:
1127 case SC_CLOSE:
1128 case SC_RESTORE:
1129 if( ci->hwndChildMaximized )
1130 return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1131 wParam, lParam);
1134 else
1136 childHwnd = MDI_GetChildByID( WIN_FindWndPtr(hwndMDIClient),
1137 wParam );
1138 if( childHwnd )
1139 SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1140 (WPARAM16)childHwnd , 0L);
1142 break;
1144 case WM_NCACTIVATE:
1145 SendMessage16(hwndMDIClient, message, wParam, lParam);
1146 break;
1148 case WM_SETTEXT:
1149 MDI_UpdateFrameText(WIN_FindWndPtr(hwnd), hwndMDIClient,
1150 MDI_REPAINTFRAME,
1151 (LPCSTR)PTR_SEG_TO_LIN(lParam));
1152 return 0;
1154 case WM_SETFOCUS:
1155 SetFocus32(hwndMDIClient);
1156 break;
1158 case WM_SIZE:
1159 MoveWindow16(hwndMDIClient, 0, 0,
1160 LOWORD(lParam), HIWORD(lParam), TRUE);
1161 break;
1163 case WM_NEXTMENU:
1165 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1166 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1168 if( !(wndPtr->parent->dwStyle & WS_MINIMIZE)
1169 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1171 /* control menu is between the frame system menu and
1172 * the first entry of menu bar */
1174 if( (wParam == VK_LEFT &&
1175 wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1176 (wParam == VK_RIGHT &&
1177 GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1179 wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1180 return MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1181 ci->hwndActiveChild);
1184 break;
1188 return DefWindowProc16(hwnd, message, wParam, lParam);
1192 /***********************************************************************
1193 * DefFrameProc32A (USER32.122)
1195 LRESULT WINAPI DefFrameProc32A( HWND32 hwnd, HWND32 hwndMDIClient,
1196 UINT32 message, WPARAM32 wParam, LPARAM lParam)
1198 if (hwndMDIClient)
1200 switch (message)
1202 case WM_COMMAND:
1203 return DefFrameProc16( hwnd, hwndMDIClient, message,
1204 (WPARAM16)wParam,
1205 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1207 case WM_NCACTIVATE:
1208 SendMessage32A(hwndMDIClient, message, wParam, lParam);
1209 break;
1211 case WM_SETTEXT: {
1212 LRESULT ret;
1213 LPSTR segstr = SEGPTR_STRDUP((LPSTR)lParam);
1215 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1216 wParam, (LPARAM)SEGPTR_GET(segstr) );
1217 SEGPTR_FREE(segstr);
1218 return ret;
1221 case WM_NEXTMENU:
1222 case WM_SETFOCUS:
1223 case WM_SIZE:
1224 return DefFrameProc16( hwnd, hwndMDIClient, message,
1225 wParam, lParam );
1229 return DefWindowProc32A(hwnd, message, wParam, lParam);
1233 /***********************************************************************
1234 * DefFrameProc32W (USER32.123)
1236 LRESULT WINAPI DefFrameProc32W( HWND32 hwnd, HWND32 hwndMDIClient,
1237 UINT32 message, WPARAM32 wParam, LPARAM lParam)
1239 if (hwndMDIClient)
1241 switch (message)
1243 case WM_COMMAND:
1244 return DefFrameProc16( hwnd, hwndMDIClient, message,
1245 (WPARAM16)wParam,
1246 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1248 case WM_NCACTIVATE:
1249 SendMessage32W(hwndMDIClient, message, wParam, lParam);
1250 break;
1252 case WM_SETTEXT:
1254 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1255 LRESULT ret = DefFrameProc32A( hwnd, hwndMDIClient, message,
1256 wParam, (DWORD)txt );
1257 HeapFree(GetProcessHeap(),0,txt);
1258 return ret;
1260 case WM_NEXTMENU:
1261 case WM_SETFOCUS:
1262 case WM_SIZE:
1263 return DefFrameProc32A( hwnd, hwndMDIClient, message,
1264 wParam, lParam );
1268 return DefWindowProc32W( hwnd, message, wParam, lParam );
1272 /***********************************************************************
1273 * DefMDIChildProc16 (USER.447)
1275 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1276 WPARAM16 wParam, LPARAM lParam )
1278 MDICLIENTINFO *ci;
1279 WND *clientWnd;
1281 clientWnd = WIN_FindWndPtr(GetParent16(hwnd));
1282 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1284 switch (message)
1286 case WM_SETTEXT:
1287 DefWindowProc16(hwnd, message, wParam, lParam);
1288 MDI_MenuModifyItem(clientWnd,hwnd);
1289 if( ci->hwndChildMaximized == hwnd )
1290 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1291 MDI_REPAINTFRAME, NULL );
1292 return 0;
1294 case WM_CLOSE:
1295 SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1296 return 0;
1298 case WM_SETFOCUS:
1299 if( ci->hwndActiveChild != hwnd )
1300 MDI_ChildActivate(clientWnd, hwnd);
1301 break;
1303 case WM_CHILDACTIVATE:
1304 MDI_ChildActivate(clientWnd, hwnd);
1305 return 0;
1307 case WM_NCPAINT:
1308 TRACE(mdi,"WM_NCPAINT for %04x, active %04x\n",
1309 hwnd, ci->hwndActiveChild );
1310 break;
1312 case WM_SYSCOMMAND:
1313 switch( wParam )
1315 case SC_MOVE:
1316 if( ci->hwndChildMaximized == hwnd) return 0;
1317 break;
1318 case SC_RESTORE:
1319 case SC_MINIMIZE:
1320 WIN_FindWndPtr(hwnd)->dwStyle |= WS_SYSMENU;
1321 break;
1322 case SC_MAXIMIZE:
1323 if( ci->hwndChildMaximized == hwnd)
1324 return SendMessage16( clientWnd->parent->hwndSelf,
1325 message, wParam, lParam);
1326 WIN_FindWndPtr(hwnd)->dwStyle &= ~WS_SYSMENU;
1327 break;
1328 case SC_NEXTWINDOW:
1329 SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1330 return 0;
1331 case SC_PREVWINDOW:
1332 SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1333 return 0;
1335 break;
1337 case WM_GETMINMAXINFO:
1338 MDI_ChildGetMinMaxInfo(clientWnd, hwnd, (MINMAXINFO16*) PTR_SEG_TO_LIN(lParam));
1339 return 0;
1341 case WM_SETVISIBLE:
1342 if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1343 else
1344 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1345 break;
1347 case WM_SIZE:
1348 /* do not change */
1350 if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1352 ci->hwndChildMaximized = 0;
1354 MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1355 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1356 MDI_REPAINTFRAME, NULL );
1359 if( wParam == SIZE_MAXIMIZED )
1361 HWND16 hMaxChild = ci->hwndChildMaximized;
1363 if( hMaxChild == hwnd ) break;
1365 if( hMaxChild)
1367 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1369 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1370 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1372 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1375 TRACE(mdi,"maximizing child %04x\n", hwnd );
1377 ci->hwndChildMaximized = hwnd; /* !!! */
1379 MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1380 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1381 MDI_REPAINTFRAME, NULL );
1384 if( wParam == SIZE_MINIMIZED )
1386 HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1388 if( switchTo )
1389 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1392 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1393 break;
1395 case WM_MENUCHAR:
1397 /* MDI children don't have menu bars */
1398 PostMessage16( clientWnd->parent->hwndSelf, WM_SYSCOMMAND,
1399 (WPARAM16)SC_KEYMENU, (LPARAM)wParam);
1400 return 0x00010000L;
1402 case WM_NEXTMENU:
1404 if( wParam == VK_LEFT ) /* switch to frame system menu */
1405 return MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1406 clientWnd->parent->hwndSelf );
1407 if( wParam == VK_RIGHT ) /* to frame menu bar */
1408 return MAKELONG( clientWnd->parent->wIDmenu,
1409 clientWnd->parent->hwndSelf );
1411 break;
1413 case WM_SYSCHAR:
1414 if (wParam == '-')
1416 SendMessage16(hwnd,WM_SYSCOMMAND,
1417 (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1418 return 0;
1422 return DefWindowProc16(hwnd, message, wParam, lParam);
1426 /***********************************************************************
1427 * DefMDIChildProc32A (USER32.124)
1429 LRESULT WINAPI DefMDIChildProc32A( HWND32 hwnd, UINT32 message,
1430 WPARAM32 wParam, LPARAM lParam )
1432 MDICLIENTINFO *ci;
1433 WND *clientWnd;
1435 clientWnd = WIN_FindWndPtr(WIN_FindWndPtr(hwnd)->parent->hwndSelf);
1436 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1438 switch (message)
1440 case WM_SETTEXT:
1441 DefWindowProc32A(hwnd, message, wParam, lParam);
1442 MDI_MenuModifyItem(clientWnd,hwnd);
1443 if( ci->hwndChildMaximized == hwnd )
1444 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1445 MDI_REPAINTFRAME, NULL );
1446 return 0;
1448 case WM_GETMINMAXINFO:
1450 MINMAXINFO16 mmi;
1451 STRUCT32_MINMAXINFO32to16( (MINMAXINFO32 *)lParam, &mmi );
1452 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1453 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO32 *)lParam );
1455 return 0;
1457 case WM_MENUCHAR:
1459 /* MDI children don't have menu bars */
1460 PostMessage16( clientWnd->parent->hwndSelf, WM_SYSCOMMAND,
1461 (WPARAM16)SC_KEYMENU, (LPARAM)LOWORD(wParam) );
1462 return 0x00010000L;
1464 case WM_CLOSE:
1465 case WM_SETFOCUS:
1466 case WM_CHILDACTIVATE:
1467 case WM_NCPAINT:
1468 case WM_SYSCOMMAND:
1469 case WM_SETVISIBLE:
1470 case WM_SIZE:
1471 case WM_NEXTMENU:
1472 return DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1474 case WM_SYSCHAR:
1475 if (wParam == '-')
1477 SendMessage32A(hwnd,WM_SYSCOMMAND,
1478 (WPARAM32)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1479 return 0;
1482 return DefWindowProc32A(hwnd, message, wParam, lParam);
1486 /***********************************************************************
1487 * DefMDIChildProc32W (USER32.125)
1489 LRESULT WINAPI DefMDIChildProc32W( HWND32 hwnd, UINT32 message,
1490 WPARAM32 wParam, LPARAM lParam )
1492 MDICLIENTINFO *ci;
1493 WND *clientWnd;
1495 clientWnd = WIN_FindWndPtr(GetParent16(hwnd));
1496 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1498 switch (message)
1500 case WM_SETTEXT:
1501 DefWindowProc32W(hwnd, message, wParam, lParam);
1502 MDI_MenuModifyItem(clientWnd,hwnd);
1503 if( ci->hwndChildMaximized == hwnd )
1504 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1505 MDI_REPAINTFRAME, NULL );
1506 return 0;
1508 case WM_GETMINMAXINFO:
1509 case WM_MENUCHAR:
1510 case WM_CLOSE:
1511 case WM_SETFOCUS:
1512 case WM_CHILDACTIVATE:
1513 case WM_NCPAINT:
1514 case WM_SYSCOMMAND:
1515 case WM_SETVISIBLE:
1516 case WM_SIZE:
1517 case WM_NEXTMENU:
1518 return DefMDIChildProc32A( hwnd, message, (WPARAM16)wParam, lParam );
1520 case WM_SYSCHAR:
1521 if (wParam == '-')
1523 SendMessage32W(hwnd,WM_SYSCOMMAND,
1524 (WPARAM32)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1525 return 0;
1528 return DefWindowProc32W(hwnd, message, wParam, lParam);
1532 /**********************************************************************
1533 * CreateMDIWindowA [USER32.79] Creates a MDI child in new thread
1534 * FIXME: its in the same thread now
1536 * RETURNS
1537 * Success: Handle to created window
1538 * Failure: NULL
1540 HWND32 WINAPI CreateMDIWindow32A(
1541 LPCSTR lpClassName, /* [in] Pointer to registered child class name */
1542 LPCSTR lpWindowName, /* [in] Pointer to window name */
1543 DWORD dwStyle, /* [in] Window style */
1544 INT32 X, /* [in] Horizontal position of window */
1545 INT32 Y, /* [in] Vertical position of window */
1546 INT32 nWidth, /* [in] Width of window */
1547 INT32 nHeight, /* [in] Height of window */
1548 HWND32 hWndParent, /* [in] Handle to parent window */
1549 HINSTANCE32 hInstance, /* [in] Handle to application instance */
1550 LPARAM lParam) /* [in] Application-defined value */
1552 WARN(mdi,"is only single threaded!\n");
1553 return MDI_CreateMDIWindow32A(lpClassName, lpWindowName, dwStyle, X, Y,
1554 nWidth, nHeight, hWndParent, hInstance, lParam);
1557 /**********************************************************************
1558 * MDI_CreateMDIWindowA
1559 * single threaded version of CreateMDIWindowA
1560 * called by CreateWindowEx32A
1562 HWND32 MDI_CreateMDIWindow32A(
1563 LPCSTR lpClassName,
1564 LPCSTR lpWindowName,
1565 DWORD dwStyle,
1566 INT32 X,
1567 INT32 Y,
1568 INT32 nWidth,
1569 INT32 nHeight,
1570 HWND32 hWndParent,
1571 HINSTANCE32 hInstance,
1572 LPARAM lParam)
1574 MDICLIENTINFO* pCi;
1575 MDICREATESTRUCT32A cs;
1576 WND *pWnd=WIN_FindWndPtr(hWndParent);
1578 TRACE(mdi, "(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
1579 debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
1580 nWidth,nHeight,hWndParent,hInstance,lParam);
1582 if(!pWnd){
1583 ERR(mdi," bad hwnd for MDI-client: %d\n",hWndParent);
1584 return 0;
1586 cs.szClass=lpClassName;
1587 cs.szTitle=lpWindowName;
1588 cs.hOwner=hInstance;
1589 cs.x=X;
1590 cs.y=Y;
1591 cs.cx=nWidth;
1592 cs.cy=nHeight;
1593 cs.style=dwStyle;
1594 cs.lParam=lParam;
1596 pCi=(MDICLIENTINFO *)pWnd->wExtra;
1598 return MDICreateChild(pWnd,pCi,hWndParent,&cs);
1601 /***************************************
1602 * CreateMDIWindow32W [USER32.80] Creates a MDI child in new thread
1604 * RETURNS
1605 * Success: Handle to created window
1606 * Failure: NULL
1608 HWND32 WINAPI CreateMDIWindow32W(
1609 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1610 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1611 DWORD dwStyle, /* [in] Window style */
1612 INT32 X, /* [in] Horizontal position of window */
1613 INT32 Y, /* [in] Vertical position of window */
1614 INT32 nWidth, /* [in] Width of window */
1615 INT32 nHeight, /* [in] Height of window */
1616 HWND32 hWndParent, /* [in] Handle to parent window */
1617 HINSTANCE32 hInstance, /* [in] Handle to application instance */
1618 LPARAM lParam) /* [in] Application-defined value */
1620 FIXME(mdi, "(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1621 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1622 nWidth,nHeight,hWndParent,hInstance,lParam);
1623 return (HWND32)NULL;
1627 /******************************************************************************
1628 * CreateMDIWindow32W [USER32.80] Creates a MDI child window
1629 * single threaded version of CreateMDIWindow
1630 * called by CreateWindowEx32W().
1632 HWND32 MDI_CreateMDIWindow32W(
1633 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1634 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1635 DWORD dwStyle, /* [in] Window style */
1636 INT32 X, /* [in] Horizontal position of window */
1637 INT32 Y, /* [in] Vertical position of window */
1638 INT32 nWidth, /* [in] Width of window */
1639 INT32 nHeight, /* [in] Height of window */
1640 HWND32 hWndParent, /* [in] Handle to parent window */
1641 HINSTANCE32 hInstance, /* [in] Handle to application instance */
1642 LPARAM lParam) /* [in] Application-defined value */
1644 FIXME(mdi, "(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1645 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1646 nWidth,nHeight,hWndParent,hInstance,lParam);
1647 return (HWND32)NULL;
1651 /**********************************************************************
1652 * TranslateMDISysAccel32 (USER32.555)
1654 BOOL32 WINAPI TranslateMDISysAccel32( HWND32 hwndClient, LPMSG32 msg )
1656 MSG16 msg16;
1658 STRUCT32_MSG32to16(msg,&msg16);
1659 /* MDICLIENTINFO is still the same for win32 and win16 ... */
1660 return TranslateMDISysAccel16(hwndClient,&msg16);
1664 /**********************************************************************
1665 * TranslateMDISysAccel16 (USER.451)
1667 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
1669 WND* clientWnd = WIN_FindWndPtr( hwndClient);
1671 if( clientWnd && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
1673 MDICLIENTINFO *ci = NULL;
1674 WND* wnd;
1676 ci = (MDICLIENTINFO*) clientWnd->wExtra;
1677 wnd = WIN_FindWndPtr(ci->hwndActiveChild);
1678 if( wnd && !(wnd->dwStyle & WS_DISABLED) )
1680 WPARAM16 wParam = 0;
1682 /* translate if the Ctrl key is down and Alt not. */
1684 if( (GetKeyState32(VK_CONTROL) & 0x8000) &&
1685 !(GetKeyState32(VK_MENU) & 0x8000))
1687 switch( msg->wParam )
1689 case VK_F6:
1690 case VK_TAB:
1691 wParam = ( GetKeyState32(VK_SHIFT) & 0x8000 )
1692 ? SC_NEXTWINDOW : SC_PREVWINDOW;
1693 break;
1694 case VK_F4:
1695 case VK_RBUTTON:
1696 wParam = SC_CLOSE;
1697 break;
1698 default:
1699 return 0;
1701 TRACE(mdi,"wParam = %04x\n", wParam);
1702 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
1703 wParam, (LPARAM)msg->wParam);
1704 return 1;
1708 return 0; /* failure */
1712 /***********************************************************************
1713 * CalcChildScroll (USER.462)
1715 void WINAPI CalcChildScroll( HWND16 hwnd, WORD scroll )
1717 SCROLLINFO info;
1718 RECT32 childRect, clientRect;
1719 INT32 vmin, vmax, hmin, hmax, vpos, hpos;
1720 WND *pWnd, *Wnd;
1722 if (!(Wnd = pWnd = WIN_FindWndPtr( hwnd ))) return;
1723 GetClientRect32( hwnd, &clientRect );
1724 SetRectEmpty32( &childRect );
1726 for ( pWnd = pWnd->child; pWnd; pWnd = pWnd->next )
1728 if( pWnd->dwStyle & WS_MAXIMIZE )
1730 ShowScrollBar32(hwnd, SB_BOTH, FALSE);
1731 return;
1733 UnionRect32( &childRect, &pWnd->rectWindow, &childRect );
1735 UnionRect32( &childRect, &clientRect, &childRect );
1737 hmin = childRect.left; hmax = childRect.right - clientRect.right;
1738 hpos = clientRect.left - childRect.left;
1739 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
1740 vpos = clientRect.top - childRect.top;
1742 switch( scroll )
1744 case SB_HORZ:
1745 vpos = hpos; vmin = hmin; vmax = hmax;
1746 case SB_VERT:
1747 info.cbSize = sizeof(info);
1748 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
1749 info.fMask = SIF_POS | SIF_RANGE;
1750 SetScrollInfo32(hwnd, scroll, &info, TRUE);
1751 break;
1752 case SB_BOTH:
1753 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
1754 hmin, hmax, hpos);
1759 /***********************************************************************
1760 * ScrollChildren16 (USER.463)
1762 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
1764 return ScrollChildren32( hWnd, uMsg, wParam, lParam );
1768 /***********************************************************************
1769 * ScrollChildren32 (USER32.448)
1771 void WINAPI ScrollChildren32(HWND32 hWnd, UINT32 uMsg, WPARAM32 wParam,
1772 LPARAM lParam)
1774 WND *wndPtr = WIN_FindWndPtr(hWnd);
1775 INT32 newPos = -1;
1776 INT32 curPos, length, minPos, maxPos, shift;
1778 if( !wndPtr ) return;
1780 if( uMsg == WM_HSCROLL )
1782 GetScrollRange32(hWnd,SB_HORZ,&minPos,&maxPos);
1783 curPos = GetScrollPos32(hWnd,SB_HORZ);
1784 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
1785 shift = SYSMETRICS_CYHSCROLL;
1787 else if( uMsg == WM_VSCROLL )
1789 GetScrollRange32(hWnd,SB_VERT,&minPos,&maxPos);
1790 curPos = GetScrollPos32(hWnd,SB_VERT);
1791 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
1792 shift = SYSMETRICS_CXVSCROLL;
1794 else return;
1796 switch( wParam )
1798 case SB_LINEUP:
1799 newPos = curPos - shift;
1800 break;
1801 case SB_LINEDOWN:
1802 newPos = curPos + shift;
1803 break;
1804 case SB_PAGEUP:
1805 newPos = curPos - length;
1806 break;
1807 case SB_PAGEDOWN:
1808 newPos = curPos + length;
1809 break;
1811 case SB_THUMBPOSITION:
1812 newPos = LOWORD(lParam);
1813 break;
1815 case SB_THUMBTRACK:
1816 return;
1818 case SB_TOP:
1819 newPos = minPos;
1820 break;
1821 case SB_BOTTOM:
1822 newPos = maxPos;
1823 break;
1824 case SB_ENDSCROLL:
1825 CalcChildScroll(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
1826 return;
1829 if( newPos > maxPos )
1830 newPos = maxPos;
1831 else
1832 if( newPos < minPos )
1833 newPos = minPos;
1835 SetScrollPos32(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
1837 if( uMsg == WM_VSCROLL )
1838 ScrollWindowEx32(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
1839 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1840 else
1841 ScrollWindowEx32(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
1842 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1846 /******************************************************************************
1847 * CascadeWindows [USER32.21] Cascades MDI child windows
1849 * RETURNS
1850 * Success: Number of cascaded windows.
1851 * Failure: 0
1853 WORD WINAPI
1854 CascadeWindows (HWND32 hwndParent, UINT32 wFlags, const LPRECT32 lpRect,
1855 UINT32 cKids, const HWND32 *lpKids)
1857 FIXME (mdi, "(0x%08x,0x%08x,...,%u,...): stub\n",
1858 hwndParent, wFlags, cKids);
1860 return 0;
1864 /******************************************************************************
1865 * TileWindows [USER32.545] Tiles MDI child windows
1867 * RETURNS
1868 * Success: Number of tiled windows.
1869 * Failure: 0
1871 WORD WINAPI
1872 TileWindows (HWND32 hwndParent, UINT32 wFlags, const LPRECT32 lpRect,
1873 UINT32 cKids, const HWND32 *lpKids)
1875 FIXME (mdi, "(0x%08x,0x%08x,...,%u,...): stub\n",
1876 hwndParent, wFlags, cKids);
1878 return 0;