- Fixups to set focus and show window support, added notes. Add is window visible. Fix a binary bit return, 1 is TRUE. Fix get client rectangle. Minor fixups.

svn path=/trunk/; revision=54634
This commit is contained in:
James Tabor 2011-12-10 06:08:29 +00:00
parent 3c7096002a
commit 9adebc4bec
3 changed files with 215 additions and 168 deletions

View file

@ -9,6 +9,9 @@
#include <win32k.h>
DBG_DEFAULT_CHANNEL(UserFocus);
PUSER_MESSAGE_QUEUE gpqForeground = NULL;
PUSER_MESSAGE_QUEUE gpqForegroundPrev = NULL;
HWND FASTCALL
IntGetCaptureWindow(VOID)
{
@ -190,9 +193,24 @@ IntFindChildWindowToOwner(PWND Root, PWND Owner)
return NULL;
}
/*
MSDN:
The system restricts which processes can set the foreground window. A process
can set the foreground window only if one of the following conditions is true:
* The process is the foreground process.
* The process was started by the foreground process.
* The process received the last input event.
* There is no foreground process.
* The foreground process is being debugged.
* The foreground is not locked (see LockSetForegroundWindow).
* The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
* No menus are active.
*/
static BOOL FASTCALL
co_IntSetForegroundAndFocusWindow(PWND Wnd, PWND FocusWindow, BOOL MouseActivate)
{
CBTACTIVATESTRUCT cbt;
HWND hWnd = Wnd->head.h;
HWND hWndPrev = NULL;
HWND hWndFocus = FocusWindow->head.h;
@ -212,7 +230,7 @@ co_IntSetForegroundAndFocusWindow(PWND Wnd, PWND FocusWindow, BOOL MouseActivate
if (0 == (Wnd->style & WS_VISIBLE) &&
Wnd->head.pti->pEThread->ThreadsProcess != CsrProcess)
{
TRACE("Failed - Invisible\n");
ERR("Failed - Invisible\n");
return FALSE;
}
@ -229,7 +247,14 @@ co_IntSetForegroundAndFocusWindow(PWND Wnd, PWND FocusWindow, BOOL MouseActivate
return TRUE;
}
/* FIXME: Call hooks. */
/* call CBT hook chain */
cbt.fMouse = MouseActivate;
cbt.hWndActive = hWndPrev;
if (co_HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hWnd, (LPARAM)&cbt))
{
ERR("IntSetForegroundAndFocusWindow WH_CBT Call Hook return!\n");
return 0;
}
co_IntSendDeactivateMessages(hWndPrev, hWnd);
co_IntSendKillFocusMessages(hWndFocusPrev, hWndFocus);
@ -326,12 +351,11 @@ co_IntSetActiveWindow(PWND Wnd OPTIONAL)
ASSERT(ThreadQueue != 0);
if (Wnd != 0)
{
if ((!(Wnd->style & WS_VISIBLE) &&
Wnd->head.pti->pEThread->ThreadsProcess != CsrProcess) ||
(Wnd->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
{
if ((Wnd->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
{
return ThreadQueue ? 0 : ThreadQueue->ActiveWindow;
/* Windows doesn't seem to return an error here */
return ThreadQueue->ActiveWindow;
}
hWnd = Wnd->head.h;
}
@ -350,9 +374,11 @@ co_IntSetActiveWindow(PWND Wnd OPTIONAL)
ERR("SetActiveWindow WH_CBT Call Hook return!\n");
return 0;
}
ThreadQueue->ActiveWindow = hWnd;
co_IntSendDeactivateMessages(hWndPrev, hWnd);
ThreadQueue->ActiveWindow = hWnd;
co_IntSendActivateMessages(hWndPrev, hWnd, FALSE);
/* FIXME */
@ -360,11 +386,11 @@ co_IntSetActiveWindow(PWND Wnd OPTIONAL)
return hWndPrev;
}
static
HWND FASTCALL
co_IntSetFocusWindow(PWND Window OPTIONAL)
co_UserSetFocus(PWND Window)
{
HWND hWndPrev = 0;
PWND pwndTop;
PTHREADINFO pti;
PUSER_MESSAGE_QUEUE ThreadQueue;
@ -381,14 +407,36 @@ co_IntSetFocusWindow(PWND Window OPTIONAL)
{
if (hWndPrev == Window->head.h)
{
return hWndPrev;
return hWndPrev; /* nothing to do */
}
/* Check if we can set the focus to this window */
for (pwndTop = Window; pwndTop != NULL; pwndTop = pwndTop->spwndParent )
{
if (pwndTop->style & (WS_MINIMIZED|WS_DISABLED)) return 0;
if ((pwndTop->style & (WS_POPUP|WS_CHILD)) != WS_CHILD) break;
}
if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)Window->head.h, (LPARAM)hWndPrev))
{
ERR("SetFocusWindow 1 WH_CBT Call Hook return!\n");
ERR("SetFocus 1 WH_CBT Call Hook return!\n");
return 0;
}
/* activate pwndTop if needed. */
if (pwndTop->head.h != ThreadQueue->ActiveWindow)
{
co_IntSetActiveWindow(pwndTop);
/* Abort if window destroyed */
if (Window->state2 & WNDS2_INDESTROY) return 0;
/* Do not change focus if the window is no longer active */
if (pwndTop->head.h != ThreadQueue->ActiveWindow)
{
ERR("SetFocus Top window did not go active!\n");
return 0;
}
}
ThreadQueue->FocusWindow = Window->head.h;
TRACE("Focus: %d -> %d\n", hWndPrev, Window->head.h);
@ -409,10 +457,6 @@ co_IntSetFocusWindow(PWND Window OPTIONAL)
return hWndPrev;
}
/*
* @implemented
*/
HWND FASTCALL
UserGetForegroundWindow(VOID)
{
@ -422,27 +466,6 @@ UserGetForegroundWindow(VOID)
return( ForegroundQueue != NULL ? ForegroundQueue->ActiveWindow : 0);
}
/*
* @implemented
*/
HWND APIENTRY
NtUserGetForegroundWindow(VOID)
{
DECLARE_RETURN(HWND);
TRACE("Enter NtUserGetForegroundWindow\n");
UserEnterExclusive();
RETURN( UserGetForegroundWindow());
CLEANUP:
TRACE("Leave NtUserGetForegroundWindow, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
HWND FASTCALL UserGetActiveWindow(VOID)
{
PTHREADINFO pti;
@ -453,57 +476,6 @@ HWND FASTCALL UserGetActiveWindow(VOID)
return( ThreadQueue ? ThreadQueue->ActiveWindow : 0);
}
HWND APIENTRY
NtUserSetActiveWindow(HWND hWnd)
{
USER_REFERENCE_ENTRY Ref;
DECLARE_RETURN(HWND);
TRACE("Enter NtUserSetActiveWindow(%x)\n", hWnd);
UserEnterExclusive();
if (hWnd)
{
PWND Window;
PTHREADINFO pti;
PUSER_MESSAGE_QUEUE ThreadQueue;
HWND hWndPrev;
if (!(Window = UserGetWindowObject(hWnd)))
{
RETURN( 0);
}
pti = PsGetCurrentThreadWin32Thread();
ThreadQueue = pti->MessageQueue;
if (Window->head.pti->MessageQueue != ThreadQueue)
{
EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
RETURN( 0);
}
UserRefObjectCo(Window, &Ref);
hWndPrev = co_IntSetActiveWindow(Window);
UserDerefObjectCo(Window);
RETURN( hWndPrev);
}
else
{
RETURN( co_IntSetActiveWindow(0));
}
CLEANUP:
TRACE("Leave NtUserSetActiveWindow, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* @implemented
*/
HWND APIENTRY
IntGetCapture(VOID)
{
@ -522,7 +494,6 @@ CLEANUP:
END_CLEANUP;
}
HWND FASTCALL
co_UserSetCapture(HWND hWnd)
{
@ -606,6 +577,72 @@ IntReleaseCapture(VOID)
return TRUE;
}
/*
* @implemented
*/
HWND APIENTRY
NtUserGetForegroundWindow(VOID)
{
DECLARE_RETURN(HWND);
TRACE("Enter NtUserGetForegroundWindow\n");
UserEnterExclusive();
RETURN( UserGetForegroundWindow());
CLEANUP:
TRACE("Leave NtUserGetForegroundWindow, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
HWND APIENTRY
NtUserSetActiveWindow(HWND hWnd)
{
USER_REFERENCE_ENTRY Ref;
DECLARE_RETURN(HWND);
TRACE("Enter NtUserSetActiveWindow(%x)\n", hWnd);
UserEnterExclusive();
if (hWnd)
{
PWND Window;
PTHREADINFO pti;
PUSER_MESSAGE_QUEUE ThreadQueue;
HWND hWndPrev;
if (!(Window = UserGetWindowObject(hWnd)))
{
RETURN( 0);
}
pti = PsGetCurrentThreadWin32Thread();
ThreadQueue = pti->MessageQueue;
if (Window->head.pti->MessageQueue != ThreadQueue)
{
EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
RETURN( 0);
}
UserRefObjectCo(Window, &Ref);
hWndPrev = co_IntSetActiveWindow(Window);
UserDerefObjectCo(Window);
RETURN( hWndPrev);
}
else
{
RETURN( co_IntSetActiveWindow(0));
}
CLEANUP:
TRACE("Leave NtUserSetActiveWindow, ret=%i\n",_ret_);
UserLeave();
END_CLEANUP;
}
/*
* @implemented
*/
@ -625,55 +662,6 @@ CLEANUP:
END_CLEANUP;
}
HWND FASTCALL co_UserSetFocus(PWND Wnd OPTIONAL)
{
if (Wnd)
{
PTHREADINFO pti;
PUSER_MESSAGE_QUEUE ThreadQueue;
HWND hWndPrev;
PWND TopWnd;
USER_REFERENCE_ENTRY Ref;
ASSERT_REFS_CO(Wnd);
pti = PsGetCurrentThreadWin32Thread();
ThreadQueue = pti->MessageQueue;
if (Wnd->style & (WS_MINIMIZE | WS_DISABLED))
{
return( (ThreadQueue ? ThreadQueue->FocusWindow : 0));
}
if (Wnd->head.pti->MessageQueue != ThreadQueue)
{
EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
return( 0);
}
TopWnd = UserGetAncestor(Wnd, GA_ROOT);
if (TopWnd && TopWnd->head.h != UserGetActiveWindow())
{
// PWND WndTops = UserGetWindowObject(hWndTop);
UserRefObjectCo(TopWnd, &Ref);
co_IntSetActiveWindow(TopWnd);
UserDerefObjectCo(TopWnd);
}
hWndPrev = co_IntSetFocusWindow(Wnd);
return( hWndPrev);
}
else
{
return( co_IntSetFocusWindow(NULL));
}
}
/*
* @implemented
*/

View file

@ -108,6 +108,25 @@ IntIsWindow(HWND hWnd)
return TRUE;
}
BOOL FASTCALL
IntIsWindowVisible(PWND Wnd)
{
BOOL Ret = TRUE;
do
{
if (!(Wnd->style & WS_VISIBLE))
{
Ret = FALSE;
break;
}
if (Wnd->spwndParent != NULL)
Wnd = Wnd->spwndParent;
else
break;
}
while (Wnd != NULL);
return Ret;
}
PWND FASTCALL
IntGetParent(PWND Wnd)
@ -138,7 +157,7 @@ IntEnableWindow( HWND hWnd, BOOL bEnable )
}
/* check if updating is needed */
bIsDisabled = (pWnd->style & WS_DISABLED);
bIsDisabled = !!(pWnd->style & WS_DISABLED);
Update = bIsDisabled;
if (bEnable)
@ -758,8 +777,6 @@ co_DestroyThreadWindows(struct _ETHREAD *Thread)
}
}
/*!
* Internal function.
* Returns client window rectangle relative to the upper-left corner of client area.
@ -767,17 +784,34 @@ co_DestroyThreadWindows(struct _ETHREAD *Thread)
* \note Does not check the validity of the parameters
*/
VOID FASTCALL
IntGetClientRect(PWND Window, RECTL *Rect)
IntGetClientRect(PWND Wnd, RECTL *Rect)
{
ASSERT( Window );
ASSERT( Wnd );
ASSERT( Rect );
Rect->left = Rect->top = 0;
Rect->right = Window->rcClient.right - Window->rcClient.left;
Rect->bottom = Window->rcClient.bottom - Window->rcClient.top;
if (Wnd->style & WS_MINIMIZED)
{
Rect->left = Rect->top = 0;
Rect->right = UserGetSystemMetrics(SM_CXMINIMIZED);
Rect->bottom = UserGetSystemMetrics(SM_CYMINIMIZED);
return;
}
if ( Wnd != UserGetDesktopWindow()) // Wnd->fnid != FNID_DESKTOP )
{
*Rect = Wnd->rcClient;
RECTL_vOffsetRect(Rect, -Wnd->rcClient.left, -Wnd->rcClient.top);
}
else
{
Rect->left = Rect->top = 0;
Rect->right = Wnd->rcClient.right;
Rect->bottom = Wnd->rcClient.bottom;
/* Do this until Init bug is fixed. This sets 640x480, see InitMetrics.
Rect->right = UserGetSystemMetrics(SM_CXSCREEN);
Rect->bottom = UserGetSystemMetrics(SM_CYSCREEN);
*/
}
}
PMENU_OBJECT FASTCALL
IntGetSystemMenu(PWND Window, BOOL bRevert, BOOL RetMenu)
{
@ -1125,6 +1159,7 @@ co_IntSetParent(PWND Wnd, PWND WndNewParent)
* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
* for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE
*/
if (WasVisible) co_WinPosShowWindow(Wnd, SW_SHOWNORMAL);
return WndOldParent;
}
@ -1637,13 +1672,15 @@ PWND FASTCALL IntCreateWindow(CREATESTRUCTW* Cs,
pWnd->spwndOwner = OwnerWindow;
pWnd->fnid = 0;
pWnd->hWndLastActive = hWnd;
pWnd->state2 |= WNDS2_WIN40COMPAT;
pWnd->state2 |= WNDS2_WIN40COMPAT; // FIXME!!!
pWnd->pcls = Class;
pWnd->hModule = Cs->hInstance;
pWnd->style = Cs->style & ~WS_VISIBLE;
pWnd->ExStyle = Cs->dwExStyle;
pWnd->cbwndExtra = pWnd->pcls->cbwndExtra;
pWnd->pActCtx = acbiBuffer;
pWnd->InternalPos.MaxPos.x = pWnd->InternalPos.MaxPos.y = -1;
pWnd->InternalPos.IconPos.x = pWnd->InternalPos.IconPos.y = -1;
IntReferenceMessageQueue(pWnd->head.pti->MessageQueue);
if (pWnd->spwndParent != NULL && Cs->hwndParent != 0)
@ -1759,16 +1796,23 @@ PWND FASTCALL IntCreateWindow(CREATESTRUCTW* Cs,
if (!(pWnd->style & WS_POPUP))
{
pWnd->style |= WS_CAPTION;
pWnd->state |= WNDS_SENDSIZEMOVEMSGS;
}
}
/*
* WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
* why does the user get to set it?
*/
if ((pWnd->ExStyle & WS_EX_DLGMODALFRAME) ||
(pWnd->style & (WS_DLGFRAME | WS_THICKFRAME)))
pWnd->ExStyle |= WS_EX_WINDOWEDGE;
else
pWnd->ExStyle &= ~WS_EX_WINDOWEDGE;
if (!(pWnd->style & (WS_CHILD | WS_POPUP)))
pWnd->state |= WNDS_SENDSIZEMOVEMSGS;
/* create system menu */
if((Cs->style & WS_SYSMENU) )//&& (dwStyle & WS_CAPTION) == WS_CAPTION)
{
@ -3670,11 +3714,11 @@ NtUserQueryWindow(HWND hWnd, DWORD Index)
break;
case QUERY_WINDOW_ACTIVE:
Result = (DWORD)UserGetActiveWindow();
Result = (DWORD)pWnd->head.pti->MessageQueue->ActiveWindow;
break;
case QUERY_WINDOW_FOCUS:
Result = (DWORD)IntGetFocusWindow();
Result = (DWORD)pWnd->head.pti->MessageQueue->FocusWindow;
break;
case QUERY_WINDOW_ISHUNG:

View file

@ -23,6 +23,8 @@ DBG_DEFAULT_CHANNEL(UserWinpos);
#define SWP_AGG_STATUSFLAGS \
(SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
#define EMPTYPOINT(pt) ((pt).x == -1 && (pt).y == -1)
/* FUNCTIONS *****************************************************************/
BOOL FASTCALL
@ -325,6 +327,7 @@ co_WinPosMinMaximize(PWND Wnd, UINT ShowFlag, RECT* NewPos)
return 0;
}
Wnd->style &= ~WS_MAXIMIZE;
Wnd->state2 &= ~WNDS2_MAXIMIZEBUTTONDOWN;
*NewPos = Wnd->InternalPos.NormalRect;
NewPos->right -= NewPos->left;
NewPos->bottom -= NewPos->top;
@ -452,9 +455,9 @@ co_WinPosGetMinMaxInfo(PWND Window, POINT* MaxSize, POINT* MaxPos,
MinMax.ptMaxPosition.x = -xinc;
MinMax.ptMaxPosition.y = -yinc;
//if (!EMPTYPOINT(win->max_pos)) MinMax.ptMaxPosition = win->max_pos;
if (!EMPTYPOINT(Window->InternalPos.MaxPos)) MinMax.ptMaxPosition = Window->InternalPos.MaxPos;
co_IntSendMessage(Window->head.h, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax);
co_IntSendMessage(Window->head.h, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax);
/* if the app didn't change the values, adapt them for the current monitor */
if ((monitor = IntGetPrimaryMonitor()))
@ -1374,11 +1377,13 @@ co_WinPosShowWindow(PWND Wnd, INT Cmd)
UINT Swp = 0;
RECTL NewPos;
BOOLEAN ShowFlag;
LONG style;
// HRGN VisibleRgn;
ASSERT_REFS_CO(Wnd);
WasVisible = (Wnd->style & WS_VISIBLE) != 0;
style = Wnd->style;
switch (Cmd)
{
@ -1403,7 +1408,7 @@ co_WinPosShowWindow(PWND Wnd, INT Cmd)
case SW_MINIMIZE:
{
Swp |= SWP_NOACTIVATE;
if (!(Wnd->style & WS_MINIMIZE))
if (!(style & WS_MINIMIZE))
{
Swp |= co_WinPosMinMaximize(Wnd, SW_MINIMIZE, &NewPos) |
SWP_FRAMECHANGED;
@ -1422,7 +1427,7 @@ co_WinPosShowWindow(PWND Wnd, INT Cmd)
case SW_SHOWMAXIMIZED:
{
Swp |= SWP_SHOWWINDOW;
if (!(Wnd->style & WS_MAXIMIZE))
if (!(style & WS_MAXIMIZE))
{
Swp |= co_WinPosMinMaximize(Wnd, SW_MAXIMIZE, &NewPos) |
SWP_FRAMECHANGED;
@ -1445,9 +1450,11 @@ co_WinPosShowWindow(PWND Wnd, INT Cmd)
if (WasVisible) return(TRUE); // Nothing to do!
Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
/* Don't activate the topmost window. */
if (style & WS_CHILD) Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
break;
case SW_SHOWNOACTIVATE:
Wnd->state2 &= ~WNDS2_MAXIMIZEBUTTONDOWN;
//Swp |= SWP_NOZORDER;
Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
/* Fall through. */
@ -1455,7 +1462,7 @@ co_WinPosShowWindow(PWND Wnd, INT Cmd)
case SW_SHOWDEFAULT:
case SW_RESTORE:
Swp |= SWP_SHOWWINDOW;
if (Wnd->style & (WS_MINIMIZE | WS_MAXIMIZE))
if (style & (WS_MINIMIZE | WS_MAXIMIZE))
{
Swp |= co_WinPosMinMaximize(Wnd, SW_RESTORE, &NewPos) |
SWP_FRAMECHANGED;
@ -1476,6 +1483,8 @@ co_WinPosShowWindow(PWND Wnd, INT Cmd)
if (ShowFlag != WasVisible)
{
co_IntSendMessageNoWait(Wnd->head.h, WM_SHOWWINDOW, ShowFlag, 0);
if (!(Wnd->state2 & WNDS2_WIN31COMPAT))
co_IntSendMessageNoWait(Wnd->head.h, WM_SETVISIBLE, ShowFlag, 0);
}
/* We can't activate a child window */
@ -1484,7 +1493,15 @@ co_WinPosShowWindow(PWND Wnd, INT Cmd)
{
Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
}
#if 0 // Explorer issues with common controls. Someone does not know how CS_SAVEBITS works.
if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
Wnd->pcls->style & CS_SAVEBITS &&
((Cmd == SW_SHOW) || (Cmd == SW_NORMAL)))
{
co_IntSetActiveWindow(Wnd);
Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
}
#endif
co_WinPosSetWindowPos(Wnd, 0 != (Wnd->ExStyle & WS_EX_TOPMOST)
? HWND_TOPMOST : HWND_TOP,
NewPos.left, NewPos.top, NewPos.right, NewPos.bottom, LOWORD(Swp));
@ -1508,8 +1525,10 @@ co_WinPosShowWindow(PWND Wnd, INT Cmd)
ThreadFocusWindow = UserGetWindowObject(IntGetThreadFocusWindow());
/* Revert focus to parent */
if (ThreadFocusWindow && (Wnd == ThreadFocusWindow ||
/* if (ThreadFocusWindow && (Wnd == ThreadFocusWindow ||
IntIsChildWindow(Wnd, ThreadFocusWindow)))
*/
if (Wnd == ThreadFocusWindow)
{
//faxme: as long as we have ref on Window, we also, indirectly, have ref on parent...
co_UserSetFocus(Wnd->spwndParent);
@ -1524,13 +1543,9 @@ co_WinPosShowWindow(PWND Wnd, INT Cmd)
co_WinPosSendSizeMove(Wnd);
}
/* Activate the window if activation is not requested and the window is not minimized */
/*
if (!(Swp & (SWP_NOACTIVATE | SWP_HIDEWINDOW)) && !(Window->style & WS_MINIMIZE))
{
WinPosChangeActiveWindow(Wnd, FALSE);
}
*/
/* if previous state was minimized Windows sets focus to the window */
if (style & WS_MINIMIZE) co_UserSetFocus(Wnd);
return(WasVisible);
}
@ -1744,8 +1759,8 @@ BOOL FASTCALL IntEndDeferWindowPosEx( HDWP hdwp )
winpos->pos.cx, winpos->pos.cy, winpos->pos.flags);
pwnd = UserGetWindowObject(winpos->pos.hwnd);
if(!pwnd)
continue;
if (!pwnd)
continue;
UserRefObjectCo(pwnd, &Ref);