More bitmap fixes.
[wine.git] / windows / mdi.c
blob94b6e5ee80be443204c67d2112b3c2e6a675f6c5
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] Creates a MDI child in new thread
1531 * FIXME: its in the same thread now
1533 * RETURNS
1534 * Success: Handle to created window
1535 * Failure: NULL
1537 HWND32 CreateMDIWindow32A(
1538 LPCSTR lpClassName, /* [in] Pointer to registered child class name */
1539 LPCSTR lpWindowName, /* [in] Pointer to window name */
1540 DWORD dwStyle, /* [in] Window style */
1541 INT32 X, /* [in] Horizontal position of window */
1542 INT32 Y, /* [in] Vertical position of window */
1543 INT32 nWidth, /* [in] Width of window */
1544 INT32 nHeight, /* [in] Height of window */
1545 HWND32 hWndParent, /* [in] Handle to parent window */
1546 HINSTANCE32 hInstance, /* [in] Handle to application instance */
1547 LPARAM lParam) /* [in] Application-defined value */
1549 WARN(mdi,"is only single threaded!\n");
1550 return MDI_CreateMDIWindow32A(lpClassName, lpWindowName, dwStyle, X, Y,
1551 nWidth, nHeight, hWndParent, hInstance, lParam);
1554 /**********************************************************************
1555 * MDI_CreateMDIWindowA
1556 * single threaded version of CreateMDIWindowA
1557 * called by CreateWindowEx32A
1559 HWND32 MDI_CreateMDIWindow32A(
1560 LPCSTR lpClassName,
1561 LPCSTR lpWindowName,
1562 DWORD dwStyle,
1563 INT32 X,
1564 INT32 Y,
1565 INT32 nWidth,
1566 INT32 nHeight,
1567 HWND32 hWndParent,
1568 HINSTANCE32 hInstance,
1569 LPARAM lParam)
1571 MDICLIENTINFO* pCi;
1572 MDICREATESTRUCT32A cs;
1573 WND *pWnd=WIN_FindWndPtr(hWndParent);
1575 TRACE(mdi, "(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
1576 debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
1577 nWidth,nHeight,hWndParent,hInstance,lParam);
1579 if(!pWnd){
1580 ERR(mdi," bad hwnd for MDI-client: %d\n",hWndParent);
1581 return 0;
1583 cs.szClass=lpClassName;
1584 cs.szTitle=lpWindowName;
1585 cs.hOwner=hInstance;
1586 cs.x=X;
1587 cs.y=Y;
1588 cs.cx=nWidth;
1589 cs.cy=nHeight;
1590 cs.style=dwStyle;
1591 cs.lParam=lParam;
1593 pCi=(MDICLIENTINFO *)pWnd->wExtra;
1595 return MDICreateChild(pWnd,pCi,hWndParent,&cs);
1598 /***************************************
1599 * CreateMDIWindow32W [USER32.80] Creates a MDI child in new thread
1601 * RETURNS
1602 * Success: Handle to created window
1603 * Failure: NULL
1605 HWND32 CreateMDIWindow32W(
1606 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1607 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1608 DWORD dwStyle, /* [in] Window style */
1609 INT32 X, /* [in] Horizontal position of window */
1610 INT32 Y, /* [in] Vertical position of window */
1611 INT32 nWidth, /* [in] Width of window */
1612 INT32 nHeight, /* [in] Height of window */
1613 HWND32 hWndParent, /* [in] Handle to parent window */
1614 HINSTANCE32 hInstance, /* [in] Handle to application instance */
1615 LPARAM lParam) /* [in] Application-defined value */
1617 FIXME(mdi, "(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1618 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1619 nWidth,nHeight,hWndParent,hInstance,lParam);
1620 return (HWND32)NULL;
1624 /******************************************************************************
1625 * CreateMDIWindow32W [USER32.80] Creates a MDI child window
1626 * single threaded version of CreateMDIWindow
1627 * called by CreateWindowEx32W().
1629 HWND32 MDI_CreateMDIWindow32W(
1630 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1631 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1632 DWORD dwStyle, /* [in] Window style */
1633 INT32 X, /* [in] Horizontal position of window */
1634 INT32 Y, /* [in] Vertical position of window */
1635 INT32 nWidth, /* [in] Width of window */
1636 INT32 nHeight, /* [in] Height of window */
1637 HWND32 hWndParent, /* [in] Handle to parent window */
1638 HINSTANCE32 hInstance, /* [in] Handle to application instance */
1639 LPARAM lParam) /* [in] Application-defined value */
1641 FIXME(mdi, "(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1642 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1643 nWidth,nHeight,hWndParent,hInstance,lParam);
1644 return (HWND32)NULL;
1648 /**********************************************************************
1649 * TranslateMDISysAccel32 (USER32.555)
1651 BOOL32 WINAPI TranslateMDISysAccel32( HWND32 hwndClient, LPMSG32 msg )
1653 MSG16 msg16;
1655 STRUCT32_MSG32to16(msg,&msg16);
1656 /* MDICLIENTINFO is still the same for win32 and win16 ... */
1657 return TranslateMDISysAccel16(hwndClient,&msg16);
1661 /**********************************************************************
1662 * TranslateMDISysAccel16 (USER.451)
1664 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
1666 WND* clientWnd = WIN_FindWndPtr( hwndClient);
1668 if( clientWnd && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
1670 MDICLIENTINFO *ci = NULL;
1671 WND* wnd;
1673 ci = (MDICLIENTINFO*) clientWnd->wExtra;
1674 wnd = WIN_FindWndPtr(ci->hwndActiveChild);
1675 if( wnd && !(wnd->dwStyle & WS_DISABLED) )
1677 WPARAM16 wParam = 0;
1679 /* translate if the Ctrl key is down and Alt not. */
1681 if( (GetKeyState32(VK_CONTROL) & 0x8000) &&
1682 !(GetKeyState32(VK_MENU) & 0x8000))
1684 switch( msg->wParam )
1686 case VK_F6:
1687 case VK_TAB:
1688 wParam = ( GetKeyState32(VK_SHIFT) & 0x8000 )
1689 ? SC_NEXTWINDOW : SC_PREVWINDOW;
1690 break;
1691 case VK_F4:
1692 case VK_RBUTTON:
1693 wParam = SC_CLOSE;
1694 break;
1695 default:
1696 return 0;
1698 TRACE(mdi,"wParam = %04x\n", wParam);
1699 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
1700 wParam, (LPARAM)msg->wParam);
1701 return 1;
1705 return 0; /* failure */
1709 /***********************************************************************
1710 * CalcChildScroll (USER.462)
1712 void WINAPI CalcChildScroll( HWND16 hwnd, WORD scroll )
1714 SCROLLINFO info;
1715 RECT32 childRect, clientRect;
1716 INT32 vmin, vmax, hmin, hmax, vpos, hpos;
1717 WND *pWnd, *Wnd;
1719 if (!(Wnd = pWnd = WIN_FindWndPtr( hwnd ))) return;
1720 GetClientRect32( hwnd, &clientRect );
1721 SetRectEmpty32( &childRect );
1723 for ( pWnd = pWnd->child; pWnd; pWnd = pWnd->next )
1725 if( pWnd->dwStyle & WS_MAXIMIZE )
1727 ShowScrollBar32(hwnd, SB_BOTH, FALSE);
1728 return;
1730 UnionRect32( &childRect, &pWnd->rectWindow, &childRect );
1732 UnionRect32( &childRect, &clientRect, &childRect );
1734 hmin = childRect.left; hmax = childRect.right - clientRect.right;
1735 hpos = clientRect.left - childRect.left;
1736 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
1737 vpos = clientRect.top - childRect.top;
1739 switch( scroll )
1741 case SB_HORZ:
1742 vpos = hpos; vmin = hmin; vmax = hmax;
1743 case SB_VERT:
1744 info.cbSize = sizeof(info);
1745 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
1746 info.fMask = SIF_POS | SIF_RANGE;
1747 SetScrollInfo32(hwnd, scroll, &info, TRUE);
1748 break;
1749 case SB_BOTH:
1750 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
1751 hmin, hmax, hpos);
1756 /***********************************************************************
1757 * ScrollChildren16 (USER.463)
1759 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
1761 return ScrollChildren32( hWnd, uMsg, wParam, lParam );
1765 /***********************************************************************
1766 * ScrollChildren32 (USER32.448)
1768 void WINAPI ScrollChildren32(HWND32 hWnd, UINT32 uMsg, WPARAM32 wParam,
1769 LPARAM lParam)
1771 WND *wndPtr = WIN_FindWndPtr(hWnd);
1772 INT32 newPos = -1;
1773 INT32 curPos, length, minPos, maxPos, shift;
1775 if( !wndPtr ) return;
1777 if( uMsg == WM_HSCROLL )
1779 GetScrollRange32(hWnd,SB_HORZ,&minPos,&maxPos);
1780 curPos = GetScrollPos32(hWnd,SB_HORZ);
1781 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
1782 shift = SYSMETRICS_CYHSCROLL;
1784 else if( uMsg == WM_VSCROLL )
1786 GetScrollRange32(hWnd,SB_VERT,&minPos,&maxPos);
1787 curPos = GetScrollPos32(hWnd,SB_VERT);
1788 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
1789 shift = SYSMETRICS_CXVSCROLL;
1791 else return;
1793 switch( wParam )
1795 case SB_LINEUP:
1796 newPos = curPos - shift;
1797 break;
1798 case SB_LINEDOWN:
1799 newPos = curPos + shift;
1800 break;
1801 case SB_PAGEUP:
1802 newPos = curPos - length;
1803 break;
1804 case SB_PAGEDOWN:
1805 newPos = curPos + length;
1806 break;
1808 case SB_THUMBPOSITION:
1809 newPos = LOWORD(lParam);
1810 break;
1812 case SB_THUMBTRACK:
1813 return;
1815 case SB_TOP:
1816 newPos = minPos;
1817 break;
1818 case SB_BOTTOM:
1819 newPos = maxPos;
1820 break;
1821 case SB_ENDSCROLL:
1822 CalcChildScroll(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
1823 return;
1826 if( newPos > maxPos )
1827 newPos = maxPos;
1828 else
1829 if( newPos < minPos )
1830 newPos = minPos;
1832 SetScrollPos32(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
1834 if( uMsg == WM_VSCROLL )
1835 ScrollWindowEx32(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
1836 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1837 else
1838 ScrollWindowEx32(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
1839 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1843 /******************************************************************************
1844 * CascadeWindows [USER32.21] Cascades MDI child windows
1846 * RETURNS
1847 * Success: Number of cascaded windows.
1848 * Failure: 0
1850 WORD WINAPI
1851 CascadeWindows (HWND32 hwndParent, UINT32 wFlags, const LPRECT32 lpRect,
1852 UINT32 cKids, const HWND32 *lpKids)
1854 FIXME (mdi, "(0x%08x,0x%08x,...,%u,...): stub\n",
1855 hwndParent, wFlags, cKids);
1857 return 0;
1861 /******************************************************************************
1862 * TileWindows [USER32.545] Tiles MDI child windows
1864 * RETURNS
1865 * Success: Number of tiled windows.
1866 * Failure: 0
1868 WORD WINAPI
1869 TileWindows (HWND32 hwndParent, UINT32 wFlags, const LPRECT32 lpRect,
1870 UINT32 cKids, const HWND32 *lpKids)
1872 FIXME (mdi, "(0x%08x,0x%08x,...,%u,...): stub\n",
1873 hwndParent, wFlags, cKids);
1875 return 0;