- Fix one of the greatest hacks in message handling: do not wake up every message queue when there is mouse or keyboard input ( wake only the thread that must take input)
- rewrite co_WinPosWindowFromPoint, co_MsqInsertMouseMessage and co_MsqPeekHardwareMessage
- port co_IntProcessMouseMessage and MsqSendParentNotify from wine 
- call co_IntProcessHardwareMessage from co_MsqPeekHardwareMessage, and not from co_IntPeekMessage
- move co_IntProcessHardwareMessage, co_IntProcessKeyboardMessage and co_IntProcessMouseMessage to msgqueue.c

svn path=/trunk/; revision=49710
This commit is contained in:
Giannis Adamopoulos 2010-11-22 20:10:56 +00:00
parent 8b5175e0ab
commit 9b693d8c69
6 changed files with 573 additions and 1120 deletions

View file

@ -58,8 +58,12 @@ typedef struct _USER_MESSAGE_QUEUE
LIST_ENTRY HardwareMessagesListHead;
/* Lock for the hardware message list. */
KMUTEX HardwareLock;
/* Pointer to the current WM_MOUSEMOVE message */
PUSER_MESSAGE MouseMoveMsg;
/* True if a WM_MOUSEMOVE is pending */
BOOLEAN MouseMoved;
/* Current WM_MOUSEMOVE message */
MSG MouseMoveMsg;
/* Last click message for translating double clicks */
MSG msgDblClk;
/* True if a WM_QUIT message is pending. */
BOOLEAN QuitPosted;
/* The quit exit code. */
@ -122,18 +126,25 @@ VOID FASTCALL
MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue, ULONG ExitCode);
BOOLEAN APIENTRY
MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
IN BOOLEAN Remove,
IN PWND Window,
IN UINT MsgFilterLow,
IN UINT MsgFilterHigh,
OUT PMSG Message);
IN BOOLEAN Remove,
IN PWND Window,
IN UINT MsgFilterLow,
IN UINT MsgFilterHigh,
OUT PMSG Message);
BOOL APIENTRY
co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
IN BOOL Remove,
IN PWND Window,
IN UINT MsgFilterLow,
IN UINT MsgFilterHigh,
OUT MSG* pMsg);
IN BOOL Remove,
IN PWND Window,
IN UINT MsgFilterLow,
IN UINT MsgFilterHigh,
OUT MSG* pMsg);
BOOL APIENTRY
co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue,
IN BOOL Remove,
IN PWND Window,
IN UINT MsgFilterLow,
IN UINT MsgFilterHigh,
OUT MSG* pMsg);
BOOLEAN FASTCALL
MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQueue);
VOID FASTCALL

View file

