/****************************************************************************\ * * MDIWIN.C - * * Copyright (c) 1985 - 1999, Microsoft Corporation * * MDI Child Windows Support * * History * 11-14-90 MikeHar Ported from windows * 14-Feb-1991 mikeke Added Revalidation code \****************************************************************************/ #include "precomp.h" #pragma hdrstop #define TITLE_EXTRA 5 #define MAX_TITLE_LEN 160 /***************************************************************************\ * xxxSetFrameTitle * * if lpch == 1, we redraw the whole frame. If 2, we don't do any redraw. Any * other value, and we redraw just the caption of the frame. * * History: * 11-14-90 MikeHar Ported from windows * 04-16-91 MikeHar Win31 Merge \***************************************************************************/ VOID xxxSetFrameTitle( PWND pwndFrame, PWND pwndMDI, LPWSTR lpch) { PWND pwnd; PMDI pmdi; WCHAR sz[MAX_TITLE_LEN]; HWND hwndFrame = HW(pwndFrame); CheckLock(pwndFrame); CheckLock(pwndMDI); /* * Get a pointer to the MDI structure. */ pmdi = ((PMDIWND)pwndMDI)->pmdi; if (IS_PTR(lpch) || lpch == NULL) { if (HTITLE(pmdi)) { UserLocalFree(HTITLE(pmdi)); } HTITLE(pmdi) = TextAlloc(lpch); } if (HTITLE(pmdi)) { LARGE_UNICODE_STRING str; int cch; RtlInitLargeUnicodeString(&str, HTITLE(pmdi), (UINT)-1); TextCopy(&str, sz, sizeof(sz)/sizeof(WCHAR)); if (MAXED(pmdi) && (pwnd = ValidateHwnd(MAXED(pmdi))) && pwnd->strName.Length) { cch = MAX_TITLE_LEN - ((str.Length / sizeof(WCHAR)) + TITLE_EXTRA); if (cch > 0) { wcscat(sz, TEXT(" - [")); wcsncat(sz, REBASE(pwnd, strName.Buffer), cch - 1); wcscat(sz, TEXT("]")); } } } else { sz[0] = 0; } _DefSetText(hwndFrame, sz, FALSE); if (lpch == (LPWSTR)1L) NtUserRedrawFrameAndHook(hwndFrame); else if (lpch != (LPWSTR)2L) { if (!NtUserRedrawTitle(hwndFrame, DC_TEXT)) NtUserRedrawFrame(hwndFrame); } } /***************************************************************************\ * TranslateMDISysAccel * * History: * 11-14-90 MikeHar Ported from windows \***************************************************************************/ FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, TranslateMDISysAccel, HWND, hwnd, LPMSG, lpMsg) BOOL TranslateMDISysAccel( HWND hwnd, LPMSG lpMsg) { PWND pwnd; PMDI pmdi; int event; /* * Is this a message we care about? */ if (lpMsg->message != WM_KEYDOWN && lpMsg->message != WM_SYSKEYDOWN) { return FALSE; } /* * This is called within a message loop. If the window gets destroyed, * there still may be other messages in the queue that get returned * after the window is destroyed. The app will call TranslateAccelerator() * on every one of these, causing RIPs.... Make it nice so it just * returns FALSE. */ if ((pwnd = ValidateHwndNoRip(hwnd)) == NULL) { RIPERR0(ERROR_INVALID_WINDOW_HANDLE, RIP_VERBOSE, ""); return FALSE; } CheckLock(pwnd); /* * Make sure this is really an MDIClient window. Harvard Graphics 2.0 * calls this function with a different window class and caused us * to get an access violation. */ if (GETFNID(pwnd) != FNID_MDICLIENT) { RIPMSG0(RIP_WARNING, "Window not of MDIClient class"); return FALSE; } /* * Get a pointer to the MDI structure */ pmdi = ((PMDIWND)pwnd)->pmdi; if (!ACTIVE(pmdi)) return FALSE; if (!IsWindowEnabled(ACTIVE(pmdi))) return FALSE; switch (lpMsg->wParam) { case VK_F4: event = SC_CLOSE; break; case VK_F6: case VK_TAB: if (GetKeyState(VK_SHIFT) < 0) event = SC_PREVWINDOW; else event = SC_NEXTWINDOW; break; default: return FALSE; } /* * All of these have the control key down */ if (GetKeyState(VK_CONTROL) >= 0) return FALSE; if (GetKeyState(VK_MENU) < 0) return FALSE; SendMessage(ACTIVE(pmdi), WM_SYSCOMMAND, event, MAKELONG(lpMsg->wParam, 0)); return TRUE; } /***************************************************************************\ * * CalcClientScrolling() * \***************************************************************************/ #define SBJ_HORZ HAS_SBHORZ #define SBJ_VERT HAS_SBVERT #define SBJ_BOTH (SBJ_HORZ | SBJ_VERT) VOID ByteOutsetRect( LPRECT lprc) { int *pi; int i; for (i = 0, pi = (int*)lprc; i < 4; i++, pi++) { if (*pi > 0) { *pi += 7; } else if (*pi < 0) { *pi -= 7; } *pi /= 8; } } VOID CalcClientScrolling( HWND hwnd, UINT sbj, BOOL fIgnoreMin) { PWND pwnd; RECT rcScroll; RECT rcClient; RECT rcRange; RECT rcT; PWND pwndT; BOOL fVert; BOOL fHorz; BYTE fHadVert, fHadHorz; BOOL fCheckVert; BOOL fCheckHorz; BOOL fNeedScrolls; SCROLLINFO si; if ((pwnd = ValidateHwnd(hwnd)) == NULL) { return; } CheckLock(pwnd); UserAssert(GETFNID(pwnd) != FNID_DESKTOP); // do nothing if the parent is iconic. This way, we don't add invisible // scrollbars which will paint and unpaint when restoring... if (TestWF(pwnd, WFMINIMIZED)) return; fVert = FALSE; fHorz = FALSE; fNeedScrolls=FALSE; fCheckHorz = (sbj & SBJ_HORZ); fCheckVert = (sbj & SBJ_VERT); // find client area without scroll bars CopyRect(&rcClient, KPRECT_TO_PRECT(&pwnd->rcClient)); fHadVert = TestWF(pwnd, WFVSCROLL); if (fCheckVert && fHadVert) if (TestWF(pwnd, WEFLAYOUTRTL)) { rcClient.left -= SYSMET(CXVSCROLL); } else { rcClient.right += SYSMET(CXVSCROLL); } fHadHorz = TestWF(pwnd, WFHSCROLL); if (fCheckHorz && fHadHorz) rcClient.bottom += SYSMET(CYHSCROLL); // find the rectangle that bounds all visible child windows SetRectEmpty(&rcScroll); for (pwndT = REBASEPWND(pwnd, spwndChild); pwndT; pwndT = REBASEPWND(pwndT, spwndNext)) { if (fIgnoreMin && TestWF(pwndT, WFMINIMIZED)) continue; if (TestWF(pwndT,WFVISIBLE)) { if (TestWF(pwndT, WFMAXIMIZED)) { fNeedScrolls = FALSE; break; } /* * add this window to the area that has to be visible */ UnionRect(&rcScroll, &rcScroll, KPRECT_TO_PRECT(&pwndT->rcWindow)); /* * add scroll bars if its not contained in the * client area */ UnionRect(&rcT, &rcClient, KPRECT_TO_PRECT(&pwndT->rcWindow)); if (!EqualRect(&rcClient, &rcT)) { fNeedScrolls = TRUE; } } } SetRectEmpty(&rcRange); // offset rectangles such that rcClient's top & left are both 0 // making rcClient's right & bottom be the page size _ScreenToClient(pwnd, (LPPOINT)&rcScroll.left); _ScreenToClient(pwnd, (LPPOINT)&rcScroll.right); /* * Swap the left and right if pwnd is a mirrored window. */ if (TestWF(pwnd, WEFLAYOUTRTL)) { int nSaveLeft; nSaveLeft = rcScroll.left; rcScroll.left = rcScroll.right; rcScroll.right = nSaveLeft; } OffsetRect(&rcClient, -rcClient.left, -rcClient.top); if (!fNeedScrolls) rcClient.bottom = rcClient.right = 0; else do { /* * the range is the union of the parent client with all of its * children */ CopyRect(&rcT, &rcRange); UnionRect(&rcRange, &rcScroll, &rcClient); if (fCheckVert) { // subtract off space for the vertical scroll if we need it if (((rcRange.bottom - rcRange.top) > rcClient.bottom) && !fVert) { fVert = TRUE; rcClient.right -= SYSMET(CXVSCROLL); } } if (fCheckHorz) { // subtract off space for the horizontal scroll if we need it if (((rcRange.right - rcRange.left) > rcClient.right) && !fHorz) { fHorz = TRUE; rcClient.bottom -= SYSMET(CYHSCROLL); } } } while (!EqualRect(&rcRange, &rcT)); if (fNeedScrolls) { // HACK of death beginning if (rcRange.right == rcClient.right) rcRange.right -= 8; if (rcRange.bottom == rcClient.bottom) rcRange.bottom -= 8; // HACK of death ending } if (fCheckVert) { /* * check to see if we are changing the presence of the vertical * scrollbar */ if ((rcRange.bottom - rcRange.top) <= rcClient.bottom) { ClearWindowState(pwnd, WFVSCROLL); } else { SetWindowState(pwnd, WFVSCROLL); } } if (fCheckHorz) { /* * same for horizontal scroll */ if ((rcRange.right - rcRange.left) <= rcClient.right) { ClearWindowState(pwnd, WFHSCROLL); } else { SetWindowState(pwnd, WFHSCROLL); } } if (fNeedScrolls) { ByteOutsetRect(&rcClient); ByteOutsetRect(&rcRange); } si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_ALL; si.nPos = 0; si.nMin = rcRange.left; si.nMax = rcRange.right; si.nPage = rcClient.right; SetScrollInfo(hwnd, SB_HORZ, &si, FALSE); si.nMin = rcRange.top; si.nMax = rcRange.bottom; si.nPage = rcClient.bottom; SetScrollInfo(hwnd, SB_VERT, &si, FALSE); if ((fHadVert != TestWF(pwnd, WFVSCROLL)) || (fHadHorz != TestWF(pwnd, WFHSCROLL))) NtUserRedrawFrame(hwnd); } /***************************************************************************\ * ScrollChildren * * Handles WM_VSCROLL and WM_HSCROLL messages * * History: * 11-14-90 MikeHar Ported from windows \***************************************************************************/ void ScrollMDIChildren( HWND hwnd, int nCtl, UINT wCmd, int iThumbPos) { SCROLLINFO si; int wInc; int wNewPos; //SHORT sPos; int x, y; wInc = (((nCtl == SB_VERT) ? SYSMET(CYSIZE) : SYSMET(CXSIZE)) + 7) / 8; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_ALL; GetScrollInfo(hwnd, nCtl, &si); si.nPage--; si.nMax -= si.nPage; switch (wCmd) { case SB_BOTTOM: wNewPos = si.nMax; break; case SB_TOP: wNewPos = si.nMin; break; case SB_LINEDOWN: wNewPos = si.nPos + wInc; break; case SB_LINEUP: wNewPos = si.nPos - wInc; break; case SB_PAGEDOWN: wNewPos = si.nPos + si.nPage; break; case SB_PAGEUP: wNewPos = si.nPos - si.nPage; break; case SB_THUMBPOSITION: wNewPos = iThumbPos; break; case SB_ENDSCROLL: CalcClientScrolling(hwnd, (nCtl == SB_VERT) ? SBJ_VERT : SBJ_HORZ, FALSE); /* ** FALL THRU ** */ default: return; } if (wNewPos < si.nMin) wNewPos = si.nMin; else if (wNewPos > si.nMax) wNewPos = si.nMax; SetScrollPos(hwnd, nCtl, wNewPos, TRUE); // the "* 8" is because we need to scroll in bytes. The scrollbar // increments for MDI are bytes (this is due to the fact that we need to // not upset the brush origin of the app workspace brush that is used to // fill the MDI background) x = (si.nPos - wNewPos) * 8; if (nCtl == SB_VERT) { y = x; x = 0; } else // x is already set properly for this case y = 0; NtUserScrollWindowEx(hwnd, x, y, NULL, NULL, NULL, NULL, SW_SCROLLWINDOW | SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN); } FUNCLOGVOID3(LOG_GENERAL, DUMMYCALLINGTYPE, ScrollChildren, HWND, hwnd, UINT, wMsg, DWORD, wParam) VOID ScrollChildren( HWND hwnd, UINT wMsg, DWORD wParam) { ScrollMDIChildren(hwnd, wMsg == WM_VSCROLL ? SB_VERT : SB_HORZ, LOWORD(wParam), (short)(HIWORD(wParam))); } /***************************************************************************\ * RecalculateScrollRanges * * History: * 11-14-90 MikeHar Ported from windows * 04-16-91 MikeHar Win31 Merge \***************************************************************************/ VOID RecalculateScrollRanges( PWND pwndParent, BOOL fIgnoreMin) { PMDI pmdi = ((PMDIWND)pwndParent)->pmdi; if (!(SCROLL(pmdi) & (CALCSCROLL | SCROLLCOUNT))) { if (PostMessage(HWq(pwndParent), MM_CALCSCROLL, fIgnoreMin, 0L)) { SCROLL(pmdi) |= CALCSCROLL; } } } /***************************************************************************\ * GetCascadeWindowPos * * History: * 11-14-90 MikeHar Ported from windows * 01-12-94 FritzS Ported from Chicago \***************************************************************************/ VOID GetCascadeWindowPos( LPCRECT prcClient, /* area to arrange to */ int iWindow, /* index of this window */ LPRECT lprc) /* resulting rectangle */ { int cStack; int xStep, yStep; int dxClient, dyClient; /* * Compute the width and breadth of the situation. */ dxClient = prcClient->right - prcClient->left; UserAssert(dxClient >= 0); dyClient = prcClient->bottom - prcClient->top; UserAssert(dyClient >= 0); /* * Compute the width and breadth of the window steps. */ xStep = SYSMET(CXSIZEFRAME) + SYSMET(CXSIZE); yStep = SYSMET(CYSIZEFRAME) + SYSMET(CYSIZE); /* * How many windows per stack? */ cStack = dyClient / (3 * yStep); lprc->right = dxClient - (cStack * xStep); lprc->bottom = dyClient - (cStack * yStep); /* * HACK!: Mod by cStack+1 and make sure no div-by-zero * exception happens. */ if (++cStack <= 0) { cStack = 1; } lprc->left = prcClient->left + (iWindow % cStack) * xStep; lprc->top = prcClient->top + (iWindow % cStack) * yStep; } /***************************************************************************\ * MDICheckCascadeRect * * History: * 11-14-90 MikeHar Ported from windows * 04-16-91 MikeHar Win31 Merge \***************************************************************************/ VOID MDICheckCascadeRect( PWND pwndClient, LPRECT lprc) { PMDI pmdi; RECT rc, rcClient; int iWindow; /* * Get a pointer to the MDI structure */ pmdi = ((PMDIWND)pwndClient)->pmdi; iWindow = ITILELEVEL(pmdi); GetRect(pwndClient, &rcClient, GRECT_CLIENT | GRECT_CLIENTCOORDS); GetCascadeWindowPos(&rcClient, iWindow, &rc); if ((lprc->right == CW_USEDEFAULT || lprc->right == CW2_USEDEFAULT) || !(lprc->right)) { lprc->right = rc.right; } if ((lprc->bottom == CW_USEDEFAULT || lprc->bottom == CW2_USEDEFAULT) || !(lprc->bottom)) { lprc->bottom = rc.bottom; } if (lprc->left == CW_USEDEFAULT || lprc->left == CW2_USEDEFAULT) { lprc->left = rc.left; lprc->top = rc.top; } } /***************************************************************************\ * UnMaximizeChildWindows * * effects: Helper routine used by TileChildWindows and CascadeChildWindows to * restore any maximized windows of the given parent. Returns TRUE if a * maximized window was restored. * * History: * 4-16-91 MikeHar Win31 Merge \***************************************************************************/ BOOL UnmaximizeChildWindows( HWND hwndParent) { HWND hwndMove; PWND pwndMove; BOOL fFoundOne = FALSE; BOOL fAsync; UINT chwnd; HWND *phwndList; HWND *phwnd; HWND hwndChild = GetWindow(hwndParent, GW_CHILD); /* * Get the hwnd list. It is returned in a block of memory allocated with * UserLocalAlloc. */ if (hwndChild == NULL || (chwnd = BuildHwndList(NULL, GetWindow(hwndParent, GW_CHILD), FALSE, 0, &phwndList)) == 0) { return FALSE; } fAsync = (hwndParent == GetDesktopWindow()); for (phwnd = phwndList; chwnd > 0; chwnd--, phwnd++) { if ((hwndMove = *phwnd) == NULL) { continue; } if ((pwndMove = ValidateHwnd(hwndMove)) == NULL) { continue; } if (TestWF(pwndMove, WFMAXIMIZED) && TestWF(pwndMove, WFVISIBLE)) { // // If we haven't done it yet, lock the screen to prevent sending // paints for a cleaner update. // if (!fFoundOne && fAsync) { NtUserLockWindowUpdate(hwndParent); } fFoundOne = TRUE; if (fAsync) { NtUserShowWindowAsync(hwndMove, SW_SHOWNOACTIVATE); } else { NtUserShowWindow(hwndMove, SW_SHOWNORMAL); } } } UserLocalFree(phwndList); if (fFoundOne && fAsync) { HWND hwndActive = NtUserGetForegroundWindow(); if (hwndActive != NULL) { /* * Hack! Since the above showwindows cause zorder changes, we want * the active window to be in front. This makes sure... */ NtUserSetWindowPos(hwndActive, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_ASYNCWINDOWPOS); } NtUserLockWindowUpdate(NULL); RedrawWindow(hwndParent, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE | RDW_FRAME); } return fFoundOne; } /***************************************************************************\ * * ARRANGEWINDOWSDATA: passed to EnumDisplayMonitors enumeration functions. * \***************************************************************************/ typedef struct tagARRANGEWINDOWSDATA { PWND pwndParent; UINT flags; LPRECT lprcParent; int chwnd; int chwndReal; HWND * phwnd; PWND pwndDesktop; HDWP hdwp; UINT uGRCFlags; int fVerifyParent; } ARRANGEWINDOWSDATA, *PARRANGEWINDOWSDATA; /***************************************************************************\ * ArrangeWindows * * Called from CascadeWindows and TileWindows, it performs what * is common to both functions, and calls out to the enumeration * function to do the work of window arrangement. * * History: * 10-Jul-1997 adams Created. \***************************************************************************/ WORD ArrangeWindows( HWND hwndParent, UINT flags, CONST RECT * lpRect, UINT chwnd, CONST HWND * ahwnd, MONITORENUMPROC lpfnEnum) { ARRANGEWINDOWSDATA awd; HWND * phwnd = NULL; /* * Get parent window */ awd.pwndDesktop = _GetDesktopWindow(); if (!hwndParent) { hwndParent = HW(awd.pwndDesktop); awd.pwndParent = awd.pwndDesktop; } else { awd.pwndParent = ValidateHwnd(hwndParent); if (awd.pwndParent == NULL) { return 0; } } UnmaximizeChildWindows(hwndParent); /* * If the rect passed in contains the desktop window, * arrange the windows on the desktop */ if ( lpRect && awd.pwndParent == awd.pwndDesktop && lpRect->left <= awd.pwndDesktop->rcClient.left && lpRect->top <= awd.pwndDesktop->rcClient.top && lpRect->right >= awd.pwndDesktop->rcClient.right && lpRect->bottom >= awd.pwndDesktop->rcClient.bottom ) { lpRect = NULL; } /* * Arrange iconic windows if appropriate, and determine flags * for getting the client rectangle if no rect is given. */ if (lpRect == NULL) { if ( ( awd.pwndParent != awd.pwndDesktop || !(SYSMET(ARRANGE) & ARW_HIDE)) && NtUserArrangeIconicWindows(hwndParent) != 0) { awd.uGRCFlags = GRC_SCROLLS | GRC_MINWNDS; } else { awd.uGRCFlags = GRC_SCROLLS; } } /* * Get window list */ if (ahwnd == NULL) { HWND hwndChild; PWND pwndChild; pwndChild = REBASEPWND(awd.pwndParent, spwndChild); hwndChild = HW(pwndChild); if ( hwndChild == NULL || (chwnd = BuildHwndList(NULL, hwndChild, FALSE, 0, &phwnd)) == 0) { return 0; } } /* * Arrange windows */ awd.hdwp = NtUserBeginDeferWindowPos(chwnd); if (awd.hdwp == NULL) goto Done; awd.flags = flags; awd.lprcParent = (LPRECT) lpRect; awd.chwnd = chwnd; awd.chwndReal = 0; awd.phwnd = ahwnd ? (HWND *) ahwnd : phwnd; awd.fVerifyParent = (ahwnd != NULL); /* * If the parent is the desktop and a rectangle is not provided, * arrange the windows on each monitor. Otherwise, arrange the * windows once by calling the enumeration function directly. */ if (awd.pwndParent == awd.pwndDesktop && lpRect == NULL) { NtUserEnumDisplayMonitors(NULL, NULL, lpfnEnum, (LPARAM) &awd); } else { (*lpfnEnum)(NULL, NULL, NULL, (LPARAM) &awd); } /* Make this arrangement asynchronous so we don't hang */ if (awd.hdwp != NULL) { NtUserEndDeferWindowPosEx(awd.hdwp, TRUE); } Done: if (phwnd) { UserLocalFree(phwnd); } return (awd.hdwp != NULL) ? awd.chwndReal : 0; } /***************************************************************************\ * GetParentArrangeRect * * Returns the rect passed in pawd if provided, otherwise gets the client * rect of the parent window. * * History: * 10-Jul-1997 adams Created. \***************************************************************************/ VOID GetParentArrangeRect( PARRANGEWINDOWSDATA pawd, PMONITOR pMonitor, LPRECT lprc) { UINT uGRCFlags; if (pawd->lprcParent) { *lprc = *pawd->lprcParent; } else { uGRCFlags = pawd->uGRCFlags; /* * If icons are shown on the desktop, then they are always * shown on the primary monitor. So remove the GRC_MINWNDS * flag for monitors other than the primary. */ if (pMonitor && pMonitor != GetPrimaryMonitor()) { uGRCFlags &= ~GRC_MINWNDS; } GetRealClientRect( pawd->pwndParent, lprc, uGRCFlags, pMonitor); } } /***************************************************************************\ * ValidatePositionableWindow * * Validates and returns a window if it is positionable, and sets * the appropriate sizing flags. * * History: * 10-Jul-1997 adams Created. \***************************************************************************/ PWND ValidatePositionableWindow( HWND hwndChild, PWND pwndParent, PWND pwndDesktop, DWORD dwMDIFlags, PMONITOR pMonitor, DWORD * pdwSWPFlags) { PWND pwndChild; pwndChild = ValidateHwnd(hwndChild); if (pwndChild) { if (pwndParent && REBASEPWND(pwndChild, spwndParent) != pwndParent) { RIPMSG0(RIP_WARNING, "Cascade/Tile Windows: Windows in list must have same parent"); } else if ( /* * mikesch - removed the maximized check since the call * to restore maximized windows in unmaximizechildwindows occurs * asynchronously now. */ TestWF(pwndChild, WFVISIBLE) && TestWF(pwndChild, WFCPRESENT) && !TestWF(pwndChild, WFMINIMIZED) && !TestWF(pwndChild, WEFTOPMOST) && (!(dwMDIFlags & MDITILE_SKIPDISABLED) || !TestWF(pwndChild, WFDISABLED)) && !TestWF(pwndChild, WEFTOOLWINDOW) && ((pMonitor) ? (pMonitor == _MonitorFromWindow(pwndChild, MONITOR_DEFAULTTONULL)) : (pwndParent != pwndDesktop || _MonitorFromWindow(pwndChild, MONITOR_DEFAULTTONULL)))) { if (pdwSWPFlags) { *pdwSWPFlags = SWP_NOACTIVATE | SWP_NOCOPYBITS; if (!TestWF(pwndChild, WFSIZEBOX)) { *pdwSWPFlags |= SWP_NOSIZE; } if (!(dwMDIFlags & MDITILE_ZORDER)) { *pdwSWPFlags |= SWP_NOZORDER; } } return pwndChild; } } return NULL; } /***************************************************************************\ * CascadeWindowsEnum * * Cascades windows on the monitor. * * History: * 10-Jul-1997 adams Created. \***************************************************************************/ BOOL CALLBACK CascadeWindowsEnum( HMONITOR hmonitor, HDC hdc, LPRECT lprc, LPARAM lparam) { PARRANGEWINDOWSDATA pawd = (PARRANGEWINDOWSDATA)lparam; PMONITOR pMonitor = hmonitor ? VALIDATEHMONITOR(hmonitor) : NULL; RECT rcParent; int i; int chwndReal = 0; RECT rc; HWND * phwnd, * phwndCopy; BOOL fRet = TRUE; UNREFERENCED_PARAMETER(hdc); UNREFERENCED_PARAMETER(lprc); /* * Get the parent rectangle if none is given. */ GetParentArrangeRect(pawd, pMonitor, &rcParent); /* * New for NT5: MDITILE_ZORDER (for the SHELL guys) * Sort pawd->phwnd by z-order */ if (pawd->flags & MDITILE_ZORDER) { PWND pwndChild; HWND * phwndFullList, * phwndNext, * phwndSort, * phwndSearch; int chwndFullList, chwndSort, chwndSearch; /* * Make a copy to leave their array alone (it's supposed to be const) */ phwndCopy = UserLocalAlloc(0, pawd->chwnd * sizeof(HWND)); if (phwndCopy == NULL) { return FALSE; } RtlCopyMemory(phwndCopy, pawd->phwnd, pawd->chwnd * sizeof(HWND)); /* * Get the sibblings Z-Ordered list. */ pwndChild = REBASEPWND(pawd->pwndParent, spwndChild); if (pwndChild == NULL) { fRet = FALSE; goto CleanUp; } chwndFullList = BuildHwndList(NULL, HWq(pwndChild), FALSE, 0, &phwndFullList); if (chwndFullList == 0) { fRet = FALSE; goto CleanUp; } /* * Loop through the Z-Ordered list looking for the windows in the array */ for (phwndNext = phwndFullList, chwndSort = pawd->chwnd, phwndSort = phwndCopy; (chwndFullList > 0) && (chwndSort > 1); chwndFullList--, phwndNext++) { for (chwndSearch = chwndSort, phwndSearch = phwndSort; chwndSearch > 0; chwndSearch--, phwndSearch++) { /* * If it found a window, move it after the last sorted window. */ if (*phwndNext == *phwndSearch) { HWND hwndFirst = *phwndSort; *phwndSort = *phwndSearch; *phwndSearch = hwndFirst; phwndSort++; chwndSort--; break; } } } UserLocalFree(phwndFullList); } else { /* if (pawd->flags & MDITILE_ZORDER) */ phwndCopy = pawd->phwnd; } /* * Arrange the windows in the list, preserving z-order. */ for (i = pawd->chwnd, phwnd = phwndCopy + i - 1; --i >= 0; phwnd--) { HWND hwndChild; PWND pwndChild = NULL; DWORD dwSWPFlags; hwndChild = *phwnd; pwndChild = ValidatePositionableWindow( hwndChild, pawd->fVerifyParent ? pawd->pwndParent : NULL, pawd->pwndDesktop, pawd->flags, pMonitor, &dwSWPFlags); if (!pwndChild) continue; GetCascadeWindowPos(&rcParent, chwndReal, &rc); pawd->hdwp = NtUserDeferWindowPos( pawd->hdwp, hwndChild, HWND_TOP, rc.left, rc.top, rc.right, rc.bottom, dwSWPFlags); chwndReal++; pawd->chwndReal++; } CleanUp: if (pawd->flags & MDITILE_ZORDER) { UserLocalFree(phwndCopy); } return fRet && (pawd->hdwp != NULL); } /***************************************************************************\ * * CascadeWindows() * * Cascades a list of children within a parent, according to the flags and * the rectangle passed in. * \***************************************************************************/ WORD CascadeWindows( HWND hwndParent, UINT flags, CONST RECT *lpRect, UINT chwnd, CONST HWND *ahwnd) { return ArrangeWindows(hwndParent, flags, lpRect, chwnd, ahwnd, CascadeWindowsEnum); } BOOL CALLBACK TileWindowsEnum( HMONITOR hmonitor, HDC hdc, LPRECT lprc, LPARAM lparam) { PARRANGEWINDOWSDATA pawd = (PARRANGEWINDOWSDATA)lparam; PMONITOR pMonitor = hmonitor ? VALIDATEHMONITOR(hmonitor) : NULL; RECT rcParent; int ihwnd; int chwndReal; int square; int iCol, iRow; int cCol, cRow; int cRem; int dx, dy; int xRes, yRes; UNREFERENCED_PARAMETER(hdc); UNREFERENCED_PARAMETER(lprc); /* * Get the parent rectangle if none is given. */ GetParentArrangeRect(pawd, pMonitor, &rcParent); /* * Now, figure out how many REAL windows we have. */ chwndReal = 0; for (ihwnd = pawd->chwnd; --ihwnd >= 0;) { if (ValidatePositionableWindow( pawd->phwnd[ihwnd], pawd->fVerifyParent ? pawd->pwndParent : NULL, pawd->pwndDesktop, pawd->flags, pMonitor, NULL)) { chwndReal++; } } if (chwndReal == 0) return TRUE; xRes = rcParent.right - rcParent.left; yRes = rcParent.bottom - rcParent.top; if (xRes <= 0 || yRes <= 0) return TRUE; /* * Compute nearest least square */ for (square = 2; square * square <= chwndReal; square++) { /* do nothing */; } if (pawd->flags & MDITILE_HORIZONTAL) { cCol = square - 1; cRow = chwndReal / cCol; cRem = chwndReal % cCol; } else { cRow = square - 1; cCol = chwndReal / cRow; cRem = chwndReal % cRow; } chwndReal = 0; ihwnd = -1; for (iCol = 0; iCol < cCol; iCol++) { /* * Add one extra row to handle the remainders. */ if (cCol - iCol <= cRem) { cRow++; } for (iRow = 0; iRow < cRow; iRow++) { HWND hwndChild; PWND pwndChild; DWORD dwSWPFlags; dx = xRes / cCol; dy = yRes / cRow; NextWindow: /* * Skip bogus and nonpositionable windows. */ ihwnd++; if (ihwnd >= pawd->chwnd) { return TRUE; } hwndChild = pawd->phwnd[ihwnd]; pwndChild = ValidatePositionableWindow( hwndChild, pawd->fVerifyParent ? pawd->pwndParent : NULL, pawd->pwndDesktop, pawd->flags, pMonitor, &dwSWPFlags); if (!pwndChild) { goto NextWindow; } /* * Move, size the window. */ pawd->hdwp = NtUserDeferWindowPos(pawd->hdwp, hwndChild, HWND_TOP, rcParent.left + iCol*dx, rcParent.top + iRow*dy, dx, dy, dwSWPFlags); if (pawd->hdwp == NULL) { return FALSE; } chwndReal++; pawd->chwndReal++; } if (cCol - iCol <= cRem) { cRow--; cRem--; } } return TRUE; } /***************************************************************************\ * * TileWindows() * * Tiles a list of children within a parent, according to the flags and * the rectangle passed in. * \***************************************************************************/ WORD TileWindows( HWND hwndParent, UINT flags, CONST RECT *lpRect, UINT chwnd, CONST HWND *ahwnd) { return ArrangeWindows(hwndParent, flags, lpRect, chwnd, ahwnd, TileWindowsEnum); } /***************************************************************************\ * xxxMDIActivate * * History: * 11-14-90 MikeHar Ported from windows * 4-16-91 MikeHar Win31 Merge \***************************************************************************/ VOID xxxMDIActivate( PWND pwnd, PWND pwndActivate) { HWND hwndOld; PWND pwndOld; PMDI pmdi; BOOL fShowActivate; UINT nID; TL tlpwnd; TL tlpwndOld; PWND pwndT; HWND hwnd = HWq(pwnd); HWND hwndActivate = HW(pwndActivate); CheckLock(pwnd); CheckLock(pwndActivate); /* * Get a pointer to the MDI structure */ pmdi = ((PMDIWND)pwnd)->pmdi; if (ACTIVE(pmdi) == hwndActivate) return; if ((pwndActivate != NULL) && (TestWF(pwndActivate, WFDISABLED))) { /* * Don't even try activating disabled or invisible windows. */ return; } pwndT = REBASEPWND(pwnd, spwndParent); fShowActivate = (HW(pwndT) == NtUserQueryWindow(hwnd, WindowActiveWindow)); hwndOld = ACTIVE(pmdi); if (hwndOld && (pwndOld = ValidateHwnd(hwndOld)) == NULL) { hwndOld = NULL; } ThreadLock(pwndOld, &tlpwndOld); if (hwndOld) { /* * Attempt to deactivate the MDI child window. * The MDI child window can fail deactivation by returning FALSE. * But this only applies if the MDI frame is the active window * and the app is a 3.1 app or later */ if (!SendMessage(hwndOld, WM_NCACTIVATE, FALSE, 0L) && fShowActivate) { if (TestWF(pwndOld, WFWIN31COMPAT)) goto UnlockOld; } if (!TestWF(pwndOld, WFWIN31COMPAT) && TestWF(pwndOld, WFFRAMEON)) { /* * Error: Quicken for Windows is sort of bogus. They try to fail * the WM_NCACTIVATE of their newly created window by not passing * it to DefWindowProc. Bug 6412. WM_NCACTIVATE sets/unsets the * WFFRAMEON bit if passed to DWP so we can double check things * here. */ goto UnlockOld; } SendMessage(hwndOld, WM_MDIACTIVATE, (WPARAM)hwndOld, (LPARAM)hwndActivate); /* * Uncheck the old window menu entry. */ if (WINDOW(pmdi)) CheckMenuItem(WINDOW(pmdi), PtrToUlong(pwndOld->spmenu), MF_BYCOMMAND | MF_UNCHECKED); } // // Handle switching to a new (or NO) maximized window. If NO window is // to become maximized, because we're activating NULL or the window to // become active doesn't have a WS_MAXIMIZEBOX, restore the old one to // it's normal size to clean up the MDI maximized menubar mess // if (MAXED(pmdi) && MAXED(pmdi) != hwndActivate) { HWND hwndMax; int iShowCode; // The MAXBOX check is a new thing for 4.0 dudes; it breaks 3.x apps. // See comment in the WM_MDIMAXIMIZE handling. if (pwndActivate && (TestWF(pwndActivate, WFMAXBOX) || !TestWF(pwndActivate, WFWIN40COMPAT))) { hwndMax = hwndActivate; iShowCode = SW_SHOWMAXIMIZED; Lock(&ACTIVE(pmdi), hwndMax); } else { hwndMax = MAXED(pmdi); iShowCode = SW_SHOWNORMAL; } // overload WFFULLSCREEN bit -- useless for child windows anyways // use it to indicate to min/max code to not animate size change. // NO -- no bit overloading. FritzS NtUserCallHwndParam(hwndMax, WFNOANIMATE, SFI_SETWINDOWSTATE); NtUserShowWindow(hwndMax, iShowCode); NtUserCallHwndParam(hwndMax, WFNOANIMATE, SFI_CLEARWINDOWSTATE); } Lock(&ACTIVE(pmdi), hwndActivate); /* * We may be removing the activation entirely... */ if (!pwndActivate) { if (fShowActivate) NtUserSetFocus(hwnd); goto UnlockOld; } if (WINDOW(pmdi)) { /* * Check the new window menu entry. */ nID = GetWindowID(ACTIVE(pmdi)); if (nID - FIRST(pmdi) < (MAXITEMS - 1)) { CheckMenuItem(WINDOW(pmdi), nID, MF_BYCOMMAND | MFS_CHECKED); } else { /* * the item is not in the menu at all! Swap it with number 9. */ PWND pwndOther = FindPwndChild(pwnd, (UINT)(FIRST(pmdi) + MAXITEMS - 2)); SetWindowLongPtr(HW(pwndOther), GWLP_ID, PtrToLong(pwndActivate->spmenu)); SetWindowLongPtr(hwndActivate, GWLP_ID, FIRST(pmdi) + MAXITEMS - 2); ModifyMenuItem(pwndActivate); } } /* * Bring the window to the top. */ NtUserSetWindowPos(ACTIVE(pmdi), NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); /* * Update the Caption bar. Don't muck with styles for 3.1. */ if (fShowActivate) { SendMessage(ACTIVE(pmdi), WM_NCACTIVATE, TRUE, 0L); ThreadLock(pwnd, &tlpwnd); if (hwnd == NtUserQueryWindow(hwnd, WindowFocusWindow)) SendMessage(hwnd, WM_SETFOCUS, (WPARAM)hwnd, 0); else NtUserSetFocus(hwnd); ThreadUnlock(&tlpwnd); } /* * Notify the new active window of his activation. */ SendMessage(ACTIVE(pmdi), WM_MDIACTIVATE, (WPARAM)hwndOld, (LPARAM)hwndActivate); UnlockOld: ThreadUnlock(&tlpwndOld); } /***************************************************************************\ * xxxMDINext * * History: * 11-14-90 MikeHar Ported from windows * 4-16-91 MikeHar Win31 Merge \***************************************************************************/ VOID xxxMDINext( PWND pwndMDI, PWND pwnd, BOOL fPrevWindow) { PMDI pmdi; PWND pwndNextGuy; HDWP hdwp; BOOL fHack = FALSE; CheckLock(pwndMDI); CheckLock(pwnd); /* * Get a pointer to the MDI structure */ pmdi = ((PMDIWND)pwndMDI)->pmdi; pwndNextGuy = pwnd; while (TRUE) { if (fPrevWindow) pwndNextGuy = _GetWindow(pwndNextGuy, GW_HWNDPREV); else pwndNextGuy = REBASEPWND(pwndNextGuy, spwndNext); if (!pwndNextGuy) { if (fPrevWindow) { pwndNextGuy = _GetWindow(pwnd, GW_HWNDLAST); } else { pwndNextGuy = REBASEPWND(pwndMDI, spwndChild); } } if (pwndNextGuy == pwnd) return; // // Ignore hidden and disabled windows. // if (TestWF(pwndNextGuy, WFVISIBLE) && !TestWF(pwndNextGuy, WFDISABLED)) break; } if (MAXED(pmdi)) { NtUserSetVisible(HWq(pwndMDI), SV_UNSET | SV_CLRFTRUEVIS); fHack = TRUE; } hdwp = NtUserBeginDeferWindowPos(2); /* * activate the new window (first, in case of maximized windows) */ hdwp = NtUserDeferWindowPos(hdwp, HW(pwndNextGuy), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); // LATER 30-Mar-1992 mikeke // this used to be _GetWindow(pwndMDI->spwndChild, GW_HWNDLAST) // instead of HWND_BOTTOM if (hdwp && !fPrevWindow && (pwnd != pwndNextGuy)) hdwp = NtUserDeferWindowPos(hdwp, HW(pwnd), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE ); NtUserEndDeferWindowPosEx(hdwp, FALSE); if (fHack) { NtUserShowWindow(HWq(pwndMDI), SW_SHOW); } } FUNCLOG10(LOG_GENERAL, HWND, DUMMYCALLINGTYPE, CreateMDIWindowA, LPCSTR, pClassName, LPCSTR, pWindowName, DWORD, dwStyle, int, x, int, y, int, nWidth, int, nHeight, HWND, hwndParent, HINSTANCE, hModule, LPARAM, lParam) HWND CreateMDIWindowA( LPCSTR pClassName, LPCSTR pWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hwndParent, HINSTANCE hModule, LPARAM lParam) { return CreateWindowExA(WS_EX_MDICHILD, pClassName, pWindowName, dwStyle, x, y, nWidth, nHeight, hwndParent, NULL, hModule, (LPVOID)lParam); } FUNCLOG10(LOG_GENERAL, HWND, DUMMYCALLINGTYPE, CreateMDIWindowW, LPCWSTR, pClassName, LPCWSTR, pWindowName, DWORD, dwStyle, int, x, int, y, int, nWidth, int, nHeight, HWND, hwndParent, HINSTANCE, hModule, LPARAM, lParam) HWND CreateMDIWindowW( LPCWSTR pClassName, LPCWSTR pWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hwndParent, HINSTANCE hModule, LPARAM lParam) { return CreateWindowExW(WS_EX_MDICHILD, pClassName, pWindowName, dwStyle, x, y, nWidth, nHeight, hwndParent, NULL, hModule, (LPVOID)lParam); } /***************************************************************************\ * xxxMDIDestroy * * History: * 11-14-90 MikeHar Ported from windows * 4-16-91 MikeHar Win31 Merge \***************************************************************************/ VOID xxxMDIDestroy( PWND pwnd, HWND hwndVictim) { PWND pwndVictim; TL tlpwndParent; PMDI pmdi; PWND pwndParent; HWND hwnd; CheckLock(pwnd); if ((pwndVictim = ValidateHwnd(hwndVictim)) == NULL) { return; } CheckLock(pwndVictim); /* * Get a pointer to the MDI structure */ pmdi = ((PMDIWND)pwnd)->pmdi; #ifdef NEVER // don't do this validation - because it sometimes doesn't work! If an // app passed in idFirstChild (through CLIENTCREATESTRUCT) as -1, this // code fails because it treats the id comparisons as unsigned compares. // Change them to signed compares and it still doesn't work. That is because // when ShiftMenuIDs() is called, you'll shift mdi windows out of the signed // comparison range and this check won't allow them to be destroyed. This // is straight win3.1 code. // /* * Validate that this is one of the mdi children we are keeping track * of. If it isn't don't destroy it because it'll get mdi id tracking * code all messed up. */ if (((UINT)pwndVictim->spmenu) < FIRST(pmdi) || ((UINT)pwndVictim->spmenu) >= (UINT)(FIRST(pmdi) + CKIDS(pmdi)) || pwndVictim->spwndOwner != NULL) { RIPERR0(ERROR_NON_MDICHILD_WINDOW, RIP_VERBOSE, ""); return; } #endif ShiftMenuIDs(pwnd, pwndVictim); /* * First Activate another window. */ if (SAMEWOWHANDLE(hwndVictim, ACTIVE(pmdi))) { xxxMDINext(pwnd, pwndVictim, FALSE); /* * Destroying only child? */ if (SAMEWOWHANDLE(hwndVictim, ACTIVE(pmdi))) { NtUserShowWindow(hwndVictim, SW_HIDE); /* * If the window is maximized, we need to remove his sys menu * now otherwise it may get deleted twice. Once when the child * is destroyed and once when the frame is destroyed. */ if (MAXED(pmdi)) { pwndParent = REBASEPWND(pwnd, spwndParent); MDIRemoveSysMenu(PtoH(REBASE(pwndParent,spmenu)), MAXED(pmdi)); Unlock(&MAXED(pmdi)); ThreadLock(pwndParent, &tlpwndParent); xxxSetFrameTitle(pwndParent, pwnd, (LPWSTR)1L); /* * Redraw frame so menu bar shows the removed sys menu stuff */ if (TestWF(pwndParent, WFVISIBLE)) NtUserRedrawFrame(HWq(pwndParent)); ThreadUnlock(&tlpwndParent); } xxxMDIActivate(pwnd, NULL); } } /* * Don't ever let this go negative or we'll get caught in long loops. */ CKIDS(pmdi)--; if ((int)CKIDS(pmdi) < 0) CKIDS(pmdi) = 0; hwnd = HWq(pwnd); SendMessage(hwnd, WM_MDIREFRESHMENU, 0L, 0L); /* * Destroy the window. */ NtUserDestroyWindow(hwndVictim); /* * During the DestroyWindow the parent may also have been deleted * Remove revalidate if we get client side locking */ if (ValidateHwnd(hwnd) == NULL) return; /* * Deleting a window can change the scroll ranges. */ RecalculateScrollRanges(pwnd, FALSE); } /***************************************************************************\ * MDIClientWndProc * * History: * 11-14-90 MikeHar Ported from windows \***************************************************************************/ LRESULT MDIClientWndProcWorker( PWND pwnd, UINT message, WPARAM wParam, LPARAM lParam, DWORD fAnsi) { HWND hwnd = HWq(pwnd); HWND hwndT; PWND pwndT; TL tlpwndT; PMDI pmdi; PWND pwndParent; CheckLock(pwnd); VALIDATECLASSANDSIZE(pwnd, FNID_MDICLIENT); /* * Get the pmdi for the given window now since we will use it a lot in * various handlers. This was stored using SetWindowLong(hwnd,4,pmdi) when * we initially created the MDI client window. */ pmdi = ((PMDIWND)pwnd)->pmdi; if (pmdi == NULL) { switch (message) { case WM_MDICREATE: case WM_MDIMAXIMIZE: case WM_PARENTNOTIFY: case WM_CREATE: /* * These messages are safe to call, even when pmdi has not already * been initialized. */ break; default: /* * Any message that is not listed above is not safe to call when * pmdi has not been initialized. Instead, just directly call DWP. */ goto CallDWP; } } switch (message) { case WM_NCACTIVATE: /* * We are changing app activation. Fix the active child's caption. */ if (ACTIVE(pmdi) != NULL) { SendMessage(ACTIVE(pmdi), WM_NCACTIVATE, wParam, lParam); } goto CallDWP; case WM_MDIGETACTIVE: if (lParam != 0) { *((LPBOOL)lParam) = (MAXED(pmdi) != NULL); } return (LRESULT)ACTIVE(pmdi); case WM_MDIACTIVATE: hwndT = (HWND)wParam; if ((pwndT = ValidateHwnd(hwndT)) == NULL) return 0; if (SAMEWOWHANDLE(hwndT, ACTIVE(pmdi))) break; NtUserSetWindowPos(hwndT, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); break; case WM_MDICASCADE: pmdi->wScroll |= SCROLLSUPPRESS; NtUserShowScrollBar(hwnd, SB_BOTH, FALSE); /* * Unmaximize any maximized window. */ #ifdef NEVER // Not in Chicago -- FritzS if (MAXED(pmdi) != NULL) { NtUserShowWindow(MAXED(pmdi), SW_SHOWNORMAL); } #endif /* * Save success/failure code to return to app */ message = (UINT)CascadeWindows(hwnd, (UINT)wParam, NULL, 0, NULL); pmdi->wScroll &= ~SCROLLCOUNT; return (LONG)message; break; case WM_VSCROLL: case WM_HSCROLL: pmdi->wScroll |= SCROLLSUPPRESS; ScrollMDIChildren(hwnd, (message == WM_VSCROLL) ? SB_VERT : SB_HORZ, LOWORD(wParam), (short)(HIWORD(wParam))); pmdi->wScroll &= ~SCROLLCOUNT; break; case WM_MDICREATE: { LPMDICREATESTRUCTA lpMCSA = (LPMDICREATESTRUCTA)lParam; LPMDICREATESTRUCTW lpMCSW = (LPMDICREATESTRUCTW)lParam; DWORD exStyle = WS_EX_MDICHILD; /* * inherit the right.to.leftness of the parent. */ exStyle |= (pwnd->ExStyle & (WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR)); if (fAnsi) { hwndT = CreateWindowExA(exStyle, lpMCSA->szClass, lpMCSA->szTitle, lpMCSA->style, lpMCSA->x, lpMCSA->y, lpMCSA->cx, lpMCSA->cy, hwnd, NULL, lpMCSA->hOwner, (LPSTR)lpMCSA->lParam); } else { hwndT = CreateWindowExW(exStyle, lpMCSW->szClass, lpMCSW->szTitle, lpMCSW->style, lpMCSW->x, lpMCSW->y, lpMCSW->cx, lpMCSW->cy, hwnd, NULL, lpMCSW->hOwner, (LPWSTR)lpMCSW->lParam); } return((LRESULT)hwndT); } case WM_MDIDESTROY: xxxMDIDestroy(pwnd, (HWND)wParam); break; case WM_MDIMAXIMIZE: hwndT = (HWND)wParam; if ((pwndT = ValidateHwnd(hwndT)) == NULL) return 0; // Only maximize children with a MAXBOX. However, this introduces // backwards-compatibility issues with VB apps (see#12211) // So, we do this only for WIN40COMPAT apps and beyond. // if ((TestWF(pwndT, WFMAXBOX)) || !(TestWF(pwndT, WFWIN40COMPAT))) { NtUserShowWindow(hwndT, SW_SHOWMAXIMIZED); } break; case WM_MDIRESTORE: hwndT = (HWND)wParam; if ((pwndT = ValidateHwnd(hwndT)) == NULL) return 0; NtUserShowWindow(hwndT, SW_SHOWNORMAL); break; case WM_MDITILE: pmdi->wScroll |= SCROLLSUPPRESS; NtUserShowScrollBar(hwnd, SB_BOTH, FALSE); /* * Unmaximize any maximized window. */ #ifdef NEVER //Not in Chicago if (MAXED(pmdi) != NULL) { NtUserShowWindow(MAXED(pmdi), SW_SHOWNORMAL); } #endif /* * Save success/failure code to return to app */ message = (UINT)TileWindows(hwnd, (UINT)wParam, NULL, 0, NULL); pmdi->wScroll &= ~SCROLLCOUNT; return (LONG)message; break; case WM_MDIICONARRANGE: pmdi->wScroll |= SCROLLSUPPRESS; NtUserArrangeIconicWindows(hwnd); pmdi->wScroll &= ~SCROLLCOUNT; RecalculateScrollRanges(pwnd, TRUE); break; case WM_MDINEXT: if (wParam) { hwndT = (HWND)wParam; } else { hwndT = ACTIVE(pmdi); } if ((pwndT = ValidateHwnd(hwndT)) == NULL) { return 0; } /* * If lParam is 1, do a prev window instead of a next window */ ThreadLockAlways(pwndT, &tlpwndT); xxxMDINext(pwnd, pwndT, (lParam == 0 ? 0 : 1)); ThreadUnlock(&tlpwndT); break; case WM_MDIREFRESHMENU: return (LRESULT)MDISetMenu(pwnd, TRUE, NULL, NULL); case WM_MDISETMENU: return (LRESULT)MDISetMenu(pwnd, FALSE, (HMENU)wParam, (HMENU)lParam); case WM_PARENTNOTIFY: if (wParam == WM_LBUTTONDOWN) { HWND hwndChild; POINT pt; if ((pwndT = ValidateHwnd(hwnd)) == NULL) { return 0; } /* * Activate this child and bring it to the top. */ pt.x = (int)MAKEPOINTS(lParam).x; pt.y = (int)MAKEPOINTS(lParam).y; /* * Since pt is relative to the client MDI window, * then the points should be mirrored if the MDI * client window is mirrored so that Scrren Coord * calculations are done properly in NtUserChildWindowFromPointEx. * [samera] */ if (TestWF(pwndT, WEFLAYOUTRTL)) { pt.x = (pwndT->rcClient.right-pwndT->rcClient.left)-pt.x; } hwndChild = NtUserChildWindowFromPointEx(hwnd, pt, CWP_SKIPDISABLED | CWP_SKIPINVISIBLE); if ((hwndChild) && (hwndChild != hwnd)) { if (hwndChild != ACTIVE(pmdi)) { NtUserSetWindowPos(hwndChild, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); } } } break; case WM_SETFOCUS: if (ACTIVE(pmdi) != NULL && !IsIconic(ACTIVE(pmdi))) { NtUserSetFocus(ACTIVE(pmdi)); } break; case WM_SIZE: if (ACTIVE(pmdi) && (pwndT = ValidateHwnd(ACTIVE(pmdi))) && TestWF(pwndT, WFMAXIMIZED)) { RECT rc; rc.top = rc.left = 0; rc.right = (int)MAKEPOINTS(lParam).x; rc.bottom = (int)MAKEPOINTS(lParam).y; RealAdjustWindowRectEx(&rc, pwndT->style, FALSE, pwndT->ExStyle); NtUserMoveWindow(ACTIVE(pmdi), rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE); } else { RecalculateScrollRanges(pwnd, FALSE); } goto CallDWP; case MM_CALCSCROLL: { if (SCROLL(pmdi) & SCROLLCOUNT) break; { WORD sbj = pmdi->wScroll & (HAS_SBVERT | HAS_SBHORZ); if (sbj) { CalcClientScrolling(hwnd, sbj, (BOOL) wParam); SCROLL(pmdi) &= ~CALCSCROLL; } } break; } case WM_CREATE: { LPCLIENTCREATESTRUCT pccs = ((LPCREATESTRUCT)lParam)->lpCreateParams; /* * Try to allocate space for the pmdi */ if ((pmdi = (PMDI)UserLocalAlloc(HEAP_ZERO_MEMORY, sizeof(MDI)))) { NtUserSetWindowLongPtr(hwnd, GWLP_MDIDATA, (LONG_PTR)pmdi, FALSE); } else { NtUserSetWindowFNID(hwnd, FNID_CLEANEDUP_BIT); break; } pwndParent = REBASEPWND(pwnd, spwndParent); ACTIVE(pmdi) = NULL; MAXED(pmdi) = NULL; CKIDS(pmdi) = 0; WINDOW(pmdi) = pccs->hWindowMenu; FIRST(pmdi) = pccs->idFirstChild; SCROLL(pmdi) = 0; HTITLE(pmdi) = TextAlloc(REBASE(pwndParent, strName.Buffer)); _DefSetText(HW(pwndParent), NULL, FALSE); ThreadLock(pwndParent, &tlpwndT); xxxSetFrameTitle(pwndParent, pwnd, (LPWSTR)2L); ThreadUnlock(&tlpwndT); if (TestWF(pwnd, WFVSCROLL)) SCROLL(pmdi) |= HAS_SBVERT; if (TestWF(pwnd, WFHSCROLL)) SCROLL(pmdi) |= HAS_SBHORZ; if (SCROLL(pmdi)) { ClearWindowState(pwnd, WFVSCROLL | WFHSCROLL); } /* * Set this dude's system menu. */ NtUserGetSystemMenu(HW(pwndParent), FALSE); /* * make sure we have the correct window client area if scrolls are * removed... hack to take care of small progman bug */ if (SCROLL(pmdi)) { NtUserUpdateClientRect(hwnd); } break; } case WM_DESTROY: case WM_FINALDESTROY: if (MAXED(pmdi)) { PWND pwndParent; PMENU pmenu; pwndParent = REBASEPWND(pwnd, spwndParent); pmenu = REBASE(pwndParent, spmenu); MDIRemoveSysMenu(PtoH(pmenu), MAXED(pmdi)); } /* * delete the title */ if (HTITLE(pmdi)) { UserLocalFree(HTITLE(pmdi)); HTITLE(pmdi) = NULL; } /* * Delete the menu items of the child windows in the frame. * Chances are, this is called by destroying the frame, but * one never knows, does one? * * Increase CKIDS by 1 after checking to delete the separator */ if (IsMenu(WINDOW(pmdi)) && CKIDS(pmdi)++) { UINT iPosition; if (CKIDS(pmdi) > MAXITEMS + 1) CKIDS(pmdi) = MAXITEMS + 1; iPosition = GetMenuItemCount(WINDOW(pmdi)); while (CKIDS(pmdi)--) { NtUserDeleteMenu(WINDOW(pmdi), --iPosition, MF_BYPOSITION); } } /* * Unlock those objects that are used by the MDI structure. */ Unlock(&MAXED(pmdi)); Unlock(&ACTIVE(pmdi)); Unlock(&WINDOW(pmdi)); /* * Free the MDI structure */ UserLocalFree(pmdi); NtUserSetWindowFNID(hwnd, FNID_CLEANEDUP_BIT); break; default: CallDWP: return DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi); } return 0L; } /***************************************************************************\ * \***************************************************************************/ LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { PWND pwnd; if ((pwnd = ValidateHwnd(hwnd)) == NULL) { return 0; } return MDIClientWndProcWorker(pwnd, message, wParam, lParam, TRUE); } LRESULT WINAPI MDIClientWndProcW( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { PWND pwnd; if ((pwnd = ValidateHwnd(hwnd)) == NULL) { return 0; } return MDIClientWndProcWorker(pwnd, message, wParam, lParam, FALSE); } /***************************************************************************\ * DefFrameProc * * History: * 11-14-90 MikeHar Ported from windows \***************************************************************************/ LRESULT DefFrameProcWorker( HWND hwnd, HWND hwndMDI, UINT wMsg, WPARAM wParam, LPARAM lParam, BOOL fAnsi) { PWND pwnd; PWND pwndMDI; PMDI pmdi; TL tlpwndT; HWND hwndT; PWND pwndT; PMDINEXTMENU pmnm; WINDOWPLACEMENT wp; if ((pwnd = ValidateHwnd(hwnd)) == NULL) { return (0L); } CheckLock(pwnd); if (hwndMDI == NULL) { goto CallDWP; } if ((pwndMDI = ValidateHwnd(hwndMDI)) == NULL) { return (0L); } CheckLock(pwndMDI); /* * Get a pointer to the MDI structure */ pmdi = ((PMDIWND)pwndMDI)->pmdi; switch (wMsg) { /* * If there is a maximized child window, add it's window text... */ case WM_SETTEXT: { LPWSTR lpwsz = NULL; if (fAnsi && lParam) { if (!MBToWCS((LPSTR)lParam, -1, &lpwsz, -1, TRUE)) return 0; lParam = (LPARAM)lpwsz; } xxxSetFrameTitle(pwnd, pwndMDI, (LPWSTR)lParam); if (lpwsz) { UserLocalFree(lpwsz); } break; } case WM_NCACTIVATE: SendMessage(hwndMDI, WM_NCACTIVATE, wParam, lParam); goto CallDWP; case WM_COMMAND: if ((UINT)LOWORD(wParam) == (FIRST(pmdi) + MAXITEMS -1)) { /* * selected the More... item */ if (fAnsi) { wParam = DialogBoxParamA(hmodUser, MAKEINTRESOURCEA(IDD_MDI_ACTIVATE), hwnd, MDIActivateDlgProcA, (LPARAM)pwndMDI); } else { wParam = DialogBoxParamW(hmodUser, MAKEINTRESOURCEW(IDD_MDI_ACTIVATE), hwnd, MDIActivateDlgProcW, (LPARAM)pwndMDI); } if ((int)wParam >= 0) { wParam += FIRST(pmdi); goto ActivateTheChild; } } else if (((UINT)LOWORD(wParam) >= FIRST(pmdi)) && ((UINT)LOWORD(wParam) < FIRST(pmdi) + CKIDS(pmdi))) { ActivateTheChild: pwndT = FindPwndChild(pwndMDI, (UINT)LOWORD(wParam)); ThreadLock(pwndT, &tlpwndT); SendMessage(hwndMDI, WM_MDIACTIVATE, (WPARAM)HW(pwndT), 0L); /* * if minimized, restore it. */ if (pwndT != NULL && TestWF(pwndT, WFMINIMIZED)) // // Fix for B#1510. Don't restore directly. Send child // a restore message. // SendMessage(HWq(pwndT), WM_SYSCOMMAND, (WPARAM)SC_RESTORE, 0L); ThreadUnlock(&tlpwndT); break; } switch (wParam & 0xFFF0) { /* * System menu commands on a maxed mdi child */ case SC_SIZE: case SC_MOVE: case SC_RESTORE: case SC_CLOSE: case SC_NEXTWINDOW: case SC_PREVWINDOW: case SC_MINIMIZE: case SC_MAXIMIZE: hwndT = MAXED(pmdi); if (hwndT != NULL) { PWND pwndT = ValidateHwnd(hwndT); if (pwndT == NULL) break; if ((wParam & 0xFFF0) == SC_CLOSE) { /* * Since the window is maxed, we've cleared WFSYSMENU (see * MDIAddSysMenu). We need to set it back here so GetSysMenuHandle * will do the right thing for _MNCanClose. */ BOOL fCanClose; UserAssert(!TestWF(pwndT, WFSYSMENU) && (pwndT->spmenuSys != NULL)); SetWindowState(pwndT, WFSYSMENU); fCanClose = xxxMNCanClose(pwndT); ClearWindowState(pwndT, WFSYSMENU); if (!fCanClose) { break; } } else if (((wParam & 0xFFF0) == SC_MINIMIZE) && !TestWF(pwndT, WFMINBOX)) { break; } return SendMessage(hwndT, WM_SYSCOMMAND, wParam, lParam); } } goto CallDWP; case WM_SIZE: if (wParam != SIZEICONIC) { NtUserMoveWindow(hwndMDI, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE); } else { wp.length = sizeof(WINDOWPLACEMENT); if (GetWindowPlacement(hwnd, &wp)) { RECT rcT; int clB; /* * If frame is iconic, size mdi win to be size of restored * frame's client area. Thus mdi children etc created in here * use the proper mdiclient size. */ clB = GetWindowBorders(pwnd->style, pwnd->ExStyle, TRUE, TRUE); CopyInflateRect(&rcT, &wp.rcNormalPosition, -clB*SYSMET(CXBORDER), -clB*SYSMET(CYBORDER)); if (TestWF(pwnd, WFBORDERMASK) == LOBYTE(WFCAPTION)) rcT.top += SYSMET(CYCAPTION); rcT.top += SYSMET(CYMENU); NtUserMoveWindow(hwndMDI, 0, 0, rcT.right-rcT.left, rcT.bottom-rcT.top, TRUE); } } goto CallDWP; case WM_SETFOCUS: NtUserSetFocus(hwndMDI); break; case WM_NEXTMENU: if (TestWF(pwnd, WFSYSMENU) && !TestWF(pwnd, WFMINIMIZED) && ACTIVE(pmdi) && !MAXED(pmdi)) { PMENU pmenuIn; /* * Go to child system menu by wrapping to the left from * the first popup in the menu bar or to the right from * the frame sysmenu. */ pmnm = (PMDINEXTMENU)lParam; pmenuIn = RevalidateHmenu(pmnm->hmenuIn); if (pmenuIn && ((wParam == VK_LEFT && pmenuIn == REBASE(pwnd, spmenu)) || (wParam == VK_RIGHT && pmnm->hmenuIn == NtUserGetSystemMenu(hwnd, FALSE)))) { HMENU hmenu; PWND pwndActive; // // Make sure the window is still valid // if ((pwndActive = ValidateHwnd(ACTIVE(pmdi))) == NULL) { return 0; } // // Make sure the child's system menu items are updated // (i.e. the ones are enabled/disabled) // if (!TestWF(pwndActive,WFMAXIMIZED)) { NtUserSetSysMenu(ACTIVE(pmdi)); } hmenu = NtUserGetSystemMenu(ACTIVE(pmdi), FALSE); pmnm->hmenuNext = hmenu; pmnm->hwndNext = ACTIVE(pmdi); return TRUE; } } /* * default behaviour */ return 0L; case WM_MENUCHAR: if (!TestWF(pwnd, WFMINIMIZED) && LOWORD(wParam) == TEXT('-')) { if (MAXED(pmdi)) return MAKELONG(0, 2); else if (ACTIVE(pmdi)) { PostMessage(ACTIVE(pmdi), WM_SYSCOMMAND, SC_KEYMENU, MAKELONG(TEXT('-'), 0)); return MAKELONG(0, 1); } } /* ** FALL THRU ** */ default: CallDWP: return DefWindowProcWorker(pwnd, wMsg, wParam, lParam, fAnsi); } return 0L; } FUNCLOG5(LOG_GENERAL, LRESULT, WINAPI, DefFrameProcW, HWND, hwnd, HWND, hwndMDIClient, UINT, message, WPARAM, wParam, LPARAM, lParam) LRESULT WINAPI DefFrameProcW( HWND hwnd, HWND hwndMDIClient, UINT message, WPARAM wParam, LPARAM lParam) { return DefFrameProcWorker(hwnd, hwndMDIClient, message, wParam, lParam, FALSE); } FUNCLOG5(LOG_GENERAL, LRESULT, WINAPI, DefFrameProcA, HWND, hwnd, HWND, hwndMDIClient, UINT, message, WPARAM, wParam, LPARAM, lParam) LRESULT WINAPI DefFrameProcA( HWND hwnd, HWND hwndMDIClient, UINT message, WPARAM wParam, LPARAM lParam) { return DefFrameProcWorker(hwnd, hwndMDIClient, message, wParam, lParam, TRUE); } /***************************************************************************\ * ChildMinMaxInfo * * History: * 11-14-90 MikeHar Ported from windows \***************************************************************************/ VOID ChildMinMaxInfo( PWND pwnd, PMINMAXINFO pmmi) { PWND pwndParent = REBASEPWND(pwnd, spwndParent); RECT rc; UserAssert(GETFNID(pwnd) != FNID_DESKTOP); CopyRect(&rc, KPRECT_TO_PRECT(&pwndParent->rcClient)); _ScreenToClient(pwndParent, (LPPOINT)&rc.left); _ScreenToClient(pwndParent, (LPPOINT)&rc.right); /* * Swap the left and right if pwnd is a mirrored window. */ if (TestWF(pwnd, WEFLAYOUTRTL)) { int nSaveLeft; nSaveLeft = rc.left; rc.left = rc.right; rc.right = nSaveLeft; } RealAdjustWindowRectEx(&rc, pwnd->style, FALSE, pwnd->ExStyle); /* * Position... */ pmmi->ptMaxPosition.x = rc.left; pmmi->ptMaxPosition.y = rc.top; pmmi->ptMaxSize.x = rc.right - rc.left; pmmi->ptMaxSize.y = rc.bottom - rc.top; } /***************************************************************************\ * xxxChildResize * * History: * 11-14-90 MikeHar Ported from windows \***************************************************************************/ VOID xxxChildResize( PWND pwnd, UINT wMode) { PWND pwndT; PWND pwndMDI = REBASEPWND(pwnd, spwndParent); PWND pwndFrame = REBASEPWND(pwndMDI, spwndParent); HWND hwndOldActive; PMDI pmdi; HWND hwndActive; TL tlpwndMDI; TL tlpwndFrame; TL tlpwndT; PMENU pmenu; HWND hwnd = HWq(pwnd); CheckLock(pwnd); NtUserSetSysMenu(hwnd); ThreadLock(pwndMDI, &tlpwndMDI); ThreadLock(pwndFrame, &tlpwndFrame); /* * Get a pointer to the MDI structure */ pmdi = ((PMDIWND)pwndMDI)->pmdi; pmenu = REBASE(pwndFrame, spmenu); if (MAXED(pmdi) == hwnd && wMode != SIZEFULLSCREEN) { /* * Restoring the current maximized window... * Remove the system menu from the Frame window. */ if (!(SCROLL(pmdi) & OTHERMAXING)) { Unlock(&MAXED(pmdi)); MDIRemoveSysMenu(PtoH(pmenu), hwnd); Unlock(&MAXED(pmdi)); xxxSetFrameTitle(pwndFrame, pwndMDI, (LPWSTR)1L); } } if (wMode == SIZEFULLSCREEN) { /* * Already maximized? */ if (hwnd == MAXED(pmdi)) goto Exit; /* * Maximizing this window... */ pmdi->wScroll |= OTHERMAXING | SCROLLCOUNT; if (hwndOldActive = MAXED(pmdi)) { SendMessage(hwndOldActive, WM_SETREDRAW, FALSE, 0L); MDIRemoveSysMenu(PtoH(pmenu), hwndOldActive); NtUserMinMaximize(hwndOldActive, SW_MDIRESTORE, FALSE); SendMessage(hwndOldActive, WM_SETREDRAW, TRUE, 0L); } Lock(&MAXED(pmdi), hwnd); /* * Add the system menu to the Frame window. */ MDIAddSysMenu(PtoH(pmenu), hwnd); xxxSetFrameTitle(pwndFrame, pwndMDI, (LPWSTR)1L); pmdi->wScroll &= ~(OTHERMAXING | SCROLLCOUNT); } if (wMode == SIZEICONIC) { for (pwndT = REBASEPWND(pwndMDI, spwndChild); pwndT; pwndT = REBASEPWND(pwndT, spwndNext)) { if (!pwndT->spwndOwner && TestWF(pwndT, WFVISIBLE)) break; } hwndActive = NtUserQueryWindow(hwnd, WindowActiveWindow); if ((pwndT != NULL) && (hwndActive != NULL) && IsChild(hwndActive, HWq(pwndMDI))) { ThreadLockAlways(pwndT, &tlpwndT); SendMessage(HWq(pwndT), WM_CHILDACTIVATE, 0, 0L); ThreadUnlock(&tlpwndT); } } if (!(SCROLL(pmdi) & SCROLLCOUNT)) RecalculateScrollRanges(pwndMDI, FALSE); Exit: ThreadUnlock(&tlpwndFrame); ThreadUnlock(&tlpwndMDI); } /***************************************************************************\ * DefMDIChildProc * * History: * 11-14-90 MikeHar Ported from windows \***************************************************************************/ LRESULT DefMDIChildProcWorker( HWND hwnd, UINT wMsg, WPARAM wParam, LPARAM lParam, BOOL fAnsi) { PWND pwnd; PWND pwndParent; PMDI pmdi; PMDINEXTMENU pmnm; HWND hwndT; PWND pwndT; TL tlpwndT; TL tlpwndParent; LRESULT lRet; if ((pwnd = ValidateHwnd(hwnd)) == NULL) { return (0L); } CheckLock(pwnd); /* * Check to see if this is a real mdi child window */ pwndParent = REBASEPWND(pwnd, spwndParent); if (!pwndParent || GETFNID(pwndParent) != FNID_MDICLIENT) { RIPERR0(ERROR_NON_MDICHILD_WINDOW, RIP_VERBOSE, ""); return DefWindowProcWorker(pwnd, wMsg, wParam, lParam, fAnsi); } /* * Get a pointer to the MDI structure, if it still exists */ pmdi = ((PMDIWND)pwndParent)->pmdi; if ((ULONG_PTR)pmdi == (ULONG_PTR)-1) { goto CallDWP; } switch (wMsg) { case WM_SETFOCUS: if (DIFFWOWHANDLE(hwnd, ACTIVE(pmdi))) { ThreadLockAlways(pwndParent, &tlpwndParent); xxxMDIActivate(pwndParent, pwnd); ThreadUnlock(&tlpwndParent); } goto CallDWP; case WM_NEXTMENU: /* * wrap to the frame menu bar, either left to the system menu, * or right to the frame menu bar. */ pmnm = (PMDINEXTMENU)lParam; pwndT = REBASEPWND(pwndParent, spwndParent); pmnm->hwndNext = HW(pwndT); pmnm->hmenuNext = (wParam == VK_LEFT) ? NtUserGetSystemMenu(pmnm->hwndNext, FALSE) : GetMenu(pmnm->hwndNext); return TRUE; #if 0 hWnd->hwndParent->hwndParent return (LONG)(((wParam == VK_LEFT) ? NtUserGetSystemMenu(HW(pwndT), FALSE): pwndT->spmenu) ); // return MAKELONG(NtUserGetSystemMenu(ACTIVE(pwndMDI), FALSE), // ACTIVE(pwndMDI)); #endif case WM_CLOSE: hwndT = GetParent(hwnd); if (hwndT != NULL) { SendMessage(hwndT, WM_MDIDESTROY, (WPARAM)hwnd, 0L); } break; case WM_MENUCHAR: PostMessage(GetParent(GetParent(hwnd)), WM_SYSCOMMAND, (DWORD)SC_KEYMENU, (LONG)LOWORD(wParam)); return 0x10000; case WM_SETTEXT: DefWindowProcWorker(pwnd, wMsg, wParam, lParam, fAnsi); if (WINDOW(pmdi)) ModifyMenuItem(pwnd); if (TestWF(pwnd, WFMAXIMIZED)) { /* * Add the child's window text to the frame since it is * maximized. But just redraw the caption so pass a 3L. */ pwndT = REBASEPWND(pwndParent, spwndParent); ThreadLock(pwndT, &tlpwndT); ThreadLock(pwndParent, &tlpwndParent); xxxSetFrameTitle(pwndT, pwndParent, (LPWSTR)3L); ThreadUnlock(&tlpwndParent); ThreadUnlock(&tlpwndT); } break; case WM_GETMINMAXINFO: ChildMinMaxInfo(pwnd, (PMINMAXINFO)lParam); break; case WM_SIZE: xxxChildResize(pwnd, (UINT)wParam); goto CallDWP; case WM_MOVE: if (!TestWF(pwnd, WFMAXIMIZED)) RecalculateScrollRanges(pwndParent, FALSE); goto CallDWP; case WM_CHILDACTIVATE: ThreadLock(pwndParent, &tlpwndParent); xxxMDIActivate(pwndParent, pwnd); ThreadUnlock(&tlpwndParent); break; case WM_SYSCOMMAND: switch (wParam & 0xFFF0) { case SC_NEXTWINDOW: case SC_PREVWINDOW: hwndT = GetParent(hwnd); SendMessage(hwndT, WM_MDINEXT, (WPARAM)hwnd, (DWORD)((wParam & 0xFFF0) == SC_PREVWINDOW)); break; case SC_SIZE: case SC_MOVE: if (SAMEWOWHANDLE(hwnd, MAXED(pmdi))) { /* * If a maxed child gets a size or move message, blow it * off. */ break; } else goto CallDWP; case SC_MAXIMIZE: if (SAMEWOWHANDLE(hwnd, MAXED(pmdi))) { /* * If a maxed child gets a maximize message, forward it * to the frame. Useful if the maximized child has a * size box so that clicking on it then maximizes the * parent. */ pwndT = REBASEPWND(pwndParent, spwndParent); ThreadLock(pwndT, &tlpwndT); lRet = SendMessage(HW(pwndT), WM_SYSCOMMAND, SC_MAXIMIZE, lParam); ThreadUnlock(&tlpwndT); return lRet; } /* * else fall through */ default: goto CallDWP; } break; default: CallDWP: return DefWindowProcWorker(pwnd, wMsg, wParam, lParam, fAnsi); } return 0L; } /***************************************************************************\ * DefMDIChildProc * * Translates the message, calls DefMDIChildProc on server side. * * 04-11-91 ScottLu Created. \***************************************************************************/ FUNCLOG4(LOG_GENERAL, LRESULT, WINAPI, DefMDIChildProcW, HWND, hwnd, UINT, message, WPARAM, wParam, LPARAM, lParam) LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { return DefMDIChildProcWorker(hwnd, message, wParam, lParam, FALSE); } FUNCLOG4(LOG_GENERAL, LRESULT, WINAPI, DefMDIChildProcA, HWND, hwnd, UINT, message, WPARAM, wParam, LPARAM, lParam) LRESULT WINAPI DefMDIChildProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { return DefMDIChildProcWorker(hwnd, message, wParam, lParam, TRUE); } BOOL MDICompleteChildCreation(HWND hwndChild, HMENU hSysMenu, BOOL fVisible, BOOL fDisabled) { PWND pwndChild; PWND pwndClient; HWND hwndClient; BOOL fHasOwnSysMenu; PMDI pmdi; pwndChild = ValidateHwnd(hwndChild); pwndClient = REBASEPWND(pwndChild,spwndParent); hwndClient = HWq(pwndClient); fHasOwnSysMenu = (pwndChild->spmenuSys) ? TRUE : FALSE; pmdi = ((PMDIWND)(pwndClient))->pmdi; CKIDS(pmdi)++; ITILELEVEL(pmdi)++; if (ITILELEVEL(pmdi) > 0x7ffe) ITILELEVEL(pmdi) = 0; // Update "Window" menu if this new window should be on it if (fVisible && !fDisabled && (CKIDS(pmdi) <= MAXITEMS)) SendMessage(hwndClient, WM_MDIREFRESHMENU, 0, 0L); // // Add the MDI System Menu. Catch the case of not being able to add a // system menu (EG, guy doesn't have WS_SYSMENU style), and delete the // menu to avoid buildup in USER's heap. // if (hSysMenu && (fHasOwnSysMenu || !NtUserSetSystemMenu(hwndChild, hSysMenu))) NtUserDestroyMenu(hSysMenu); if (fVisible) { if (!TestWF(pwndChild, WFMINIMIZED) || !ACTIVE(pmdi)) { NtUserSetWindowPos(hwndChild, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); if (TestWF(pwndChild, WFMAXIMIZED) && !fHasOwnSysMenu) { PWND pwndParent = REBASEPWND(pwndClient, spwndParent); PMENU pmenu = REBASE(pwndParent, spmenu); MDIAddSysMenu(PtoH(pmenu), hwndChild); NtUserRedrawFrame(HW(pwndParent)); } } else { NtUserShowWindow(hwndChild, SW_SHOWMINNOACTIVE); } } return TRUE; } BOOL CreateMDIChild( PSHORTCREATE psc, LPMDICREATESTRUCT pmcs, DWORD dwExpWinVerAndFlags, HMENU * phSysMenu, PWND pwndParent) { BOOL fVisible; RECT rcT; HMENU hSysMenu = NULL; HWND hwndPrevMaxed; PMDI pmdi; /* * Get a pointer to the MDI structure */ pmdi = ((PMDIWND)(pwndParent))->pmdi; pmcs->style = psc->style; // Mask off ignored style bits and add required ones. psc->style |= (WS_CHILD | WS_CLIPSIBLINGS); if (!(pwndParent->style & MDIS_ALLCHILDSTYLES)) { psc->style &= WS_MDIALLOWED; psc->style |= (WS_MDISTYLE | WS_VISIBLE); } else if (psc->style & WS_POPUP) { RIPMSG0(RIP_ERROR, "CreateWindowEx: WS_POPUP not allowed on MDI children"); if (LOWORD(dwExpWinVerAndFlags) >= VER40) return FALSE; } fVisible = ((psc->style & WS_VISIBLE) != 0L); // // Save ORIGINAL parameters in MDICREATESTRUCT. This is for // compatibility with old WM_MDICREATE. // pmcs->x = rcT.left = psc->x; pmcs->y = rcT.top = psc->y; pmcs->cx = rcT.right = psc->cx; pmcs->cy = rcT.bottom = psc->cy; MDICheckCascadeRect(pwndParent, &rcT); // // Setup creation coords // psc->x = rcT.left; psc->y = rcT.top; psc->cx = rcT.right; psc->cy = rcT.bottom; // Load the system menu if (psc->style & WS_SYSMENU) { #ifdef LAME_BUTTON hSysMenu = xxxLoadSysMenu(CHILDSYSMENU, NULL); #else hSysMenu = xxxLoadSysMenu(CHILDSYSMENU); #endif // LAME_BUTTON if (hSysMenu == NULL) { return FALSE; } } // The window got created ok: now restore the current maximized window // so we can maximize ourself in its place. hwndPrevMaxed = MAXED(pmdi); if (fVisible && IsWindow(hwndPrevMaxed)) { if (psc->style & WS_MAXIMIZE) SendMessage(hwndPrevMaxed, WM_SETREDRAW, (WPARAM)FALSE, 0L); // we could nuke the hwndPrevMaxed during the SendMessage32 // so recheck just in case, B#11122, [t-arthb] if ( IsWindow(hwndPrevMaxed) ) { NtUserMinMaximize(hwndPrevMaxed, SW_SHOWNORMAL, TRUE); if ( psc->style & WS_MAXIMIZE ) SendMessage(hwndPrevMaxed, WM_SETREDRAW, (WPARAM)TRUE, 0L); } } // Set the proper Child Window ID for this MDI child. psc->hMenu = (HMENU)UIntToPtr( (FIRST(pmdi) + CKIDS(pmdi)) ); *phSysMenu = hSysMenu; return TRUE; }