Release 980913
[wine/multimedia.git] / windows / mdi.c
blobf38c164c09549eb49e7ba58fc53eb2a74c3bfa63
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 DWORD 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,"partial 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 SetWindowPos32( hwnd, 0, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE );
361 /* Set maximized state here in case hwnd didn't receive WM_SIZE
362 * during CreateWindow - bad!
365 if((wnd->dwStyle & WS_MAXIMIZE) && !ci->hwndChildMaximized )
367 ci->hwndChildMaximized = wnd->hwndSelf;
368 MDI_AugmentFrameMenu( ci, w->parent, hwnd );
369 MDI_UpdateFrameText( w->parent, ci->self, MDI_REPAINTFRAME, NULL );
372 TRACE(mdi, "created child - %04x\n",hwnd);
374 else
376 ci->nActiveChildren--;
377 DeleteMenu32(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
378 if( IsWindow32(hwndMax) )
379 ShowWindow32(hwndMax, SW_SHOWMAXIMIZED);
382 return hwnd;
385 /**********************************************************************
386 * MDI_ChildGetMinMaxInfo
388 * Note: The rule here is that client rect of the maximized MDI child
389 * is equal to the client rect of the MDI client window.
391 static void MDI_ChildGetMinMaxInfo( WND* clientWnd, HWND32 hwnd,
392 MINMAXINFO16* lpMinMax )
394 WND* childWnd = WIN_FindWndPtr(hwnd);
395 RECT32 rect = clientWnd->rectClient;
397 MapWindowPoints32( clientWnd->parent->hwndSelf,
398 ((MDICLIENTINFO*)clientWnd->wExtra)->self, (LPPOINT32)&rect, 2);
399 AdjustWindowRectEx32( &rect, childWnd->dwStyle, 0, childWnd->dwExStyle );
401 lpMinMax->ptMaxSize.x = rect.right -= rect.left;
402 lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
404 lpMinMax->ptMaxPosition.x = rect.left;
405 lpMinMax->ptMaxPosition.y = rect.top;
407 TRACE(mdi,"max rect (%i,%i - %i, %i)\n",
408 rect.left,rect.top,rect.right,rect.bottom);
411 /**********************************************************************
412 * MDI_SwitchActiveChild
414 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
415 * being activated
417 static void MDI_SwitchActiveChild( HWND32 clientHwnd, HWND32 childHwnd,
418 BOOL32 bNextWindow )
420 WND *w = WIN_FindWndPtr(clientHwnd);
421 HWND32 hwndTo = 0;
422 HWND32 hwndPrev = 0;
423 MDICLIENTINFO *ci;
425 hwndTo = MDI_GetWindow(w, childHwnd, bNextWindow, 0);
427 ci = (MDICLIENTINFO *) w->wExtra;
429 TRACE(mdi, "from %04x, to %04x\n",childHwnd,hwndTo);
431 if ( !hwndTo ) return; /* no window to switch to */
433 hwndPrev = ci->hwndActiveChild;
435 if ( hwndTo != hwndPrev )
437 BOOL32 bOptimize = 0;
439 if( ci->hwndChildMaximized )
441 bOptimize = 1;
442 w->dwStyle &= ~WS_VISIBLE;
445 SetWindowPos32( hwndTo, HWND_TOP, 0, 0, 0, 0,
446 SWP_NOMOVE | SWP_NOSIZE );
448 if( bNextWindow && hwndPrev )
449 SetWindowPos32( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0,
450 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
451 if( bOptimize )
452 ShowWindow32( clientHwnd, SW_SHOW );
457 /**********************************************************************
458 * MDIDestroyChild
460 static LRESULT MDIDestroyChild( WND *w_parent, MDICLIENTINFO *ci,
461 HWND32 parent, HWND32 child,
462 BOOL32 flagDestroy )
464 WND *childPtr = WIN_FindWndPtr(child);
466 if( childPtr )
468 if( child == ci->hwndActiveChild )
470 MDI_SwitchActiveChild(parent, child, TRUE);
472 if( child == ci->hwndActiveChild )
474 ShowWindow32( child, SW_HIDE);
475 if( child == ci->hwndChildMaximized )
477 MDI_RestoreFrameMenu(w_parent->parent, child);
478 ci->hwndChildMaximized = 0;
479 MDI_UpdateFrameText(w_parent->parent,parent,TRUE,NULL);
482 MDI_ChildActivate(w_parent, 0);
484 MDI_MenuDeleteItem(w_parent, child);
487 ci->nActiveChildren--;
489 TRACE(mdi,"child destroyed - %04x\n",child);
491 if (flagDestroy)
493 MDI_PostUpdate(GetParent32(child), ci, SB_BOTH+1);
494 DestroyWindow32(child);
498 return 0;
502 /**********************************************************************
503 * MDI_ChildActivate
505 * Note: hWndChild is NULL when last child is being destroyed
507 static LONG MDI_ChildActivate( WND *clientPtr, HWND32 hWndChild )
509 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientPtr->wExtra;
510 HWND32 prevActiveWnd = clientInfo->hwndActiveChild;
511 WND *wndPtr = WIN_FindWndPtr( hWndChild );
512 WND *wndPrev = WIN_FindWndPtr( prevActiveWnd );
513 BOOL32 isActiveFrameWnd = 0;
515 if( hWndChild == prevActiveWnd ) return 0L;
517 if( wndPtr )
518 if( wndPtr->dwStyle & WS_DISABLED ) return 0L;
520 TRACE(mdi,"%04x\n", hWndChild);
522 if( GetActiveWindow32() == clientPtr->parent->hwndSelf )
523 isActiveFrameWnd = TRUE;
525 /* deactivate prev. active child */
526 if( wndPrev )
528 wndPrev->dwStyle |= WS_SYSMENU;
529 SendMessage32A( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
530 SendMessage32A( prevActiveWnd, WM_MDIACTIVATE, (WPARAM32)prevActiveWnd,
531 (LPARAM)hWndChild);
532 /* uncheck menu item */
533 if( clientInfo->hWindowMenu )
534 CheckMenuItem32( clientInfo->hWindowMenu,
535 wndPrev->wIDmenu, 0);
538 /* set appearance */
539 if( clientInfo->hwndChildMaximized )
540 if( clientInfo->hwndChildMaximized != hWndChild )
541 if( hWndChild )
543 clientInfo->hwndActiveChild = hWndChild;
544 ShowWindow32( hWndChild, SW_SHOWMAXIMIZED);
546 else
547 ShowWindow32( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
549 clientInfo->hwndActiveChild = hWndChild;
551 /* check if we have any children left */
552 if( !hWndChild )
554 if( isActiveFrameWnd )
555 SetFocus32( clientInfo->self );
556 return 0;
559 /* check menu item */
560 if( clientInfo->hWindowMenu )
561 CheckMenuItem32( clientInfo->hWindowMenu,
562 wndPtr->wIDmenu, MF_CHECKED);
564 /* bring active child to the top */
565 SetWindowPos32( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
567 if( isActiveFrameWnd )
569 SendMessage32A( hWndChild, WM_NCACTIVATE, TRUE, 0L);
570 if( GetFocus32() == clientInfo->self )
571 SendMessage32A( clientInfo->self, WM_SETFOCUS,
572 (WPARAM32)clientInfo->self, 0L );
573 else
574 SetFocus32( clientInfo->self );
576 SendMessage32A( hWndChild, WM_MDIACTIVATE, (WPARAM32)prevActiveWnd,
577 (LPARAM)hWndChild );
578 return 1;
581 /* -------------------- MDI client window functions ------------------- */
583 /**********************************************************************
584 * CreateMDIMenuBitmap
586 static HBITMAP16 CreateMDIMenuBitmap(void)
588 HDC32 hDCSrc = CreateCompatibleDC32(0);
589 HDC32 hDCDest = CreateCompatibleDC32(hDCSrc);
590 HBITMAP16 hbClose = LoadBitmap16(0, MAKEINTRESOURCE16(OBM_CLOSE) );
591 HBITMAP16 hbCopy;
592 HANDLE16 hobjSrc, hobjDest;
594 hobjSrc = SelectObject32(hDCSrc, hbClose);
595 hbCopy = CreateCompatibleBitmap32(hDCSrc,SYSMETRICS_CXSIZE,SYSMETRICS_CYSIZE);
596 hobjDest = SelectObject32(hDCDest, hbCopy);
598 BitBlt32(hDCDest, 0, 0, SYSMETRICS_CXSIZE, SYSMETRICS_CYSIZE,
599 hDCSrc, SYSMETRICS_CXSIZE, 0, SRCCOPY);
601 SelectObject32(hDCSrc, hobjSrc);
602 DeleteObject32(hbClose);
603 DeleteDC32(hDCSrc);
605 hobjSrc = SelectObject32( hDCDest, GetStockObject32(BLACK_PEN) );
607 MoveToEx32( hDCDest, SYSMETRICS_CXSIZE - 1, 0, NULL );
608 LineTo32( hDCDest, SYSMETRICS_CXSIZE - 1, SYSMETRICS_CYSIZE - 1);
610 SelectObject32(hDCDest, hobjSrc );
611 SelectObject32(hDCDest, hobjDest);
612 DeleteDC32(hDCDest);
614 return hbCopy;
617 /**********************************************************************
618 * MDICascade
620 static LONG MDICascade(WND* clientWnd, MDICLIENTINFO *ci)
622 WND** ppWnd;
623 UINT32 total;
625 if (ci->hwndChildMaximized)
626 ShowWindow16( ci->hwndChildMaximized, SW_NORMAL);
628 if (ci->nActiveChildren == 0) return 0;
630 if ((ppWnd = WIN_BuildWinArray(clientWnd, BWA_SKIPHIDDEN | BWA_SKIPOWNED |
631 BWA_SKIPICONIC, &total)))
633 WND** heapPtr = ppWnd;
634 if( total )
636 INT32 delta = 0, n = 0;
637 POINT32 pos[2];
638 if( total < ci->nActiveChildren )
639 delta = SYSMETRICS_CYICONSPACING + SYSMETRICS_CYICON;
641 /* walk the list (backwards) and move windows */
642 while (*ppWnd) ppWnd++;
643 while (ppWnd != heapPtr)
645 ppWnd--;
646 TRACE(mdi, "move %04x to (%d,%d) size [%d,%d]\n",
647 (*ppWnd)->hwndSelf, pos[0].x, pos[0].y, pos[1].x, pos[1].y);
649 MDI_CalcDefaultChildPos(clientWnd, n++, pos, delta);
650 SetWindowPos32( (*ppWnd)->hwndSelf, 0, pos[0].x, pos[0].y,
651 pos[1].x, pos[1].y,
652 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
655 HeapFree( SystemHeap, 0, heapPtr );
658 if( total < ci->nActiveChildren )
659 ArrangeIconicWindows32( clientWnd->hwndSelf );
660 return 0;
663 /**********************************************************************
664 * MDITile
666 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM32 wParam )
668 WND** ppWnd;
669 UINT32 total = 0;
671 if (ci->hwndChildMaximized)
672 ShowWindow32(ci->hwndChildMaximized, SW_NORMAL);
674 if (ci->nActiveChildren == 0) return;
676 ppWnd = WIN_BuildWinArray(wndClient, BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
677 ((wParam & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
679 TRACE(mdi,"%u windows to tile\n", total);
681 if( ppWnd )
683 WND** heapPtr = ppWnd;
685 if( total )
687 RECT32 rect;
688 int x, y, xsize, ysize;
689 int rows, columns, r, c, i;
691 rect = wndClient->rectClient;
692 rows = (int) sqrt((double)total);
693 columns = total / rows;
695 if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */
697 i = rows;
698 rows = columns; /* exchange r and c */
699 columns = i;
702 if( total != ci->nActiveChildren)
704 y = rect.bottom - 2 * SYSMETRICS_CYICONSPACING - SYSMETRICS_CYICON;
705 rect.bottom = ( y - SYSMETRICS_CYICON < rect.top )? rect.bottom: y;
708 ysize = rect.bottom / rows;
709 xsize = rect.right / columns;
711 for (x = i = 0, c = 1; c <= columns && *ppWnd; c++)
713 if (c == columns)
715 rows = total - i;
716 ysize = rect.bottom / rows;
719 y = 0;
720 for (r = 1; r <= rows && *ppWnd; r++, i++)
722 SetWindowPos32((*ppWnd)->hwndSelf, 0, x, y, xsize, ysize,
723 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
724 y += ysize;
725 ppWnd++;
727 x += xsize;
730 HeapFree( SystemHeap, 0, heapPtr );
733 if( total < ci->nActiveChildren ) ArrangeIconicWindows32( wndClient->hwndSelf );
736 /* ----------------------- Frame window ---------------------------- */
739 /**********************************************************************
740 * MDI_AugmentFrameMenu
742 static BOOL32 MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
743 HWND32 hChild )
745 WND* child = WIN_FindWndPtr(hChild);
746 HMENU32 hSysPopup = 0;
748 TRACE(mdi,"frame %p,child %04x\n",frame,hChild);
750 if( !frame->wIDmenu || !child->hSysMenu ) return 0;
752 /* create a copy of sysmenu popup and insert it into frame menu bar */
754 if (!(hSysPopup = LoadMenuIndirect32A(SYSRES_GetResPtr(SYSRES_MENU_SYSMENU))))
755 return 0;
757 TRACE(mdi,"\tgot popup %04x in sysmenu %04x\n",
758 hSysPopup, child->hSysMenu);
760 if( !InsertMenu32A(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
761 hSysPopup, (LPSTR)(DWORD)hBmpClose ))
763 DestroyMenu32(hSysPopup);
764 return 0;
767 if( !AppendMenu32A(frame->wIDmenu,MF_HELP | MF_BITMAP,
768 SC_RESTORE, (LPSTR)(DWORD)hBmpRestore ))
770 RemoveMenu32(frame->wIDmenu,0,MF_BYPOSITION);
771 return 0;
774 EnableMenuItem32(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
775 EnableMenuItem32(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
776 EnableMenuItem32(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
778 /* redraw menu */
779 DrawMenuBar32(frame->hwndSelf);
781 return 1;
784 /**********************************************************************
785 * MDI_RestoreFrameMenu
787 static BOOL32 MDI_RestoreFrameMenu( WND *frameWnd, HWND32 hChild )
789 INT32 nItems = GetMenuItemCount32(frameWnd->wIDmenu) - 1;
791 TRACE(mdi,"for child %04x\n",hChild);
793 if( GetMenuItemID32(frameWnd->wIDmenu,nItems) != SC_RESTORE )
794 return 0;
796 RemoveMenu32(frameWnd->wIDmenu,0,MF_BYPOSITION);
797 DeleteMenu32(frameWnd->wIDmenu,nItems-1,MF_BYPOSITION);
799 DrawMenuBar32(frameWnd->hwndSelf);
801 return 1;
804 /**********************************************************************
805 * MDI_UpdateFrameText
807 * used when child window is maximized/restored
809 * Note: lpTitle can be NULL
811 static void MDI_UpdateFrameText( WND *frameWnd, HWND32 hClient,
812 BOOL32 repaint, LPCSTR lpTitle )
814 char lpBuffer[MDI_MAXTITLELENGTH+1];
815 WND* clientWnd = WIN_FindWndPtr(hClient);
816 MDICLIENTINFO *ci = (MDICLIENTINFO *) clientWnd->wExtra;
818 TRACE(mdi, "repaint %i, frameText %s\n", repaint, (lpTitle)?lpTitle:"NULL");
820 if (!clientWnd)
821 return;
823 if (!ci)
824 return;
826 /* store new "default" title if lpTitle is not NULL */
827 if (lpTitle)
829 if (ci->frameTitle) HeapFree( SystemHeap, 0, ci->frameTitle );
830 ci->frameTitle = HEAP_strdupA( SystemHeap, 0, lpTitle );
833 if (ci->frameTitle)
835 WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );
837 if( childWnd && childWnd->text )
839 /* combine frame title and child title if possible */
841 LPCSTR lpBracket = " - [";
842 int i_frame_text_length = strlen(ci->frameTitle);
843 int i_child_text_length = strlen(childWnd->text);
845 lstrcpyn32A( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
847 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
849 strcat( lpBuffer, lpBracket );
851 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
853 strcat( lpBuffer, childWnd->text );
854 strcat( lpBuffer, "]" );
856 else
858 lstrcpyn32A( lpBuffer + i_frame_text_length + 4,
859 childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
860 strcat( lpBuffer, "]" );
864 else
866 strncpy(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH );
867 lpBuffer[MDI_MAXTITLELENGTH]='\0';
870 else
871 lpBuffer[0] = '\0';
873 DEFWND_SetText( frameWnd, lpBuffer );
874 if( repaint == MDI_REPAINTFRAME)
875 SetWindowPos32( frameWnd->hwndSelf, 0,0,0,0,0, SWP_FRAMECHANGED |
876 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
880 /* ----------------------------- Interface ---------------------------- */
883 /**********************************************************************
884 * MDIClientWndProc
886 * This function handles all MDI requests.
888 LRESULT WINAPI MDIClientWndProc( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
889 LPARAM lParam )
891 LPCREATESTRUCT32A cs;
892 MDICLIENTINFO *ci;
893 RECT32 rect;
894 WND *w = WIN_FindWndPtr(hwnd);
895 WND *frameWnd = w->parent;
896 INT32 nItems;
898 ci = (MDICLIENTINFO *) w->wExtra;
900 switch (message)
902 case WM_CREATE:
904 cs = (LPCREATESTRUCT32A)lParam;
906 /* Translation layer doesn't know what's in the cs->lpCreateParams
907 * so we have to keep track of what environment we're in. */
909 if( w->flags & WIN_ISWIN32 )
911 #define ccs ((LPCLIENTCREATESTRUCT32)cs->lpCreateParams)
912 ci->hWindowMenu = ccs->hWindowMenu;
913 ci->idFirstChild = ccs->idFirstChild;
914 #undef ccs
916 else
918 LPCLIENTCREATESTRUCT16 ccs = (LPCLIENTCREATESTRUCT16)
919 PTR_SEG_TO_LIN(cs->lpCreateParams);
920 ci->hWindowMenu = ccs->hWindowMenu;
921 ci->idFirstChild = ccs->idFirstChild;
924 ci->hwndChildMaximized = 0;
925 ci->nActiveChildren = 0;
926 ci->nTotalCreated = 0;
927 ci->frameTitle = NULL;
928 ci->mdiFlags = 0;
929 ci->self = hwnd;
930 w->dwStyle |= WS_CLIPCHILDREN;
932 if (!hBmpClose)
934 hBmpClose = CreateMDIMenuBitmap();
935 hBmpRestore = LoadBitmap16( 0, MAKEINTRESOURCE16(OBM_RESTORE) );
937 MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
939 AppendMenu32A( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
941 GetClientRect32(frameWnd->hwndSelf, &rect);
942 NC_HandleNCCalcSize( w, &rect );
943 w->rectClient = rect;
945 TRACE(mdi,"Client created - hwnd = %04x, idFirst = %u\n",
946 hwnd, ci->idFirstChild );
948 return 0;
950 case WM_DESTROY:
951 if( ci->hwndChildMaximized ) MDI_RestoreFrameMenu(w, frameWnd->hwndSelf);
952 if((nItems = GetMenuItemCount32(ci->hWindowMenu)) > 0)
954 ci->idFirstChild = nItems - 1;
955 ci->nActiveChildren++; /* to delete a separator */
956 while( ci->nActiveChildren-- )
957 DeleteMenu32(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
959 return 0;
961 case WM_MDIACTIVATE:
962 if( ci->hwndActiveChild != (HWND32)wParam )
963 SetWindowPos32((HWND32)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
964 return 0;
966 case WM_MDICASCADE:
967 return MDICascade(w, ci);
969 case WM_MDICREATE:
970 if (lParam) return MDICreateChild( w, ci, hwnd,
971 (MDICREATESTRUCT32A*)lParam );
972 return 0;
974 case WM_MDIDESTROY:
975 return MDIDestroyChild( w, ci, hwnd, (HWND32)wParam, TRUE );
977 case WM_MDIGETACTIVE:
978 if (lParam) *(BOOL32 *)lParam = (ci->hwndChildMaximized > 0);
979 return ci->hwndActiveChild;
981 case WM_MDIICONARRANGE:
982 ci->mdiFlags |= MDIF_NEEDUPDATE;
983 ArrangeIconicWindows32(hwnd);
984 ci->sbRecalc = SB_BOTH+1;
985 SendMessage32A(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
986 return 0;
988 case WM_MDIMAXIMIZE:
989 ShowWindow32( (HWND32)wParam, SW_MAXIMIZE );
990 return 0;
992 case WM_MDINEXT: /* lParam != 0 means previous window */
993 MDI_SwitchActiveChild(hwnd, (HWND32)wParam, (lParam)? FALSE : TRUE );
994 break;
996 case WM_MDIRESTORE:
997 ShowWindow32( (HWND32)wParam, SW_NORMAL);
998 return 0;
1000 case WM_MDISETMENU:
1001 return MDISetMenu( hwnd, (HMENU32)wParam, (HMENU32)lParam );
1003 case WM_MDIREFRESHMENU:
1004 return MDIRefreshMenu( hwnd, (HMENU32)wParam, (HMENU32)lParam );
1006 case WM_MDITILE:
1007 ci->mdiFlags |= MDIF_NEEDUPDATE;
1008 ShowScrollBar32(hwnd,SB_BOTH,FALSE);
1009 MDITile(w, ci, wParam);
1010 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1011 return 0;
1013 case WM_VSCROLL:
1014 case WM_HSCROLL:
1015 ci->mdiFlags |= MDIF_NEEDUPDATE;
1016 ScrollChildren32(hwnd, message, wParam, lParam);
1017 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1018 return 0;
1020 case WM_SETFOCUS:
1021 if( ci->hwndActiveChild )
1023 w = WIN_FindWndPtr( ci->hwndActiveChild );
1024 if( !(w->dwStyle & WS_MINIMIZE) )
1025 SetFocus32( ci->hwndActiveChild );
1027 return 0;
1029 case WM_NCACTIVATE:
1030 if( ci->hwndActiveChild )
1031 SendMessage32A(ci->hwndActiveChild, message, wParam, lParam);
1032 break;
1034 case WM_PARENTNOTIFY:
1035 if (LOWORD(wParam) == WM_LBUTTONDOWN)
1037 POINT16 pt = MAKEPOINT16(lParam);
1038 HWND16 child = ChildWindowFromPoint16(hwnd, pt);
1040 TRACE(mdi,"notification from %04x (%i,%i)\n",child,pt.x,pt.y);
1042 if( child && child != hwnd && child != ci->hwndActiveChild )
1043 SetWindowPos32(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1045 return 0;
1047 case WM_SIZE:
1048 if( ci->hwndChildMaximized )
1050 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1051 RECT32 rect = { 0, 0, LOWORD(lParam), HIWORD(lParam) };
1053 AdjustWindowRectEx32(&rect, child->dwStyle, 0, child->dwExStyle);
1054 MoveWindow32(ci->hwndChildMaximized, rect.left, rect.top,
1055 rect.right - rect.left, rect.bottom - rect.top, 1);
1057 else
1058 MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1060 break;
1062 case WM_MDICALCCHILDSCROLL:
1063 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1065 CalcChildScroll(hwnd, ci->sbRecalc-1);
1066 ci->sbRecalc = 0;
1067 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1069 return 0;
1072 return DefWindowProc32A( hwnd, message, wParam, lParam );
1076 /***********************************************************************
1077 * DefFrameProc16 (USER.445)
1079 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1080 UINT16 message, WPARAM16 wParam, LPARAM lParam )
1082 HWND16 childHwnd;
1083 MDICLIENTINFO* ci;
1084 WND* wndPtr;
1086 if (hwndMDIClient)
1088 switch (message)
1090 case WM_COMMAND:
1091 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1092 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1094 /* check for possible syscommands for maximized MDI child */
1096 if( ci && (
1097 wParam < ci->idFirstChild ||
1098 wParam >= ci->idFirstChild + ci->nActiveChildren
1100 if( (wParam - 0xF000) & 0xF00F ) break;
1101 switch( wParam )
1103 case SC_SIZE:
1104 case SC_MOVE:
1105 case SC_MINIMIZE:
1106 case SC_MAXIMIZE:
1107 case SC_NEXTWINDOW:
1108 case SC_PREVWINDOW:
1109 case SC_CLOSE:
1110 case SC_RESTORE:
1111 if( ci->hwndChildMaximized )
1112 return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1113 wParam, lParam);
1116 else
1118 childHwnd = MDI_GetChildByID( WIN_FindWndPtr(hwndMDIClient),
1119 wParam );
1120 if( childHwnd )
1121 SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1122 (WPARAM16)childHwnd , 0L);
1124 break;
1126 case WM_NCACTIVATE:
1127 SendMessage16(hwndMDIClient, message, wParam, lParam);
1128 break;
1130 case WM_SETTEXT:
1131 MDI_UpdateFrameText(WIN_FindWndPtr(hwnd), hwndMDIClient,
1132 MDI_REPAINTFRAME,
1133 (LPCSTR)PTR_SEG_TO_LIN(lParam));
1134 return 0;
1136 case WM_SETFOCUS:
1137 SetFocus32(hwndMDIClient);
1138 break;
1140 case WM_SIZE:
1141 MoveWindow16(hwndMDIClient, 0, 0,
1142 LOWORD(lParam), HIWORD(lParam), TRUE);
1143 break;
1145 case WM_NEXTMENU:
1147 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1148 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1150 if( !(wndPtr->parent->dwStyle & WS_MINIMIZE)
1151 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1153 /* control menu is between the frame system menu and
1154 * the first entry of menu bar */
1156 if( (wParam == VK_LEFT &&
1157 wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1158 (wParam == VK_RIGHT &&
1159 GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1161 wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1162 return MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1163 ci->hwndActiveChild);
1166 break;
1170 return DefWindowProc16(hwnd, message, wParam, lParam);
1174 /***********************************************************************
1175 * DefFrameProc32A (USER32.122)
1177 LRESULT WINAPI DefFrameProc32A( HWND32 hwnd, HWND32 hwndMDIClient,
1178 UINT32 message, WPARAM32 wParam, LPARAM lParam)
1180 if (hwndMDIClient)
1182 switch (message)
1184 case WM_COMMAND:
1185 return DefFrameProc16( hwnd, hwndMDIClient, message,
1186 (WPARAM16)wParam,
1187 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1189 case WM_NCACTIVATE:
1190 SendMessage32A(hwndMDIClient, message, wParam, lParam);
1191 break;
1193 case WM_SETTEXT: {
1194 LRESULT ret;
1195 LPSTR segstr = SEGPTR_STRDUP((LPSTR)lParam);
1197 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1198 wParam, (LPARAM)SEGPTR_GET(segstr) );
1199 SEGPTR_FREE(segstr);
1200 return ret;
1203 case WM_SETFOCUS:
1204 case WM_SIZE:
1205 return DefFrameProc16( hwnd, hwndMDIClient, message,
1206 wParam, lParam );
1210 return DefWindowProc32A(hwnd, message, wParam, lParam);
1214 /***********************************************************************
1215 * DefFrameProc32W (USER32.123)
1217 LRESULT WINAPI DefFrameProc32W( HWND32 hwnd, HWND32 hwndMDIClient,
1218 UINT32 message, WPARAM32 wParam, LPARAM lParam)
1220 if (hwndMDIClient)
1222 switch (message)
1224 case WM_COMMAND:
1225 return DefFrameProc16( hwnd, hwndMDIClient, message,
1226 (WPARAM16)wParam,
1227 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1229 case WM_NCACTIVATE:
1230 SendMessage32W(hwndMDIClient, message, wParam, lParam);
1231 break;
1233 case WM_SETTEXT:
1235 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1236 LRESULT ret = DefFrameProc32A( hwnd, hwndMDIClient, message,
1237 wParam, (DWORD)txt );
1238 HeapFree(GetProcessHeap(),0,txt);
1239 return ret;
1241 case WM_SETFOCUS:
1242 case WM_SIZE:
1243 return DefFrameProc32A( hwnd, hwndMDIClient, message,
1244 wParam, lParam );
1248 return DefWindowProc32W( hwnd, message, wParam, lParam );
1252 /***********************************************************************
1253 * DefMDIChildProc16 (USER.447)
1255 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1256 WPARAM16 wParam, LPARAM lParam )
1258 MDICLIENTINFO *ci;
1259 WND *clientWnd;
1261 clientWnd = WIN_FindWndPtr(GetParent16(hwnd));
1262 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1264 switch (message)
1266 case WM_SETTEXT:
1267 DefWindowProc16(hwnd, message, wParam, lParam);
1268 MDI_MenuModifyItem(clientWnd,hwnd);
1269 if( ci->hwndChildMaximized == hwnd )
1270 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1271 MDI_REPAINTFRAME, NULL );
1272 return 0;
1274 case WM_CLOSE:
1275 SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1276 return 0;
1278 case WM_SETFOCUS:
1279 if( ci->hwndActiveChild != hwnd )
1280 MDI_ChildActivate(clientWnd, hwnd);
1281 break;
1283 case WM_CHILDACTIVATE:
1284 MDI_ChildActivate(clientWnd, hwnd);
1285 return 0;
1287 case WM_NCPAINT:
1288 TRACE(mdi,"WM_NCPAINT for %04x, active %04x\n",
1289 hwnd, ci->hwndActiveChild );
1290 break;
1292 case WM_SYSCOMMAND:
1293 switch( wParam )
1295 case SC_MOVE:
1296 if( ci->hwndChildMaximized == hwnd) return 0;
1297 break;
1298 case SC_RESTORE:
1299 case SC_MINIMIZE:
1300 WIN_FindWndPtr(hwnd)->dwStyle |= WS_SYSMENU;
1301 break;
1302 case SC_MAXIMIZE:
1303 if( ci->hwndChildMaximized == hwnd)
1304 return SendMessage16( clientWnd->parent->hwndSelf,
1305 message, wParam, lParam);
1306 WIN_FindWndPtr(hwnd)->dwStyle &= ~WS_SYSMENU;
1307 break;
1308 case SC_NEXTWINDOW:
1309 SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1310 return 0;
1311 case SC_PREVWINDOW:
1312 SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1313 return 0;
1315 break;
1317 case WM_GETMINMAXINFO:
1318 MDI_ChildGetMinMaxInfo(clientWnd, hwnd, (MINMAXINFO16*) PTR_SEG_TO_LIN(lParam));
1319 return 0;
1321 case WM_SETVISIBLE:
1322 if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1323 else
1324 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1325 break;
1327 case WM_SIZE:
1328 /* do not change */
1330 if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1332 ci->hwndChildMaximized = 0;
1334 MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1335 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1336 MDI_REPAINTFRAME, NULL );
1339 if( wParam == SIZE_MAXIMIZED )
1341 HWND16 hMaxChild = ci->hwndChildMaximized;
1343 if( hMaxChild == hwnd ) break;
1345 if( hMaxChild)
1347 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1349 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1350 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1352 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1355 TRACE(mdi,"maximizing child %04x\n", hwnd );
1357 ci->hwndChildMaximized = hwnd; /* !!! */
1359 MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1360 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1361 MDI_REPAINTFRAME, NULL );
1364 if( wParam == SIZE_MINIMIZED )
1366 HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1368 if( switchTo )
1369 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1372 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1373 break;
1375 case WM_MENUCHAR:
1377 /* MDI children don't have menu bars */
1378 PostMessage16( clientWnd->parent->hwndSelf, WM_SYSCOMMAND,
1379 (WPARAM16)SC_KEYMENU, (LPARAM)wParam);
1380 return 0x00010000L;
1382 case WM_NEXTMENU:
1384 if( wParam == VK_LEFT ) /* switch to frame system menu */
1385 return MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1386 clientWnd->parent->hwndSelf );
1387 if( wParam == VK_RIGHT ) /* to frame menu bar */
1388 return MAKELONG( clientWnd->parent->wIDmenu,
1389 clientWnd->parent->hwndSelf );
1391 break;
1394 return DefWindowProc16(hwnd, message, wParam, lParam);
1398 /***********************************************************************
1399 * DefMDIChildProc32A (USER32.124)
1401 LRESULT WINAPI DefMDIChildProc32A( HWND32 hwnd, UINT32 message,
1402 WPARAM32 wParam, LPARAM lParam )
1404 MDICLIENTINFO *ci;
1405 WND *clientWnd;
1407 clientWnd = WIN_FindWndPtr(WIN_FindWndPtr(hwnd)->parent->hwndSelf);
1408 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1410 switch (message)
1412 case WM_SETTEXT:
1413 DefWindowProc32A(hwnd, message, wParam, lParam);
1414 MDI_MenuModifyItem(clientWnd,hwnd);
1415 if( ci->hwndChildMaximized == hwnd )
1416 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1417 MDI_REPAINTFRAME, NULL );
1418 return 0;
1420 case WM_GETMINMAXINFO:
1422 MINMAXINFO16 mmi;
1423 STRUCT32_MINMAXINFO32to16( (MINMAXINFO32 *)lParam, &mmi );
1424 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1425 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO32 *)lParam );
1427 return 0;
1429 case WM_MENUCHAR:
1431 /* MDI children don't have menu bars */
1432 PostMessage16( clientWnd->parent->hwndSelf, WM_SYSCOMMAND,
1433 (WPARAM16)SC_KEYMENU, (LPARAM)LOWORD(wParam) );
1434 return 0x00010000L;
1436 case WM_CLOSE:
1437 case WM_SETFOCUS:
1438 case WM_CHILDACTIVATE:
1439 case WM_NCPAINT:
1440 case WM_SYSCOMMAND:
1441 case WM_SETVISIBLE:
1442 case WM_SIZE:
1443 case WM_NEXTMENU:
1444 return DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1446 return DefWindowProc32A(hwnd, message, wParam, lParam);
1450 /***********************************************************************
1451 * DefMDIChildProc32W (USER32.125)
1453 LRESULT WINAPI DefMDIChildProc32W( HWND32 hwnd, UINT32 message,
1454 WPARAM32 wParam, LPARAM lParam )
1456 MDICLIENTINFO *ci;
1457 WND *clientWnd;
1459 clientWnd = WIN_FindWndPtr(GetParent16(hwnd));
1460 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1462 switch (message)
1464 case WM_SETTEXT:
1465 DefWindowProc32W(hwnd, message, wParam, lParam);
1466 MDI_MenuModifyItem(clientWnd,hwnd);
1467 if( ci->hwndChildMaximized == hwnd )
1468 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1469 MDI_REPAINTFRAME, NULL );
1470 return 0;
1472 case WM_GETMINMAXINFO:
1473 case WM_MENUCHAR:
1474 case WM_CLOSE:
1475 case WM_SETFOCUS:
1476 case WM_CHILDACTIVATE:
1477 case WM_NCPAINT:
1478 case WM_SYSCOMMAND:
1479 case WM_SETVISIBLE:
1480 case WM_SIZE:
1481 case WM_NEXTMENU:
1482 return DefMDIChildProc32A( hwnd, message, (WPARAM16)wParam, lParam );
1484 return DefWindowProc32W(hwnd, message, wParam, lParam);
1488 /**********************************************************************
1489 * CreateMDIWindowA [USER32.79]
1491 HWND32 WINAPI CreateMDIWindowA(
1492 LPCSTR lpClassName,
1493 LPCSTR lpWindowName,
1494 DWORD dwStyle,
1495 INT32 X,
1496 INT32 Y,
1497 INT32 nWidth,
1498 INT32 nHeight,
1499 HWND32 hWndParent,
1500 HINSTANCE32 hInstance,
1501 LPARAM lParam)
1503 FIXME(mdi, "(%s,%s,%ld,...): stub\n",debugstr_a(lpClassName),
1504 debugstr_a(lpWindowName),dwStyle);
1505 return (HWND32)NULL;
1509 /******************************************************************************
1510 * CreateMDIWindowW [USER32.80] Creates a MDI child window
1512 * RETURNS
1513 * Success: Handle to created window
1514 * Failure: NULL
1516 HWND32 WINAPI CreateMDIWindowW(
1517 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1518 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1519 DWORD dwStyle, /* [in] Window style */
1520 INT32 X, /* [in] Horizontal position of window */
1521 INT32 Y, /* [in] Vertical position of window */
1522 INT32 nWidth, /* [in] Width of window */
1523 INT32 nHeight, /* [in] Height of window */
1524 HWND32 hWndParent, /* [in] Handle to parent window */
1525 HINSTANCE32 hInstance, /* [in] Handle to application instance */
1526 LPARAM lParam) /* [in] Application-defined value */
1528 FIXME(mdi, "(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1529 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1530 nWidth,nHeight,hWndParent,hInstance,lParam);
1531 return (HWND32)NULL;
1535 /**********************************************************************
1536 * TranslateMDISysAccel32 (USER32.555)
1538 BOOL32 WINAPI TranslateMDISysAccel32( HWND32 hwndClient, LPMSG32 msg )
1540 MSG16 msg16;
1542 STRUCT32_MSG32to16(msg,&msg16);
1543 /* MDICLIENTINFO is still the same for win32 and win16 ... */
1544 return TranslateMDISysAccel16(hwndClient,&msg16);
1548 /**********************************************************************
1549 * TranslateMDISysAccel16 (USER.451)
1551 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
1553 WND* clientWnd = WIN_FindWndPtr( hwndClient);
1555 if( clientWnd && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
1557 MDICLIENTINFO *ci = NULL;
1558 WND* wnd;
1560 ci = (MDICLIENTINFO*) clientWnd->wExtra;
1561 wnd = WIN_FindWndPtr(ci->hwndActiveChild);
1562 if( wnd && !(wnd->dwStyle & WS_DISABLED) )
1564 WPARAM16 wParam = 0;
1566 /* translate if the Ctrl key is down and Alt not. */
1568 if( (GetKeyState32(VK_CONTROL) & 0x8000) &&
1569 !(GetKeyState32(VK_MENU) & 0x8000))
1571 switch( msg->wParam )
1573 case VK_F6:
1574 case VK_TAB:
1575 wParam = ( GetKeyState32(VK_SHIFT) & 0x8000 )
1576 ? SC_NEXTWINDOW : SC_PREVWINDOW;
1577 break;
1578 case VK_F4:
1579 case VK_RBUTTON:
1580 wParam = SC_CLOSE;
1581 break;
1582 default:
1583 return 0;
1585 TRACE(mdi,"wParam = %04x\n", wParam);
1586 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
1587 wParam, (LPARAM)msg->wParam);
1588 return 1;
1592 return 0; /* failure */
1596 /***********************************************************************
1597 * CalcChildScroll (USER.462)
1599 void WINAPI CalcChildScroll( HWND16 hwnd, WORD scroll )
1601 RECT32 childRect, clientRect;
1602 INT32 vmin, vmax, hmin, hmax, vpos, hpos;
1603 WND *pWnd, *Wnd;
1605 if (!(Wnd = pWnd = WIN_FindWndPtr( hwnd ))) return;
1606 GetClientRect32( hwnd, &clientRect );
1607 SetRectEmpty32( &childRect );
1609 for ( pWnd = pWnd->child; pWnd; pWnd = pWnd->next )
1611 if( pWnd->dwStyle & WS_MAXIMIZE )
1613 ShowScrollBar32(hwnd, SB_BOTH, FALSE);
1614 return;
1616 UnionRect32( &childRect, &pWnd->rectWindow, &childRect );
1618 UnionRect32( &childRect, &clientRect, &childRect );
1620 /* jump through the hoops to prevent excessive flashing
1623 hmin = childRect.left; hmax = childRect.right - clientRect.right;
1624 hpos = clientRect.left - childRect.left;
1625 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
1626 vpos = clientRect.top - childRect.top;
1628 switch( scroll )
1630 case SB_HORZ:
1631 vpos = hpos; vmin = hmin; vmax = hmax;
1632 case SB_VERT:
1633 SetScrollPos32(hwnd, scroll, vpos, FALSE);
1634 SetScrollRange32(hwnd, scroll, vmin, vmax, TRUE);
1635 break;
1636 case SB_BOTH:
1637 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
1638 hmin, hmax, hpos);
1639 SetWindowPos32(hwnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE
1640 | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
1645 /***********************************************************************
1646 * ScrollChildren16 (USER.463)
1648 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
1650 return ScrollChildren32( hWnd, uMsg, wParam, lParam );
1654 /***********************************************************************
1655 * ScrollChildren32 (USER32.448)
1657 void WINAPI ScrollChildren32(HWND32 hWnd, UINT32 uMsg, WPARAM32 wParam,
1658 LPARAM lParam)
1660 WND *wndPtr = WIN_FindWndPtr(hWnd);
1661 INT32 newPos = -1;
1662 INT32 curPos, length, minPos, maxPos, shift;
1664 if( !wndPtr ) return;
1666 if( uMsg == WM_HSCROLL )
1668 GetScrollRange32(hWnd,SB_HORZ,&minPos,&maxPos);
1669 curPos = GetScrollPos32(hWnd,SB_HORZ);
1670 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
1671 shift = SYSMETRICS_CYHSCROLL;
1673 else if( uMsg == WM_VSCROLL )
1675 GetScrollRange32(hWnd,SB_VERT,&minPos,&maxPos);
1676 curPos = GetScrollPos32(hWnd,SB_VERT);
1677 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
1678 shift = SYSMETRICS_CXVSCROLL;
1680 else return;
1682 switch( wParam )
1684 case SB_LINEUP:
1685 newPos = curPos - shift;
1686 break;
1687 case SB_LINEDOWN:
1688 newPos = curPos + shift;
1689 break;
1690 case SB_PAGEUP:
1691 newPos = curPos - length;
1692 break;
1693 case SB_PAGEDOWN:
1694 newPos = curPos + length;
1695 break;
1697 case SB_THUMBPOSITION:
1698 newPos = LOWORD(lParam);
1699 break;
1701 case SB_THUMBTRACK:
1702 return;
1704 case SB_TOP:
1705 newPos = minPos;
1706 break;
1707 case SB_BOTTOM:
1708 newPos = maxPos;
1709 break;
1710 case SB_ENDSCROLL:
1711 CalcChildScroll(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
1712 return;
1715 if( newPos > maxPos )
1716 newPos = maxPos;
1717 else
1718 if( newPos < minPos )
1719 newPos = minPos;
1721 SetScrollPos32(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
1723 if( uMsg == WM_VSCROLL )
1724 ScrollWindowEx32(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
1725 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1726 else
1727 ScrollWindowEx32(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
1728 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1732 /******************************************************************************
1733 * CascadeWindows [USER32.21] Cascades MDI child windows
1735 * RETURNS
1736 * Success: Number of cascaded windows.
1737 * Failure: 0
1739 WORD WINAPI
1740 CascadeWindows (HWND32 hwndParent, UINT32 wFlags, const LPRECT32 lpRect,
1741 UINT32 cKids, const HWND32 *lpKids)
1743 FIXME (mdi, "(0x%08x,0x%08x,...,%u,...): stub\n",
1744 hwndParent, wFlags, cKids);
1746 return 0;
1750 /******************************************************************************
1751 * TileWindows [USER32.545] Tiles MDI child windows
1753 * RETURNS
1754 * Success: Number of tiled windows.
1755 * Failure: 0
1757 WORD WINAPI
1758 TileWindows (HWND32 hwndParent, UINT32 wFlags, const LPRECT32 lpRect,
1759 UINT32 cKids, const HWND32 *lpKids)
1761 FIXME (mdi, "(0x%08x,0x%08x,...,%u,...): stub\n",
1762 hwndParent, wFlags, cKids);
1764 return 0;