Fix a couple of 64bit platform problems and speed up compilation. See
[wine/multimedia.git] / windows / mdi.c
blob250255acc545f83b8f7da412d4286e048ab93dd4
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 "tweak.h"
29 #include "debug.h"
31 #define MDIF_NEEDUPDATE 0x0001
33 static HBITMAP16 hBmpClose = 0;
34 static HBITMAP16 hBmpRestore = 0;
36 INT32 SCROLL_SetNCSbState(WND*,int,int,int,int,int,int);
38 /* ----------------- declarations ----------------- */
39 static void MDI_UpdateFrameText(WND *, HWND32, BOOL32, LPCSTR);
40 static BOOL32 MDI_AugmentFrameMenu(MDICLIENTINFO*, WND *, HWND32);
41 static BOOL32 MDI_RestoreFrameMenu(WND *, HWND32);
43 static LONG MDI_ChildActivate( WND*, HWND32 );
45 /* -------- Miscellaneous service functions ----------
47 * MDI_GetChildByID
50 static HWND32 MDI_GetChildByID(WND* wndPtr, INT32 id)
52 for (wndPtr = wndPtr->child; wndPtr; wndPtr = wndPtr->next)
53 if (wndPtr->wIDmenu == id) return wndPtr->hwndSelf;
54 return 0;
57 static void MDI_PostUpdate(HWND32 hwnd, MDICLIENTINFO* ci, WORD recalc)
59 if( !(ci->mdiFlags & MDIF_NEEDUPDATE) )
61 ci->mdiFlags |= MDIF_NEEDUPDATE;
62 PostMessage32A( hwnd, WM_MDICALCCHILDSCROLL, 0, 0);
64 ci->sbRecalc = recalc;
67 /**********************************************************************
68 * MDI_MenuModifyItem
70 static BOOL32 MDI_MenuModifyItem(WND* clientWnd, HWND32 hWndChild )
72 char buffer[128];
73 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
74 WND *wndPtr = WIN_FindWndPtr(hWndChild);
75 UINT32 n = sprintf(buffer, "%d ",
76 wndPtr->wIDmenu - clientInfo->idFirstChild + 1);
77 BOOL32 bRet = 0;
79 if( !clientInfo->hWindowMenu ) return 0;
81 if (wndPtr->text) lstrcpyn32A(buffer + n, wndPtr->text, sizeof(buffer) - n );
83 n = GetMenuState32(clientInfo->hWindowMenu,wndPtr->wIDmenu ,MF_BYCOMMAND);
84 bRet = ModifyMenu32A(clientInfo->hWindowMenu , wndPtr->wIDmenu,
85 MF_BYCOMMAND | MF_STRING, wndPtr->wIDmenu, buffer );
86 CheckMenuItem32(clientInfo->hWindowMenu ,wndPtr->wIDmenu , n & MF_CHECKED);
87 return bRet;
90 /**********************************************************************
91 * MDI_MenuDeleteItem
93 static BOOL32 MDI_MenuDeleteItem(WND* clientWnd, HWND32 hWndChild )
95 char buffer[128];
96 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
97 WND *wndPtr = WIN_FindWndPtr(hWndChild);
98 UINT32 index = 0,id,n;
100 if( !clientInfo->nActiveChildren ||
101 !clientInfo->hWindowMenu ) return 0;
103 id = wndPtr->wIDmenu;
104 DeleteMenu32(clientInfo->hWindowMenu,id,MF_BYCOMMAND);
106 /* walk the rest of MDI children to prevent gaps in the id
107 * sequence and in the menu child list */
109 for( index = id+1; index <= clientInfo->nActiveChildren +
110 clientInfo->idFirstChild; index++ )
112 wndPtr = WIN_FindWndPtr(MDI_GetChildByID(clientWnd,index));
113 if( !wndPtr )
115 TRACE(mdi,"no window for id=%i\n",index);
116 continue;
119 /* set correct id */
120 wndPtr->wIDmenu--;
122 n = sprintf(buffer, "%d ",index - clientInfo->idFirstChild);
123 if (wndPtr->text)
124 lstrcpyn32A(buffer + n, wndPtr->text, sizeof(buffer) - n );
126 /* change menu */
127 ModifyMenu32A(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING,
128 index - 1 , buffer );
130 return 1;
133 /**********************************************************************
134 * MDI_GetWindow
136 * returns "activateable" child different from the current or zero
138 static HWND32 MDI_GetWindow(WND *clientWnd, HWND32 hWnd, BOOL32 bNext,
139 DWORD dwStyleMask )
141 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
142 WND *wndPtr, *pWnd, *pWndLast = NULL;
144 dwStyleMask |= WS_DISABLED | WS_VISIBLE;
145 if( !hWnd ) hWnd = clientInfo->hwndActiveChild;
147 if( !(wndPtr = WIN_FindWndPtr(hWnd)) ) return 0;
149 for ( pWnd = wndPtr->next; ; pWnd = pWnd->next )
151 if (!pWnd ) pWnd = wndPtr->parent->child;
153 if ( pWnd == wndPtr ) break; /* went full circle */
155 if (!pWnd->owner && (pWnd->dwStyle & dwStyleMask) == WS_VISIBLE )
157 pWndLast = pWnd;
158 if ( bNext ) break;
161 return pWndLast ? pWndLast->hwndSelf : 0;
164 /**********************************************************************
165 * MDI_CalcDefaultChildPos
167 * It seems that the default height is about 2/3 of the client rect
169 static void MDI_CalcDefaultChildPos( WND* w, WORD n, LPPOINT32 lpPos,
170 INT32 delta)
172 INT32 nstagger;
173 RECT32 rect = w->rectClient;
174 INT32 spacing = GetSystemMetrics32(SM_CYCAPTION) +
175 GetSystemMetrics32(SM_CYFRAME) - 1;
177 if( rect.bottom - rect.top - delta >= spacing )
178 rect.bottom -= delta;
180 nstagger = (rect.bottom - rect.top)/(3 * spacing);
181 lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
182 lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
183 lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
186 /**********************************************************************
187 * MDISetMenu
189 static LRESULT MDISetMenu( HWND32 hwnd, HMENU32 hmenuFrame,
190 HMENU32 hmenuWindow)
192 WND *w = WIN_FindWndPtr(hwnd);
193 MDICLIENTINFO *ci;
194 HWND32 hwndFrame = GetParent32(hwnd);
195 HMENU32 oldFrameMenu = GetMenu32(hwndFrame);
197 TRACE(mdi, "%04x %04x %04x\n",
198 hwnd, hmenuFrame, hmenuWindow);
200 ci = (MDICLIENTINFO *) w->wExtra;
202 if( ci->hwndChildMaximized && hmenuFrame && hmenuFrame!=oldFrameMenu )
203 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized );
205 if( hmenuWindow && hmenuWindow!=ci->hWindowMenu )
207 /* delete menu items from ci->hWindowMenu
208 * and add them to hmenuWindow */
210 INT32 i = GetMenuItemCount32(ci->hWindowMenu) - 1;
211 INT32 pos = GetMenuItemCount32(hmenuWindow) + 1;
213 AppendMenu32A( hmenuWindow, MF_SEPARATOR, 0, NULL);
215 if( ci->nActiveChildren )
217 INT32 j = i - ci->nActiveChildren + 1;
218 char buffer[100];
219 UINT32 id,state;
221 for( ; i >= j ; i-- )
223 id = GetMenuItemID32(ci->hWindowMenu,i );
224 state = GetMenuState32(ci->hWindowMenu,i,MF_BYPOSITION);
226 GetMenuString32A(ci->hWindowMenu, i, buffer, 100, MF_BYPOSITION);
228 DeleteMenu32(ci->hWindowMenu, i , MF_BYPOSITION);
229 InsertMenu32A(hmenuWindow, pos, MF_BYPOSITION | MF_STRING,
230 id, buffer);
231 CheckMenuItem32(hmenuWindow ,pos , MF_BYPOSITION | (state & MF_CHECKED));
235 /* remove separator */
236 DeleteMenu32(ci->hWindowMenu, i, MF_BYPOSITION);
238 ci->hWindowMenu = hmenuWindow;
241 if( hmenuFrame && hmenuFrame!=oldFrameMenu)
243 SetMenu32(hwndFrame, hmenuFrame);
244 if( ci->hwndChildMaximized )
245 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
246 return oldFrameMenu;
248 return 0;
251 /**********************************************************************
252 * MDIRefreshMenu
254 static LRESULT MDIRefreshMenu( HWND32 hwnd, HMENU32 hmenuFrame,
255 HMENU32 hmenuWindow)
257 HWND32 hwndFrame = GetParent32(hwnd);
258 HMENU32 oldFrameMenu = GetMenu32(hwndFrame);
260 TRACE(mdi, "%04x %04x %04x\n",
261 hwnd, hmenuFrame, hmenuWindow);
263 FIXME(mdi,"partially function stub\n");
265 return oldFrameMenu;
269 /* ------------------ MDI child window functions ---------------------- */
272 /**********************************************************************
273 * MDICreateChild
275 static HWND32 MDICreateChild( WND *w, MDICLIENTINFO *ci, HWND32 parent,
276 LPMDICREATESTRUCT32A cs )
278 POINT32 pos[2];
279 DWORD style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
280 HWND32 hwnd, hwndMax = 0;
281 WORD wIDmenu = ci->idFirstChild + ci->nActiveChildren;
282 char lpstrDef[]="junk!";
284 TRACE(mdi, "origin %i,%i - dim %i,%i, style %08x\n",
285 cs->x, cs->y, cs->cx, cs->cy, (unsigned)cs->style);
286 /* calculate placement */
287 MDI_CalcDefaultChildPos(w, ci->nTotalCreated++, pos, 0);
289 if (cs->cx == CW_USEDEFAULT32 || !cs->cx) cs->cx = pos[1].x;
290 if (cs->cy == CW_USEDEFAULT32 || !cs->cy) cs->cy = pos[1].y;
292 if( cs->x == CW_USEDEFAULT32 )
294 cs->x = pos[0].x;
295 cs->y = pos[0].y;
298 /* restore current maximized child */
299 if( style & WS_VISIBLE && ci->hwndChildMaximized )
301 if( style & WS_MAXIMIZE )
302 SendMessage32A(w->hwndSelf, WM_SETREDRAW, FALSE, 0L );
303 hwndMax = ci->hwndChildMaximized;
304 ShowWindow32( hwndMax, SW_SHOWNOACTIVATE );
305 if( style & WS_MAXIMIZE )
306 SendMessage32A(w->hwndSelf, WM_SETREDRAW, TRUE, 0L );
309 /* this menu is needed to set a check mark in MDI_ChildActivate */
310 AppendMenu32A(ci->hWindowMenu ,MF_STRING ,wIDmenu, lpstrDef );
312 ci->nActiveChildren++;
314 /* fix window style */
315 if( !(w->dwStyle & MDIS_ALLCHILDSTYLES) )
317 style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE |
318 WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL );
319 style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW);
322 if( w->flags & WIN_ISWIN32 )
324 hwnd = CreateWindow32A( cs->szClass, cs->szTitle, style,
325 cs->x, cs->y, cs->cx, cs->cy, parent,
326 (HMENU16)wIDmenu, cs->hOwner, cs );
328 else
330 MDICREATESTRUCT16 *cs16;
331 LPSTR title, cls;
333 cs16 = SEGPTR_NEW(MDICREATESTRUCT16);
334 STRUCT32_MDICREATESTRUCT32Ato16( cs, cs16 );
335 title = SEGPTR_STRDUP( cs->szTitle );
336 cls = SEGPTR_STRDUP( cs->szClass );
337 cs16->szTitle = SEGPTR_GET(title);
338 cs16->szClass = SEGPTR_GET(cls);
340 hwnd = CreateWindow16( cs->szClass, cs->szTitle, style,
341 cs16->x, cs16->y, cs16->cx, cs16->cy, parent,
342 (HMENU32)wIDmenu, cs16->hOwner,
343 (LPVOID)SEGPTR_GET(cs16) );
344 SEGPTR_FREE( title );
345 SEGPTR_FREE( cls );
346 SEGPTR_FREE( cs16 );
349 /* MDI windows are WS_CHILD so they won't be activated by CreateWindow */
351 if (hwnd)
353 WND* wnd = WIN_FindWndPtr( hwnd );
355 MDI_MenuModifyItem(w ,hwnd);
356 if( wnd->dwStyle & WS_MINIMIZE && ci->hwndActiveChild )
357 ShowWindow32( hwnd, SW_SHOWMINNOACTIVE );
358 else
360 /* WS_VISIBLE is clear if a) the MDI client has
361 * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the
362 * MDICreateStruct. If so the created window is not shown nor
363 * activated.
365 int showflag=wnd->dwStyle & WS_VISIBLE;
366 /* clear visible flag, otherwise SetWindoPos32 ignores
367 * the SWP_SHOWWINDOW command.
369 wnd->dwStyle &= ~WS_VISIBLE;
370 if(showflag){
371 SetWindowPos32( hwnd, 0, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE );
373 /* Set maximized state here in case hwnd didn't receive WM_SIZE
374 * during CreateWindow - bad!
377 if((wnd->dwStyle & WS_MAXIMIZE) && !ci->hwndChildMaximized )
379 ci->hwndChildMaximized = wnd->hwndSelf;
380 MDI_AugmentFrameMenu( ci, w->parent, hwnd );
381 MDI_UpdateFrameText( w->parent, ci->self, MDI_REPAINTFRAME, NULL );
383 }else
384 /* needed, harmless ? */
385 SetWindowPos32( hwnd, 0, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE );
388 TRACE(mdi, "created child - %04x\n",hwnd);
390 else
392 ci->nActiveChildren--;
393 DeleteMenu32(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
394 if( IsWindow32(hwndMax) )
395 ShowWindow32(hwndMax, SW_SHOWMAXIMIZED);
398 return hwnd;
401 /**********************************************************************
402 * MDI_ChildGetMinMaxInfo
404 * Note: The rule here is that client rect of the maximized MDI child
405 * is equal to the client rect of the MDI client window.
407 static void MDI_ChildGetMinMaxInfo( WND* clientWnd, HWND32 hwnd,
408 MINMAXINFO16* lpMinMax )
410 WND* childWnd = WIN_FindWndPtr(hwnd);
411 RECT32 rect = clientWnd->rectClient;
413 MapWindowPoints32( clientWnd->parent->hwndSelf,
414 ((MDICLIENTINFO*)clientWnd->wExtra)->self, (LPPOINT32)&rect, 2);
415 AdjustWindowRectEx32( &rect, childWnd->dwStyle, 0, childWnd->dwExStyle );
417 lpMinMax->ptMaxSize.x = rect.right -= rect.left;
418 lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
420 lpMinMax->ptMaxPosition.x = rect.left;
421 lpMinMax->ptMaxPosition.y = rect.top;
423 TRACE(mdi,"max rect (%i,%i - %i, %i)\n",
424 rect.left,rect.top,rect.right,rect.bottom);
427 /**********************************************************************
428 * MDI_SwitchActiveChild
430 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
431 * being activated
433 static void MDI_SwitchActiveChild( HWND32 clientHwnd, HWND32 childHwnd,
434 BOOL32 bNextWindow )
436 WND *w = WIN_FindWndPtr(clientHwnd);
437 HWND32 hwndTo = 0;
438 HWND32 hwndPrev = 0;
439 MDICLIENTINFO *ci;
441 hwndTo = MDI_GetWindow(w, childHwnd, bNextWindow, 0);
443 ci = (MDICLIENTINFO *) w->wExtra;
445 TRACE(mdi, "from %04x, to %04x\n",childHwnd,hwndTo);
447 if ( !hwndTo ) return; /* no window to switch to */
449 hwndPrev = ci->hwndActiveChild;
451 if ( hwndTo != hwndPrev )
453 BOOL32 bOptimize = 0;
455 if( ci->hwndChildMaximized )
457 bOptimize = 1;
458 w->dwStyle &= ~WS_VISIBLE;
461 SetWindowPos32( hwndTo, HWND_TOP, 0, 0, 0, 0,
462 SWP_NOMOVE | SWP_NOSIZE );
464 if( bNextWindow && hwndPrev )
465 SetWindowPos32( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0,
466 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
467 if( bOptimize )
468 ShowWindow32( clientHwnd, SW_SHOW );
473 /**********************************************************************
474 * MDIDestroyChild
476 static LRESULT MDIDestroyChild( WND *w_parent, MDICLIENTINFO *ci,
477 HWND32 parent, HWND32 child,
478 BOOL32 flagDestroy )
480 WND *childPtr = WIN_FindWndPtr(child);
482 if( childPtr )
484 if( child == ci->hwndActiveChild )
486 MDI_SwitchActiveChild(parent, child, TRUE);
488 if( child == ci->hwndActiveChild )
490 ShowWindow32( child, SW_HIDE);
491 if( child == ci->hwndChildMaximized )
493 MDI_RestoreFrameMenu(w_parent->parent, child);
494 ci->hwndChildMaximized = 0;
495 MDI_UpdateFrameText(w_parent->parent,parent,TRUE,NULL);
498 MDI_ChildActivate(w_parent, 0);
500 MDI_MenuDeleteItem(w_parent, child);
503 ci->nActiveChildren--;
505 TRACE(mdi,"child destroyed - %04x\n",child);
507 if (flagDestroy)
509 MDI_PostUpdate(GetParent32(child), ci, SB_BOTH+1);
510 DestroyWindow32(child);
514 return 0;
518 /**********************************************************************
519 * MDI_ChildActivate
521 * Note: hWndChild is NULL when last child is being destroyed
523 static LONG MDI_ChildActivate( WND *clientPtr, HWND32 hWndChild )
525 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientPtr->wExtra;
526 HWND32 prevActiveWnd = clientInfo->hwndActiveChild;
527 WND *wndPtr = WIN_FindWndPtr( hWndChild );
528 WND *wndPrev = WIN_FindWndPtr( prevActiveWnd );
529 BOOL32 isActiveFrameWnd = 0;
531 if( hWndChild == prevActiveWnd ) return 0L;
533 if( wndPtr )
534 if( wndPtr->dwStyle & WS_DISABLED ) return 0L;
536 TRACE(mdi,"%04x\n", hWndChild);
538 if( GetActiveWindow32() == clientPtr->parent->hwndSelf )
539 isActiveFrameWnd = TRUE;
541 /* deactivate prev. active child */
542 if( wndPrev )
544 wndPrev->dwStyle |= WS_SYSMENU;
545 SendMessage32A( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
546 SendMessage32A( prevActiveWnd, WM_MDIACTIVATE, (WPARAM32)prevActiveWnd,
547 (LPARAM)hWndChild);
548 /* uncheck menu item */
549 if( clientInfo->hWindowMenu )
550 CheckMenuItem32( clientInfo->hWindowMenu,
551 wndPrev->wIDmenu, 0);
554 /* set appearance */
555 if( clientInfo->hwndChildMaximized )
557 if( clientInfo->hwndChildMaximized != hWndChild ) {
558 if( hWndChild ) {
559 clientInfo->hwndActiveChild = hWndChild;
560 ShowWindow32( hWndChild, SW_SHOWMAXIMIZED);
561 } else
562 ShowWindow32( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
566 clientInfo->hwndActiveChild = hWndChild;
568 /* check if we have any children left */
569 if( !hWndChild )
571 if( isActiveFrameWnd )
572 SetFocus32( clientInfo->self );
573 return 0;
576 /* check menu item */
577 if( clientInfo->hWindowMenu )
578 CheckMenuItem32( clientInfo->hWindowMenu,
579 wndPtr->wIDmenu, MF_CHECKED);
581 /* bring active child to the top */
582 SetWindowPos32( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
584 if( isActiveFrameWnd )
586 SendMessage32A( hWndChild, WM_NCACTIVATE, TRUE, 0L);
587 if( GetFocus32() == clientInfo->self )
588 SendMessage32A( clientInfo->self, WM_SETFOCUS,
589 (WPARAM32)clientInfo->self, 0L );
590 else
591 SetFocus32( clientInfo->self );
593 SendMessage32A( hWndChild, WM_MDIACTIVATE, (WPARAM32)prevActiveWnd,
594 (LPARAM)hWndChild );
595 return 1;
598 /* -------------------- MDI client window functions ------------------- */
600 /**********************************************************************
601 * CreateMDIMenuBitmap
603 static HBITMAP16 CreateMDIMenuBitmap(void)
605 HDC32 hDCSrc = CreateCompatibleDC32(0);
606 HDC32 hDCDest = CreateCompatibleDC32(hDCSrc);
607 HBITMAP16 hbClose = LoadBitmap16(0, MAKEINTRESOURCE16(OBM_CLOSE) );
608 HBITMAP16 hbCopy;
609 HANDLE16 hobjSrc, hobjDest;
611 hobjSrc = SelectObject32(hDCSrc, hbClose);
612 hbCopy = CreateCompatibleBitmap32(hDCSrc,SYSMETRICS_CXSIZE,SYSMETRICS_CYSIZE);
613 hobjDest = SelectObject32(hDCDest, hbCopy);
615 BitBlt32(hDCDest, 0, 0, SYSMETRICS_CXSIZE, SYSMETRICS_CYSIZE,
616 hDCSrc, SYSMETRICS_CXSIZE, 0, SRCCOPY);
618 SelectObject32(hDCSrc, hobjSrc);
619 DeleteObject32(hbClose);
620 DeleteDC32(hDCSrc);
622 hobjSrc = SelectObject32( hDCDest, GetStockObject32(BLACK_PEN) );
624 MoveToEx32( hDCDest, SYSMETRICS_CXSIZE - 1, 0, NULL );
625 LineTo32( hDCDest, SYSMETRICS_CXSIZE - 1, SYSMETRICS_CYSIZE - 1);
627 SelectObject32(hDCDest, hobjSrc );
628 SelectObject32(hDCDest, hobjDest);
629 DeleteDC32(hDCDest);
631 return hbCopy;
634 /**********************************************************************
635 * MDICascade
637 static LONG MDICascade(WND* clientWnd, MDICLIENTINFO *ci)
639 WND** ppWnd;
640 UINT32 total;
642 if (ci->hwndChildMaximized)
643 SendMessage32A( clientWnd->hwndSelf, WM_MDIRESTORE,
644 (WPARAM32)ci->hwndChildMaximized, 0);
646 if (ci->nActiveChildren == 0) return 0;
648 if ((ppWnd = WIN_BuildWinArray(clientWnd, BWA_SKIPHIDDEN | BWA_SKIPOWNED |
649 BWA_SKIPICONIC, &total)))
651 WND** heapPtr = ppWnd;
652 if( total )
654 INT32 delta = 0, n = 0;
655 POINT32 pos[2];
656 if( total < ci->nActiveChildren )
657 delta = SYSMETRICS_CYICONSPACING + SYSMETRICS_CYICON;
659 /* walk the list (backwards) and move windows */
660 while (*ppWnd) ppWnd++;
661 while (ppWnd != heapPtr)
663 ppWnd--;
664 TRACE(mdi, "move %04x to (%ld,%ld) size [%ld,%ld]\n",
665 (*ppWnd)->hwndSelf, pos[0].x, pos[0].y, pos[1].x, pos[1].y);
667 MDI_CalcDefaultChildPos(clientWnd, n++, pos, delta);
668 SetWindowPos32( (*ppWnd)->hwndSelf, 0, pos[0].x, pos[0].y,
669 pos[1].x, pos[1].y,
670 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
673 HeapFree( SystemHeap, 0, heapPtr );
676 if( total < ci->nActiveChildren )
677 ArrangeIconicWindows32( clientWnd->hwndSelf );
678 return 0;
681 /**********************************************************************
682 * MDITile
684 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM32 wParam )
686 WND** ppWnd;
687 UINT32 total = 0;
689 if (ci->hwndChildMaximized)
690 SendMessage32A( wndClient->hwndSelf, WM_MDIRESTORE,
691 (WPARAM32)ci->hwndChildMaximized, 0);
693 if (ci->nActiveChildren == 0) return;
695 ppWnd = WIN_BuildWinArray(wndClient, BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
696 ((wParam & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
698 TRACE(mdi,"%u windows to tile\n", total);
700 if( ppWnd )
702 WND** heapPtr = ppWnd;
704 if( total )
706 RECT32 rect;
707 int x, y, xsize, ysize;
708 int rows, columns, r, c, i;
710 rect = wndClient->rectClient;
711 rows = (int) sqrt((double)total);
712 columns = total / rows;
714 if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */
716 i = rows;
717 rows = columns; /* exchange r and c */
718 columns = i;
721 if( total != ci->nActiveChildren)
723 y = rect.bottom - 2 * SYSMETRICS_CYICONSPACING - SYSMETRICS_CYICON;
724 rect.bottom = ( y - SYSMETRICS_CYICON < rect.top )? rect.bottom: y;
727 ysize = rect.bottom / rows;
728 xsize = rect.right / columns;
730 for (x = i = 0, c = 1; c <= columns && *ppWnd; c++)
732 if (c == columns)
734 rows = total - i;
735 ysize = rect.bottom / rows;
738 y = 0;
739 for (r = 1; r <= rows && *ppWnd; r++, i++)
741 SetWindowPos32((*ppWnd)->hwndSelf, 0, x, y, xsize, ysize,
742 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
743 y += ysize;
744 ppWnd++;
746 x += xsize;
749 HeapFree( SystemHeap, 0, heapPtr );
752 if( total < ci->nActiveChildren ) ArrangeIconicWindows32( wndClient->hwndSelf );
755 /* ----------------------- Frame window ---------------------------- */
758 /**********************************************************************
759 * MDI_AugmentFrameMenu
761 static BOOL32 MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
762 HWND32 hChild )
764 WND* child = WIN_FindWndPtr(hChild);
765 HMENU32 hSysPopup = 0;
767 TRACE(mdi,"frame %p,child %04x\n",frame,hChild);
769 if( !frame->wIDmenu || !child->hSysMenu ) return 0;
771 /* create a copy of sysmenu popup and insert it into frame menu bar */
773 if (!(hSysPopup = LoadMenuIndirect32A(SYSRES_GetResPtr(SYSRES_MENU_SYSMENU))))
774 return 0;
776 TRACE(mdi,"\tgot popup %04x in sysmenu %04x\n",
777 hSysPopup, child->hSysMenu);
779 AppendMenu32A(frame->wIDmenu,MF_HELP | MF_BITMAP,
780 SC_MINIMIZE, (LPSTR)(DWORD)MAGIC_REDUCE ) ;
781 AppendMenu32A(frame->wIDmenu,MF_HELP | MF_BITMAP,
782 SC_RESTORE, (LPSTR)(DWORD)MAGIC_RESTORE );
784 if( !InsertMenu32A(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
785 hSysPopup, (LPSTR)(DWORD)hBmpClose ))
787 TRACE(mdi,"not inserted\n");
788 DestroyMenu32(hSysPopup);
789 return 0;
792 // The close button is only present in Win 95 look
793 if(TWEAK_WineLook > WIN31_LOOK)
795 AppendMenu32A(frame->wIDmenu,MF_HELP | MF_BITMAP,
796 SC_CLOSE, (LPSTR)(DWORD)MAGIC_CLOSE );
799 EnableMenuItem32(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
800 EnableMenuItem32(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
801 EnableMenuItem32(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
803 /* redraw menu */
804 DrawMenuBar32(frame->hwndSelf);
806 return 1;
809 /**********************************************************************
810 * MDI_RestoreFrameMenu
812 static BOOL32 MDI_RestoreFrameMenu( WND *frameWnd, HWND32 hChild )
814 INT32 nItems = GetMenuItemCount32(frameWnd->wIDmenu) - 1;
815 UINT32 iId = GetMenuItemID32(frameWnd->wIDmenu,nItems) ;
817 TRACE(mdi,"frameWnd %p,child %04x\n",frameWnd,hChild);
819 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
820 return 0;
822 // app button
823 RemoveMenu32(frameWnd->wIDmenu,0,MF_BYPOSITION);
825 if(TWEAK_WineLook > WIN31_LOOK)
827 // close
828 DeleteMenu32(frameWnd->wIDmenu,GetMenuItemCount32(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
830 // restore
831 DeleteMenu32(frameWnd->wIDmenu,GetMenuItemCount32(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
832 // minimize
833 DeleteMenu32(frameWnd->wIDmenu,GetMenuItemCount32(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
835 DrawMenuBar32(frameWnd->hwndSelf);
837 return 1;
841 /**********************************************************************
842 * MDI_UpdateFrameText
844 * used when child window is maximized/restored
846 * Note: lpTitle can be NULL
848 static void MDI_UpdateFrameText( WND *frameWnd, HWND32 hClient,
849 BOOL32 repaint, LPCSTR lpTitle )
851 char lpBuffer[MDI_MAXTITLELENGTH+1];
852 WND* clientWnd = WIN_FindWndPtr(hClient);
853 MDICLIENTINFO *ci = (MDICLIENTINFO *) clientWnd->wExtra;
855 TRACE(mdi, "repaint %i, frameText %s\n", repaint, (lpTitle)?lpTitle:"NULL");
857 if (!clientWnd)
858 return;
860 if (!ci)
861 return;
863 /* store new "default" title if lpTitle is not NULL */
864 if (lpTitle)
866 if (ci->frameTitle) HeapFree( SystemHeap, 0, ci->frameTitle );
867 ci->frameTitle = HEAP_strdupA( SystemHeap, 0, lpTitle );
870 if (ci->frameTitle)
872 WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );
874 if( childWnd && childWnd->text )
876 /* combine frame title and child title if possible */
878 LPCSTR lpBracket = " - [";
879 int i_frame_text_length = strlen(ci->frameTitle);
880 int i_child_text_length = strlen(childWnd->text);
882 lstrcpyn32A( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
884 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
886 strcat( lpBuffer, lpBracket );
888 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
890 strcat( lpBuffer, childWnd->text );
891 strcat( lpBuffer, "]" );
893 else
895 lstrcpyn32A( lpBuffer + i_frame_text_length + 4,
896 childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
897 strcat( lpBuffer, "]" );
901 else
903 strncpy(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH );
904 lpBuffer[MDI_MAXTITLELENGTH]='\0';
907 else
908 lpBuffer[0] = '\0';
910 DEFWND_SetText( frameWnd, lpBuffer );
911 if( repaint == MDI_REPAINTFRAME)
912 SetWindowPos32( frameWnd->hwndSelf, 0,0,0,0,0, SWP_FRAMECHANGED |
913 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
917 /* ----------------------------- Interface ---------------------------- */
920 /**********************************************************************
921 * MDIClientWndProc
923 * This function handles all MDI requests.
925 LRESULT WINAPI MDIClientWndProc( HWND32 hwnd, UINT32 message, WPARAM32 wParam,
926 LPARAM lParam )
928 LPCREATESTRUCT32A cs;
929 MDICLIENTINFO *ci;
930 RECT32 rect;
931 WND *w = WIN_FindWndPtr(hwnd);
932 WND *frameWnd = w->parent;
933 INT32 nItems;
935 ci = (MDICLIENTINFO *) w->wExtra;
937 switch (message)
939 case WM_CREATE:
941 cs = (LPCREATESTRUCT32A)lParam;
943 /* Translation layer doesn't know what's in the cs->lpCreateParams
944 * so we have to keep track of what environment we're in. */
946 if( w->flags & WIN_ISWIN32 )
948 #define ccs ((LPCLIENTCREATESTRUCT32)cs->lpCreateParams)
949 ci->hWindowMenu = ccs->hWindowMenu;
950 ci->idFirstChild = ccs->idFirstChild;
951 #undef ccs
953 else
955 LPCLIENTCREATESTRUCT16 ccs = (LPCLIENTCREATESTRUCT16)
956 PTR_SEG_TO_LIN(cs->lpCreateParams);
957 ci->hWindowMenu = ccs->hWindowMenu;
958 ci->idFirstChild = ccs->idFirstChild;
961 ci->hwndChildMaximized = 0;
962 ci->nActiveChildren = 0;
963 ci->nTotalCreated = 0;
964 ci->frameTitle = NULL;
965 ci->mdiFlags = 0;
966 ci->self = hwnd;
967 w->dwStyle |= WS_CLIPCHILDREN;
969 if (!hBmpClose)
971 hBmpClose = CreateMDIMenuBitmap();
972 hBmpRestore = LoadBitmap16( 0, MAKEINTRESOURCE16(OBM_RESTORE) );
974 MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
976 AppendMenu32A( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
978 GetClientRect32(frameWnd->hwndSelf, &rect);
979 NC_HandleNCCalcSize( w, &rect );
980 w->rectClient = rect;
982 TRACE(mdi,"Client created - hwnd = %04x, idFirst = %u\n",
983 hwnd, ci->idFirstChild );
985 return 0;
987 case WM_DESTROY:
988 if( ci->hwndChildMaximized ) MDI_RestoreFrameMenu(w, frameWnd->hwndSelf);
989 if((nItems = GetMenuItemCount32(ci->hWindowMenu)) > 0)
991 ci->idFirstChild = nItems - 1;
992 ci->nActiveChildren++; /* to delete a separator */
993 while( ci->nActiveChildren-- )
994 DeleteMenu32(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
996 return 0;
998 case WM_MDIACTIVATE:
999 if( ci->hwndActiveChild != (HWND32)wParam )
1000 SetWindowPos32((HWND32)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
1001 return 0;
1003 case WM_MDICASCADE:
1004 return MDICascade(w, ci);
1006 case WM_MDICREATE:
1007 if (lParam) return MDICreateChild( w, ci, hwnd,
1008 (MDICREATESTRUCT32A*)lParam );
1009 return 0;
1011 case WM_MDIDESTROY:
1012 return MDIDestroyChild( w, ci, hwnd, (HWND32)wParam, TRUE );
1014 case WM_MDIGETACTIVE:
1015 if (lParam) *(BOOL32 *)lParam = (ci->hwndChildMaximized > 0);
1016 return ci->hwndActiveChild;
1018 case WM_MDIICONARRANGE:
1019 ci->mdiFlags |= MDIF_NEEDUPDATE;
1020 ArrangeIconicWindows32(hwnd);
1021 ci->sbRecalc = SB_BOTH+1;
1022 SendMessage32A(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
1023 return 0;
1025 case WM_MDIMAXIMIZE:
1026 ShowWindow32( (HWND32)wParam, SW_MAXIMIZE );
1027 return 0;
1029 case WM_MDINEXT: /* lParam != 0 means previous window */
1030 MDI_SwitchActiveChild(hwnd, (HWND32)wParam, (lParam)? FALSE : TRUE );
1031 break;
1033 case WM_MDIRESTORE:
1034 SendMessage32A( (HWND32)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
1035 return 0;
1037 case WM_MDISETMENU:
1038 return MDISetMenu( hwnd, (HMENU32)wParam, (HMENU32)lParam );
1040 case WM_MDIREFRESHMENU:
1041 return MDIRefreshMenu( hwnd, (HMENU32)wParam, (HMENU32)lParam );
1043 case WM_MDITILE:
1044 ci->mdiFlags |= MDIF_NEEDUPDATE;
1045 ShowScrollBar32(hwnd,SB_BOTH,FALSE);
1046 MDITile(w, ci, wParam);
1047 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1048 return 0;
1050 case WM_VSCROLL:
1051 case WM_HSCROLL:
1052 ci->mdiFlags |= MDIF_NEEDUPDATE;
1053 ScrollChildren32(hwnd, message, wParam, lParam);
1054 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1055 return 0;
1057 case WM_SETFOCUS:
1058 if( ci->hwndActiveChild )
1060 w = WIN_FindWndPtr( ci->hwndActiveChild );
1061 if( !(w->dwStyle & WS_MINIMIZE) )
1062 SetFocus32( ci->hwndActiveChild );
1064 return 0;
1066 case WM_NCACTIVATE:
1067 if( ci->hwndActiveChild )
1068 SendMessage32A(ci->hwndActiveChild, message, wParam, lParam);
1069 break;
1071 case WM_PARENTNOTIFY:
1072 if (LOWORD(wParam) == WM_LBUTTONDOWN)
1074 POINT16 pt = MAKEPOINT16(lParam);
1075 HWND16 child = ChildWindowFromPoint16(hwnd, pt);
1077 TRACE(mdi,"notification from %04x (%i,%i)\n",child,pt.x,pt.y);
1079 if( child && child != hwnd && child != ci->hwndActiveChild )
1080 SetWindowPos32(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1082 return 0;
1084 case WM_SIZE:
1085 if( IsWindow32(ci->hwndChildMaximized) )
1087 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1088 RECT32 rect = { 0, 0, LOWORD(lParam), HIWORD(lParam) };
1090 AdjustWindowRectEx32(&rect, child->dwStyle, 0, child->dwExStyle);
1091 MoveWindow32(ci->hwndChildMaximized, rect.left, rect.top,
1092 rect.right - rect.left, rect.bottom - rect.top, 1);
1094 else
1095 MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1097 break;
1099 case WM_MDICALCCHILDSCROLL:
1100 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1102 CalcChildScroll(hwnd, ci->sbRecalc-1);
1103 ci->sbRecalc = 0;
1104 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1106 return 0;
1109 return DefWindowProc32A( hwnd, message, wParam, lParam );
1113 /***********************************************************************
1114 * DefFrameProc16 (USER.445)
1116 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1117 UINT16 message, WPARAM16 wParam, LPARAM lParam )
1119 HWND16 childHwnd;
1120 MDICLIENTINFO* ci;
1121 WND* wndPtr;
1123 if (hwndMDIClient)
1125 switch (message)
1127 case WM_COMMAND:
1128 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1129 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1131 /* check for possible syscommands for maximized MDI child */
1133 if( ci && (
1134 wParam < ci->idFirstChild ||
1135 wParam >= ci->idFirstChild + ci->nActiveChildren
1137 if( (wParam - 0xF000) & 0xF00F ) break;
1138 switch( wParam )
1140 case SC_SIZE:
1141 case SC_MOVE:
1142 case SC_MINIMIZE:
1143 case SC_MAXIMIZE:
1144 case SC_NEXTWINDOW:
1145 case SC_PREVWINDOW:
1146 case SC_CLOSE:
1147 case SC_RESTORE:
1148 if( ci->hwndChildMaximized )
1149 return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1150 wParam, lParam);
1153 else
1155 childHwnd = MDI_GetChildByID( WIN_FindWndPtr(hwndMDIClient),
1156 wParam );
1157 if( childHwnd )
1158 SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1159 (WPARAM16)childHwnd , 0L);
1161 break;
1163 case WM_NCACTIVATE:
1164 SendMessage16(hwndMDIClient, message, wParam, lParam);
1165 break;
1167 case WM_SETTEXT:
1168 MDI_UpdateFrameText(WIN_FindWndPtr(hwnd), hwndMDIClient,
1169 MDI_REPAINTFRAME,
1170 (LPCSTR)PTR_SEG_TO_LIN(lParam));
1171 return 0;
1173 case WM_SETFOCUS:
1174 SetFocus32(hwndMDIClient);
1175 break;
1177 case WM_SIZE:
1178 MoveWindow16(hwndMDIClient, 0, 0,
1179 LOWORD(lParam), HIWORD(lParam), TRUE);
1180 break;
1182 case WM_NEXTMENU:
1184 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1185 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1187 if( !(wndPtr->parent->dwStyle & WS_MINIMIZE)
1188 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1190 /* control menu is between the frame system menu and
1191 * the first entry of menu bar */
1193 if( (wParam == VK_LEFT &&
1194 wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1195 (wParam == VK_RIGHT &&
1196 GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1198 wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1199 return MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1200 ci->hwndActiveChild);
1203 break;
1207 return DefWindowProc16(hwnd, message, wParam, lParam);
1211 /***********************************************************************
1212 * DefFrameProc32A (USER32.122)
1214 LRESULT WINAPI DefFrameProc32A( HWND32 hwnd, HWND32 hwndMDIClient,
1215 UINT32 message, WPARAM32 wParam, LPARAM lParam)
1217 if (hwndMDIClient)
1219 switch (message)
1221 case WM_COMMAND:
1222 return DefFrameProc16( hwnd, hwndMDIClient, message,
1223 (WPARAM16)wParam,
1224 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1226 case WM_NCACTIVATE:
1227 SendMessage32A(hwndMDIClient, message, wParam, lParam);
1228 break;
1230 case WM_SETTEXT: {
1231 LRESULT ret;
1232 LPSTR segstr = SEGPTR_STRDUP((LPSTR)lParam);
1234 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1235 wParam, (LPARAM)SEGPTR_GET(segstr) );
1236 SEGPTR_FREE(segstr);
1237 return ret;
1240 case WM_NEXTMENU:
1241 case WM_SETFOCUS:
1242 case WM_SIZE:
1243 return DefFrameProc16( hwnd, hwndMDIClient, message,
1244 wParam, lParam );
1248 return DefWindowProc32A(hwnd, message, wParam, lParam);
1252 /***********************************************************************
1253 * DefFrameProc32W (USER32.123)
1255 LRESULT WINAPI DefFrameProc32W( HWND32 hwnd, HWND32 hwndMDIClient,
1256 UINT32 message, WPARAM32 wParam, LPARAM lParam)
1258 if (hwndMDIClient)
1260 switch (message)
1262 case WM_COMMAND:
1263 return DefFrameProc16( hwnd, hwndMDIClient, message,
1264 (WPARAM16)wParam,
1265 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1267 case WM_NCACTIVATE:
1268 SendMessage32W(hwndMDIClient, message, wParam, lParam);
1269 break;
1271 case WM_SETTEXT:
1273 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1274 LRESULT ret = DefFrameProc32A( hwnd, hwndMDIClient, message,
1275 wParam, (DWORD)txt );
1276 HeapFree(GetProcessHeap(),0,txt);
1277 return ret;
1279 case WM_NEXTMENU:
1280 case WM_SETFOCUS:
1281 case WM_SIZE:
1282 return DefFrameProc32A( hwnd, hwndMDIClient, message,
1283 wParam, lParam );
1287 return DefWindowProc32W( hwnd, message, wParam, lParam );
1291 /***********************************************************************
1292 * DefMDIChildProc16 (USER.447)
1294 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1295 WPARAM16 wParam, LPARAM lParam )
1297 MDICLIENTINFO *ci;
1298 WND *clientWnd;
1300 clientWnd = WIN_FindWndPtr(GetParent16(hwnd));
1301 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1303 switch (message)
1305 case WM_SETTEXT:
1306 DefWindowProc16(hwnd, message, wParam, lParam);
1307 MDI_MenuModifyItem(clientWnd,hwnd);
1308 if( ci->hwndChildMaximized == hwnd )
1309 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1310 MDI_REPAINTFRAME, NULL );
1311 return 0;
1313 case WM_CLOSE:
1314 SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1315 return 0;
1317 case WM_SETFOCUS:
1318 if( ci->hwndActiveChild != hwnd )
1319 MDI_ChildActivate(clientWnd, hwnd);
1320 break;
1322 case WM_CHILDACTIVATE:
1323 MDI_ChildActivate(clientWnd, hwnd);
1324 return 0;
1326 case WM_NCPAINT:
1327 TRACE(mdi,"WM_NCPAINT for %04x, active %04x\n",
1328 hwnd, ci->hwndActiveChild );
1329 break;
1331 case WM_SYSCOMMAND:
1332 switch( wParam )
1334 case SC_MOVE:
1335 if( ci->hwndChildMaximized == hwnd) return 0;
1336 break;
1337 case SC_RESTORE:
1338 case SC_MINIMIZE:
1339 WIN_FindWndPtr(hwnd)->dwStyle |= WS_SYSMENU;
1340 break;
1341 case SC_MAXIMIZE:
1342 if( ci->hwndChildMaximized == hwnd)
1343 return SendMessage16( clientWnd->parent->hwndSelf,
1344 message, wParam, lParam);
1345 WIN_FindWndPtr(hwnd)->dwStyle &= ~WS_SYSMENU;
1346 break;
1347 case SC_NEXTWINDOW:
1348 SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1349 return 0;
1350 case SC_PREVWINDOW:
1351 SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1352 return 0;
1354 break;
1356 case WM_GETMINMAXINFO:
1357 MDI_ChildGetMinMaxInfo(clientWnd, hwnd, (MINMAXINFO16*) PTR_SEG_TO_LIN(lParam));
1358 return 0;
1360 case WM_SETVISIBLE:
1361 if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1362 else
1363 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1364 break;
1366 case WM_SIZE:
1367 /* do not change */
1369 if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1371 ci->hwndChildMaximized = 0;
1373 MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1374 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1375 MDI_REPAINTFRAME, NULL );
1378 if( wParam == SIZE_MAXIMIZED )
1380 HWND16 hMaxChild = ci->hwndChildMaximized;
1382 if( hMaxChild == hwnd ) break;
1384 if( hMaxChild)
1386 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1388 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1389 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1391 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1394 TRACE(mdi,"maximizing child %04x\n", hwnd );
1396 ci->hwndChildMaximized = hwnd; /* !!! */
1397 ci->hwndActiveChild = hwnd;
1399 MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1400 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1401 MDI_REPAINTFRAME, NULL );
1404 if( wParam == SIZE_MINIMIZED )
1406 HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1408 if( switchTo )
1409 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1412 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1413 break;
1415 case WM_MENUCHAR:
1417 /* MDI children don't have menu bars */
1418 PostMessage16( clientWnd->parent->hwndSelf, WM_SYSCOMMAND,
1419 (WPARAM16)SC_KEYMENU, (LPARAM)wParam);
1420 return 0x00010000L;
1422 case WM_NEXTMENU:
1424 if( wParam == VK_LEFT ) /* switch to frame system menu */
1425 return MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1426 clientWnd->parent->hwndSelf );
1427 if( wParam == VK_RIGHT ) /* to frame menu bar */
1428 return MAKELONG( clientWnd->parent->wIDmenu,
1429 clientWnd->parent->hwndSelf );
1431 break;
1433 case WM_SYSCHAR:
1434 if (wParam == '-')
1436 SendMessage16(hwnd,WM_SYSCOMMAND,
1437 (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1438 return 0;
1442 return DefWindowProc16(hwnd, message, wParam, lParam);
1446 /***********************************************************************
1447 * DefMDIChildProc32A (USER32.124)
1449 LRESULT WINAPI DefMDIChildProc32A( HWND32 hwnd, UINT32 message,
1450 WPARAM32 wParam, LPARAM lParam )
1452 MDICLIENTINFO *ci;
1453 WND *clientWnd;
1455 clientWnd = WIN_FindWndPtr(WIN_FindWndPtr(hwnd)->parent->hwndSelf);
1456 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1458 switch (message)
1460 case WM_SETTEXT:
1461 DefWindowProc32A(hwnd, message, wParam, lParam);
1462 MDI_MenuModifyItem(clientWnd,hwnd);
1463 if( ci->hwndChildMaximized == hwnd )
1464 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1465 MDI_REPAINTFRAME, NULL );
1466 return 0;
1468 case WM_GETMINMAXINFO:
1470 MINMAXINFO16 mmi;
1471 STRUCT32_MINMAXINFO32to16( (MINMAXINFO32 *)lParam, &mmi );
1472 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1473 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO32 *)lParam );
1475 return 0;
1477 case WM_MENUCHAR:
1479 /* MDI children don't have menu bars */
1480 PostMessage16( clientWnd->parent->hwndSelf, WM_SYSCOMMAND,
1481 (WPARAM16)SC_KEYMENU, (LPARAM)LOWORD(wParam) );
1482 return 0x00010000L;
1484 case WM_CLOSE:
1485 case WM_SETFOCUS:
1486 case WM_CHILDACTIVATE:
1487 case WM_NCPAINT:
1488 case WM_SYSCOMMAND:
1489 case WM_SETVISIBLE:
1490 case WM_SIZE:
1491 case WM_NEXTMENU:
1492 return DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1494 case WM_SYSCHAR:
1495 if (wParam == '-')
1497 SendMessage32A(hwnd,WM_SYSCOMMAND,
1498 (WPARAM32)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1499 return 0;
1502 return DefWindowProc32A(hwnd, message, wParam, lParam);
1506 /***********************************************************************
1507 * DefMDIChildProc32W (USER32.125)
1509 LRESULT WINAPI DefMDIChildProc32W( HWND32 hwnd, UINT32 message,
1510 WPARAM32 wParam, LPARAM lParam )
1512 MDICLIENTINFO *ci;
1513 WND *clientWnd;
1515 clientWnd = WIN_FindWndPtr(GetParent16(hwnd));
1516 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1518 switch (message)
1520 case WM_SETTEXT:
1521 DefWindowProc32W(hwnd, message, wParam, lParam);
1522 MDI_MenuModifyItem(clientWnd,hwnd);
1523 if( ci->hwndChildMaximized == hwnd )
1524 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1525 MDI_REPAINTFRAME, NULL );
1526 return 0;
1528 case WM_GETMINMAXINFO:
1529 case WM_MENUCHAR:
1530 case WM_CLOSE:
1531 case WM_SETFOCUS:
1532 case WM_CHILDACTIVATE:
1533 case WM_NCPAINT:
1534 case WM_SYSCOMMAND:
1535 case WM_SETVISIBLE:
1536 case WM_SIZE:
1537 case WM_NEXTMENU:
1538 return DefMDIChildProc32A( hwnd, message, (WPARAM16)wParam, lParam );
1540 case WM_SYSCHAR:
1541 if (wParam == '-')
1543 SendMessage32W(hwnd,WM_SYSCOMMAND,
1544 (WPARAM32)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1545 return 0;
1548 return DefWindowProc32W(hwnd, message, wParam, lParam);
1552 /**********************************************************************
1553 * CreateMDIWindowA [USER32.79] Creates a MDI child in new thread
1554 * FIXME: its in the same thread now
1556 * RETURNS
1557 * Success: Handle to created window
1558 * Failure: NULL
1560 HWND32 WINAPI CreateMDIWindow32A(
1561 LPCSTR lpClassName, /* [in] Pointer to registered child class name */
1562 LPCSTR lpWindowName, /* [in] Pointer to window name */
1563 DWORD dwStyle, /* [in] Window style */
1564 INT32 X, /* [in] Horizontal position of window */
1565 INT32 Y, /* [in] Vertical position of window */
1566 INT32 nWidth, /* [in] Width of window */
1567 INT32 nHeight, /* [in] Height of window */
1568 HWND32 hWndParent, /* [in] Handle to parent window */
1569 HINSTANCE32 hInstance, /* [in] Handle to application instance */
1570 LPARAM lParam) /* [in] Application-defined value */
1572 WARN(mdi,"is only single threaded!\n");
1573 return MDI_CreateMDIWindow32A(lpClassName, lpWindowName, dwStyle, X, Y,
1574 nWidth, nHeight, hWndParent, hInstance, lParam);
1577 /**********************************************************************
1578 * MDI_CreateMDIWindowA
1579 * single threaded version of CreateMDIWindowA
1580 * called by CreateWindowEx32A
1582 HWND32 MDI_CreateMDIWindow32A(
1583 LPCSTR lpClassName,
1584 LPCSTR lpWindowName,
1585 DWORD dwStyle,
1586 INT32 X,
1587 INT32 Y,
1588 INT32 nWidth,
1589 INT32 nHeight,
1590 HWND32 hWndParent,
1591 HINSTANCE32 hInstance,
1592 LPARAM lParam)
1594 MDICLIENTINFO* pCi;
1595 MDICREATESTRUCT32A cs;
1596 WND *pWnd=WIN_FindWndPtr(hWndParent);
1598 TRACE(mdi, "(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
1599 debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
1600 nWidth,nHeight,hWndParent,hInstance,lParam);
1602 if(!pWnd){
1603 ERR(mdi," bad hwnd for MDI-client: %d\n",hWndParent);
1604 return 0;
1606 cs.szClass=lpClassName;
1607 cs.szTitle=lpWindowName;
1608 cs.hOwner=hInstance;
1609 cs.x=X;
1610 cs.y=Y;
1611 cs.cx=nWidth;
1612 cs.cy=nHeight;
1613 cs.style=dwStyle;
1614 cs.lParam=lParam;
1616 pCi=(MDICLIENTINFO *)pWnd->wExtra;
1618 return MDICreateChild(pWnd,pCi,hWndParent,&cs);
1621 /***************************************
1622 * CreateMDIWindow32W [USER32.80] Creates a MDI child in new thread
1624 * RETURNS
1625 * Success: Handle to created window
1626 * Failure: NULL
1628 HWND32 WINAPI CreateMDIWindow32W(
1629 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1630 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1631 DWORD dwStyle, /* [in] Window style */
1632 INT32 X, /* [in] Horizontal position of window */
1633 INT32 Y, /* [in] Vertical position of window */
1634 INT32 nWidth, /* [in] Width of window */
1635 INT32 nHeight, /* [in] Height of window */
1636 HWND32 hWndParent, /* [in] Handle to parent window */
1637 HINSTANCE32 hInstance, /* [in] Handle to application instance */
1638 LPARAM lParam) /* [in] Application-defined value */
1640 FIXME(mdi, "(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1641 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1642 nWidth,nHeight,hWndParent,hInstance,lParam);
1643 return (HWND32)NULL;
1647 /******************************************************************************
1648 * CreateMDIWindow32W [USER32.80] Creates a MDI child window
1649 * single threaded version of CreateMDIWindow
1650 * called by CreateWindowEx32W().
1652 HWND32 MDI_CreateMDIWindow32W(
1653 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1654 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1655 DWORD dwStyle, /* [in] Window style */
1656 INT32 X, /* [in] Horizontal position of window */
1657 INT32 Y, /* [in] Vertical position of window */
1658 INT32 nWidth, /* [in] Width of window */
1659 INT32 nHeight, /* [in] Height of window */
1660 HWND32 hWndParent, /* [in] Handle to parent window */
1661 HINSTANCE32 hInstance, /* [in] Handle to application instance */
1662 LPARAM lParam) /* [in] Application-defined value */
1664 FIXME(mdi, "(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1665 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1666 nWidth,nHeight,hWndParent,hInstance,lParam);
1667 return (HWND32)NULL;
1671 /**********************************************************************
1672 * TranslateMDISysAccel32 (USER32.555)
1674 BOOL32 WINAPI TranslateMDISysAccel32( HWND32 hwndClient, LPMSG32 msg )
1676 MSG16 msg16;
1678 STRUCT32_MSG32to16(msg,&msg16);
1679 /* MDICLIENTINFO is still the same for win32 and win16 ... */
1680 return TranslateMDISysAccel16(hwndClient,&msg16);
1684 /**********************************************************************
1685 * TranslateMDISysAccel16 (USER.451)
1687 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
1689 WND* clientWnd = WIN_FindWndPtr( hwndClient);
1691 if( clientWnd && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
1693 MDICLIENTINFO *ci = NULL;
1694 WND* wnd;
1696 ci = (MDICLIENTINFO*) clientWnd->wExtra;
1697 wnd = WIN_FindWndPtr(ci->hwndActiveChild);
1698 if( wnd && !(wnd->dwStyle & WS_DISABLED) )
1700 WPARAM16 wParam = 0;
1702 /* translate if the Ctrl key is down and Alt not. */
1704 if( (GetKeyState32(VK_CONTROL) & 0x8000) &&
1705 !(GetKeyState32(VK_MENU) & 0x8000))
1707 switch( msg->wParam )
1709 case VK_F6:
1710 case VK_TAB:
1711 wParam = ( GetKeyState32(VK_SHIFT) & 0x8000 )
1712 ? SC_NEXTWINDOW : SC_PREVWINDOW;
1713 break;
1714 case VK_F4:
1715 case VK_RBUTTON:
1716 wParam = SC_CLOSE;
1717 break;
1718 default:
1719 return 0;
1721 TRACE(mdi,"wParam = %04x\n", wParam);
1722 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
1723 wParam, (LPARAM)msg->wParam);
1724 return 1;
1728 return 0; /* failure */
1732 /***********************************************************************
1733 * CalcChildScroll (USER.462)
1735 void WINAPI CalcChildScroll( HWND16 hwnd, WORD scroll )
1737 SCROLLINFO info;
1738 RECT32 childRect, clientRect;
1739 INT32 vmin, vmax, hmin, hmax, vpos, hpos;
1740 WND *pWnd, *Wnd;
1742 if (!(Wnd = pWnd = WIN_FindWndPtr( hwnd ))) return;
1743 GetClientRect32( hwnd, &clientRect );
1744 SetRectEmpty32( &childRect );
1746 for ( pWnd = pWnd->child; pWnd; pWnd = pWnd->next )
1748 if( pWnd->dwStyle & WS_MAXIMIZE )
1750 ShowScrollBar32(hwnd, SB_BOTH, FALSE);
1751 return;
1753 UnionRect32( &childRect, &pWnd->rectWindow, &childRect );
1755 UnionRect32( &childRect, &clientRect, &childRect );
1757 hmin = childRect.left; hmax = childRect.right - clientRect.right;
1758 hpos = clientRect.left - childRect.left;
1759 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
1760 vpos = clientRect.top - childRect.top;
1762 switch( scroll )
1764 case SB_HORZ:
1765 vpos = hpos; vmin = hmin; vmax = hmax;
1766 case SB_VERT:
1767 info.cbSize = sizeof(info);
1768 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
1769 info.fMask = SIF_POS | SIF_RANGE;
1770 SetScrollInfo32(hwnd, scroll, &info, TRUE);
1771 break;
1772 case SB_BOTH:
1773 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
1774 hmin, hmax, hpos);
1779 /***********************************************************************
1780 * ScrollChildren16 (USER.463)
1782 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
1784 return ScrollChildren32( hWnd, uMsg, wParam, lParam );
1788 /***********************************************************************
1789 * ScrollChildren32 (USER32.448)
1791 void WINAPI ScrollChildren32(HWND32 hWnd, UINT32 uMsg, WPARAM32 wParam,
1792 LPARAM lParam)
1794 WND *wndPtr = WIN_FindWndPtr(hWnd);
1795 INT32 newPos = -1;
1796 INT32 curPos, length, minPos, maxPos, shift;
1798 if( !wndPtr ) return;
1800 if( uMsg == WM_HSCROLL )
1802 GetScrollRange32(hWnd,SB_HORZ,&minPos,&maxPos);
1803 curPos = GetScrollPos32(hWnd,SB_HORZ);
1804 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
1805 shift = SYSMETRICS_CYHSCROLL;
1807 else if( uMsg == WM_VSCROLL )
1809 GetScrollRange32(hWnd,SB_VERT,&minPos,&maxPos);
1810 curPos = GetScrollPos32(hWnd,SB_VERT);
1811 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
1812 shift = SYSMETRICS_CXVSCROLL;
1814 else return;
1816 switch( wParam )
1818 case SB_LINEUP:
1819 newPos = curPos - shift;
1820 break;
1821 case SB_LINEDOWN:
1822 newPos = curPos + shift;
1823 break;
1824 case SB_PAGEUP:
1825 newPos = curPos - length;
1826 break;
1827 case SB_PAGEDOWN:
1828 newPos = curPos + length;
1829 break;
1831 case SB_THUMBPOSITION:
1832 newPos = LOWORD(lParam);
1833 break;
1835 case SB_THUMBTRACK:
1836 return;
1838 case SB_TOP:
1839 newPos = minPos;
1840 break;
1841 case SB_BOTTOM:
1842 newPos = maxPos;
1843 break;
1844 case SB_ENDSCROLL:
1845 CalcChildScroll(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
1846 return;
1849 if( newPos > maxPos )
1850 newPos = maxPos;
1851 else
1852 if( newPos < minPos )
1853 newPos = minPos;
1855 SetScrollPos32(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
1857 if( uMsg == WM_VSCROLL )
1858 ScrollWindowEx32(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
1859 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1860 else
1861 ScrollWindowEx32(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
1862 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1866 /******************************************************************************
1867 * CascadeWindows [USER32.21] Cascades MDI child windows
1869 * RETURNS
1870 * Success: Number of cascaded windows.
1871 * Failure: 0
1873 WORD WINAPI
1874 CascadeWindows (HWND32 hwndParent, UINT32 wFlags, const LPRECT32 lpRect,
1875 UINT32 cKids, const HWND32 *lpKids)
1877 FIXME (mdi, "(0x%08x,0x%08x,...,%u,...): stub\n",
1878 hwndParent, wFlags, cKids);
1880 return 0;
1884 /******************************************************************************
1885 * TileWindows [USER32.545] Tiles MDI child windows
1887 * RETURNS
1888 * Success: Number of tiled windows.
1889 * Failure: 0
1891 WORD WINAPI
1892 TileWindows (HWND32 hwndParent, UINT32 wFlags, const LPRECT32 lpRect,
1893 UINT32 cKids, const HWND32 *lpKids)
1895 FIXME (mdi, "(0x%08x,0x%08x,...,%u,...): stub\n",
1896 hwndParent, wFlags, cKids);
1898 return 0;