Jean-Claude Batista
[wine/multimedia.git] / windows / mdi.c
blobdd64a74838607e8ca1fe7e2eba585fc5da2d4672
1 /* MDI.C
3 * Copyright 1994, Bob Amstadt
4 * 1995,1996 Alex Korobka
6 * This file contains routines to support MDI (Multiple Document
7 * Interface) features .
9 * Notes: Fairly complete implementation. Any volunteers for
10 * "More windows..." stuff?
12 * Also, Excel and WinWord do _not_ use MDI so if you're trying
13 * to fix them look elsewhere.
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <math.h>
20 #include "windef.h"
21 #include "wingdi.h"
22 #include "winuser.h"
23 #include "win.h"
24 #include "heap.h"
25 #include "nonclient.h"
26 #include "mdi.h"
27 #include "user.h"
28 #include "menu.h"
29 #include "scroll.h"
30 #include "struct32.h"
31 #include "tweak.h"
32 #include "debugtools.h"
34 DEFAULT_DEBUG_CHANNEL(mdi);
36 #define MDIF_NEEDUPDATE 0x0001
38 static HBITMAP16 hBmpClose = 0;
39 static HBITMAP16 hBmpRestore = 0;
41 /* ----------------- declarations ----------------- */
42 static void MDI_UpdateFrameText(WND *, HWND, BOOL, LPCSTR);
43 static BOOL MDI_AugmentFrameMenu(MDICLIENTINFO*, WND *, HWND);
44 static BOOL MDI_RestoreFrameMenu(WND *, HWND);
46 static LONG MDI_ChildActivate( WND*, HWND );
48 /* -------- Miscellaneous service functions ----------
50 * MDI_GetChildByID
53 static HWND MDI_GetChildByID(WND* wndPtr, INT id)
55 for (wndPtr = wndPtr->child; wndPtr; wndPtr = wndPtr->next)
56 if (wndPtr->wIDmenu == id) return wndPtr->hwndSelf;
57 return 0;
60 static void MDI_PostUpdate(HWND hwnd, MDICLIENTINFO* ci, WORD recalc)
62 if( !(ci->mdiFlags & MDIF_NEEDUPDATE) )
64 ci->mdiFlags |= MDIF_NEEDUPDATE;
65 PostMessageA( hwnd, WM_MDICALCCHILDSCROLL, 0, 0);
67 ci->sbRecalc = recalc;
70 /**********************************************************************
71 * MDI_MenuModifyItem
73 static BOOL MDI_MenuModifyItem(WND* clientWnd, HWND hWndChild )
75 char buffer[128];
76 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
77 WND *wndPtr = WIN_FindWndPtr(hWndChild);
78 UINT n = sprintf(buffer, "%d ",
79 wndPtr->wIDmenu - clientInfo->idFirstChild + 1);
80 BOOL bRet = 0;
82 if( !clientInfo->hWindowMenu )
84 bRet = FALSE;
85 goto END;
88 if (wndPtr->text) lstrcpynA(buffer + n, wndPtr->text, sizeof(buffer) - n );
90 n = GetMenuState(clientInfo->hWindowMenu,wndPtr->wIDmenu ,MF_BYCOMMAND);
91 bRet = ModifyMenuA(clientInfo->hWindowMenu , wndPtr->wIDmenu,
92 MF_BYCOMMAND | MF_STRING, wndPtr->wIDmenu, buffer );
93 CheckMenuItem(clientInfo->hWindowMenu ,wndPtr->wIDmenu , n & MF_CHECKED);
94 END:
95 WIN_ReleaseWndPtr(wndPtr);
96 return bRet;
99 /**********************************************************************
100 * MDI_MenuDeleteItem
102 static BOOL MDI_MenuDeleteItem(WND* clientWnd, HWND hWndChild )
104 char buffer[128];
105 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
106 WND *wndPtr = WIN_FindWndPtr(hWndChild);
107 UINT index = 0,id,n;
108 BOOL retvalue;
110 if( !clientInfo->nActiveChildren ||
111 !clientInfo->hWindowMenu )
113 retvalue = FALSE;
114 goto END;
117 id = wndPtr->wIDmenu;
118 DeleteMenu(clientInfo->hWindowMenu,id,MF_BYCOMMAND);
120 /* walk the rest of MDI children to prevent gaps in the id
121 * sequence and in the menu child list */
123 for( index = id+1; index <= clientInfo->nActiveChildren +
124 clientInfo->idFirstChild; index++ )
126 WND *tmpWnd = WIN_FindWndPtr(MDI_GetChildByID(clientWnd,index));
127 if( !tmpWnd )
129 TRACE("no window for id=%i\n",index);
130 WIN_ReleaseWndPtr(tmpWnd);
131 continue;
134 /* set correct id */
135 tmpWnd->wIDmenu--;
137 n = sprintf(buffer, "%d ",index - clientInfo->idFirstChild);
138 if (tmpWnd->text)
139 lstrcpynA(buffer + n, tmpWnd->text, sizeof(buffer) - n );
141 /* change menu */
142 ModifyMenuA(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING,
143 index - 1 , buffer );
144 WIN_ReleaseWndPtr(tmpWnd);
146 retvalue = TRUE;
147 END:
148 WIN_ReleaseWndPtr(wndPtr);
149 return retvalue;
152 /**********************************************************************
153 * MDI_GetWindow
155 * returns "activateable" child different from the current or zero
157 static HWND MDI_GetWindow(WND *clientWnd, HWND hWnd, BOOL bNext,
158 DWORD dwStyleMask )
160 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
161 WND *wndPtr, *pWnd, *pWndLast = NULL;
163 dwStyleMask |= WS_DISABLED | WS_VISIBLE;
164 if( !hWnd ) hWnd = clientInfo->hwndActiveChild;
166 if( !(wndPtr = WIN_FindWndPtr(hWnd)) ) return 0;
168 for ( pWnd = WIN_LockWndPtr(wndPtr->next); ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
170 if (!pWnd ) WIN_UpdateWndPtr(&pWnd,wndPtr->parent->child);
172 if ( pWnd == wndPtr ) break; /* went full circle */
174 if (!pWnd->owner && (pWnd->dwStyle & dwStyleMask) == WS_VISIBLE )
176 pWndLast = pWnd;
177 if ( bNext ) break;
180 WIN_ReleaseWndPtr(wndPtr);
181 WIN_ReleaseWndPtr(pWnd);
182 return pWndLast ? pWndLast->hwndSelf : 0;
185 /**********************************************************************
186 * MDI_CalcDefaultChildPos
188 * It seems that the default height is about 2/3 of the client rect
190 static void MDI_CalcDefaultChildPos( WND* w, WORD n, LPPOINT lpPos,
191 INT delta)
193 INT nstagger;
194 RECT rect = w->rectClient;
195 INT spacing = GetSystemMetrics(SM_CYCAPTION) +
196 GetSystemMetrics(SM_CYFRAME) - 1;
198 if( rect.bottom - rect.top - delta >= spacing )
199 rect.bottom -= delta;
201 nstagger = (rect.bottom - rect.top)/(3 * spacing);
202 lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
203 lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
204 lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
207 /**********************************************************************
208 * MDISetMenu
210 static LRESULT MDISetMenu( HWND hwnd, HMENU hmenuFrame,
211 HMENU hmenuWindow)
213 WND *w;
214 MDICLIENTINFO *ci;
215 HWND hwndFrame = GetParent(hwnd);
216 HMENU oldFrameMenu = GetMenu(hwndFrame);
218 TRACE("%04x %04x %04x\n",
219 hwnd, hmenuFrame, hmenuWindow);
221 if (hmenuFrame && !IsMenu(hmenuFrame))
223 WARN("hmenuFrame is not a menu handle\n");
224 return 0L;
227 if (hmenuWindow && !IsMenu(hmenuWindow))
229 WARN("hmenuWindow is not a menu handle\n");
230 return 0L;
233 w = WIN_FindWndPtr(hwnd);
234 ci = (MDICLIENTINFO *) w->wExtra;
236 if( ci->hwndChildMaximized && hmenuFrame && hmenuFrame!=oldFrameMenu )
237 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized );
239 if( hmenuWindow && hmenuWindow!=ci->hWindowMenu )
241 /* delete menu items from ci->hWindowMenu
242 * and add them to hmenuWindow */
244 INT i = GetMenuItemCount(ci->hWindowMenu) - 1;
245 INT pos = GetMenuItemCount(hmenuWindow) + 1;
247 AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL);
249 if( ci->nActiveChildren )
251 INT j = i - ci->nActiveChildren + 1;
252 LPWSTR buffer = NULL;
253 MENUITEMINFOW mii;
255 for( ; i >= j ; i-- )
257 memset(&mii, 0, sizeof(mii));
258 mii.cbSize = sizeof(mii);
259 mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE
260 | MIIM_SUBMENU | MIIM_TYPE | MIIM_BITMAP;
262 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
263 if(mii.cch) { /* Menu is MFT_STRING */
264 mii.cch++; /* add room for '\0' */
265 buffer = HeapAlloc(GetProcessHeap(), 0,
266 mii.cch * sizeof(WCHAR));
267 mii.dwTypeData = buffer;
268 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
270 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
271 InsertMenuItemW(hmenuWindow, pos, TRUE, &mii);
272 if(buffer) {
273 HeapFree(GetProcessHeap(), 0, buffer);
274 buffer = NULL;
279 /* remove separator */
280 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
282 ci->hWindowMenu = hmenuWindow;
285 if (hmenuFrame)
287 SetMenu(hwndFrame, hmenuFrame);
288 if( hmenuFrame!=oldFrameMenu )
290 if( ci->hwndChildMaximized )
291 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
292 WIN_ReleaseWndPtr(w);
293 return oldFrameMenu;
296 WIN_ReleaseWndPtr(w);
297 return 0;
300 /**********************************************************************
301 * MDIRefreshMenu
303 static LRESULT MDIRefreshMenu( HWND hwnd, HMENU hmenuFrame,
304 HMENU hmenuWindow)
306 HWND hwndFrame = GetParent(hwnd);
307 HMENU oldFrameMenu = GetMenu(hwndFrame);
309 TRACE("%04x %04x %04x\n",
310 hwnd, hmenuFrame, hmenuWindow);
312 FIXME("partially function stub\n");
314 return oldFrameMenu;
318 /* ------------------ MDI child window functions ---------------------- */
321 /**********************************************************************
322 * MDICreateChild
324 static HWND MDICreateChild( WND *w, MDICLIENTINFO *ci, HWND parent,
325 LPMDICREATESTRUCTA cs )
327 POINT pos[2];
328 DWORD style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
329 HWND hwnd, hwndMax = 0;
330 WORD wIDmenu = ci->idFirstChild + ci->nActiveChildren;
331 char lpstrDef[]="junk!";
333 TRACE("origin %i,%i - dim %i,%i, style %08x\n",
334 cs->x, cs->y, cs->cx, cs->cy, (unsigned)cs->style);
335 /* calculate placement */
336 MDI_CalcDefaultChildPos(w, ci->nTotalCreated++, pos, 0);
338 if (cs->cx == CW_USEDEFAULT || !cs->cx) cs->cx = pos[1].x;
339 if (cs->cy == CW_USEDEFAULT || !cs->cy) cs->cy = pos[1].y;
341 if( cs->x == CW_USEDEFAULT )
343 cs->x = pos[0].x;
344 cs->y = pos[0].y;
347 /* restore current maximized child */
348 if( style & WS_VISIBLE && ci->hwndChildMaximized )
350 if( style & WS_MAXIMIZE )
351 SendMessageA(w->hwndSelf, WM_SETREDRAW, FALSE, 0L );
352 hwndMax = ci->hwndChildMaximized;
353 ShowWindow( hwndMax, SW_SHOWNOACTIVATE );
354 if( style & WS_MAXIMIZE )
355 SendMessageA(w->hwndSelf, WM_SETREDRAW, TRUE, 0L );
358 /* this menu is needed to set a check mark in MDI_ChildActivate */
359 if (ci->hWindowMenu != 0)
360 AppendMenuA(ci->hWindowMenu ,MF_STRING ,wIDmenu, lpstrDef );
362 ci->nActiveChildren++;
364 /* fix window style */
365 if( !(w->dwStyle & MDIS_ALLCHILDSTYLES) )
367 style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE |
368 WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL );
369 style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW);
372 if( w->flags & WIN_ISWIN32 )
374 hwnd = CreateWindowA( cs->szClass, cs->szTitle, style,
375 cs->x, cs->y, cs->cx, cs->cy, parent,
376 (HMENU16)wIDmenu, cs->hOwner, cs );
378 else
380 MDICREATESTRUCT16 *cs16;
381 LPSTR title, cls;
383 cs16 = SEGPTR_NEW(MDICREATESTRUCT16);
384 STRUCT32_MDICREATESTRUCT32Ato16( cs, cs16 );
385 title = SEGPTR_STRDUP( cs->szTitle );
386 cls = SEGPTR_STRDUP( cs->szClass );
387 cs16->szTitle = SEGPTR_GET(title);
388 cs16->szClass = SEGPTR_GET(cls);
390 hwnd = CreateWindow16( cs->szClass, cs->szTitle, style,
391 cs16->x, cs16->y, cs16->cx, cs16->cy, parent,
392 (HMENU)wIDmenu, cs16->hOwner,
393 (LPVOID)SEGPTR_GET(cs16) );
394 SEGPTR_FREE( title );
395 SEGPTR_FREE( cls );
396 SEGPTR_FREE( cs16 );
399 /* MDI windows are WS_CHILD so they won't be activated by CreateWindow */
401 if (hwnd)
403 WND* wnd = WIN_FindWndPtr( hwnd );
405 /* All MDI child windows have the WS_EX_MDICHILD style */
406 wnd->dwExStyle |= WS_EX_MDICHILD;
408 MDI_MenuModifyItem(w ,hwnd);
409 if( wnd->dwStyle & WS_MINIMIZE && ci->hwndActiveChild )
410 ShowWindow( hwnd, SW_SHOWMINNOACTIVE );
411 else
413 /* WS_VISIBLE is clear if a) the MDI client has
414 * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the
415 * MDICreateStruct. If so the created window is not shown nor
416 * activated.
418 int showflag=wnd->dwStyle & WS_VISIBLE;
419 /* clear visible flag, otherwise SetWindoPos32 ignores
420 * the SWP_SHOWWINDOW command.
422 wnd->dwStyle &= ~WS_VISIBLE;
423 if(showflag){
424 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE );
426 /* Set maximized state here in case hwnd didn't receive WM_SIZE
427 * during CreateWindow - bad!
430 if((wnd->dwStyle & WS_MAXIMIZE) && !ci->hwndChildMaximized )
432 ci->hwndChildMaximized = wnd->hwndSelf;
433 MDI_AugmentFrameMenu( ci, w->parent, hwnd );
434 MDI_UpdateFrameText( w->parent, ci->self, MDI_REPAINTFRAME, NULL );
436 }else
437 /* needed, harmless ? */
438 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE );
441 WIN_ReleaseWndPtr(wnd);
442 TRACE("created child - %04x\n",hwnd);
444 else
446 ci->nActiveChildren--;
447 DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
448 if( IsWindow(hwndMax) )
449 ShowWindow(hwndMax, SW_SHOWMAXIMIZED);
452 return hwnd;
455 /**********************************************************************
456 * MDI_ChildGetMinMaxInfo
458 * Note: The rule here is that client rect of the maximized MDI child
459 * is equal to the client rect of the MDI client window.
461 static void MDI_ChildGetMinMaxInfo( WND* clientWnd, HWND hwnd,
462 MINMAXINFO16* lpMinMax )
464 WND* childWnd = WIN_FindWndPtr(hwnd);
465 RECT rect = clientWnd->rectClient;
467 MapWindowPoints( clientWnd->parent->hwndSelf,
468 ((MDICLIENTINFO*)clientWnd->wExtra)->self, (LPPOINT)&rect, 2);
469 AdjustWindowRectEx( &rect, childWnd->dwStyle, 0, childWnd->dwExStyle );
471 lpMinMax->ptMaxSize.x = rect.right -= rect.left;
472 lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
474 lpMinMax->ptMaxPosition.x = rect.left;
475 lpMinMax->ptMaxPosition.y = rect.top;
477 WIN_ReleaseWndPtr(childWnd);
479 TRACE("max rect (%i,%i - %i, %i)\n",
480 rect.left,rect.top,rect.right,rect.bottom);
484 /**********************************************************************
485 * MDI_SwitchActiveChild
487 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
488 * being activated
490 static void MDI_SwitchActiveChild( HWND clientHwnd, HWND childHwnd,
491 BOOL bNextWindow )
493 WND *w = WIN_FindWndPtr(clientHwnd);
494 HWND hwndTo = 0;
495 HWND hwndPrev = 0;
496 MDICLIENTINFO *ci;
498 hwndTo = MDI_GetWindow(w, childHwnd, bNextWindow, 0);
500 ci = (MDICLIENTINFO *) w->wExtra;
502 TRACE("from %04x, to %04x\n",childHwnd,hwndTo);
504 if ( !hwndTo ) goto END; /* no window to switch to */
506 hwndPrev = ci->hwndActiveChild;
508 if ( hwndTo != hwndPrev )
510 BOOL bOptimize = 0;
512 if( ci->hwndChildMaximized )
514 bOptimize = 1;
515 w->dwStyle &= ~WS_VISIBLE;
518 SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0,
519 SWP_NOMOVE | SWP_NOSIZE );
521 if( bNextWindow && hwndPrev )
522 SetWindowPos( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0,
523 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
524 if( bOptimize )
525 ShowWindow( clientHwnd, SW_SHOW );
527 END:
528 WIN_ReleaseWndPtr(w);
532 /**********************************************************************
533 * MDIDestroyChild
535 static LRESULT MDIDestroyChild( WND *w_parent, MDICLIENTINFO *ci,
536 HWND parent, HWND child,
537 BOOL flagDestroy )
539 WND *childPtr = WIN_FindWndPtr(child);
541 if( childPtr )
543 if( child == ci->hwndActiveChild )
545 MDI_SwitchActiveChild(parent, child, TRUE);
547 if( child == ci->hwndActiveChild )
549 ShowWindow( child, SW_HIDE);
550 if( child == ci->hwndChildMaximized )
552 MDI_RestoreFrameMenu(w_parent->parent, child);
553 ci->hwndChildMaximized = 0;
554 MDI_UpdateFrameText(w_parent->parent,parent,TRUE,NULL);
557 MDI_ChildActivate(w_parent, 0);
560 MDI_MenuDeleteItem(w_parent, child);
562 WIN_ReleaseWndPtr(childPtr);
564 ci->nActiveChildren--;
566 TRACE("child destroyed - %04x\n",child);
568 if (flagDestroy)
570 MDI_PostUpdate(GetParent(child), ci, SB_BOTH+1);
571 DestroyWindow(child);
575 return 0;
579 /**********************************************************************
580 * MDI_ChildActivate
582 * Note: hWndChild is NULL when last child is being destroyed
584 static LONG MDI_ChildActivate( WND *clientPtr, HWND hWndChild )
586 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientPtr->wExtra;
587 HWND prevActiveWnd = clientInfo->hwndActiveChild;
588 WND *wndPtr = WIN_FindWndPtr( hWndChild );
589 WND *wndPrev = WIN_FindWndPtr( prevActiveWnd );
590 BOOL isActiveFrameWnd = 0;
591 LONG retvalue;
593 if( wndPtr )
595 if( wndPtr->dwStyle & WS_DISABLED )
597 retvalue = 0L;
598 goto END;
602 /* Don't activate if it is already active. Might happen
603 since ShowWindow DOES activate MDI children */
604 if (clientInfo->hwndActiveChild == hWndChild)
606 retvalue = 0L;
607 goto END;
610 TRACE("%04x\n", hWndChild);
612 if( GetActiveWindow() == clientPtr->parent->hwndSelf )
613 isActiveFrameWnd = TRUE;
615 /* deactivate prev. active child */
616 if( wndPrev )
618 wndPrev->dwStyle |= WS_SYSMENU;
619 SendMessageA( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
620 SendMessageA( prevActiveWnd, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
621 (LPARAM)hWndChild);
622 /* uncheck menu item */
623 if( clientInfo->hWindowMenu )
624 CheckMenuItem( clientInfo->hWindowMenu,
625 wndPrev->wIDmenu, 0);
628 /* set appearance */
629 if( clientInfo->hwndChildMaximized )
631 if( clientInfo->hwndChildMaximized != hWndChild ) {
632 if( hWndChild ) {
633 clientInfo->hwndActiveChild = hWndChild;
634 ShowWindow( hWndChild, SW_SHOWMAXIMIZED);
635 } else
636 ShowWindow( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
640 clientInfo->hwndActiveChild = hWndChild;
642 /* check if we have any children left */
643 if( !hWndChild )
645 if( isActiveFrameWnd )
646 SetFocus( clientInfo->self );
647 retvalue = 0;
648 goto END;
651 /* check menu item */
652 if( clientInfo->hWindowMenu )
653 CheckMenuItem( clientInfo->hWindowMenu,
654 wndPtr->wIDmenu, MF_CHECKED);
656 /* bring active child to the top */
657 SetWindowPos( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
659 if( isActiveFrameWnd )
661 SendMessageA( hWndChild, WM_NCACTIVATE, TRUE, 0L);
662 if( GetFocus() == clientInfo->self )
663 SendMessageA( clientInfo->self, WM_SETFOCUS,
664 (WPARAM)clientInfo->self, 0L );
665 else
666 SetFocus( clientInfo->self );
668 SendMessageA( hWndChild, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
669 (LPARAM)hWndChild );
670 retvalue = 1;
671 END:
672 WIN_ReleaseWndPtr(wndPtr);
673 WIN_ReleaseWndPtr(wndPrev);
674 return retvalue;
677 /* -------------------- MDI client window functions ------------------- */
679 /**********************************************************************
680 * CreateMDIMenuBitmap
682 static HBITMAP16 CreateMDIMenuBitmap(void)
684 HDC hDCSrc = CreateCompatibleDC(0);
685 HDC hDCDest = CreateCompatibleDC(hDCSrc);
686 HBITMAP16 hbClose = LoadBitmap16(0, MAKEINTRESOURCE16(OBM_CLOSE) );
687 HBITMAP16 hbCopy;
688 HANDLE16 hobjSrc, hobjDest;
690 hobjSrc = SelectObject(hDCSrc, hbClose);
691 hbCopy = CreateCompatibleBitmap(hDCSrc,GetSystemMetrics(SM_CXSIZE),GetSystemMetrics(SM_CYSIZE));
692 hobjDest = SelectObject(hDCDest, hbCopy);
694 BitBlt(hDCDest, 0, 0, GetSystemMetrics(SM_CXSIZE), GetSystemMetrics(SM_CYSIZE),
695 hDCSrc, GetSystemMetrics(SM_CXSIZE), 0, SRCCOPY);
697 SelectObject(hDCSrc, hobjSrc);
698 DeleteObject(hbClose);
699 DeleteDC(hDCSrc);
701 hobjSrc = SelectObject( hDCDest, GetStockObject(BLACK_PEN) );
703 MoveToEx( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, 0, NULL );
704 LineTo( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, GetSystemMetrics(SM_CYSIZE) - 1);
706 SelectObject(hDCDest, hobjSrc );
707 SelectObject(hDCDest, hobjDest);
708 DeleteDC(hDCDest);
710 return hbCopy;
713 /**********************************************************************
714 * MDICascade
716 static LONG MDICascade(WND* clientWnd, MDICLIENTINFO *ci)
718 WND** ppWnd;
719 UINT total;
721 if (ci->hwndChildMaximized)
722 SendMessageA( clientWnd->hwndSelf, WM_MDIRESTORE,
723 (WPARAM)ci->hwndChildMaximized, 0);
725 if (ci->nActiveChildren == 0) return 0;
727 if ((ppWnd = WIN_BuildWinArray(clientWnd, BWA_SKIPHIDDEN | BWA_SKIPOWNED |
728 BWA_SKIPICONIC, &total)))
730 WND** heapPtr = ppWnd;
731 if( total )
733 INT delta = 0, n = 0;
734 POINT pos[2];
735 if( total < ci->nActiveChildren )
736 delta = GetSystemMetrics(SM_CYICONSPACING) +
737 GetSystemMetrics(SM_CYICON);
739 /* walk the list (backwards) and move windows */
740 while (*ppWnd) ppWnd++;
741 while (ppWnd != heapPtr)
743 ppWnd--;
744 TRACE("move %04x to (%ld,%ld) size [%ld,%ld]\n",
745 (*ppWnd)->hwndSelf, pos[0].x, pos[0].y, pos[1].x, pos[1].y);
747 MDI_CalcDefaultChildPos(clientWnd, n++, pos, delta);
748 SetWindowPos( (*ppWnd)->hwndSelf, 0, pos[0].x, pos[0].y,
749 pos[1].x, pos[1].y,
750 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
753 WIN_ReleaseWinArray(heapPtr);
756 if( total < ci->nActiveChildren )
757 ArrangeIconicWindows( clientWnd->hwndSelf );
758 return 0;
761 /**********************************************************************
762 * MDITile
764 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM wParam )
766 WND** ppWnd;
767 UINT total = 0;
769 if (ci->hwndChildMaximized)
770 SendMessageA( wndClient->hwndSelf, WM_MDIRESTORE,
771 (WPARAM)ci->hwndChildMaximized, 0);
773 if (ci->nActiveChildren == 0) return;
775 ppWnd = WIN_BuildWinArray(wndClient, BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
776 ((wParam & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
778 TRACE("%u windows to tile\n", total);
780 if( ppWnd )
782 WND** heapPtr = ppWnd;
784 if( total )
786 RECT rect;
787 int x, y, xsize, ysize;
788 int rows, columns, r, c, i;
790 GetClientRect(wndClient->hwndSelf,&rect);
791 rows = (int) sqrt((double)total);
792 columns = total / rows;
794 if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */
796 i = rows;
797 rows = columns; /* exchange r and c */
798 columns = i;
801 if( total != ci->nActiveChildren)
803 y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
804 rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
807 ysize = rect.bottom / rows;
808 xsize = rect.right / columns;
810 for (x = i = 0, c = 1; c <= columns && *ppWnd; c++)
812 if (c == columns)
814 rows = total - i;
815 ysize = rect.bottom / rows;
818 y = 0;
819 for (r = 1; r <= rows && *ppWnd; r++, i++)
821 SetWindowPos((*ppWnd)->hwndSelf, 0, x, y, xsize, ysize,
822 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
823 y += ysize;
824 ppWnd++;
826 x += xsize;
829 WIN_ReleaseWinArray(heapPtr);
832 if( total < ci->nActiveChildren ) ArrangeIconicWindows( wndClient->hwndSelf );
835 /* ----------------------- Frame window ---------------------------- */
838 /**********************************************************************
839 * MDI_AugmentFrameMenu
841 static BOOL MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
842 HWND hChild )
844 WND* child = WIN_FindWndPtr(hChild);
845 HMENU hSysPopup = 0;
846 HBITMAP hSysMenuBitmap = 0;
848 TRACE("frame %p,child %04x\n",frame,hChild);
850 if( !frame->wIDmenu || !child->hSysMenu )
852 WIN_ReleaseWndPtr(child);
853 return 0;
855 WIN_ReleaseWndPtr(child);
857 /* create a copy of sysmenu popup and insert it into frame menu bar */
859 if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
860 return 0;
862 TRACE("\tgot popup %04x in sysmenu %04x\n",
863 hSysPopup, child->hSysMenu);
865 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
866 SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
867 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
868 SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
870 /* In Win 95 look, the system menu is replaced by the child icon */
872 if(TWEAK_WineLook > WIN31_LOOK)
874 HICON hIcon = GetClassLongA(hChild, GCL_HICONSM);
875 if (!hIcon)
876 hIcon = GetClassLongA(hChild, GCL_HICON);
877 if (hIcon)
879 HDC hMemDC;
880 HBITMAP hBitmap, hOldBitmap;
881 HBRUSH hBrush;
882 HDC hdc = GetDC(hChild);
884 if (hdc)
886 int cx, cy;
887 cx = GetSystemMetrics(SM_CXSMICON);
888 cy = GetSystemMetrics(SM_CYSMICON);
889 hMemDC = CreateCompatibleDC(hdc);
890 hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
891 hOldBitmap = SelectObject(hMemDC, hBitmap);
892 SetMapMode(hMemDC, MM_TEXT);
893 hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
894 DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL);
895 SelectObject (hMemDC, hOldBitmap);
896 DeleteObject(hBrush);
897 DeleteDC(hMemDC);
898 ReleaseDC(hChild, hdc);
899 hSysMenuBitmap = hBitmap;
903 else
904 hSysMenuBitmap = hBmpClose;
906 if( !InsertMenuA(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
907 hSysPopup, (LPSTR)(DWORD)hSysMenuBitmap))
909 TRACE("not inserted\n");
910 DestroyMenu(hSysPopup);
911 return 0;
914 /* The close button is only present in Win 95 look */
915 if(TWEAK_WineLook > WIN31_LOOK)
917 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
918 SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
921 EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
922 EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
923 EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
924 SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE);
926 /* redraw menu */
927 DrawMenuBar(frame->hwndSelf);
929 return 1;
932 /**********************************************************************
933 * MDI_RestoreFrameMenu
935 static BOOL MDI_RestoreFrameMenu( WND *frameWnd, HWND hChild )
937 MENUITEMINFOA menuInfo;
938 INT nItems = GetMenuItemCount(frameWnd->wIDmenu) - 1;
939 UINT iId = GetMenuItemID(frameWnd->wIDmenu,nItems) ;
941 TRACE("frameWnd %p,(%04x),child %04x,nIt=%d,iId=%d\n",
942 frameWnd,frameWnd->hwndSelf,hChild,nItems,iId);
944 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
945 return 0;
948 * Remove the system menu, If that menu is the icon of the window
949 * as it is in win95, we have to delete the bitmap.
951 menuInfo.cbSize = sizeof(MENUITEMINFOA);
952 menuInfo.fMask = MIIM_DATA | MIIM_TYPE;
954 GetMenuItemInfoA(frameWnd->wIDmenu,
956 TRUE,
957 &menuInfo);
959 RemoveMenu(frameWnd->wIDmenu,0,MF_BYPOSITION);
961 if ( (menuInfo.fType & MFT_BITMAP) &&
962 (LOWORD(menuInfo.dwTypeData)!=0) &&
963 (LOWORD(menuInfo.dwTypeData)!=hBmpClose) )
965 DeleteObject((HBITMAP)LOWORD(menuInfo.dwTypeData));
968 if(TWEAK_WineLook > WIN31_LOOK)
970 /* close */
971 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
973 /* restore */
974 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
975 /* minimize */
976 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
978 DrawMenuBar(frameWnd->hwndSelf);
980 return 1;
984 /**********************************************************************
985 * MDI_UpdateFrameText
987 * used when child window is maximized/restored
989 * Note: lpTitle can be NULL
991 static void MDI_UpdateFrameText( WND *frameWnd, HWND hClient,
992 BOOL repaint, LPCSTR lpTitle )
994 char lpBuffer[MDI_MAXTITLELENGTH+1];
995 WND* clientWnd = WIN_FindWndPtr(hClient);
996 MDICLIENTINFO *ci = (MDICLIENTINFO *) clientWnd->wExtra;
998 TRACE("repaint %i, frameText %s\n", repaint, (lpTitle)?lpTitle:"NULL");
1000 if (!clientWnd)
1001 return;
1003 if (!ci)
1005 WIN_ReleaseWndPtr(clientWnd);
1006 return;
1009 /* store new "default" title if lpTitle is not NULL */
1010 if (lpTitle)
1012 if (ci->frameTitle) HeapFree( SystemHeap, 0, ci->frameTitle );
1013 ci->frameTitle = HEAP_strdupA( SystemHeap, 0, lpTitle );
1016 if (ci->frameTitle)
1018 WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );
1020 if( childWnd && childWnd->text )
1022 /* combine frame title and child title if possible */
1024 LPCSTR lpBracket = " - [";
1025 int i_frame_text_length = strlen(ci->frameTitle);
1026 int i_child_text_length = strlen(childWnd->text);
1028 lstrcpynA( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
1030 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
1032 strcat( lpBuffer, lpBracket );
1034 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
1036 strcat( lpBuffer, childWnd->text );
1037 strcat( lpBuffer, "]" );
1039 else
1041 lstrcpynA( lpBuffer + i_frame_text_length + 4,
1042 childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
1043 strcat( lpBuffer, "]" );
1047 else
1049 lstrcpynA(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH+1 );
1051 WIN_ReleaseWndPtr(childWnd);
1054 else
1055 lpBuffer[0] = '\0';
1057 DEFWND_SetText( frameWnd, lpBuffer );
1058 if( repaint == MDI_REPAINTFRAME)
1059 SetWindowPos( frameWnd->hwndSelf, 0,0,0,0,0, SWP_FRAMECHANGED |
1060 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
1062 WIN_ReleaseWndPtr(clientWnd);
1067 /* ----------------------------- Interface ---------------------------- */
1070 /**********************************************************************
1071 * MDIClientWndProc
1073 * This function handles all MDI requests.
1075 LRESULT WINAPI MDIClientWndProc( HWND hwnd, UINT message, WPARAM wParam,
1076 LPARAM lParam )
1078 LPCREATESTRUCTA cs;
1079 MDICLIENTINFO *ci;
1080 RECT rect;
1081 WND *w, *frameWnd;
1082 INT nItems;
1083 LRESULT retvalue;
1085 if ( ( w = WIN_FindWndPtr(hwnd) ) == NULL )
1086 return 0;
1088 if ( ( frameWnd = WIN_LockWndPtr(w->parent) ) == NULL ) {
1089 WIN_ReleaseWndPtr(w);
1090 return 0;
1093 ci = (MDICLIENTINFO *) w->wExtra;
1095 switch (message)
1097 case WM_CREATE:
1099 cs = (LPCREATESTRUCTA)lParam;
1101 /* Translation layer doesn't know what's in the cs->lpCreateParams
1102 * so we have to keep track of what environment we're in. */
1104 if( w->flags & WIN_ISWIN32 )
1106 #define ccs ((LPCLIENTCREATESTRUCT)cs->lpCreateParams)
1107 ci->hWindowMenu = ccs->hWindowMenu;
1108 ci->idFirstChild = ccs->idFirstChild;
1109 #undef ccs
1111 else
1113 LPCLIENTCREATESTRUCT16 ccs = (LPCLIENTCREATESTRUCT16)
1114 PTR_SEG_TO_LIN(cs->lpCreateParams);
1115 ci->hWindowMenu = ccs->hWindowMenu;
1116 ci->idFirstChild = ccs->idFirstChild;
1119 ci->hwndChildMaximized = 0;
1120 ci->nActiveChildren = 0;
1121 ci->nTotalCreated = 0;
1122 ci->frameTitle = NULL;
1123 ci->mdiFlags = 0;
1124 ci->self = hwnd;
1125 w->dwStyle |= WS_CLIPCHILDREN;
1127 if (!hBmpClose)
1129 hBmpClose = CreateMDIMenuBitmap();
1130 hBmpRestore = LoadBitmap16( 0, MAKEINTRESOURCE16(OBM_RESTORE) );
1132 MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
1134 if (ci->hWindowMenu != 0)
1135 AppendMenuA( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
1137 GetClientRect(frameWnd->hwndSelf, &rect);
1138 NC_HandleNCCalcSize( w, &rect );
1139 w->rectClient = rect;
1141 TRACE("Client created - hwnd = %04x, idFirst = %u\n",
1142 hwnd, ci->idFirstChild );
1144 retvalue = 0;
1145 goto END;
1147 case WM_DESTROY:
1148 if( ci->hwndChildMaximized )
1149 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized);
1150 if((ci->hWindowMenu != 0) &&
1151 (nItems = GetMenuItemCount(ci->hWindowMenu)) > 0)
1153 ci->idFirstChild = nItems - 1;
1154 ci->nActiveChildren++; /* to delete a separator */
1155 while( ci->nActiveChildren-- )
1156 DeleteMenu(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
1158 retvalue = 0;
1159 goto END;
1161 case WM_MDIACTIVATE:
1162 if( ci->hwndActiveChild != (HWND)wParam )
1163 SetWindowPos((HWND)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
1164 retvalue = 0;
1165 goto END;
1167 case WM_MDICASCADE:
1168 retvalue = MDICascade(w, ci);
1169 goto END;
1171 case WM_MDICREATE:
1172 if (lParam) retvalue = MDICreateChild( w, ci, hwnd,
1173 (MDICREATESTRUCTA*)lParam );
1174 else retvalue = 0;
1175 goto END;
1177 case WM_MDIDESTROY:
1178 retvalue = MDIDestroyChild( w, ci, hwnd, (HWND)wParam, TRUE );
1179 goto END;
1181 case WM_MDIGETACTIVE:
1182 if (lParam) *(BOOL *)lParam = (ci->hwndChildMaximized > 0);
1183 retvalue = ci->hwndActiveChild;
1184 goto END;
1186 case WM_MDIICONARRANGE:
1187 ci->mdiFlags |= MDIF_NEEDUPDATE;
1188 ArrangeIconicWindows(hwnd);
1189 ci->sbRecalc = SB_BOTH+1;
1190 SendMessageA(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
1191 retvalue = 0;
1192 goto END;
1194 case WM_MDIMAXIMIZE:
1195 ShowWindow( (HWND)wParam, SW_MAXIMIZE );
1196 retvalue = 0;
1197 goto END;
1199 case WM_MDINEXT: /* lParam != 0 means previous window */
1200 MDI_SwitchActiveChild(hwnd, (HWND)wParam, (lParam)? FALSE : TRUE );
1201 break;
1203 case WM_MDIRESTORE:
1204 SendMessageA( (HWND)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
1205 retvalue = 0;
1206 goto END;
1208 case WM_MDISETMENU:
1209 retvalue = MDISetMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1210 goto END;
1211 case WM_MDIREFRESHMENU:
1212 retvalue = MDIRefreshMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1213 goto END;
1215 case WM_MDITILE:
1216 ci->mdiFlags |= MDIF_NEEDUPDATE;
1217 ShowScrollBar(hwnd,SB_BOTH,FALSE);
1218 MDITile(w, ci, wParam);
1219 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1220 retvalue = 0;
1221 goto END;
1223 case WM_VSCROLL:
1224 case WM_HSCROLL:
1225 ci->mdiFlags |= MDIF_NEEDUPDATE;
1226 ScrollChildren(hwnd, message, wParam, lParam);
1227 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1228 retvalue = 0;
1229 goto END;
1231 case WM_SETFOCUS:
1232 if( ci->hwndActiveChild )
1234 WND* pw = WIN_FindWndPtr( ci->hwndActiveChild );
1235 if( !(pw->dwStyle & WS_MINIMIZE) )
1236 SetFocus( ci->hwndActiveChild );
1237 WIN_ReleaseWndPtr(pw);
1239 retvalue = 0;
1240 goto END;
1242 case WM_NCACTIVATE:
1243 if( ci->hwndActiveChild )
1244 SendMessageA(ci->hwndActiveChild, message, wParam, lParam);
1245 break;
1247 case WM_PARENTNOTIFY:
1248 if (LOWORD(wParam) == WM_LBUTTONDOWN)
1250 POINT16 pt = MAKEPOINT16(lParam);
1251 HWND16 child = ChildWindowFromPoint16(hwnd, pt);
1253 TRACE("notification from %04x (%i,%i)\n",child,pt.x,pt.y);
1255 if( child && child != hwnd && child != ci->hwndActiveChild )
1256 SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1258 retvalue = 0;
1259 goto END;
1261 case WM_SIZE:
1262 if( IsWindow(ci->hwndChildMaximized) )
1264 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1265 RECT rect;
1267 rect.left = 0;
1268 rect.top = 0;
1269 rect.right = LOWORD(lParam);
1270 rect.bottom = HIWORD(lParam);
1272 AdjustWindowRectEx(&rect, child->dwStyle, 0, child->dwExStyle);
1273 MoveWindow(ci->hwndChildMaximized, rect.left, rect.top,
1274 rect.right - rect.left, rect.bottom - rect.top, 1);
1275 WIN_ReleaseWndPtr(child);
1277 else
1278 MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1280 break;
1282 case WM_MDICALCCHILDSCROLL:
1283 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1285 CalcChildScroll16(hwnd, ci->sbRecalc-1);
1286 ci->sbRecalc = 0;
1287 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1289 retvalue = 0;
1290 goto END;
1293 retvalue = DefWindowProcA( hwnd, message, wParam, lParam );
1294 END:
1295 WIN_ReleaseWndPtr(w);
1296 WIN_ReleaseWndPtr(frameWnd);
1297 return retvalue;
1301 /***********************************************************************
1302 * DefFrameProc16 (USER.445)
1304 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1305 UINT16 message, WPARAM16 wParam, LPARAM lParam )
1307 HWND16 childHwnd;
1308 MDICLIENTINFO* ci;
1309 WND* wndPtr;
1311 if (hwndMDIClient)
1313 switch (message)
1315 case WM_COMMAND:
1316 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1318 if (!wndPtr) {
1319 ERR("null wndPtr for mdi window hwndMDIClient=%04x\n",
1320 hwndMDIClient);
1321 return 0;
1324 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1326 /* check for possible syscommands for maximized MDI child */
1327 WIN_ReleaseWndPtr(wndPtr);
1329 if( ci && (
1330 wParam < ci->idFirstChild ||
1331 wParam >= ci->idFirstChild + ci->nActiveChildren
1333 if( (wParam - 0xF000) & 0xF00F ) break;
1334 switch( wParam )
1336 case SC_SIZE:
1337 case SC_MOVE:
1338 case SC_MINIMIZE:
1339 case SC_MAXIMIZE:
1340 case SC_NEXTWINDOW:
1341 case SC_PREVWINDOW:
1342 case SC_CLOSE:
1343 case SC_RESTORE:
1344 if( ci->hwndChildMaximized )
1345 return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1346 wParam, lParam);
1349 else
1351 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1352 childHwnd = MDI_GetChildByID(wndPtr,wParam );
1353 WIN_ReleaseWndPtr(wndPtr);
1355 if( childHwnd )
1356 SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1357 (WPARAM16)childHwnd , 0L);
1359 break;
1361 case WM_NCACTIVATE:
1362 SendMessage16(hwndMDIClient, message, wParam, lParam);
1363 break;
1365 case WM_SETTEXT:
1366 wndPtr = WIN_FindWndPtr(hwnd);
1367 MDI_UpdateFrameText(wndPtr, hwndMDIClient,
1368 MDI_REPAINTFRAME,
1369 (LPCSTR)PTR_SEG_TO_LIN(lParam));
1370 WIN_ReleaseWndPtr(wndPtr);
1371 return 0;
1373 case WM_SETFOCUS:
1374 SetFocus(hwndMDIClient);
1375 break;
1377 case WM_SIZE:
1378 MoveWindow16(hwndMDIClient, 0, 0,
1379 LOWORD(lParam), HIWORD(lParam), TRUE);
1380 break;
1382 case WM_NEXTMENU:
1384 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1385 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1387 if( !(wndPtr->parent->dwStyle & WS_MINIMIZE)
1388 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1390 /* control menu is between the frame system menu and
1391 * the first entry of menu bar */
1393 if( (wParam == VK_LEFT &&
1394 wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1395 (wParam == VK_RIGHT &&
1396 GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1398 LRESULT retvalue;
1399 WIN_ReleaseWndPtr(wndPtr);
1400 wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1401 retvalue = MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1402 ci->hwndActiveChild);
1403 WIN_ReleaseWndPtr(wndPtr);
1404 return retvalue;
1407 WIN_ReleaseWndPtr(wndPtr);
1408 break;
1412 return DefWindowProc16(hwnd, message, wParam, lParam);
1416 /***********************************************************************
1417 * DefFrameProcA (USER32.122)
1419 LRESULT WINAPI DefFrameProcA( HWND hwnd, HWND hwndMDIClient,
1420 UINT message, WPARAM wParam, LPARAM lParam)
1422 if (hwndMDIClient)
1424 switch (message)
1426 case WM_COMMAND:
1427 return DefFrameProc16( hwnd, hwndMDIClient, message,
1428 (WPARAM16)wParam,
1429 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1431 case WM_NCACTIVATE:
1432 SendMessageA(hwndMDIClient, message, wParam, lParam);
1433 break;
1435 case WM_SETTEXT: {
1436 LRESULT ret;
1437 LPSTR segstr = SEGPTR_STRDUP((LPSTR)lParam);
1439 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1440 wParam, (LPARAM)SEGPTR_GET(segstr) );
1441 SEGPTR_FREE(segstr);
1442 return ret;
1445 case WM_NEXTMENU:
1446 case WM_SETFOCUS:
1447 case WM_SIZE:
1448 return DefFrameProc16( hwnd, hwndMDIClient, message,
1449 wParam, lParam );
1453 return DefWindowProcA(hwnd, message, wParam, lParam);
1457 /***********************************************************************
1458 * DefFrameProcW (USER32.123)
1460 LRESULT WINAPI DefFrameProcW( HWND hwnd, HWND hwndMDIClient,
1461 UINT message, WPARAM wParam, LPARAM lParam)
1463 if (hwndMDIClient)
1465 switch (message)
1467 case WM_COMMAND:
1468 return DefFrameProc16( hwnd, hwndMDIClient, message,
1469 (WPARAM16)wParam,
1470 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1472 case WM_NCACTIVATE:
1473 SendMessageW(hwndMDIClient, message, wParam, lParam);
1474 break;
1476 case WM_SETTEXT:
1478 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1479 LRESULT ret = DefFrameProcA( hwnd, hwndMDIClient, message,
1480 wParam, (DWORD)txt );
1481 HeapFree(GetProcessHeap(),0,txt);
1482 return ret;
1484 case WM_NEXTMENU:
1485 case WM_SETFOCUS:
1486 case WM_SIZE:
1487 return DefFrameProcA( hwnd, hwndMDIClient, message,
1488 wParam, lParam );
1492 return DefWindowProcW( hwnd, message, wParam, lParam );
1496 /***********************************************************************
1497 * DefMDIChildProc16 (USER.447)
1499 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1500 WPARAM16 wParam, LPARAM lParam )
1502 MDICLIENTINFO *ci;
1503 WND *clientWnd,*tmpWnd = 0;
1504 LRESULT retvalue;
1506 tmpWnd = WIN_FindWndPtr(hwnd);
1507 if (!tmpWnd) return 0;
1508 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1509 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1510 WIN_ReleaseWndPtr(tmpWnd);
1512 switch (message)
1514 case WM_SETTEXT:
1515 DefWindowProc16(hwnd, message, wParam, lParam);
1516 MDI_MenuModifyItem(clientWnd,hwnd);
1517 if( ci->hwndChildMaximized == hwnd )
1518 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1519 MDI_REPAINTFRAME, NULL );
1520 retvalue = 0;
1521 goto END;
1523 case WM_CLOSE:
1524 SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1525 retvalue = 0;
1526 goto END;
1528 case WM_SETFOCUS:
1529 if( ci->hwndActiveChild != hwnd )
1530 MDI_ChildActivate(clientWnd, hwnd);
1531 break;
1533 case WM_CHILDACTIVATE:
1534 MDI_ChildActivate(clientWnd, hwnd);
1535 retvalue = 0;
1536 goto END;
1538 case WM_NCPAINT:
1539 TRACE("WM_NCPAINT for %04x, active %04x\n",
1540 hwnd, ci->hwndActiveChild );
1541 break;
1543 case WM_SYSCOMMAND:
1544 switch( wParam )
1546 case SC_MOVE:
1547 if( ci->hwndChildMaximized == hwnd)
1549 retvalue = 0;
1550 goto END;
1552 break;
1553 case SC_RESTORE:
1554 case SC_MINIMIZE:
1555 tmpWnd = WIN_FindWndPtr(hwnd);
1556 tmpWnd->dwStyle |= WS_SYSMENU;
1557 WIN_ReleaseWndPtr(tmpWnd);
1558 break;
1559 case SC_MAXIMIZE:
1560 if( ci->hwndChildMaximized == hwnd)
1562 retvalue = SendMessage16( clientWnd->parent->hwndSelf,
1563 message, wParam, lParam);
1564 goto END;
1566 tmpWnd = WIN_FindWndPtr(hwnd);
1567 tmpWnd->dwStyle &= ~WS_SYSMENU;
1568 WIN_ReleaseWndPtr(tmpWnd);
1569 break;
1570 case SC_NEXTWINDOW:
1571 SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1572 retvalue = 0;
1573 goto END;
1574 case SC_PREVWINDOW:
1575 SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1576 retvalue = 0;
1577 goto END;
1579 break;
1581 case WM_GETMINMAXINFO:
1582 MDI_ChildGetMinMaxInfo(clientWnd, hwnd, (MINMAXINFO16*) PTR_SEG_TO_LIN(lParam));
1583 retvalue = 0;
1584 goto END;
1586 case WM_SETVISIBLE:
1587 if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1588 else
1589 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1590 break;
1592 case WM_SIZE:
1593 /* do not change */
1595 if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1597 ci->hwndChildMaximized = 0;
1599 MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1600 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1601 MDI_REPAINTFRAME, NULL );
1604 if( wParam == SIZE_MAXIMIZED )
1606 HWND16 hMaxChild = ci->hwndChildMaximized;
1608 if( hMaxChild == hwnd ) break;
1610 if( hMaxChild)
1612 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1614 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1615 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1617 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1620 TRACE("maximizing child %04x\n", hwnd );
1622 ci->hwndChildMaximized = hwnd; /* !!! */
1623 ci->hwndActiveChild = hwnd;
1625 MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1626 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1627 MDI_REPAINTFRAME, NULL );
1630 if( wParam == SIZE_MINIMIZED )
1632 HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1634 if( switchTo )
1635 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1638 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1639 break;
1641 case WM_MENUCHAR:
1643 /* MDI children don't have menu bars */
1644 retvalue = 0x00010000L;
1645 goto END;
1647 case WM_NEXTMENU:
1649 if( wParam == VK_LEFT ) /* switch to frame system menu */
1651 retvalue = MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1652 clientWnd->parent->hwndSelf );
1653 goto END;
1655 if( wParam == VK_RIGHT ) /* to frame menu bar */
1657 retvalue = MAKELONG( clientWnd->parent->wIDmenu,
1658 clientWnd->parent->hwndSelf );
1659 goto END;
1662 break;
1664 case WM_SYSCHAR:
1665 if (wParam == '-')
1667 SendMessage16(hwnd,WM_SYSCOMMAND,
1668 (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1669 retvalue = 0;
1670 goto END;
1674 retvalue = DefWindowProc16(hwnd, message, wParam, lParam);
1675 END:
1676 WIN_ReleaseWndPtr(clientWnd);
1677 return retvalue;
1681 /***********************************************************************
1682 * DefMDIChildProcA (USER32.124)
1684 LRESULT WINAPI DefMDIChildProcA( HWND hwnd, UINT message,
1685 WPARAM wParam, LPARAM lParam )
1687 MDICLIENTINFO *ci;
1688 WND *clientWnd,*tmpWnd;
1689 LRESULT retvalue;
1691 tmpWnd = WIN_FindWndPtr(hwnd);
1692 if (!tmpWnd) return 0;
1693 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1694 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1695 WIN_ReleaseWndPtr(tmpWnd);
1697 switch (message)
1699 case WM_SETTEXT:
1700 DefWindowProcA(hwnd, message, wParam, lParam);
1701 MDI_MenuModifyItem(clientWnd,hwnd);
1702 if( ci->hwndChildMaximized == hwnd )
1703 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1704 MDI_REPAINTFRAME, NULL );
1705 retvalue = 0;
1706 goto END;
1708 case WM_GETMINMAXINFO:
1710 MINMAXINFO16 mmi;
1711 STRUCT32_MINMAXINFO32to16( (MINMAXINFO *)lParam, &mmi );
1712 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1713 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO *)lParam );
1715 retvalue = 0;
1716 goto END;
1718 case WM_MENUCHAR:
1720 /* MDI children don't have menu bars */
1721 retvalue = 0x00010000L;
1722 goto END;
1724 case WM_CLOSE:
1725 case WM_SETFOCUS:
1726 case WM_CHILDACTIVATE:
1727 case WM_NCPAINT:
1728 case WM_SYSCOMMAND:
1729 case WM_SETVISIBLE:
1730 case WM_SIZE:
1731 case WM_NEXTMENU:
1732 retvalue = DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1733 goto END;
1735 case WM_SYSCHAR:
1736 if (wParam == '-')
1738 SendMessageA(hwnd,WM_SYSCOMMAND,
1739 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1740 retvalue = 0;
1741 goto END;
1744 retvalue = DefWindowProcA(hwnd, message, wParam, lParam);
1745 END:
1746 WIN_ReleaseWndPtr(clientWnd);
1747 return retvalue;
1751 /***********************************************************************
1752 * DefMDIChildProcW (USER32.125)
1754 LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message,
1755 WPARAM wParam, LPARAM lParam )
1757 MDICLIENTINFO *ci;
1758 WND *clientWnd,*tmpWnd;
1759 LRESULT retvalue;
1761 tmpWnd = WIN_FindWndPtr(hwnd);
1762 if (!tmpWnd) return 0;
1763 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1764 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1765 WIN_ReleaseWndPtr(tmpWnd);
1767 switch (message)
1769 case WM_SETTEXT:
1770 DefWindowProcW(hwnd, message, wParam, lParam);
1771 MDI_MenuModifyItem(clientWnd,hwnd);
1772 if( ci->hwndChildMaximized == hwnd )
1773 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1774 MDI_REPAINTFRAME, NULL );
1775 retvalue = 0;
1776 goto END;
1778 case WM_GETMINMAXINFO:
1779 case WM_MENUCHAR:
1780 case WM_CLOSE:
1781 case WM_SETFOCUS:
1782 case WM_CHILDACTIVATE:
1783 case WM_NCPAINT:
1784 case WM_SYSCOMMAND:
1785 case WM_SETVISIBLE:
1786 case WM_SIZE:
1787 case WM_NEXTMENU:
1788 retvalue = DefMDIChildProcA( hwnd, message, (WPARAM16)wParam, lParam );
1789 goto END;
1791 case WM_SYSCHAR:
1792 if (wParam == '-')
1794 SendMessageW(hwnd,WM_SYSCOMMAND,
1795 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1796 retvalue = 0;
1797 goto END;
1800 retvalue = DefWindowProcW(hwnd, message, wParam, lParam);
1801 END:
1802 WIN_ReleaseWndPtr(clientWnd);
1803 return retvalue;
1808 /**********************************************************************
1809 * CreateMDIWindowA [USER32.79] Creates a MDI child in new thread
1810 * FIXME: its in the same thread now
1812 * RETURNS
1813 * Success: Handle to created window
1814 * Failure: NULL
1816 HWND WINAPI CreateMDIWindowA(
1817 LPCSTR lpClassName, /* [in] Pointer to registered child class name */
1818 LPCSTR lpWindowName, /* [in] Pointer to window name */
1819 DWORD dwStyle, /* [in] Window style */
1820 INT X, /* [in] Horizontal position of window */
1821 INT Y, /* [in] Vertical position of window */
1822 INT nWidth, /* [in] Width of window */
1823 INT nHeight, /* [in] Height of window */
1824 HWND hWndParent, /* [in] Handle to parent window */
1825 HINSTANCE hInstance, /* [in] Handle to application instance */
1826 LPARAM lParam) /* [in] Application-defined value */
1828 WARN("is only single threaded!\n");
1829 return MDI_CreateMDIWindowA(lpClassName, lpWindowName, dwStyle, X, Y,
1830 nWidth, nHeight, hWndParent, hInstance, lParam);
1833 /**********************************************************************
1834 * MDI_CreateMDIWindowA
1835 * single threaded version of CreateMDIWindowA
1836 * called by CreateWindowExA
1838 HWND MDI_CreateMDIWindowA(
1839 LPCSTR lpClassName,
1840 LPCSTR lpWindowName,
1841 DWORD dwStyle,
1842 INT X,
1843 INT Y,
1844 INT nWidth,
1845 INT nHeight,
1846 HWND hWndParent,
1847 HINSTANCE hInstance,
1848 LPARAM lParam)
1850 MDICLIENTINFO* pCi;
1851 MDICREATESTRUCTA cs;
1852 WND *pWnd=WIN_FindWndPtr(hWndParent);
1853 HWND retvalue;
1855 TRACE("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
1856 debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
1857 nWidth,nHeight,hWndParent,hInstance,lParam);
1859 if(!pWnd){
1860 ERR(" bad hwnd for MDI-client: %d\n",hWndParent);
1861 return 0;
1863 cs.szClass=lpClassName;
1864 cs.szTitle=lpWindowName;
1865 cs.hOwner=hInstance;
1866 cs.x=X;
1867 cs.y=Y;
1868 cs.cx=nWidth;
1869 cs.cy=nHeight;
1870 cs.style=dwStyle;
1871 cs.lParam=lParam;
1873 pCi=(MDICLIENTINFO *)pWnd->wExtra;
1875 retvalue = MDICreateChild(pWnd,pCi,hWndParent,&cs);
1876 WIN_ReleaseWndPtr(pWnd);
1877 return retvalue;
1880 /***********************************************************************
1881 * CreateMDIWindowW [USER32.80] Creates a MDI child in new thread
1883 * RETURNS
1884 * Success: Handle to created window
1885 * Failure: NULL
1887 HWND WINAPI CreateMDIWindowW(
1888 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1889 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1890 DWORD dwStyle, /* [in] Window style */
1891 INT X, /* [in] Horizontal position of window */
1892 INT Y, /* [in] Vertical position of window */
1893 INT nWidth, /* [in] Width of window */
1894 INT nHeight, /* [in] Height of window */
1895 HWND hWndParent, /* [in] Handle to parent window */
1896 HINSTANCE hInstance, /* [in] Handle to application instance */
1897 LPARAM lParam) /* [in] Application-defined value */
1899 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1900 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1901 nWidth,nHeight,hWndParent,hInstance,lParam);
1902 return (HWND)NULL;
1906 /******************************************************************************
1907 * CreateMDIWindowW [USER32.80] Creates a MDI child window
1908 * single threaded version of CreateMDIWindow
1909 * called by CreateWindowExW().
1911 HWND MDI_CreateMDIWindowW(
1912 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1913 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1914 DWORD dwStyle, /* [in] Window style */
1915 INT X, /* [in] Horizontal position of window */
1916 INT Y, /* [in] Vertical position of window */
1917 INT nWidth, /* [in] Width of window */
1918 INT nHeight, /* [in] Height of window */
1919 HWND hWndParent, /* [in] Handle to parent window */
1920 HINSTANCE hInstance, /* [in] Handle to application instance */
1921 LPARAM lParam) /* [in] Application-defined value */
1923 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1924 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1925 nWidth,nHeight,hWndParent,hInstance,lParam);
1926 return (HWND)NULL;
1930 /**********************************************************************
1931 * TranslateMDISysAccel (USER32.555)
1933 BOOL WINAPI TranslateMDISysAccel( HWND hwndClient, LPMSG msg )
1935 MSG16 msg16;
1937 STRUCT32_MSG32to16(msg,&msg16);
1938 /* MDICLIENTINFO is still the same for win32 and win16 ... */
1939 return TranslateMDISysAccel16(hwndClient,&msg16);
1943 /**********************************************************************
1944 * TranslateMDISysAccel16 (USER.451)
1946 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
1949 if( IsWindow(hwndClient) && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
1951 MDICLIENTINFO *ci = NULL;
1952 HWND wnd;
1953 WND *clientWnd = WIN_FindWndPtr(hwndClient);
1955 ci = (MDICLIENTINFO*) clientWnd->wExtra;
1956 wnd = ci->hwndActiveChild;
1958 WIN_ReleaseWndPtr(clientWnd);
1960 if( IsWindow(wnd) && !(GetWindowLongA(wnd,GWL_STYLE) & WS_DISABLED) )
1962 WPARAM16 wParam = 0;
1964 /* translate if the Ctrl key is down and Alt not. */
1966 if( (GetKeyState(VK_CONTROL) & 0x8000) &&
1967 !(GetKeyState(VK_MENU) & 0x8000))
1969 switch( msg->wParam )
1971 case VK_F6:
1972 case VK_TAB:
1973 wParam = ( GetKeyState(VK_SHIFT) & 0x8000 )
1974 ? SC_NEXTWINDOW : SC_PREVWINDOW;
1975 break;
1976 case VK_F4:
1977 case VK_RBUTTON:
1978 wParam = SC_CLOSE;
1979 break;
1980 default:
1981 return 0;
1983 TRACE("wParam = %04x\n", wParam);
1984 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
1985 wParam, (LPARAM)msg->wParam);
1986 return 1;
1990 return 0; /* failure */
1994 /***********************************************************************
1995 * CalcChildScroll (USER.462)
1997 void WINAPI CalcChildScroll16( HWND16 hwnd, WORD scroll )
1999 SCROLLINFO info;
2000 RECT childRect, clientRect;
2001 INT vmin, vmax, hmin, hmax, vpos, hpos;
2002 WND *pWnd, *Wnd;
2004 if (!(pWnd = WIN_FindWndPtr( hwnd ))) return;
2005 Wnd = WIN_FindWndPtr(hwnd);
2006 GetClientRect( hwnd, &clientRect );
2007 SetRectEmpty( &childRect );
2009 for ( WIN_UpdateWndPtr(&pWnd,pWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2011 if( pWnd->dwStyle & WS_MAXIMIZE )
2013 ShowScrollBar(hwnd, SB_BOTH, FALSE);
2014 WIN_ReleaseWndPtr(pWnd);
2015 WIN_ReleaseWndPtr(Wnd);
2016 return;
2018 UnionRect( &childRect, &pWnd->rectWindow, &childRect );
2020 WIN_ReleaseWndPtr(pWnd);
2021 UnionRect( &childRect, &clientRect, &childRect );
2023 hmin = childRect.left; hmax = childRect.right - clientRect.right;
2024 hpos = clientRect.left - childRect.left;
2025 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
2026 vpos = clientRect.top - childRect.top;
2028 switch( scroll )
2030 case SB_HORZ:
2031 vpos = hpos; vmin = hmin; vmax = hmax;
2032 case SB_VERT:
2033 info.cbSize = sizeof(info);
2034 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
2035 info.fMask = SIF_POS | SIF_RANGE;
2036 SetScrollInfo(hwnd, scroll, &info, TRUE);
2037 break;
2038 case SB_BOTH:
2039 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
2040 hmin, hmax, hpos);
2042 WIN_ReleaseWndPtr(Wnd);
2046 /***********************************************************************
2047 * ScrollChildren16 (USER.463)
2049 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
2051 ScrollChildren( hWnd, uMsg, wParam, lParam );
2055 /***********************************************************************
2056 * ScrollChildren (USER32.448)
2058 void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
2059 LPARAM lParam)
2061 WND *wndPtr = WIN_FindWndPtr(hWnd);
2062 INT newPos = -1;
2063 INT curPos, length, minPos, maxPos, shift;
2065 if( !wndPtr ) return;
2067 if( uMsg == WM_HSCROLL )
2069 GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
2070 curPos = GetScrollPos(hWnd,SB_HORZ);
2071 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
2072 shift = GetSystemMetrics(SM_CYHSCROLL);
2074 else if( uMsg == WM_VSCROLL )
2076 GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
2077 curPos = GetScrollPos(hWnd,SB_VERT);
2078 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
2079 shift = GetSystemMetrics(SM_CXVSCROLL);
2081 else
2083 WIN_ReleaseWndPtr(wndPtr);
2084 return;
2087 WIN_ReleaseWndPtr(wndPtr);
2088 switch( wParam )
2090 case SB_LINEUP:
2091 newPos = curPos - shift;
2092 break;
2093 case SB_LINEDOWN:
2094 newPos = curPos + shift;
2095 break;
2096 case SB_PAGEUP:
2097 newPos = curPos - length;
2098 break;
2099 case SB_PAGEDOWN:
2100 newPos = curPos + length;
2101 break;
2103 case SB_THUMBPOSITION:
2104 newPos = LOWORD(lParam);
2105 break;
2107 case SB_THUMBTRACK:
2108 return;
2110 case SB_TOP:
2111 newPos = minPos;
2112 break;
2113 case SB_BOTTOM:
2114 newPos = maxPos;
2115 break;
2116 case SB_ENDSCROLL:
2117 CalcChildScroll16(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
2118 return;
2121 if( newPos > maxPos )
2122 newPos = maxPos;
2123 else
2124 if( newPos < minPos )
2125 newPos = minPos;
2127 SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
2129 if( uMsg == WM_VSCROLL )
2130 ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
2131 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2132 else
2133 ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
2134 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2138 /******************************************************************************
2139 * CascadeWindows [USER32.21] Cascades MDI child windows
2141 * RETURNS
2142 * Success: Number of cascaded windows.
2143 * Failure: 0
2145 WORD WINAPI
2146 CascadeWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2147 UINT cKids, const HWND *lpKids)
2149 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2150 hwndParent, wFlags, cKids);
2152 return 0;
2156 /******************************************************************************
2157 * TileWindows [USER32.545] Tiles MDI child windows
2159 * RETURNS
2160 * Success: Number of tiled windows.
2161 * Failure: 0
2163 WORD WINAPI
2164 TileWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2165 UINT cKids, const HWND *lpKids)
2167 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2168 hwndParent, wFlags, cKids);
2170 return 0;