929 lines
25 KiB
C
929 lines
25 KiB
C
|
/****************************** Module Header ******************************\
|
||
|
* Module Name: winmgr.c
|
||
|
|
||
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
||
|
|
||
|
* This module contains routines common to client and kernel.
|
||
|
|
||
|
* History:
|
||
|
* 02-20-92 DarrinM Pulled functions from user\server.
|
||
|
* 11-11-94 JimA Separated from client.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* FindNCHit
|
||
|
|
||
|
* History:
|
||
|
* 11-09-90 DavidPe Ported.
|
||
|
*/
|
||
|
int FindNCHit(
|
||
|
PWND pwnd,
|
||
|
LONG lPt)
|
||
|
{
|
||
|
POINT pt;
|
||
|
RECT rcWindow;
|
||
|
RECT rcClient;
|
||
|
RECT rcClientAdj;
|
||
|
int cBorders;
|
||
|
int dxButton;
|
||
|
|
||
|
pt.x = GET_X_LPARAM(lPt);
|
||
|
pt.y = GET_Y_LPARAM(lPt);
|
||
|
|
||
|
if (!PtInRect(&((WND *)pwnd)->rcWindow, pt))
|
||
|
return HTNOWHERE;
|
||
|
|
||
|
if (TestWF(pwnd, WFMINIMIZED)) {
|
||
|
CopyInflateRect(&rcWindow, &((WND *)pwnd)->rcWindow,
|
||
|
-(SYSMETRTL(CXFIXEDFRAME) + SYSMETRTL(CXBORDER)), -(SYSMETRTL(CYFIXEDFRAME) + SYSMETRTL(CYBORDER)));
|
||
|
|
||
|
if (!PtInRect(&rcWindow, pt))
|
||
|
return HTCAPTION;
|
||
|
|
||
|
goto CaptionHit;
|
||
|
}
|
||
|
|
||
|
// Get client rectangle
|
||
|
rcClient = pwnd->rcClient;
|
||
|
if (PtInRect(&rcClient, pt))
|
||
|
return HTCLIENT;
|
||
|
|
||
|
// Are we in "pseudo" client, i.e. the client & scrollbars & border
|
||
|
if (TestWF(pwnd, WEFCLIENTEDGE))
|
||
|
CopyInflateRect(&rcClientAdj, &rcClient, SYSMETRTL(CXEDGE), SYSMETRTL(CYEDGE));
|
||
|
else
|
||
|
rcClientAdj = rcClient;
|
||
|
|
||
|
if (TestWF(pwnd, WFVPRESENT)) {
|
||
|
#ifdef USE_MIRRORING
|
||
|
if ((!!TestWF(pwnd, WEFLEFTSCROLL)) ^ (!!TestWF(pwnd, WEFLAYOUTRTL)))
|
||
|
#else
|
||
|
if (TestWF(pwnd, WEFLEFTSCROLL))
|
||
|
#endif
|
||
|
rcClientAdj.left -= SYSMETRTL(CXVSCROLL);
|
||
|
else
|
||
|
rcClientAdj.right += SYSMETRTL(CXVSCROLL);
|
||
|
}
|
||
|
if (TestWF(pwnd, WFHPRESENT))
|
||
|
rcClientAdj.bottom += SYSMETRTL(CYHSCROLL);
|
||
|
|
||
|
if (!PtInRect(&rcClientAdj, pt))
|
||
|
{
|
||
|
// Subtract out window borders
|
||
|
cBorders = GetWindowBorders(pwnd->style, pwnd->ExStyle, TRUE, FALSE);
|
||
|
CopyInflateRect(&rcWindow, &((WND *)pwnd)->rcWindow,
|
||
|
-cBorders*SYSMETRTL(CXBORDER), -cBorders*SYSMETRTL(CYBORDER));
|
||
|
|
||
|
// Are we on the border?
|
||
|
if (!PtInRect(&rcWindow, pt))
|
||
|
{
|
||
|
// On a sizing border?
|
||
|
if (!TestWF(pwnd, WFSIZEBOX)) {
|
||
|
|
||
|
// Old compatibility thing: For 3.x windows that just had
|
||
|
// a border, we returned HTNOWHERE, believe it or not,
|
||
|
// because our hit-testing code was so brain dead.
|
||
|
|
||
|
if (!TestWF(pwnd, WFWIN40COMPAT) &&
|
||
|
!TestWF(pwnd, WFDLGFRAME) &&
|
||
|
!TestWF(pwnd, WEFDLGMODALFRAME)) {
|
||
|
return(HTNOWHERE);
|
||
|
|
||
|
} else {
|
||
|
return(HTBORDER); // We are on a dlg frame.
|
||
|
}
|
||
|
} else {
|
||
|
|
||
|
int ht;
|
||
|
|
||
|
|
||
|
// Note this improvement. The HT codes are numbered so that
|
||
|
// if you subtract HTSIZEFIRST-1 from them all, they sum up. I.E.,
|
||
|
// (HTLEFT - HTSIZEFIRST + 1) + (HTTOP - HTSIZEFIRST + 1) ==
|
||
|
// (HTTOPLEFT - HTSIZEFIRST + 1).
|
||
|
|
||
|
|
||
|
if (TestWF(pwnd, WEFTOOLWINDOW))
|
||
|
InflateRect(&rcWindow, -SYSMETRTL(CXSMSIZE), -SYSMETRTL(CYSMSIZE));
|
||
|
else
|
||
|
InflateRect(&rcWindow, -SYSMETRTL(CXSIZE), -SYSMETRTL(CYSIZE));
|
||
|
|
||
|
if (pt.y < rcWindow.top)
|
||
|
ht = (HTTOP - HTSIZEFIRST + 1);
|
||
|
else if (pt.y >= rcWindow.bottom)
|
||
|
ht = (HTBOTTOM - HTSIZEFIRST + 1);
|
||
|
else
|
||
|
ht = 0;
|
||
|
|
||
|
if (pt.x < rcWindow.left)
|
||
|
ht += (HTLEFT - HTSIZEFIRST + 1);
|
||
|
else if (pt.x >= rcWindow.right)
|
||
|
ht += (HTRIGHT - HTSIZEFIRST + 1);
|
||
|
|
||
|
return (ht + HTSIZEFIRST - 1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Are we above the client area?
|
||
|
if (pt.y < rcClientAdj.top)
|
||
|
{
|
||
|
// Are we in the caption?
|
||
|
if (TestWF(pwnd, WFBORDERMASK) == LOBYTE(WFCAPTION))
|
||
|
{
|
||
|
CaptionHit:
|
||
|
|
||
|
#ifdef USE_MIRRORING
|
||
|
if (TestWF(pwnd, WEFLAYOUTRTL)) {
|
||
|
pt.x = pwnd->rcWindow.right - (pt.x - pwnd->rcWindow.left);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (pt.y >= rcWindow.top)
|
||
|
{
|
||
|
if (TestWF(pwnd, WEFTOOLWINDOW))
|
||
|
{
|
||
|
rcWindow.top += SYSMETRTL(CYSMCAPTION);
|
||
|
dxButton = SYSMETRTL(CXSMSIZE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
rcWindow.top += SYSMETRTL(CYCAPTION);
|
||
|
dxButton = SYSMETRTL(CXSIZE);
|
||
|
}
|
||
|
|
||
|
if ((pt.y >= rcWindow.top) && TestWF(pwnd, WFMPRESENT))
|
||
|
return(HTMENU);
|
||
|
|
||
|
if ((pt.x >= rcWindow.left) &&
|
||
|
(pt.x < rcWindow.right) &&
|
||
|
(pt.y < rcWindow.top))
|
||
|
{
|
||
|
// Are we in the window menu?
|
||
|
if (TestWF(pwnd, WFSYSMENU))
|
||
|
{
|
||
|
rcWindow.left += dxButton;
|
||
|
if (pt.x < rcWindow.left)
|
||
|
{
|
||
|
if (!_HasCaptionIcon(pwnd))
|
||
|
// iconless windows have no sysmenu hit rect
|
||
|
return(HTCAPTION);
|
||
|
|
||
|
return(HTSYSMENU);
|
||
|
}
|
||
|
}
|
||
|
else if (TestWF(pwnd, WFWIN40COMPAT))
|
||
|
return(HTCAPTION);
|
||
|
|
||
|
// only a close button if window has a system menu
|
||
|
|
||
|
// Are we in the close button?
|
||
|
rcWindow.right -= dxButton;
|
||
|
if (pt.x >= rcWindow.right)
|
||
|
return HTCLOSE;
|
||
|
|
||
|
if ((pt.x < rcWindow.right) && !TestWF(pwnd, WEFTOOLWINDOW))
|
||
|
{
|
||
|
// Are we in the maximize/restore button?
|
||
|
if (TestWF(pwnd, (WFMAXBOX | WFMINBOX)))
|
||
|
{
|
||
|
// Note that sizing buttons are same width for both
|
||
|
// big captions and small captions.
|
||
|
rcWindow.right -= dxButton;
|
||
|
if (pt.x >= rcWindow.right)
|
||
|
return HTZOOM;
|
||
|
|
||
|
// Are we in the minimize button?
|
||
|
rcWindow.right -= dxButton;
|
||
|
if (pt.x >= rcWindow.right)
|
||
|
return HTREDUCE;
|
||
|
}
|
||
|
else if (TestWF(pwnd, WEFCONTEXTHELP))
|
||
|
{
|
||
|
rcWindow.right -= dxButton;
|
||
|
if (pt.x >= rcWindow.right)
|
||
|
return HTHELP;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// We're in the caption proper
|
||
|
return HTCAPTION;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Are we in the menu?
|
||
|
|
||
|
if (TestWF(pwnd, WFMPRESENT))
|
||
|
return HTMENU;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
// NOTE:
|
||
|
// We can only be here if we are on the client edge, horz scroll,
|
||
|
// sizebox, or vert scroll. Hence, if we are not on the first 3,
|
||
|
// we must be on the last one.
|
||
|
|
||
|
|
||
|
|
||
|
// Are we on the client edge?
|
||
|
|
||
|
if (TestWF(pwnd, WEFCLIENTEDGE))
|
||
|
{
|
||
|
InflateRect(&rcClientAdj, -SYSMETRTL(CXEDGE), -SYSMETRTL(CYEDGE));
|
||
|
if (!PtInRect(&rcClientAdj, pt))
|
||
|
return(HTBORDER);
|
||
|
}
|
||
|
|
||
|
|
||
|
// Are we on the scrollbars?
|
||
|
|
||
|
if (TestWF(pwnd, WFHPRESENT) && (pt.y >= rcClient.bottom))
|
||
|
{
|
||
|
int iHitTest=HTHSCROLL;
|
||
|
UserAssert(pt.y < rcClientAdj.bottom);
|
||
|
|
||
|
if (TestWF(pwnd, WFVPRESENT)) {
|
||
|
PWND pwndSizeBox = SizeBoxHwnd(pwnd);
|
||
|
|
||
|
if(pt.x >= rcClient.right)
|
||
|
return(pwndSizeBox ? HTBOTTOMRIGHT : HTGROWBOX);
|
||
|
#ifdef USE_MIRRORING
|
||
|
|
||
|
// Mirror the grip box location so that it becomes
|
||
|
// on the bottom-left side if this is a RTL mirrrored
|
||
|
// windows.
|
||
|
|
||
|
else if (TestWF(pwnd, WEFLAYOUTRTL) && (pt.x < rcClient.left))
|
||
|
return(pwndSizeBox ? HTBOTTOMLEFT : HTGROWBOX);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
return(iHitTest);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
UserAssert(TestWF(pwnd, WFVPRESENT));
|
||
|
#ifdef USE_MIRRORING
|
||
|
if ((!!TestWF(pwnd, WEFLEFTSCROLL)) ^ (!!TestWF(pwnd, WEFLAYOUTRTL))) {
|
||
|
#else
|
||
|
if (TestWF(pwnd, WEFLEFTSCROLL)) {
|
||
|
#endif
|
||
|
UserAssert(pt.x < rcClient.left);
|
||
|
UserAssert(pt.x >= rcClientAdj.left);
|
||
|
} else {
|
||
|
UserAssert(pt.x >= rcClient.right);
|
||
|
UserAssert(pt.x < rcClientAdj.right);
|
||
|
}
|
||
|
return(HTVSCROLL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// We give up.
|
||
|
|
||
|
// Win31 returned HTNOWHERE in this case; For compatibility, we will
|
||
|
// keep it that way.
|
||
|
|
||
|
return(HTNOWHERE);
|
||
|
|
||
|
}
|
||
|
|
||
|
BOOL _FChildVisible(
|
||
|
PWND pwnd)
|
||
|
{
|
||
|
while (TestwndChild(pwnd)) {
|
||
|
pwnd = REBASEPWND(pwnd, spwndParent);
|
||
|
if (pwnd == NULL)
|
||
|
break;
|
||
|
if (!TestWF(pwnd, WFVISIBLE))
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* _MapWindowPoints
|
||
|
|
||
|
|
||
|
* History:
|
||
|
* 03-03-92 JimA Ported from Win 3.1 sources.
|
||
|
*/
|
||
|
|
||
|
int _MapWindowPoints(
|
||
|
PWND pwndFrom,
|
||
|
PWND pwndTo,
|
||
|
LPPOINT lppt,
|
||
|
DWORD cpt)
|
||
|
{
|
||
|
#ifdef USE_MIRRORING
|
||
|
int dx = 0, dy = 0;
|
||
|
int SaveLeft, Sign = 1;
|
||
|
RECT *pR = (RECT *)lppt;
|
||
|
BOOL bMirrored = FALSE;
|
||
|
#else
|
||
|
int dx, dy;
|
||
|
LPPOINT pptFrom, pptTo;
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* If a window is NULL, use the desktop window.
|
||
|
* If the window is the desktop, don't offset by
|
||
|
* the client rect, since it won't work if the screen
|
||
|
* origin is not (0,0) - use zero instead.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Compute deltas
|
||
|
*/
|
||
|
#ifdef USE_MIRRORING
|
||
|
if (pwndFrom && GETFNID(pwndFrom) != FNID_DESKTOP) {
|
||
|
if (TestWF(pwndFrom, WEFLAYOUTRTL)) {
|
||
|
Sign = -Sign;
|
||
|
dx = -pwndFrom->rcClient.right;
|
||
|
bMirrored = (cpt == 2);
|
||
|
} else {
|
||
|
dx = pwndFrom->rcClient.left;
|
||
|
}
|
||
|
dy = pwndFrom->rcClient.top;
|
||
|
}
|
||
|
|
||
|
if (pwndTo && GETFNID(pwndTo) != FNID_DESKTOP) {
|
||
|
if (TestWF(pwndTo, WEFLAYOUTRTL)) {
|
||
|
Sign = -Sign;
|
||
|
dx = dx + Sign * pwndTo->rcClient.right;
|
||
|
bMirrored = (cpt == 2);
|
||
|
} else {
|
||
|
dx = dx - Sign * pwndTo->rcClient.left;
|
||
|
}
|
||
|
dy = dy - pwndTo->rcClient.top;
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
if (pwndFrom == NULL || GETFNID(pwndFrom) == FNID_DESKTOP) {
|
||
|
pptFrom = PZERO(POINT);
|
||
|
} else {
|
||
|
pptFrom = (LPPOINT) &pwndFrom->rcClient;
|
||
|
}
|
||
|
|
||
|
if (pwndTo == NULL || GETFNID(pwndTo) == FNID_DESKTOP) {
|
||
|
pptTo = PZERO(POINT);
|
||
|
} else {
|
||
|
pptTo = (LPPOINT) &pwndTo->rcClient;
|
||
|
}
|
||
|
dx = pptFrom->x - pptTo->x;
|
||
|
dy = pptFrom->y - pptTo->y;
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* Map the points
|
||
|
*/
|
||
|
while (cpt--) {
|
||
|
lppt->x += dx;
|
||
|
#ifdef USE_MIRRORING
|
||
|
lppt->x *= Sign;
|
||
|
#endif
|
||
|
lppt->y += dy;
|
||
|
++lppt;
|
||
|
}
|
||
|
|
||
|
#ifdef USE_MIRRORING
|
||
|
if (bMirrored) { //Special case for Rect
|
||
|
SaveLeft = min (pR->left, pR->right);
|
||
|
pR->right = max (pR->left, pR->right);
|
||
|
pR->left = SaveLeft;
|
||
|
}
|
||
|
#endif
|
||
|
return MAKELONG(dx, dy);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* GetRealClientRect()
|
||
|
|
||
|
* Gets real client rectangle, inc. scrolls and excl. one row or column
|
||
|
* of minimized windows.
|
||
|
|
||
|
* If hwndParent is the desktop, then
|
||
|
* * If pMonitor is NULL, use the primary monitor
|
||
|
* * Otherwise use the appropriate monitor's rectangles
|
||
|
|
||
|
*/
|
||
|
|
||
|
void GetRealClientRect(
|
||
|
PWND pwnd,
|
||
|
LPRECT prc,
|
||
|
UINT uFlags,
|
||
|
PMONITOR pMonitor
|
||
|
)
|
||
|
{
|
||
|
if (GETFNID(pwnd) == FNID_DESKTOP) {
|
||
|
if (!pMonitor) {
|
||
|
pMonitor = GetPrimaryMonitor();
|
||
|
}
|
||
|
*prc = (uFlags & GRC_FULLSCREEN) ? pMonitor->rcMonitor : pMonitor->rcWork;
|
||
|
} else {
|
||
|
GetRect(pwnd, prc, GRECT_CLIENT | GRECT_CLIENTCOORDS);
|
||
|
if (uFlags & GRC_SCROLLS) {
|
||
|
if (TestWF(pwnd, WFHPRESENT)){
|
||
|
prc->bottom += SYSMETRTL(CYHSCROLL);
|
||
|
}
|
||
|
|
||
|
if (TestWF(pwnd, WFVPRESENT)) {
|
||
|
prc->right += SYSMETRTL(CXVSCROLL);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (uFlags & GRC_MINWNDS) {
|
||
|
switch (SYSMETRTL(ARRANGE) & ~ARW_HIDE) {
|
||
|
case ARW_TOPLEFT | ARW_RIGHT:
|
||
|
case ARW_TOPRIGHT | ARW_LEFT:
|
||
|
|
||
|
// Leave space on top for one row of min windows
|
||
|
|
||
|
prc->top += SYSMETRTL(CYMINSPACING);
|
||
|
break;
|
||
|
|
||
|
case ARW_TOPLEFT | ARW_DOWN:
|
||
|
case ARW_BOTTOMLEFT | ARW_UP:
|
||
|
|
||
|
// Leave space on left for one column of min windows
|
||
|
|
||
|
prc->left += SYSMETRTL(CXMINSPACING);
|
||
|
break;
|
||
|
|
||
|
case ARW_TOPRIGHT | ARW_DOWN:
|
||
|
case ARW_BOTTOMRIGHT | ARW_UP:
|
||
|
|
||
|
// Leave space on right for one column of min windows
|
||
|
|
||
|
prc->right -= SYSMETRTL(CXMINSPACING);
|
||
|
break;
|
||
|
|
||
|
case ARW_BOTTOMLEFT | ARW_RIGHT:
|
||
|
case ARW_BOTTOMRIGHT | ARW_LEFT:
|
||
|
|
||
|
// Leave space on bottom for one row of min windows
|
||
|
|
||
|
prc->bottom -= SYSMETRTL(CYMINSPACING);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* _GetLastActivePopup (API)
|
||
|
|
||
|
|
||
|
|
||
|
* History:
|
||
|
* 11-27-90 darrinm Ported from Win 3.0 sources.
|
||
|
* 02-19-91 JimA Added enum access check
|
||
|
*/
|
||
|
|
||
|
PWND _GetLastActivePopup(
|
||
|
PWND pwnd)
|
||
|
{
|
||
|
if (pwnd->spwndLastActive == NULL)
|
||
|
return pwnd;
|
||
|
|
||
|
return REBASEPWND(pwnd, spwndLastActive);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* IsDescendant
|
||
|
|
||
|
* Internal version if IsChild that is a bit faster and ignores the WFCHILD
|
||
|
* business.
|
||
|
|
||
|
* Returns TRUE if pwndChild == pwndParent (IsChild doesn't).
|
||
|
|
||
|
* History:
|
||
|
* 07-22-91 darrinm Translated from Win 3.1 ASM code.
|
||
|
* 03-03-94 Johnl Moved from server
|
||
|
*/
|
||
|
|
||
|
BOOL _IsDescendant(
|
||
|
PWND pwndParent,
|
||
|
PWND pwndChild)
|
||
|
{
|
||
|
while (1) {
|
||
|
if (pwndParent == pwndChild)
|
||
|
return TRUE;
|
||
|
if (GETFNID(pwndChild) == FNID_DESKTOP)
|
||
|
break;
|
||
|
pwndChild = REBASEPWND(pwndChild, spwndParent);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* IsVisible
|
||
|
|
||
|
* Return whether or not a given window can be drawn in or not.
|
||
|
|
||
|
* History:
|
||
|
* 07-22-91 darrinm Translated from Win 3.1 ASM code.
|
||
|
*/
|
||
|
|
||
|
BOOL IsVisible(
|
||
|
PWND pwnd)
|
||
|
{
|
||
|
PWND pwndT;
|
||
|
|
||
|
for (pwndT = pwnd; pwndT; pwndT = REBASEPWND(pwndT, spwndParent)) {
|
||
|
|
||
|
/*
|
||
|
* Invisible windows are always invisible
|
||
|
*/
|
||
|
if (!TestWF(pwndT, WFVISIBLE))
|
||
|
return FALSE;
|
||
|
|
||
|
if (TestWF(pwndT, WFMINIMIZED)) {
|
||
|
|
||
|
/*
|
||
|
* Children of minimized windows are always invisible.
|
||
|
*/
|
||
|
if (pwndT != pwnd)
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If we're at the desktop, then we don't want to go any further.
|
||
|
*/
|
||
|
if (GETFNID(pwndT) == FNID_DESKTOP)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
* Function: GetWindowBorders
|
||
|
|
||
|
* Synopsis: Calculates # of borders around window
|
||
|
|
||
|
* Algorithm: Calculate # of window borders and # of client borders
|
||
|
|
||
|
* This routine is ported from Chicago wmclient.c -- FritzS
|
||
|
|
||
|
*/
|
||
|
|
||
|
int GetWindowBorders(LONG lStyle, DWORD dwExStyle, BOOL fWindow, BOOL fClient)
|
||
|
{
|
||
|
int cBorders = 0;
|
||
|
|
||
|
if (fWindow) {
|
||
|
|
||
|
// Is there a 3D border around the window?
|
||
|
|
||
|
if (dwExStyle & WS_EX_WINDOWEDGE)
|
||
|
cBorders += 2;
|
||
|
else if (dwExStyle & WS_EX_STATICEDGE)
|
||
|
++cBorders;
|
||
|
|
||
|
|
||
|
// Is there a single flat border around the window? This is true for
|
||
|
// WS_BORDER, WS_DLGFRAME, and WS_EX_DLGMODALFRAME windows.
|
||
|
|
||
|
if ( (lStyle & WS_CAPTION) || (dwExStyle & WS_EX_DLGMODALFRAME) )
|
||
|
++cBorders;
|
||
|
|
||
|
|
||
|
// Is there a sizing flat border around the window?
|
||
|
|
||
|
if (lStyle & WS_SIZEBOX)
|
||
|
cBorders += gpsi->gclBorder;
|
||
|
}
|
||
|
|
||
|
if (fClient) {
|
||
|
|
||
|
// Is there a 3D border around the client?
|
||
|
|
||
|
if (dwExStyle & WS_EX_CLIENTEDGE)
|
||
|
cBorders += 2;
|
||
|
}
|
||
|
|
||
|
return(cBorders);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* SizeBoxHwnd()
|
||
|
|
||
|
* Returns the HWND that will be sized if the user drags in the given window's
|
||
|
* sizebox -- If NULL, then the sizebox is not needed
|
||
|
|
||
|
* Criteria for choosing what window will be sized:
|
||
|
* find first sizeable parent; if that parent is not maximized and the child's
|
||
|
* bottom, right corner is within a scroll bar height and width of the parent's
|
||
|
* bottom, right corner, that parent will be sized.
|
||
|
|
||
|
* From Chicago
|
||
|
*/
|
||
|
|
||
|
PWND SizeBoxHwnd(
|
||
|
PWND pwnd)
|
||
|
{
|
||
|
#ifdef USE_MIRRORING
|
||
|
BOOL bMirroredSizeBox = (BOOL) TestWF(pwnd, WEFLAYOUTRTL);
|
||
|
#endif
|
||
|
|
||
|
int xbrChild;
|
||
|
int ybrChild = pwnd->rcWindow.bottom;
|
||
|
|
||
|
#ifdef USE_MIRRORING
|
||
|
if (bMirroredSizeBox) {
|
||
|
xbrChild = pwnd->rcWindow.left;
|
||
|
} else
|
||
|
#endif
|
||
|
{
|
||
|
xbrChild = pwnd->rcWindow.right;
|
||
|
}
|
||
|
|
||
|
while (GETFNID(pwnd) != FNID_DESKTOP) {
|
||
|
if (TestWF(pwnd, WFSIZEBOX)) {
|
||
|
// First sizeable parent found
|
||
|
int xbrParent;
|
||
|
int ybrParent;
|
||
|
|
||
|
if (TestWF(pwnd, WFMAXIMIZED))
|
||
|
return(NULL);
|
||
|
|
||
|
#ifdef USE_MIRRORING
|
||
|
if (bMirroredSizeBox) {
|
||
|
xbrParent = pwnd->rcClient.left;
|
||
|
} else
|
||
|
#endif
|
||
|
{
|
||
|
xbrParent = pwnd->rcClient.right;
|
||
|
}
|
||
|
ybrParent = pwnd->rcClient.bottom;
|
||
|
|
||
|
/* If the sizebox dude is within an EDGE of the client's bottom
|
||
|
* right corner (left corner for mirrored windows), let this succeed.
|
||
|
* That way people who draw their own sunken clients will be happy.
|
||
|
*/
|
||
|
#ifdef USE_MIRRORING
|
||
|
if (bMirroredSizeBox) {
|
||
|
if ((xbrChild - SYSMETRTL(CXEDGE) > xbrParent) || (ybrChild + SYSMETRTL(CYEDGE) < ybrParent)) {
|
||
|
|
||
|
// Child's bottom, left corner of SIZEBOX isn't close enough
|
||
|
// to bottom left of parent's client.
|
||
|
|
||
|
return(NULL);
|
||
|
}
|
||
|
} else
|
||
|
#endif
|
||
|
{
|
||
|
if ((xbrChild + SYSMETRTL(CXEDGE) < xbrParent) || (ybrChild + SYSMETRTL(CYEDGE) < ybrParent)) {
|
||
|
|
||
|
// Child's bottom, right corner of SIZEBOX isn't close enough
|
||
|
// to bottom right of parent's client.
|
||
|
|
||
|
return(NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(pwnd);
|
||
|
}
|
||
|
|
||
|
if (!TestWF(pwnd, WFCHILD) || TestWF(pwnd, WFCPRESENT))
|
||
|
break;
|
||
|
|
||
|
pwnd = REBASEPWND(pwnd, spwndParent);
|
||
|
}
|
||
|
return(NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
// NeedsWindowEdge()
|
||
|
|
||
|
// Modifies style/extended style to enforce WS_EX_WINDOWEDGE when we want
|
||
|
// it.
|
||
|
|
||
|
|
||
|
// When do we want WS_EX_WINDOWEDGE on a window?
|
||
|
// (1) If the window has a caption
|
||
|
// (2) If the window has the WS_DLGFRAME or WS_EX_DLGFRAME style (note
|
||
|
// that this takes care of (1))
|
||
|
// (3) If the window has WS_THICKFRAME
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
BOOL NeedsWindowEdge(DWORD dwStyle, DWORD dwExStyle, BOOL fNewApp)
|
||
|
{
|
||
|
BOOL fGetsWindowEdge;
|
||
|
|
||
|
fGetsWindowEdge = FALSE;
|
||
|
|
||
|
if (dwExStyle & WS_EX_DLGMODALFRAME)
|
||
|
fGetsWindowEdge = TRUE;
|
||
|
else if (dwExStyle & WS_EX_STATICEDGE)
|
||
|
fGetsWindowEdge = FALSE;
|
||
|
else if (dwStyle & WS_THICKFRAME)
|
||
|
fGetsWindowEdge = TRUE;
|
||
|
else switch (dwStyle & WS_CAPTION)
|
||
|
{
|
||
|
case WS_DLGFRAME:
|
||
|
fGetsWindowEdge = TRUE;
|
||
|
break;
|
||
|
|
||
|
case WS_CAPTION:
|
||
|
fGetsWindowEdge = fNewApp;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return(fGetsWindowEdge);
|
||
|
}
|
||
|
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
// HasCaptionIcon()
|
||
|
|
||
|
// TRUE if this is a window that should have an icon drawn in its caption
|
||
|
// FALSE otherwise
|
||
|
|
||
|
// --------------------------------------------------------------------------
|
||
|
|
||
|
BOOL _HasCaptionIcon(PWND pwnd)
|
||
|
{
|
||
|
HICON hIcon;
|
||
|
PCLS pcls;
|
||
|
|
||
|
if (TestWF(pwnd, WEFTOOLWINDOW))
|
||
|
// it's a tool window -- it doesn't get an icon
|
||
|
return(FALSE);
|
||
|
|
||
|
if ((TestWF(pwnd, WFBORDERMASK) != (BYTE)LOBYTE(WFDLGFRAME)) &&
|
||
|
!TestWF(pwnd, WEFDLGMODALFRAME))
|
||
|
// they are not trying to look like a dialog, they get an icon
|
||
|
return TRUE;
|
||
|
|
||
|
if (!TestWF(pwnd, WFWIN40COMPAT) &&
|
||
|
(((PCLS)REBASEALWAYS(pwnd, pcls))->atomClassName == (ATOM)(ULONG_PTR)DIALOGCLASS))
|
||
|
// it's an older REAL dialog -- it doesn't get an icon
|
||
|
return(FALSE);
|
||
|
|
||
|
hIcon = (HICON) _GetProp(pwnd, MAKEINTATOM(gpsi->atomIconSmProp), TRUE);
|
||
|
|
||
|
if (hIcon) {
|
||
|
// it's a 4.0 dialog with a small icon -- if that small icon is
|
||
|
// something other than the generic small windows icon, it gets an icon
|
||
|
return(hIcon != gpsi->hIconSmWindows);
|
||
|
}
|
||
|
hIcon = (HICON) _GetProp(pwnd, MAKEINTATOM(gpsi->atomIconProp), TRUE);
|
||
|
|
||
|
if (hIcon && (hIcon != gpsi->hIcoWindows))
|
||
|
// it's a 4.0 dialog with no small icon, but instead a large icon
|
||
|
// that's not the generic windows icon -- it gets an icon
|
||
|
return(TRUE);
|
||
|
|
||
|
pcls = REBASEALWAYS(pwnd, pcls);
|
||
|
if (pcls->spicnSm) {
|
||
|
if (pcls->spicnSm != HMObjectFromHandle(gpsi->hIconSmWindows)) {
|
||
|
// it's a 4.0 dialog with a class icon that's not the generic windows
|
||
|
// icon -- it gets an icon
|
||
|
return(TRUE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// it's a 4.0 dialog with no small or large icon -- it doesn't get an icon
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* GetTopLevelWindow
|
||
|
|
||
|
* History:
|
||
|
* 10-19-90 darrinm Ported from Win 3.0 sources.
|
||
|
*/
|
||
|
|
||
|
PWND GetTopLevelWindow(
|
||
|
PWND pwnd)
|
||
|
{
|
||
|
if (pwnd != NULL) {
|
||
|
while (TestwndChild(pwnd))
|
||
|
pwnd = REBASEPWND(pwnd, spwndParent);
|
||
|
}
|
||
|
|
||
|
return pwnd;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* GetRect
|
||
|
|
||
|
* Returns a rect from pwnd (client or window) and returns it in
|
||
|
* one of these coordinate schemes:
|
||
|
|
||
|
* (a) Own Client
|
||
|
* (b) Own Window
|
||
|
* (c) Parent Client
|
||
|
|
||
|
* Moreover, it does the right thing for case (d) when pwnd is top level.
|
||
|
* In that case, we never want to offset by origin of the parent, which is the
|
||
|
* desktop, since that will not work when the virtual screen has a
|
||
|
* negative origin. And it does the right thing for cases (b) and (c)
|
||
|
* if pwnd is the desktop.
|
||
|
|
||
|
* NOTE: The Win95 version of this function had a flag GRECT_SCREENCOORDS,
|
||
|
* which would return the rectangle in screen coords. There's no reason to
|
||
|
* call a function to do this, since the smallest and fastest to copy a
|
||
|
* rectangle is simple assignment. Therefore, I removed GRECT_SCREENCOORDS.
|
||
|
|
||
|
* History:
|
||
|
* 19-Sep-1996 adams Created.
|
||
|
*/
|
||
|
|
||
|
void
|
||
|
GetRect(PWND pwnd, LPRECT lprc, UINT uCoords)
|
||
|
{
|
||
|
PWND pwndParent;
|
||
|
LPRECT lprcOffset;
|
||
|
|
||
|
UserAssert(lprc);
|
||
|
UserAssert((uCoords & ~(GRECT_COORDMASK | GRECT_RECTMASK)) == 0);
|
||
|
UserAssert(uCoords & GRECT_COORDMASK);
|
||
|
UserAssert(uCoords & GRECT_RECTMASK);
|
||
|
|
||
|
*lprc = (uCoords & GRECT_WINDOW) ? pwnd->rcWindow : pwnd->rcClient;
|
||
|
|
||
|
/*
|
||
|
* If this is the desktop window, we have what we want, whether we
|
||
|
* are asking for GRECT_PARENTCOORDS, WINDOWCOORD or CLIENTCOORDS
|
||
|
*/
|
||
|
if (GETFNID(pwnd) == FNID_DESKTOP)
|
||
|
return;
|
||
|
|
||
|
switch (uCoords & GRECT_COORDMASK) {
|
||
|
case GRECT_PARENTCOORDS:
|
||
|
pwndParent = REBASEPWND(pwnd, spwndParent);
|
||
|
if (GETFNID(pwndParent) == FNID_DESKTOP)
|
||
|
return;
|
||
|
|
||
|
lprcOffset = &pwndParent->rcClient;
|
||
|
|
||
|
#if defined(USE_MIRRORING)
|
||
|
|
||
|
// Let's mirror the edges of the child's window since the parent
|
||
|
// is mirrored, so should the child window be. [samera]
|
||
|
|
||
|
if (TestWF(pwndParent,WEFLAYOUTRTL) &&
|
||
|
(uCoords & GRECT_WINDOW) &&
|
||
|
(TestWF(pwnd,WFCHILD))) {
|
||
|
int iLeft;
|
||
|
|
||
|
|
||
|
// I am using OffsetRect instead of implementing a new
|
||
|
// OffsetMirrorRect API since this is the only place I am
|
||
|
// doing it in.
|
||
|
|
||
|
// Since screen coordinates are not mirrored, the rect offsetting
|
||
|
// should be done relative to prcOffset->right since it is the
|
||
|
// leading edge for mirrored windows. [samera]
|
||
|
|
||
|
|
||
|
UserVerify(OffsetRect(lprc, -lprcOffset->right, -lprcOffset->top));
|
||
|
|
||
|
iLeft = lprc->left;
|
||
|
lprc->left = (lprc->right * -1);
|
||
|
lprc->right = (iLeft * -1);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
break;
|
||
|
|
||
|
case GRECT_WINDOWCOORDS:
|
||
|
lprcOffset = &pwnd->rcWindow;
|
||
|
break;
|
||
|
|
||
|
case GRECT_CLIENTCOORDS:
|
||
|
lprcOffset = &pwnd->rcClient;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
UserAssert(0 && "Logic error in _GetRect - invalid uCoords");
|
||
|
}
|
||
|
|
||
|
UserVerify(OffsetRect(lprc, -lprcOffset->left, -lprcOffset->top));
|
||
|
}
|