Added change notifications.
[wine/multimedia.git] / windows / mdi.c
blob9bfcf4b0c8b7a7e22bf0a75c2b3071238a2a84dc
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 )
559 clientInfo->hwndActiveChild = hWndChild;
560 ShowWindow32( hWndChild, SW_SHOWMAXIMIZED);
562 else
563 ShowWindow32( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
566 clientInfo->hwndActiveChild = hWndChild;
568 /* check if we have any children left */
569 if( !hWndChild )
571 if( isActiveFrameWnd )
572 SetFocus32( clientInfo->self );
573 return 0;
576 /* check menu item */
577 if( clientInfo->hWindowMenu )
578 CheckMenuItem32( clientInfo->hWindowMenu,
579 wndPtr->wIDmenu, MF_CHECKED);
581 /* bring active child to the top */
582 SetWindowPos32( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
584 if( isActiveFrameWnd )
586 SendMessage32A( hWndChild, WM_NCACTIVATE, TRUE, 0L);
587 if( GetFocus32() == clientInfo->self )
588 SendMessage32A( clientInfo->self, WM_SETFOCUS,
589 (WPARAM32)clientInfo->self, 0L );
590 else
591 SetFocus32( clientInfo->self );
593 SendMessage32A( hWndChild, WM_MDIACTIVATE, (WPARAM32)prevActiveWnd,
594 (LPARAM)hWndChild );
595 return 1;
598 /* -------------------- MDI client window functions ------------------- */
600 /**********************************************************************
601 * CreateMDIMenuBitmap
603 static HBITMAP16 CreateMDIMenuBitmap(void)
605 HDC32 hDCSrc = CreateCompatibleDC32(0);
606 HDC32 hDCDest = CreateCompatibleDC32(hDCSrc);
607 HBITMAP16 hbClose = LoadBitmap16(0, MAKEINTRESOURCE16(OBM_CLOSE) );
608 HBITMAP16 hbCopy;
609 HANDLE16 hobjSrc, hobjDest;
611 hobjSrc = SelectObject32(hDCSrc, hbClose);
612 hbCopy = CreateCompatibleBitmap32(hDCSrc,SYSMETRICS_CXSIZE,SYSMETRICS_CYSIZE);
613 hobjDest = SelectObject32(hDCDest, hbCopy);
615 BitBlt32(hDCDest, 0, 0, SYSMETRICS_CXSIZE, SYSMETRICS_CYSIZE,
616 hDCSrc, SYSMETRICS_CXSIZE, 0, SRCCOPY);
618 SelectObject32(hDCSrc, hobjSrc);
619 DeleteObject32(hbClose);
620 DeleteDC32(hDCSrc);
622 hobjSrc = SelectObject32( hDCDest, GetStockObject32(BLACK_PEN) );
624 MoveToEx32( hDCDest, SYSMETRICS_CXSIZE - 1, 0, NULL );
625 LineTo32( hDCDest, SYSMETRICS_CXSIZE - 1, SYSMETRICS_CYSIZE - 1);
627 SelectObject32(hDCDest, hobjSrc );
628 SelectObject32(hDCDest, hobjDest);
629 DeleteDC32(hDCDest);
631 return hbCopy;
634 /**********************************************************************
635 * MDICascade
637 static LONG MDICascade(WND* clientWnd, MDICLIENTINFO *ci)
639 WND** ppWnd;
640 UINT32 total;
642 if (ci->hwndChildMaximized)
643 SendMessage32A( clientWnd->hwndSelf, WM_MDIRESTORE,
644 (WPARAM32)ci->hwndChildMaximized, 0);
646 if (ci->nActiveChildren == 0) return 0;
648 if ((ppWnd = WIN_BuildWinArray(clientWnd, BWA_SKIPHIDDEN | BWA_SKIPOWNED |
649 BWA_SKIPICONIC, &total)))
651 WND** heapPtr = ppWnd;
652 if( total )
654 INT32 delta = 0, n = 0;
655 POINT32 pos[2];
656 if( total < ci->nActiveChildren )
657 delta = SYSMETRICS_CYICONSPACING + SYSMETRICS_CYICON;
659 /* walk the list (backwards) and move windows */
660 while (*ppWnd) ppWnd++;
661 while (ppWnd != heapPtr)
663 ppWnd--;
664 TRACE(mdi, "move %04x to (%d,%d) size [%d,%d]\n",
665 (*ppWnd)->hwndSelf, pos[0].x, pos[0].y, pos[1].x, pos[1].y);
667 MDI_CalcDefaultChildPos(clientWnd, n++, pos, delta);
668 SetWindowPos32( (*ppWnd)->hwndSelf, 0, pos[0].x, pos[0].y,
669 pos[1].x, pos[1].y,
670 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
673 HeapFree( SystemHeap, 0, heapPtr );
676 if( total < ci->nActiveChildren )
677 ArrangeIconicWindows32( clientWnd->hwndSelf );
678 return 0;
681 /**********************************************************************
682 * MDITile
684 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM32 wParam )
686 WND** ppWnd;
687 UINT32 total = 0;
689 if (ci->hwndChildMaximized)
690 SendMessage32A( wndClient->hwndSelf, WM_MDIRESTORE,
691 (WPARAM32)ci->hwndChildMaximized, 0);
693 if (ci->nActiveChildren == 0) return;
695 ppWnd = WIN_BuildWinArray(wndClient, BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
696 ((wParam & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
698 TRACE(mdi,"%u windows to tile\n", total);
700 if( ppWnd )
702 WND** heapPtr = ppWnd;
704 if( total )
706 RECT32 rect;
707 int x, y, xsize, ysize;
708 int rows, columns, r, c, i;
710 rect = wndClient->rectClient;
711 rows = (int) sqrt((double)total);
712 columns = total / rows;
714 if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */
716 i = rows;
717 rows = columns; /* exchange r and c */
718 columns = i;
721 if( total != ci->nActiveChildren)
723 y = rect.bottom - 2 * SYSMETRICS_CYICONSPACING - SYSMETRICS_CYICON;
724 rect.bottom = ( y - SYSMETRICS_CYICON < rect.top )? rect.bottom: y;
727 ysize = rect.bottom / rows;
728 xsize = rect.right / columns;
730 for (x = i = 0, c = 1; c <= columns && *ppWnd; c++)
732 if (c == columns)
734 rows = total - i;
735 ysize = rect.bottom / rows;
738 y = 0;
739 for (r = 1; r <= rows && *ppWnd; r++, i++)
741 SetWindowPos32((*ppWnd)->hwndSelf, 0, x, y, xsize, ysize,
742 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
743 y += ysize;
744 ppWnd++;
746 x += xsize;
749 HeapFree( SystemHeap, 0, heapPtr );
752 if( total < ci->nActiveChildren ) ArrangeIconicWindows32( wndClient->hwndSelf );
755 /* ----------------------- Frame window ---------------------------- */
758 /**********************************************************************
759 * MDI_AugmentFrameMenu
761 static BOOL32 MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
762 HWND32 hChild )
764 WND* child = WIN_FindWndPtr(hChild);
765 HMENU32 hSysPopup = 0;
767 TRACE(mdi,"frame %p,child %04x\n",frame,hChild);
769 if( !frame->wIDmenu || !child->hSysMenu ) return 0;
771 /* create a copy of sysmenu popup and insert it into frame menu bar */
773 if (!(hSysPopup = LoadMenuIndirect32A(SYSRES_GetResPtr(SYSRES_MENU_SYSMENU))))
774 return 0;
776 TRACE(mdi,"\tgot popup %04x in sysmenu %04x\n",
777 hSysPopup, child->hSysMenu);
779 if( !InsertMenu32A(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
780 hSysPopup, (LPSTR)(DWORD)hBmpClose ))
782 DestroyMenu32(hSysPopup);
783 return 0;
786 if( !AppendMenu32A(frame->wIDmenu,MF_HELP | MF_BITMAP,
787 SC_RESTORE, (LPSTR)(DWORD)hBmpRestore ))
789 RemoveMenu32(frame->wIDmenu,0,MF_BYPOSITION);
790 return 0;
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_RESTORE )
813 return 0;
815 RemoveMenu32(frameWnd->wIDmenu,0,MF_BYPOSITION);
816 DeleteMenu32(frameWnd->wIDmenu,nItems-1,MF_BYPOSITION);
818 DrawMenuBar32(frameWnd->hwndSelf);
820 return 1;
823 /**********************************************************************
824 * MDI_UpdateFrameText
826 * used when child window is maximized/restored
828 * Note: lpTitle can be NULL
830 static void MDI_UpdateFrameText( WND *frameWnd, HWND32 hClient,
831 BOOL32 repaint, LPCSTR lpTitle )
833 char lpBuffer[MDI_MAXTITLELENGTH+1];
834 WND* clientWnd = WIN_FindWndPtr(hClient);
835 MDICLIENTINFO *ci = (MDICLIENTINFO *) clientWnd->wExtra;
837 TRACE(mdi, "repaint %i, frameText %s\n", repaint, (lpTitle)?lpTitle:"NULL");
839 if (!clientWnd)
840 return;
842 if (!ci)
843 return;
845 /* store new "default" title if lpTitle is not NULL */
846 if (lpTitle)
848 if (ci->frameTitle) HeapFree( SystemHeap, 0, ci->frameTitle );
849 ci->frameTitle = HEAP_strdupA( SystemHeap, 0, lpTitle );
852 if (ci->frameTitle)
854 WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );
856 if( childWnd && childWnd->text )
858 /* combine frame title and child title if possible */
860 LPCSTR lpBracket = " - [";
861 int i_frame_text_length = strlen(ci->frameTitle);
862 int i_child_text_length = strlen(childWnd->text);
864 lstrcpyn32A( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
866 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
868 strcat( lpBuffer, lpBracket );
870 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
872 strcat( lpBuffer, childWnd->text );
873 strcat( lpBuffer, "]" );
875 else
877 lstrcpyn32A( lpBuffer + i_frame_text_length + 4,
878 childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
879 strcat( lpBuffer, "]" );
883 else
885 strncpy(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH );
886 lpBuffer[MDI_MAXTITLELENGTH]='\0';
889 else
890 lpBuffer[0] = '\0';
892 DEFWND_SetText( frameWnd, lpBuffer );
893 if( repaint == MDI_REPAINTFRAME)
894 SetWindowPos32( frameWnd->hwndSelf, 0,0,0,0,0, SWP_FRAMECHANGED |
895 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
899 /* ----------------------------- Interface ---------------------------- */
902 /**********************************************************************
903 * MDIClientWndProc
905 * This function handles all MDI requests.
907 LRESULT WINAPI MDIClientWndProc( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
908 LPARAM lParam )
910 LPCREATESTRUCT32A cs;
911 MDICLIENTINFO *ci;
912 RECT32 rect;
913 WND *w = WIN_FindWndPtr(hwnd);
914 WND *frameWnd = w->parent;
915 INT32 nItems;
917 ci = (MDICLIENTINFO *) w->wExtra;
919 switch (message)
921 case WM_CREATE:
923 cs = (LPCREATESTRUCT32A)lParam;
925 /* Translation layer doesn't know what's in the cs->lpCreateParams
926 * so we have to keep track of what environment we're in. */
928 if( w->flags & WIN_ISWIN32 )
930 #define ccs ((LPCLIENTCREATESTRUCT32)cs->lpCreateParams)
931 ci->hWindowMenu = ccs->hWindowMenu;
932 ci->idFirstChild = ccs->idFirstChild;
933 #undef ccs
935 else
937 LPCLIENTCREATESTRUCT16 ccs = (LPCLIENTCREATESTRUCT16)
938 PTR_SEG_TO_LIN(cs->lpCreateParams);
939 ci->hWindowMenu = ccs->hWindowMenu;
940 ci->idFirstChild = ccs->idFirstChild;
943 ci->hwndChildMaximized = 0;
944 ci->nActiveChildren = 0;
945 ci->nTotalCreated = 0;
946 ci->frameTitle = NULL;
947 ci->mdiFlags = 0;
948 ci->self = hwnd;
949 w->dwStyle |= WS_CLIPCHILDREN;
951 if (!hBmpClose)
953 hBmpClose = CreateMDIMenuBitmap();
954 hBmpRestore = LoadBitmap16( 0, MAKEINTRESOURCE16(OBM_RESTORE) );
956 MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
958 AppendMenu32A( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
960 GetClientRect32(frameWnd->hwndSelf, &rect);
961 NC_HandleNCCalcSize( w, &rect );
962 w->rectClient = rect;
964 TRACE(mdi,"Client created - hwnd = %04x, idFirst = %u\n",
965 hwnd, ci->idFirstChild );
967 return 0;
969 case WM_DESTROY:
970 if( ci->hwndChildMaximized ) MDI_RestoreFrameMenu(w, frameWnd->hwndSelf);
971 if((nItems = GetMenuItemCount32(ci->hWindowMenu)) > 0)
973 ci->idFirstChild = nItems - 1;
974 ci->nActiveChildren++; /* to delete a separator */
975 while( ci->nActiveChildren-- )
976 DeleteMenu32(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
978 return 0;
980 case WM_MDIACTIVATE:
981 if( ci->hwndActiveChild != (HWND32)wParam )
982 SetWindowPos32((HWND32)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
983 return 0;
985 case WM_MDICASCADE:
986 return MDICascade(w, ci);
988 case WM_MDICREATE:
989 if (lParam) return MDICreateChild( w, ci, hwnd,
990 (MDICREATESTRUCT32A*)lParam );
991 return 0;
993 case WM_MDIDESTROY:
994 return MDIDestroyChild( w, ci, hwnd, (HWND32)wParam, TRUE );
996 case WM_MDIGETACTIVE:
997 if (lParam) *(BOOL32 *)lParam = (ci->hwndChildMaximized > 0);
998 return ci->hwndActiveChild;
1000 case WM_MDIICONARRANGE:
1001 ci->mdiFlags |= MDIF_NEEDUPDATE;
1002 ArrangeIconicWindows32(hwnd);
1003 ci->sbRecalc = SB_BOTH+1;
1004 SendMessage32A(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
1005 return 0;
1007 case WM_MDIMAXIMIZE:
1008 ShowWindow32( (HWND32)wParam, SW_MAXIMIZE );
1009 return 0;
1011 case WM_MDINEXT: /* lParam != 0 means previous window */
1012 MDI_SwitchActiveChild(hwnd, (HWND32)wParam, (lParam)? FALSE : TRUE );
1013 break;
1015 case WM_MDIRESTORE:
1016 SendMessage32A( (HWND32)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
1017 return 0;
1019 case WM_MDISETMENU:
1020 return MDISetMenu( hwnd, (HMENU32)wParam, (HMENU32)lParam );
1022 case WM_MDIREFRESHMENU:
1023 return MDIRefreshMenu( hwnd, (HMENU32)wParam, (HMENU32)lParam );
1025 case WM_MDITILE:
1026 ci->mdiFlags |= MDIF_NEEDUPDATE;
1027 ShowScrollBar32(hwnd,SB_BOTH,FALSE);
1028 MDITile(w, ci, wParam);
1029 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1030 return 0;
1032 case WM_VSCROLL:
1033 case WM_HSCROLL:
1034 ci->mdiFlags |= MDIF_NEEDUPDATE;
1035 ScrollChildren32(hwnd, message, wParam, lParam);
1036 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1037 return 0;
1039 case WM_SETFOCUS:
1040 if( ci->hwndActiveChild )
1042 w = WIN_FindWndPtr( ci->hwndActiveChild );
1043 if( !(w->dwStyle & WS_MINIMIZE) )
1044 SetFocus32( ci->hwndActiveChild );
1046 return 0;
1048 case WM_NCACTIVATE:
1049 if( ci->hwndActiveChild )
1050 SendMessage32A(ci->hwndActiveChild, message, wParam, lParam);
1051 break;
1053 case WM_PARENTNOTIFY:
1054 if (LOWORD(wParam) == WM_LBUTTONDOWN)
1056 POINT16 pt = MAKEPOINT16(lParam);
1057 HWND16 child = ChildWindowFromPoint16(hwnd, pt);
1059 TRACE(mdi,"notification from %04x (%i,%i)\n",child,pt.x,pt.y);
1061 if( child && child != hwnd && child != ci->hwndActiveChild )
1062 SetWindowPos32(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1064 return 0;
1066 case WM_SIZE:
1067 if( ci->hwndChildMaximized )
1069 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1070 RECT32 rect = { 0, 0, LOWORD(lParam), HIWORD(lParam) };
1072 AdjustWindowRectEx32(&rect, child->dwStyle, 0, child->dwExStyle);
1073 MoveWindow32(ci->hwndChildMaximized, rect.left, rect.top,
1074 rect.right - rect.left, rect.bottom - rect.top, 1);
1076 else
1077 MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1079 break;
1081 case WM_MDICALCCHILDSCROLL:
1082 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1084 CalcChildScroll(hwnd, ci->sbRecalc-1);
1085 ci->sbRecalc = 0;
1086 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1088 return 0;
1091 return DefWindowProc32A( hwnd, message, wParam, lParam );
1095 /***********************************************************************
1096 * DefFrameProc16 (USER.445)
1098 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1099 UINT16 message, WPARAM16 wParam, LPARAM lParam )
1101 HWND16 childHwnd;
1102 MDICLIENTINFO* ci;
1103 WND* wndPtr;
1105 if (hwndMDIClient)
1107 switch (message)
1109 case WM_COMMAND:
1110 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1111 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1113 /* check for possible syscommands for maximized MDI child */
1115 if( ci && (
1116 wParam < ci->idFirstChild ||
1117 wParam >= ci->idFirstChild + ci->nActiveChildren
1119 if( (wParam - 0xF000) & 0xF00F ) break;
1120 switch( wParam )
1122 case SC_SIZE:
1123 case SC_MOVE:
1124 case SC_MINIMIZE:
1125 case SC_MAXIMIZE:
1126 case SC_NEXTWINDOW:
1127 case SC_PREVWINDOW:
1128 case SC_CLOSE:
1129 case SC_RESTORE:
1130 if( ci->hwndChildMaximized )
1131 return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1132 wParam, lParam);
1135 else
1137 childHwnd = MDI_GetChildByID( WIN_FindWndPtr(hwndMDIClient),
1138 wParam );
1139 if( childHwnd )
1140 SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1141 (WPARAM16)childHwnd , 0L);
1143 break;
1145 case WM_NCACTIVATE:
1146 SendMessage16(hwndMDIClient, message, wParam, lParam);
1147 break;
1149 case WM_SETTEXT:
1150 MDI_UpdateFrameText(WIN_FindWndPtr(hwnd), hwndMDIClient,
1151 MDI_REPAINTFRAME,
1152 (LPCSTR)PTR_SEG_TO_LIN(lParam));
1153 return 0;
1155 case WM_SETFOCUS:
1156 SetFocus32(hwndMDIClient);
1157 break;
1159 case WM_SIZE:
1160 MoveWindow16(hwndMDIClient, 0, 0,
1161 LOWORD(lParam), HIWORD(lParam), TRUE);
1162 break;
1164 case WM_NEXTMENU:
1166 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1167 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1169 if( !(wndPtr->parent->dwStyle & WS_MINIMIZE)
1170 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1172 /* control menu is between the frame system menu and
1173 * the first entry of menu bar */
1175 if( (wParam == VK_LEFT &&
1176 wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1177 (wParam == VK_RIGHT &&
1178 GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1180 wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1181 return MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1182 ci->hwndActiveChild);
1185 break;
1189 return DefWindowProc16(hwnd, message, wParam, lParam);
1193 /***********************************************************************
1194 * DefFrameProc32A (USER32.122)
1196 LRESULT WINAPI DefFrameProc32A( HWND32 hwnd, HWND32 hwndMDIClient,
1197 UINT32 message, WPARAM32 wParam, LPARAM lParam)
1199 if (hwndMDIClient)
1201 switch (message)
1203 case WM_COMMAND:
1204 return DefFrameProc16( hwnd, hwndMDIClient, message,
1205 (WPARAM16)wParam,
1206 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1208 case WM_NCACTIVATE:
1209 SendMessage32A(hwndMDIClient, message, wParam, lParam);
1210 break;
1212 case WM_SETTEXT: {
1213 LRESULT ret;
1214 LPSTR segstr = SEGPTR_STRDUP((LPSTR)lParam);
1216 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1217 wParam, (LPARAM)SEGPTR_GET(segstr) );
1218 SEGPTR_FREE(segstr);
1219 return ret;
1222 case WM_NEXTMENU:
1223 case WM_SETFOCUS:
1224 case WM_SIZE:
1225 return DefFrameProc16( hwnd, hwndMDIClient, message,
1226 wParam, lParam );
1230 return DefWindowProc32A(hwnd, message, wParam, lParam);
1234 /***********************************************************************
1235 * DefFrameProc32W (USER32.123)
1237 LRESULT WINAPI DefFrameProc32W( HWND32 hwnd, HWND32 hwndMDIClient,
1238 UINT32 message, WPARAM32 wParam, LPARAM lParam)
1240 if (hwndMDIClient)
1242 switch (message)
1244 case WM_COMMAND:
1245 return DefFrameProc16( hwnd, hwndMDIClient, message,
1246 (WPARAM16)wParam,
1247 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1249 case WM_NCACTIVATE:
1250 SendMessage32W(hwndMDIClient, message, wParam, lParam);
1251 break;
1253 case WM_SETTEXT:
1255 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1256 LRESULT ret = DefFrameProc32A( hwnd, hwndMDIClient, message,
1257 wParam, (DWORD)txt );
1258 HeapFree(GetProcessHeap(),0,txt);
1259 return ret;
1261 case WM_NEXTMENU:
1262 case WM_SETFOCUS:
1263 case WM_SIZE:
1264 return DefFrameProc32A( hwnd, hwndMDIClient, message,
1265 wParam, lParam );
1269 return DefWindowProc32W( hwnd, message, wParam, lParam );
1273 /***********************************************************************
1274 * DefMDIChildProc16 (USER.447)
1276 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1277 WPARAM16 wParam, LPARAM lParam )
1279 MDICLIENTINFO *ci;
1280 WND *clientWnd;
1282 clientWnd = WIN_FindWndPtr(GetParent16(hwnd));
1283 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1285 switch (message)
1287 case WM_SETTEXT:
1288 DefWindowProc16(hwnd, message, wParam, lParam);
1289 MDI_MenuModifyItem(clientWnd,hwnd);
1290 if( ci->hwndChildMaximized == hwnd )
1291 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1292 MDI_REPAINTFRAME, NULL );
1293 return 0;
1295 case WM_CLOSE:
1296 SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1297 return 0;
1299 case WM_SETFOCUS:
1300 if( ci->hwndActiveChild != hwnd )
1301 MDI_ChildActivate(clientWnd, hwnd);
1302 break;
1304 case WM_CHILDACTIVATE:
1305 MDI_ChildActivate(clientWnd, hwnd);
1306 return 0;
1308 case WM_NCPAINT:
1309 TRACE(mdi,"WM_NCPAINT for %04x, active %04x\n",
1310 hwnd, ci->hwndActiveChild );
1311 break;
1313 case WM_SYSCOMMAND:
1314 switch( wParam )
1316 case SC_MOVE:
1317 if( ci->hwndChildMaximized == hwnd) return 0;
1318 break;
1319 case SC_RESTORE:
1320 case SC_MINIMIZE:
1321 WIN_FindWndPtr(hwnd)->dwStyle |= WS_SYSMENU;
1322 break;
1323 case SC_MAXIMIZE:
1324 if( ci->hwndChildMaximized == hwnd)
1325 return SendMessage16( clientWnd->parent->hwndSelf,
1326 message, wParam, lParam);
1327 WIN_FindWndPtr(hwnd)->dwStyle &= ~WS_SYSMENU;
1328 break;
1329 case SC_NEXTWINDOW:
1330 SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1331 return 0;
1332 case SC_PREVWINDOW:
1333 SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1334 return 0;
1336 break;
1338 case WM_GETMINMAXINFO:
1339 MDI_ChildGetMinMaxInfo(clientWnd, hwnd, (MINMAXINFO16*) PTR_SEG_TO_LIN(lParam));
1340 return 0;
1342 case WM_SETVISIBLE:
1343 if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1344 else
1345 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1346 break;
1348 case WM_SIZE:
1349 /* do not change */
1351 if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1353 ci->hwndChildMaximized = 0;
1355 MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1356 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1357 MDI_REPAINTFRAME, NULL );
1360 if( wParam == SIZE_MAXIMIZED )
1362 HWND16 hMaxChild = ci->hwndChildMaximized;
1364 if( hMaxChild == hwnd ) break;
1366 if( hMaxChild)
1368 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1370 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1371 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1373 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1376 TRACE(mdi,"maximizing child %04x\n", hwnd );
1378 ci->hwndChildMaximized = hwnd; /* !!! */
1380 MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1381 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1382 MDI_REPAINTFRAME, NULL );
1385 if( wParam == SIZE_MINIMIZED )
1387 HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1389 if( switchTo )
1390 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1393 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1394 break;
1396 case WM_MENUCHAR:
1398 /* MDI children don't have menu bars */
1399 PostMessage16( clientWnd->parent->hwndSelf, WM_SYSCOMMAND,
1400 (WPARAM16)SC_KEYMENU, (LPARAM)wParam);
1401 return 0x00010000L;
1403 case WM_NEXTMENU:
1405 if( wParam == VK_LEFT ) /* switch to frame system menu */
1406 return MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1407 clientWnd->parent->hwndSelf );
1408 if( wParam == VK_RIGHT ) /* to frame menu bar */
1409 return MAKELONG( clientWnd->parent->wIDmenu,
1410 clientWnd->parent->hwndSelf );
1412 break;
1414 case WM_SYSCHAR:
1415 if (wParam == '-')
1417 SendMessage16(hwnd,WM_SYSCOMMAND,
1418 (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1419 return 0;
1423 return DefWindowProc16(hwnd, message, wParam, lParam);
1427 /***********************************************************************
1428 * DefMDIChildProc32A (USER32.124)
1430 LRESULT WINAPI DefMDIChildProc32A( HWND32 hwnd, UINT32 message,
1431 WPARAM32 wParam, LPARAM lParam )
1433 MDICLIENTINFO *ci;
1434 WND *clientWnd;
1436 clientWnd = WIN_FindWndPtr(WIN_FindWndPtr(hwnd)->parent->hwndSelf);
1437 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1439 switch (message)
1441 case WM_SETTEXT:
1442 DefWindowProc32A(hwnd, message, wParam, lParam);
1443 MDI_MenuModifyItem(clientWnd,hwnd);
1444 if( ci->hwndChildMaximized == hwnd )
1445 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1446 MDI_REPAINTFRAME, NULL );
1447 return 0;
1449 case WM_GETMINMAXINFO:
1451 MINMAXINFO16 mmi;
1452 STRUCT32_MINMAXINFO32to16( (MINMAXINFO32 *)lParam, &mmi );
1453 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1454 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO32 *)lParam );
1456 return 0;
1458 case WM_MENUCHAR:
1460 /* MDI children don't have menu bars */
1461 PostMessage16( clientWnd->parent->hwndSelf, WM_SYSCOMMAND,
1462 (WPARAM16)SC_KEYMENU, (LPARAM)LOWORD(wParam) );
1463 return 0x00010000L;
1465 case WM_CLOSE:
1466 case WM_SETFOCUS:
1467 case WM_CHILDACTIVATE:
1468 case WM_NCPAINT:
1469 case WM_SYSCOMMAND:
1470 case WM_SETVISIBLE:
1471 case WM_SIZE:
1472 case WM_NEXTMENU:
1473 return DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1475 case WM_SYSCHAR:
1476 if (wParam == '-')
1478 SendMessage32A(hwnd,WM_SYSCOMMAND,
1479 (WPARAM32)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1480 return 0;
1483 return DefWindowProc32A(hwnd, message, wParam, lParam);
1487 /***********************************************************************
1488 * DefMDIChildProc32W (USER32.125)
1490 LRESULT WINAPI DefMDIChildProc32W( HWND32 hwnd, UINT32 message,
1491 WPARAM32 wParam, LPARAM lParam )
1493 MDICLIENTINFO *ci;
1494 WND *clientWnd;
1496 clientWnd = WIN_FindWndPtr(GetParent16(hwnd));
1497 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1499 switch (message)
1501 case WM_SETTEXT:
1502 DefWindowProc32W(hwnd, message, wParam, lParam);
1503 MDI_MenuModifyItem(clientWnd,hwnd);
1504 if( ci->hwndChildMaximized == hwnd )
1505 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1506 MDI_REPAINTFRAME, NULL );
1507 return 0;
1509 case WM_GETMINMAXINFO:
1510 case WM_MENUCHAR:
1511 case WM_CLOSE:
1512 case WM_SETFOCUS:
1513 case WM_CHILDACTIVATE:
1514 case WM_NCPAINT:
1515 case WM_SYSCOMMAND:
1516 case WM_SETVISIBLE:
1517 case WM_SIZE:
1518 case WM_NEXTMENU:
1519 return DefMDIChildProc32A( hwnd, message, (WPARAM16)wParam, lParam );
1521 case WM_SYSCHAR:
1522 if (wParam == '-')
1524 SendMessage32W(hwnd,WM_SYSCOMMAND,
1525 (WPARAM32)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1526 return 0;
1529 return DefWindowProc32W(hwnd, message, wParam, lParam);
1533 /**********************************************************************
1534 * CreateMDIWindowA [USER32.79] Creates a MDI child in new thread
1535 * FIXME: its in the same thread now
1537 * RETURNS
1538 * Success: Handle to created window
1539 * Failure: NULL
1541 HWND32 WINAPI CreateMDIWindow32A(
1542 LPCSTR lpClassName, /* [in] Pointer to registered child class name */
1543 LPCSTR lpWindowName, /* [in] Pointer to window name */
1544 DWORD dwStyle, /* [in] Window style */
1545 INT32 X, /* [in] Horizontal position of window */
1546 INT32 Y, /* [in] Vertical position of window */
1547 INT32 nWidth, /* [in] Width of window */
1548 INT32 nHeight, /* [in] Height of window */
1549 HWND32 hWndParent, /* [in] Handle to parent window */
1550 HINSTANCE32 hInstance, /* [in] Handle to application instance */
1551 LPARAM lParam) /* [in] Application-defined value */
1553 WARN(mdi,"is only single threaded!\n");
1554 return MDI_CreateMDIWindow32A(lpClassName, lpWindowName, dwStyle, X, Y,
1555 nWidth, nHeight, hWndParent, hInstance, lParam);
1558 /**********************************************************************
1559 * MDI_CreateMDIWindowA
1560 * single threaded version of CreateMDIWindowA
1561 * called by CreateWindowEx32A
1563 HWND32 MDI_CreateMDIWindow32A(
1564 LPCSTR lpClassName,
1565 LPCSTR lpWindowName,
1566 DWORD dwStyle,
1567 INT32 X,
1568 INT32 Y,
1569 INT32 nWidth,
1570 INT32 nHeight,
1571 HWND32 hWndParent,
1572 HINSTANCE32 hInstance,
1573 LPARAM lParam)
1575 MDICLIENTINFO* pCi;
1576 MDICREATESTRUCT32A cs;
1577 WND *pWnd=WIN_FindWndPtr(hWndParent);
1579 TRACE(mdi, "(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
1580 debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
1581 nWidth,nHeight,hWndParent,hInstance,lParam);
1583 if(!pWnd){
1584 ERR(mdi," bad hwnd for MDI-client: %d\n",hWndParent);
1585 return 0;
1587 cs.szClass=lpClassName;
1588 cs.szTitle=lpWindowName;
1589 cs.hOwner=hInstance;
1590 cs.x=X;
1591 cs.y=Y;
1592 cs.cx=nWidth;
1593 cs.cy=nHeight;
1594 cs.style=dwStyle;
1595 cs.lParam=lParam;
1597 pCi=(MDICLIENTINFO *)pWnd->wExtra;
1599 return MDICreateChild(pWnd,pCi,hWndParent,&cs);
1602 /***************************************
1603 * CreateMDIWindow32W [USER32.80] Creates a MDI child in new thread
1605 * RETURNS
1606 * Success: Handle to created window
1607 * Failure: NULL
1609 HWND32 WINAPI CreateMDIWindow32W(
1610 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1611 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1612 DWORD dwStyle, /* [in] Window style */
1613 INT32 X, /* [in] Horizontal position of window */
1614 INT32 Y, /* [in] Vertical position of window */
1615 INT32 nWidth, /* [in] Width of window */
1616 INT32 nHeight, /* [in] Height of window */
1617 HWND32 hWndParent, /* [in] Handle to parent window */
1618 HINSTANCE32 hInstance, /* [in] Handle to application instance */
1619 LPARAM lParam) /* [in] Application-defined value */
1621 FIXME(mdi, "(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1622 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1623 nWidth,nHeight,hWndParent,hInstance,lParam);
1624 return (HWND32)NULL;
1628 /******************************************************************************
1629 * CreateMDIWindow32W [USER32.80] Creates a MDI child window
1630 * single threaded version of CreateMDIWindow
1631 * called by CreateWindowEx32W().
1633 HWND32 MDI_CreateMDIWindow32W(
1634 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1635 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1636 DWORD dwStyle, /* [in] Window style */
1637 INT32 X, /* [in] Horizontal position of window */
1638 INT32 Y, /* [in] Vertical position of window */
1639 INT32 nWidth, /* [in] Width of window */
1640 INT32 nHeight, /* [in] Height of window */
1641 HWND32 hWndParent, /* [in] Handle to parent window */
1642 HINSTANCE32 hInstance, /* [in] Handle to application instance */
1643 LPARAM lParam) /* [in] Application-defined value */
1645 FIXME(mdi, "(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1646 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1647 nWidth,nHeight,hWndParent,hInstance,lParam);
1648 return (HWND32)NULL;
1652 /**********************************************************************
1653 * TranslateMDISysAccel32 (USER32.555)
1655 BOOL32 WINAPI TranslateMDISysAccel32( HWND32 hwndClient, LPMSG32 msg )
1657 MSG16 msg16;
1659 STRUCT32_MSG32to16(msg,&msg16);
1660 /* MDICLIENTINFO is still the same for win32 and win16 ... */
1661 return TranslateMDISysAccel16(hwndClient,&msg16);
1665 /**********************************************************************
1666 * TranslateMDISysAccel16 (USER.451)
1668 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
1670 WND* clientWnd = WIN_FindWndPtr( hwndClient);
1672 if( clientWnd && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
1674 MDICLIENTINFO *ci = NULL;
1675 WND* wnd;
1677 ci = (MDICLIENTINFO*) clientWnd->wExtra;
1678 wnd = WIN_FindWndPtr(ci->hwndActiveChild);
1679 if( wnd && !(wnd->dwStyle & WS_DISABLED) )
1681 WPARAM16 wParam = 0;
1683 /* translate if the Ctrl key is down and Alt not. */
1685 if( (GetKeyState32(VK_CONTROL) & 0x8000) &&
1686 !(GetKeyState32(VK_MENU) & 0x8000))
1688 switch( msg->wParam )
1690 case VK_F6:
1691 case VK_TAB:
1692 wParam = ( GetKeyState32(VK_SHIFT) & 0x8000 )
1693 ? SC_NEXTWINDOW : SC_PREVWINDOW;
1694 break;
1695 case VK_F4:
1696 case VK_RBUTTON:
1697 wParam = SC_CLOSE;
1698 break;
1699 default:
1700 return 0;
1702 TRACE(mdi,"wParam = %04x\n", wParam);
1703 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
1704 wParam, (LPARAM)msg->wParam);
1705 return 1;
1709 return 0; /* failure */
1713 /***********************************************************************
1714 * CalcChildScroll (USER.462)
1716 void WINAPI CalcChildScroll( HWND16 hwnd, WORD scroll )
1718 SCROLLINFO info;
1719 RECT32 childRect, clientRect;
1720 INT32 vmin, vmax, hmin, hmax, vpos, hpos;
1721 WND *pWnd, *Wnd;
1723 if (!(Wnd = pWnd = WIN_FindWndPtr( hwnd ))) return;
1724 GetClientRect32( hwnd, &clientRect );
1725 SetRectEmpty32( &childRect );
1727 for ( pWnd = pWnd->child; pWnd; pWnd = pWnd->next )
1729 if( pWnd->dwStyle & WS_MAXIMIZE )
1731 ShowScrollBar32(hwnd, SB_BOTH, FALSE);
1732 return;
1734 UnionRect32( &childRect, &pWnd->rectWindow, &childRect );
1736 UnionRect32( &childRect, &clientRect, &childRect );
1738 hmin = childRect.left; hmax = childRect.right - clientRect.right;
1739 hpos = clientRect.left - childRect.left;
1740 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
1741 vpos = clientRect.top - childRect.top;
1743 switch( scroll )
1745 case SB_HORZ:
1746 vpos = hpos; vmin = hmin; vmax = hmax;
1747 case SB_VERT:
1748 info.cbSize = sizeof(info);
1749 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
1750 info.fMask = SIF_POS | SIF_RANGE;
1751 SetScrollInfo32(hwnd, scroll, &info, TRUE);
1752 break;
1753 case SB_BOTH:
1754 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
1755 hmin, hmax, hpos);
1760 /***********************************************************************
1761 * ScrollChildren16 (USER.463)
1763 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
1765 return ScrollChildren32( hWnd, uMsg, wParam, lParam );
1769 /***********************************************************************
1770 * ScrollChildren32 (USER32.448)
1772 void WINAPI ScrollChildren32(HWND32 hWnd, UINT32 uMsg, WPARAM32 wParam,
1773 LPARAM lParam)
1775 WND *wndPtr = WIN_FindWndPtr(hWnd);
1776 INT32 newPos = -1;
1777 INT32 curPos, length, minPos, maxPos, shift;
1779 if( !wndPtr ) return;
1781 if( uMsg == WM_HSCROLL )
1783 GetScrollRange32(hWnd,SB_HORZ,&minPos,&maxPos);
1784 curPos = GetScrollPos32(hWnd,SB_HORZ);
1785 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
1786 shift = SYSMETRICS_CYHSCROLL;
1788 else if( uMsg == WM_VSCROLL )
1790 GetScrollRange32(hWnd,SB_VERT,&minPos,&maxPos);
1791 curPos = GetScrollPos32(hWnd,SB_VERT);
1792 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
1793 shift = SYSMETRICS_CXVSCROLL;
1795 else return;
1797 switch( wParam )
1799 case SB_LINEUP:
1800 newPos = curPos - shift;
1801 break;
1802 case SB_LINEDOWN:
1803 newPos = curPos + shift;
1804 break;
1805 case SB_PAGEUP:
1806 newPos = curPos - length;
1807 break;
1808 case SB_PAGEDOWN:
1809 newPos = curPos + length;
1810 break;
1812 case SB_THUMBPOSITION:
1813 newPos = LOWORD(lParam);
1814 break;
1816 case SB_THUMBTRACK:
1817 return;
1819 case SB_TOP:
1820 newPos = minPos;
1821 break;
1822 case SB_BOTTOM:
1823 newPos = maxPos;
1824 break;
1825 case SB_ENDSCROLL:
1826 CalcChildScroll(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
1827 return;
1830 if( newPos > maxPos )
1831 newPos = maxPos;
1832 else
1833 if( newPos < minPos )
1834 newPos = minPos;
1836 SetScrollPos32(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
1838 if( uMsg == WM_VSCROLL )
1839 ScrollWindowEx32(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
1840 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1841 else
1842 ScrollWindowEx32(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
1843 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1847 /******************************************************************************
1848 * CascadeWindows [USER32.21] Cascades MDI child windows
1850 * RETURNS
1851 * Success: Number of cascaded windows.
1852 * Failure: 0
1854 WORD WINAPI
1855 CascadeWindows (HWND32 hwndParent, UINT32 wFlags, const LPRECT32 lpRect,
1856 UINT32 cKids, const HWND32 *lpKids)
1858 FIXME (mdi, "(0x%08x,0x%08x,...,%u,...): stub\n",
1859 hwndParent, wFlags, cKids);
1861 return 0;
1865 /******************************************************************************
1866 * TileWindows [USER32.545] Tiles MDI child windows
1868 * RETURNS
1869 * Success: Number of tiled windows.
1870 * Failure: 0
1872 WORD WINAPI
1873 TileWindows (HWND32 hwndParent, UINT32 wFlags, const LPRECT32 lpRect,
1874 UINT32 cKids, const HWND32 *lpKids)
1876 FIXME (mdi, "(0x%08x,0x%08x,...,%u,...): stub\n",
1877 hwndParent, wFlags, cKids);
1879 return 0;