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.
 
 
 
 
 
 

469 lines
12 KiB

/****************************** Module Header ******************************\
* Module Name: winwhere.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* History:
* 08-Nov-1990 DavidPe Created.
* 23-Jan-1991 IanJa Serialization: Handle revalidation added
* 19-Feb-1991 JimA Added enum access checks
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/***************************************************************************\
* LayerHitTest
*
* 9/21/1998 vadimg created
\***************************************************************************/
__inline BOOL LayerHitTest(PWND pwnd, POINT pt)
{
ASSERT(TestWF(pwnd, WEFLAYERED));
if (TestWF(pwnd, WEFTRANSPARENT))
return FALSE;
if (!GrePtInSprite(gpDispInfo->hDev, PtoHq(pwnd), pt.x, pt.y))
return FALSE;
return TRUE;
}
/***************************************************************************\
* ChildWindowFromPoint (API)
*
* Returns NULL if pt is not in parent's client area at all,
* hwndParent if point is not over any children, and a child window if it is
* over a child. Will return hidden and disabled windows if they are at the
* given point.
*
* History:
* 19-Nov-1990 DavidPe Created.
* 19-Feb-1991 JimA Added enum access check
\***************************************************************************/
PWND _ChildWindowFromPointEx(
PWND pwnd,
POINT pt,
UINT uFlags)
{
if (pwnd != PWNDDESKTOP(pwnd)) {
if (TestWF(pwnd, WEFLAYOUTRTL)) {
pt.x = pwnd->rcClient.right - pt.x;
} else {
pt.x += pwnd->rcClient.left;
}
pt.y += pwnd->rcClient.top;
}
// _ClientToScreen(pwndParent, (LPPOINT)&pt);
if (PtInRect(&pwnd->rcClient, pt)) {
PWND pwndChild;
if (pwnd->hrgnClip != NULL) {
if (!GrePtInRegion(pwnd->hrgnClip, pt.x, pt.y))
return NULL;
}
if (TestWF(pwnd, WEFLAYERED)) {
if (!LayerHitTest(pwnd, pt))
return NULL;
}
/*
* Enumerate the children, skipping disabled and invisible ones
* if so desired. Still doesn't work for WS_EX_TRANSPARENT windows.
*/
for (pwndChild = pwnd->spwndChild;
pwndChild;
pwndChild = pwndChild->spwndNext) {
/*
* Skip windows as desired.
*/
if ((uFlags & CWP_SKIPINVISIBLE) && !TestWF(pwndChild, WFVISIBLE))
continue;
if ((uFlags & CWP_SKIPDISABLED) && TestWF(pwndChild, WFDISABLED))
continue;
if ((uFlags & CWP_SKIPTRANSPARENT) && TestWF(pwndChild, WEFTRANSPARENT))
continue;
if (PtInRect(&pwndChild->rcWindow, pt)) {
if (pwndChild->hrgnClip != NULL) {
if (!GrePtInRegion(pwndChild->hrgnClip, pt.x, pt.y))
continue;
}
if (TestWF(pwndChild, WEFLAYERED)) {
if (!LayerHitTest(pwndChild, pt))
continue;
}
return(pwndChild);
}
}
return pwnd;
}
return NULL;
}
/***************************************************************************\
* xxxWindowFromPoint (API)
*
* History:
* 19-Nov-1990 DavidPe Created.
* 19-Feb-1991 JimA Added enum access check
\***************************************************************************/
PWND xxxWindowFromPoint(
POINT pt)
{
HWND hwnd;
PWND pwndT;
TL tlpwndT;
pwndT = _GetDesktopWindow();
ThreadLock(pwndT, &tlpwndT);
hwnd = xxxWindowHitTest2(pwndT, pt, NULL, WHT_IGNOREDISABLED);
ThreadUnlock(&tlpwndT);
return RevalidateHwnd(hwnd);
}
#ifdef REDIRECTION
/***************************************************************************\
* xxxCallSpeedHitTestHook
*
* Call the speed hit test hook to give the opportunity to the hook to fake
* where the mouse pointer is.
*
* 25-Jan-1999 CLupu Created.
\***************************************************************************/
PWND xxxCallSpeedHitTestHook(POINT* ppt)
{
PHOOK pHook;
PWND pwnd = NULL;
/*
* Call the hit test hooks to give them the opportunity to change
* the coordinates and the hwnd
*/
if ((pHook = PhkFirstValid(PtiCurrent(), WH_HITTEST)) != NULL) {
HTHOOKSTRUCT ht;
BOOL bAnsiHook;
ht.pt = *ppt;
ht.hwndHit = NULL;
xxxCallHook2(pHook, HC_ACTION, 0, (LPARAM)&ht, &bAnsiHook);
if (ht.hwndHit != NULL) {
pwnd = HMValidateHandle(ht.hwndHit, TYPE_WINDOW);
if (pwnd != NULL) {
ppt->x = ht.pt.x;
ppt->y = ht.pt.y;
}
}
}
return pwnd;
}
#endif // REDIRECTION
/***************************************************************************\
* SpeedHitTest
*
* This routine quickly finds out what top level window this mouse point
* belongs to. Used purely for ownership purposes.
*
* 12-Nov-1992 ScottLu Created.
\***************************************************************************/
PWND SpeedHitTest(
PWND pwndParent,
POINT pt)
{
PWND pwndT;
PWND pwnd;
if (pwndParent == NULL)
return NULL;
for (pwnd = pwndParent->spwndChild; pwnd != NULL; pwnd = pwnd->spwndNext) {
/*
* Are we looking at an hidden window?
*/
if (!TestWF(pwnd, WFVISIBLE))
continue;
/*
* Are we barking up the wrong tree?
*/
if (!PtInRect((LPRECT)&pwnd->rcWindow, pt)) {
continue;
}
/*
* Check to see if in window region (if it has one)
*/
if (pwnd->hrgnClip != NULL) {
if (!GrePtInRegion(pwnd->hrgnClip, pt.x, pt.y))
continue;
}
/*
* Is this a sprite?
*/
if (TestWF(pwnd, WEFLAYERED)) {
if (!LayerHitTest(pwnd, pt))
continue;
}
#ifdef REDIRECTION
if (TestWF(pwnd, WEFEXTREDIRECTED)) {
continue;
}
#endif // REDIRECTION
/*
* Children?
*/
if ((pwnd->spwndChild != NULL) &&
PtInRect((LPRECT)&pwnd->rcClient, pt)) {
pwndT = SpeedHitTest(pwnd, pt);
if (pwndT != NULL)
return pwndT;
}
return pwnd;
}
return pwndParent;
}
/***************************************************************************\
* xxxWindowHitTest
*
* History:
* 08-Nov-1990 DavidPe Ported.
* 28-Nov-1990 DavidPe Add pwndTransparent support for HTTRANSPARENT.
* 25-Jan-1991 IanJa change PWNDPOS parameter to int *
* 19-Feb-1991 JimA Added enum access check
* 02-Nov-1992 ScottLu Removed pwndTransparent.
* 12-Nov-1992 ScottLu Took out fSendHitTest, fixed locking bug
\***************************************************************************/
HWND xxxWindowHitTest(
PWND pwnd,
POINT pt,
int *piPos,
DWORD dwHitTestFlags)
{
HWND hwndT;
TL tlpwnd;
CheckLock(pwnd);
hwndT = NULL;
ThreadLockNever(&tlpwnd);
while (pwnd != NULL) {
ThreadLockExchangeAlways(pwnd, &tlpwnd);
hwndT = xxxWindowHitTest2(pwnd, pt, piPos, dwHitTestFlags);
if (hwndT != NULL)
break;
pwnd = pwnd->spwndNext;
}
ThreadUnlock(&tlpwnd);
return hwndT;
}
/***************************************************************************\
* xxxWindowHitTest2
*
* When this routine is entered, all windows must be locked. When this
* routine returns a window handle, it locks that window handle and unlocks
* all windows. If this routine returns NULL, all windows are still locked.
* Ignores disabled and hidden windows.
*
* History:
* 08-Nov-1990 DavidPe Ported.
* 25-Jan-1991 IanJa change PWNDPOS parameter to int *
* 19-Feb-1991 JimA Added enum access check
* 12-Nov-1992 ScottLu Took out fSendHitTest
\***************************************************************************/
HWND xxxWindowHitTest2(
PWND pwnd,
POINT pt,
int *piPos,
DWORD dwHitTestFlags)
{
int ht = HTERROR, htGrip=HTBOTTOMRIGHT;
HWND hwndT;
TL tlpwndChild;
CheckLock(pwnd);
/*
* Are we at the bottom of the window chain?
*/
if (pwnd == NULL)
return NULL;
/*
* Are we looking at an hidden window?
*/
if (!TestWF(pwnd, WFVISIBLE))
return NULL;
/*
* Are we barking up the wrong tree?
*/
if (!PtInRect((LPRECT)&pwnd->rcWindow, pt)) {
return NULL;
}
if (pwnd->hrgnClip != NULL) {
if (!GrePtInRegion(pwnd->hrgnClip, pt.x, pt.y))
return(NULL);
}
if (TestWF(pwnd, WEFLAYERED)) {
if (!LayerHitTest(pwnd, pt))
return NULL;
}
#ifdef REDIRECTION
/*
* If this is called when the layered window is actually trying
* to process the message then let it see the hit test
*/
if (TestWF(pwnd, WEFEXTREDIRECTED) && PpiCurrent() != GETPTI(pwnd)->ppi) {
return NULL;
}
#endif // REDIRECTION
/*
* Are we looking at an disabled window?
*/
if (TestWF(pwnd, WFDISABLED) && (dwHitTestFlags & WHT_IGNOREDISABLED)) {
if (TestwndChild(pwnd)) {
return NULL;
} else {
ht = HTERROR;
goto Exit;
}
}
#ifdef SYSMODALWINDOWS
/*
* If SysModal window present and we're not in it, return an error.
* Be sure to assign the point to the SysModal window, so the message
* will be sure to be removed from the queue.
*/
if (!CheckPwndFilter(pwnd, gspwndSysModal)) {
pwnd = gspwndSysModal;
/*
* Fix notorious stack overflow bug (some WINABLE fix from Memphis)
*/
ht = HTCLIENT;
goto Exit;
}
#endif
/*
* Are we on a minimized window?
*/
if (!TestWF(pwnd, WFMINIMIZED)) {
/*
* Are we in the window's client area?
*/
if (PtInRect((LPRECT)&pwnd->rcClient, pt)) {
/*
* Recurse through the children.
*/
ThreadLock(pwnd->spwndChild, &tlpwndChild);
hwndT = xxxWindowHitTest(pwnd->spwndChild,
pt,
piPos,
dwHitTestFlags);
ThreadUnlock(&tlpwndChild);
if (hwndT != NULL)
return hwndT;
}
}
/*
* If window not in same task, don't send WM_NCHITTEST.
*/
if (GETPTI(pwnd) != PtiCurrent()) {
ht = HTCLIENT;
goto Exit;
}
/*
* Send the message.
*/
ht = (int)xxxSendMessage(pwnd, WM_NCHITTEST, 0, MAKELONG(pt.x, pt.y));
/*
* If window is transparent keep enumerating.
*/
if (ht == HTTRANSPARENT) {
return NULL;
}
Exit:
/*
* Set wndpos accordingly.
*/
if (piPos) {
*piPos = ht;
}
/*
* If this is a RTL mirrored window, then the grip is at
* HTBOTTOMLEFT (in terms of screen coordinates since they are
* not RTL mirrored).
*/
if (TestWF(pwnd, WEFLAYOUTRTL)) {
htGrip = HTBOTTOMLEFT;
}
/*
* if the click is in the sizebox of the window and this window itself is
* not sizable, return the window that will be sized by this sizebox
*/
if ((ht == htGrip) && !TestWF(pwnd, WFSIZEBOX)) {
PWND pwndT;
/*
* SizeBoxHwnd() can return NULL! We don't want to act like this
* is transparent if the sizebox isn't a grip
*/
pwnd = (pwndT = SizeBoxHwnd(pwnd)) ? pwndT : pwnd;
}
return HWq(pwnd);
}