|
|
/****************************************************************************\
* * 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; }
|