Rewrote PSDRV_SetDeviceClipping to use GetRegionData API.
[wine.git] / windows / mdi.c
blob6cfe2bdd917ebd22dfaa37effb30f8daa86bf1eb
1 /* MDI.C
3 * Copyright 1994, Bob Amstadt
4 * 1995,1996 Alex Korobka
6 * This file contains routines to support MDI features.
8 * Notes: Fairly complete implementation. Any volunteers for
9 * "More windows..." stuff?
11 * Also, Excel and WinWord do _not_ use MDI so if you're trying
12 * to fix them look elsewhere.
15 #include <stdlib.h>
16 #include <string.h>
17 #include <math.h>
18 #include "winuser.h"
19 #include "win.h"
20 #include "heap.h"
21 #include "nonclient.h"
22 #include "mdi.h"
23 #include "user.h"
24 #include "menu.h"
25 #include "resource.h"
26 #include "scroll.h"
27 #include "struct32.h"
28 #include "tweak.h"
29 #include "debugtools.h"
31 DEFAULT_DEBUG_CHANNEL(mdi)
33 #define MDIF_NEEDUPDATE 0x0001
35 static HBITMAP16 hBmpClose = 0;
36 static HBITMAP16 hBmpRestore = 0;
38 /* ----------------- declarations ----------------- */
39 static void MDI_UpdateFrameText(WND *, HWND, BOOL, LPCSTR);
40 static BOOL MDI_AugmentFrameMenu(MDICLIENTINFO*, WND *, HWND);
41 static BOOL MDI_RestoreFrameMenu(WND *, HWND);
43 static LONG MDI_ChildActivate( WND*, HWND );
45 /* -------- Miscellaneous service functions ----------
47 * MDI_GetChildByID
50 static HWND MDI_GetChildByID(WND* wndPtr, INT id)
52 for (wndPtr = wndPtr->child; wndPtr; wndPtr = wndPtr->next)
53 if (wndPtr->wIDmenu == id) return wndPtr->hwndSelf;
54 return 0;
57 static void MDI_PostUpdate(HWND hwnd, MDICLIENTINFO* ci, WORD recalc)
59 if( !(ci->mdiFlags & MDIF_NEEDUPDATE) )
61 ci->mdiFlags |= MDIF_NEEDUPDATE;
62 PostMessageA( hwnd, WM_MDICALCCHILDSCROLL, 0, 0);
64 ci->sbRecalc = recalc;
67 /**********************************************************************
68 * MDI_MenuModifyItem
70 static BOOL MDI_MenuModifyItem(WND* clientWnd, HWND hWndChild )
72 char buffer[128];
73 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
74 WND *wndPtr = WIN_FindWndPtr(hWndChild);
75 UINT n = sprintf(buffer, "%d ",
76 wndPtr->wIDmenu - clientInfo->idFirstChild + 1);
77 BOOL bRet = 0;
79 if( !clientInfo->hWindowMenu )
81 bRet = FALSE;
82 goto END;
85 if (wndPtr->text) lstrcpynA(buffer + n, wndPtr->text, sizeof(buffer) - n );
87 n = GetMenuState(clientInfo->hWindowMenu,wndPtr->wIDmenu ,MF_BYCOMMAND);
88 bRet = ModifyMenuA(clientInfo->hWindowMenu , wndPtr->wIDmenu,
89 MF_BYCOMMAND | MF_STRING, wndPtr->wIDmenu, buffer );
90 CheckMenuItem(clientInfo->hWindowMenu ,wndPtr->wIDmenu , n & MF_CHECKED);
91 END:
92 WIN_ReleaseWndPtr(wndPtr);
93 return bRet;
96 /**********************************************************************
97 * MDI_MenuDeleteItem
99 static BOOL MDI_MenuDeleteItem(WND* clientWnd, HWND hWndChild )
101 char buffer[128];
102 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
103 WND *wndPtr = WIN_FindWndPtr(hWndChild);
104 UINT index = 0,id,n;
105 BOOL retvalue;
107 if( !clientInfo->nActiveChildren ||
108 !clientInfo->hWindowMenu )
110 retvalue = FALSE;
111 goto END;
114 id = wndPtr->wIDmenu;
115 DeleteMenu(clientInfo->hWindowMenu,id,MF_BYCOMMAND);
117 /* walk the rest of MDI children to prevent gaps in the id
118 * sequence and in the menu child list */
120 for( index = id+1; index <= clientInfo->nActiveChildren +
121 clientInfo->idFirstChild; index++ )
123 WND *tmpWnd = WIN_FindWndPtr(MDI_GetChildByID(clientWnd,index));
124 if( !tmpWnd )
126 TRACE("no window for id=%i\n",index);
127 WIN_ReleaseWndPtr(tmpWnd);
128 continue;
131 /* set correct id */
132 tmpWnd->wIDmenu--;
134 n = sprintf(buffer, "%d ",index - clientInfo->idFirstChild);
135 if (tmpWnd->text)
136 lstrcpynA(buffer + n, tmpWnd->text, sizeof(buffer) - n );
138 /* change menu */
139 ModifyMenuA(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING,
140 index - 1 , buffer );
141 WIN_ReleaseWndPtr(tmpWnd);
143 retvalue = TRUE;
144 END:
145 WIN_ReleaseWndPtr(wndPtr);
146 return retvalue;
149 /**********************************************************************
150 * MDI_GetWindow
152 * returns "activateable" child different from the current or zero
154 static HWND MDI_GetWindow(WND *clientWnd, HWND hWnd, BOOL bNext,
155 DWORD dwStyleMask )
157 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
158 WND *wndPtr, *pWnd, *pWndLast = NULL;
160 dwStyleMask |= WS_DISABLED | WS_VISIBLE;
161 if( !hWnd ) hWnd = clientInfo->hwndActiveChild;
163 if( !(wndPtr = WIN_FindWndPtr(hWnd)) ) return 0;
165 for ( pWnd = WIN_LockWndPtr(wndPtr->next); ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
167 if (!pWnd ) WIN_UpdateWndPtr(&pWnd,wndPtr->parent->child);
169 if ( pWnd == wndPtr ) break; /* went full circle */
171 if (!pWnd->owner && (pWnd->dwStyle & dwStyleMask) == WS_VISIBLE )
173 pWndLast = pWnd;
174 if ( bNext ) break;
177 WIN_ReleaseWndPtr(wndPtr);
178 WIN_ReleaseWndPtr(pWnd);
179 return pWndLast ? pWndLast->hwndSelf : 0;
182 /**********************************************************************
183 * MDI_CalcDefaultChildPos
185 * It seems that the default height is about 2/3 of the client rect
187 static void MDI_CalcDefaultChildPos( WND* w, WORD n, LPPOINT lpPos,
188 INT delta)
190 INT nstagger;
191 RECT rect = w->rectClient;
192 INT spacing = GetSystemMetrics(SM_CYCAPTION) +
193 GetSystemMetrics(SM_CYFRAME) - 1;
195 if( rect.bottom - rect.top - delta >= spacing )
196 rect.bottom -= delta;
198 nstagger = (rect.bottom - rect.top)/(3 * spacing);
199 lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
200 lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
201 lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
204 /**********************************************************************
205 * MDISetMenu
207 static LRESULT MDISetMenu( HWND hwnd, HMENU hmenuFrame,
208 HMENU hmenuWindow)
210 WND *w = WIN_FindWndPtr(hwnd);
211 MDICLIENTINFO *ci;
212 HWND hwndFrame = GetParent(hwnd);
213 HMENU oldFrameMenu = GetMenu(hwndFrame);
215 TRACE("%04x %04x %04x\n",
216 hwnd, hmenuFrame, hmenuWindow);
218 ci = (MDICLIENTINFO *) w->wExtra;
220 if( ci->hwndChildMaximized && hmenuFrame && hmenuFrame!=oldFrameMenu )
221 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized );
223 if( hmenuWindow && hmenuWindow!=ci->hWindowMenu )
225 /* delete menu items from ci->hWindowMenu
226 * and add them to hmenuWindow */
228 INT i = GetMenuItemCount(ci->hWindowMenu) - 1;
229 INT pos = GetMenuItemCount(hmenuWindow) + 1;
231 AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL);
233 if( ci->nActiveChildren )
235 INT j = i - ci->nActiveChildren + 1;
236 char buffer[100];
237 UINT id,state;
239 for( ; i >= j ; i-- )
241 id = GetMenuItemID(ci->hWindowMenu,i );
242 state = GetMenuState(ci->hWindowMenu,i,MF_BYPOSITION);
244 GetMenuStringA(ci->hWindowMenu, i, buffer, 100, MF_BYPOSITION);
246 DeleteMenu(ci->hWindowMenu, i , MF_BYPOSITION);
247 InsertMenuA(hmenuWindow, pos, MF_BYPOSITION | MF_STRING,
248 id, buffer);
249 CheckMenuItem(hmenuWindow ,pos , MF_BYPOSITION | (state & MF_CHECKED));
253 /* remove separator */
254 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
256 ci->hWindowMenu = hmenuWindow;
259 if( hmenuFrame && hmenuFrame!=oldFrameMenu)
261 SetMenu(hwndFrame, hmenuFrame);
262 if( ci->hwndChildMaximized )
263 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
264 WIN_ReleaseWndPtr(w);
265 return oldFrameMenu;
267 WIN_ReleaseWndPtr(w);
268 return 0;
271 /**********************************************************************
272 * MDIRefreshMenu
274 static LRESULT MDIRefreshMenu( HWND hwnd, HMENU hmenuFrame,
275 HMENU hmenuWindow)
277 HWND hwndFrame = GetParent(hwnd);
278 HMENU oldFrameMenu = GetMenu(hwndFrame);
280 TRACE("%04x %04x %04x\n",
281 hwnd, hmenuFrame, hmenuWindow);
283 FIXME("partially function stub\n");
285 return oldFrameMenu;
289 /* ------------------ MDI child window functions ---------------------- */
292 /**********************************************************************
293 * MDICreateChild
295 static HWND MDICreateChild( WND *w, MDICLIENTINFO *ci, HWND parent,
296 LPMDICREATESTRUCTA cs )
298 POINT pos[2];
299 DWORD style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
300 HWND hwnd, hwndMax = 0;
301 WORD wIDmenu = ci->idFirstChild + ci->nActiveChildren;
302 char lpstrDef[]="junk!";
304 TRACE("origin %i,%i - dim %i,%i, style %08x\n",
305 cs->x, cs->y, cs->cx, cs->cy, (unsigned)cs->style);
306 /* calculate placement */
307 MDI_CalcDefaultChildPos(w, ci->nTotalCreated++, pos, 0);
309 if (cs->cx == CW_USEDEFAULT || !cs->cx) cs->cx = pos[1].x;
310 if (cs->cy == CW_USEDEFAULT || !cs->cy) cs->cy = pos[1].y;
312 if( cs->x == CW_USEDEFAULT )
314 cs->x = pos[0].x;
315 cs->y = pos[0].y;
318 /* restore current maximized child */
319 if( style & WS_VISIBLE && ci->hwndChildMaximized )
321 if( style & WS_MAXIMIZE )
322 SendMessageA(w->hwndSelf, WM_SETREDRAW, FALSE, 0L );
323 hwndMax = ci->hwndChildMaximized;
324 ShowWindow( hwndMax, SW_SHOWNOACTIVATE );
325 if( style & WS_MAXIMIZE )
326 SendMessageA(w->hwndSelf, WM_SETREDRAW, TRUE, 0L );
329 /* this menu is needed to set a check mark in MDI_ChildActivate */
330 AppendMenuA(ci->hWindowMenu ,MF_STRING ,wIDmenu, lpstrDef );
332 ci->nActiveChildren++;
334 /* fix window style */
335 if( !(w->dwStyle & MDIS_ALLCHILDSTYLES) )
337 style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE |
338 WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL );
339 style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW);
342 if( w->flags & WIN_ISWIN32 )
344 hwnd = CreateWindowA( cs->szClass, cs->szTitle, style,
345 cs->x, cs->y, cs->cx, cs->cy, parent,
346 (HMENU16)wIDmenu, cs->hOwner, cs );
348 else
350 MDICREATESTRUCT16 *cs16;
351 LPSTR title, cls;
353 cs16 = SEGPTR_NEW(MDICREATESTRUCT16);
354 STRUCT32_MDICREATESTRUCT32Ato16( cs, cs16 );
355 title = SEGPTR_STRDUP( cs->szTitle );
356 cls = SEGPTR_STRDUP( cs->szClass );
357 cs16->szTitle = SEGPTR_GET(title);
358 cs16->szClass = SEGPTR_GET(cls);
360 hwnd = CreateWindow16( cs->szClass, cs->szTitle, style,
361 cs16->x, cs16->y, cs16->cx, cs16->cy, parent,
362 (HMENU)wIDmenu, cs16->hOwner,
363 (LPVOID)SEGPTR_GET(cs16) );
364 SEGPTR_FREE( title );
365 SEGPTR_FREE( cls );
366 SEGPTR_FREE( cs16 );
369 /* MDI windows are WS_CHILD so they won't be activated by CreateWindow */
371 if (hwnd)
373 WND* wnd = WIN_FindWndPtr( hwnd );
375 MDI_MenuModifyItem(w ,hwnd);
376 if( wnd->dwStyle & WS_MINIMIZE && ci->hwndActiveChild )
377 ShowWindow( hwnd, SW_SHOWMINNOACTIVE );
378 else
380 /* WS_VISIBLE is clear if a) the MDI client has
381 * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the
382 * MDICreateStruct. If so the created window is not shown nor
383 * activated.
385 int showflag=wnd->dwStyle & WS_VISIBLE;
386 /* clear visible flag, otherwise SetWindoPos32 ignores
387 * the SWP_SHOWWINDOW command.
389 wnd->dwStyle &= ~WS_VISIBLE;
390 if(showflag){
391 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE );
393 /* Set maximized state here in case hwnd didn't receive WM_SIZE
394 * during CreateWindow - bad!
397 if((wnd->dwStyle & WS_MAXIMIZE) && !ci->hwndChildMaximized )
399 ci->hwndChildMaximized = wnd->hwndSelf;
400 MDI_AugmentFrameMenu( ci, w->parent, hwnd );
401 MDI_UpdateFrameText( w->parent, ci->self, MDI_REPAINTFRAME, NULL );
403 }else
404 /* needed, harmless ? */
405 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE );
408 WIN_ReleaseWndPtr(wnd);
409 TRACE("created child - %04x\n",hwnd);
411 else
413 ci->nActiveChildren--;
414 DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
415 if( IsWindow(hwndMax) )
416 ShowWindow(hwndMax, SW_SHOWMAXIMIZED);
419 return hwnd;
422 /**********************************************************************
423 * MDI_ChildGetMinMaxInfo
425 * Note: The rule here is that client rect of the maximized MDI child
426 * is equal to the client rect of the MDI client window.
428 static void MDI_ChildGetMinMaxInfo( WND* clientWnd, HWND hwnd,
429 MINMAXINFO16* lpMinMax )
431 WND* childWnd = WIN_FindWndPtr(hwnd);
432 RECT rect = clientWnd->rectClient;
434 MapWindowPoints( clientWnd->parent->hwndSelf,
435 ((MDICLIENTINFO*)clientWnd->wExtra)->self, (LPPOINT)&rect, 2);
436 AdjustWindowRectEx( &rect, childWnd->dwStyle, 0, childWnd->dwExStyle );
438 lpMinMax->ptMaxSize.x = rect.right -= rect.left;
439 lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
441 lpMinMax->ptMaxPosition.x = rect.left;
442 lpMinMax->ptMaxPosition.y = rect.top;
444 WIN_ReleaseWndPtr(childWnd);
446 TRACE("max rect (%i,%i - %i, %i)\n",
447 rect.left,rect.top,rect.right,rect.bottom);
451 /**********************************************************************
452 * MDI_SwitchActiveChild
454 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
455 * being activated
457 static void MDI_SwitchActiveChild( HWND clientHwnd, HWND childHwnd,
458 BOOL bNextWindow )
460 WND *w = WIN_FindWndPtr(clientHwnd);
461 HWND hwndTo = 0;
462 HWND hwndPrev = 0;
463 MDICLIENTINFO *ci;
465 hwndTo = MDI_GetWindow(w, childHwnd, bNextWindow, 0);
467 ci = (MDICLIENTINFO *) w->wExtra;
469 TRACE("from %04x, to %04x\n",childHwnd,hwndTo);
471 if ( !hwndTo ) goto END; /* no window to switch to */
473 hwndPrev = ci->hwndActiveChild;
475 if ( hwndTo != hwndPrev )
477 BOOL bOptimize = 0;
479 if( ci->hwndChildMaximized )
481 bOptimize = 1;
482 w->dwStyle &= ~WS_VISIBLE;
485 SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0,
486 SWP_NOMOVE | SWP_NOSIZE );
488 if( bNextWindow && hwndPrev )
489 SetWindowPos( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0,
490 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
491 if( bOptimize )
492 ShowWindow( clientHwnd, SW_SHOW );
494 END:
495 WIN_ReleaseWndPtr(w);
499 /**********************************************************************
500 * MDIDestroyChild
502 static LRESULT MDIDestroyChild( WND *w_parent, MDICLIENTINFO *ci,
503 HWND parent, HWND child,
504 BOOL flagDestroy )
506 WND *childPtr = WIN_FindWndPtr(child);
508 if( childPtr )
510 if( child == ci->hwndActiveChild )
512 MDI_SwitchActiveChild(parent, child, TRUE);
514 if( child == ci->hwndActiveChild )
516 ShowWindow( child, SW_HIDE);
517 if( child == ci->hwndChildMaximized )
519 MDI_RestoreFrameMenu(w_parent->parent, child);
520 ci->hwndChildMaximized = 0;
521 MDI_UpdateFrameText(w_parent->parent,parent,TRUE,NULL);
524 MDI_ChildActivate(w_parent, 0);
527 MDI_MenuDeleteItem(w_parent, child);
529 WIN_ReleaseWndPtr(childPtr);
531 ci->nActiveChildren--;
533 TRACE("child destroyed - %04x\n",child);
535 if (flagDestroy)
537 MDI_PostUpdate(GetParent(child), ci, SB_BOTH+1);
538 DestroyWindow(child);
542 return 0;
546 /**********************************************************************
547 * MDI_ChildActivate
549 * Note: hWndChild is NULL when last child is being destroyed
551 static LONG MDI_ChildActivate( WND *clientPtr, HWND hWndChild )
553 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientPtr->wExtra;
554 HWND prevActiveWnd = clientInfo->hwndActiveChild;
555 WND *wndPtr = WIN_FindWndPtr( hWndChild );
556 WND *wndPrev = WIN_FindWndPtr( prevActiveWnd );
557 BOOL isActiveFrameWnd = 0;
558 LONG retvalue;
560 if( hWndChild == prevActiveWnd )
562 retvalue = 0L;
563 goto END;
566 if( wndPtr )
568 if( wndPtr->dwStyle & WS_DISABLED )
570 retvalue = 0L;
571 goto END;
575 TRACE("%04x\n", hWndChild);
577 if( GetActiveWindow() == clientPtr->parent->hwndSelf )
578 isActiveFrameWnd = TRUE;
580 /* deactivate prev. active child */
581 if( wndPrev )
583 wndPrev->dwStyle |= WS_SYSMENU;
584 SendMessageA( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
585 SendMessageA( prevActiveWnd, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
586 (LPARAM)hWndChild);
587 /* uncheck menu item */
588 if( clientInfo->hWindowMenu )
589 CheckMenuItem( clientInfo->hWindowMenu,
590 wndPrev->wIDmenu, 0);
593 /* set appearance */
594 if( clientInfo->hwndChildMaximized )
596 if( clientInfo->hwndChildMaximized != hWndChild ) {
597 if( hWndChild ) {
598 clientInfo->hwndActiveChild = hWndChild;
599 ShowWindow( hWndChild, SW_SHOWMAXIMIZED);
600 } else
601 ShowWindow( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
605 clientInfo->hwndActiveChild = hWndChild;
607 /* check if we have any children left */
608 if( !hWndChild )
610 if( isActiveFrameWnd )
611 SetFocus( clientInfo->self );
612 retvalue = 0;
613 goto END;
616 /* check menu item */
617 if( clientInfo->hWindowMenu )
618 CheckMenuItem( clientInfo->hWindowMenu,
619 wndPtr->wIDmenu, MF_CHECKED);
621 /* bring active child to the top */
622 SetWindowPos( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
624 if( isActiveFrameWnd )
626 SendMessageA( hWndChild, WM_NCACTIVATE, TRUE, 0L);
627 if( GetFocus() == clientInfo->self )
628 SendMessageA( clientInfo->self, WM_SETFOCUS,
629 (WPARAM)clientInfo->self, 0L );
630 else
631 SetFocus( clientInfo->self );
633 SendMessageA( hWndChild, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
634 (LPARAM)hWndChild );
635 retvalue = 1;
636 END:
637 WIN_ReleaseWndPtr(wndPtr);
638 WIN_ReleaseWndPtr(wndPrev);
639 return retvalue;
642 /* -------------------- MDI client window functions ------------------- */
644 /**********************************************************************
645 * CreateMDIMenuBitmap
647 static HBITMAP16 CreateMDIMenuBitmap(void)
649 HDC hDCSrc = CreateCompatibleDC(0);
650 HDC hDCDest = CreateCompatibleDC(hDCSrc);
651 HBITMAP16 hbClose = LoadBitmap16(0, MAKEINTRESOURCE16(OBM_CLOSE) );
652 HBITMAP16 hbCopy;
653 HANDLE16 hobjSrc, hobjDest;
655 hobjSrc = SelectObject(hDCSrc, hbClose);
656 hbCopy = CreateCompatibleBitmap(hDCSrc,GetSystemMetrics(SM_CXSIZE),GetSystemMetrics(SM_CYSIZE));
657 hobjDest = SelectObject(hDCDest, hbCopy);
659 BitBlt(hDCDest, 0, 0, GetSystemMetrics(SM_CXSIZE), GetSystemMetrics(SM_CYSIZE),
660 hDCSrc, GetSystemMetrics(SM_CXSIZE), 0, SRCCOPY);
662 SelectObject(hDCSrc, hobjSrc);
663 DeleteObject(hbClose);
664 DeleteDC(hDCSrc);
666 hobjSrc = SelectObject( hDCDest, GetStockObject(BLACK_PEN) );
668 MoveToEx( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, 0, NULL );
669 LineTo( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, GetSystemMetrics(SM_CYSIZE) - 1);
671 SelectObject(hDCDest, hobjSrc );
672 SelectObject(hDCDest, hobjDest);
673 DeleteDC(hDCDest);
675 return hbCopy;
678 /**********************************************************************
679 * MDICascade
681 static LONG MDICascade(WND* clientWnd, MDICLIENTINFO *ci)
683 WND** ppWnd;
684 UINT total;
686 if (ci->hwndChildMaximized)
687 SendMessageA( clientWnd->hwndSelf, WM_MDIRESTORE,
688 (WPARAM)ci->hwndChildMaximized, 0);
690 if (ci->nActiveChildren == 0) return 0;
692 if ((ppWnd = WIN_BuildWinArray(clientWnd, BWA_SKIPHIDDEN | BWA_SKIPOWNED |
693 BWA_SKIPICONIC, &total)))
695 WND** heapPtr = ppWnd;
696 if( total )
698 INT delta = 0, n = 0;
699 POINT pos[2];
700 if( total < ci->nActiveChildren )
701 delta = GetSystemMetrics(SM_CYICONSPACING) +
702 GetSystemMetrics(SM_CYICON);
704 /* walk the list (backwards) and move windows */
705 while (*ppWnd) ppWnd++;
706 while (ppWnd != heapPtr)
708 ppWnd--;
709 TRACE("move %04x to (%ld,%ld) size [%ld,%ld]\n",
710 (*ppWnd)->hwndSelf, pos[0].x, pos[0].y, pos[1].x, pos[1].y);
712 MDI_CalcDefaultChildPos(clientWnd, n++, pos, delta);
713 SetWindowPos( (*ppWnd)->hwndSelf, 0, pos[0].x, pos[0].y,
714 pos[1].x, pos[1].y,
715 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
718 WIN_ReleaseWinArray(heapPtr);
721 if( total < ci->nActiveChildren )
722 ArrangeIconicWindows( clientWnd->hwndSelf );
723 return 0;
726 /**********************************************************************
727 * MDITile
729 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM wParam )
731 WND** ppWnd;
732 UINT total = 0;
734 if (ci->hwndChildMaximized)
735 SendMessageA( wndClient->hwndSelf, WM_MDIRESTORE,
736 (WPARAM)ci->hwndChildMaximized, 0);
738 if (ci->nActiveChildren == 0) return;
740 ppWnd = WIN_BuildWinArray(wndClient, BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
741 ((wParam & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
743 TRACE("%u windows to tile\n", total);
745 if( ppWnd )
747 WND** heapPtr = ppWnd;
749 if( total )
751 RECT rect;
752 int x, y, xsize, ysize;
753 int rows, columns, r, c, i;
755 GetClientRect(wndClient->hwndSelf,&rect);
756 rows = (int) sqrt((double)total);
757 columns = total / rows;
759 if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */
761 i = rows;
762 rows = columns; /* exchange r and c */
763 columns = i;
766 if( total != ci->nActiveChildren)
768 y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
769 rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
772 ysize = rect.bottom / rows;
773 xsize = rect.right / columns;
775 for (x = i = 0, c = 1; c <= columns && *ppWnd; c++)
777 if (c == columns)
779 rows = total - i;
780 ysize = rect.bottom / rows;
783 y = 0;
784 for (r = 1; r <= rows && *ppWnd; r++, i++)
786 SetWindowPos((*ppWnd)->hwndSelf, 0, x, y, xsize, ysize,
787 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
788 y += ysize;
789 ppWnd++;
791 x += xsize;
794 WIN_ReleaseWinArray(heapPtr);
797 if( total < ci->nActiveChildren ) ArrangeIconicWindows( wndClient->hwndSelf );
800 /* ----------------------- Frame window ---------------------------- */
803 /**********************************************************************
804 * MDI_AugmentFrameMenu
806 static BOOL MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
807 HWND hChild )
809 WND* child = WIN_FindWndPtr(hChild);
810 HMENU hSysPopup = 0;
811 HBITMAP hSysMenuBitmap = 0;
813 TRACE("frame %p,child %04x\n",frame,hChild);
815 if( !frame->wIDmenu || !child->hSysMenu )
817 WIN_ReleaseWndPtr(child);
818 return 0;
820 WIN_ReleaseWndPtr(child);
822 /* create a copy of sysmenu popup and insert it into frame menu bar */
824 if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
825 return 0;
827 TRACE("\tgot popup %04x in sysmenu %04x\n",
828 hSysPopup, child->hSysMenu);
830 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
831 SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
832 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
833 SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
835 /* In Win 95 look, the system menu is replaced by the child icon */
837 if(TWEAK_WineLook > WIN31_LOOK)
839 HICON hIcon = GetClassLongA(hChild, GCL_HICONSM);
840 if (!hIcon)
841 hIcon = GetClassLongA(hChild, GCL_HICON);
842 if (hIcon)
844 HDC hMemDC;
845 HBITMAP hBitmap, hOldBitmap;
846 HBRUSH hBrush;
847 HDC hdc = GetDC(hChild);
849 if (hdc)
851 int cx, cy;
852 cx = GetSystemMetrics(SM_CXSMICON);
853 cy = GetSystemMetrics(SM_CYSMICON);
854 hMemDC = CreateCompatibleDC(hdc);
855 hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
856 hOldBitmap = SelectObject(hMemDC, hBitmap);
857 SetMapMode(hMemDC, MM_TEXT);
858 hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
859 DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL);
860 SelectObject (hMemDC, hOldBitmap);
861 DeleteObject(hBrush);
862 DeleteDC(hMemDC);
863 ReleaseDC(hChild, hdc);
864 hSysMenuBitmap = hBitmap;
868 else
869 hSysMenuBitmap = hBmpClose;
871 if( !InsertMenuA(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
872 hSysPopup, (LPSTR)(DWORD)hSysMenuBitmap))
874 TRACE("not inserted\n");
875 DestroyMenu(hSysPopup);
876 return 0;
879 /* The close button is only present in Win 95 look */
880 if(TWEAK_WineLook > WIN31_LOOK)
882 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
883 SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
886 EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
887 EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
888 EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
889 SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE);
891 /* redraw menu */
892 DrawMenuBar(frame->hwndSelf);
894 return 1;
897 /**********************************************************************
898 * MDI_RestoreFrameMenu
900 static BOOL MDI_RestoreFrameMenu( WND *frameWnd, HWND hChild )
902 INT nItems = GetMenuItemCount(frameWnd->wIDmenu) - 1;
903 UINT iId = GetMenuItemID(frameWnd->wIDmenu,nItems) ;
905 TRACE("frameWnd %p,child %04x\n",frameWnd,hChild);
907 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
908 return 0;
910 /* app button */
911 RemoveMenu(frameWnd->wIDmenu,0,MF_BYPOSITION);
913 if(TWEAK_WineLook > WIN31_LOOK)
915 /* close */
916 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
918 /* restore */
919 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
920 /* minimize */
921 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
923 DrawMenuBar(frameWnd->hwndSelf);
925 return 1;
929 /**********************************************************************
930 * MDI_UpdateFrameText
932 * used when child window is maximized/restored
934 * Note: lpTitle can be NULL
936 static void MDI_UpdateFrameText( WND *frameWnd, HWND hClient,
937 BOOL repaint, LPCSTR lpTitle )
939 char lpBuffer[MDI_MAXTITLELENGTH+1];
940 WND* clientWnd = WIN_FindWndPtr(hClient);
941 MDICLIENTINFO *ci = (MDICLIENTINFO *) clientWnd->wExtra;
943 TRACE("repaint %i, frameText %s\n", repaint, (lpTitle)?lpTitle:"NULL");
945 if (!clientWnd)
946 return;
948 if (!ci)
950 WIN_ReleaseWndPtr(clientWnd);
951 return;
954 /* store new "default" title if lpTitle is not NULL */
955 if (lpTitle)
957 if (ci->frameTitle) HeapFree( SystemHeap, 0, ci->frameTitle );
958 ci->frameTitle = HEAP_strdupA( SystemHeap, 0, lpTitle );
961 if (ci->frameTitle)
963 WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );
965 if( childWnd && childWnd->text )
967 /* combine frame title and child title if possible */
969 LPCSTR lpBracket = " - [";
970 int i_frame_text_length = strlen(ci->frameTitle);
971 int i_child_text_length = strlen(childWnd->text);
973 lstrcpynA( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
975 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
977 strcat( lpBuffer, lpBracket );
979 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
981 strcat( lpBuffer, childWnd->text );
982 strcat( lpBuffer, "]" );
984 else
986 lstrcpynA( lpBuffer + i_frame_text_length + 4,
987 childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
988 strcat( lpBuffer, "]" );
992 else
994 strncpy(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH );
995 lpBuffer[MDI_MAXTITLELENGTH]='\0';
997 WIN_ReleaseWndPtr(childWnd);
1000 else
1001 lpBuffer[0] = '\0';
1003 DEFWND_SetText( frameWnd, lpBuffer );
1004 if( repaint == MDI_REPAINTFRAME)
1005 SetWindowPos( frameWnd->hwndSelf, 0,0,0,0,0, SWP_FRAMECHANGED |
1006 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
1008 WIN_ReleaseWndPtr(clientWnd);
1013 /* ----------------------------- Interface ---------------------------- */
1016 /**********************************************************************
1017 * MDIClientWndProc
1019 * This function handles all MDI requests.
1021 LRESULT WINAPI MDIClientWndProc( HWND hwnd, UINT message, WPARAM wParam,
1022 LPARAM lParam )
1024 LPCREATESTRUCTA cs;
1025 MDICLIENTINFO *ci;
1026 RECT rect;
1027 WND *w, *frameWnd;
1028 INT nItems;
1029 LRESULT retvalue;
1031 if ( ( w = WIN_FindWndPtr(hwnd) ) == NULL )
1032 return 0;
1034 if ( ( frameWnd = WIN_LockWndPtr(w->parent) ) == NULL ) {
1035 WIN_ReleaseWndPtr(w);
1036 return 0;
1039 ci = (MDICLIENTINFO *) w->wExtra;
1041 switch (message)
1043 case WM_CREATE:
1045 cs = (LPCREATESTRUCTA)lParam;
1047 /* Translation layer doesn't know what's in the cs->lpCreateParams
1048 * so we have to keep track of what environment we're in. */
1050 if( w->flags & WIN_ISWIN32 )
1052 #define ccs ((LPCLIENTCREATESTRUCT)cs->lpCreateParams)
1053 ci->hWindowMenu = ccs->hWindowMenu;
1054 ci->idFirstChild = ccs->idFirstChild;
1055 #undef ccs
1057 else
1059 LPCLIENTCREATESTRUCT16 ccs = (LPCLIENTCREATESTRUCT16)
1060 PTR_SEG_TO_LIN(cs->lpCreateParams);
1061 ci->hWindowMenu = ccs->hWindowMenu;
1062 ci->idFirstChild = ccs->idFirstChild;
1065 ci->hwndChildMaximized = 0;
1066 ci->nActiveChildren = 0;
1067 ci->nTotalCreated = 0;
1068 ci->frameTitle = NULL;
1069 ci->mdiFlags = 0;
1070 ci->self = hwnd;
1071 w->dwStyle |= WS_CLIPCHILDREN;
1073 if (!hBmpClose)
1075 hBmpClose = CreateMDIMenuBitmap();
1076 hBmpRestore = LoadBitmap16( 0, MAKEINTRESOURCE16(OBM_RESTORE) );
1078 MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
1080 AppendMenuA( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
1082 GetClientRect(frameWnd->hwndSelf, &rect);
1083 NC_HandleNCCalcSize( w, &rect );
1084 w->rectClient = rect;
1086 TRACE("Client created - hwnd = %04x, idFirst = %u\n",
1087 hwnd, ci->idFirstChild );
1089 retvalue = 0;
1090 goto END;
1092 case WM_DESTROY:
1093 if( ci->hwndChildMaximized ) MDI_RestoreFrameMenu(w, frameWnd->hwndSelf);
1094 if((nItems = GetMenuItemCount(ci->hWindowMenu)) > 0)
1096 ci->idFirstChild = nItems - 1;
1097 ci->nActiveChildren++; /* to delete a separator */
1098 while( ci->nActiveChildren-- )
1099 DeleteMenu(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
1101 retvalue = 0;
1102 goto END;
1104 case WM_MDIACTIVATE:
1105 if( ci->hwndActiveChild != (HWND)wParam )
1106 SetWindowPos((HWND)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
1107 retvalue = 0;
1108 goto END;
1110 case WM_MDICASCADE:
1111 retvalue = MDICascade(w, ci);
1112 goto END;
1114 case WM_MDICREATE:
1115 if (lParam) retvalue = MDICreateChild( w, ci, hwnd,
1116 (MDICREATESTRUCTA*)lParam );
1117 else retvalue = 0;
1118 goto END;
1120 case WM_MDIDESTROY:
1121 retvalue = MDIDestroyChild( w, ci, hwnd, (HWND)wParam, TRUE );
1122 goto END;
1124 case WM_MDIGETACTIVE:
1125 if (lParam) *(BOOL *)lParam = (ci->hwndChildMaximized > 0);
1126 retvalue = ci->hwndActiveChild;
1127 goto END;
1129 case WM_MDIICONARRANGE:
1130 ci->mdiFlags |= MDIF_NEEDUPDATE;
1131 ArrangeIconicWindows(hwnd);
1132 ci->sbRecalc = SB_BOTH+1;
1133 SendMessageA(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
1134 retvalue = 0;
1135 goto END;
1137 case WM_MDIMAXIMIZE:
1138 ShowWindow( (HWND)wParam, SW_MAXIMIZE );
1139 retvalue = 0;
1140 goto END;
1142 case WM_MDINEXT: /* lParam != 0 means previous window */
1143 MDI_SwitchActiveChild(hwnd, (HWND)wParam, (lParam)? FALSE : TRUE );
1144 break;
1146 case WM_MDIRESTORE:
1147 SendMessageA( (HWND)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
1148 retvalue = 0;
1149 goto END;
1151 case WM_MDISETMENU:
1152 retvalue = MDISetMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1153 goto END;
1154 case WM_MDIREFRESHMENU:
1155 retvalue = MDIRefreshMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1156 goto END;
1158 case WM_MDITILE:
1159 ci->mdiFlags |= MDIF_NEEDUPDATE;
1160 ShowScrollBar(hwnd,SB_BOTH,FALSE);
1161 MDITile(w, ci, wParam);
1162 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1163 retvalue = 0;
1164 goto END;
1166 case WM_VSCROLL:
1167 case WM_HSCROLL:
1168 ci->mdiFlags |= MDIF_NEEDUPDATE;
1169 ScrollChildren(hwnd, message, wParam, lParam);
1170 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1171 retvalue = 0;
1172 goto END;
1174 case WM_SETFOCUS:
1175 if( ci->hwndActiveChild )
1177 WND* pw = WIN_FindWndPtr( ci->hwndActiveChild );
1178 if( !(pw->dwStyle & WS_MINIMIZE) )
1179 SetFocus( ci->hwndActiveChild );
1180 WIN_ReleaseWndPtr(pw);
1182 retvalue = 0;
1183 goto END;
1185 case WM_NCACTIVATE:
1186 if( ci->hwndActiveChild )
1187 SendMessageA(ci->hwndActiveChild, message, wParam, lParam);
1188 break;
1190 case WM_PARENTNOTIFY:
1191 if (LOWORD(wParam) == WM_LBUTTONDOWN)
1193 POINT16 pt = MAKEPOINT16(lParam);
1194 HWND16 child = ChildWindowFromPoint16(hwnd, pt);
1196 TRACE("notification from %04x (%i,%i)\n",child,pt.x,pt.y);
1198 if( child && child != hwnd && child != ci->hwndActiveChild )
1199 SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1201 retvalue = 0;
1202 goto END;
1204 case WM_SIZE:
1205 if( IsWindow(ci->hwndChildMaximized) )
1207 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1208 RECT rect;
1210 rect.left = 0;
1211 rect.top = 0;
1212 rect.right = LOWORD(lParam);
1213 rect.bottom = HIWORD(lParam);
1215 AdjustWindowRectEx(&rect, child->dwStyle, 0, child->dwExStyle);
1216 MoveWindow(ci->hwndChildMaximized, rect.left, rect.top,
1217 rect.right - rect.left, rect.bottom - rect.top, 1);
1218 WIN_ReleaseWndPtr(child);
1220 else
1221 MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1223 break;
1225 case WM_MDICALCCHILDSCROLL:
1226 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1228 CalcChildScroll16(hwnd, ci->sbRecalc-1);
1229 ci->sbRecalc = 0;
1230 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1232 retvalue = 0;
1233 goto END;
1236 retvalue = DefWindowProcA( hwnd, message, wParam, lParam );
1237 END:
1238 WIN_ReleaseWndPtr(w);
1239 WIN_ReleaseWndPtr(frameWnd);
1240 return retvalue;
1244 /***********************************************************************
1245 * DefFrameProc16 (USER.445)
1247 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1248 UINT16 message, WPARAM16 wParam, LPARAM lParam )
1250 HWND16 childHwnd;
1251 MDICLIENTINFO* ci;
1252 WND* wndPtr;
1254 if (hwndMDIClient)
1256 switch (message)
1258 case WM_COMMAND:
1259 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1261 if (!wndPtr) {
1262 ERR("null wndPtr for mdi window hwndMDIClient=%04x\n",
1263 hwndMDIClient);
1264 return 0;
1267 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1269 /* check for possible syscommands for maximized MDI child */
1270 WIN_ReleaseWndPtr(wndPtr);
1272 if( ci && (
1273 wParam < ci->idFirstChild ||
1274 wParam >= ci->idFirstChild + ci->nActiveChildren
1276 if( (wParam - 0xF000) & 0xF00F ) break;
1277 switch( wParam )
1279 case SC_SIZE:
1280 case SC_MOVE:
1281 case SC_MINIMIZE:
1282 case SC_MAXIMIZE:
1283 case SC_NEXTWINDOW:
1284 case SC_PREVWINDOW:
1285 case SC_CLOSE:
1286 case SC_RESTORE:
1287 if( ci->hwndChildMaximized )
1288 return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1289 wParam, lParam);
1292 else
1294 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1295 childHwnd = MDI_GetChildByID(wndPtr,wParam );
1296 WIN_ReleaseWndPtr(wndPtr);
1298 if( childHwnd )
1299 SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1300 (WPARAM16)childHwnd , 0L);
1302 break;
1304 case WM_NCACTIVATE:
1305 SendMessage16(hwndMDIClient, message, wParam, lParam);
1306 break;
1308 case WM_SETTEXT:
1309 wndPtr = WIN_FindWndPtr(hwnd);
1310 MDI_UpdateFrameText(wndPtr, hwndMDIClient,
1311 MDI_REPAINTFRAME,
1312 (LPCSTR)PTR_SEG_TO_LIN(lParam));
1313 WIN_ReleaseWndPtr(wndPtr);
1314 return 0;
1316 case WM_SETFOCUS:
1317 SetFocus(hwndMDIClient);
1318 break;
1320 case WM_SIZE:
1321 MoveWindow16(hwndMDIClient, 0, 0,
1322 LOWORD(lParam), HIWORD(lParam), TRUE);
1323 break;
1325 case WM_NEXTMENU:
1327 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1328 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1330 if( !(wndPtr->parent->dwStyle & WS_MINIMIZE)
1331 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1333 /* control menu is between the frame system menu and
1334 * the first entry of menu bar */
1336 if( (wParam == VK_LEFT &&
1337 wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1338 (wParam == VK_RIGHT &&
1339 GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1341 LRESULT retvalue;
1342 WIN_ReleaseWndPtr(wndPtr);
1343 wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1344 retvalue = MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1345 ci->hwndActiveChild);
1346 WIN_ReleaseWndPtr(wndPtr);
1347 return retvalue;
1350 WIN_ReleaseWndPtr(wndPtr);
1351 break;
1355 return DefWindowProc16(hwnd, message, wParam, lParam);
1359 /***********************************************************************
1360 * DefFrameProc32A (USER32.122)
1362 LRESULT WINAPI DefFrameProcA( HWND hwnd, HWND hwndMDIClient,
1363 UINT message, WPARAM wParam, LPARAM lParam)
1365 if (hwndMDIClient)
1367 switch (message)
1369 case WM_COMMAND:
1370 return DefFrameProc16( hwnd, hwndMDIClient, message,
1371 (WPARAM16)wParam,
1372 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1374 case WM_NCACTIVATE:
1375 SendMessageA(hwndMDIClient, message, wParam, lParam);
1376 break;
1378 case WM_SETTEXT: {
1379 LRESULT ret;
1380 LPSTR segstr = SEGPTR_STRDUP((LPSTR)lParam);
1382 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1383 wParam, (LPARAM)SEGPTR_GET(segstr) );
1384 SEGPTR_FREE(segstr);
1385 return ret;
1388 case WM_NEXTMENU:
1389 case WM_SETFOCUS:
1390 case WM_SIZE:
1391 return DefFrameProc16( hwnd, hwndMDIClient, message,
1392 wParam, lParam );
1396 return DefWindowProcA(hwnd, message, wParam, lParam);
1400 /***********************************************************************
1401 * DefFrameProc32W (USER32.123)
1403 LRESULT WINAPI DefFrameProcW( HWND hwnd, HWND hwndMDIClient,
1404 UINT message, WPARAM wParam, LPARAM lParam)
1406 if (hwndMDIClient)
1408 switch (message)
1410 case WM_COMMAND:
1411 return DefFrameProc16( hwnd, hwndMDIClient, message,
1412 (WPARAM16)wParam,
1413 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1415 case WM_NCACTIVATE:
1416 SendMessageW(hwndMDIClient, message, wParam, lParam);
1417 break;
1419 case WM_SETTEXT:
1421 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1422 LRESULT ret = DefFrameProcA( hwnd, hwndMDIClient, message,
1423 wParam, (DWORD)txt );
1424 HeapFree(GetProcessHeap(),0,txt);
1425 return ret;
1427 case WM_NEXTMENU:
1428 case WM_SETFOCUS:
1429 case WM_SIZE:
1430 return DefFrameProcA( hwnd, hwndMDIClient, message,
1431 wParam, lParam );
1435 return DefWindowProcW( hwnd, message, wParam, lParam );
1439 /***********************************************************************
1440 * DefMDIChildProc16 (USER.447)
1442 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1443 WPARAM16 wParam, LPARAM lParam )
1445 MDICLIENTINFO *ci;
1446 WND *clientWnd,*tmpWnd = 0;
1447 LRESULT retvalue;
1449 clientWnd = WIN_FindWndPtr(GetParent16(hwnd));
1450 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1452 switch (message)
1454 case WM_SETTEXT:
1455 DefWindowProc16(hwnd, message, wParam, lParam);
1456 MDI_MenuModifyItem(clientWnd,hwnd);
1457 if( ci->hwndChildMaximized == hwnd )
1458 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1459 MDI_REPAINTFRAME, NULL );
1460 retvalue = 0;
1461 goto END;
1463 case WM_CLOSE:
1464 SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1465 retvalue = 0;
1466 goto END;
1468 case WM_SETFOCUS:
1469 if( ci->hwndActiveChild != hwnd )
1470 MDI_ChildActivate(clientWnd, hwnd);
1471 break;
1473 case WM_CHILDACTIVATE:
1474 MDI_ChildActivate(clientWnd, hwnd);
1475 retvalue = 0;
1476 goto END;
1478 case WM_NCPAINT:
1479 TRACE("WM_NCPAINT for %04x, active %04x\n",
1480 hwnd, ci->hwndActiveChild );
1481 break;
1483 case WM_SYSCOMMAND:
1484 switch( wParam )
1486 case SC_MOVE:
1487 if( ci->hwndChildMaximized == hwnd)
1489 retvalue = 0;
1490 goto END;
1492 break;
1493 case SC_RESTORE:
1494 case SC_MINIMIZE:
1495 tmpWnd = WIN_FindWndPtr(hwnd);
1496 tmpWnd->dwStyle |= WS_SYSMENU;
1497 WIN_ReleaseWndPtr(tmpWnd);
1498 break;
1499 case SC_MAXIMIZE:
1500 if( ci->hwndChildMaximized == hwnd)
1502 retvalue = SendMessage16( clientWnd->parent->hwndSelf,
1503 message, wParam, lParam);
1504 goto END;
1506 tmpWnd = WIN_FindWndPtr(hwnd);
1507 tmpWnd->dwStyle &= ~WS_SYSMENU;
1508 WIN_ReleaseWndPtr(tmpWnd);
1509 break;
1510 case SC_NEXTWINDOW:
1511 SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1512 retvalue = 0;
1513 goto END;
1514 case SC_PREVWINDOW:
1515 SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1516 retvalue = 0;
1517 goto END;
1519 break;
1521 case WM_GETMINMAXINFO:
1522 MDI_ChildGetMinMaxInfo(clientWnd, hwnd, (MINMAXINFO16*) PTR_SEG_TO_LIN(lParam));
1523 retvalue = 0;
1524 goto END;
1526 case WM_SETVISIBLE:
1527 if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1528 else
1529 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1530 break;
1532 case WM_SIZE:
1533 /* do not change */
1535 if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1537 ci->hwndChildMaximized = 0;
1539 MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1540 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1541 MDI_REPAINTFRAME, NULL );
1544 if( wParam == SIZE_MAXIMIZED )
1546 HWND16 hMaxChild = ci->hwndChildMaximized;
1548 if( hMaxChild == hwnd ) break;
1550 if( hMaxChild)
1552 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1554 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1555 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1557 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1560 TRACE("maximizing child %04x\n", hwnd );
1562 ci->hwndChildMaximized = hwnd; /* !!! */
1563 ci->hwndActiveChild = hwnd;
1565 MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1566 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1567 MDI_REPAINTFRAME, NULL );
1570 if( wParam == SIZE_MINIMIZED )
1572 HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1574 if( switchTo )
1575 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1578 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1579 break;
1581 case WM_MENUCHAR:
1583 /* MDI children don't have menu bars */
1584 PostMessage16( clientWnd->parent->hwndSelf, WM_SYSCOMMAND,
1585 (WPARAM16)SC_KEYMENU, (LPARAM)wParam);
1586 retvalue = 0x00010000L;
1587 goto END;
1589 case WM_NEXTMENU:
1591 if( wParam == VK_LEFT ) /* switch to frame system menu */
1593 retvalue = MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1594 clientWnd->parent->hwndSelf );
1595 goto END;
1597 if( wParam == VK_RIGHT ) /* to frame menu bar */
1599 retvalue = MAKELONG( clientWnd->parent->wIDmenu,
1600 clientWnd->parent->hwndSelf );
1601 goto END;
1604 break;
1606 case WM_SYSCHAR:
1607 if (wParam == '-')
1609 SendMessage16(hwnd,WM_SYSCOMMAND,
1610 (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1611 retvalue = 0;
1612 goto END;
1616 retvalue = DefWindowProc16(hwnd, message, wParam, lParam);
1617 END:
1618 WIN_ReleaseWndPtr(clientWnd);
1619 return retvalue;
1623 /***********************************************************************
1624 * DefMDIChildProc32A (USER32.124)
1626 LRESULT WINAPI DefMDIChildProcA( HWND hwnd, UINT message,
1627 WPARAM wParam, LPARAM lParam )
1629 MDICLIENTINFO *ci;
1630 WND *clientWnd,*tmpWnd;
1631 LRESULT retvalue;
1633 tmpWnd = WIN_FindWndPtr(hwnd);
1634 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1635 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1636 WIN_ReleaseWndPtr(tmpWnd);
1638 switch (message)
1640 case WM_SETTEXT:
1641 DefWindowProcA(hwnd, message, wParam, lParam);
1642 MDI_MenuModifyItem(clientWnd,hwnd);
1643 if( ci->hwndChildMaximized == hwnd )
1644 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1645 MDI_REPAINTFRAME, NULL );
1646 retvalue = 0;
1647 goto END;
1649 case WM_GETMINMAXINFO:
1651 MINMAXINFO16 mmi;
1652 STRUCT32_MINMAXINFO32to16( (MINMAXINFO *)lParam, &mmi );
1653 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1654 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO *)lParam );
1656 retvalue = 0;
1657 goto END;
1659 case WM_MENUCHAR:
1661 /* MDI children don't have menu bars */
1662 PostMessage16( clientWnd->parent->hwndSelf, WM_SYSCOMMAND,
1663 (WPARAM16)SC_KEYMENU, (LPARAM)LOWORD(wParam) );
1664 retvalue = 0x00010000L;
1665 goto END;
1667 case WM_CLOSE:
1668 case WM_SETFOCUS:
1669 case WM_CHILDACTIVATE:
1670 case WM_NCPAINT:
1671 case WM_SYSCOMMAND:
1672 case WM_SETVISIBLE:
1673 case WM_SIZE:
1674 case WM_NEXTMENU:
1675 retvalue = DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1676 goto END;
1678 case WM_SYSCHAR:
1679 if (wParam == '-')
1681 SendMessageA(hwnd,WM_SYSCOMMAND,
1682 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1683 retvalue = 0;
1684 goto END;
1687 retvalue = DefWindowProcA(hwnd, message, wParam, lParam);
1688 END:
1689 WIN_ReleaseWndPtr(clientWnd);
1690 return retvalue;
1694 /***********************************************************************
1695 * DefMDIChildProc32W (USER32.125)
1697 LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message,
1698 WPARAM wParam, LPARAM lParam )
1700 MDICLIENTINFO *ci;
1701 WND *clientWnd;
1702 LRESULT retvalue;
1704 clientWnd = WIN_FindWndPtr(GetParent16(hwnd));
1705 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1707 switch (message)
1709 case WM_SETTEXT:
1710 DefWindowProcW(hwnd, message, wParam, lParam);
1711 MDI_MenuModifyItem(clientWnd,hwnd);
1712 if( ci->hwndChildMaximized == hwnd )
1713 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1714 MDI_REPAINTFRAME, NULL );
1715 retvalue = 0;
1716 goto END;
1718 case WM_GETMINMAXINFO:
1719 case WM_MENUCHAR:
1720 case WM_CLOSE:
1721 case WM_SETFOCUS:
1722 case WM_CHILDACTIVATE:
1723 case WM_NCPAINT:
1724 case WM_SYSCOMMAND:
1725 case WM_SETVISIBLE:
1726 case WM_SIZE:
1727 case WM_NEXTMENU:
1728 retvalue = DefMDIChildProcA( hwnd, message, (WPARAM16)wParam, lParam );
1729 goto END;
1731 case WM_SYSCHAR:
1732 if (wParam == '-')
1734 SendMessageW(hwnd,WM_SYSCOMMAND,
1735 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1736 retvalue = 0;
1737 goto END;
1740 retvalue = DefWindowProcW(hwnd, message, wParam, lParam);
1741 END:
1742 WIN_ReleaseWndPtr(clientWnd);
1743 return retvalue;
1748 /**********************************************************************
1749 * CreateMDIWindowA [USER32.79] Creates a MDI child in new thread
1750 * FIXME: its in the same thread now
1752 * RETURNS
1753 * Success: Handle to created window
1754 * Failure: NULL
1756 HWND WINAPI CreateMDIWindowA(
1757 LPCSTR lpClassName, /* [in] Pointer to registered child class name */
1758 LPCSTR lpWindowName, /* [in] Pointer to window name */
1759 DWORD dwStyle, /* [in] Window style */
1760 INT X, /* [in] Horizontal position of window */
1761 INT Y, /* [in] Vertical position of window */
1762 INT nWidth, /* [in] Width of window */
1763 INT nHeight, /* [in] Height of window */
1764 HWND hWndParent, /* [in] Handle to parent window */
1765 HINSTANCE hInstance, /* [in] Handle to application instance */
1766 LPARAM lParam) /* [in] Application-defined value */
1768 WARN("is only single threaded!\n");
1769 return MDI_CreateMDIWindowA(lpClassName, lpWindowName, dwStyle, X, Y,
1770 nWidth, nHeight, hWndParent, hInstance, lParam);
1773 /**********************************************************************
1774 * MDI_CreateMDIWindowA
1775 * single threaded version of CreateMDIWindowA
1776 * called by CreateWindowEx32A
1778 HWND MDI_CreateMDIWindowA(
1779 LPCSTR lpClassName,
1780 LPCSTR lpWindowName,
1781 DWORD dwStyle,
1782 INT X,
1783 INT Y,
1784 INT nWidth,
1785 INT nHeight,
1786 HWND hWndParent,
1787 HINSTANCE hInstance,
1788 LPARAM lParam)
1790 MDICLIENTINFO* pCi;
1791 MDICREATESTRUCTA cs;
1792 WND *pWnd=WIN_FindWndPtr(hWndParent);
1793 HWND retvalue;
1795 TRACE("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
1796 debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
1797 nWidth,nHeight,hWndParent,hInstance,lParam);
1799 if(!pWnd){
1800 ERR(" bad hwnd for MDI-client: %d\n",hWndParent);
1801 return 0;
1803 cs.szClass=lpClassName;
1804 cs.szTitle=lpWindowName;
1805 cs.hOwner=hInstance;
1806 cs.x=X;
1807 cs.y=Y;
1808 cs.cx=nWidth;
1809 cs.cy=nHeight;
1810 cs.style=dwStyle;
1811 cs.lParam=lParam;
1813 pCi=(MDICLIENTINFO *)pWnd->wExtra;
1815 retvalue = MDICreateChild(pWnd,pCi,hWndParent,&cs);
1816 WIN_ReleaseWndPtr(pWnd);
1817 return retvalue;
1820 /***************************************
1821 * CreateMDIWindow32W [USER32.80] Creates a MDI child in new thread
1823 * RETURNS
1824 * Success: Handle to created window
1825 * Failure: NULL
1827 HWND WINAPI CreateMDIWindowW(
1828 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1829 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1830 DWORD dwStyle, /* [in] Window style */
1831 INT X, /* [in] Horizontal position of window */
1832 INT Y, /* [in] Vertical position of window */
1833 INT nWidth, /* [in] Width of window */
1834 INT nHeight, /* [in] Height of window */
1835 HWND hWndParent, /* [in] Handle to parent window */
1836 HINSTANCE hInstance, /* [in] Handle to application instance */
1837 LPARAM lParam) /* [in] Application-defined value */
1839 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1840 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1841 nWidth,nHeight,hWndParent,hInstance,lParam);
1842 return (HWND)NULL;
1846 /******************************************************************************
1847 * CreateMDIWindow32W [USER32.80] Creates a MDI child window
1848 * single threaded version of CreateMDIWindow
1849 * called by CreateWindowEx32W().
1851 HWND MDI_CreateMDIWindowW(
1852 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1853 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1854 DWORD dwStyle, /* [in] Window style */
1855 INT X, /* [in] Horizontal position of window */
1856 INT Y, /* [in] Vertical position of window */
1857 INT nWidth, /* [in] Width of window */
1858 INT nHeight, /* [in] Height of window */
1859 HWND hWndParent, /* [in] Handle to parent window */
1860 HINSTANCE hInstance, /* [in] Handle to application instance */
1861 LPARAM lParam) /* [in] Application-defined value */
1863 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1864 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1865 nWidth,nHeight,hWndParent,hInstance,lParam);
1866 return (HWND)NULL;
1870 /**********************************************************************
1871 * TranslateMDISysAccel32 (USER32.555)
1873 BOOL WINAPI TranslateMDISysAccel( HWND hwndClient, LPMSG msg )
1875 MSG16 msg16;
1877 STRUCT32_MSG32to16(msg,&msg16);
1878 /* MDICLIENTINFO is still the same for win32 and win16 ... */
1879 return TranslateMDISysAccel16(hwndClient,&msg16);
1883 /**********************************************************************
1884 * TranslateMDISysAccel16 (USER.451)
1886 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
1889 if( IsWindow(hwndClient) && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
1891 MDICLIENTINFO *ci = NULL;
1892 HWND wnd;
1893 WND *clientWnd = WIN_FindWndPtr(hwndClient);
1895 ci = (MDICLIENTINFO*) clientWnd->wExtra;
1896 wnd = ci->hwndActiveChild;
1898 WIN_ReleaseWndPtr(clientWnd);
1900 if( IsWindow(wnd) && !(GetWindowLongA(wnd,GWL_STYLE) & WS_DISABLED) )
1902 WPARAM16 wParam = 0;
1904 /* translate if the Ctrl key is down and Alt not. */
1906 if( (GetKeyState(VK_CONTROL) & 0x8000) &&
1907 !(GetKeyState(VK_MENU) & 0x8000))
1909 switch( msg->wParam )
1911 case VK_F6:
1912 case VK_TAB:
1913 wParam = ( GetKeyState(VK_SHIFT) & 0x8000 )
1914 ? SC_NEXTWINDOW : SC_PREVWINDOW;
1915 break;
1916 case VK_F4:
1917 case VK_RBUTTON:
1918 wParam = SC_CLOSE;
1919 break;
1920 default:
1921 return 0;
1923 TRACE("wParam = %04x\n", wParam);
1924 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
1925 wParam, (LPARAM)msg->wParam);
1926 return 1;
1930 return 0; /* failure */
1934 /***********************************************************************
1935 * CalcChildScroll (USER.462)
1937 void WINAPI CalcChildScroll16( HWND16 hwnd, WORD scroll )
1939 SCROLLINFO info;
1940 RECT childRect, clientRect;
1941 INT vmin, vmax, hmin, hmax, vpos, hpos;
1942 WND *pWnd, *Wnd;
1944 if (!(pWnd = WIN_FindWndPtr( hwnd ))) return;
1945 Wnd = WIN_FindWndPtr(hwnd);
1946 GetClientRect( hwnd, &clientRect );
1947 SetRectEmpty( &childRect );
1949 for ( WIN_UpdateWndPtr(&pWnd,pWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
1951 if( pWnd->dwStyle & WS_MAXIMIZE )
1953 ShowScrollBar(hwnd, SB_BOTH, FALSE);
1954 WIN_ReleaseWndPtr(pWnd);
1955 WIN_ReleaseWndPtr(Wnd);
1956 return;
1958 UnionRect( &childRect, &pWnd->rectWindow, &childRect );
1960 WIN_ReleaseWndPtr(pWnd);
1961 UnionRect( &childRect, &clientRect, &childRect );
1963 hmin = childRect.left; hmax = childRect.right - clientRect.right;
1964 hpos = clientRect.left - childRect.left;
1965 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
1966 vpos = clientRect.top - childRect.top;
1968 switch( scroll )
1970 case SB_HORZ:
1971 vpos = hpos; vmin = hmin; vmax = hmax;
1972 case SB_VERT:
1973 info.cbSize = sizeof(info);
1974 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
1975 info.fMask = SIF_POS | SIF_RANGE;
1976 SetScrollInfo(hwnd, scroll, &info, TRUE);
1977 break;
1978 case SB_BOTH:
1979 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
1980 hmin, hmax, hpos);
1982 WIN_ReleaseWndPtr(Wnd);
1986 /***********************************************************************
1987 * ScrollChildren16 (USER.463)
1989 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
1991 ScrollChildren( hWnd, uMsg, wParam, lParam );
1995 /***********************************************************************
1996 * ScrollChildren32 (USER32.448)
1998 void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
1999 LPARAM lParam)
2001 WND *wndPtr = WIN_FindWndPtr(hWnd);
2002 INT newPos = -1;
2003 INT curPos, length, minPos, maxPos, shift;
2005 if( !wndPtr ) return;
2007 if( uMsg == WM_HSCROLL )
2009 GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
2010 curPos = GetScrollPos(hWnd,SB_HORZ);
2011 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
2012 shift = GetSystemMetrics(SM_CYHSCROLL);
2014 else if( uMsg == WM_VSCROLL )
2016 GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
2017 curPos = GetScrollPos(hWnd,SB_VERT);
2018 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
2019 shift = GetSystemMetrics(SM_CXVSCROLL);
2021 else
2023 WIN_ReleaseWndPtr(wndPtr);
2024 return;
2027 WIN_ReleaseWndPtr(wndPtr);
2028 switch( wParam )
2030 case SB_LINEUP:
2031 newPos = curPos - shift;
2032 break;
2033 case SB_LINEDOWN:
2034 newPos = curPos + shift;
2035 break;
2036 case SB_PAGEUP:
2037 newPos = curPos - length;
2038 break;
2039 case SB_PAGEDOWN:
2040 newPos = curPos + length;
2041 break;
2043 case SB_THUMBPOSITION:
2044 newPos = LOWORD(lParam);
2045 break;
2047 case SB_THUMBTRACK:
2048 return;
2050 case SB_TOP:
2051 newPos = minPos;
2052 break;
2053 case SB_BOTTOM:
2054 newPos = maxPos;
2055 break;
2056 case SB_ENDSCROLL:
2057 CalcChildScroll16(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
2058 return;
2061 if( newPos > maxPos )
2062 newPos = maxPos;
2063 else
2064 if( newPos < minPos )
2065 newPos = minPos;
2067 SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
2069 if( uMsg == WM_VSCROLL )
2070 ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
2071 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2072 else
2073 ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
2074 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2078 /******************************************************************************
2079 * CascadeWindows [USER32.21] Cascades MDI child windows
2081 * RETURNS
2082 * Success: Number of cascaded windows.
2083 * Failure: 0
2085 WORD WINAPI
2086 CascadeWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2087 UINT cKids, const HWND *lpKids)
2089 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2090 hwndParent, wFlags, cKids);
2092 return 0;
2096 /******************************************************************************
2097 * TileWindows [USER32.545] Tiles MDI child windows
2099 * RETURNS
2100 * Success: Number of tiled windows.
2101 * Failure: 0
2103 WORD WINAPI
2104 TileWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2105 UINT cKids, const HWND *lpKids)
2107 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2108 hwndParent, wFlags, cKids);
2110 return 0;