Added CoFreeLibrary stub.
[wine/multimedia.git] / windows / mdi.c
blob022d6b4029a661cea2e0732c970d0e074714c808
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 )
555 if( clientInfo->hwndChildMaximized != hWndChild )
556 if( hWndChild )
558 clientInfo->hwndActiveChild = hWndChild;
559 ShowWindow32( hWndChild, SW_SHOWMAXIMIZED);
561 else
562 ShowWindow32( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
564 clientInfo->hwndActiveChild = hWndChild;
566 /* check if we have any children left */
567 if( !hWndChild )
569 if( isActiveFrameWnd )
570 SetFocus32( clientInfo->self );
571 return 0;
574 /* check menu item */
575 if( clientInfo->hWindowMenu )
576 CheckMenuItem32( clientInfo->hWindowMenu,
577 wndPtr->wIDmenu, MF_CHECKED);
579 /* bring active child to the top */
580 SetWindowPos32( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
582 if( isActiveFrameWnd )
584 SendMessage32A( hWndChild, WM_NCACTIVATE, TRUE, 0L);
585 if( GetFocus32() == clientInfo->self )
586 SendMessage32A( clientInfo->self, WM_SETFOCUS,
587 (WPARAM32)clientInfo->self, 0L );
588 else
589 SetFocus32( clientInfo->self );
591 SendMessage32A( hWndChild, WM_MDIACTIVATE, (WPARAM32)prevActiveWnd,
592 (LPARAM)hWndChild );
593 return 1;
596 /* -------------------- MDI client window functions ------------------- */
598 /**********************************************************************
599 * CreateMDIMenuBitmap
601 static HBITMAP16 CreateMDIMenuBitmap(void)
603 HDC32 hDCSrc = CreateCompatibleDC32(0);
604 HDC32 hDCDest = CreateCompatibleDC32(hDCSrc);
605 HBITMAP16 hbClose = LoadBitmap16(0, MAKEINTRESOURCE16(OBM_CLOSE) );
606 HBITMAP16 hbCopy;
607 HANDLE16 hobjSrc, hobjDest;
609 hobjSrc = SelectObject32(hDCSrc, hbClose);
610 hbCopy = CreateCompatibleBitmap32(hDCSrc,SYSMETRICS_CXSIZE,SYSMETRICS_CYSIZE);
611 hobjDest = SelectObject32(hDCDest, hbCopy);
613 BitBlt32(hDCDest, 0, 0, SYSMETRICS_CXSIZE, SYSMETRICS_CYSIZE,
614 hDCSrc, SYSMETRICS_CXSIZE, 0, SRCCOPY);
616 SelectObject32(hDCSrc, hobjSrc);
617 DeleteObject32(hbClose);
618 DeleteDC32(hDCSrc);
620 hobjSrc = SelectObject32( hDCDest, GetStockObject32(BLACK_PEN) );
622 MoveToEx32( hDCDest, SYSMETRICS_CXSIZE - 1, 0, NULL );
623 LineTo32( hDCDest, SYSMETRICS_CXSIZE - 1, SYSMETRICS_CYSIZE - 1);
625 SelectObject32(hDCDest, hobjSrc );
626 SelectObject32(hDCDest, hobjDest);
627 DeleteDC32(hDCDest);
629 return hbCopy;
632 /**********************************************************************
633 * MDICascade
635 static LONG MDICascade(WND* clientWnd, MDICLIENTINFO *ci)
637 WND** ppWnd;
638 UINT32 total;
640 if (ci->hwndChildMaximized)
641 ShowWindow16( ci->hwndChildMaximized, SW_NORMAL);
643 if (ci->nActiveChildren == 0) return 0;
645 if ((ppWnd = WIN_BuildWinArray(clientWnd, BWA_SKIPHIDDEN | BWA_SKIPOWNED |
646 BWA_SKIPICONIC, &total)))
648 WND** heapPtr = ppWnd;
649 if( total )
651 INT32 delta = 0, n = 0;
652 POINT32 pos[2];
653 if( total < ci->nActiveChildren )
654 delta = SYSMETRICS_CYICONSPACING + SYSMETRICS_CYICON;
656 /* walk the list (backwards) and move windows */
657 while (*ppWnd) ppWnd++;
658 while (ppWnd != heapPtr)
660 ppWnd--;
661 TRACE(mdi, "move %04x to (%d,%d) size [%d,%d]\n",
662 (*ppWnd)->hwndSelf, pos[0].x, pos[0].y, pos[1].x, pos[1].y);
664 MDI_CalcDefaultChildPos(clientWnd, n++, pos, delta);
665 SetWindowPos32( (*ppWnd)->hwndSelf, 0, pos[0].x, pos[0].y,
666 pos[1].x, pos[1].y,
667 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
670 HeapFree( SystemHeap, 0, heapPtr );
673 if( total < ci->nActiveChildren )
674 ArrangeIconicWindows32( clientWnd->hwndSelf );
675 return 0;
678 /**********************************************************************
679 * MDITile
681 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM32 wParam )
683 WND** ppWnd;
684 UINT32 total = 0;
686 if (ci->hwndChildMaximized)
687 ShowWindow32(ci->hwndChildMaximized, SW_NORMAL);
689 if (ci->nActiveChildren == 0) return;
691 ppWnd = WIN_BuildWinArray(wndClient, BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
692 ((wParam & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
694 TRACE(mdi,"%u windows to tile\n", total);
696 if( ppWnd )
698 WND** heapPtr = ppWnd;
700 if( total )
702 RECT32 rect;
703 int x, y, xsize, ysize;
704 int rows, columns, r, c, i;
706 rect = wndClient->rectClient;
707 rows = (int) sqrt((double)total);
708 columns = total / rows;
710 if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */
712 i = rows;
713 rows = columns; /* exchange r and c */
714 columns = i;
717 if( total != ci->nActiveChildren)
719 y = rect.bottom - 2 * SYSMETRICS_CYICONSPACING - SYSMETRICS_CYICON;
720 rect.bottom = ( y - SYSMETRICS_CYICON < rect.top )? rect.bottom: y;
723 ysize = rect.bottom / rows;
724 xsize = rect.right / columns;
726 for (x = i = 0, c = 1; c <= columns && *ppWnd; c++)
728 if (c == columns)
730 rows = total - i;
731 ysize = rect.bottom / rows;
734 y = 0;
735 for (r = 1; r <= rows && *ppWnd; r++, i++)
737 SetWindowPos32((*ppWnd)->hwndSelf, 0, x, y, xsize, ysize,
738 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
739 y += ysize;
740 ppWnd++;
742 x += xsize;
745 HeapFree( SystemHeap, 0, heapPtr );
748 if( total < ci->nActiveChildren ) ArrangeIconicWindows32( wndClient->hwndSelf );
751 /* ----------------------- Frame window ---------------------------- */
754 /**********************************************************************
755 * MDI_AugmentFrameMenu
757 static BOOL32 MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
758 HWND32 hChild )
760 WND* child = WIN_FindWndPtr(hChild);
761 HMENU32 hSysPopup = 0;
763 TRACE(mdi,"frame %p,child %04x\n",frame,hChild);
765 if( !frame->wIDmenu || !child->hSysMenu ) return 0;
767 /* create a copy of sysmenu popup and insert it into frame menu bar */
769 if (!(hSysPopup = LoadMenuIndirect32A(SYSRES_GetResPtr(SYSRES_MENU_SYSMENU))))
770 return 0;
772 TRACE(mdi,"\tgot popup %04x in sysmenu %04x\n",
773 hSysPopup, child->hSysMenu);
775 if( !InsertMenu32A(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
776 hSysPopup, (LPSTR)(DWORD)hBmpClose ))
778 DestroyMenu32(hSysPopup);
779 return 0;
782 if( !AppendMenu32A(frame->wIDmenu,MF_HELP | MF_BITMAP,
783 SC_RESTORE, (LPSTR)(DWORD)hBmpRestore ))
785 RemoveMenu32(frame->wIDmenu,0,MF_BYPOSITION);
786 return 0;
789 EnableMenuItem32(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
790 EnableMenuItem32(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
791 EnableMenuItem32(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
793 /* redraw menu */
794 DrawMenuBar32(frame->hwndSelf);
796 return 1;
799 /**********************************************************************
800 * MDI_RestoreFrameMenu
802 static BOOL32 MDI_RestoreFrameMenu( WND *frameWnd, HWND32 hChild )
804 INT32 nItems = GetMenuItemCount32(frameWnd->wIDmenu) - 1;
806 TRACE(mdi,"for child %04x\n",hChild);
808 if( GetMenuItemID32(frameWnd->wIDmenu,nItems) != SC_RESTORE )
809 return 0;
811 RemoveMenu32(frameWnd->wIDmenu,0,MF_BYPOSITION);
812 DeleteMenu32(frameWnd->wIDmenu,nItems-1,MF_BYPOSITION);
814 DrawMenuBar32(frameWnd->hwndSelf);
816 return 1;
819 /**********************************************************************
820 * MDI_UpdateFrameText
822 * used when child window is maximized/restored
824 * Note: lpTitle can be NULL
826 static void MDI_UpdateFrameText( WND *frameWnd, HWND32 hClient,
827 BOOL32 repaint, LPCSTR lpTitle )
829 char lpBuffer[MDI_MAXTITLELENGTH+1];
830 WND* clientWnd = WIN_FindWndPtr(hClient);
831 MDICLIENTINFO *ci = (MDICLIENTINFO *) clientWnd->wExtra;
833 TRACE(mdi, "repaint %i, frameText %s\n", repaint, (lpTitle)?lpTitle:"NULL");
835 if (!clientWnd)
836 return;
838 if (!ci)
839 return;
841 /* store new "default" title if lpTitle is not NULL */
842 if (lpTitle)
844 if (ci->frameTitle) HeapFree( SystemHeap, 0, ci->frameTitle );
845 ci->frameTitle = HEAP_strdupA( SystemHeap, 0, lpTitle );
848 if (ci->frameTitle)
850 WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );
852 if( childWnd && childWnd->text )
854 /* combine frame title and child title if possible */
856 LPCSTR lpBracket = " - [";
857 int i_frame_text_length = strlen(ci->frameTitle);
858 int i_child_text_length = strlen(childWnd->text);
860 lstrcpyn32A( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
862 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
864 strcat( lpBuffer, lpBracket );
866 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
868 strcat( lpBuffer, childWnd->text );
869 strcat( lpBuffer, "]" );
871 else
873 lstrcpyn32A( lpBuffer + i_frame_text_length + 4,
874 childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
875 strcat( lpBuffer, "]" );
879 else
881 strncpy(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH );
882 lpBuffer[MDI_MAXTITLELENGTH]='\0';
885 else
886 lpBuffer[0] = '\0';
888 DEFWND_SetText( frameWnd, lpBuffer );
889 if( repaint == MDI_REPAINTFRAME)
890 SetWindowPos32( frameWnd->hwndSelf, 0,0,0,0,0, SWP_FRAMECHANGED |
891 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
895 /* ----------------------------- Interface ---------------------------- */
898 /**********************************************************************
899 * MDIClientWndProc
901 * This function handles all MDI requests.
903 LRESULT WINAPI MDIClientWndProc( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
904 LPARAM lParam )
906 LPCREATESTRUCT32A cs;
907 MDICLIENTINFO *ci;
908 RECT32 rect;
909 WND *w = WIN_FindWndPtr(hwnd);
910 WND *frameWnd = w->parent;
911 INT32 nItems;
913 ci = (MDICLIENTINFO *) w->wExtra;
915 switch (message)
917 case WM_CREATE:
919 cs = (LPCREATESTRUCT32A)lParam;
921 /* Translation layer doesn't know what's in the cs->lpCreateParams
922 * so we have to keep track of what environment we're in. */
924 if( w->flags & WIN_ISWIN32 )
926 #define ccs ((LPCLIENTCREATESTRUCT32)cs->lpCreateParams)
927 ci->hWindowMenu = ccs->hWindowMenu;
928 ci->idFirstChild = ccs->idFirstChild;
929 #undef ccs
931 else
933 LPCLIENTCREATESTRUCT16 ccs = (LPCLIENTCREATESTRUCT16)
934 PTR_SEG_TO_LIN(cs->lpCreateParams);
935 ci->hWindowMenu = ccs->hWindowMenu;
936 ci->idFirstChild = ccs->idFirstChild;
939 ci->hwndChildMaximized = 0;
940 ci->nActiveChildren = 0;
941 ci->nTotalCreated = 0;
942 ci->frameTitle = NULL;
943 ci->mdiFlags = 0;
944 ci->self = hwnd;
945 w->dwStyle |= WS_CLIPCHILDREN;
947 if (!hBmpClose)
949 hBmpClose = CreateMDIMenuBitmap();
950 hBmpRestore = LoadBitmap16( 0, MAKEINTRESOURCE16(OBM_RESTORE) );
952 MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
954 AppendMenu32A( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
956 GetClientRect32(frameWnd->hwndSelf, &rect);
957 NC_HandleNCCalcSize( w, &rect );
958 w->rectClient = rect;
960 TRACE(mdi,"Client created - hwnd = %04x, idFirst = %u\n",
961 hwnd, ci->idFirstChild );
963 return 0;
965 case WM_DESTROY:
966 if( ci->hwndChildMaximized ) MDI_RestoreFrameMenu(w, frameWnd->hwndSelf);
967 if((nItems = GetMenuItemCount32(ci->hWindowMenu)) > 0)
969 ci->idFirstChild = nItems - 1;
970 ci->nActiveChildren++; /* to delete a separator */
971 while( ci->nActiveChildren-- )
972 DeleteMenu32(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
974 return 0;
976 case WM_MDIACTIVATE:
977 if( ci->hwndActiveChild != (HWND32)wParam )
978 SetWindowPos32((HWND32)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
979 return 0;
981 case WM_MDICASCADE:
982 return MDICascade(w, ci);
984 case WM_MDICREATE:
985 if (lParam) return MDICreateChild( w, ci, hwnd,
986 (MDICREATESTRUCT32A*)lParam );
987 return 0;
989 case WM_MDIDESTROY:
990 return MDIDestroyChild( w, ci, hwnd, (HWND32)wParam, TRUE );
992 case WM_MDIGETACTIVE:
993 if (lParam) *(BOOL32 *)lParam = (ci->hwndChildMaximized > 0);
994 return ci->hwndActiveChild;
996 case WM_MDIICONARRANGE:
997 ci->mdiFlags |= MDIF_NEEDUPDATE;
998 ArrangeIconicWindows32(hwnd);
999 ci->sbRecalc = SB_BOTH+1;
1000 SendMessage32A(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
1001 return 0;
1003 case WM_MDIMAXIMIZE:
1004 ShowWindow32( (HWND32)wParam, SW_MAXIMIZE );
1005 return 0;
1007 case WM_MDINEXT: /* lParam != 0 means previous window */
1008 MDI_SwitchActiveChild(hwnd, (HWND32)wParam, (lParam)? FALSE : TRUE );
1009 break;
1011 case WM_MDIRESTORE:
1012 ShowWindow32( (HWND32)wParam, SW_NORMAL);
1013 return 0;
1015 case WM_MDISETMENU:
1016 return MDISetMenu( hwnd, (HMENU32)wParam, (HMENU32)lParam );
1018 case WM_MDIREFRESHMENU:
1019 return MDIRefreshMenu( hwnd, (HMENU32)wParam, (HMENU32)lParam );
1021 case WM_MDITILE:
1022 ci->mdiFlags |= MDIF_NEEDUPDATE;
1023 ShowScrollBar32(hwnd,SB_BOTH,FALSE);
1024 MDITile(w, ci, wParam);
1025 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1026 return 0;
1028 case WM_VSCROLL:
1029 case WM_HSCROLL:
1030 ci->mdiFlags |= MDIF_NEEDUPDATE;
1031 ScrollChildren32(hwnd, message, wParam, lParam);
1032 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1033 return 0;
1035 case WM_SETFOCUS:
1036 if( ci->hwndActiveChild )
1038 w = WIN_FindWndPtr( ci->hwndActiveChild );
1039 if( !(w->dwStyle & WS_MINIMIZE) )
1040 SetFocus32( ci->hwndActiveChild );
1042 return 0;
1044 case WM_NCACTIVATE:
1045 if( ci->hwndActiveChild )
1046 SendMessage32A(ci->hwndActiveChild, message, wParam, lParam);
1047 break;
1049 case WM_PARENTNOTIFY:
1050 if (LOWORD(wParam) == WM_LBUTTONDOWN)
1052 POINT16 pt = MAKEPOINT16(lParam);
1053 HWND16 child = ChildWindowFromPoint16(hwnd, pt);
1055 TRACE(mdi,"notification from %04x (%i,%i)\n",child,pt.x,pt.y);
1057 if( child && child != hwnd && child != ci->hwndActiveChild )
1058 SetWindowPos32(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1060 return 0;
1062 case WM_SIZE:
1063 if( ci->hwndChildMaximized )
1065 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1066 RECT32 rect = { 0, 0, LOWORD(lParam), HIWORD(lParam) };
1068 AdjustWindowRectEx32(&rect, child->dwStyle, 0, child->dwExStyle);
1069 MoveWindow32(ci->hwndChildMaximized, rect.left, rect.top,
1070 rect.right - rect.left, rect.bottom - rect.top, 1);
1072 else
1073 MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1075 break;
1077 case WM_MDICALCCHILDSCROLL:
1078 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1080 CalcChildScroll(hwnd, ci->sbRecalc-1);
1081 ci->sbRecalc = 0;
1082 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1084 return 0;
1087 return DefWindowProc32A( hwnd, message, wParam, lParam );
1091 /***********************************************************************
1092 * DefFrameProc16 (USER.445)
1094 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1095 UINT16 message, WPARAM16 wParam, LPARAM lParam )
1097 HWND16 childHwnd;
1098 MDICLIENTINFO* ci;
1099 WND* wndPtr;
1101 if (hwndMDIClient)
1103 switch (message)
1105 case WM_COMMAND:
1106 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1107 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1109 /* check for possible syscommands for maximized MDI child */
1111 if( ci && (
1112 wParam < ci->idFirstChild ||
1113 wParam >= ci->idFirstChild + ci->nActiveChildren
1115 if( (wParam - 0xF000) & 0xF00F ) break;
1116 switch( wParam )
1118 case SC_SIZE:
1119 case SC_MOVE:
1120 case SC_MINIMIZE:
1121 case SC_MAXIMIZE:
1122 case SC_NEXTWINDOW:
1123 case SC_PREVWINDOW:
1124 case SC_CLOSE:
1125 case SC_RESTORE:
1126 if( ci->hwndChildMaximized )
1127 return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1128 wParam, lParam);
1131 else
1133 childHwnd = MDI_GetChildByID( WIN_FindWndPtr(hwndMDIClient),
1134 wParam );
1135 if( childHwnd )
1136 SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1137 (WPARAM16)childHwnd , 0L);
1139 break;
1141 case WM_NCACTIVATE:
1142 SendMessage16(hwndMDIClient, message, wParam, lParam);
1143 break;
1145 case WM_SETTEXT:
1146 MDI_UpdateFrameText(WIN_FindWndPtr(hwnd), hwndMDIClient,
1147 MDI_REPAINTFRAME,
1148 (LPCSTR)PTR_SEG_TO_LIN(lParam));
1149 return 0;
1151 case WM_SETFOCUS:
1152 SetFocus32(hwndMDIClient);
1153 break;
1155 case WM_SIZE:
1156 MoveWindow16(hwndMDIClient, 0, 0,
1157 LOWORD(lParam), HIWORD(lParam), TRUE);
1158 break;
1160 case WM_NEXTMENU:
1162 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1163 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1165 if( !(wndPtr->parent->dwStyle & WS_MINIMIZE)
1166 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1168 /* control menu is between the frame system menu and
1169 * the first entry of menu bar */
1171 if( (wParam == VK_LEFT &&
1172 wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1173 (wParam == VK_RIGHT &&
1174 GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1176 wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1177 return MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1178 ci->hwndActiveChild);
1181 break;
1185 return DefWindowProc16(hwnd, message, wParam, lParam);
1189 /***********************************************************************
1190 * DefFrameProc32A (USER32.122)
1192 LRESULT WINAPI DefFrameProc32A( HWND32 hwnd, HWND32 hwndMDIClient,
1193 UINT32 message, WPARAM32 wParam, LPARAM lParam)
1195 if (hwndMDIClient)
1197 switch (message)
1199 case WM_COMMAND:
1200 return DefFrameProc16( hwnd, hwndMDIClient, message,
1201 (WPARAM16)wParam,
1202 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1204 case WM_NCACTIVATE:
1205 SendMessage32A(hwndMDIClient, message, wParam, lParam);
1206 break;
1208 case WM_SETTEXT: {
1209 LRESULT ret;
1210 LPSTR segstr = SEGPTR_STRDUP((LPSTR)lParam);
1212 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1213 wParam, (LPARAM)SEGPTR_GET(segstr) );
1214 SEGPTR_FREE(segstr);
1215 return ret;
1218 case WM_NEXTMENU:
1219 case WM_SETFOCUS:
1220 case WM_SIZE:
1221 return DefFrameProc16( hwnd, hwndMDIClient, message,
1222 wParam, lParam );
1226 return DefWindowProc32A(hwnd, message, wParam, lParam);
1230 /***********************************************************************
1231 * DefFrameProc32W (USER32.123)
1233 LRESULT WINAPI DefFrameProc32W( HWND32 hwnd, HWND32 hwndMDIClient,
1234 UINT32 message, WPARAM32 wParam, LPARAM lParam)
1236 if (hwndMDIClient)
1238 switch (message)
1240 case WM_COMMAND:
1241 return DefFrameProc16( hwnd, hwndMDIClient, message,
1242 (WPARAM16)wParam,
1243 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1245 case WM_NCACTIVATE:
1246 SendMessage32W(hwndMDIClient, message, wParam, lParam);
1247 break;
1249 case WM_SETTEXT:
1251 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1252 LRESULT ret = DefFrameProc32A( hwnd, hwndMDIClient, message,
1253 wParam, (DWORD)txt );
1254 HeapFree(GetProcessHeap(),0,txt);
1255 return ret;
1257 case WM_NEXTMENU:
1258 case WM_SETFOCUS:
1259 case WM_SIZE:
1260 return DefFrameProc32A( hwnd, hwndMDIClient, message,
1261 wParam, lParam );
1265 return DefWindowProc32W( hwnd, message, wParam, lParam );
1269 /***********************************************************************
1270 * DefMDIChildProc16 (USER.447)
1272 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1273 WPARAM16 wParam, LPARAM lParam )
1275 MDICLIENTINFO *ci;
1276 WND *clientWnd;
1278 clientWnd = WIN_FindWndPtr(GetParent16(hwnd));
1279 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1281 switch (message)
1283 case WM_SETTEXT:
1284 DefWindowProc16(hwnd, message, wParam, lParam);
1285 MDI_MenuModifyItem(clientWnd,hwnd);
1286 if( ci->hwndChildMaximized == hwnd )
1287 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1288 MDI_REPAINTFRAME, NULL );
1289 return 0;
1291 case WM_CLOSE:
1292 SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1293 return 0;
1295 case WM_SETFOCUS:
1296 if( ci->hwndActiveChild != hwnd )
1297 MDI_ChildActivate(clientWnd, hwnd);
1298 break;
1300 case WM_CHILDACTIVATE:
1301 MDI_ChildActivate(clientWnd, hwnd);
1302 return 0;
1304 case WM_NCPAINT:
1305 TRACE(mdi,"WM_NCPAINT for %04x, active %04x\n",
1306 hwnd, ci->hwndActiveChild );
1307 break;
1309 case WM_SYSCOMMAND:
1310 switch( wParam )
1312 case SC_MOVE:
1313 if( ci->hwndChildMaximized == hwnd) return 0;
1314 break;
1315 case SC_RESTORE:
1316 case SC_MINIMIZE:
1317 WIN_FindWndPtr(hwnd)->dwStyle |= WS_SYSMENU;
1318 break;
1319 case SC_MAXIMIZE:
1320 if( ci->hwndChildMaximized == hwnd)
1321 return SendMessage16( clientWnd->parent->hwndSelf,
1322 message, wParam, lParam);
1323 WIN_FindWndPtr(hwnd)->dwStyle &= ~WS_SYSMENU;
1324 break;
1325 case SC_NEXTWINDOW:
1326 SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1327 return 0;
1328 case SC_PREVWINDOW:
1329 SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1330 return 0;
1332 break;
1334 case WM_GETMINMAXINFO:
1335 MDI_ChildGetMinMaxInfo(clientWnd, hwnd, (MINMAXINFO16*) PTR_SEG_TO_LIN(lParam));
1336 return 0;
1338 case WM_SETVISIBLE:
1339 if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1340 else
1341 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1342 break;
1344 case WM_SIZE:
1345 /* do not change */
1347 if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1349 ci->hwndChildMaximized = 0;
1351 MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1352 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1353 MDI_REPAINTFRAME, NULL );
1356 if( wParam == SIZE_MAXIMIZED )
1358 HWND16 hMaxChild = ci->hwndChildMaximized;
1360 if( hMaxChild == hwnd ) break;
1362 if( hMaxChild)
1364 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1366 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1367 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1369 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1372 TRACE(mdi,"maximizing child %04x\n", hwnd );
1374 ci->hwndChildMaximized = hwnd; /* !!! */
1376 MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1377 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1378 MDI_REPAINTFRAME, NULL );
1381 if( wParam == SIZE_MINIMIZED )
1383 HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1385 if( switchTo )
1386 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1389 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1390 break;
1392 case WM_MENUCHAR:
1394 /* MDI children don't have menu bars */
1395 PostMessage16( clientWnd->parent->hwndSelf, WM_SYSCOMMAND,
1396 (WPARAM16)SC_KEYMENU, (LPARAM)wParam);
1397 return 0x00010000L;
1399 case WM_NEXTMENU:
1401 if( wParam == VK_LEFT ) /* switch to frame system menu */
1402 return MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1403 clientWnd->parent->hwndSelf );
1404 if( wParam == VK_RIGHT ) /* to frame menu bar */
1405 return MAKELONG( clientWnd->parent->wIDmenu,
1406 clientWnd->parent->hwndSelf );
1408 break;
1410 case WM_SYSCHAR:
1411 if (wParam == '-')
1413 SendMessage16(hwnd,WM_SYSCOMMAND,
1414 (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1415 return 0;
1419 return DefWindowProc16(hwnd, message, wParam, lParam);
1423 /***********************************************************************
1424 * DefMDIChildProc32A (USER32.124)
1426 LRESULT WINAPI DefMDIChildProc32A( HWND32 hwnd, UINT32 message,
1427 WPARAM32 wParam, LPARAM lParam )
1429 MDICLIENTINFO *ci;
1430 WND *clientWnd;
1432 clientWnd = WIN_FindWndPtr(WIN_FindWndPtr(hwnd)->parent->hwndSelf);
1433 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1435 switch (message)
1437 case WM_SETTEXT:
1438 DefWindowProc32A(hwnd, message, wParam, lParam);
1439 MDI_MenuModifyItem(clientWnd,hwnd);
1440 if( ci->hwndChildMaximized == hwnd )
1441 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1442 MDI_REPAINTFRAME, NULL );
1443 return 0;
1445 case WM_GETMINMAXINFO:
1447 MINMAXINFO16 mmi;
1448 STRUCT32_MINMAXINFO32to16( (MINMAXINFO32 *)lParam, &mmi );
1449 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1450 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO32 *)lParam );
1452 return 0;
1454 case WM_MENUCHAR:
1456 /* MDI children don't have menu bars */
1457 PostMessage16( clientWnd->parent->hwndSelf, WM_SYSCOMMAND,
1458 (WPARAM16)SC_KEYMENU, (LPARAM)LOWORD(wParam) );
1459 return 0x00010000L;
1461 case WM_CLOSE:
1462 case WM_SETFOCUS:
1463 case WM_CHILDACTIVATE:
1464 case WM_NCPAINT:
1465 case WM_SYSCOMMAND:
1466 case WM_SETVISIBLE:
1467 case WM_SIZE:
1468 case WM_NEXTMENU:
1469 return DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1471 case WM_SYSCHAR:
1472 if (wParam == '-')
1474 SendMessage32A(hwnd,WM_SYSCOMMAND,
1475 (WPARAM32)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1476 return 0;
1479 return DefWindowProc32A(hwnd, message, wParam, lParam);
1483 /***********************************************************************
1484 * DefMDIChildProc32W (USER32.125)
1486 LRESULT WINAPI DefMDIChildProc32W( HWND32 hwnd, UINT32 message,
1487 WPARAM32 wParam, LPARAM lParam )
1489 MDICLIENTINFO *ci;
1490 WND *clientWnd;
1492 clientWnd = WIN_FindWndPtr(GetParent16(hwnd));
1493 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1495 switch (message)
1497 case WM_SETTEXT:
1498 DefWindowProc32W(hwnd, message, wParam, lParam);
1499 MDI_MenuModifyItem(clientWnd,hwnd);
1500 if( ci->hwndChildMaximized == hwnd )
1501 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1502 MDI_REPAINTFRAME, NULL );
1503 return 0;
1505 case WM_GETMINMAXINFO:
1506 case WM_MENUCHAR:
1507 case WM_CLOSE:
1508 case WM_SETFOCUS:
1509 case WM_CHILDACTIVATE:
1510 case WM_NCPAINT:
1511 case WM_SYSCOMMAND:
1512 case WM_SETVISIBLE:
1513 case WM_SIZE:
1514 case WM_NEXTMENU:
1515 return DefMDIChildProc32A( hwnd, message, (WPARAM16)wParam, lParam );
1517 case WM_SYSCHAR:
1518 if (wParam == '-')
1520 SendMessage32W(hwnd,WM_SYSCOMMAND,
1521 (WPARAM32)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1522 return 0;
1525 return DefWindowProc32W(hwnd, message, wParam, lParam);
1529 /**********************************************************************
1530 * CreateMDIWindowA [USER32.79]
1532 HWND32 WINAPI CreateMDIWindowA(
1533 LPCSTR lpClassName,
1534 LPCSTR lpWindowName,
1535 DWORD dwStyle,
1536 INT32 X,
1537 INT32 Y,
1538 INT32 nWidth,
1539 INT32 nHeight,
1540 HWND32 hWndParent,
1541 HINSTANCE32 hInstance,
1542 LPARAM lParam)
1544 FIXME(mdi, "(%s,%s,%ld,...): stub\n",debugstr_a(lpClassName),
1545 debugstr_a(lpWindowName),dwStyle);
1546 return (HWND32)NULL;
1550 /******************************************************************************
1551 * CreateMDIWindowW [USER32.80] Creates a MDI child window
1553 * RETURNS
1554 * Success: Handle to created window
1555 * Failure: NULL
1557 HWND32 WINAPI CreateMDIWindowW(
1558 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1559 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1560 DWORD dwStyle, /* [in] Window style */
1561 INT32 X, /* [in] Horizontal position of window */
1562 INT32 Y, /* [in] Vertical position of window */
1563 INT32 nWidth, /* [in] Width of window */
1564 INT32 nHeight, /* [in] Height of window */
1565 HWND32 hWndParent, /* [in] Handle to parent window */
1566 HINSTANCE32 hInstance, /* [in] Handle to application instance */
1567 LPARAM lParam) /* [in] Application-defined value */
1569 FIXME(mdi, "(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1570 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1571 nWidth,nHeight,hWndParent,hInstance,lParam);
1572 return (HWND32)NULL;
1576 /**********************************************************************
1577 * TranslateMDISysAccel32 (USER32.555)
1579 BOOL32 WINAPI TranslateMDISysAccel32( HWND32 hwndClient, LPMSG32 msg )
1581 MSG16 msg16;
1583 STRUCT32_MSG32to16(msg,&msg16);
1584 /* MDICLIENTINFO is still the same for win32 and win16 ... */
1585 return TranslateMDISysAccel16(hwndClient,&msg16);
1589 /**********************************************************************
1590 * TranslateMDISysAccel16 (USER.451)
1592 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
1594 WND* clientWnd = WIN_FindWndPtr( hwndClient);
1596 if( clientWnd && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
1598 MDICLIENTINFO *ci = NULL;
1599 WND* wnd;
1601 ci = (MDICLIENTINFO*) clientWnd->wExtra;
1602 wnd = WIN_FindWndPtr(ci->hwndActiveChild);
1603 if( wnd && !(wnd->dwStyle & WS_DISABLED) )
1605 WPARAM16 wParam = 0;
1607 /* translate if the Ctrl key is down and Alt not. */
1609 if( (GetKeyState32(VK_CONTROL) & 0x8000) &&
1610 !(GetKeyState32(VK_MENU) & 0x8000))
1612 switch( msg->wParam )
1614 case VK_F6:
1615 case VK_TAB:
1616 wParam = ( GetKeyState32(VK_SHIFT) & 0x8000 )
1617 ? SC_NEXTWINDOW : SC_PREVWINDOW;
1618 break;
1619 case VK_F4:
1620 case VK_RBUTTON:
1621 wParam = SC_CLOSE;
1622 break;
1623 default:
1624 return 0;
1626 TRACE(mdi,"wParam = %04x\n", wParam);
1627 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
1628 wParam, (LPARAM)msg->wParam);
1629 return 1;
1633 return 0; /* failure */
1637 /***********************************************************************
1638 * CalcChildScroll (USER.462)
1640 void WINAPI CalcChildScroll( HWND16 hwnd, WORD scroll )
1642 SCROLLINFO info;
1643 RECT32 childRect, clientRect;
1644 INT32 vmin, vmax, hmin, hmax, vpos, hpos;
1645 WND *pWnd, *Wnd;
1647 if (!(Wnd = pWnd = WIN_FindWndPtr( hwnd ))) return;
1648 GetClientRect32( hwnd, &clientRect );
1649 SetRectEmpty32( &childRect );
1651 for ( pWnd = pWnd->child; pWnd; pWnd = pWnd->next )
1653 if( pWnd->dwStyle & WS_MAXIMIZE )
1655 ShowScrollBar32(hwnd, SB_BOTH, FALSE);
1656 return;
1658 UnionRect32( &childRect, &pWnd->rectWindow, &childRect );
1660 UnionRect32( &childRect, &clientRect, &childRect );
1662 hmin = childRect.left; hmax = childRect.right - clientRect.right;
1663 hpos = clientRect.left - childRect.left;
1664 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
1665 vpos = clientRect.top - childRect.top;
1667 switch( scroll )
1669 case SB_HORZ:
1670 vpos = hpos; vmin = hmin; vmax = hmax;
1671 case SB_VERT:
1672 info.cbSize = sizeof(info);
1673 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
1674 info.fMask = SIF_POS | SIF_RANGE;
1675 SetScrollInfo32(hwnd, scroll, &info, TRUE);
1676 break;
1677 case SB_BOTH:
1678 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
1679 hmin, hmax, hpos);
1684 /***********************************************************************
1685 * ScrollChildren16 (USER.463)
1687 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
1689 return ScrollChildren32( hWnd, uMsg, wParam, lParam );
1693 /***********************************************************************
1694 * ScrollChildren32 (USER32.448)
1696 void WINAPI ScrollChildren32(HWND32 hWnd, UINT32 uMsg, WPARAM32 wParam,
1697 LPARAM lParam)
1699 WND *wndPtr = WIN_FindWndPtr(hWnd);
1700 INT32 newPos = -1;
1701 INT32 curPos, length, minPos, maxPos, shift;
1703 if( !wndPtr ) return;
1705 if( uMsg == WM_HSCROLL )
1707 GetScrollRange32(hWnd,SB_HORZ,&minPos,&maxPos);
1708 curPos = GetScrollPos32(hWnd,SB_HORZ);
1709 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
1710 shift = SYSMETRICS_CYHSCROLL;
1712 else if( uMsg == WM_VSCROLL )
1714 GetScrollRange32(hWnd,SB_VERT,&minPos,&maxPos);
1715 curPos = GetScrollPos32(hWnd,SB_VERT);
1716 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
1717 shift = SYSMETRICS_CXVSCROLL;
1719 else return;
1721 switch( wParam )
1723 case SB_LINEUP:
1724 newPos = curPos - shift;
1725 break;
1726 case SB_LINEDOWN:
1727 newPos = curPos + shift;
1728 break;
1729 case SB_PAGEUP:
1730 newPos = curPos - length;
1731 break;
1732 case SB_PAGEDOWN:
1733 newPos = curPos + length;
1734 break;
1736 case SB_THUMBPOSITION:
1737 newPos = LOWORD(lParam);
1738 break;
1740 case SB_THUMBTRACK:
1741 return;
1743 case SB_TOP:
1744 newPos = minPos;
1745 break;
1746 case SB_BOTTOM:
1747 newPos = maxPos;
1748 break;
1749 case SB_ENDSCROLL:
1750 CalcChildScroll(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
1751 return;
1754 if( newPos > maxPos )
1755 newPos = maxPos;
1756 else
1757 if( newPos < minPos )
1758 newPos = minPos;
1760 SetScrollPos32(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
1762 if( uMsg == WM_VSCROLL )
1763 ScrollWindowEx32(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
1764 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1765 else
1766 ScrollWindowEx32(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
1767 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1771 /******************************************************************************
1772 * CascadeWindows [USER32.21] Cascades MDI child windows
1774 * RETURNS
1775 * Success: Number of cascaded windows.
1776 * Failure: 0
1778 WORD WINAPI
1779 CascadeWindows (HWND32 hwndParent, UINT32 wFlags, const LPRECT32 lpRect,
1780 UINT32 cKids, const HWND32 *lpKids)
1782 FIXME (mdi, "(0x%08x,0x%08x,...,%u,...): stub\n",
1783 hwndParent, wFlags, cKids);
1785 return 0;
1789 /******************************************************************************
1790 * TileWindows [USER32.545] Tiles MDI child windows
1792 * RETURNS
1793 * Success: Number of tiled windows.
1794 * Failure: 0
1796 WORD WINAPI
1797 TileWindows (HWND32 hwndParent, UINT32 wFlags, const LPRECT32 lpRect,
1798 UINT32 cKids, const HWND32 *lpKids)
1800 FIXME (mdi, "(0x%08x,0x%08x,...,%u,...): stub\n",
1801 hwndParent, wFlags, cKids);
1803 return 0;