Account for the trailing NULL in GetLogicalDriveStringsA.
[wine.git] / windows / mdi.c
blobc647daf749e84c3ed6d8f8c5ad2945828468893b
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;
211 MDICLIENTINFO *ci;
212 HWND hwndFrame = GetParent(hwnd);
213 HMENU oldFrameMenu = GetMenu(hwndFrame);
215 TRACE("%04x %04x %04x\n",
216 hwnd, hmenuFrame, hmenuWindow);
218 if (hmenuFrame && !IsMenu(hmenuFrame))
220 WARN("hmenuFrame is not a menu handle\n");
221 return 0L;
224 if (hmenuWindow && !IsMenu(hmenuWindow))
226 WARN("hmenuWindow is not a menu handle\n");
227 return 0L;
230 w = WIN_FindWndPtr(hwnd);
231 ci = (MDICLIENTINFO *) w->wExtra;
233 if( ci->hwndChildMaximized && hmenuFrame && hmenuFrame!=oldFrameMenu )
234 MDI_RestoreFrameMenu(w->parent, ci->hwndChildMaximized );
236 if( hmenuWindow && hmenuWindow!=ci->hWindowMenu )
238 /* delete menu items from ci->hWindowMenu
239 * and add them to hmenuWindow */
241 INT i = GetMenuItemCount(ci->hWindowMenu) - 1;
242 INT pos = GetMenuItemCount(hmenuWindow) + 1;
244 AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL);
246 if( ci->nActiveChildren )
248 INT j = i - ci->nActiveChildren + 1;
249 char buffer[100];
250 UINT id,state;
252 for( ; i >= j ; i-- )
254 id = GetMenuItemID(ci->hWindowMenu,i );
255 state = GetMenuState(ci->hWindowMenu,i,MF_BYPOSITION);
257 GetMenuStringA(ci->hWindowMenu, i, buffer, 100, MF_BYPOSITION);
259 DeleteMenu(ci->hWindowMenu, i , MF_BYPOSITION);
260 InsertMenuA(hmenuWindow, pos, MF_BYPOSITION | MF_STRING,
261 id, buffer);
262 CheckMenuItem(hmenuWindow ,pos , MF_BYPOSITION | (state & MF_CHECKED));
266 /* remove separator */
267 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
269 ci->hWindowMenu = hmenuWindow;
272 if( hmenuFrame && hmenuFrame!=oldFrameMenu)
274 SetMenu(hwndFrame, hmenuFrame);
275 if( ci->hwndChildMaximized )
276 MDI_AugmentFrameMenu(ci, w->parent, ci->hwndChildMaximized );
277 WIN_ReleaseWndPtr(w);
278 return oldFrameMenu;
280 WIN_ReleaseWndPtr(w);
281 return 0;
284 /**********************************************************************
285 * MDIRefreshMenu
287 static LRESULT MDIRefreshMenu( HWND hwnd, HMENU hmenuFrame,
288 HMENU hmenuWindow)
290 HWND hwndFrame = GetParent(hwnd);
291 HMENU oldFrameMenu = GetMenu(hwndFrame);
293 TRACE("%04x %04x %04x\n",
294 hwnd, hmenuFrame, hmenuWindow);
296 FIXME("partially function stub\n");
298 return oldFrameMenu;
302 /* ------------------ MDI child window functions ---------------------- */
305 /**********************************************************************
306 * MDICreateChild
308 static HWND MDICreateChild( WND *w, MDICLIENTINFO *ci, HWND parent,
309 LPMDICREATESTRUCTA cs )
311 POINT pos[2];
312 DWORD style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
313 HWND hwnd, hwndMax = 0;
314 WORD wIDmenu = ci->idFirstChild + ci->nActiveChildren;
315 char lpstrDef[]="junk!";
317 TRACE("origin %i,%i - dim %i,%i, style %08x\n",
318 cs->x, cs->y, cs->cx, cs->cy, (unsigned)cs->style);
319 /* calculate placement */
320 MDI_CalcDefaultChildPos(w, ci->nTotalCreated++, pos, 0);
322 if (cs->cx == CW_USEDEFAULT || !cs->cx) cs->cx = pos[1].x;
323 if (cs->cy == CW_USEDEFAULT || !cs->cy) cs->cy = pos[1].y;
325 if( cs->x == CW_USEDEFAULT )
327 cs->x = pos[0].x;
328 cs->y = pos[0].y;
331 /* restore current maximized child */
332 if( style & WS_VISIBLE && ci->hwndChildMaximized )
334 if( style & WS_MAXIMIZE )
335 SendMessageA(w->hwndSelf, WM_SETREDRAW, FALSE, 0L );
336 hwndMax = ci->hwndChildMaximized;
337 ShowWindow( hwndMax, SW_SHOWNOACTIVATE );
338 if( style & WS_MAXIMIZE )
339 SendMessageA(w->hwndSelf, WM_SETREDRAW, TRUE, 0L );
342 /* this menu is needed to set a check mark in MDI_ChildActivate */
343 AppendMenuA(ci->hWindowMenu ,MF_STRING ,wIDmenu, lpstrDef );
345 ci->nActiveChildren++;
347 /* fix window style */
348 if( !(w->dwStyle & MDIS_ALLCHILDSTYLES) )
350 style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE |
351 WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL );
352 style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW);
355 if( w->flags & WIN_ISWIN32 )
357 hwnd = CreateWindowA( cs->szClass, cs->szTitle, style,
358 cs->x, cs->y, cs->cx, cs->cy, parent,
359 (HMENU16)wIDmenu, cs->hOwner, cs );
361 else
363 MDICREATESTRUCT16 *cs16;
364 LPSTR title, cls;
366 cs16 = SEGPTR_NEW(MDICREATESTRUCT16);
367 STRUCT32_MDICREATESTRUCT32Ato16( cs, cs16 );
368 title = SEGPTR_STRDUP( cs->szTitle );
369 cls = SEGPTR_STRDUP( cs->szClass );
370 cs16->szTitle = SEGPTR_GET(title);
371 cs16->szClass = SEGPTR_GET(cls);
373 hwnd = CreateWindow16( cs->szClass, cs->szTitle, style,
374 cs16->x, cs16->y, cs16->cx, cs16->cy, parent,
375 (HMENU)wIDmenu, cs16->hOwner,
376 (LPVOID)SEGPTR_GET(cs16) );
377 SEGPTR_FREE( title );
378 SEGPTR_FREE( cls );
379 SEGPTR_FREE( cs16 );
382 /* MDI windows are WS_CHILD so they won't be activated by CreateWindow */
384 if (hwnd)
386 WND* wnd = WIN_FindWndPtr( hwnd );
388 /* All MDI child windows have the WS_EX_MDICHILD style */
389 wnd->dwExStyle |= WS_EX_MDICHILD;
391 MDI_MenuModifyItem(w ,hwnd);
392 if( wnd->dwStyle & WS_MINIMIZE && ci->hwndActiveChild )
393 ShowWindow( hwnd, SW_SHOWMINNOACTIVE );
394 else
396 /* WS_VISIBLE is clear if a) the MDI client has
397 * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the
398 * MDICreateStruct. If so the created window is not shown nor
399 * activated.
401 int showflag=wnd->dwStyle & WS_VISIBLE;
402 /* clear visible flag, otherwise SetWindoPos32 ignores
403 * the SWP_SHOWWINDOW command.
405 wnd->dwStyle &= ~WS_VISIBLE;
406 if(showflag){
407 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE );
409 /* Set maximized state here in case hwnd didn't receive WM_SIZE
410 * during CreateWindow - bad!
413 if((wnd->dwStyle & WS_MAXIMIZE) && !ci->hwndChildMaximized )
415 ci->hwndChildMaximized = wnd->hwndSelf;
416 MDI_AugmentFrameMenu( ci, w->parent, hwnd );
417 MDI_UpdateFrameText( w->parent, ci->self, MDI_REPAINTFRAME, NULL );
419 }else
420 /* needed, harmless ? */
421 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE );
424 WIN_ReleaseWndPtr(wnd);
425 TRACE("created child - %04x\n",hwnd);
427 else
429 ci->nActiveChildren--;
430 DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
431 if( IsWindow(hwndMax) )
432 ShowWindow(hwndMax, SW_SHOWMAXIMIZED);
435 return hwnd;
438 /**********************************************************************
439 * MDI_ChildGetMinMaxInfo
441 * Note: The rule here is that client rect of the maximized MDI child
442 * is equal to the client rect of the MDI client window.
444 static void MDI_ChildGetMinMaxInfo( WND* clientWnd, HWND hwnd,
445 MINMAXINFO16* lpMinMax )
447 WND* childWnd = WIN_FindWndPtr(hwnd);
448 RECT rect = clientWnd->rectClient;
450 MapWindowPoints( clientWnd->parent->hwndSelf,
451 ((MDICLIENTINFO*)clientWnd->wExtra)->self, (LPPOINT)&rect, 2);
452 AdjustWindowRectEx( &rect, childWnd->dwStyle, 0, childWnd->dwExStyle );
454 lpMinMax->ptMaxSize.x = rect.right -= rect.left;
455 lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
457 lpMinMax->ptMaxPosition.x = rect.left;
458 lpMinMax->ptMaxPosition.y = rect.top;
460 WIN_ReleaseWndPtr(childWnd);
462 TRACE("max rect (%i,%i - %i, %i)\n",
463 rect.left,rect.top,rect.right,rect.bottom);
467 /**********************************************************************
468 * MDI_SwitchActiveChild
470 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
471 * being activated
473 static void MDI_SwitchActiveChild( HWND clientHwnd, HWND childHwnd,
474 BOOL bNextWindow )
476 WND *w = WIN_FindWndPtr(clientHwnd);
477 HWND hwndTo = 0;
478 HWND hwndPrev = 0;
479 MDICLIENTINFO *ci;
481 hwndTo = MDI_GetWindow(w, childHwnd, bNextWindow, 0);
483 ci = (MDICLIENTINFO *) w->wExtra;
485 TRACE("from %04x, to %04x\n",childHwnd,hwndTo);
487 if ( !hwndTo ) goto END; /* no window to switch to */
489 hwndPrev = ci->hwndActiveChild;
491 if ( hwndTo != hwndPrev )
493 BOOL bOptimize = 0;
495 if( ci->hwndChildMaximized )
497 bOptimize = 1;
498 w->dwStyle &= ~WS_VISIBLE;
501 SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0,
502 SWP_NOMOVE | SWP_NOSIZE );
504 if( bNextWindow && hwndPrev )
505 SetWindowPos( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0,
506 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
507 if( bOptimize )
508 ShowWindow( clientHwnd, SW_SHOW );
510 END:
511 WIN_ReleaseWndPtr(w);
515 /**********************************************************************
516 * MDIDestroyChild
518 static LRESULT MDIDestroyChild( WND *w_parent, MDICLIENTINFO *ci,
519 HWND parent, HWND child,
520 BOOL flagDestroy )
522 WND *childPtr = WIN_FindWndPtr(child);
524 if( childPtr )
526 if( child == ci->hwndActiveChild )
528 MDI_SwitchActiveChild(parent, child, TRUE);
530 if( child == ci->hwndActiveChild )
532 ShowWindow( child, SW_HIDE);
533 if( child == ci->hwndChildMaximized )
535 MDI_RestoreFrameMenu(w_parent->parent, child);
536 ci->hwndChildMaximized = 0;
537 MDI_UpdateFrameText(w_parent->parent,parent,TRUE,NULL);
540 MDI_ChildActivate(w_parent, 0);
543 MDI_MenuDeleteItem(w_parent, child);
545 WIN_ReleaseWndPtr(childPtr);
547 ci->nActiveChildren--;
549 TRACE("child destroyed - %04x\n",child);
551 if (flagDestroy)
553 MDI_PostUpdate(GetParent(child), ci, SB_BOTH+1);
554 DestroyWindow(child);
558 return 0;
562 /**********************************************************************
563 * MDI_ChildActivate
565 * Note: hWndChild is NULL when last child is being destroyed
567 static LONG MDI_ChildActivate( WND *clientPtr, HWND hWndChild )
569 MDICLIENTINFO *clientInfo = (MDICLIENTINFO*)clientPtr->wExtra;
570 HWND prevActiveWnd = clientInfo->hwndActiveChild;
571 WND *wndPtr = WIN_FindWndPtr( hWndChild );
572 WND *wndPrev = WIN_FindWndPtr( prevActiveWnd );
573 BOOL isActiveFrameWnd = 0;
574 LONG retvalue;
576 if( wndPtr )
578 if( wndPtr->dwStyle & WS_DISABLED )
580 retvalue = 0L;
581 goto END;
585 TRACE("%04x\n", hWndChild);
587 if( GetActiveWindow() == clientPtr->parent->hwndSelf )
588 isActiveFrameWnd = TRUE;
590 /* deactivate prev. active child */
591 if( wndPrev )
593 wndPrev->dwStyle |= WS_SYSMENU;
594 SendMessageA( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
595 SendMessageA( prevActiveWnd, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
596 (LPARAM)hWndChild);
597 /* uncheck menu item */
598 if( clientInfo->hWindowMenu )
599 CheckMenuItem( clientInfo->hWindowMenu,
600 wndPrev->wIDmenu, 0);
603 /* set appearance */
604 if( clientInfo->hwndChildMaximized )
606 if( clientInfo->hwndChildMaximized != hWndChild ) {
607 if( hWndChild ) {
608 clientInfo->hwndActiveChild = hWndChild;
609 clientInfo->hwndChildMaximized = hWndChild;
610 ShowWindow( hWndChild, SW_SHOWMAXIMIZED);
611 } else
612 ShowWindow( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
616 clientInfo->hwndActiveChild = hWndChild;
618 /* check if we have any children left */
619 if( !hWndChild )
621 if( isActiveFrameWnd )
622 SetFocus( clientInfo->self );
623 retvalue = 0;
624 goto END;
627 /* check menu item */
628 if( clientInfo->hWindowMenu )
629 CheckMenuItem( clientInfo->hWindowMenu,
630 wndPtr->wIDmenu, MF_CHECKED);
632 /* bring active child to the top */
633 SetWindowPos( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
635 if( isActiveFrameWnd )
637 SendMessageA( hWndChild, WM_NCACTIVATE, TRUE, 0L);
638 if( GetFocus() == clientInfo->self )
639 SendMessageA( clientInfo->self, WM_SETFOCUS,
640 (WPARAM)clientInfo->self, 0L );
641 else
642 SetFocus( clientInfo->self );
644 SendMessageA( hWndChild, WM_MDIACTIVATE, (WPARAM)prevActiveWnd,
645 (LPARAM)hWndChild );
646 retvalue = 1;
647 END:
648 WIN_ReleaseWndPtr(wndPtr);
649 WIN_ReleaseWndPtr(wndPrev);
650 return retvalue;
653 /* -------------------- MDI client window functions ------------------- */
655 /**********************************************************************
656 * CreateMDIMenuBitmap
658 static HBITMAP16 CreateMDIMenuBitmap(void)
660 HDC hDCSrc = CreateCompatibleDC(0);
661 HDC hDCDest = CreateCompatibleDC(hDCSrc);
662 HBITMAP16 hbClose = LoadBitmap16(0, MAKEINTRESOURCE16(OBM_CLOSE) );
663 HBITMAP16 hbCopy;
664 HANDLE16 hobjSrc, hobjDest;
666 hobjSrc = SelectObject(hDCSrc, hbClose);
667 hbCopy = CreateCompatibleBitmap(hDCSrc,GetSystemMetrics(SM_CXSIZE),GetSystemMetrics(SM_CYSIZE));
668 hobjDest = SelectObject(hDCDest, hbCopy);
670 BitBlt(hDCDest, 0, 0, GetSystemMetrics(SM_CXSIZE), GetSystemMetrics(SM_CYSIZE),
671 hDCSrc, GetSystemMetrics(SM_CXSIZE), 0, SRCCOPY);
673 SelectObject(hDCSrc, hobjSrc);
674 DeleteObject(hbClose);
675 DeleteDC(hDCSrc);
677 hobjSrc = SelectObject( hDCDest, GetStockObject(BLACK_PEN) );
679 MoveToEx( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, 0, NULL );
680 LineTo( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, GetSystemMetrics(SM_CYSIZE) - 1);
682 SelectObject(hDCDest, hobjSrc );
683 SelectObject(hDCDest, hobjDest);
684 DeleteDC(hDCDest);
686 return hbCopy;
689 /**********************************************************************
690 * MDICascade
692 static LONG MDICascade(WND* clientWnd, MDICLIENTINFO *ci)
694 WND** ppWnd;
695 UINT total;
697 if (ci->hwndChildMaximized)
698 SendMessageA( clientWnd->hwndSelf, WM_MDIRESTORE,
699 (WPARAM)ci->hwndChildMaximized, 0);
701 if (ci->nActiveChildren == 0) return 0;
703 if ((ppWnd = WIN_BuildWinArray(clientWnd, BWA_SKIPHIDDEN | BWA_SKIPOWNED |
704 BWA_SKIPICONIC, &total)))
706 WND** heapPtr = ppWnd;
707 if( total )
709 INT delta = 0, n = 0;
710 POINT pos[2];
711 if( total < ci->nActiveChildren )
712 delta = GetSystemMetrics(SM_CYICONSPACING) +
713 GetSystemMetrics(SM_CYICON);
715 /* walk the list (backwards) and move windows */
716 while (*ppWnd) ppWnd++;
717 while (ppWnd != heapPtr)
719 ppWnd--;
720 TRACE("move %04x to (%ld,%ld) size [%ld,%ld]\n",
721 (*ppWnd)->hwndSelf, pos[0].x, pos[0].y, pos[1].x, pos[1].y);
723 MDI_CalcDefaultChildPos(clientWnd, n++, pos, delta);
724 SetWindowPos( (*ppWnd)->hwndSelf, 0, pos[0].x, pos[0].y,
725 pos[1].x, pos[1].y,
726 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
729 WIN_ReleaseWinArray(heapPtr);
732 if( total < ci->nActiveChildren )
733 ArrangeIconicWindows( clientWnd->hwndSelf );
734 return 0;
737 /**********************************************************************
738 * MDITile
740 static void MDITile( WND* wndClient, MDICLIENTINFO *ci, WPARAM wParam )
742 WND** ppWnd;
743 UINT total = 0;
745 if (ci->hwndChildMaximized)
746 SendMessageA( wndClient->hwndSelf, WM_MDIRESTORE,
747 (WPARAM)ci->hwndChildMaximized, 0);
749 if (ci->nActiveChildren == 0) return;
751 ppWnd = WIN_BuildWinArray(wndClient, BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
752 ((wParam & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
754 TRACE("%u windows to tile\n", total);
756 if( ppWnd )
758 WND** heapPtr = ppWnd;
760 if( total )
762 RECT rect;
763 int x, y, xsize, ysize;
764 int rows, columns, r, c, i;
766 GetClientRect(wndClient->hwndSelf,&rect);
767 rows = (int) sqrt((double)total);
768 columns = total / rows;
770 if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */
772 i = rows;
773 rows = columns; /* exchange r and c */
774 columns = i;
777 if( total != ci->nActiveChildren)
779 y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
780 rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
783 ysize = rect.bottom / rows;
784 xsize = rect.right / columns;
786 for (x = i = 0, c = 1; c <= columns && *ppWnd; c++)
788 if (c == columns)
790 rows = total - i;
791 ysize = rect.bottom / rows;
794 y = 0;
795 for (r = 1; r <= rows && *ppWnd; r++, i++)
797 SetWindowPos((*ppWnd)->hwndSelf, 0, x, y, xsize, ysize,
798 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
799 y += ysize;
800 ppWnd++;
802 x += xsize;
805 WIN_ReleaseWinArray(heapPtr);
808 if( total < ci->nActiveChildren ) ArrangeIconicWindows( wndClient->hwndSelf );
811 /* ----------------------- Frame window ---------------------------- */
814 /**********************************************************************
815 * MDI_AugmentFrameMenu
817 static BOOL MDI_AugmentFrameMenu( MDICLIENTINFO* ci, WND *frame,
818 HWND hChild )
820 WND* child = WIN_FindWndPtr(hChild);
821 HMENU hSysPopup = 0;
822 HBITMAP hSysMenuBitmap = 0;
824 TRACE("frame %p,child %04x\n",frame,hChild);
826 if( !frame->wIDmenu || !child->hSysMenu )
828 WIN_ReleaseWndPtr(child);
829 return 0;
831 WIN_ReleaseWndPtr(child);
833 /* create a copy of sysmenu popup and insert it into frame menu bar */
835 if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
836 return 0;
838 TRACE("\tgot popup %04x in sysmenu %04x\n",
839 hSysPopup, child->hSysMenu);
841 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
842 SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
843 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
844 SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
846 /* In Win 95 look, the system menu is replaced by the child icon */
848 if(TWEAK_WineLook > WIN31_LOOK)
850 HICON hIcon = GetClassLongA(hChild, GCL_HICONSM);
851 if (!hIcon)
852 hIcon = GetClassLongA(hChild, GCL_HICON);
853 if (hIcon)
855 HDC hMemDC;
856 HBITMAP hBitmap, hOldBitmap;
857 HBRUSH hBrush;
858 HDC hdc = GetDC(hChild);
860 if (hdc)
862 int cx, cy;
863 cx = GetSystemMetrics(SM_CXSMICON);
864 cy = GetSystemMetrics(SM_CYSMICON);
865 hMemDC = CreateCompatibleDC(hdc);
866 hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
867 hOldBitmap = SelectObject(hMemDC, hBitmap);
868 SetMapMode(hMemDC, MM_TEXT);
869 hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
870 DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL);
871 SelectObject (hMemDC, hOldBitmap);
872 DeleteObject(hBrush);
873 DeleteDC(hMemDC);
874 ReleaseDC(hChild, hdc);
875 hSysMenuBitmap = hBitmap;
879 else
880 hSysMenuBitmap = hBmpClose;
882 if( !InsertMenuA(frame->wIDmenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
883 hSysPopup, (LPSTR)(DWORD)hSysMenuBitmap))
885 TRACE("not inserted\n");
886 DestroyMenu(hSysPopup);
887 return 0;
890 /* The close button is only present in Win 95 look */
891 if(TWEAK_WineLook > WIN31_LOOK)
893 AppendMenuA(frame->wIDmenu,MF_HELP | MF_BITMAP,
894 SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
897 EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
898 EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
899 EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
900 SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE);
902 /* redraw menu */
903 DrawMenuBar(frame->hwndSelf);
905 return 1;
908 /**********************************************************************
909 * MDI_RestoreFrameMenu
911 static BOOL MDI_RestoreFrameMenu( WND *frameWnd, HWND hChild )
913 MENUITEMINFOA menuInfo;
914 INT nItems = GetMenuItemCount(frameWnd->wIDmenu) - 1;
915 UINT iId = GetMenuItemID(frameWnd->wIDmenu,nItems) ;
917 TRACE("frameWnd %p,child %04x\n",frameWnd,hChild);
919 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
920 return 0;
923 * Remove the system menu, If that menu is the icon of the window
924 * as it is in win95, we have to delete the bitmap.
926 menuInfo.cbSize = sizeof(MENUITEMINFOA);
927 menuInfo.fMask = MIIM_DATA | MIIM_TYPE;
929 GetMenuItemInfoA(frameWnd->wIDmenu,
931 TRUE,
932 &menuInfo);
934 RemoveMenu(frameWnd->wIDmenu,0,MF_BYPOSITION);
936 if ( (menuInfo.fType & MFT_BITMAP) &&
937 (LOWORD(menuInfo.dwTypeData)!=0) &&
938 (LOWORD(menuInfo.dwTypeData)!=hBmpClose) )
940 DeleteObject((HBITMAP)LOWORD(menuInfo.dwTypeData));
943 if(TWEAK_WineLook > WIN31_LOOK)
945 /* close */
946 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
948 /* restore */
949 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
950 /* minimize */
951 DeleteMenu(frameWnd->wIDmenu,GetMenuItemCount(frameWnd->wIDmenu) - 1,MF_BYPOSITION);
953 DrawMenuBar(frameWnd->hwndSelf);
955 return 1;
959 /**********************************************************************
960 * MDI_UpdateFrameText
962 * used when child window is maximized/restored
964 * Note: lpTitle can be NULL
966 static void MDI_UpdateFrameText( WND *frameWnd, HWND hClient,
967 BOOL repaint, LPCSTR lpTitle )
969 char lpBuffer[MDI_MAXTITLELENGTH+1];
970 WND* clientWnd = WIN_FindWndPtr(hClient);
971 MDICLIENTINFO *ci = (MDICLIENTINFO *) clientWnd->wExtra;
973 TRACE("repaint %i, frameText %s\n", repaint, (lpTitle)?lpTitle:"NULL");
975 if (!clientWnd)
976 return;
978 if (!ci)
980 WIN_ReleaseWndPtr(clientWnd);
981 return;
984 /* store new "default" title if lpTitle is not NULL */
985 if (lpTitle)
987 if (ci->frameTitle) HeapFree( SystemHeap, 0, ci->frameTitle );
988 ci->frameTitle = HEAP_strdupA( SystemHeap, 0, lpTitle );
991 if (ci->frameTitle)
993 WND* childWnd = WIN_FindWndPtr( ci->hwndChildMaximized );
995 if( childWnd && childWnd->text )
997 /* combine frame title and child title if possible */
999 LPCSTR lpBracket = " - [";
1000 int i_frame_text_length = strlen(ci->frameTitle);
1001 int i_child_text_length = strlen(childWnd->text);
1003 lstrcpynA( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
1005 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
1007 strcat( lpBuffer, lpBracket );
1009 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
1011 strcat( lpBuffer, childWnd->text );
1012 strcat( lpBuffer, "]" );
1014 else
1016 lstrcpynA( lpBuffer + i_frame_text_length + 4,
1017 childWnd->text, MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
1018 strcat( lpBuffer, "]" );
1022 else
1024 strncpy(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH );
1025 lpBuffer[MDI_MAXTITLELENGTH]='\0';
1027 WIN_ReleaseWndPtr(childWnd);
1030 else
1031 lpBuffer[0] = '\0';
1033 DEFWND_SetText( frameWnd, lpBuffer );
1034 if( repaint == MDI_REPAINTFRAME)
1035 SetWindowPos( frameWnd->hwndSelf, 0,0,0,0,0, SWP_FRAMECHANGED |
1036 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
1038 WIN_ReleaseWndPtr(clientWnd);
1043 /* ----------------------------- Interface ---------------------------- */
1046 /**********************************************************************
1047 * MDIClientWndProc
1049 * This function handles all MDI requests.
1051 LRESULT WINAPI MDIClientWndProc( HWND hwnd, UINT message, WPARAM wParam,
1052 LPARAM lParam )
1054 LPCREATESTRUCTA cs;
1055 MDICLIENTINFO *ci;
1056 RECT rect;
1057 WND *w, *frameWnd;
1058 INT nItems;
1059 LRESULT retvalue;
1061 if ( ( w = WIN_FindWndPtr(hwnd) ) == NULL )
1062 return 0;
1064 if ( ( frameWnd = WIN_LockWndPtr(w->parent) ) == NULL ) {
1065 WIN_ReleaseWndPtr(w);
1066 return 0;
1069 ci = (MDICLIENTINFO *) w->wExtra;
1071 switch (message)
1073 case WM_CREATE:
1075 cs = (LPCREATESTRUCTA)lParam;
1077 /* Translation layer doesn't know what's in the cs->lpCreateParams
1078 * so we have to keep track of what environment we're in. */
1080 if( w->flags & WIN_ISWIN32 )
1082 #define ccs ((LPCLIENTCREATESTRUCT)cs->lpCreateParams)
1083 ci->hWindowMenu = ccs->hWindowMenu;
1084 ci->idFirstChild = ccs->idFirstChild;
1085 #undef ccs
1087 else
1089 LPCLIENTCREATESTRUCT16 ccs = (LPCLIENTCREATESTRUCT16)
1090 PTR_SEG_TO_LIN(cs->lpCreateParams);
1091 ci->hWindowMenu = ccs->hWindowMenu;
1092 ci->idFirstChild = ccs->idFirstChild;
1095 ci->hwndChildMaximized = 0;
1096 ci->nActiveChildren = 0;
1097 ci->nTotalCreated = 0;
1098 ci->frameTitle = NULL;
1099 ci->mdiFlags = 0;
1100 ci->self = hwnd;
1101 w->dwStyle |= WS_CLIPCHILDREN;
1103 if (!hBmpClose)
1105 hBmpClose = CreateMDIMenuBitmap();
1106 hBmpRestore = LoadBitmap16( 0, MAKEINTRESOURCE16(OBM_RESTORE) );
1108 MDI_UpdateFrameText(frameWnd, hwnd, MDI_NOFRAMEREPAINT,frameWnd->text);
1110 AppendMenuA( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
1112 GetClientRect(frameWnd->hwndSelf, &rect);
1113 NC_HandleNCCalcSize( w, &rect );
1114 w->rectClient = rect;
1116 TRACE("Client created - hwnd = %04x, idFirst = %u\n",
1117 hwnd, ci->idFirstChild );
1119 retvalue = 0;
1120 goto END;
1122 case WM_DESTROY:
1123 if( ci->hwndChildMaximized ) MDI_RestoreFrameMenu(w, frameWnd->hwndSelf);
1124 if((nItems = GetMenuItemCount(ci->hWindowMenu)) > 0)
1126 ci->idFirstChild = nItems - 1;
1127 ci->nActiveChildren++; /* to delete a separator */
1128 while( ci->nActiveChildren-- )
1129 DeleteMenu(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
1131 retvalue = 0;
1132 goto END;
1134 case WM_MDIACTIVATE:
1135 if( ci->hwndActiveChild != (HWND)wParam )
1136 SetWindowPos((HWND)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
1137 retvalue = 0;
1138 goto END;
1140 case WM_MDICASCADE:
1141 retvalue = MDICascade(w, ci);
1142 goto END;
1144 case WM_MDICREATE:
1145 if (lParam) retvalue = MDICreateChild( w, ci, hwnd,
1146 (MDICREATESTRUCTA*)lParam );
1147 else retvalue = 0;
1148 goto END;
1150 case WM_MDIDESTROY:
1151 retvalue = MDIDestroyChild( w, ci, hwnd, (HWND)wParam, TRUE );
1152 goto END;
1154 case WM_MDIGETACTIVE:
1155 if (lParam) *(BOOL *)lParam = (ci->hwndChildMaximized > 0);
1156 retvalue = ci->hwndActiveChild;
1157 goto END;
1159 case WM_MDIICONARRANGE:
1160 ci->mdiFlags |= MDIF_NEEDUPDATE;
1161 ArrangeIconicWindows(hwnd);
1162 ci->sbRecalc = SB_BOTH+1;
1163 SendMessageA(hwnd, WM_MDICALCCHILDSCROLL, 0, 0L);
1164 retvalue = 0;
1165 goto END;
1167 case WM_MDIMAXIMIZE:
1168 ShowWindow( (HWND)wParam, SW_MAXIMIZE );
1169 retvalue = 0;
1170 goto END;
1172 case WM_MDINEXT: /* lParam != 0 means previous window */
1173 MDI_SwitchActiveChild(hwnd, (HWND)wParam, (lParam)? FALSE : TRUE );
1174 break;
1176 case WM_MDIRESTORE:
1177 SendMessageA( (HWND)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
1178 retvalue = 0;
1179 goto END;
1181 case WM_MDISETMENU:
1182 retvalue = MDISetMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1183 goto END;
1184 case WM_MDIREFRESHMENU:
1185 retvalue = MDIRefreshMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1186 goto END;
1188 case WM_MDITILE:
1189 ci->mdiFlags |= MDIF_NEEDUPDATE;
1190 ShowScrollBar(hwnd,SB_BOTH,FALSE);
1191 MDITile(w, ci, wParam);
1192 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1193 retvalue = 0;
1194 goto END;
1196 case WM_VSCROLL:
1197 case WM_HSCROLL:
1198 ci->mdiFlags |= MDIF_NEEDUPDATE;
1199 ScrollChildren(hwnd, message, wParam, lParam);
1200 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1201 retvalue = 0;
1202 goto END;
1204 case WM_SETFOCUS:
1205 if( ci->hwndActiveChild )
1207 WND* pw = WIN_FindWndPtr( ci->hwndActiveChild );
1208 if( !(pw->dwStyle & WS_MINIMIZE) )
1209 SetFocus( ci->hwndActiveChild );
1210 WIN_ReleaseWndPtr(pw);
1212 retvalue = 0;
1213 goto END;
1215 case WM_NCACTIVATE:
1216 if( ci->hwndActiveChild )
1217 SendMessageA(ci->hwndActiveChild, message, wParam, lParam);
1218 break;
1220 case WM_PARENTNOTIFY:
1221 if (LOWORD(wParam) == WM_LBUTTONDOWN)
1223 POINT16 pt = MAKEPOINT16(lParam);
1224 HWND16 child = ChildWindowFromPoint16(hwnd, pt);
1226 TRACE("notification from %04x (%i,%i)\n",child,pt.x,pt.y);
1228 if( child && child != hwnd && child != ci->hwndActiveChild )
1229 SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
1231 retvalue = 0;
1232 goto END;
1234 case WM_SIZE:
1235 if( IsWindow(ci->hwndChildMaximized) )
1237 WND* child = WIN_FindWndPtr(ci->hwndChildMaximized);
1238 RECT rect;
1240 rect.left = 0;
1241 rect.top = 0;
1242 rect.right = LOWORD(lParam);
1243 rect.bottom = HIWORD(lParam);
1245 AdjustWindowRectEx(&rect, child->dwStyle, 0, child->dwExStyle);
1246 MoveWindow(ci->hwndChildMaximized, rect.left, rect.top,
1247 rect.right - rect.left, rect.bottom - rect.top, 1);
1248 WIN_ReleaseWndPtr(child);
1250 else
1251 MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
1253 break;
1255 case WM_MDICALCCHILDSCROLL:
1256 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
1258 CalcChildScroll16(hwnd, ci->sbRecalc-1);
1259 ci->sbRecalc = 0;
1260 ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1262 retvalue = 0;
1263 goto END;
1266 retvalue = DefWindowProcA( hwnd, message, wParam, lParam );
1267 END:
1268 WIN_ReleaseWndPtr(w);
1269 WIN_ReleaseWndPtr(frameWnd);
1270 return retvalue;
1274 /***********************************************************************
1275 * DefFrameProc16 (USER.445)
1277 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
1278 UINT16 message, WPARAM16 wParam, LPARAM lParam )
1280 HWND16 childHwnd;
1281 MDICLIENTINFO* ci;
1282 WND* wndPtr;
1284 if (hwndMDIClient)
1286 switch (message)
1288 case WM_COMMAND:
1289 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1291 if (!wndPtr) {
1292 ERR("null wndPtr for mdi window hwndMDIClient=%04x\n",
1293 hwndMDIClient);
1294 return 0;
1297 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1299 /* check for possible syscommands for maximized MDI child */
1300 WIN_ReleaseWndPtr(wndPtr);
1302 if( ci && (
1303 wParam < ci->idFirstChild ||
1304 wParam >= ci->idFirstChild + ci->nActiveChildren
1306 if( (wParam - 0xF000) & 0xF00F ) break;
1307 switch( wParam )
1309 case SC_SIZE:
1310 case SC_MOVE:
1311 case SC_MINIMIZE:
1312 case SC_MAXIMIZE:
1313 case SC_NEXTWINDOW:
1314 case SC_PREVWINDOW:
1315 case SC_CLOSE:
1316 case SC_RESTORE:
1317 if( ci->hwndChildMaximized )
1318 return SendMessage16( ci->hwndChildMaximized, WM_SYSCOMMAND,
1319 wParam, lParam);
1322 else
1324 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1325 childHwnd = MDI_GetChildByID(wndPtr,wParam );
1326 WIN_ReleaseWndPtr(wndPtr);
1328 if( childHwnd )
1329 SendMessage16(hwndMDIClient, WM_MDIACTIVATE,
1330 (WPARAM16)childHwnd , 0L);
1332 break;
1334 case WM_NCACTIVATE:
1335 SendMessage16(hwndMDIClient, message, wParam, lParam);
1336 break;
1338 case WM_SETTEXT:
1339 wndPtr = WIN_FindWndPtr(hwnd);
1340 MDI_UpdateFrameText(wndPtr, hwndMDIClient,
1341 MDI_REPAINTFRAME,
1342 (LPCSTR)PTR_SEG_TO_LIN(lParam));
1343 WIN_ReleaseWndPtr(wndPtr);
1344 return 0;
1346 case WM_SETFOCUS:
1347 SetFocus(hwndMDIClient);
1348 break;
1350 case WM_SIZE:
1351 MoveWindow16(hwndMDIClient, 0, 0,
1352 LOWORD(lParam), HIWORD(lParam), TRUE);
1353 break;
1355 case WM_NEXTMENU:
1357 wndPtr = WIN_FindWndPtr(hwndMDIClient);
1358 ci = (MDICLIENTINFO*)wndPtr->wExtra;
1360 if( !(wndPtr->parent->dwStyle & WS_MINIMIZE)
1361 && ci->hwndActiveChild && !ci->hwndChildMaximized )
1363 /* control menu is between the frame system menu and
1364 * the first entry of menu bar */
1366 if( (wParam == VK_LEFT &&
1367 wndPtr->parent->wIDmenu == LOWORD(lParam)) ||
1368 (wParam == VK_RIGHT &&
1369 GetSubMenu16(wndPtr->parent->hSysMenu, 0) == LOWORD(lParam)) )
1371 LRESULT retvalue;
1372 WIN_ReleaseWndPtr(wndPtr);
1373 wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
1374 retvalue = MAKELONG( GetSubMenu16(wndPtr->hSysMenu, 0),
1375 ci->hwndActiveChild);
1376 WIN_ReleaseWndPtr(wndPtr);
1377 return retvalue;
1380 WIN_ReleaseWndPtr(wndPtr);
1381 break;
1385 return DefWindowProc16(hwnd, message, wParam, lParam);
1389 /***********************************************************************
1390 * DefFrameProc32A (USER32.122)
1392 LRESULT WINAPI DefFrameProcA( HWND hwnd, HWND hwndMDIClient,
1393 UINT message, WPARAM wParam, LPARAM lParam)
1395 if (hwndMDIClient)
1397 switch (message)
1399 case WM_COMMAND:
1400 return DefFrameProc16( hwnd, hwndMDIClient, message,
1401 (WPARAM16)wParam,
1402 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1404 case WM_NCACTIVATE:
1405 SendMessageA(hwndMDIClient, message, wParam, lParam);
1406 break;
1408 case WM_SETTEXT: {
1409 LRESULT ret;
1410 LPSTR segstr = SEGPTR_STRDUP((LPSTR)lParam);
1412 ret = DefFrameProc16(hwnd, hwndMDIClient, message,
1413 wParam, (LPARAM)SEGPTR_GET(segstr) );
1414 SEGPTR_FREE(segstr);
1415 return ret;
1418 case WM_NEXTMENU:
1419 case WM_SETFOCUS:
1420 case WM_SIZE:
1421 return DefFrameProc16( hwnd, hwndMDIClient, message,
1422 wParam, lParam );
1426 return DefWindowProcA(hwnd, message, wParam, lParam);
1430 /***********************************************************************
1431 * DefFrameProc32W (USER32.123)
1433 LRESULT WINAPI DefFrameProcW( HWND hwnd, HWND hwndMDIClient,
1434 UINT message, WPARAM wParam, LPARAM lParam)
1436 if (hwndMDIClient)
1438 switch (message)
1440 case WM_COMMAND:
1441 return DefFrameProc16( hwnd, hwndMDIClient, message,
1442 (WPARAM16)wParam,
1443 MAKELPARAM( (HWND16)lParam, HIWORD(wParam) ) );
1445 case WM_NCACTIVATE:
1446 SendMessageW(hwndMDIClient, message, wParam, lParam);
1447 break;
1449 case WM_SETTEXT:
1451 LPSTR txt = HEAP_strdupWtoA(GetProcessHeap(),0,(LPWSTR)lParam);
1452 LRESULT ret = DefFrameProcA( hwnd, hwndMDIClient, message,
1453 wParam, (DWORD)txt );
1454 HeapFree(GetProcessHeap(),0,txt);
1455 return ret;
1457 case WM_NEXTMENU:
1458 case WM_SETFOCUS:
1459 case WM_SIZE:
1460 return DefFrameProcA( hwnd, hwndMDIClient, message,
1461 wParam, lParam );
1465 return DefWindowProcW( hwnd, message, wParam, lParam );
1469 /***********************************************************************
1470 * DefMDIChildProc16 (USER.447)
1472 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
1473 WPARAM16 wParam, LPARAM lParam )
1475 MDICLIENTINFO *ci;
1476 WND *clientWnd,*tmpWnd = 0;
1477 LRESULT retvalue;
1479 clientWnd = WIN_FindWndPtr(GetParent16(hwnd));
1480 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1482 switch (message)
1484 case WM_SETTEXT:
1485 DefWindowProc16(hwnd, message, wParam, lParam);
1486 MDI_MenuModifyItem(clientWnd,hwnd);
1487 if( ci->hwndChildMaximized == hwnd )
1488 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1489 MDI_REPAINTFRAME, NULL );
1490 retvalue = 0;
1491 goto END;
1493 case WM_CLOSE:
1494 SendMessage16(ci->self,WM_MDIDESTROY,(WPARAM16)hwnd,0L);
1495 retvalue = 0;
1496 goto END;
1498 case WM_SETFOCUS:
1499 if( ci->hwndActiveChild != hwnd )
1500 MDI_ChildActivate(clientWnd, hwnd);
1501 break;
1503 case WM_CHILDACTIVATE:
1504 MDI_ChildActivate(clientWnd, hwnd);
1505 retvalue = 0;
1506 goto END;
1508 case WM_NCPAINT:
1509 TRACE("WM_NCPAINT for %04x, active %04x\n",
1510 hwnd, ci->hwndActiveChild );
1511 break;
1513 case WM_SYSCOMMAND:
1514 switch( wParam )
1516 case SC_MOVE:
1517 if( ci->hwndChildMaximized == hwnd)
1519 retvalue = 0;
1520 goto END;
1522 break;
1523 case SC_RESTORE:
1524 case SC_MINIMIZE:
1525 tmpWnd = WIN_FindWndPtr(hwnd);
1526 tmpWnd->dwStyle |= WS_SYSMENU;
1527 WIN_ReleaseWndPtr(tmpWnd);
1528 break;
1529 case SC_MAXIMIZE:
1530 if( ci->hwndChildMaximized == hwnd)
1532 retvalue = SendMessage16( clientWnd->parent->hwndSelf,
1533 message, wParam, lParam);
1534 goto END;
1536 tmpWnd = WIN_FindWndPtr(hwnd);
1537 tmpWnd->dwStyle &= ~WS_SYSMENU;
1538 WIN_ReleaseWndPtr(tmpWnd);
1539 break;
1540 case SC_NEXTWINDOW:
1541 SendMessage16( ci->self, WM_MDINEXT, 0, 0);
1542 retvalue = 0;
1543 goto END;
1544 case SC_PREVWINDOW:
1545 SendMessage16( ci->self, WM_MDINEXT, 0, 1);
1546 retvalue = 0;
1547 goto END;
1549 break;
1551 case WM_GETMINMAXINFO:
1552 MDI_ChildGetMinMaxInfo(clientWnd, hwnd, (MINMAXINFO16*) PTR_SEG_TO_LIN(lParam));
1553 retvalue = 0;
1554 goto END;
1556 case WM_SETVISIBLE:
1557 if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1558 else
1559 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1560 break;
1562 case WM_SIZE:
1563 /* do not change */
1565 if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
1567 ci->hwndChildMaximized = 0;
1569 MDI_RestoreFrameMenu( clientWnd->parent, hwnd);
1570 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1571 MDI_REPAINTFRAME, NULL );
1574 if( wParam == SIZE_MAXIMIZED )
1576 HWND16 hMaxChild = ci->hwndChildMaximized;
1578 if( hMaxChild == hwnd ) break;
1580 if( hMaxChild)
1582 SendMessage16( hMaxChild, WM_SETREDRAW, FALSE, 0L );
1584 MDI_RestoreFrameMenu( clientWnd->parent, hMaxChild);
1585 ShowWindow16( hMaxChild, SW_SHOWNOACTIVATE);
1587 SendMessage16( hMaxChild, WM_SETREDRAW, TRUE, 0L );
1590 TRACE("maximizing child %04x\n", hwnd );
1592 ci->hwndChildMaximized = hwnd; /* !!! */
1593 ci->hwndActiveChild = hwnd;
1595 MDI_AugmentFrameMenu( ci, clientWnd->parent, hwnd);
1596 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1597 MDI_REPAINTFRAME, NULL );
1600 if( wParam == SIZE_MINIMIZED )
1602 HWND16 switchTo = MDI_GetWindow(clientWnd, hwnd, TRUE, WS_MINIMIZE);
1604 if( switchTo )
1605 SendMessage16( switchTo, WM_CHILDACTIVATE, 0, 0L);
1608 MDI_PostUpdate(clientWnd->hwndSelf, ci, SB_BOTH+1);
1609 break;
1611 case WM_MENUCHAR:
1613 /* MDI children don't have menu bars */
1614 PostMessage16( clientWnd->parent->hwndSelf, WM_SYSCOMMAND,
1615 (WPARAM16)SC_KEYMENU, (LPARAM)wParam);
1616 retvalue = 0x00010000L;
1617 goto END;
1619 case WM_NEXTMENU:
1621 if( wParam == VK_LEFT ) /* switch to frame system menu */
1623 retvalue = MAKELONG( GetSubMenu16(clientWnd->parent->hSysMenu, 0),
1624 clientWnd->parent->hwndSelf );
1625 goto END;
1627 if( wParam == VK_RIGHT ) /* to frame menu bar */
1629 retvalue = MAKELONG( clientWnd->parent->wIDmenu,
1630 clientWnd->parent->hwndSelf );
1631 goto END;
1634 break;
1636 case WM_SYSCHAR:
1637 if (wParam == '-')
1639 SendMessage16(hwnd,WM_SYSCOMMAND,
1640 (WPARAM16)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1641 retvalue = 0;
1642 goto END;
1646 retvalue = DefWindowProc16(hwnd, message, wParam, lParam);
1647 END:
1648 WIN_ReleaseWndPtr(clientWnd);
1649 return retvalue;
1653 /***********************************************************************
1654 * DefMDIChildProc32A (USER32.124)
1656 LRESULT WINAPI DefMDIChildProcA( HWND hwnd, UINT message,
1657 WPARAM wParam, LPARAM lParam )
1659 MDICLIENTINFO *ci;
1660 WND *clientWnd,*tmpWnd;
1661 LRESULT retvalue;
1663 tmpWnd = WIN_FindWndPtr(hwnd);
1664 clientWnd = WIN_FindWndPtr(tmpWnd->parent->hwndSelf);
1665 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1666 WIN_ReleaseWndPtr(tmpWnd);
1668 switch (message)
1670 case WM_SETTEXT:
1671 DefWindowProcA(hwnd, message, wParam, lParam);
1672 MDI_MenuModifyItem(clientWnd,hwnd);
1673 if( ci->hwndChildMaximized == hwnd )
1674 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1675 MDI_REPAINTFRAME, NULL );
1676 retvalue = 0;
1677 goto END;
1679 case WM_GETMINMAXINFO:
1681 MINMAXINFO16 mmi;
1682 STRUCT32_MINMAXINFO32to16( (MINMAXINFO *)lParam, &mmi );
1683 MDI_ChildGetMinMaxInfo( clientWnd, hwnd, &mmi );
1684 STRUCT32_MINMAXINFO16to32( &mmi, (MINMAXINFO *)lParam );
1686 retvalue = 0;
1687 goto END;
1689 case WM_MENUCHAR:
1691 /* MDI children don't have menu bars */
1692 PostMessage16( clientWnd->parent->hwndSelf, WM_SYSCOMMAND,
1693 (WPARAM16)SC_KEYMENU, (LPARAM)LOWORD(wParam) );
1694 retvalue = 0x00010000L;
1695 goto END;
1697 case WM_CLOSE:
1698 case WM_SETFOCUS:
1699 case WM_CHILDACTIVATE:
1700 case WM_NCPAINT:
1701 case WM_SYSCOMMAND:
1702 case WM_SETVISIBLE:
1703 case WM_SIZE:
1704 case WM_NEXTMENU:
1705 retvalue = DefMDIChildProc16( hwnd, message, (WPARAM16)wParam, lParam );
1706 goto END;
1708 case WM_SYSCHAR:
1709 if (wParam == '-')
1711 SendMessageA(hwnd,WM_SYSCOMMAND,
1712 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1713 retvalue = 0;
1714 goto END;
1717 retvalue = DefWindowProcA(hwnd, message, wParam, lParam);
1718 END:
1719 WIN_ReleaseWndPtr(clientWnd);
1720 return retvalue;
1724 /***********************************************************************
1725 * DefMDIChildProc32W (USER32.125)
1727 LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message,
1728 WPARAM wParam, LPARAM lParam )
1730 MDICLIENTINFO *ci;
1731 WND *clientWnd;
1732 LRESULT retvalue;
1734 clientWnd = WIN_FindWndPtr(GetParent16(hwnd));
1735 ci = (MDICLIENTINFO *) clientWnd->wExtra;
1737 switch (message)
1739 case WM_SETTEXT:
1740 DefWindowProcW(hwnd, message, wParam, lParam);
1741 MDI_MenuModifyItem(clientWnd,hwnd);
1742 if( ci->hwndChildMaximized == hwnd )
1743 MDI_UpdateFrameText( clientWnd->parent, ci->self,
1744 MDI_REPAINTFRAME, NULL );
1745 retvalue = 0;
1746 goto END;
1748 case WM_GETMINMAXINFO:
1749 case WM_MENUCHAR:
1750 case WM_CLOSE:
1751 case WM_SETFOCUS:
1752 case WM_CHILDACTIVATE:
1753 case WM_NCPAINT:
1754 case WM_SYSCOMMAND:
1755 case WM_SETVISIBLE:
1756 case WM_SIZE:
1757 case WM_NEXTMENU:
1758 retvalue = DefMDIChildProcA( hwnd, message, (WPARAM16)wParam, lParam );
1759 goto END;
1761 case WM_SYSCHAR:
1762 if (wParam == '-')
1764 SendMessageW(hwnd,WM_SYSCOMMAND,
1765 (WPARAM)SC_KEYMENU, (LPARAM)(DWORD)VK_SPACE);
1766 retvalue = 0;
1767 goto END;
1770 retvalue = DefWindowProcW(hwnd, message, wParam, lParam);
1771 END:
1772 WIN_ReleaseWndPtr(clientWnd);
1773 return retvalue;
1778 /**********************************************************************
1779 * CreateMDIWindowA [USER32.79] Creates a MDI child in new thread
1780 * FIXME: its in the same thread now
1782 * RETURNS
1783 * Success: Handle to created window
1784 * Failure: NULL
1786 HWND WINAPI CreateMDIWindowA(
1787 LPCSTR lpClassName, /* [in] Pointer to registered child class name */
1788 LPCSTR lpWindowName, /* [in] Pointer to window name */
1789 DWORD dwStyle, /* [in] Window style */
1790 INT X, /* [in] Horizontal position of window */
1791 INT Y, /* [in] Vertical position of window */
1792 INT nWidth, /* [in] Width of window */
1793 INT nHeight, /* [in] Height of window */
1794 HWND hWndParent, /* [in] Handle to parent window */
1795 HINSTANCE hInstance, /* [in] Handle to application instance */
1796 LPARAM lParam) /* [in] Application-defined value */
1798 WARN("is only single threaded!\n");
1799 return MDI_CreateMDIWindowA(lpClassName, lpWindowName, dwStyle, X, Y,
1800 nWidth, nHeight, hWndParent, hInstance, lParam);
1803 /**********************************************************************
1804 * MDI_CreateMDIWindowA
1805 * single threaded version of CreateMDIWindowA
1806 * called by CreateWindowEx32A
1808 HWND MDI_CreateMDIWindowA(
1809 LPCSTR lpClassName,
1810 LPCSTR lpWindowName,
1811 DWORD dwStyle,
1812 INT X,
1813 INT Y,
1814 INT nWidth,
1815 INT nHeight,
1816 HWND hWndParent,
1817 HINSTANCE hInstance,
1818 LPARAM lParam)
1820 MDICLIENTINFO* pCi;
1821 MDICREATESTRUCTA cs;
1822 WND *pWnd=WIN_FindWndPtr(hWndParent);
1823 HWND retvalue;
1825 TRACE("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
1826 debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
1827 nWidth,nHeight,hWndParent,hInstance,lParam);
1829 if(!pWnd){
1830 ERR(" bad hwnd for MDI-client: %d\n",hWndParent);
1831 return 0;
1833 cs.szClass=lpClassName;
1834 cs.szTitle=lpWindowName;
1835 cs.hOwner=hInstance;
1836 cs.x=X;
1837 cs.y=Y;
1838 cs.cx=nWidth;
1839 cs.cy=nHeight;
1840 cs.style=dwStyle;
1841 cs.lParam=lParam;
1843 pCi=(MDICLIENTINFO *)pWnd->wExtra;
1845 retvalue = MDICreateChild(pWnd,pCi,hWndParent,&cs);
1846 WIN_ReleaseWndPtr(pWnd);
1847 return retvalue;
1850 /***************************************
1851 * CreateMDIWindow32W [USER32.80] Creates a MDI child in new thread
1853 * RETURNS
1854 * Success: Handle to created window
1855 * Failure: NULL
1857 HWND WINAPI CreateMDIWindowW(
1858 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1859 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1860 DWORD dwStyle, /* [in] Window style */
1861 INT X, /* [in] Horizontal position of window */
1862 INT Y, /* [in] Vertical position of window */
1863 INT nWidth, /* [in] Width of window */
1864 INT nHeight, /* [in] Height of window */
1865 HWND hWndParent, /* [in] Handle to parent window */
1866 HINSTANCE hInstance, /* [in] Handle to application instance */
1867 LPARAM lParam) /* [in] Application-defined value */
1869 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1870 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1871 nWidth,nHeight,hWndParent,hInstance,lParam);
1872 return (HWND)NULL;
1876 /******************************************************************************
1877 * CreateMDIWindow32W [USER32.80] Creates a MDI child window
1878 * single threaded version of CreateMDIWindow
1879 * called by CreateWindowEx32W().
1881 HWND MDI_CreateMDIWindowW(
1882 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */
1883 LPCWSTR lpWindowName, /* [in] Pointer to window name */
1884 DWORD dwStyle, /* [in] Window style */
1885 INT X, /* [in] Horizontal position of window */
1886 INT Y, /* [in] Vertical position of window */
1887 INT nWidth, /* [in] Width of window */
1888 INT nHeight, /* [in] Height of window */
1889 HWND hWndParent, /* [in] Handle to parent window */
1890 HINSTANCE hInstance, /* [in] Handle to application instance */
1891 LPARAM lParam) /* [in] Application-defined value */
1893 FIXME("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld): stub\n",
1894 debugstr_w(lpClassName),debugstr_w(lpWindowName),dwStyle,X,Y,
1895 nWidth,nHeight,hWndParent,hInstance,lParam);
1896 return (HWND)NULL;
1900 /**********************************************************************
1901 * TranslateMDISysAccel32 (USER32.555)
1903 BOOL WINAPI TranslateMDISysAccel( HWND hwndClient, LPMSG msg )
1905 MSG16 msg16;
1907 STRUCT32_MSG32to16(msg,&msg16);
1908 /* MDICLIENTINFO is still the same for win32 and win16 ... */
1909 return TranslateMDISysAccel16(hwndClient,&msg16);
1913 /**********************************************************************
1914 * TranslateMDISysAccel16 (USER.451)
1916 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
1919 if( IsWindow(hwndClient) && (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN))
1921 MDICLIENTINFO *ci = NULL;
1922 HWND wnd;
1923 WND *clientWnd = WIN_FindWndPtr(hwndClient);
1925 ci = (MDICLIENTINFO*) clientWnd->wExtra;
1926 wnd = ci->hwndActiveChild;
1928 WIN_ReleaseWndPtr(clientWnd);
1930 if( IsWindow(wnd) && !(GetWindowLongA(wnd,GWL_STYLE) & WS_DISABLED) )
1932 WPARAM16 wParam = 0;
1934 /* translate if the Ctrl key is down and Alt not. */
1936 if( (GetKeyState(VK_CONTROL) & 0x8000) &&
1937 !(GetKeyState(VK_MENU) & 0x8000))
1939 switch( msg->wParam )
1941 case VK_F6:
1942 case VK_TAB:
1943 wParam = ( GetKeyState(VK_SHIFT) & 0x8000 )
1944 ? SC_NEXTWINDOW : SC_PREVWINDOW;
1945 break;
1946 case VK_F4:
1947 case VK_RBUTTON:
1948 wParam = SC_CLOSE;
1949 break;
1950 default:
1951 return 0;
1953 TRACE("wParam = %04x\n", wParam);
1954 SendMessage16( ci->hwndActiveChild, WM_SYSCOMMAND,
1955 wParam, (LPARAM)msg->wParam);
1956 return 1;
1960 return 0; /* failure */
1964 /***********************************************************************
1965 * CalcChildScroll (USER.462)
1967 void WINAPI CalcChildScroll16( HWND16 hwnd, WORD scroll )
1969 SCROLLINFO info;
1970 RECT childRect, clientRect;
1971 INT vmin, vmax, hmin, hmax, vpos, hpos;
1972 WND *pWnd, *Wnd;
1974 if (!(pWnd = WIN_FindWndPtr( hwnd ))) return;
1975 Wnd = WIN_FindWndPtr(hwnd);
1976 GetClientRect( hwnd, &clientRect );
1977 SetRectEmpty( &childRect );
1979 for ( WIN_UpdateWndPtr(&pWnd,pWnd->child); pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
1981 if( pWnd->dwStyle & WS_MAXIMIZE )
1983 ShowScrollBar(hwnd, SB_BOTH, FALSE);
1984 WIN_ReleaseWndPtr(pWnd);
1985 WIN_ReleaseWndPtr(Wnd);
1986 return;
1988 UnionRect( &childRect, &pWnd->rectWindow, &childRect );
1990 WIN_ReleaseWndPtr(pWnd);
1991 UnionRect( &childRect, &clientRect, &childRect );
1993 hmin = childRect.left; hmax = childRect.right - clientRect.right;
1994 hpos = clientRect.left - childRect.left;
1995 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
1996 vpos = clientRect.top - childRect.top;
1998 switch( scroll )
2000 case SB_HORZ:
2001 vpos = hpos; vmin = hmin; vmax = hmax;
2002 case SB_VERT:
2003 info.cbSize = sizeof(info);
2004 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
2005 info.fMask = SIF_POS | SIF_RANGE;
2006 SetScrollInfo(hwnd, scroll, &info, TRUE);
2007 break;
2008 case SB_BOTH:
2009 SCROLL_SetNCSbState( Wnd, vmin, vmax, vpos,
2010 hmin, hmax, hpos);
2012 WIN_ReleaseWndPtr(Wnd);
2016 /***********************************************************************
2017 * ScrollChildren16 (USER.463)
2019 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
2021 ScrollChildren( hWnd, uMsg, wParam, lParam );
2025 /***********************************************************************
2026 * ScrollChildren32 (USER32.448)
2028 void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
2029 LPARAM lParam)
2031 WND *wndPtr = WIN_FindWndPtr(hWnd);
2032 INT newPos = -1;
2033 INT curPos, length, minPos, maxPos, shift;
2035 if( !wndPtr ) return;
2037 if( uMsg == WM_HSCROLL )
2039 GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
2040 curPos = GetScrollPos(hWnd,SB_HORZ);
2041 length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
2042 shift = GetSystemMetrics(SM_CYHSCROLL);
2044 else if( uMsg == WM_VSCROLL )
2046 GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
2047 curPos = GetScrollPos(hWnd,SB_VERT);
2048 length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
2049 shift = GetSystemMetrics(SM_CXVSCROLL);
2051 else
2053 WIN_ReleaseWndPtr(wndPtr);
2054 return;
2057 WIN_ReleaseWndPtr(wndPtr);
2058 switch( wParam )
2060 case SB_LINEUP:
2061 newPos = curPos - shift;
2062 break;
2063 case SB_LINEDOWN:
2064 newPos = curPos + shift;
2065 break;
2066 case SB_PAGEUP:
2067 newPos = curPos - length;
2068 break;
2069 case SB_PAGEDOWN:
2070 newPos = curPos + length;
2071 break;
2073 case SB_THUMBPOSITION:
2074 newPos = LOWORD(lParam);
2075 break;
2077 case SB_THUMBTRACK:
2078 return;
2080 case SB_TOP:
2081 newPos = minPos;
2082 break;
2083 case SB_BOTTOM:
2084 newPos = maxPos;
2085 break;
2086 case SB_ENDSCROLL:
2087 CalcChildScroll16(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
2088 return;
2091 if( newPos > maxPos )
2092 newPos = maxPos;
2093 else
2094 if( newPos < minPos )
2095 newPos = minPos;
2097 SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
2099 if( uMsg == WM_VSCROLL )
2100 ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
2101 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2102 else
2103 ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
2104 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
2108 /******************************************************************************
2109 * CascadeWindows [USER32.21] Cascades MDI child windows
2111 * RETURNS
2112 * Success: Number of cascaded windows.
2113 * Failure: 0
2115 WORD WINAPI
2116 CascadeWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2117 UINT cKids, const HWND *lpKids)
2119 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2120 hwndParent, wFlags, cKids);
2122 return 0;
2126 /******************************************************************************
2127 * TileWindows [USER32.545] Tiles MDI child windows
2129 * RETURNS
2130 * Success: Number of tiled windows.
2131 * Failure: 0
2133 WORD WINAPI
2134 TileWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
2135 UINT cKids, const HWND *lpKids)
2137 FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
2138 hwndParent, wFlags, cKids);
2140 return 0;