Fixed some issues reported by winapi_check.
[wine.git] / windows / mdi.c
blob39b696c604b2a6128d4e1189b8b753a7c51169fa
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 && hmenuFrame!=oldFrameMenu)
287 SetMenu(hwndFrame, hmenuFrame);
288 if( ci->hwndChildMaximized )
289 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
290 WIN_ReleaseWndPtr(w);
291 return oldFrameMenu;
293 WIN_ReleaseWndPtr(w);
294 return 0;
297 /**********************************************************************
298 * MDIRefreshMenu
300 static LRESULT MDIRefreshMenu( HWND hwnd, HMENU hmenuFrame,
301 HMENU hmenuWindow)
303 HWND hwndFrame = GetParent(hwnd);
304 HMENU oldFrameMenu = GetMenu(hwndFrame);
306 TRACE("%04x %04x %04x\n",
307 hwnd, hmenuFrame, hmenuWindow);
309 FIXME("partially function stub\n");
311 return oldFrameMenu;
315 /* ------------------ MDI child window functions ---------------------- */
318 /**********************************************************************
319 * MDICreateChild
321 static HWND MDICreateChild( WND *w, MDICLIENTINFO *ci, HWND parent,
322 LPMDICREATESTRUCTA cs )
324 POINT pos[2];
325 DWORD style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
326 HWND hwnd, hwndMax = 0;
327 WORD wIDmenu = ci->idFirstChild + ci->nActiveChildren;
328 char lpstrDef[]="junk!";
330 TRACE("origin %i,%i - dim %i,%i, style %08x\n",
331 cs->x, cs->y, cs->cx, cs->cy, (unsigned)cs->style);
332 /* calculate placement */
333 MDI_CalcDefaultChildPos(w, ci->nTotalCreated++, pos, 0);
335 if (cs->cx == CW_USEDEFAULT || !cs->cx) cs->cx = pos[1].x;
336 if (cs->cy == CW_USEDEFAULT || !cs->cy) cs->cy = pos[1].y;
338 if( cs->x == CW_USEDEFAULT )
340 cs->x = pos[0].x;
341 cs->y = pos[0].y;
344 /* restore current maximized child */
345 if( style & WS_VISIBLE && ci->hwndChildMaximized )
347 if( style & WS_MAXIMIZE )
348 SendMessageA(w->hwndSelf, WM_SETREDRAW, FALSE, 0L );
349 hwndMax = ci->hwndChildMaximized;
350 ShowWindow( hwndMax, SW_SHOWNOACTIVATE );
351 if( style & WS_MAXIMIZE )
352 SendMessageA(w->hwndSelf, WM_SETREDRAW, TRUE, 0L );
355 /* this menu is needed to set a check mark in MDI_ChildActivate */
356 if (ci->hWindowMenu != 0)
357 AppendMenuA(ci->hWindowMenu ,MF_STRING ,wIDmenu, lpstrDef );
359 ci->nActiveChildren++;
361 /* fix window style */
362 if( !(w->dwStyle & MDIS_ALLCHILDSTYLES) )
364 style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE |
365 WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL );
366 style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW);
369 if( w->flags & WIN_ISWIN32 )
371 hwnd = CreateWindowA( cs->szClass, cs->szTitle, style,
372 cs->x, cs->y, cs->cx, cs->cy, parent,
373 (HMENU16)wIDmenu, cs->hOwner, cs );
375 else
377 MDICREATESTRUCT16 *cs16;
378 LPSTR title, cls;
380 cs16 = SEGPTR_NEW(MDICREATESTRUCT16);
381 STRUCT32_MDICREATESTRUCT32Ato16( cs, cs16 );
382 title = SEGPTR_STRDUP( cs->szTitle );
383 cls = SEGPTR_STRDUP( cs->szClass );
384 cs16->szTitle = SEGPTR_GET(title);
385 cs16->szClass = SEGPTR_GET(cls);
387 hwnd = CreateWindow16( cs->szClass, cs->szTitle, style,
388 cs16->x, cs16->y, cs16->cx, cs16->cy, parent,
389 (HMENU)wIDmenu, cs16->hOwner,
390 (LPVOID)SEGPTR_GET(cs16) );
391 SEGPTR_FREE( title );
392 SEGPTR_FREE( cls );
393 SEGPTR_FREE( cs16 );
396 /* MDI windows are WS_CHILD so they won't be activated by CreateWindow */
398 if (hwnd)
400 WND* wnd = WIN_FindWndPtr( hwnd );
402 /* All MDI child windows have the WS_EX_MDICHILD style */
403 wnd->dwExStyle |= WS_EX_MDICHILD;
405 MDI_MenuModifyItem(w ,hwnd);
406 if( wnd->dwStyle & WS_MINIMIZE && ci->hwndActiveChild )
407 ShowWindow( hwnd, SW_SHOWMINNOACTIVE );
408 else
410 /* WS_VISIBLE is clear if a) the MDI client has
411 * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the
412 * MDICreateStruct. If so the created window is not shown nor
413 * activated.
415 int showflag=wnd->dwStyle & WS_VISIBLE;
416 /* clear visible flag, otherwise SetWindoPos32 ignores
417 * the SWP_SHOWWINDOW command.
419 wnd->dwStyle &= ~WS_VISIBLE;
420 if(showflag){
421 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE );
423 /* Set maximized state here in case hwnd didn't receive WM_SIZE
424 * during CreateWindow - bad!
427 if((wnd->dwStyle & WS_MAXIMIZE) && !ci->hwndChildMaximized )
429 ci->hwndChildMaximized = wnd->hwndSelf;
430 MDI_AugmentFrameMenu( ci, w->parent, hwnd );
431 MDI_UpdateFrameText( w->parent, ci->self, MDI_REPAINTFRAME, NULL );
433 }else
434 /* needed, harmless ? */
435 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE );
438 WIN_ReleaseWndPtr(wnd);
439 TRACE("created child - %04x\n",hwnd);
441 else
443 ci->nActiveChildren--;
444 DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
445 if( IsWindow(hwndMax) )
446 ShowWindow(hwndMax, SW_SHOWMAXIMIZED);
449 return hwnd;
452 /**********************************************************************
453 * MDI_ChildGetMinMaxInfo
455 * Note: The rule here is that client rect of the maximized MDI child
456 * is equal to the client rect of the MDI client window.
458 static void MDI_ChildGetMinMaxInfo( WND* clientWnd, HWND hwnd,
459 MINMAXINFO16* lpMinMax )
461 WND* childWnd = WIN_FindWndPtr(hwnd);
462 RECT rect = clientWnd->rectClient;
464 MapWindowPoints( clientWnd->parent->hwndSelf,
465 ((MDICLIENTINFO*)clientWnd->wExtra)->self, (LPPOINT)&rect, 2);
466 AdjustWindowRectEx( &rect, childWnd->dwStyle, 0, childWnd->dwExStyle );
468 lpMinMax->ptMaxSize.x = rect.right -= rect.left;
469 lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
471 lpMinMax->ptMaxPosition.x = rect.left;
472 lpMinMax->ptMaxPosition.y = rect.top;
474 WIN_ReleaseWndPtr(childWnd);
476 TRACE("max rect (%i,%i - %i, %i)\n",
477 rect.left,rect.top,rect.right,rect.bottom);
481 /**********************************************************************
482 * MDI_SwitchActiveChild
484 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
485 * being activated
487 static void MDI_SwitchActiveChild( HWND clientHwnd, HWND childHwnd,
488 BOOL bNextWindow )
490 WND *w = WIN_FindWndPtr(clientHwnd);
491 HWND hwndTo = 0;
492 HWND hwndPrev = 0;
493 MDICLIENTINFO *ci;
495 hwndTo = MDI_GetWindow(w, childHwnd, bNextWindow, 0);
497 ci = (MDICLIENTINFO *) w->wExtra;
499 TRACE("from %04x, to %04x\n",childHwnd,hwndTo);
501 if ( !hwndTo ) goto END; /* no window to switch to */
503 hwndPrev = ci->hwndActiveChild;
505 if ( hwndTo != hwndPrev )
507 BOOL bOptimize = 0;
509 if( ci->hwndChildMaximized )
511 bOptimize = 1;
512 w->dwStyle &= ~WS_VISIBLE;
515 SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0,
516 SWP_NOMOVE | SWP_NOSIZE );
518 if( bNextWindow && hwndPrev )
519 SetWindowPos( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0,
520 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
521 if( bOptimize )
522 ShowWindow( clientHwnd, SW_SHOW );
524 END:
525 WIN_ReleaseWndPtr(w);
529 /**********************************************************************
530 * MDIDestroyChild
532 static LRESULT MDIDestroyChild( WND *w_parent, MDICLIENTINFO *ci,
533 HWND parent, HWND child,
534 BOOL flagDestroy )
536 WND *childPtr = WIN_FindWndPtr(child);
538 if( childPtr )
540 if( child == ci->hwndActiveChild )
542 MDI_SwitchActiveChild(parent, child, TRUE);
544 if( child == ci->hwndActiveChild )
546 ShowWindow( child, SW_HIDE);
547 if( child == ci->hwndChildMaximized )
549 MDI_RestoreFrameMenu(w_parent->parent, child);
550 ci->hwndChildMaximized = 0;
551 MDI_UpdateFrameText(w_parent->parent,parent,TRUE,NULL);
554 MDI_ChildActivate(w_parent, 0);
557 MDI_MenuDeleteItem(w_parent, child);
559 WIN_ReleaseWndPtr(childPtr);
561 ci->nActiveChildren--;
563 TRACE("child destroyed - %04x\n",child);
565 if (flagDestroy)
567 MDI_PostUpdate(GetParent(child), ci, SB_BOTH+1);
568 DestroyWindow(child);
572 return 0;
576 /**********************************************************************
577 * MDI_ChildActivate
579 * Note: hWndChild is NULL when last child is being destroyed
581 static LONG MDI_ChildActivate( WND *clientPtr, HWND hWndChild )
583 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientPtr->wExtra;
584 HWND prevActiveWnd = clientInfo->hwndActiveChild;
585 WND *wndPtr = WIN_FindWndPtr( hWndChild );
586 WND *wndPrev = WIN_FindWndPtr( prevActiveWnd );
587 BOOL isActiveFrameWnd = 0;
588 LONG retvalue;
590 if( wndPtr )
592 if( wndPtr->dwStyle & WS_DISABLED )
594 retvalue = 0L;
595 goto END;
599 /* Don't activate if it is already active. Might happen
600 since ShowWindow DOES activate MDI children */
601 if (clientInfo->hwndActiveChild == hWndChild)
603 retvalue = 0L;
604 goto END;
607 TRACE("%04x\n", hWndChild);
609 if( GetActiveWindow() == clientPtr->parent->hwndSelf )
610 isActiveFrameWnd = TRUE;
612 /* deactivate prev. active child */
613 if( wndPrev )
615 wndPrev->dwStyle |= WS_SYSMENU;
616 SendMessageA( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
617 SendMessageA( prevActiveWnd, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
618 (LPARAM)hWndChild);
619 /* uncheck menu item */
620 if( clientInfo->hWindowMenu )
621 CheckMenuItem( clientInfo->hWindowMenu,
622 wndPrev->wIDmenu, 0);
625 /* set appearance */
626 if( clientInfo->hwndChildMaximized )
628 if( clientInfo->hwndChildMaximized != hWndChild ) {
629 if( hWndChild ) {
630 clientInfo->hwndActiveChild = hWndChild;
631 ShowWindow( hWndChild, SW_SHOWMAXIMIZED);
632 } else
633 ShowWindow( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
637 clientInfo->hwndActiveChild = hWndChild;
639 /* check if we have any children left */
640 if( !hWndChild )
642 if( isActiveFrameWnd )
643 SetFocus( clientInfo->self );
644 retvalue = 0;
645 goto END;
648 /* check menu item */
649 if( clientInfo->hWindowMenu )
650 CheckMenuItem( clientInfo->hWindowMenu,
651 wndPtr->wIDmenu, MF_CHECKED);
653 /* bring active child to the top */
654 SetWindowPos( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
656 if( isActiveFrameWnd )
658 SendMessageA( hWndChild, WM_NCACTIVATE, TRUE, 0L);
659 if( GetFocus() == clientInfo->self )
660 SendMessageA( clientInfo->self, WM_SETFOCUS,
661 (WPARAM)clientInfo->self, 0L );
662 else
663 SetFocus( clientInfo->self );
665 SendMessageA( hWndChild, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
666 (LPARAM)hWndChild );
667 retvalue = 1;
668 END:
669 WIN_ReleaseWndPtr(wndPtr);
670 WIN_ReleaseWndPtr(wndPrev);
671 return retvalue;
674 /* -------------------- MDI client window functions ------------------- */
676 /**********************************************************************
677 * CreateMDIMenuBitmap
679 static HBITMAP16 CreateMDIMenuBitmap(void)
681 HDC hDCSrc = CreateCompatibleDC(0);
682 HDC hDCDest = CreateCompatibleDC(hDCSrc);
683 HBITMAP16 hbClose = LoadBitmap16(0, MAKEINTRESOURCE16(OBM_CLOSE) );
684 HBITMAP16 hbCopy;
685 HANDLE16 hobjSrc, hobjDest;
687 hobjSrc = SelectObject(hDCSrc, hbClose);
688 hbCopy = CreateCompatibleBitmap(hDCSrc,GetSystemMetrics(SM_CXSIZE),GetSystemMetrics(SM_CYSIZE));
689 hobjDest = SelectObject(hDCDest, hbCopy);
691 BitBlt(hDCDest, 0, 0, GetSystemMetrics(SM_CXSIZE), GetSystemMetrics(SM_CYSIZE),
692 hDCSrc, GetSystemMetrics(SM_CXSIZE), 0, SRCCOPY);
694 SelectObject(hDCSrc, hobjSrc);
695 DeleteObject(hbClose);
696 DeleteDC(hDCSrc);
698 hobjSrc = SelectObject( hDCDest, GetStockObject(BLACK_PEN) );
700 MoveToEx( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, 0, NULL );
701 LineTo( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, GetSystemMetrics(SM_CYSIZE) - 1);
703 SelectObject(hDCDest, hobjSrc );
704 SelectObject(hDCDest, hobjDest);
705 DeleteDC(hDCDest);
707 return hbCopy;
710 /**********************************************************************
711 * MDICascade
713 static LONG MDICascade(WND* clientWnd, MDICLIENTINFO *ci)
715 WND** ppWnd;
716 UINT total;
718 if (ci->hwndChildMaximized)
719 SendMessageA( clientWnd->hwndSelf, WM_MDIRESTORE,
720 (WPARAM)ci->hwndChildMaximized, 0);
722 if (ci->nActiveChildren == 0) return 0;
724 if ((ppWnd = WIN_BuildWinArray(clientWnd, BWA_SKIPHIDDEN | BWA_SKIPOWNED |
725 BWA_SKIPICONIC, &total)))
727 WND** heapPtr = ppWnd;
728 if( total )
730 INT delta = 0, n = 0;
731 POINT pos[2];
732 if( total < ci->nActiveChildren )
733 delta = GetSystemMetrics(SM_CYICONSPACING) +
734 GetSystemMetrics(SM_CYICON);
736 /* walk the list (backwards) and move windows */
737 while (*ppWnd) ppWnd++;
738 while (ppWnd != heapPtr)
740 ppWnd--;
741 TRACE("move %04x to (%ld,%ld) size [%ld,%ld]\n",
742 (*ppWnd)->hwndSelf, pos[0].x, pos[0].y, pos[1].x, pos[1].y);
744 MDI_CalcDefaultChildPos(clientWnd, n++, pos, delta);
745 SetWindowPos( (*ppWnd)->hwndSelf, 0, pos[0].x, pos[0].y,
746 pos[1].x, pos[1].y,
747 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
750 WIN_ReleaseWinArray(heapPtr);
753 if( total < ci->nActiveChildren )
754 ArrangeIconicWindows( clientWnd->hwndSelf );
755 return 0;
758 /**********************************************************************
759 * MDITile
761 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM wParam )
763 WND** ppWnd;
764 UINT total = 0;
766 if (ci->hwndChildMaximized)
767 SendMessageA( wndClient->hwndSelf, WM_MDIRESTORE,
768 (WPARAM)ci->hwndChildMaximized, 0);
770 if (ci->nActiveChildren == 0) return;
772 ppWnd = WIN_BuildWinArray(wndClient, BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
773 ((wParam & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
775 TRACE("%u windows to tile\n", total);
777 if( ppWnd )
779 WND** heapPtr = ppWnd;
781 if( total )
783 RECT rect;
784 int x, y, xsize, ysize;
785 int rows, columns, r, c, i;
787 GetClientRect(wndClient->hwndSelf,&rect);
788 rows = (int) sqrt((double)total);
789 columns = total / rows;
791 if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */
793 i = rows;
794 rows = columns; /* exchange r and c */
795 columns = i;
798 if( total != ci->nActiveChildren)
800 y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
801 rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
804 ysize = rect.bottom / rows;
805 xsize = rect.right / columns;
807 for (x = i = 0, c = 1; c <= columns && *ppWnd; c++)
809 if (c == columns)
811 rows = total - i;
812 ysize = rect.bottom / rows;
815 y = 0;
816 for (r = 1; r <= rows && *ppWnd; r++, i++)
818 SetWindowPos((*ppWnd)->hwndSelf, 0, x, y, xsize, ysize,
819 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
820 y += ysize;
821 ppWnd++;
823 x += xsize;
826 WIN_ReleaseWinArray(heapPtr);
829 if( total < ci->nActiveChildren ) ArrangeIconicWindows( wndClient->hwndSelf );
832 /* ----------------------- Frame window ---------------------------- */
835 /**********************************************************************
836 * MDI_AugmentFrameMenu
838 static BOOL MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
839 HWND hChild )
841 WND* child = WIN_FindWndPtr(hChild);
842 HMENU hSysPopup = 0;
843 HBITMAP hSysMenuBitmap = 0;
845 TRACE("frame %p,child %04x\n",frame,hChild);
847 if( !frame->wIDmenu || !child->hSysMenu )
849 WIN_ReleaseWndPtr(child);
850 return 0;
852 WIN_ReleaseWndPtr(child);
854 /* create a copy of sysmenu popup and insert it into frame menu bar */
856 if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
857 return 0;
859 TRACE("\tgot popup %04x in sysmenu %04x\n",
860 hSysPopup, child->hSysMenu);
862 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
863 SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
864 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
865 SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
867 /* In Win 95 look, the system menu is replaced by the child icon */
869 if(TWEAK_WineLook > WIN31_LOOK)
871 HICON hIcon = GetClassLongA(hChild, GCL_HICONSM);
872 if (!hIcon)
873 hIcon = GetClassLongA(hChild, GCL_HICON);
874 if (hIcon)
876 HDC hMemDC;
877 HBITMAP hBitmap, hOldBitmap;
878 HBRUSH hBrush;
879 HDC hdc = GetDC(hChild);
881 if (hdc)
883 int cx, cy;
884 cx = GetSystemMetrics(SM_CXSMICON);
885 cy = GetSystemMetrics(SM_CYSMICON);
886 hMemDC = CreateCompatibleDC(hdc);
887 hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
888 hOldBitmap = SelectObject(hMemDC, hBitmap);
889 SetMapMode(hMemDC, MM_TEXT);
890 hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
891 DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL);
892 SelectObject (hMemDC, hOldBitmap);
893 DeleteObject(hBrush);
894 DeleteDC(hMemDC);
895 ReleaseDC(hChild, hdc);
896 hSysMenuBitmap = hBitmap;
900 else
901 hSysMenuBitmap = hBmpClose;
903 if( !InsertMenuA(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
904 hSysPopup, (LPSTR)(DWORD)hSysMenuBitmap))
906 TRACE("not inserted\n");
907 DestroyMenu(hSysPopup);
908 return 0;
911 /* The close button is only present in Win 95 look */
912 if(TWEAK_WineLook > WIN31_LOOK)
914 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
915 SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
918 EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
919 EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
920 EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
921 SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE);
923 /* redraw menu */
924 DrawMenuBar(frame->hwndSelf);
926 return 1;
929 /**********************************************************************
930 * MDI_RestoreFrameMenu
932 static BOOL MDI_RestoreFrameMenu( WND *frameWnd, HWND hChild )
934 MENUITEMINFOA menuInfo;
935 INT nItems = GetMenuItemCount(frameWnd->wIDmenu) - 1;
936 UINT iId = GetMenuItemID(frameWnd->wIDmenu,nItems) ;
938 TRACE("frameWnd %p,(%04x),child %04x,nIt=%d,iId=%d\n",
939 frameWnd,frameWnd->hwndSelf,hChild,nItems,iId);
941 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
942 return 0;
945 * Remove the system menu, If that menu is the icon of the window
946 * as it is in win95, we have to delete the bitmap.
948 menuInfo.cbSize = sizeof(MENUITEMINFOA);
949 menuInfo.fMask = MIIM_DATA | MIIM_TYPE;
951 GetMenuItemInfoA(frameWnd->wIDmenu,
953 TRUE,
954 &menuInfo);
956 RemoveMenu(frameWnd->wIDmenu,0,MF_BYPOSITION);
958 if ( (menuInfo.fType & MFT_BITMAP) &&
959 (LOWORD(menuInfo.dwTypeData)!=0) &&
960 (LOWORD(menuInfo.dwTypeData)!=hBmpClose) )
962 DeleteObject((HBITMAP)LOWORD(menuInfo.dwTypeData));
965 if(TWEAK_WineLook > WIN31_LOOK)
967 /* close */
968 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
970 /* restore */
971 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
972 /* minimize */
973 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
975 DrawMenuBar(frameWnd->hwndSelf);
977 return 1;
981 /**********************************************************************
982 * MDI_UpdateFrameText
984 * used when child window is maximized/restored
986 * Note: lpTitle can be NULL
988 static void MDI_UpdateFrameText( WND *frameWnd, HWND hClient,
989 BOOL repaint, LPCSTR lpTitle )
991 char lpBuffer[MDI_MAXTITLELENGTH+1];
992 WND* clientWnd = WIN_FindWndPtr(hClient);
993 MDICLIENTINFO *ci = (MDICLIENTINFO *) clientWnd->wExtra;
995 TRACE("repaint %i, frameText %s\n", repaint, (lpTitle)?lpTitle:"NULL");
997 if (!clientWnd)
998 return;
1000 if (!ci)
1002 WIN_ReleaseWndPtr(clientWnd);
1003 return;
1006 /* store new "default" title if lpTitle is not NULL */
1007 if (lpTitle)
1009 if (ci->frameTitle) HeapFree( SystemHeap, 0, ci->frameTitle );
1010 ci->frameTitle = HEAP_strdupA( SystemHeap, 0, lpTitle );
1013 if (ci->frameTitle)
1015 WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );
1017 if( childWnd && childWnd->text )
1019 /* combine frame title and child title if possible */
1021 LPCSTR lpBracket = " - [";
1022 int i_frame_text_length = strlen(ci->frameTitle);
1023 int i_child_text_length = strlen(childWnd->text);
1025 lstrcpynA( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
1027 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
1029 strcat( lpBuffer, lpBracket );
1031 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
1033 strcat( lpBuffer, childWnd->text );
1034 strcat( lpBuffer, "]" );
1036 else
1038 lstrcpynA( lpBuffer + i_frame_text_length + 4,
1039 childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
1040 strcat( lpBuffer, "]" );
1044 else
1046 lstrcpynA(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH+1 );
1048 WIN_ReleaseWndPtr(childWnd);
1051 else
1052 lpBuffer[0] = '\0';
1054 DEFWND_SetText( frameWnd, lpBuffer );
1055 if( repaint == MDI_REPAINTFRAME)
1056 SetWindowPos( frameWnd->hwndSelf, 0,0,0,0,0, SWP_FRAMECHANGED |
1057 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
1059 WIN_ReleaseWndPtr(clientWnd);
1064 /* ----------------------------- Interface ---------------------------- */
1067 /**********************************************************************
1068 * MDIClientWndProc
1070 * This function handles all MDI requests.
1072 LRESULT WINAPI MDIClientWndProc( HWND hwnd, UINT message, WPARAM wParam,
1073 LPARAM lParam )
1075 LPCREATESTRUCTA cs;
1076 MDICLIENTINFO *ci;
1077 RECT rect;
1078 WND *w, *frameWnd;
1079 INT nItems;
1080 LRESULT retvalue;
1082 if ( ( w = WIN_FindWndPtr(hwnd) ) == NULL )
1083 return 0;
1085 if ( ( frameWnd = WIN_LockWndPtr(w->parent) ) == NULL ) {
1086 WIN_ReleaseWndPtr(w);
1087 return 0;
1090 ci = (MDICLIENTINFO *) w->wExtra;
1092 switch (message)
1094 case WM_CREATE:
1096 cs = (LPCREATESTRUCTA)lParam;
1098 /* Translation layer doesn't know what's in the cs->lpCreateParams
1099 * so we have to keep track of what environment we're in. */
1101 if( w->flags & WIN_ISWIN32 )
1103 #define ccs ((LPCLIENTCREATESTRUCT)cs->lpCreateParams)
1104 ci->hWindowMenu = ccs->hWindowMenu;
1105 ci->idFirstChild = ccs->idFirstChild;
1106 #undef ccs
1108 else
1110 LPCLIENTCREATESTRUCT16 ccs = (LPCLIENTCREATESTRUCT16)
1111 PTR_SEG_TO_LIN(cs->lpCreateParams);
1112 ci->hWindowMenu = ccs->hWindowMenu;
1113 ci->idFirstChild = ccs->idFirstChild;
1116 ci->hwndChildMaximized = 0;
1117 ci->nActiveChildren = 0;
1118 ci->nTotalCreated = 0;
1119 ci->frameTitle = NULL;
1120 ci->mdiFlags = 0;
1121 ci->self = hwnd;
1122 w->dwStyle |= WS_CLIPCHILDREN;
1124 if (!hBmpClose)
1126 hBmpClose = CreateMDIMenuBitmap();
1127 hBmpRestore = LoadBitmap16( 0, MAKEINTRESOURCE16(OBM_RESTORE) );
1129 MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
1131 if (ci->hWindowMenu != 0)
1132 AppendMenuA( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
1134 GetClientRect(frameWnd->hwndSelf, &rect);
1135 NC_HandleNCCalcSize( w, &rect );
1136 w->rectClient = rect;
1138 TRACE("Client created - hwnd = %04x, idFirst = %u\n",
1139 hwnd, ci->idFirstChild );
1141 retvalue = 0;
1142 goto END;
1144 case WM_DESTROY:
1145 if( ci->hwndChildMaximized )
1146 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized);
1147 if((ci->hWindowMenu != 0) &&
1148 (nItems = GetMenuItemCount(ci->hWindowMenu)) > 0)
1150 ci->idFirstChild = nItems - 1;
1151 ci->nActiveChildren++; /* to delete a separator */
1152 while( ci->nActiveChildren-- )
1153 DeleteMenu(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
1155 retvalue = 0;
1156 goto END;
1158 case WM_MDIACTIVATE:
1159 if( ci->hwndActiveChild != (HWND)wParam )
1160 SetWindowPos((HWND)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
1161 retvalue = 0;
1162 goto END;
1164 case WM_MDICASCADE:
1165 retvalue = MDICascade(w, ci);
1166 goto END;
1168 case WM_MDICREATE:
1169 if (lParam) retvalue = MDICreateChild( w, ci, hwnd,
1170 (MDICREATESTRUCTA*)lParam );
1171 else retvalue = 0;
1172 goto END;
1174 case WM_MDIDESTROY:
1175 retvalue = MDIDestroyChild( w, ci, hwnd, (HWND)wParam, TRUE );
1176 goto END;
1178 case WM_MDIGETACTIVE:
1179 if (lParam) *(BOOL *)lParam = (ci->hwndChildMaximized > 0);
1180 retvalue = ci->hwndActiveChild;
1181 goto END;
1183 case WM_MDIICONARRANGE:
1184 ci->mdiFlags |= MDIF_NEEDUPDATE;
1185 ArrangeIconicWindows(hwnd);
1186 ci->sbRecalc = SB_BOTH+1;
1187 SendMessageA(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
1188 retvalue = 0;
1189 goto END;
1191 case WM_MDIMAXIMIZE:
1192 ShowWindow( (HWND)wParam, SW_MAXIMIZE );
1193 retvalue = 0;
1194 goto END;
1196 case WM_MDINEXT: /* lParam != 0 means previous window */
1197 MDI_SwitchActiveChild(hwnd, (HWND)wParam, (lParam)? FALSE : TRUE );
1198 break;
1200 case WM_MDIRESTORE:
1201 SendMessageA( (HWND)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
1202 retvalue = 0;
1203 goto END;
1205 case WM_MDISETMENU:
1206 retvalue = MDISetMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1207 goto END;
1208 case WM_MDIREFRESHMENU:
1209 retvalue = MDIRefreshMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1210 goto END;
1212 case WM_MDITILE:
1213 ci->mdiFlags |= MDIF_NEEDUPDATE;
1214 ShowScrollBar(hwnd,SB_BOTH,FALSE);
1215 MDITile(w, ci, wParam);
1216 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1217 retvalue = 0;
1218 goto END;
1220 case WM_VSCROLL:
1221 case WM_HSCROLL:
1222 ci->mdiFlags |= MDIF_NEEDUPDATE;
1223 ScrollChildren(hwnd, message, wParam, lParam);
1224 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1225 retvalue = 0;
1226 goto END;
1228 case WM_SETFOCUS:
1229 if( ci->hwndActiveChild )
1231 WND* pw = WIN_FindWndPtr( ci->hwndActiveChild );
1232 if( !(pw->dwStyle & WS_MINIMIZE) )
1233 SetFocus( ci->hwndActiveChild );
1234 WIN_ReleaseWndPtr(pw);
1236 retvalue = 0;
1237 goto END;
1239 case WM_NCACTIVATE:
1240 if( ci->hwndActiveChild )
1241 SendMessageA(ci->hwndActiveChild, message, wParam, lParam);
1242 break;
1244 case WM_PARENTNOTIFY:
1245 if (LOWORD(wParam) == WM_LBUTTONDOWN)
1247 POINT16 pt = MAKEPOINT16(lParam);
1248 HWND16 child = ChildWindowFromPoint16(hwnd, pt);
1250 TRACE("notification from %04x (%i,%i)\n",child,pt.x,pt.y);
1252 if( child && child != hwnd && child != ci->hwndActiveChild )
1253 SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1255 retvalue = 0;
1256 goto END;
1258 case WM_SIZE:
1259 if( IsWindow(ci->hwndChildMaximized) )
1261 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1262 RECT rect;
1264 rect.left = 0;
1265 rect.top = 0;
1266 rect.right = LOWORD(lParam);
1267 rect.bottom = HIWORD(lParam);
1269 AdjustWindowRectEx(&rect, child->dwStyle, 0, child->dwExStyle);
1270 MoveWindow(ci->hwndChildMaximized, rect.left, rect.top,
1271 rect.right - rect.left, rect.bottom - rect.top, 1);
1272 WIN_ReleaseWndPtr(child);
1274 else
1275 MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1277 break;
1279 case WM_MDICALCCHILDSCROLL:
1280 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1282 CalcChildScroll16(hwnd, ci->sbRecalc-1);
1283 ci->sbRecalc = 0;
1284 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1286 retvalue = 0;
1287 goto END;
1290 retvalue = DefWindowProcA( hwnd, message, wParam, lParam );
1291 END:
1292 WIN_ReleaseWndPtr(w);
1293 WIN_ReleaseWndPtr(frameWnd);
1294 return retvalue;
1298 /***********************************************************************
1299 * DefFrameProc16 (USER.445)
1301 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1302 UINT16 message, WPARAM16 wParam, LPARAM lParam )
1304 HWND16 childHwnd;
1305 MDICLIENTINFO* ci;
1306 WND* wndPtr;
1308 if (hwndMDIClient)
1310 switch (message)
1312 case WM_COMMAND:
1313 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1315 if (!wndPtr) {
1316 ERR("null wndPtr for mdi window hwndMDIClient=%04x\n",
1317 hwndMDIClient);
1318 return 0;
1321 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1323 /* check for possible syscommands for maximized MDI child */
1324 WIN_ReleaseWndPtr(wndPtr);
1326 if( ci && (
1327 wParam < ci->idFirstChild ||
1328 wParam >= ci->idFirstChild + ci->nActiveChildren
1330 if( (wParam - 0xF000) & 0xF00F ) break;
1331 switch( wParam )
1333 case SC_SIZE:
1334 case SC_MOVE:
1335 case SC_MINIMIZE:
1336 case SC_MAXIMIZE:
1337 case SC_NEXTWINDOW:
1338 case SC_PREVWINDOW:
1339 case SC_CLOSE:
1340 case SC_RESTORE:
1341 if( ci->hwndChildMaximized )
1342 return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1343 wParam, lParam);
1346 else
1348 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1349 childHwnd = MDI_GetChildByID(wndPtr,wParam );
1350 WIN_ReleaseWndPtr(wndPtr);
1352 if( childHwnd )
1353 SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1354 (WPARAM16)childHwnd , 0L);
1356 break;
1358 case WM_NCACTIVATE:
1359 SendMessage16(hwndMDIClient, message, wParam, lParam);
1360 break;
1362 case WM_SETTEXT:
1363 wndPtr = WIN_FindWndPtr(hwnd);
1364 MDI_UpdateFrameText(wndPtr, hwndMDIClient,
1365 MDI_REPAINTFRAME,
1366 (LPCSTR)PTR_SEG_TO_LIN(lParam));
1367 WIN_ReleaseWndPtr(wndPtr);
1368 return 0;
1370 case WM_SETFOCUS:
1371 SetFocus(hwndMDIClient);
1372 break;
1374 case WM_SIZE:
1375 MoveWindow16(hwndMDIClient, 0, 0,
1376 LOWORD(lParam), HIWORD(lParam), TRUE);
1377 break;
1379 case WM_NEXTMENU:
1381 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1382 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1384 if( !(wndPtr->parent->dwStyle & WS_MINIMIZE)
1385 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1387 /* control menu is between the frame system menu and
1388 * the first entry of menu bar */
1390 if( (wParam == VK_LEFT &&
1391 wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1392 (wParam == VK_RIGHT &&
1393 GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1395 LRESULT retvalue;
1396 WIN_ReleaseWndPtr(wndPtr);
1397 wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1398 retvalue = MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1399 ci->hwndActiveChild);
1400 WIN_ReleaseWndPtr(wndPtr);
1401 return retvalue;
1404 WIN_ReleaseWndPtr(wndPtr);
1405 break;
1409 return DefWindowProc16(hwnd, message, wParam, lParam);
1413 /***********************************************************************
1414 * DefFrameProcA (USER32.122)
1416 LRESULT WINAPI DefFrameProcA( HWND hwnd, HWND hwndMDIClient,
1417 UINT message, WPARAM wParam, LPARAM lParam)
1419 if (hwndMDIClient)
1421 switch (message)
1423 case WM_COMMAND:
1424 return DefFrameProc16( hwnd, hwndMDIClient, message,
1425 (WPARAM16)wParam,
1426 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1428 case WM_NCACTIVATE:
1429 SendMessageA(hwndMDIClient, message, wParam, lParam);
1430 break;
1432 case WM_SETTEXT: {
1433 LRESULT ret;
1434 LPSTR segstr = SEGPTR_STRDUP((LPSTR)lParam);
1436 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1437 wParam, (LPARAM)SEGPTR_GET(segstr) );
1438 SEGPTR_FREE(segstr);
1439 return ret;
1442 case WM_NEXTMENU:
1443 case WM_SETFOCUS:
1444 case WM_SIZE:
1445 return DefFrameProc16( hwnd, hwndMDIClient, message,
1446 wParam, lParam );
1450 return DefWindowProcA(hwnd, message, wParam, lParam);
1454 /***********************************************************************
1455 * DefFrameProcW (USER32.123)
1457 LRESULT WINAPI DefFrameProcW( HWND hwnd, HWND hwndMDIClient,
1458 UINT message, WPARAM wParam, LPARAM lParam)
1460 if (hwndMDIClient)
1462 switch (message)
1464 case WM_COMMAND:
1465 return DefFrameProc16( hwnd, hwndMDIClient, message,
1466 (WPARAM16)wParam,
1467 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1469 case WM_NCACTIVATE:
1470 SendMessageW(hwndMDIClient, message, wParam, lParam);
1471 break;
1473 case WM_SETTEXT:
1475 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1476 LRESULT ret = DefFrameProcA( hwnd, hwndMDIClient, message,
1477 wParam, (DWORD)txt );
1478 HeapFree(GetProcessHeap(),0,txt);
1479 return ret;
1481 case WM_NEXTMENU:
1482 case WM_SETFOCUS:
1483 case WM_SIZE:
1484 return DefFrameProcA( hwnd, hwndMDIClient, message,
1485 wParam, lParam );
1489 return DefWindowProcW( hwnd, message, wParam, lParam );
1493 /***********************************************************************
1494 * DefMDIChildProc16 (USER.447)
1496 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1497 WPARAM16 wParam, LPARAM lParam )
1499 MDICLIENTINFO *ci;
1500 WND *clientWnd,*tmpWnd = 0;
1501 LRESULT retvalue;
1503 tmpWnd = WIN_FindWndPtr(hwnd);
1504 if (!tmpWnd) return 0;
1505 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1506 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1507 WIN_ReleaseWndPtr(tmpWnd);
1509 switch (message)
1511 case WM_SETTEXT:
1512 DefWindowProc16(hwnd, message, wParam, lParam);
1513 MDI_MenuModifyItem(clientWnd,hwnd);
1514 if( ci->hwndChildMaximized == hwnd )
1515 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1516 MDI_REPAINTFRAME, NULL );
1517 retvalue = 0;
1518 goto END;
1520 case WM_CLOSE:
1521 SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1522 retvalue = 0;
1523 goto END;
1525 case WM_SETFOCUS:
1526 if( ci->hwndActiveChild != hwnd )
1527 MDI_ChildActivate(clientWnd, hwnd);
1528 break;
1530 case WM_CHILDACTIVATE:
1531 MDI_ChildActivate(clientWnd, hwnd);
1532 retvalue = 0;
1533 goto END;
1535 case WM_NCPAINT:
1536 TRACE("WM_NCPAINT for %04x, active %04x\n",
1537 hwnd, ci->hwndActiveChild );
1538 break;
1540 case WM_SYSCOMMAND:
1541 switch( wParam )
1543 case SC_MOVE:
1544 if( ci->hwndChildMaximized == hwnd)
1546 retvalue = 0;
1547 goto END;
1549 break;
1550 case SC_RESTORE:
1551 case SC_MINIMIZE:
1552 tmpWnd = WIN_FindWndPtr(hwnd);
1553 tmpWnd->dwStyle |= WS_SYSMENU;
1554 WIN_ReleaseWndPtr(tmpWnd);
1555 break;
1556 case SC_MAXIMIZE:
1557 if( ci->hwndChildMaximized == hwnd)
1559 retvalue = SendMessage16( clientWnd->parent->hwndSelf,
1560 message, wParam, lParam);
1561 goto END;
1563 tmpWnd = WIN_FindWndPtr(hwnd);
1564 tmpWnd->dwStyle &= ~WS_SYSMENU;
1565 WIN_ReleaseWndPtr(tmpWnd);
1566 break;
1567 case SC_NEXTWINDOW:
1568 SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1569 retvalue = 0;
1570 goto END;
1571 case SC_PREVWINDOW:
1572 SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1573 retvalue = 0;
1574 goto END;
1576 break;
1578 case WM_GETMINMAXINFO:
1579 MDI_ChildGetMinMaxInfo(clientWnd, hwnd, (MINMAXINFO16*) PTR_SEG_TO_LIN(lParam));
1580 retvalue = 0;
1581 goto END;
1583 case WM_SETVISIBLE:
1584 if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1585 else
1586 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1587 break;
1589 case WM_SIZE:
1590 /* do not change */
1592 if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1594 ci->hwndChildMaximized = 0;
1596 MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1597 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1598 MDI_REPAINTFRAME, NULL );
1601 if( wParam == SIZE_MAXIMIZED )
1603 HWND16 hMaxChild = ci->hwndChildMaximized;
1605 if( hMaxChild == hwnd ) break;
1607 if( hMaxChild)
1609 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1611 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1612 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1614 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1617 TRACE("maximizing child %04x\n", hwnd );
1619 ci->hwndChildMaximized = hwnd; /* !!! */
1620 ci->hwndActiveChild = hwnd;
1622 MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1623 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1624 MDI_REPAINTFRAME, NULL );
1627 if( wParam == SIZE_MINIMIZED )
1629 HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1631 if( switchTo )
1632 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1635 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1636 break;
1638 case WM_MENUCHAR:
1640 /* MDI children don't have menu bars */
1641 retvalue = 0x00010000L;
1642 goto END;
1644 case WM_NEXTMENU:
1646 if( wParam == VK_LEFT ) /* switch to frame system menu */
1648 retvalue = MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1649 clientWnd->parent->hwndSelf );
1650 goto END;
1652 if( wParam == VK_RIGHT ) /* to frame menu bar */
1654 retvalue = MAKELONG( clientWnd->parent->wIDmenu,
1655 clientWnd->parent->hwndSelf );
1656 goto END;
1659 break;
1661 case WM_SYSCHAR:
1662 if (wParam == '-')
1664 SendMessage16(hwnd,WM_SYSCOMMAND,
1665 (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1666 retvalue = 0;
1667 goto END;
1671 retvalue = DefWindowProc16(hwnd, message, wParam, lParam);
1672 END:
1673 WIN_ReleaseWndPtr(clientWnd);
1674 return retvalue;
1678 /***********************************************************************
1679 * DefMDIChildProcA (USER32.124)
1681 LRESULT WINAPI DefMDIChildProcA( HWND hwnd, UINT message,
1682 WPARAM wParam, LPARAM lParam )
1684 MDICLIENTINFO *ci;
1685 WND *clientWnd,*tmpWnd;
1686 LRESULT retvalue;
1688 tmpWnd = WIN_FindWndPtr(hwnd);
1689 if (!tmpWnd) return 0;
1690 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1691 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1692 WIN_ReleaseWndPtr(tmpWnd);
1694 switch (message)
1696 case WM_SETTEXT:
1697 DefWindowProcA(hwnd, message, wParam, lParam);
1698 MDI_MenuModifyItem(clientWnd,hwnd);
1699 if( ci->hwndChildMaximized == hwnd )
1700 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1701 MDI_REPAINTFRAME, NULL );
1702 retvalue = 0;
1703 goto END;
1705 case WM_GETMINMAXINFO:
1707 MINMAXINFO16 mmi;
1708 STRUCT32_MINMAXINFO32to16( (MINMAXINFO *)lParam, &mmi );
1709 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1710 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO *)lParam );
1712 retvalue = 0;
1713 goto END;
1715 case WM_MENUCHAR:
1717 /* MDI children don't have menu bars */
1718 retvalue = 0x00010000L;
1719 goto END;
1721 case WM_CLOSE:
1722 case WM_SETFOCUS:
1723 case WM_CHILDACTIVATE:
1724 case WM_NCPAINT:
1725 case WM_SYSCOMMAND:
1726 case WM_SETVISIBLE:
1727 case WM_SIZE:
1728 case WM_NEXTMENU:
1729 retvalue = DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1730 goto END;
1732 case WM_SYSCHAR:
1733 if (wParam == '-')
1735 SendMessageA(hwnd,WM_SYSCOMMAND,
1736 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1737 retvalue = 0;
1738 goto END;
1741 retvalue = DefWindowProcA(hwnd, message, wParam, lParam);
1742 END:
1743 WIN_ReleaseWndPtr(clientWnd);
1744 return retvalue;
1748 /***********************************************************************
1749 * DefMDIChildProcW (USER32.125)
1751 LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message,
1752 WPARAM wParam, LPARAM lParam )
1754 MDICLIENTINFO *ci;
1755 WND *clientWnd,*tmpWnd;
1756 LRESULT retvalue;
1758 tmpWnd = WIN_FindWndPtr(hwnd);
1759 if (!tmpWnd) return 0;
1760 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1761 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1762 WIN_ReleaseWndPtr(tmpWnd);
1764 switch (message)
1766 case WM_SETTEXT:
1767 DefWindowProcW(hwnd, message, wParam, lParam);
1768 MDI_MenuModifyItem(clientWnd,hwnd);
1769 if( ci->hwndChildMaximized == hwnd )
1770 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1771 MDI_REPAINTFRAME, NULL );
1772 retvalue = 0;
1773 goto END;
1775 case WM_GETMINMAXINFO:
1776 case WM_MENUCHAR:
1777 case WM_CLOSE:
1778 case WM_SETFOCUS:
1779 case WM_CHILDACTIVATE:
1780 case WM_NCPAINT:
1781 case WM_SYSCOMMAND:
1782 case WM_SETVISIBLE:
1783 case WM_SIZE:
1784 case WM_NEXTMENU:
1785 retvalue = DefMDIChildProcA( hwnd, message, (WPARAM16)wParam, lParam );
1786 goto END;
1788 case WM_SYSCHAR:
1789 if (wParam == '-')
1791 SendMessageW(hwnd,WM_SYSCOMMAND,
1792 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1793 retvalue = 0;
1794 goto END;
1797 retvalue = DefWindowProcW(hwnd, message, wParam, lParam);
1798 END:
1799 WIN_ReleaseWndPtr(clientWnd);
1800 return retvalue;
1805 /**********************************************************************
1806 * CreateMDIWindowA [USER32.79] Creates a MDI child in new thread
1807 * FIXME: its in the same thread now
1809 * RETURNS
1810 * Success: Handle to created window
1811 * Failure: NULL
1813 HWND WINAPI CreateMDIWindowA(
1814 LPCSTR lpClassName, /* [in] Pointer to registered child class name */
1815 LPCSTR lpWindowName, /* [in] Pointer to window name */
1816 DWORD dwStyle, /* [in] Window style */
1817 INT X, /* [in] Horizontal position of window */
1818 INT Y, /* [in] Vertical position of window */
1819 INT nWidth, /* [in] Width of window */
1820 INT nHeight, /* [in] Height of window */
1821 HWND hWndParent, /* [in] Handle to parent window */
1822 HINSTANCE hInstance, /* [in] Handle to application instance */
1823 LPARAM lParam) /* [in] Application-defined value */
1825 WARN("is only single threaded!\n");
1826 return MDI_CreateMDIWindowA(lpClassName, lpWindowName, dwStyle, X, Y,
1827 nWidth, nHeight, hWndParent, hInstance, lParam);
1830 /**********************************************************************
1831 * MDI_CreateMDIWindowA
1832 * single threaded version of CreateMDIWindowA
1833 * called by CreateWindowExA
1835 HWND MDI_CreateMDIWindowA(
1836 LPCSTR lpClassName,
1837 LPCSTR lpWindowName,
1838 DWORD dwStyle,
1839 INT X,
1840 INT Y,
1841 INT nWidth,
1842 INT nHeight,
1843 HWND hWndParent,
1844 HINSTANCE hInstance,
1845 LPARAM lParam)
1847 MDICLIENTINFO* pCi;
1848 MDICREATESTRUCTA cs;
1849 WND *pWnd=WIN_FindWndPtr(hWndParent);
1850 HWND retvalue;
1852 TRACE("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
1853 debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
1854 nWidth,nHeight,hWndParent,hInstance,lParam);
1856 if(!pWnd){
1857 ERR(" bad hwnd for MDI-client: %d\n",hWndParent);
1858 return 0;
1860 cs.szClass=lpClassName;
1861 cs.szTitle=lpWindowName;
1862 cs.hOwner=hInstance;
1863 cs.x=X;
1864 cs.y=Y;
1865 cs.cx=nWidth;
1866 cs.cy=nHeight;
1867 cs.style=dwStyle;
1868 cs.lParam=lParam;
1870 pCi=(MDICLIENTINFO *)pWnd->wExtra;
1872 retvalue = MDICreateChild(pWnd,pCi,hWndParent,&cs);
1873 WIN_ReleaseWndPtr(pWnd);
1874 return retvalue;
1877 /***********************************************************************
1878 * CreateMDIWindowW [USER32.80] Creates a MDI child in new thread
1880 * RETURNS
1881 * Success: Handle to created window
1882 * Failure: NULL
1884 HWND WINAPI CreateMDIWindowW(
1885 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1886 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1887 DWORD dwStyle, /* [in] Window style */
1888 INT X, /* [in] Horizontal position of window */
1889 INT Y, /* [in] Vertical position of window */
1890 INT nWidth, /* [in] Width of window */
1891 INT nHeight, /* [in] Height of window */
1892 HWND hWndParent, /* [in] Handle to parent window */
1893 HINSTANCE hInstance, /* [in] Handle to application instance */
1894 LPARAM lParam) /* [in] Application-defined value */
1896 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1897 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1898 nWidth,nHeight,hWndParent,hInstance,lParam);
1899 return (HWND)NULL;
1903 /******************************************************************************
1904 * CreateMDIWindowW [USER32.80] Creates a MDI child window
1905 * single threaded version of CreateMDIWindow
1906 * called by CreateWindowExW().
1908 HWND MDI_CreateMDIWindowW(
1909 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1910 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1911 DWORD dwStyle, /* [in] Window style */
1912 INT X, /* [in] Horizontal position of window */
1913 INT Y, /* [in] Vertical position of window */
1914 INT nWidth, /* [in] Width of window */
1915 INT nHeight, /* [in] Height of window */
1916 HWND hWndParent, /* [in] Handle to parent window */
1917 HINSTANCE hInstance, /* [in] Handle to application instance */
1918 LPARAM lParam) /* [in] Application-defined value */
1920 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1921 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1922 nWidth,nHeight,hWndParent,hInstance,lParam);
1923 return (HWND)NULL;
1927 /**********************************************************************
1928 * TranslateMDISysAccel (USER32.555)
1930 BOOL WINAPI TranslateMDISysAccel( HWND hwndClient, LPMSG msg )
1932 MSG16 msg16;
1934 STRUCT32_MSG32to16(msg,&msg16);
1935 /* MDICLIENTINFO is still the same for win32 and win16 ... */
1936 return TranslateMDISysAccel16(hwndClient,&msg16);
1940 /**********************************************************************
1941 * TranslateMDISysAccel16 (USER.451)
1943 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
1946 if( IsWindow(hwndClient) && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
1948 MDICLIENTINFO *ci = NULL;
1949 HWND wnd;
1950 WND *clientWnd = WIN_FindWndPtr(hwndClient);
1952 ci = (MDICLIENTINFO*) clientWnd->wExtra;
1953 wnd = ci->hwndActiveChild;
1955 WIN_ReleaseWndPtr(clientWnd);
1957 if( IsWindow(wnd) && !(GetWindowLongA(wnd,GWL_STYLE) & WS_DISABLED) )
1959 WPARAM16 wParam = 0;
1961 /* translate if the Ctrl key is down and Alt not. */
1963 if( (GetKeyState(VK_CONTROL) & 0x8000) &&
1964 !(GetKeyState(VK_MENU) & 0x8000))
1966 switch( msg->wParam )
1968 case VK_F6:
1969 case VK_TAB:
1970 wParam = ( GetKeyState(VK_SHIFT) & 0x8000 )
1971 ? SC_NEXTWINDOW : SC_PREVWINDOW;
1972 break;
1973 case VK_F4:
1974 case VK_RBUTTON:
1975 wParam = SC_CLOSE;
1976 break;
1977 default:
1978 return 0;
1980 TRACE("wParam = %04x\n", wParam);
1981 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
1982 wParam, (LPARAM)msg->wParam);
1983 return 1;
1987 return 0; /* failure */
1991 /***********************************************************************
1992 * CalcChildScroll (USER.462)
1994 void WINAPI CalcChildScroll16( HWND16 hwnd, WORD scroll )
1996 SCROLLINFO info;
1997 RECT childRect, clientRect;
1998 INT vmin, vmax, hmin, hmax, vpos, hpos;
1999 WND *pWnd, *Wnd;
2001 if (!(pWnd = WIN_FindWndPtr( hwnd ))) return;
2002 Wnd = WIN_FindWndPtr(hwnd);
2003 GetClientRect( hwnd, &clientRect );
2004 SetRectEmpty( &childRect );
2006 for ( WIN_UpdateWndPtr(&pWnd,pWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2008 if( pWnd->dwStyle & WS_MAXIMIZE )
2010 ShowScrollBar(hwnd, SB_BOTH, FALSE);
2011 WIN_ReleaseWndPtr(pWnd);
2012 WIN_ReleaseWndPtr(Wnd);
2013 return;
2015 UnionRect( &childRect, &pWnd->rectWindow, &childRect );
2017 WIN_ReleaseWndPtr(pWnd);
2018 UnionRect( &childRect, &clientRect, &childRect );
2020 hmin = childRect.left; hmax = childRect.right - clientRect.right;
2021 hpos = clientRect.left - childRect.left;
2022 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
2023 vpos = clientRect.top - childRect.top;
2025 switch( scroll )
2027 case SB_HORZ:
2028 vpos = hpos; vmin = hmin; vmax = hmax;
2029 case SB_VERT:
2030 info.cbSize = sizeof(info);
2031 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
2032 info.fMask = SIF_POS | SIF_RANGE;
2033 SetScrollInfo(hwnd, scroll, &info, TRUE);
2034 break;
2035 case SB_BOTH:
2036 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
2037 hmin, hmax, hpos);
2039 WIN_ReleaseWndPtr(Wnd);
2043 /***********************************************************************
2044 * ScrollChildren16 (USER.463)
2046 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
2048 ScrollChildren( hWnd, uMsg, wParam, lParam );
2052 /***********************************************************************
2053 * ScrollChildren (USER32.448)
2055 void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
2056 LPARAM lParam)
2058 WND *wndPtr = WIN_FindWndPtr(hWnd);
2059 INT newPos = -1;
2060 INT curPos, length, minPos, maxPos, shift;
2062 if( !wndPtr ) return;
2064 if( uMsg == WM_HSCROLL )
2066 GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
2067 curPos = GetScrollPos(hWnd,SB_HORZ);
2068 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
2069 shift = GetSystemMetrics(SM_CYHSCROLL);
2071 else if( uMsg == WM_VSCROLL )
2073 GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
2074 curPos = GetScrollPos(hWnd,SB_VERT);
2075 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
2076 shift = GetSystemMetrics(SM_CXVSCROLL);
2078 else
2080 WIN_ReleaseWndPtr(wndPtr);
2081 return;
2084 WIN_ReleaseWndPtr(wndPtr);
2085 switch( wParam )
2087 case SB_LINEUP:
2088 newPos = curPos - shift;
2089 break;
2090 case SB_LINEDOWN:
2091 newPos = curPos + shift;
2092 break;
2093 case SB_PAGEUP:
2094 newPos = curPos - length;
2095 break;
2096 case SB_PAGEDOWN:
2097 newPos = curPos + length;
2098 break;
2100 case SB_THUMBPOSITION:
2101 newPos = LOWORD(lParam);
2102 break;
2104 case SB_THUMBTRACK:
2105 return;
2107 case SB_TOP:
2108 newPos = minPos;
2109 break;
2110 case SB_BOTTOM:
2111 newPos = maxPos;
2112 break;
2113 case SB_ENDSCROLL:
2114 CalcChildScroll16(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
2115 return;
2118 if( newPos > maxPos )
2119 newPos = maxPos;
2120 else
2121 if( newPos < minPos )
2122 newPos = minPos;
2124 SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
2126 if( uMsg == WM_VSCROLL )
2127 ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
2128 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2129 else
2130 ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
2131 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2135 /******************************************************************************
2136 * CascadeWindows [USER32.21] Cascades MDI child windows
2138 * RETURNS
2139 * Success: Number of cascaded windows.
2140 * Failure: 0
2142 WORD WINAPI
2143 CascadeWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2144 UINT cKids, const HWND *lpKids)
2146 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2147 hwndParent, wFlags, cKids);
2149 return 0;
2153 /******************************************************************************
2154 * TileWindows [USER32.545] Tiles MDI child windows
2156 * RETURNS
2157 * Success: Number of tiled windows.
2158 * Failure: 0
2160 WORD WINAPI
2161 TileWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2162 UINT cKids, const HWND *lpKids)
2164 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2165 hwndParent, wFlags, cKids);
2167 return 0;