Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2918 lines
82 KiB

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