@ -27,9 +27,8 @@ BOOLEAN FASTCALL
co_WinPosShowWindow(PWND Window, INT Cmd);
void FASTCALL
co_WinPosSendSizeMove(PWND Window);
USHORT FASTCALL
co_WinPosWindowFromPoint(PWND ScopeWin, PUSER_MESSAGE_QUEUE OnlyHitTests, POINT *WinPoint,
PWND* Window);
PWND FASTCALL
co_WinPosWindowFromPoint(PWND ScopeWin, POINT *WinPoint, USHORT* HitTest);
VOID FASTCALL co_WinPosActivateOtherWindow(PWND Window);
VOID FASTCALL WinPosInitInternalPos(PWND WindowObject,

View file

@ -502,387 +502,6 @@ IntDispatchMessage(PMSG pMsg)
return retval;
}
VOID FASTCALL
co_IntSendHitTestMessages(PUSER_MESSAGE_QUEUE ThreadQueue, LPMSG Msg)
{
if(!Msg->hwnd || ThreadQueue->CaptureWindow)
{
return;
}
switch(Msg->message)
{
case WM_MOUSEMOVE:
{
co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(HTCLIENT, Msg->message));
break;
}
case WM_NCMOUSEMOVE:
{
co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(Msg->wParam, Msg->message));
break;
}
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_XBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_MBUTTONDBLCLK:
case WM_RBUTTONDBLCLK:
case WM_XBUTTONDBLCLK:
{
WPARAM wParam;
PSYSTEM_CURSORINFO CurInfo;
CurInfo = IntGetSysCursorInfo();
wParam = (WPARAM)(CurInfo->ButtonsDown);
co_IntSendMessage(Msg->hwnd, WM_MOUSEMOVE, wParam, Msg->lParam);
co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(HTCLIENT, Msg->message));
break;
}
case WM_NCLBUTTONDOWN:
case WM_NCMBUTTONDOWN:
case WM_NCRBUTTONDOWN:
case WM_NCXBUTTONDOWN:
case WM_NCLBUTTONDBLCLK:
case WM_NCMBUTTONDBLCLK:
case WM_NCRBUTTONDBLCLK:
case WM_NCXBUTTONDBLCLK:
{
co_IntSendMessage(Msg->hwnd, WM_NCMOUSEMOVE, (WPARAM)Msg->wParam, Msg->lParam);
co_IntSendMessage(Msg->hwnd, WM_SETCURSOR, (WPARAM)Msg->hwnd, MAKELPARAM(Msg->wParam, Msg->message));
break;
}
}
}
BOOL FASTCALL
co_IntActivateWindowMouse( PUSER_MESSAGE_QUEUE ThreadQueue,
LPMSG Msg,
PWND MsgWindow,
USHORT *HitTest)
{
ULONG Result;
PWND Parent;
ASSERT_REFS_CO(MsgWindow);
if(*HitTest == (USHORT)HTTRANSPARENT)
{
/* eat the message, search again! */
return TRUE;
}
Parent = IntGetParent(MsgWindow);//fixme: deref retval?
/* If no parent window, pass MsgWindows HWND as wParam. Fixes bug #3111 */
Result = co_IntSendMessage(MsgWindow->head.h,
WM_MOUSEACTIVATE,
(WPARAM) (Parent ? Parent->head.h : MsgWindow->head.h),
(LPARAM)MAKELONG(*HitTest, Msg->message)
);
switch (Result)
{
case MA_NOACTIVATEANDEAT:
return TRUE;
case MA_NOACTIVATE:
break;
case MA_ACTIVATEANDEAT:
co_IntMouseActivateWindow(MsgWindow);
return TRUE;
default:
/* MA_ACTIVATE */
co_IntMouseActivateWindow(MsgWindow);
break;
}
return FALSE;
}
BOOL FASTCALL
co_IntTranslateMouseMessage( PUSER_MESSAGE_QUEUE ThreadQueue,
LPMSG Msg,
USHORT *HitTest,
BOOL Remove)
{
PWND Window;
USER_REFERENCE_ENTRY Ref, DesktopRef;
if(!(Window = UserGetWindowObject(Msg->hwnd)))
{
/* let's just eat the message?! */
return TRUE;
}
*HitTest = HTCLIENT;
UserRefObjectCo(Window, &Ref);
if ( ThreadQueue == Window->head.pti->MessageQueue &&
ThreadQueue->CaptureWindow != Window->head.h)
{
/* only send WM_NCHITTEST messages if we're not capturing the window! */
if (Remove )
{
*HitTest = co_IntSendMessage(Window->head.h, WM_NCHITTEST, 0,
MAKELONG(Msg->pt.x, Msg->pt.y));
}
/* else we are going to see this message again, but then with Remove == TRUE */
if (*HitTest == (USHORT)HTTRANSPARENT)
{
PWND DesktopWindow;
HWND hDesktop = IntGetDesktopWindow();
if ((DesktopWindow = UserGetWindowObject(hDesktop)))
{
PWND Wnd;
UserRefObjectCo(DesktopWindow, &DesktopRef);
co_WinPosWindowFromPoint(DesktopWindow, Window->head.pti->MessageQueue, &Msg->pt, &Wnd);
if (Wnd)
{
if (Wnd != Window)
{
/* post the message to the other window */
Msg->hwnd = Wnd->head.h;
if(!(Wnd->state & WNDS_DESTROYED))
{
MsqPostMessage(Wnd->head.pti->MessageQueue, Msg, FALSE,
Msg->message == WM_MOUSEMOVE ? QS_MOUSEMOVE :
QS_MOUSEBUTTON);
}
/* eat the message */
UserDereferenceObject(Wnd);
UserDerefObjectCo(DesktopWindow);
UserDerefObjectCo(Window);
return TRUE;
}
UserDereferenceObject(Wnd);
}
UserDerefObjectCo(DesktopWindow);
}
}
}
if ( gspv.bMouseClickLock &&
((Msg->message == WM_LBUTTONUP) ||
(Msg->message == WM_LBUTTONDOWN) ) )
{
if (MsqIsClkLck(Msg, Remove))
{
// FIXME: drop the message, hack: use WM_NULL
Msg->message = WM_NULL;
}
}
if (IS_BTN_MESSAGE(Msg->message, DOWN))
{
/* generate double click messages, if necessary */
if ((((*HitTest) != HTCLIENT) ||
(Window->pcls->style & CS_DBLCLKS)) &&
MsqIsDblClk(Msg, Remove))
{
Msg->message += WM_LBUTTONDBLCLK - WM_LBUTTONDOWN;
}
}
if(Msg->message != WM_MOUSEWHEEL)
{
if ((*HitTest) != HTCLIENT)
{
Msg->message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
if ( (Msg->message == WM_NCRBUTTONUP) &&
(((*HitTest) == HTCAPTION) || ((*HitTest) == HTSYSMENU)) )
{
Msg->message = WM_CONTEXTMENU;
Msg->wParam = (WPARAM)Window->head.h;
}
else
{
Msg->wParam = *HitTest;
}
Msg->lParam = MAKELONG(Msg->pt.x, Msg->pt.y);
}
else if ( ThreadQueue->MoveSize == NULL &&
ThreadQueue->MenuOwner == NULL )
{
/* NOTE: Msg->pt should remain in screen coordinates. -- FiN */
Msg->lParam = MAKELONG(
Msg->pt.x - (WORD)Window->rcClient.left,
Msg->pt.y - (WORD)Window->rcClient.top);
}
}
UserDerefObjectCo(Window);
return FALSE;
}
BOOL ProcessMouseMessage(MSG* Msg, BOOLEAN RemoveMessages)
{
MOUSEHOOKSTRUCT MHook;
EVENTMSG Event;
PTHREADINFO pti;
PUSER_MESSAGE_QUEUE ThreadQueue;
USER_REFERENCE_ENTRY Ref;
USHORT HitTest = HTNOWHERE;
pti = PsGetCurrentThreadWin32Thread();
ThreadQueue = pti->MessageQueue;
if(RemoveMessages)
{
PWND MsgWindow = NULL;
/* Mouse message process */
if( Msg->hwnd &&
( MsgWindow = UserGetWindowObject(Msg->hwnd) ) &&
Msg->message >= WM_MOUSEFIRST &&
Msg->message <= WM_MOUSELAST )
{
USHORT HitTest;
UserRefObjectCo(MsgWindow, &Ref);
if ( co_IntTranslateMouseMessage( ThreadQueue,
Msg,
&HitTest,
TRUE))
/* FIXME - check message filter again, if the message doesn't match anymore,
search again */
{
UserDerefObjectCo(MsgWindow);
/* eat the message, search again */
return FALSE;
}
if(ThreadQueue->CaptureWindow == NULL)
{
co_IntSendHitTestMessages(ThreadQueue, Msg);
if ( ( Msg->message != WM_MOUSEMOVE &&
Msg->message != WM_NCMOUSEMOVE ) &&
IS_BTN_MESSAGE(Msg->message, DOWN) &&
co_IntActivateWindowMouse(ThreadQueue, Msg, MsgWindow, &HitTest) )
{
UserDerefObjectCo(MsgWindow);
/* eat the message, search again */
return FALSE;
}
}
UserDerefObjectCo(MsgWindow);
}
else
{
co_IntSendHitTestMessages(ThreadQueue, Msg);
}
return TRUE;
}
if ( ( Msg->hwnd &&
Msg->message >= WM_MOUSEFIRST &&
Msg->message <= WM_MOUSELAST ) &&
co_IntTranslateMouseMessage( ThreadQueue,
Msg,
&HitTest,
FALSE) )
/* FIXME - check message filter again, if the message doesn't match anymore,
search again */
{
/* eat the message, search again */
return FALSE;
}
pti->rpdesk->htEx = HitTest; /* Now set the capture hit. */
Event.message = Msg->message;
Event.time = Msg->time;
Event.hwnd = Msg->hwnd;
Event.paramL = Msg->pt.x;
Event.paramH = Msg->pt.y;
co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event);
MHook.pt = Msg->pt;
MHook.hwnd = Msg->hwnd;
MHook.wHitTestCode = HitTest;
MHook.dwExtraInfo = 0;
if (co_HOOK_CallHooks( WH_MOUSE,
RemoveMessages ? HC_ACTION : HC_NOREMOVE,
Msg->message,
(LPARAM)&MHook ))
{
MHook.pt = Msg->pt;
MHook.hwnd = Msg->hwnd;
MHook.wHitTestCode = HitTest;
MHook.dwExtraInfo = 0;
co_HOOK_CallHooks( WH_CBT,
HCBT_CLICKSKIPPED,
Msg->message,
(LPARAM)&MHook);
DPRINT1("MouseMessage WH_CBT Call Hook return!\n");
return FALSE;
}
return TRUE;
}
BOOL ProcessKeyboardMessage(MSG* Msg, BOOLEAN RemoveMessages)
{
EVENTMSG Event;
Event.message = Msg->message;
Event.hwnd = Msg->hwnd;
Event.time = Msg->time;
Event.paramL = (Msg->wParam & 0xFF) | (HIWORD(Msg->lParam) << 8);
Event.paramH = Msg->lParam & 0x7FFF;
if (HIWORD(Msg->lParam) & 0x0100) Event.paramH |= 0x8000;
co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event);
if (co_HOOK_CallHooks( WH_KEYBOARD,
RemoveMessages ? HC_ACTION : HC_NOREMOVE,
LOWORD(Msg->wParam),
Msg->lParam))
{
/* skip this message */
co_HOOK_CallHooks( WH_CBT,
HCBT_KEYSKIPPED,
LOWORD(Msg->wParam),
Msg->lParam );
DPRINT1("KeyboardMessage WH_CBT Call Hook return!\n");
return FALSE;
}
return TRUE;
}
BOOL ProcessHardwareMessage(MSG* Msg, BOOLEAN RemoveMessages)
{
if ( IS_MOUSE_MESSAGE(Msg->message))
{
if (!ProcessMouseMessage(Msg, RemoveMessages))
{
return FALSE;
}
}
else if ( IS_KBD_MESSAGE(Msg->message))
{
if(!ProcessKeyboardMessage(Msg, RemoveMessages))
{
return FALSE;
}
}
return TRUE;
}
/*
* Internal version of PeekMessage() doing all the work
*/
@ -933,27 +552,33 @@ co_IntPeekMessage( PMSG Msg,
/* Now check for normal messages. */
if (MsqPeekMessage( ThreadQueue,
RemoveMessages,
Window,
MsgFilterMin,
MsgFilterMax,
Msg ))
RemoveMessages,
Window,
MsgFilterMin,
MsgFilterMax,
Msg ))
{
return TRUE;
}
/* Check for hardware events. */
if(co_MsqPeekHardwareMessage( ThreadQueue,
if(co_MsqPeekMouseMove(ThreadQueue,
RemoveMessages,
Window,
MsgFilterMin,
MsgFilterMax,
Msg ))
{
return TRUE;
}
if(co_MsqPeekHardwareMessage(ThreadQueue,
RemoveMessages,
Window,
MsgFilterMin,
MsgFilterMax,
Msg))
{
if(!ProcessHardwareMessage(Msg, RemoveMessages))
continue;
return TRUE;
}

File diff suppressed because it is too large Load diff

View file

@ -4424,6 +4424,7 @@ NtUserWindowFromPoint(LONG X, LONG Y)
POINT pt;
HWND Ret;
PWND DesktopWindow = NULL, Window = NULL;
USHORT hittest;
DECLARE_RETURN(HWND);
USER_REFERENCE_ENTRY Ref;
@ -4442,7 +4443,7 @@ NtUserWindowFromPoint(LONG X, LONG Y)
UserRefObjectCo(DesktopWindow, &Ref);
pti = PsGetCurrentThreadWin32Thread();
co_WinPosWindowFromPoint(DesktopWindow, pti->MessageQueue, &pt, &Window);
Window = co_WinPosWindowFromPoint(DesktopWindow, &pt, &hittest);
if(Window)
{

View file

@ -1578,162 +1578,99 @@ co_WinPosShowWindow(PWND Wnd, INT Cmd)
return(WasVisible);
}
#if 0
/* find child of 'parent' that contains the given point (in parent-relative coords) */
PWND child_window_from_point(PWND parent, int x, int y )
{
PWND Wnd;// = parent->spwndChild;
// LIST_FOR_EACH_ENTRY( Wnd, &parent->children, struct window, entry )
for (Wnd = parent->spwndChild; Wnd; Wnd = Wnd->spwndNext)
{
if (!IntPtInWindow( Wnd, x, y )) continue; /* skip it */
/* if window is minimized or disabled, return at once */
if (Wnd->style & (WS_MINIMIZE|WS_DISABLED)) return Wnd;
/* if point is not in client area, return at once */
if (x < Wnd->rcClient.left || x >= Wnd->rcClient.right ||
y < Wnd->rcClient.top || y >= Wnd->rcClient.bottom)
return Wnd;
return child_window_from_point( Wnd, x - Wnd->rcClient.left, y - Wnd->rcClient.top );
}
return parent; /* not found any child */
}
#endif
/* wine server: child_window_from_point
Caller must dereference the "returned" Window
*/
static
VOID FASTCALL
PWND FASTCALL
co_WinPosSearchChildren(
PWND ScopeWin,
PUSER_MESSAGE_QUEUE OnlyHitTests,
POINT *Point,
PWND* Window,
USHORT *HitTest
)
{
PWND Current;
HWND *List, *phWnd;
USER_REFERENCE_ENTRY Ref;
PWND pwndChild;
HWND *List, *phWnd;
ASSERT_REFS_CO(ScopeWin);
if (!(ScopeWin->style & WS_VISIBLE))
{
return NULL;
}
if ((List = IntWinListChildren(ScopeWin)))
{
for (phWnd = List; *phWnd; ++phWnd)
{
if (!(Current = UserGetWindowObject(*phWnd)))
continue;
if ((ScopeWin->style & WS_DISABLED))
{
return NULL;
}
if (!(Current->style & WS_VISIBLE))
{
continue;
}
if (!IntPtInWindow(ScopeWin, Point->x, Point->y))
{
return NULL;
}
if ((Current->style & (WS_POPUP | WS_CHILD | WS_DISABLED)) ==
(WS_CHILD | WS_DISABLED))
{
continue;
}
UserReferenceObject(ScopeWin);
if (!IntPtInWindow(Current, Point->x, Point->y))
{
continue;
}
if (*Window) UserDereferenceObject(*Window);
*Window = Current;
UserReferenceObject(*Window);
if (Current->style & WS_MINIMIZE)
{
*HitTest = HTCAPTION;
break;
}
if (Current->style & WS_DISABLED)
{
*HitTest = HTERROR;
break;
}
UserRefObjectCo(Current, &Ref);
if (OnlyHitTests && (Current->head.pti->MessageQueue == OnlyHitTests))
{
*HitTest = co_IntSendMessage(Current->head.h, WM_NCHITTEST, 0,
MAKELONG(Point->x, Point->y));
if ((*HitTest) == (USHORT)HTTRANSPARENT)
if (Point->x - ScopeWin->rcClient.left < ScopeWin->rcClient.right &&
Point->y - ScopeWin->rcClient.top < ScopeWin->rcClient.bottom )
{
List = IntWinListChildren(ScopeWin);
if(List)
{
for (phWnd = List; *phWnd; ++phWnd)
{
UserDerefObjectCo(Current);
continue;
if (!(pwndChild = UserGetWindowObject(*phWnd)))
{
continue;
}
pwndChild = co_WinPosSearchChildren(pwndChild, Point, HitTest);
if(pwndChild != NULL)
{
/* We found a window. Don't send any more WM_NCHITTEST messages */
UserDereferenceObject(ScopeWin);
return pwndChild;
}
}
}
else
*HitTest = HTCLIENT;
}
if (Point->x >= Current->rcClient.left &&
Point->x < Current->rcClient.right &&
Point->y >= Current->rcClient.top &&
Point->y < Current->rcClient.bottom)
{
co_WinPosSearchChildren(Current, OnlyHitTests, Point, Window, HitTest);
}
ExFreePool(List);
}
UserDerefObjectCo(Current);
break;
}
ExFreePool(List);
}
*HitTest = co_IntSendMessage(ScopeWin->head.h, WM_NCHITTEST, 0,
MAKELONG(Point->x, Point->y));
if ((*HitTest) == (USHORT)HTTRANSPARENT)
{
UserDereferenceObject(ScopeWin);
return NULL;
}
return ScopeWin;
}
/* wine: WINPOS_WindowFromPoint */
USHORT FASTCALL
co_WinPosWindowFromPoint(PWND ScopeWin, PUSER_MESSAGE_QUEUE OnlyHitTests, POINT *WinPoint,
PWND* Window)
PWND FASTCALL
co_WinPosWindowFromPoint(PWND ScopeWin, POINT *WinPoint, USHORT* HitTest)
{
HWND DesktopWindowHandle;
PWND DesktopWindow;
PWND Window;
POINT Point = *WinPoint;
USHORT HitTest;
USER_REFERENCE_ENTRY Ref;
if( ScopeWin == NULL )
{
ScopeWin = UserGetDesktopWindow();
if(ScopeWin == NULL)
return NULL;
}
*HitTest = HTNOWHERE;
ASSERT_REFS_CO(ScopeWin);
UserRefObjectCo(ScopeWin, &Ref);
*Window = NULL;
Window = co_WinPosSearchChildren(ScopeWin, &Point, HitTest);
if(!ScopeWin)
{
DPRINT1("WinPosWindowFromPoint(): ScopeWin == NULL!\n");
return(HTERROR);
}
UserDerefObjectCo(ScopeWin);
if(Window)
ASSERT_REFS_CO(Window);
ASSERT_REFS_CO(ScopeWin);
if (ScopeWin->style & WS_DISABLED)
{
return(HTERROR);
}
/* Translate the point to the space of the scope window. */
DesktopWindowHandle = IntGetDesktopWindow();
if((DesktopWindowHandle != ScopeWin->head.h) &&
(DesktopWindow = UserGetWindowObject(DesktopWindowHandle)))
{
Point.x += ScopeWin->rcClient.left - DesktopWindow->rcClient.left;
Point.y += ScopeWin->rcClient.top - DesktopWindow->rcClient.top;
}
HitTest = HTNOWHERE;
co_WinPosSearchChildren(ScopeWin, OnlyHitTests, &Point, Window, &HitTest);
return ((*Window) ? HitTest : HTNOWHERE);
return Window;
}
BOOL