ugfixes for IPX code and preliminary groundwork for other address
[wine.git] / windows / mdi.c
blobb551ba52bede2be641b9d383f346d7df58b187c7
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 ShowWindow16( ci->hwndChildMaximized, SW_NORMAL);
645 if (ci->nActiveChildren == 0) return 0;
647 if ((ppWnd = WIN_BuildWinArray(clientWnd, BWA_SKIPHIDDEN | BWA_SKIPOWNED |
648 BWA_SKIPICONIC, &total)))
650 WND** heapPtr = ppWnd;
651 if( total )
653 INT32 delta = 0, n = 0;
654 POINT32 pos[2];
655 if( total < ci->nActiveChildren )
656 delta = SYSMETRICS_CYICONSPACING + SYSMETRICS_CYICON;
658 /* walk the list (backwards) and move windows */
659 while (*ppWnd) ppWnd++;
660 while (ppWnd != heapPtr)
662 ppWnd--;
663 TRACE(mdi, "move %04x to (%d,%d) size [%d,%d]\n",
664 (*ppWnd)->hwndSelf, pos[0].x, pos[0].y, pos[1].x, pos[1].y);
666 MDI_CalcDefaultChildPos(clientWnd, n++, pos, delta);
667 SetWindowPos32( (*ppWnd)->hwndSelf, 0, pos[0].x, pos[0].y,
668 pos[1].x, pos[1].y,
669 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
672 HeapFree( SystemHeap, 0, heapPtr );
675 if( total < ci->nActiveChildren )
676 ArrangeIconicWindows32( clientWnd->hwndSelf );
677 return 0;
680 /**********************************************************************
681 * MDITile
683 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM32 wParam )
685 WND** ppWnd;
686 UINT32 total = 0;
688 if (ci->hwndChildMaximized)
689 ShowWindow32(ci->hwndChildMaximized, SW_NORMAL);
691 if (ci->nActiveChildren == 0) return;
693 ppWnd = WIN_BuildWinArray(wndClient, BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
694 ((wParam & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
696 TRACE(mdi,"%u windows to tile\n", total);
698 if( ppWnd )
700 WND** heapPtr = ppWnd;
702 if( total )
704 RECT32 rect;
705 int x, y, xsize, ysize;
706 int rows, columns, r, c, i;
708 rect = wndClient->rectClient;
709 rows = (int) sqrt((double)total);
710 columns = total / rows;
712 if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */
714 i = rows;
715 rows = columns; /* exchange r and c */
716 columns = i;
719 if( total != ci->nActiveChildren)
721 y = rect.bottom - 2 * SYSMETRICS_CYICONSPACING - SYSMETRICS_CYICON;
722 rect.bottom = ( y - SYSMETRICS_CYICON < rect.top )? rect.bottom: y;
725 ysize = rect.bottom / rows;
726 xsize = rect.right / columns;
728 for (x = i = 0, c = 1; c <= columns && *ppWnd; c++)
730 if (c == columns)
732 rows = total - i;
733 ysize = rect.bottom / rows;
736 y = 0;
737 for (r = 1; r <= rows && *ppWnd; r++, i++)
739 SetWindowPos32((*ppWnd)->hwndSelf, 0, x, y, xsize, ysize,
740 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
741 y += ysize;
742 ppWnd++;
744 x += xsize;
747 HeapFree( SystemHeap, 0, heapPtr );
750 if( total < ci->nActiveChildren ) ArrangeIconicWindows32( wndClient->hwndSelf );
753 /* ----------------------- Frame window ---------------------------- */
756 /**********************************************************************
757 * MDI_AugmentFrameMenu
759 static BOOL32 MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
760 HWND32 hChild )
762 WND* child = WIN_FindWndPtr(hChild);
763 HMENU32 hSysPopup = 0;
765 TRACE(mdi,"frame %p,child %04x\n",frame,hChild);
767 if( !frame->wIDmenu || !child->hSysMenu ) return 0;
769 /* create a copy of sysmenu popup and insert it into frame menu bar */
771 if (!(hSysPopup = LoadMenuIndirect32A(SYSRES_GetResPtr(SYSRES_MENU_SYSMENU))))
772 return 0;
774 TRACE(mdi,"\tgot popup %04x in sysmenu %04x\n",
775 hSysPopup, child->hSysMenu);
777 if( !InsertMenu32A(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
778 hSysPopup, (LPSTR)(DWORD)hBmpClose ))
780 DestroyMenu32(hSysPopup);
781 return 0;
784 if( !AppendMenu32A(frame->wIDmenu,MF_HELP | MF_BITMAP,
785 SC_RESTORE, (LPSTR)(DWORD)hBmpRestore ))
787 RemoveMenu32(frame->wIDmenu,0,MF_BYPOSITION);
788 return 0;
791 EnableMenuItem32(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
792 EnableMenuItem32(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
793 EnableMenuItem32(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
795 /* redraw menu */
796 DrawMenuBar32(frame->hwndSelf);
798 return 1;
801 /**********************************************************************
802 * MDI_RestoreFrameMenu
804 static BOOL32 MDI_RestoreFrameMenu( WND *frameWnd, HWND32 hChild )
806 INT32 nItems = GetMenuItemCount32(frameWnd->wIDmenu) - 1;
808 TRACE(mdi,"for child %04x\n",hChild);
810 if( GetMenuItemID32(frameWnd->wIDmenu,nItems) != SC_RESTORE )
811 return 0;
813 RemoveMenu32(frameWnd->wIDmenu,0,MF_BYPOSITION);
814 DeleteMenu32(frameWnd->wIDmenu,nItems-1,MF_BYPOSITION);
816 DrawMenuBar32(frameWnd->hwndSelf);
818 return 1;
821 /**********************************************************************
822 * MDI_UpdateFrameText
824 * used when child window is maximized/restored
826 * Note: lpTitle can be NULL
828 static void MDI_UpdateFrameText( WND *frameWnd, HWND32 hClient,
829 BOOL32 repaint, LPCSTR lpTitle )
831 char lpBuffer[MDI_MAXTITLELENGTH+1];
832 WND* clientWnd = WIN_FindWndPtr(hClient);
833 MDICLIENTINFO *ci = (MDICLIENTINFO *) clientWnd->wExtra;
835 TRACE(mdi, "repaint %i, frameText %s\n", repaint, (lpTitle)?lpTitle:"NULL");
837 if (!clientWnd)
838 return;
840 if (!ci)
841 return;
843 /* store new "default" title if lpTitle is not NULL */
844 if (lpTitle)
846 if (ci->frameTitle) HeapFree( SystemHeap, 0, ci->frameTitle );
847 ci->frameTitle = HEAP_strdupA( SystemHeap, 0, lpTitle );
850 if (ci->frameTitle)
852 WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );
854 if( childWnd && childWnd->text )
856 /* combine frame title and child title if possible */
858 LPCSTR lpBracket = " - [";
859 int i_frame_text_length = strlen(ci->frameTitle);
860 int i_child_text_length = strlen(childWnd->text);
862 lstrcpyn32A( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
864 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
866 strcat( lpBuffer, lpBracket );
868 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
870 strcat( lpBuffer, childWnd->text );
871 strcat( lpBuffer, "]" );
873 else
875 lstrcpyn32A( lpBuffer + i_frame_text_length + 4,
876 childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
877 strcat( lpBuffer, "]" );
881 else
883 strncpy(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH );
884 lpBuffer[MDI_MAXTITLELENGTH]='\0';
887 else
888 lpBuffer[0] = '\0';
890 DEFWND_SetText( frameWnd, lpBuffer );
891 if( repaint == MDI_REPAINTFRAME)
892 SetWindowPos32( frameWnd->hwndSelf, 0,0,0,0,0, SWP_FRAMECHANGED |
893 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
897 /* ----------------------------- Interface ---------------------------- */
900 /**********************************************************************
901 * MDIClientWndProc
903 * This function handles all MDI requests.
905 LRESULT WINAPI MDIClientWndProc( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
906 LPARAM lParam )
908 LPCREATESTRUCT32A cs;
909 MDICLIENTINFO *ci;
910 RECT32 rect;
911 WND *w = WIN_FindWndPtr(hwnd);
912 WND *frameWnd = w->parent;
913 INT32 nItems;
915 ci = (MDICLIENTINFO *) w->wExtra;
917 switch (message)
919 case WM_CREATE:
921 cs = (LPCREATESTRUCT32A)lParam;
923 /* Translation layer doesn't know what's in the cs->lpCreateParams
924 * so we have to keep track of what environment we're in. */
926 if( w->flags & WIN_ISWIN32 )
928 #define ccs ((LPCLIENTCREATESTRUCT32)cs->lpCreateParams)
929 ci->hWindowMenu = ccs->hWindowMenu;
930 ci->idFirstChild = ccs->idFirstChild;
931 #undef ccs
933 else
935 LPCLIENTCREATESTRUCT16 ccs = (LPCLIENTCREATESTRUCT16)
936 PTR_SEG_TO_LIN(cs->lpCreateParams);
937 ci->hWindowMenu = ccs->hWindowMenu;
938 ci->idFirstChild = ccs->idFirstChild;
941 ci->hwndChildMaximized = 0;
942 ci->nActiveChildren = 0;
943 ci->nTotalCreated = 0;
944 ci->frameTitle = NULL;
945 ci->mdiFlags = 0;
946 ci->self = hwnd;
947 w->dwStyle |= WS_CLIPCHILDREN;
949 if (!hBmpClose)
951 hBmpClose = CreateMDIMenuBitmap();
952 hBmpRestore = LoadBitmap16( 0, MAKEINTRESOURCE16(OBM_RESTORE) );
954 MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
956 AppendMenu32A( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
958 GetClientRect32(frameWnd->hwndSelf, &rect);
959 NC_HandleNCCalcSize( w, &rect );
960 w->rectClient = rect;
962 TRACE(mdi,"Client created - hwnd = %04x, idFirst = %u\n",
963 hwnd, ci->idFirstChild );
965 return 0;
967 case WM_DESTROY:
968 if( ci->hwndChildMaximized ) MDI_RestoreFrameMenu(w, frameWnd->hwndSelf);
969 if((nItems = GetMenuItemCount32(ci->hWindowMenu)) > 0)
971 ci->idFirstChild = nItems - 1;
972 ci->nActiveChildren++; /* to delete a separator */
973 while( ci->nActiveChildren-- )
974 DeleteMenu32(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
976 return 0;
978 case WM_MDIACTIVATE:
979 if( ci->hwndActiveChild != (HWND32)wParam )
980 SetWindowPos32((HWND32)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
981 return 0;
983 case WM_MDICASCADE:
984 return MDICascade(w, ci);
986 case WM_MDICREATE:
987 if (lParam) return MDICreateChild( w, ci, hwnd,
988 (MDICREATESTRUCT32A*)lParam );
989 return 0;
991 case WM_MDIDESTROY:
992 return MDIDestroyChild( w, ci, hwnd, (HWND32)wParam, TRUE );
994 case WM_MDIGETACTIVE:
995 if (lParam) *(BOOL32 *)lParam = (ci->hwndChildMaximized > 0);
996 return ci->hwndActiveChild;
998 case WM_MDIICONARRANGE:
999 ci->mdiFlags |= MDIF_NEEDUPDATE;
1000 ArrangeIconicWindows32(hwnd);
1001 ci->sbRecalc = SB_BOTH+1;
1002 SendMessage32A(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
1003 return 0;
1005 case WM_MDIMAXIMIZE:
1006 ShowWindow32( (HWND32)wParam, SW_MAXIMIZE );
1007 return 0;
1009 case WM_MDINEXT: /* lParam != 0 means previous window */
1010 MDI_SwitchActiveChild(hwnd, (HWND32)wParam, (lParam)? FALSE : TRUE );
1011 break;
1013 case WM_MDIRESTORE:
1014 ShowWindow32( (HWND32)wParam, SW_NORMAL);
1015 return 0;
1017 case WM_MDISETMENU:
1018 return MDISetMenu( hwnd, (HMENU32)wParam, (HMENU32)lParam );
1020 case WM_MDIREFRESHMENU:
1021 return MDIRefreshMenu( hwnd, (HMENU32)wParam, (HMENU32)lParam );
1023 case WM_MDITILE:
1024 ci->mdiFlags |= MDIF_NEEDUPDATE;
1025 ShowScrollBar32(hwnd,SB_BOTH,FALSE);
1026 MDITile(w, ci, wParam);
1027 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1028 return 0;
1030 case WM_VSCROLL:
1031 case WM_HSCROLL:
1032 ci->mdiFlags |= MDIF_NEEDUPDATE;
1033 ScrollChildren32(hwnd, message, wParam, lParam);
1034 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1035 return 0;
1037 case WM_SETFOCUS:
1038 if( ci->hwndActiveChild )
1040 w = WIN_FindWndPtr( ci->hwndActiveChild );
1041 if( !(w->dwStyle & WS_MINIMIZE) )
1042 SetFocus32( ci->hwndActiveChild );
1044 return 0;
1046 case WM_NCACTIVATE:
1047 if( ci->hwndActiveChild )
1048 SendMessage32A(ci->hwndActiveChild, message, wParam, lParam);
1049 break;
1051 case WM_PARENTNOTIFY:
1052 if (LOWORD(wParam) == WM_LBUTTONDOWN)
1054 POINT16 pt = MAKEPOINT16(lParam);
1055 HWND16 child = ChildWindowFromPoint16(hwnd, pt);
1057 TRACE(mdi,"notification from %04x (%i,%i)\n",child,pt.x,pt.y);
1059 if( child && child != hwnd && child != ci->hwndActiveChild )
1060 SetWindowPos32(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1062 return 0;
1064 case WM_SIZE:
1065 if( ci->hwndChildMaximized )
1067 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1068 RECT32 rect = { 0, 0, LOWORD(lParam), HIWORD(lParam) };
1070 AdjustWindowRectEx32(&rect, child->dwStyle, 0, child->dwExStyle);
1071 MoveWindow32(ci->hwndChildMaximized, rect.left, rect.top,
1072 rect.right - rect.left, rect.bottom - rect.top, 1);
1074 else
1075 MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1077 break;
1079 case WM_MDICALCCHILDSCROLL:
1080 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1082 CalcChildScroll(hwnd, ci->sbRecalc-1);
1083 ci->sbRecalc = 0;
1084 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1086 return 0;
1089 return DefWindowProc32A( hwnd, message, wParam, lParam );
1093 /***********************************************************************
1094 * DefFrameProc16 (USER.445)
1096 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1097 UINT16 message, WPARAM16 wParam, LPARAM lParam )
1099 HWND16 childHwnd;
1100 MDICLIENTINFO* ci;
1101 WND* wndPtr;
1103 if (hwndMDIClient)
1105 switch (message)
1107 case WM_COMMAND:
1108 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1109 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1111 /* check for possible syscommands for maximized MDI child */
1113 if( ci && (
1114 wParam < ci->idFirstChild ||
1115 wParam >= ci->idFirstChild + ci->nActiveChildren
1117 if( (wParam - 0xF000) & 0xF00F ) break;
1118 switch( wParam )
1120 case SC_SIZE:
1121 case SC_MOVE:
1122 case SC_MINIMIZE:
1123 case SC_MAXIMIZE:
1124 case SC_NEXTWINDOW:
1125 case SC_PREVWINDOW:
1126 case SC_CLOSE:
1127 case SC_RESTORE:
1128 if( ci->hwndChildMaximized )
1129 return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1130 wParam, lParam);
1133 else
1135 childHwnd = MDI_GetChildByID( WIN_FindWndPtr(hwndMDIClient),
1136 wParam );
1137 if( childHwnd )
1138 SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1139 (WPARAM16)childHwnd , 0L);
1141 break;
1143 case WM_NCACTIVATE:
1144 SendMessage16(hwndMDIClient, message, wParam, lParam);
1145 break;
1147 case WM_SETTEXT:
1148 MDI_UpdateFrameText(WIN_FindWndPtr(hwnd), hwndMDIClient,
1149 MDI_REPAINTFRAME,
1150 (LPCSTR)PTR_SEG_TO_LIN(lParam));
1151 return 0;
1153 case WM_SETFOCUS:
1154 SetFocus32(hwndMDIClient);
1155 break;
1157 case WM_SIZE:
1158 MoveWindow16(hwndMDIClient, 0, 0,
1159 LOWORD(lParam), HIWORD(lParam), TRUE);
1160 break;
1162 case WM_NEXTMENU:
1164 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1165 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1167 if( !(wndPtr->parent->dwStyle & WS_MINIMIZE)
1168 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1170 /* control menu is between the frame system menu and
1171 * the first entry of menu bar */
1173 if( (wParam == VK_LEFT &&
1174 wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1175 (wParam == VK_RIGHT &&
1176 GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1178 wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1179 return MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1180 ci->hwndActiveChild);
1183 break;
1187 return DefWindowProc16(hwnd, message, wParam, lParam);
1191 /***********************************************************************
1192 * DefFrameProc32A (USER32.122)
1194 LRESULT WINAPI DefFrameProc32A( HWND32 hwnd, HWND32 hwndMDIClient,
1195 UINT32 message, WPARAM32 wParam, LPARAM lParam)
1197 if (hwndMDIClient)
1199 switch (message)
1201 case WM_COMMAND:
1202 return DefFrameProc16( hwnd, hwndMDIClient, message,
1203 (WPARAM16)wParam,
1204 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1206 case WM_NCACTIVATE:
1207 SendMessage32A(hwndMDIClient, message, wParam, lParam);
1208 break;
1210 case WM_SETTEXT: {
1211 LRESULT ret;
1212 LPSTR segstr = SEGPTR_STRDUP((LPSTR)lParam);
1214 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1215 wParam, (LPARAM)SEGPTR_GET(segstr) );
1216 SEGPTR_FREE(segstr);
1217 return ret;
1220 case WM_NEXTMENU:
1221 case WM_SETFOCUS:
1222 case WM_SIZE:
1223 return DefFrameProc16( hwnd, hwndMDIClient, message,
1224 wParam, lParam );
1228 return DefWindowProc32A(hwnd, message, wParam, lParam);
1232 /***********************************************************************
1233 * DefFrameProc32W (USER32.123)
1235 LRESULT WINAPI DefFrameProc32W( HWND32 hwnd, HWND32 hwndMDIClient,
1236 UINT32 message, WPARAM32 wParam, LPARAM lParam)
1238 if (hwndMDIClient)
1240 switch (message)
1242 case WM_COMMAND:
1243 return DefFrameProc16( hwnd, hwndMDIClient, message,
1244 (WPARAM16)wParam,
1245 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1247 case WM_NCACTIVATE:
1248 SendMessage32W(hwndMDIClient, message, wParam, lParam);
1249 break;
1251 case WM_SETTEXT:
1253 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1254 LRESULT ret = DefFrameProc32A( hwnd, hwndMDIClient, message,
1255 wParam, (DWORD)txt );
1256 HeapFree(GetProcessHeap(),0,txt);
1257 return ret;
1259 case WM_NEXTMENU:
1260 case WM_SETFOCUS:
1261 case WM_SIZE:
1262 return DefFrameProc32A( hwnd, hwndMDIClient, message,
1263 wParam, lParam );
1267 return DefWindowProc32W( hwnd, message, wParam, lParam );
1271 /***********************************************************************
1272 * DefMDIChildProc16 (USER.447)
1274 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1275 WPARAM16 wParam, LPARAM lParam )
1277 MDICLIENTINFO *ci;
1278 WND *clientWnd;
1280 clientWnd = WIN_FindWndPtr(GetParent16(hwnd));
1281 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1283 switch (message)
1285 case WM_SETTEXT:
1286 DefWindowProc16(hwnd, message, wParam, lParam);
1287 MDI_MenuModifyItem(clientWnd,hwnd);
1288 if( ci->hwndChildMaximized == hwnd )
1289 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1290 MDI_REPAINTFRAME, NULL );
1291 return 0;
1293 case WM_CLOSE:
1294 SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1295 return 0;
1297 case WM_SETFOCUS:
1298 if( ci->hwndActiveChild != hwnd )
1299 MDI_ChildActivate(clientWnd, hwnd);
1300 break;
1302 case WM_CHILDACTIVATE:
1303 MDI_ChildActivate(clientWnd, hwnd);
1304 return 0;
1306 case WM_NCPAINT:
1307 TRACE(mdi,"WM_NCPAINT for %04x, active %04x\n",
1308 hwnd, ci->hwndActiveChild );
1309 break;
1311 case WM_SYSCOMMAND:
1312 switch( wParam )
1314 case SC_MOVE:
1315 if( ci->hwndChildMaximized == hwnd) return 0;
1316 break;
1317 case SC_RESTORE:
1318 case SC_MINIMIZE:
1319 WIN_FindWndPtr(hwnd)->dwStyle |= WS_SYSMENU;
1320 break;
1321 case SC_MAXIMIZE:
1322 if( ci->hwndChildMaximized == hwnd)
1323 return SendMessage16( clientWnd->parent->hwndSelf,
1324 message, wParam, lParam);
1325 WIN_FindWndPtr(hwnd)->dwStyle &= ~WS_SYSMENU;
1326 break;
1327 case SC_NEXTWINDOW:
1328 SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1329 return 0;
1330 case SC_PREVWINDOW:
1331 SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1332 return 0;
1334 break;
1336 case WM_GETMINMAXINFO:
1337 MDI_ChildGetMinMaxInfo(clientWnd, hwnd, (MINMAXINFO16*) PTR_SEG_TO_LIN(lParam));
1338 return 0;
1340 case WM_SETVISIBLE:
1341 if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1342 else
1343 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1344 break;
1346 case WM_SIZE:
1347 /* do not change */
1349 if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1351 ci->hwndChildMaximized = 0;
1353 MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1354 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1355 MDI_REPAINTFRAME, NULL );
1358 if( wParam == SIZE_MAXIMIZED )
1360 HWND16 hMaxChild = ci->hwndChildMaximized;
1362 if( hMaxChild == hwnd ) break;
1364 if( hMaxChild)
1366 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1368 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1369 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1371 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1374 TRACE(mdi,"maximizing child %04x\n", hwnd );
1376 ci->hwndChildMaximized = hwnd; /* !!! */
1378 MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1379 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1380 MDI_REPAINTFRAME, NULL );
1383 if( wParam == SIZE_MINIMIZED )
1385 HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1387 if( switchTo )
1388 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1391 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1392 break;
1394 case WM_MENUCHAR:
1396 /* MDI children don't have menu bars */
1397 PostMessage16( clientWnd->parent->hwndSelf, WM_SYSCOMMAND,
1398 (WPARAM16)SC_KEYMENU, (LPARAM)wParam);
1399 return 0x00010000L;
1401 case WM_NEXTMENU:
1403 if( wParam == VK_LEFT ) /* switch to frame system menu */
1404 return MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1405 clientWnd->parent->hwndSelf );
1406 if( wParam == VK_RIGHT ) /* to frame menu bar */
1407 return MAKELONG( clientWnd->parent->wIDmenu,
1408 clientWnd->parent->hwndSelf );
1410 break;
1412 case WM_SYSCHAR:
1413 if (wParam == '-')
1415 SendMessage16(hwnd,WM_SYSCOMMAND,
1416 (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1417 return 0;
1421 return DefWindowProc16(hwnd, message, wParam, lParam);
1425 /***********************************************************************
1426 * DefMDIChildProc32A (USER32.124)
1428 LRESULT WINAPI DefMDIChildProc32A( HWND32 hwnd, UINT32 message,
1429 WPARAM32 wParam, LPARAM lParam )
1431 MDICLIENTINFO *ci;
1432 WND *clientWnd;
1434 clientWnd = WIN_FindWndPtr(WIN_FindWndPtr(hwnd)->parent->hwndSelf);
1435 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1437 switch (message)
1439 case WM_SETTEXT:
1440 DefWindowProc32A(hwnd, message, wParam, lParam);
1441 MDI_MenuModifyItem(clientWnd,hwnd);
1442 if( ci->hwndChildMaximized == hwnd )
1443 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1444 MDI_REPAINTFRAME, NULL );
1445 return 0;
1447 case WM_GETMINMAXINFO:
1449 MINMAXINFO16 mmi;
1450 STRUCT32_MINMAXINFO32to16( (MINMAXINFO32 *)lParam, &mmi );
1451 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1452 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO32 *)lParam );
1454 return 0;
1456 case WM_MENUCHAR:
1458 /* MDI children don't have menu bars */
1459 PostMessage16( clientWnd->parent->hwndSelf, WM_SYSCOMMAND,
1460 (WPARAM16)SC_KEYMENU, (LPARAM)LOWORD(wParam) );
1461 return 0x00010000L;
1463 case WM_CLOSE:
1464 case WM_SETFOCUS:
1465 case WM_CHILDACTIVATE:
1466 case WM_NCPAINT:
1467 case WM_SYSCOMMAND:
1468 case WM_SETVISIBLE:
1469 case WM_SIZE:
1470 case WM_NEXTMENU:
1471 return DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1473 case WM_SYSCHAR:
1474 if (wParam == '-')
1476 SendMessage32A(hwnd,WM_SYSCOMMAND,
1477 (WPARAM32)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1478 return 0;
1481 return DefWindowProc32A(hwnd, message, wParam, lParam);
1485 /***********************************************************************
1486 * DefMDIChildProc32W (USER32.125)
1488 LRESULT WINAPI DefMDIChildProc32W( HWND32 hwnd, UINT32 message,
1489 WPARAM32 wParam, LPARAM lParam )
1491 MDICLIENTINFO *ci;
1492 WND *clientWnd;
1494 clientWnd = WIN_FindWndPtr(GetParent16(hwnd));
1495 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1497 switch (message)
1499 case WM_SETTEXT:
1500 DefWindowProc32W(hwnd, message, wParam, lParam);
1501 MDI_MenuModifyItem(clientWnd,hwnd);
1502 if( ci->hwndChildMaximized == hwnd )
1503 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1504 MDI_REPAINTFRAME, NULL );
1505 return 0;
1507 case WM_GETMINMAXINFO:
1508 case WM_MENUCHAR:
1509 case WM_CLOSE:
1510 case WM_SETFOCUS:
1511 case WM_CHILDACTIVATE:
1512 case WM_NCPAINT:
1513 case WM_SYSCOMMAND:
1514 case WM_SETVISIBLE:
1515 case WM_SIZE:
1516 case WM_NEXTMENU:
1517 return DefMDIChildProc32A( hwnd, message, (WPARAM16)wParam, lParam );
1519 case WM_SYSCHAR:
1520 if (wParam == '-')
1522 SendMessage32W(hwnd,WM_SYSCOMMAND,
1523 (WPARAM32)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1524 return 0;
1527 return DefWindowProc32W(hwnd, message, wParam, lParam);
1531 /**********************************************************************
1532 * CreateMDIWindowA [USER32.79] Creates a MDI child in new thread
1533 * FIXME: its in the same thread now
1535 * RETURNS
1536 * Success: Handle to created window
1537 * Failure: NULL
1539 HWND32 WINAPI CreateMDIWindow32A(
1540 LPCSTR lpClassName, /* [in] Pointer to registered child class name */
1541 LPCSTR lpWindowName, /* [in] Pointer to window name */
1542 DWORD dwStyle, /* [in] Window style */
1543 INT32 X, /* [in] Horizontal position of window */
1544 INT32 Y, /* [in] Vertical position of window */
1545 INT32 nWidth, /* [in] Width of window */
1546 INT32 nHeight, /* [in] Height of window */
1547 HWND32 hWndParent, /* [in] Handle to parent window */
1548 HINSTANCE32 hInstance, /* [in] Handle to application instance */
1549 LPARAM lParam) /* [in] Application-defined value */
1551 WARN(mdi,"is only single threaded!\n");
1552 return MDI_CreateMDIWindow32A(lpClassName, lpWindowName, dwStyle, X, Y,
1553 nWidth, nHeight, hWndParent, hInstance, lParam);
1556 /**********************************************************************
1557 * MDI_CreateMDIWindowA
1558 * single threaded version of CreateMDIWindowA
1559 * called by CreateWindowEx32A
1561 HWND32 MDI_CreateMDIWindow32A(
1562 LPCSTR lpClassName,
1563 LPCSTR lpWindowName,
1564 DWORD dwStyle,
1565 INT32 X,
1566 INT32 Y,
1567 INT32 nWidth,
1568 INT32 nHeight,
1569 HWND32 hWndParent,
1570 HINSTANCE32 hInstance,
1571 LPARAM lParam)
1573 MDICLIENTINFO* pCi;
1574 MDICREATESTRUCT32A cs;
1575 WND *pWnd=WIN_FindWndPtr(hWndParent);
1577 TRACE(mdi, "(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
1578 debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
1579 nWidth,nHeight,hWndParent,hInstance,lParam);
1581 if(!pWnd){
1582 ERR(mdi," bad hwnd for MDI-client: %d\n",hWndParent);
1583 return 0;
1585 cs.szClass=lpClassName;
1586 cs.szTitle=lpWindowName;
1587 cs.hOwner=hInstance;
1588 cs.x=X;
1589 cs.y=Y;
1590 cs.cx=nWidth;
1591 cs.cy=nHeight;
1592 cs.style=dwStyle;
1593 cs.lParam=lParam;
1595 pCi=(MDICLIENTINFO *)pWnd->wExtra;
1597 return MDICreateChild(pWnd,pCi,hWndParent,&cs);
1600 /***************************************
1601 * CreateMDIWindow32W [USER32.80] Creates a MDI child in new thread
1603 * RETURNS
1604 * Success: Handle to created window
1605 * Failure: NULL
1607 HWND32 WINAPI CreateMDIWindow32W(
1608 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1609 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1610 DWORD dwStyle, /* [in] Window style */
1611 INT32 X, /* [in] Horizontal position of window */
1612 INT32 Y, /* [in] Vertical position of window */
1613 INT32 nWidth, /* [in] Width of window */
1614 INT32 nHeight, /* [in] Height of window */
1615 HWND32 hWndParent, /* [in] Handle to parent window */
1616 HINSTANCE32 hInstance, /* [in] Handle to application instance */
1617 LPARAM lParam) /* [in] Application-defined value */
1619 FIXME(mdi, "(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1620 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1621 nWidth,nHeight,hWndParent,hInstance,lParam);
1622 return (HWND32)NULL;
1626 /******************************************************************************
1627 * CreateMDIWindow32W [USER32.80] Creates a MDI child window
1628 * single threaded version of CreateMDIWindow
1629 * called by CreateWindowEx32W().
1631 HWND32 MDI_CreateMDIWindow32W(
1632 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1633 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1634 DWORD dwStyle, /* [in] Window style */
1635 INT32 X, /* [in] Horizontal position of window */
1636 INT32 Y, /* [in] Vertical position of window */
1637 INT32 nWidth, /* [in] Width of window */
1638 INT32 nHeight, /* [in] Height of window */
1639 HWND32 hWndParent, /* [in] Handle to parent window */
1640 HINSTANCE32 hInstance, /* [in] Handle to application instance */
1641 LPARAM lParam) /* [in] Application-defined value */
1643 FIXME(mdi, "(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1644 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1645 nWidth,nHeight,hWndParent,hInstance,lParam);
1646 return (HWND32)NULL;
1650 /**********************************************************************
1651 * TranslateMDISysAccel32 (USER32.555)
1653 BOOL32 WINAPI TranslateMDISysAccel32( HWND32 hwndClient, LPMSG32 msg )
1655 MSG16 msg16;
1657 STRUCT32_MSG32to16(msg,&msg16);
1658 /* MDICLIENTINFO is still the same for win32 and win16 ... */
1659 return TranslateMDISysAccel16(hwndClient,&msg16);
1663 /**********************************************************************
1664 * TranslateMDISysAccel16 (USER.451)
1666 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
1668 WND* clientWnd = WIN_FindWndPtr( hwndClient);
1670 if( clientWnd && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
1672 MDICLIENTINFO *ci = NULL;
1673 WND* wnd;
1675 ci = (MDICLIENTINFO*) clientWnd->wExtra;
1676 wnd = WIN_FindWndPtr(ci->hwndActiveChild);
1677 if( wnd && !(wnd->dwStyle & WS_DISABLED) )
1679 WPARAM16 wParam = 0;
1681 /* translate if the Ctrl key is down and Alt not. */
1683 if( (GetKeyState32(VK_CONTROL) & 0x8000) &&
1684 !(GetKeyState32(VK_MENU) & 0x8000))
1686 switch( msg->wParam )
1688 case VK_F6:
1689 case VK_TAB:
1690 wParam = ( GetKeyState32(VK_SHIFT) & 0x8000 )
1691 ? SC_NEXTWINDOW : SC_PREVWINDOW;
1692 break;
1693 case VK_F4:
1694 case VK_RBUTTON:
1695 wParam = SC_CLOSE;
1696 break;
1697 default:
1698 return 0;
1700 TRACE(mdi,"wParam = %04x\n", wParam);
1701 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
1702 wParam, (LPARAM)msg->wParam);
1703 return 1;
1707 return 0; /* failure */
1711 /***********************************************************************
1712 * CalcChildScroll (USER.462)
1714 void WINAPI CalcChildScroll( HWND16 hwnd, WORD scroll )
1716 SCROLLINFO info;
1717 RECT32 childRect, clientRect;
1718 INT32 vmin, vmax, hmin, hmax, vpos, hpos;
1719 WND *pWnd, *Wnd;
1721 if (!(Wnd = pWnd = WIN_FindWndPtr( hwnd ))) return;
1722 GetClientRect32( hwnd, &clientRect );
1723 SetRectEmpty32( &childRect );
1725 for ( pWnd = pWnd->child; pWnd; pWnd = pWnd->next )
1727 if( pWnd->dwStyle & WS_MAXIMIZE )
1729 ShowScrollBar32(hwnd, SB_BOTH, FALSE);
1730 return;
1732 UnionRect32( &childRect, &pWnd->rectWindow, &childRect );
1734 UnionRect32( &childRect, &clientRect, &childRect );
1736 hmin = childRect.left; hmax = childRect.right - clientRect.right;
1737 hpos = clientRect.left - childRect.left;
1738 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
1739 vpos = clientRect.top - childRect.top;
1741 switch( scroll )
1743 case SB_HORZ:
1744 vpos = hpos; vmin = hmin; vmax = hmax;
1745 case SB_VERT:
1746 info.cbSize = sizeof(info);
1747 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
1748 info.fMask = SIF_POS | SIF_RANGE;
1749 SetScrollInfo32(hwnd, scroll, &info, TRUE);
1750 break;
1751 case SB_BOTH:
1752 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
1753 hmin, hmax, hpos);
1758 /***********************************************************************
1759 * ScrollChildren16 (USER.463)
1761 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
1763 return ScrollChildren32( hWnd, uMsg, wParam, lParam );
1767 /***********************************************************************
1768 * ScrollChildren32 (USER32.448)
1770 void WINAPI ScrollChildren32(HWND32 hWnd, UINT32 uMsg, WPARAM32 wParam,
1771 LPARAM lParam)
1773 WND *wndPtr = WIN_FindWndPtr(hWnd);
1774 INT32 newPos = -1;
1775 INT32 curPos, length, minPos, maxPos, shift;
1777 if( !wndPtr ) return;
1779 if( uMsg == WM_HSCROLL )
1781 GetScrollRange32(hWnd,SB_HORZ,&minPos,&maxPos);
1782 curPos = GetScrollPos32(hWnd,SB_HORZ);
1783 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
1784 shift = SYSMETRICS_CYHSCROLL;
1786 else if( uMsg == WM_VSCROLL )
1788 GetScrollRange32(hWnd,SB_VERT,&minPos,&maxPos);
1789 curPos = GetScrollPos32(hWnd,SB_VERT);
1790 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
1791 shift = SYSMETRICS_CXVSCROLL;
1793 else return;
1795 switch( wParam )
1797 case SB_LINEUP:
1798 newPos = curPos - shift;
1799 break;
1800 case SB_LINEDOWN:
1801 newPos = curPos + shift;
1802 break;
1803 case SB_PAGEUP:
1804 newPos = curPos - length;
1805 break;
1806 case SB_PAGEDOWN:
1807 newPos = curPos + length;
1808 break;
1810 case SB_THUMBPOSITION:
1811 newPos = LOWORD(lParam);
1812 break;
1814 case SB_THUMBTRACK:
1815 return;
1817 case SB_TOP:
1818 newPos = minPos;
1819 break;
1820 case SB_BOTTOM:
1821 newPos = maxPos;
1822 break;
1823 case SB_ENDSCROLL:
1824 CalcChildScroll(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
1825 return;
1828 if( newPos > maxPos )
1829 newPos = maxPos;
1830 else
1831 if( newPos < minPos )
1832 newPos = minPos;
1834 SetScrollPos32(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
1836 if( uMsg == WM_VSCROLL )
1837 ScrollWindowEx32(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
1838 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1839 else
1840 ScrollWindowEx32(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
1841 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1845 /******************************************************************************
1846 * CascadeWindows [USER32.21] Cascades MDI child windows
1848 * RETURNS
1849 * Success: Number of cascaded windows.
1850 * Failure: 0
1852 WORD WINAPI
1853 CascadeWindows (HWND32 hwndParent, UINT32 wFlags, const LPRECT32 lpRect,
1854 UINT32 cKids, const HWND32 *lpKids)
1856 FIXME (mdi, "(0x%08x,0x%08x,...,%u,...): stub\n",
1857 hwndParent, wFlags, cKids);
1859 return 0;
1863 /******************************************************************************
1864 * TileWindows [USER32.545] Tiles MDI child windows
1866 * RETURNS
1867 * Success: Number of tiled windows.
1868 * Failure: 0
1870 WORD WINAPI
1871 TileWindows (HWND32 hwndParent, UINT32 wFlags, const LPRECT32 lpRect,
1872 UINT32 cKids, const HWND32 *lpKids)
1874 FIXME (mdi, "(0x%08x,0x%08x,...,%u,...): stub\n",
1875 hwndParent, wFlags, cKids);
1877 return 0;