Authors: Adrian Thurston <adriant@corel.ca>, Zygo Blaxell <zblaxell@corel.ca>
[wine.git] / windows / mdi.c
blobf6ea50bbe66ebb26472da4f05a5552bfd21b7a1e
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 // Using the magic menu id's to insert system buttons in the menu bar
786 AppendMenu32A(frame->wIDmenu,MF_HELP | MF_BITMAP,
787 SC_MINIMIZE, (LPSTR)(DWORD)3 ) ;
788 AppendMenu32A(frame->wIDmenu,MF_HELP | MF_BITMAP,
789 SC_RESTORE, (LPSTR)(DWORD)2 );
790 AppendMenu32A(frame->wIDmenu,MF_HELP | MF_BITMAP,
791 SC_CLOSE, (LPSTR)(DWORD)5 );
793 EnableMenuItem32(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
794 EnableMenuItem32(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
795 EnableMenuItem32(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
797 /* redraw menu */
798 DrawMenuBar32(frame->hwndSelf);
800 return 1;
803 /**********************************************************************
804 * MDI_RestoreFrameMenu
806 static BOOL32 MDI_RestoreFrameMenu( WND *frameWnd, HWND32 hChild )
808 INT32 nItems = GetMenuItemCount32(frameWnd->wIDmenu) - 1;
810 TRACE(mdi,"for child %04x\n",hChild);
812 if( GetMenuItemID32(frameWnd->wIDmenu,nItems) != SC_CLOSE )
813 return 0;
815 RemoveMenu32(frameWnd->wIDmenu,0,MF_BYPOSITION);
817 DeleteMenu32(frameWnd->wIDmenu,GetMenuItemCount32(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
818 DeleteMenu32(frameWnd->wIDmenu,GetMenuItemCount32(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
819 DeleteMenu32(frameWnd->wIDmenu,GetMenuItemCount32(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
823 DrawMenuBar32(frameWnd->hwndSelf);
825 return 1;
828 /**********************************************************************
829 * MDI_UpdateFrameText
831 * used when child window is maximized/restored
833 * Note: lpTitle can be NULL
835 static void MDI_UpdateFrameText( WND *frameWnd, HWND32 hClient,
836 BOOL32 repaint, LPCSTR lpTitle )
838 char lpBuffer[MDI_MAXTITLELENGTH+1];
839 WND* clientWnd = WIN_FindWndPtr(hClient);
840 MDICLIENTINFO *ci = (MDICLIENTINFO *) clientWnd->wExtra;
842 TRACE(mdi, "repaint %i, frameText %s\n", repaint, (lpTitle)?lpTitle:"NULL");
844 if (!clientWnd)
845 return;
847 if (!ci)
848 return;
850 /* store new "default" title if lpTitle is not NULL */
851 if (lpTitle)
853 if (ci->frameTitle) HeapFree( SystemHeap, 0, ci->frameTitle );
854 ci->frameTitle = HEAP_strdupA( SystemHeap, 0, lpTitle );
857 if (ci->frameTitle)
859 WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );
861 if( childWnd && childWnd->text )
863 /* combine frame title and child title if possible */
865 LPCSTR lpBracket = " - [";
866 int i_frame_text_length = strlen(ci->frameTitle);
867 int i_child_text_length = strlen(childWnd->text);
869 lstrcpyn32A( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
871 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
873 strcat( lpBuffer, lpBracket );
875 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
877 strcat( lpBuffer, childWnd->text );
878 strcat( lpBuffer, "]" );
880 else
882 lstrcpyn32A( lpBuffer + i_frame_text_length + 4,
883 childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
884 strcat( lpBuffer, "]" );
888 else
890 strncpy(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH );
891 lpBuffer[MDI_MAXTITLELENGTH]='\0';
894 else
895 lpBuffer[0] = '\0';
897 DEFWND_SetText( frameWnd, lpBuffer );
898 if( repaint == MDI_REPAINTFRAME)
899 SetWindowPos32( frameWnd->hwndSelf, 0,0,0,0,0, SWP_FRAMECHANGED |
900 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
904 /* ----------------------------- Interface ---------------------------- */
907 /**********************************************************************
908 * MDIClientWndProc
910 * This function handles all MDI requests.
912 LRESULT WINAPI MDIClientWndProc( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
913 LPARAM lParam )
915 LPCREATESTRUCT32A cs;
916 MDICLIENTINFO *ci;
917 RECT32 rect;
918 WND *w = WIN_FindWndPtr(hwnd);
919 WND *frameWnd = w->parent;
920 INT32 nItems;
922 ci = (MDICLIENTINFO *) w->wExtra;
924 switch (message)
926 case WM_CREATE:
928 cs = (LPCREATESTRUCT32A)lParam;
930 /* Translation layer doesn't know what's in the cs->lpCreateParams
931 * so we have to keep track of what environment we're in. */
933 if( w->flags & WIN_ISWIN32 )
935 #define ccs ((LPCLIENTCREATESTRUCT32)cs->lpCreateParams)
936 ci->hWindowMenu = ccs->hWindowMenu;
937 ci->idFirstChild = ccs->idFirstChild;
938 #undef ccs
940 else
942 LPCLIENTCREATESTRUCT16 ccs = (LPCLIENTCREATESTRUCT16)
943 PTR_SEG_TO_LIN(cs->lpCreateParams);
944 ci->hWindowMenu = ccs->hWindowMenu;
945 ci->idFirstChild = ccs->idFirstChild;
948 ci->hwndChildMaximized = 0;
949 ci->nActiveChildren = 0;
950 ci->nTotalCreated = 0;
951 ci->frameTitle = NULL;
952 ci->mdiFlags = 0;
953 ci->self = hwnd;
954 w->dwStyle |= WS_CLIPCHILDREN;
956 if (!hBmpClose)
958 hBmpClose = CreateMDIMenuBitmap();
959 hBmpRestore = LoadBitmap16( 0, MAKEINTRESOURCE16(OBM_RESTORE) );
961 MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
963 AppendMenu32A( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
965 GetClientRect32(frameWnd->hwndSelf, &rect);
966 NC_HandleNCCalcSize( w, &rect );
967 w->rectClient = rect;
969 TRACE(mdi,"Client created - hwnd = %04x, idFirst = %u\n",
970 hwnd, ci->idFirstChild );
972 return 0;
974 case WM_DESTROY:
975 if( ci->hwndChildMaximized ) MDI_RestoreFrameMenu(w, frameWnd->hwndSelf);
976 if((nItems = GetMenuItemCount32(ci->hWindowMenu)) > 0)
978 ci->idFirstChild = nItems - 1;
979 ci->nActiveChildren++; /* to delete a separator */
980 while( ci->nActiveChildren-- )
981 DeleteMenu32(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
983 return 0;
985 case WM_MDIACTIVATE:
986 if( ci->hwndActiveChild != (HWND32)wParam )
987 SetWindowPos32((HWND32)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
988 return 0;
990 case WM_MDICASCADE:
991 return MDICascade(w, ci);
993 case WM_MDICREATE:
994 if (lParam) return MDICreateChild( w, ci, hwnd,
995 (MDICREATESTRUCT32A*)lParam );
996 return 0;
998 case WM_MDIDESTROY:
999 return MDIDestroyChild( w, ci, hwnd, (HWND32)wParam, TRUE );
1001 case WM_MDIGETACTIVE:
1002 if (lParam) *(BOOL32 *)lParam = (ci->hwndChildMaximized > 0);
1003 return ci->hwndActiveChild;
1005 case WM_MDIICONARRANGE:
1006 ci->mdiFlags |= MDIF_NEEDUPDATE;
1007 ArrangeIconicWindows32(hwnd);
1008 ci->sbRecalc = SB_BOTH+1;
1009 SendMessage32A(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
1010 return 0;
1012 case WM_MDIMAXIMIZE:
1013 ShowWindow32( (HWND32)wParam, SW_MAXIMIZE );
1014 return 0;
1016 case WM_MDINEXT: /* lParam != 0 means previous window */
1017 MDI_SwitchActiveChild(hwnd, (HWND32)wParam, (lParam)? FALSE : TRUE );
1018 break;
1020 case WM_MDIRESTORE:
1021 SendMessage32A( (HWND32)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
1022 return 0;
1024 case WM_MDISETMENU:
1025 return MDISetMenu( hwnd, (HMENU32)wParam, (HMENU32)lParam );
1027 case WM_MDIREFRESHMENU:
1028 return MDIRefreshMenu( hwnd, (HMENU32)wParam, (HMENU32)lParam );
1030 case WM_MDITILE:
1031 ci->mdiFlags |= MDIF_NEEDUPDATE;
1032 ShowScrollBar32(hwnd,SB_BOTH,FALSE);
1033 MDITile(w, ci, wParam);
1034 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1035 return 0;
1037 case WM_VSCROLL:
1038 case WM_HSCROLL:
1039 ci->mdiFlags |= MDIF_NEEDUPDATE;
1040 ScrollChildren32(hwnd, message, wParam, lParam);
1041 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1042 return 0;
1044 case WM_SETFOCUS:
1045 if( ci->hwndActiveChild )
1047 w = WIN_FindWndPtr( ci->hwndActiveChild );
1048 if( !(w->dwStyle & WS_MINIMIZE) )
1049 SetFocus32( ci->hwndActiveChild );
1051 return 0;
1053 case WM_NCACTIVATE:
1054 if( ci->hwndActiveChild )
1055 SendMessage32A(ci->hwndActiveChild, message, wParam, lParam);
1056 break;
1058 case WM_PARENTNOTIFY:
1059 if (LOWORD(wParam) == WM_LBUTTONDOWN)
1061 POINT16 pt = MAKEPOINT16(lParam);
1062 HWND16 child = ChildWindowFromPoint16(hwnd, pt);
1064 TRACE(mdi,"notification from %04x (%i,%i)\n",child,pt.x,pt.y);
1066 if( child && child != hwnd && child != ci->hwndActiveChild )
1067 SetWindowPos32(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1069 return 0;
1071 case WM_SIZE:
1072 if( IsWindow32(ci->hwndChildMaximized) )
1074 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1075 RECT32 rect = { 0, 0, LOWORD(lParam), HIWORD(lParam) };
1077 AdjustWindowRectEx32(&rect, child->dwStyle, 0, child->dwExStyle);
1078 MoveWindow32(ci->hwndChildMaximized, rect.left, rect.top,
1079 rect.right - rect.left, rect.bottom - rect.top, 1);
1081 else
1082 MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1084 break;
1086 case WM_MDICALCCHILDSCROLL:
1087 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1089 CalcChildScroll(hwnd, ci->sbRecalc-1);
1090 ci->sbRecalc = 0;
1091 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1093 return 0;
1096 return DefWindowProc32A( hwnd, message, wParam, lParam );
1100 /***********************************************************************
1101 * DefFrameProc16 (USER.445)
1103 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1104 UINT16 message, WPARAM16 wParam, LPARAM lParam )
1106 HWND16 childHwnd;
1107 MDICLIENTINFO* ci;
1108 WND* wndPtr;
1110 if (hwndMDIClient)
1112 switch (message)
1114 case WM_COMMAND:
1115 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1116 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1118 /* check for possible syscommands for maximized MDI child */
1120 if( ci && (
1121 wParam < ci->idFirstChild ||
1122 wParam >= ci->idFirstChild + ci->nActiveChildren
1124 if( (wParam - 0xF000) & 0xF00F ) break;
1125 switch( wParam )
1127 case SC_SIZE:
1128 case SC_MOVE:
1129 case SC_MINIMIZE:
1130 case SC_MAXIMIZE:
1131 case SC_NEXTWINDOW:
1132 case SC_PREVWINDOW:
1133 case SC_CLOSE:
1134 case SC_RESTORE:
1135 if( ci->hwndChildMaximized )
1136 return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1137 wParam, lParam);
1140 else
1142 childHwnd = MDI_GetChildByID( WIN_FindWndPtr(hwndMDIClient),
1143 wParam );
1144 if( childHwnd )
1145 SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1146 (WPARAM16)childHwnd , 0L);
1148 break;
1150 case WM_NCACTIVATE:
1151 SendMessage16(hwndMDIClient, message, wParam, lParam);
1152 break;
1154 case WM_SETTEXT:
1155 MDI_UpdateFrameText(WIN_FindWndPtr(hwnd), hwndMDIClient,
1156 MDI_REPAINTFRAME,
1157 (LPCSTR)PTR_SEG_TO_LIN(lParam));
1158 return 0;
1160 case WM_SETFOCUS:
1161 SetFocus32(hwndMDIClient);
1162 break;
1164 case WM_SIZE:
1165 MoveWindow16(hwndMDIClient, 0, 0,
1166 LOWORD(lParam), HIWORD(lParam), TRUE);
1167 break;
1169 case WM_NEXTMENU:
1171 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1172 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1174 if( !(wndPtr->parent->dwStyle & WS_MINIMIZE)
1175 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1177 /* control menu is between the frame system menu and
1178 * the first entry of menu bar */
1180 if( (wParam == VK_LEFT &&
1181 wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1182 (wParam == VK_RIGHT &&
1183 GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1185 wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1186 return MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1187 ci->hwndActiveChild);
1190 break;
1194 return DefWindowProc16(hwnd, message, wParam, lParam);
1198 /***********************************************************************
1199 * DefFrameProc32A (USER32.122)
1201 LRESULT WINAPI DefFrameProc32A( HWND32 hwnd, HWND32 hwndMDIClient,
1202 UINT32 message, WPARAM32 wParam, LPARAM lParam)
1204 if (hwndMDIClient)
1206 switch (message)
1208 case WM_COMMAND:
1209 return DefFrameProc16( hwnd, hwndMDIClient, message,
1210 (WPARAM16)wParam,
1211 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1213 case WM_NCACTIVATE:
1214 SendMessage32A(hwndMDIClient, message, wParam, lParam);
1215 break;
1217 case WM_SETTEXT: {
1218 LRESULT ret;
1219 LPSTR segstr = SEGPTR_STRDUP((LPSTR)lParam);
1221 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1222 wParam, (LPARAM)SEGPTR_GET(segstr) );
1223 SEGPTR_FREE(segstr);
1224 return ret;
1227 case WM_NEXTMENU:
1228 case WM_SETFOCUS:
1229 case WM_SIZE:
1230 return DefFrameProc16( hwnd, hwndMDIClient, message,
1231 wParam, lParam );
1235 return DefWindowProc32A(hwnd, message, wParam, lParam);
1239 /***********************************************************************
1240 * DefFrameProc32W (USER32.123)
1242 LRESULT WINAPI DefFrameProc32W( HWND32 hwnd, HWND32 hwndMDIClient,
1243 UINT32 message, WPARAM32 wParam, LPARAM lParam)
1245 if (hwndMDIClient)
1247 switch (message)
1249 case WM_COMMAND:
1250 return DefFrameProc16( hwnd, hwndMDIClient, message,
1251 (WPARAM16)wParam,
1252 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1254 case WM_NCACTIVATE:
1255 SendMessage32W(hwndMDIClient, message, wParam, lParam);
1256 break;
1258 case WM_SETTEXT:
1260 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1261 LRESULT ret = DefFrameProc32A( hwnd, hwndMDIClient, message,
1262 wParam, (DWORD)txt );
1263 HeapFree(GetProcessHeap(),0,txt);
1264 return ret;
1266 case WM_NEXTMENU:
1267 case WM_SETFOCUS:
1268 case WM_SIZE:
1269 return DefFrameProc32A( hwnd, hwndMDIClient, message,
1270 wParam, lParam );
1274 return DefWindowProc32W( hwnd, message, wParam, lParam );
1278 /***********************************************************************
1279 * DefMDIChildProc16 (USER.447)
1281 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1282 WPARAM16 wParam, LPARAM lParam )
1284 MDICLIENTINFO *ci;
1285 WND *clientWnd;
1287 clientWnd = WIN_FindWndPtr(GetParent16(hwnd));
1288 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1290 switch (message)
1292 case WM_SETTEXT:
1293 DefWindowProc16(hwnd, message, wParam, lParam);
1294 MDI_MenuModifyItem(clientWnd,hwnd);
1295 if( ci->hwndChildMaximized == hwnd )
1296 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1297 MDI_REPAINTFRAME, NULL );
1298 return 0;
1300 case WM_CLOSE:
1301 SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1302 return 0;
1304 case WM_SETFOCUS:
1305 if( ci->hwndActiveChild != hwnd )
1306 MDI_ChildActivate(clientWnd, hwnd);
1307 break;
1309 case WM_CHILDACTIVATE:
1310 MDI_ChildActivate(clientWnd, hwnd);
1311 return 0;
1313 case WM_NCPAINT:
1314 TRACE(mdi,"WM_NCPAINT for %04x, active %04x\n",
1315 hwnd, ci->hwndActiveChild );
1316 break;
1318 case WM_SYSCOMMAND:
1319 switch( wParam )
1321 case SC_MOVE:
1322 if( ci->hwndChildMaximized == hwnd) return 0;
1323 break;
1324 case SC_RESTORE:
1325 case SC_MINIMIZE:
1326 WIN_FindWndPtr(hwnd)->dwStyle |= WS_SYSMENU;
1327 break;
1328 case SC_MAXIMIZE:
1329 if( ci->hwndChildMaximized == hwnd)
1330 return SendMessage16( clientWnd->parent->hwndSelf,
1331 message, wParam, lParam);
1332 WIN_FindWndPtr(hwnd)->dwStyle &= ~WS_SYSMENU;
1333 break;
1334 case SC_NEXTWINDOW:
1335 SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1336 return 0;
1337 case SC_PREVWINDOW:
1338 SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1339 return 0;
1341 break;
1343 case WM_GETMINMAXINFO:
1344 MDI_ChildGetMinMaxInfo(clientWnd, hwnd, (MINMAXINFO16*) PTR_SEG_TO_LIN(lParam));
1345 return 0;
1347 case WM_SETVISIBLE:
1348 if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1349 else
1350 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1351 break;
1353 case WM_SIZE:
1354 /* do not change */
1356 if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1358 ci->hwndChildMaximized = 0;
1360 MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1361 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1362 MDI_REPAINTFRAME, NULL );
1365 if( wParam == SIZE_MAXIMIZED )
1367 HWND16 hMaxChild = ci->hwndChildMaximized;
1369 if( hMaxChild == hwnd ) break;
1371 if( hMaxChild)
1373 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1375 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1376 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1378 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1381 TRACE(mdi,"maximizing child %04x\n", hwnd );
1383 ci->hwndChildMaximized = hwnd; /* !!! */
1385 MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1386 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1387 MDI_REPAINTFRAME, NULL );
1390 if( wParam == SIZE_MINIMIZED )
1392 HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1394 if( switchTo )
1395 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1398 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1399 break;
1401 case WM_MENUCHAR:
1403 /* MDI children don't have menu bars */
1404 PostMessage16( clientWnd->parent->hwndSelf, WM_SYSCOMMAND,
1405 (WPARAM16)SC_KEYMENU, (LPARAM)wParam);
1406 return 0x00010000L;
1408 case WM_NEXTMENU:
1410 if( wParam == VK_LEFT ) /* switch to frame system menu */
1411 return MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1412 clientWnd->parent->hwndSelf );
1413 if( wParam == VK_RIGHT ) /* to frame menu bar */
1414 return MAKELONG( clientWnd->parent->wIDmenu,
1415 clientWnd->parent->hwndSelf );
1417 break;
1419 case WM_SYSCHAR:
1420 if (wParam == '-')
1422 SendMessage16(hwnd,WM_SYSCOMMAND,
1423 (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1424 return 0;
1428 return DefWindowProc16(hwnd, message, wParam, lParam);
1432 /***********************************************************************
1433 * DefMDIChildProc32A (USER32.124)
1435 LRESULT WINAPI DefMDIChildProc32A( HWND32 hwnd, UINT32 message,
1436 WPARAM32 wParam, LPARAM lParam )
1438 MDICLIENTINFO *ci;
1439 WND *clientWnd;
1441 clientWnd = WIN_FindWndPtr(WIN_FindWndPtr(hwnd)->parent->hwndSelf);
1442 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1444 switch (message)
1446 case WM_SETTEXT:
1447 DefWindowProc32A(hwnd, message, wParam, lParam);
1448 MDI_MenuModifyItem(clientWnd,hwnd);
1449 if( ci->hwndChildMaximized == hwnd )
1450 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1451 MDI_REPAINTFRAME, NULL );
1452 return 0;
1454 case WM_GETMINMAXINFO:
1456 MINMAXINFO16 mmi;
1457 STRUCT32_MINMAXINFO32to16( (MINMAXINFO32 *)lParam, &mmi );
1458 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1459 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO32 *)lParam );
1461 return 0;
1463 case WM_MENUCHAR:
1465 /* MDI children don't have menu bars */
1466 PostMessage16( clientWnd->parent->hwndSelf, WM_SYSCOMMAND,
1467 (WPARAM16)SC_KEYMENU, (LPARAM)LOWORD(wParam) );
1468 return 0x00010000L;
1470 case WM_CLOSE:
1471 case WM_SETFOCUS:
1472 case WM_CHILDACTIVATE:
1473 case WM_NCPAINT:
1474 case WM_SYSCOMMAND:
1475 case WM_SETVISIBLE:
1476 case WM_SIZE:
1477 case WM_NEXTMENU:
1478 return DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1480 case WM_SYSCHAR:
1481 if (wParam == '-')
1483 SendMessage32A(hwnd,WM_SYSCOMMAND,
1484 (WPARAM32)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1485 return 0;
1488 return DefWindowProc32A(hwnd, message, wParam, lParam);
1492 /***********************************************************************
1493 * DefMDIChildProc32W (USER32.125)
1495 LRESULT WINAPI DefMDIChildProc32W( HWND32 hwnd, UINT32 message,
1496 WPARAM32 wParam, LPARAM lParam )
1498 MDICLIENTINFO *ci;
1499 WND *clientWnd;
1501 clientWnd = WIN_FindWndPtr(GetParent16(hwnd));
1502 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1504 switch (message)
1506 case WM_SETTEXT:
1507 DefWindowProc32W(hwnd, message, wParam, lParam);
1508 MDI_MenuModifyItem(clientWnd,hwnd);
1509 if( ci->hwndChildMaximized == hwnd )
1510 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1511 MDI_REPAINTFRAME, NULL );
1512 return 0;
1514 case WM_GETMINMAXINFO:
1515 case WM_MENUCHAR:
1516 case WM_CLOSE:
1517 case WM_SETFOCUS:
1518 case WM_CHILDACTIVATE:
1519 case WM_NCPAINT:
1520 case WM_SYSCOMMAND:
1521 case WM_SETVISIBLE:
1522 case WM_SIZE:
1523 case WM_NEXTMENU:
1524 return DefMDIChildProc32A( hwnd, message, (WPARAM16)wParam, lParam );
1526 case WM_SYSCHAR:
1527 if (wParam == '-')
1529 SendMessage32W(hwnd,WM_SYSCOMMAND,
1530 (WPARAM32)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1531 return 0;
1534 return DefWindowProc32W(hwnd, message, wParam, lParam);
1538 /**********************************************************************
1539 * CreateMDIWindowA [USER32.79] Creates a MDI child in new thread
1540 * FIXME: its in the same thread now
1542 * RETURNS
1543 * Success: Handle to created window
1544 * Failure: NULL
1546 HWND32 WINAPI CreateMDIWindow32A(
1547 LPCSTR lpClassName, /* [in] Pointer to registered child class name */
1548 LPCSTR lpWindowName, /* [in] Pointer to window name */
1549 DWORD dwStyle, /* [in] Window style */
1550 INT32 X, /* [in] Horizontal position of window */
1551 INT32 Y, /* [in] Vertical position of window */
1552 INT32 nWidth, /* [in] Width of window */
1553 INT32 nHeight, /* [in] Height of window */
1554 HWND32 hWndParent, /* [in] Handle to parent window */
1555 HINSTANCE32 hInstance, /* [in] Handle to application instance */
1556 LPARAM lParam) /* [in] Application-defined value */
1558 WARN(mdi,"is only single threaded!\n");
1559 return MDI_CreateMDIWindow32A(lpClassName, lpWindowName, dwStyle, X, Y,
1560 nWidth, nHeight, hWndParent, hInstance, lParam);
1563 /**********************************************************************
1564 * MDI_CreateMDIWindowA
1565 * single threaded version of CreateMDIWindowA
1566 * called by CreateWindowEx32A
1568 HWND32 MDI_CreateMDIWindow32A(
1569 LPCSTR lpClassName,
1570 LPCSTR lpWindowName,
1571 DWORD dwStyle,
1572 INT32 X,
1573 INT32 Y,
1574 INT32 nWidth,
1575 INT32 nHeight,
1576 HWND32 hWndParent,
1577 HINSTANCE32 hInstance,
1578 LPARAM lParam)
1580 MDICLIENTINFO* pCi;
1581 MDICREATESTRUCT32A cs;
1582 WND *pWnd=WIN_FindWndPtr(hWndParent);
1584 TRACE(mdi, "(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
1585 debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
1586 nWidth,nHeight,hWndParent,hInstance,lParam);
1588 if(!pWnd){
1589 ERR(mdi," bad hwnd for MDI-client: %d\n",hWndParent);
1590 return 0;
1592 cs.szClass=lpClassName;
1593 cs.szTitle=lpWindowName;
1594 cs.hOwner=hInstance;
1595 cs.x=X;
1596 cs.y=Y;
1597 cs.cx=nWidth;
1598 cs.cy=nHeight;
1599 cs.style=dwStyle;
1600 cs.lParam=lParam;
1602 pCi=(MDICLIENTINFO *)pWnd->wExtra;
1604 return MDICreateChild(pWnd,pCi,hWndParent,&cs);
1607 /***************************************
1608 * CreateMDIWindow32W [USER32.80] Creates a MDI child in new thread
1610 * RETURNS
1611 * Success: Handle to created window
1612 * Failure: NULL
1614 HWND32 WINAPI CreateMDIWindow32W(
1615 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1616 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1617 DWORD dwStyle, /* [in] Window style */
1618 INT32 X, /* [in] Horizontal position of window */
1619 INT32 Y, /* [in] Vertical position of window */
1620 INT32 nWidth, /* [in] Width of window */
1621 INT32 nHeight, /* [in] Height of window */
1622 HWND32 hWndParent, /* [in] Handle to parent window */
1623 HINSTANCE32 hInstance, /* [in] Handle to application instance */
1624 LPARAM lParam) /* [in] Application-defined value */
1626 FIXME(mdi, "(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1627 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1628 nWidth,nHeight,hWndParent,hInstance,lParam);
1629 return (HWND32)NULL;
1633 /******************************************************************************
1634 * CreateMDIWindow32W [USER32.80] Creates a MDI child window
1635 * single threaded version of CreateMDIWindow
1636 * called by CreateWindowEx32W().
1638 HWND32 MDI_CreateMDIWindow32W(
1639 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1640 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1641 DWORD dwStyle, /* [in] Window style */
1642 INT32 X, /* [in] Horizontal position of window */
1643 INT32 Y, /* [in] Vertical position of window */
1644 INT32 nWidth, /* [in] Width of window */
1645 INT32 nHeight, /* [in] Height of window */
1646 HWND32 hWndParent, /* [in] Handle to parent window */
1647 HINSTANCE32 hInstance, /* [in] Handle to application instance */
1648 LPARAM lParam) /* [in] Application-defined value */
1650 FIXME(mdi, "(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1651 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1652 nWidth,nHeight,hWndParent,hInstance,lParam);
1653 return (HWND32)NULL;
1657 /**********************************************************************
1658 * TranslateMDISysAccel32 (USER32.555)
1660 BOOL32 WINAPI TranslateMDISysAccel32( HWND32 hwndClient, LPMSG32 msg )
1662 MSG16 msg16;
1664 STRUCT32_MSG32to16(msg,&msg16);
1665 /* MDICLIENTINFO is still the same for win32 and win16 ... */
1666 return TranslateMDISysAccel16(hwndClient,&msg16);
1670 /**********************************************************************
1671 * TranslateMDISysAccel16 (USER.451)
1673 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
1675 WND* clientWnd = WIN_FindWndPtr( hwndClient);
1677 if( clientWnd && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
1679 MDICLIENTINFO *ci = NULL;
1680 WND* wnd;
1682 ci = (MDICLIENTINFO*) clientWnd->wExtra;
1683 wnd = WIN_FindWndPtr(ci->hwndActiveChild);
1684 if( wnd && !(wnd->dwStyle & WS_DISABLED) )
1686 WPARAM16 wParam = 0;
1688 /* translate if the Ctrl key is down and Alt not. */
1690 if( (GetKeyState32(VK_CONTROL) & 0x8000) &&
1691 !(GetKeyState32(VK_MENU) & 0x8000))
1693 switch( msg->wParam )
1695 case VK_F6:
1696 case VK_TAB:
1697 wParam = ( GetKeyState32(VK_SHIFT) & 0x8000 )
1698 ? SC_NEXTWINDOW : SC_PREVWINDOW;
1699 break;
1700 case VK_F4:
1701 case VK_RBUTTON:
1702 wParam = SC_CLOSE;
1703 break;
1704 default:
1705 return 0;
1707 TRACE(mdi,"wParam = %04x\n", wParam);
1708 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
1709 wParam, (LPARAM)msg->wParam);
1710 return 1;
1714 return 0; /* failure */
1718 /***********************************************************************
1719 * CalcChildScroll (USER.462)
1721 void WINAPI CalcChildScroll( HWND16 hwnd, WORD scroll )
1723 SCROLLINFO info;
1724 RECT32 childRect, clientRect;
1725 INT32 vmin, vmax, hmin, hmax, vpos, hpos;
1726 WND *pWnd, *Wnd;
1728 if (!(Wnd = pWnd = WIN_FindWndPtr( hwnd ))) return;
1729 GetClientRect32( hwnd, &clientRect );
1730 SetRectEmpty32( &childRect );
1732 for ( pWnd = pWnd->child; pWnd; pWnd = pWnd->next )
1734 if( pWnd->dwStyle & WS_MAXIMIZE )
1736 ShowScrollBar32(hwnd, SB_BOTH, FALSE);
1737 return;
1739 UnionRect32( &childRect, &pWnd->rectWindow, &childRect );
1741 UnionRect32( &childRect, &clientRect, &childRect );
1743 hmin = childRect.left; hmax = childRect.right - clientRect.right;
1744 hpos = clientRect.left - childRect.left;
1745 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
1746 vpos = clientRect.top - childRect.top;
1748 switch( scroll )
1750 case SB_HORZ:
1751 vpos = hpos; vmin = hmin; vmax = hmax;
1752 case SB_VERT:
1753 info.cbSize = sizeof(info);
1754 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
1755 info.fMask = SIF_POS | SIF_RANGE;
1756 SetScrollInfo32(hwnd, scroll, &info, TRUE);
1757 break;
1758 case SB_BOTH:
1759 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
1760 hmin, hmax, hpos);
1765 /***********************************************************************
1766 * ScrollChildren16 (USER.463)
1768 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
1770 return ScrollChildren32( hWnd, uMsg, wParam, lParam );
1774 /***********************************************************************
1775 * ScrollChildren32 (USER32.448)
1777 void WINAPI ScrollChildren32(HWND32 hWnd, UINT32 uMsg, WPARAM32 wParam,
1778 LPARAM lParam)
1780 WND *wndPtr = WIN_FindWndPtr(hWnd);
1781 INT32 newPos = -1;
1782 INT32 curPos, length, minPos, maxPos, shift;
1784 if( !wndPtr ) return;
1786 if( uMsg == WM_HSCROLL )
1788 GetScrollRange32(hWnd,SB_HORZ,&minPos,&maxPos);
1789 curPos = GetScrollPos32(hWnd,SB_HORZ);
1790 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
1791 shift = SYSMETRICS_CYHSCROLL;
1793 else if( uMsg == WM_VSCROLL )
1795 GetScrollRange32(hWnd,SB_VERT,&minPos,&maxPos);
1796 curPos = GetScrollPos32(hWnd,SB_VERT);
1797 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
1798 shift = SYSMETRICS_CXVSCROLL;
1800 else return;
1802 switch( wParam )
1804 case SB_LINEUP:
1805 newPos = curPos - shift;
1806 break;
1807 case SB_LINEDOWN:
1808 newPos = curPos + shift;
1809 break;
1810 case SB_PAGEUP:
1811 newPos = curPos - length;
1812 break;
1813 case SB_PAGEDOWN:
1814 newPos = curPos + length;
1815 break;
1817 case SB_THUMBPOSITION:
1818 newPos = LOWORD(lParam);
1819 break;
1821 case SB_THUMBTRACK:
1822 return;
1824 case SB_TOP:
1825 newPos = minPos;
1826 break;
1827 case SB_BOTTOM:
1828 newPos = maxPos;
1829 break;
1830 case SB_ENDSCROLL:
1831 CalcChildScroll(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
1832 return;
1835 if( newPos > maxPos )
1836 newPos = maxPos;
1837 else
1838 if( newPos < minPos )
1839 newPos = minPos;
1841 SetScrollPos32(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
1843 if( uMsg == WM_VSCROLL )
1844 ScrollWindowEx32(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
1845 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1846 else
1847 ScrollWindowEx32(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
1848 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1852 /******************************************************************************
1853 * CascadeWindows [USER32.21] Cascades MDI child windows
1855 * RETURNS
1856 * Success: Number of cascaded windows.
1857 * Failure: 0
1859 WORD WINAPI
1860 CascadeWindows (HWND32 hwndParent, UINT32 wFlags, const LPRECT32 lpRect,
1861 UINT32 cKids, const HWND32 *lpKids)
1863 FIXME (mdi, "(0x%08x,0x%08x,...,%u,...): stub\n",
1864 hwndParent, wFlags, cKids);
1866 return 0;
1870 /******************************************************************************
1871 * TileWindows [USER32.545] Tiles MDI child windows
1873 * RETURNS
1874 * Success: Number of tiled windows.
1875 * Failure: 0
1877 WORD WINAPI
1878 TileWindows (HWND32 hwndParent, UINT32 wFlags, const LPRECT32 lpRect,
1879 UINT32 cKids, const HWND32 *lpKids)
1881 FIXME (mdi, "(0x%08x,0x%08x,...,%u,...): stub\n",
1882 hwndParent, wFlags, cKids);
1884 return 0;