Release 990226.
[wine/gsoc-2012-control.git] / windows / mdi.c
blob10c9ff33ef00f788f8abb8754a656480e834d30c
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 "winuser.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 INT SCROLL_SetNCSbState(WND*,int,int,int,int,int,int);
38 /* ----------------- declarations ----------------- */
39 static void MDI_UpdateFrameText(WND *, HWND, BOOL, LPCSTR);
40 static BOOL MDI_AugmentFrameMenu(MDICLIENTINFO*, WND *, HWND);
41 static BOOL MDI_RestoreFrameMenu(WND *, HWND);
43 static LONG MDI_ChildActivate( WND*, HWND );
45 /* -------- Miscellaneous service functions ----------
47 * MDI_GetChildByID
50 static HWND MDI_GetChildByID(WND* wndPtr, INT 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(HWND hwnd, MDICLIENTINFO* ci, WORD recalc)
59 if( !(ci->mdiFlags & MDIF_NEEDUPDATE) )
61 ci->mdiFlags |= MDIF_NEEDUPDATE;
62 PostMessageA( hwnd, WM_MDICALCCHILDSCROLL, 0, 0);
64 ci->sbRecalc = recalc;
67 /**********************************************************************
68 * MDI_MenuModifyItem
70 static BOOL MDI_MenuModifyItem(WND* clientWnd, HWND hWndChild )
72 char buffer[128];
73 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
74 WND *wndPtr = WIN_FindWndPtr(hWndChild);
75 UINT n = sprintf(buffer, "%d ",
76 wndPtr->wIDmenu - clientInfo->idFirstChild + 1);
77 BOOL bRet = 0;
79 if( !clientInfo->hWindowMenu ) return 0;
81 if (wndPtr->text) lstrcpynA(buffer + n, wndPtr->text, sizeof(buffer) - n );
83 n = GetMenuState(clientInfo->hWindowMenu,wndPtr->wIDmenu ,MF_BYCOMMAND);
84 bRet = ModifyMenuA(clientInfo->hWindowMenu , wndPtr->wIDmenu,
85 MF_BYCOMMAND | MF_STRING, wndPtr->wIDmenu, buffer );
86 CheckMenuItem(clientInfo->hWindowMenu ,wndPtr->wIDmenu , n & MF_CHECKED);
87 return bRet;
90 /**********************************************************************
91 * MDI_MenuDeleteItem
93 static BOOL MDI_MenuDeleteItem(WND* clientWnd, HWND hWndChild )
95 char buffer[128];
96 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
97 WND *wndPtr = WIN_FindWndPtr(hWndChild);
98 UINT index = 0,id,n;
100 if( !clientInfo->nActiveChildren ||
101 !clientInfo->hWindowMenu ) return 0;
103 id = wndPtr->wIDmenu;
104 DeleteMenu(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 lstrcpynA(buffer + n, wndPtr->text, sizeof(buffer) - n );
126 /* change menu */
127 ModifyMenuA(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 HWND MDI_GetWindow(WND *clientWnd, HWND hWnd, BOOL 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, LPPOINT lpPos,
170 INT delta)
172 INT nstagger;
173 RECT rect = w->rectClient;
174 INT spacing = GetSystemMetrics(SM_CYCAPTION) +
175 GetSystemMetrics(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( HWND hwnd, HMENU hmenuFrame,
190 HMENU hmenuWindow)
192 WND *w = WIN_FindWndPtr(hwnd);
193 MDICLIENTINFO *ci;
194 HWND hwndFrame = GetParent(hwnd);
195 HMENU oldFrameMenu = GetMenu(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 INT i = GetMenuItemCount(ci->hWindowMenu) - 1;
211 INT pos = GetMenuItemCount(hmenuWindow) + 1;
213 AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL);
215 if( ci->nActiveChildren )
217 INT j = i - ci->nActiveChildren + 1;
218 char buffer[100];
219 UINT id,state;
221 for( ; i >= j ; i-- )
223 id = GetMenuItemID(ci->hWindowMenu,i );
224 state = GetMenuState(ci->hWindowMenu,i,MF_BYPOSITION);
226 GetMenuStringA(ci->hWindowMenu, i, buffer, 100, MF_BYPOSITION);
228 DeleteMenu(ci->hWindowMenu, i , MF_BYPOSITION);
229 InsertMenuA(hmenuWindow, pos, MF_BYPOSITION | MF_STRING,
230 id, buffer);
231 CheckMenuItem(hmenuWindow ,pos , MF_BYPOSITION | (state & MF_CHECKED));
235 /* remove separator */
236 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
238 ci->hWindowMenu = hmenuWindow;
241 if( hmenuFrame && hmenuFrame!=oldFrameMenu)
243 SetMenu(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( HWND hwnd, HMENU hmenuFrame,
255 HMENU hmenuWindow)
257 HWND hwndFrame = GetParent(hwnd);
258 HMENU oldFrameMenu = GetMenu(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 HWND MDICreateChild( WND *w, MDICLIENTINFO *ci, HWND parent,
276 LPMDICREATESTRUCTA cs )
278 POINT pos[2];
279 DWORD style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
280 HWND 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_USEDEFAULT || !cs->cx) cs->cx = pos[1].x;
290 if (cs->cy == CW_USEDEFAULT || !cs->cy) cs->cy = pos[1].y;
292 if( cs->x == CW_USEDEFAULT )
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 SendMessageA(w->hwndSelf, WM_SETREDRAW, FALSE, 0L );
303 hwndMax = ci->hwndChildMaximized;
304 ShowWindow( hwndMax, SW_SHOWNOACTIVATE );
305 if( style & WS_MAXIMIZE )
306 SendMessageA(w->hwndSelf, WM_SETREDRAW, TRUE, 0L );
309 /* this menu is needed to set a check mark in MDI_ChildActivate */
310 AppendMenuA(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 = CreateWindowA( 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 (HMENU)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 ShowWindow( 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 SetWindowPos( 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 SetWindowPos( 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 DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
394 if( IsWindow(hwndMax) )
395 ShowWindow(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, HWND hwnd,
408 MINMAXINFO16* lpMinMax )
410 WND* childWnd = WIN_FindWndPtr(hwnd);
411 RECT rect = clientWnd->rectClient;
413 MapWindowPoints( clientWnd->parent->hwndSelf,
414 ((MDICLIENTINFO*)clientWnd->wExtra)->self, (LPPOINT)&rect, 2);
415 AdjustWindowRectEx( &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( HWND clientHwnd, HWND childHwnd,
434 BOOL bNextWindow )
436 WND *w = WIN_FindWndPtr(clientHwnd);
437 HWND hwndTo = 0;
438 HWND 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 BOOL bOptimize = 0;
455 if( ci->hwndChildMaximized )
457 bOptimize = 1;
458 w->dwStyle &= ~WS_VISIBLE;
461 SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0,
462 SWP_NOMOVE | SWP_NOSIZE );
464 if( bNextWindow && hwndPrev )
465 SetWindowPos( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0,
466 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
467 if( bOptimize )
468 ShowWindow( clientHwnd, SW_SHOW );
473 /**********************************************************************
474 * MDIDestroyChild
476 static LRESULT MDIDestroyChild( WND *w_parent, MDICLIENTINFO *ci,
477 HWND parent, HWND child,
478 BOOL 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 ShowWindow( 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(GetParent(child), ci, SB_BOTH+1);
510 DestroyWindow(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, HWND hWndChild )
525 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientPtr->wExtra;
526 HWND prevActiveWnd = clientInfo->hwndActiveChild;
527 WND *wndPtr = WIN_FindWndPtr( hWndChild );
528 WND *wndPrev = WIN_FindWndPtr( prevActiveWnd );
529 BOOL 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( GetActiveWindow() == clientPtr->parent->hwndSelf )
539 isActiveFrameWnd = TRUE;
541 /* deactivate prev. active child */
542 if( wndPrev )
544 wndPrev->dwStyle |= WS_SYSMENU;
545 SendMessageA( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
546 SendMessageA( prevActiveWnd, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
547 (LPARAM)hWndChild);
548 /* uncheck menu item */
549 if( clientInfo->hWindowMenu )
550 CheckMenuItem( 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 ShowWindow( hWndChild, SW_SHOWMAXIMIZED);
561 } else
562 ShowWindow( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
566 clientInfo->hwndActiveChild = hWndChild;
568 /* check if we have any children left */
569 if( !hWndChild )
571 if( isActiveFrameWnd )
572 SetFocus( clientInfo->self );
573 return 0;
576 /* check menu item */
577 if( clientInfo->hWindowMenu )
578 CheckMenuItem( clientInfo->hWindowMenu,
579 wndPtr->wIDmenu, MF_CHECKED);
581 /* bring active child to the top */
582 SetWindowPos( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
584 if( isActiveFrameWnd )
586 SendMessageA( hWndChild, WM_NCACTIVATE, TRUE, 0L);
587 if( GetFocus() == clientInfo->self )
588 SendMessageA( clientInfo->self, WM_SETFOCUS,
589 (WPARAM)clientInfo->self, 0L );
590 else
591 SetFocus( clientInfo->self );
593 SendMessageA( hWndChild, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
594 (LPARAM)hWndChild );
595 return 1;
598 /* -------------------- MDI client window functions ------------------- */
600 /**********************************************************************
601 * CreateMDIMenuBitmap
603 static HBITMAP16 CreateMDIMenuBitmap(void)
605 HDC hDCSrc = CreateCompatibleDC(0);
606 HDC hDCDest = CreateCompatibleDC(hDCSrc);
607 HBITMAP16 hbClose = LoadBitmap16(0, MAKEINTRESOURCE16(OBM_CLOSE) );
608 HBITMAP16 hbCopy;
609 HANDLE16 hobjSrc, hobjDest;
611 hobjSrc = SelectObject(hDCSrc, hbClose);
612 hbCopy = CreateCompatibleBitmap(hDCSrc,SYSMETRICS_CXSIZE,SYSMETRICS_CYSIZE);
613 hobjDest = SelectObject(hDCDest, hbCopy);
615 BitBlt(hDCDest, 0, 0, SYSMETRICS_CXSIZE, SYSMETRICS_CYSIZE,
616 hDCSrc, SYSMETRICS_CXSIZE, 0, SRCCOPY);
618 SelectObject(hDCSrc, hobjSrc);
619 DeleteObject(hbClose);
620 DeleteDC(hDCSrc);
622 hobjSrc = SelectObject( hDCDest, GetStockObject(BLACK_PEN) );
624 MoveToEx( hDCDest, SYSMETRICS_CXSIZE - 1, 0, NULL );
625 LineTo( hDCDest, SYSMETRICS_CXSIZE - 1, SYSMETRICS_CYSIZE - 1);
627 SelectObject(hDCDest, hobjSrc );
628 SelectObject(hDCDest, hobjDest);
629 DeleteDC(hDCDest);
631 return hbCopy;
634 /**********************************************************************
635 * MDICascade
637 static LONG MDICascade(WND* clientWnd, MDICLIENTINFO *ci)
639 WND** ppWnd;
640 UINT total;
642 if (ci->hwndChildMaximized)
643 SendMessageA( clientWnd->hwndSelf, WM_MDIRESTORE,
644 (WPARAM)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 INT delta = 0, n = 0;
655 POINT 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 SetWindowPos( (*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 ArrangeIconicWindows( clientWnd->hwndSelf );
678 return 0;
681 /**********************************************************************
682 * MDITile
684 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM wParam )
686 WND** ppWnd;
687 UINT total = 0;
689 if (ci->hwndChildMaximized)
690 SendMessageA( wndClient->hwndSelf, WM_MDIRESTORE,
691 (WPARAM)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 RECT 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 SetWindowPos((*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 ) ArrangeIconicWindows( wndClient->hwndSelf );
755 /* ----------------------- Frame window ---------------------------- */
758 /**********************************************************************
759 * MDI_AugmentFrameMenu
761 static BOOL MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
762 HWND hChild )
764 WND* child = WIN_FindWndPtr(hChild);
765 HMENU 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 = LoadMenuIndirectA(SYSRES_GetResPtr(SYSRES_MENU_SYSMENU))))
774 return 0;
776 TRACE(mdi,"\tgot popup %04x in sysmenu %04x\n",
777 hSysPopup, child->hSysMenu);
779 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
780 SC_MINIMIZE, (LPSTR)(DWORD)MAGIC_REDUCE ) ;
781 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
782 SC_RESTORE, (LPSTR)(DWORD)MAGIC_RESTORE );
784 if( !InsertMenuA(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
785 hSysPopup, (LPSTR)(DWORD)hBmpClose ))
787 TRACE(mdi,"not inserted\n");
788 DestroyMenu(hSysPopup);
789 return 0;
792 // The close button is only present in Win 95 look
793 if(TWEAK_WineLook > WIN31_LOOK)
795 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
796 SC_CLOSE, (LPSTR)(DWORD)MAGIC_CLOSE );
799 EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
800 EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
801 EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
803 /* redraw menu */
804 DrawMenuBar(frame->hwndSelf);
806 return 1;
809 /**********************************************************************
810 * MDI_RestoreFrameMenu
812 static BOOL MDI_RestoreFrameMenu( WND *frameWnd, HWND hChild )
814 INT nItems = GetMenuItemCount(frameWnd->wIDmenu) - 1;
815 UINT iId = GetMenuItemID(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 RemoveMenu(frameWnd->wIDmenu,0,MF_BYPOSITION);
825 if(TWEAK_WineLook > WIN31_LOOK)
827 // close
828 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
830 // restore
831 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
832 // minimize
833 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
835 DrawMenuBar(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, HWND hClient,
849 BOOL 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 lstrcpynA( 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 lstrcpynA( 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 SetWindowPos( 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( HWND hwnd, UINT message, WPARAM wParam,
926 LPARAM lParam )
928 LPCREATESTRUCTA cs;
929 MDICLIENTINFO *ci;
930 RECT rect;
931 WND *w = WIN_FindWndPtr(hwnd);
932 WND *frameWnd = w->parent;
933 INT nItems;
935 ci = (MDICLIENTINFO *) w->wExtra;
937 switch (message)
939 case WM_CREATE:
941 cs = (LPCREATESTRUCTA)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 ((LPCLIENTCREATESTRUCT)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 AppendMenuA( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
978 GetClientRect(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 = GetMenuItemCount(ci->hWindowMenu)) > 0)
991 ci->idFirstChild = nItems - 1;
992 ci->nActiveChildren++; /* to delete a separator */
993 while( ci->nActiveChildren-- )
994 DeleteMenu(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
996 return 0;
998 case WM_MDIACTIVATE:
999 if( ci->hwndActiveChild != (HWND)wParam )
1000 SetWindowPos((HWND)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 (MDICREATESTRUCTA*)lParam );
1009 return 0;
1011 case WM_MDIDESTROY:
1012 return MDIDestroyChild( w, ci, hwnd, (HWND)wParam, TRUE );
1014 case WM_MDIGETACTIVE:
1015 if (lParam) *(BOOL *)lParam = (ci->hwndChildMaximized > 0);
1016 return ci->hwndActiveChild;
1018 case WM_MDIICONARRANGE:
1019 ci->mdiFlags |= MDIF_NEEDUPDATE;
1020 ArrangeIconicWindows(hwnd);
1021 ci->sbRecalc = SB_BOTH+1;
1022 SendMessageA(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
1023 return 0;
1025 case WM_MDIMAXIMIZE:
1026 ShowWindow( (HWND)wParam, SW_MAXIMIZE );
1027 return 0;
1029 case WM_MDINEXT: /* lParam != 0 means previous window */
1030 MDI_SwitchActiveChild(hwnd, (HWND)wParam, (lParam)? FALSE : TRUE );
1031 break;
1033 case WM_MDIRESTORE:
1034 SendMessageA( (HWND)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
1035 return 0;
1037 case WM_MDISETMENU:
1038 return MDISetMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1040 case WM_MDIREFRESHMENU:
1041 return MDIRefreshMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1043 case WM_MDITILE:
1044 ci->mdiFlags |= MDIF_NEEDUPDATE;
1045 ShowScrollBar(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 ScrollChildren(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 SetFocus( ci->hwndActiveChild );
1064 return 0;
1066 case WM_NCACTIVATE:
1067 if( ci->hwndActiveChild )
1068 SendMessageA(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 SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1082 return 0;
1084 case WM_SIZE:
1085 if( IsWindow(ci->hwndChildMaximized) )
1087 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1088 RECT rect = { 0, 0, LOWORD(lParam), HIWORD(lParam) };
1090 AdjustWindowRectEx(&rect, child->dwStyle, 0, child->dwExStyle);
1091 MoveWindow(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 CalcChildScroll16(hwnd, ci->sbRecalc-1);
1103 ci->sbRecalc = 0;
1104 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1106 return 0;
1109 return DefWindowProcA( 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 SetFocus(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 DefFrameProcA( HWND hwnd, HWND hwndMDIClient,
1215 UINT message, WPARAM 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 SendMessageA(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 DefWindowProcA(hwnd, message, wParam, lParam);
1252 /***********************************************************************
1253 * DefFrameProc32W (USER32.123)
1255 LRESULT WINAPI DefFrameProcW( HWND hwnd, HWND hwndMDIClient,
1256 UINT message, WPARAM 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 SendMessageW(hwndMDIClient, message, wParam, lParam);
1269 break;
1271 case WM_SETTEXT:
1273 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1274 LRESULT ret = DefFrameProcA( 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 DefFrameProcA( hwnd, hwndMDIClient, message,
1283 wParam, lParam );
1287 return DefWindowProcW( 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 DefMDIChildProcA( HWND hwnd, UINT message,
1450 WPARAM 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 DefWindowProcA(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( (MINMAXINFO *)lParam, &mmi );
1472 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1473 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO *)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 SendMessageA(hwnd,WM_SYSCOMMAND,
1498 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1499 return 0;
1502 return DefWindowProcA(hwnd, message, wParam, lParam);
1506 /***********************************************************************
1507 * DefMDIChildProc32W (USER32.125)
1509 LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message,
1510 WPARAM 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 DefWindowProcW(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 DefMDIChildProcA( hwnd, message, (WPARAM16)wParam, lParam );
1540 case WM_SYSCHAR:
1541 if (wParam == '-')
1543 SendMessageW(hwnd,WM_SYSCOMMAND,
1544 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1545 return 0;
1548 return DefWindowProcW(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 HWND WINAPI CreateMDIWindowA(
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 INT X, /* [in] Horizontal position of window */
1565 INT Y, /* [in] Vertical position of window */
1566 INT nWidth, /* [in] Width of window */
1567 INT nHeight, /* [in] Height of window */
1568 HWND hWndParent, /* [in] Handle to parent window */
1569 HINSTANCE hInstance, /* [in] Handle to application instance */
1570 LPARAM lParam) /* [in] Application-defined value */
1572 WARN(mdi,"is only single threaded!\n");
1573 return MDI_CreateMDIWindowA(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 HWND MDI_CreateMDIWindowA(
1583 LPCSTR lpClassName,
1584 LPCSTR lpWindowName,
1585 DWORD dwStyle,
1586 INT X,
1587 INT Y,
1588 INT nWidth,
1589 INT nHeight,
1590 HWND hWndParent,
1591 HINSTANCE hInstance,
1592 LPARAM lParam)
1594 MDICLIENTINFO* pCi;
1595 MDICREATESTRUCTA 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 HWND WINAPI CreateMDIWindowW(
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 INT X, /* [in] Horizontal position of window */
1633 INT Y, /* [in] Vertical position of window */
1634 INT nWidth, /* [in] Width of window */
1635 INT nHeight, /* [in] Height of window */
1636 HWND hWndParent, /* [in] Handle to parent window */
1637 HINSTANCE 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 (HWND)NULL;
1647 /******************************************************************************
1648 * CreateMDIWindow32W [USER32.80] Creates a MDI child window
1649 * single threaded version of CreateMDIWindow
1650 * called by CreateWindowEx32W().
1652 HWND MDI_CreateMDIWindowW(
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 INT X, /* [in] Horizontal position of window */
1657 INT Y, /* [in] Vertical position of window */
1658 INT nWidth, /* [in] Width of window */
1659 INT nHeight, /* [in] Height of window */
1660 HWND hWndParent, /* [in] Handle to parent window */
1661 HINSTANCE 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 (HWND)NULL;
1671 /**********************************************************************
1672 * TranslateMDISysAccel32 (USER32.555)
1674 BOOL WINAPI TranslateMDISysAccel( HWND hwndClient, LPMSG 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( (GetKeyState(VK_CONTROL) & 0x8000) &&
1705 !(GetKeyState(VK_MENU) & 0x8000))
1707 switch( msg->wParam )
1709 case VK_F6:
1710 case VK_TAB:
1711 wParam = ( GetKeyState(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 CalcChildScroll16( HWND16 hwnd, WORD scroll )
1737 SCROLLINFO info;
1738 RECT childRect, clientRect;
1739 INT vmin, vmax, hmin, hmax, vpos, hpos;
1740 WND *pWnd, *Wnd;
1742 if (!(Wnd = pWnd = WIN_FindWndPtr( hwnd ))) return;
1743 GetClientRect( hwnd, &clientRect );
1744 SetRectEmpty( &childRect );
1746 for ( pWnd = pWnd->child; pWnd; pWnd = pWnd->next )
1748 if( pWnd->dwStyle & WS_MAXIMIZE )
1750 ShowScrollBar(hwnd, SB_BOTH, FALSE);
1751 return;
1753 UnionRect( &childRect, &pWnd->rectWindow, &childRect );
1755 UnionRect( &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 SetScrollInfo(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 ScrollChildren( hWnd, uMsg, wParam, lParam );
1788 /***********************************************************************
1789 * ScrollChildren32 (USER32.448)
1791 void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
1792 LPARAM lParam)
1794 WND *wndPtr = WIN_FindWndPtr(hWnd);
1795 INT newPos = -1;
1796 INT curPos, length, minPos, maxPos, shift;
1798 if( !wndPtr ) return;
1800 if( uMsg == WM_HSCROLL )
1802 GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
1803 curPos = GetScrollPos(hWnd,SB_HORZ);
1804 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
1805 shift = SYSMETRICS_CYHSCROLL;
1807 else if( uMsg == WM_VSCROLL )
1809 GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
1810 curPos = GetScrollPos(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 CalcChildScroll16(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 SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
1857 if( uMsg == WM_VSCROLL )
1858 ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
1859 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1860 else
1861 ScrollWindowEx(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 (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
1875 UINT cKids, const HWND *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 (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
1893 UINT cKids, const HWND *lpKids)
1895 FIXME (mdi, "(0x%08x,0x%08x,...,%u,...): stub\n",
1896 hwndParent, wFlags, cKids);
1898 return 0;