From 81a46fb20dd35dba4fd9cf58b04cb34142934ed3 Mon Sep 17 00:00:00 2001 From: Thomas Bluemel Date: Wed, 14 Apr 2004 17:19:38 +0000 Subject: [PATCH] fixed major bugs in the message queue svn path=/trunk/; revision=9139 --- reactos/subsys/win32k/include/winpos.h | 2 +- reactos/subsys/win32k/ntuser/msgqueue.c | 234 ++++++++++++++---------- reactos/subsys/win32k/ntuser/window.c | 4 +- reactos/subsys/win32k/ntuser/winpos.c | 13 +- 4 files changed, 143 insertions(+), 110 deletions(-) diff --git a/reactos/subsys/win32k/include/winpos.h b/reactos/subsys/win32k/include/winpos.h index 2929d8137de..2255a772a73 100644 --- a/reactos/subsys/win32k/include/winpos.h +++ b/reactos/subsys/win32k/include/winpos.h @@ -29,7 +29,7 @@ WinPosSetWindowPos(HWND Wnd, HWND WndInsertAfter, INT x, INT y, INT cx, BOOLEAN FASTCALL WinPosShowWindow(HWND Wnd, INT Cmd); USHORT FASTCALL -WinPosWindowFromPoint(PWINDOW_OBJECT ScopeWin, BOOL SendHitTestMessage, POINT *WinPoint, +WinPosWindowFromPoint(PWINDOW_OBJECT ScopeWin, PUSER_MESSAGE_QUEUE OnlyHitTests, POINT *WinPoint, PWINDOW_OBJECT* Window); VOID FASTCALL WinPosActivateOtherWindow(PWINDOW_OBJECT Window); diff --git a/reactos/subsys/win32k/ntuser/msgqueue.c b/reactos/subsys/win32k/ntuser/msgqueue.c index df0c98b72b4..9dc9505a0e3 100644 --- a/reactos/subsys/win32k/ntuser/msgqueue.c +++ b/reactos/subsys/win32k/ntuser/msgqueue.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: msgqueue.c,v 1.83 2004/04/13 13:50:31 weiden Exp $ +/* $Id: msgqueue.c,v 1.84 2004/04/14 17:19:38 weiden Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -249,65 +249,73 @@ MsqTranslateMouseMessage(HWND hWnd, UINT FilterLow, UINT FilterHigh, PWINDOW_OBJECT Window = NULL; HWND CaptureWin; POINT Point; - + + ThreadQueue = PsGetWin32Thread()->MessageQueue; + if (Msg == WM_LBUTTONDOWN || Msg == WM_MBUTTONDOWN || Msg == WM_RBUTTONDOWN || Msg == WM_XBUTTONDOWN) { - *HitTest = WinPosWindowFromPoint(ScopeWin, !FromGlobalQueue, &Message->Msg.pt, &Window); - if(Window && FromGlobalQueue && (PsGetWin32Thread()->MessageQueue == Window->MessageQueue)) - { - *HitTest = IntSendMessage(Window->Self, WM_NCHITTEST, 0, - MAKELONG(Message->Msg.pt.x, Message->Msg.pt.y)); - } + *HitTest = WinPosWindowFromPoint(ScopeWin, ThreadQueue, &Message->Msg.pt, &Window); /* **Make sure that we have a window that is not already in focus */ - if (Window) + if (Window && (Window->Self != IntGetFocusWindow())) { - if(Window->Self != IntGetFocusWindow()) + if(ThreadQueue == Window->MessageQueue) { + /* only get a more detailed hit-test if the window is in the same thread! */ + *HitTest = IntSendMessage(Window->Self, WM_NCHITTEST, 0, + MAKELONG(Message->Msg.pt.x, Message->Msg.pt.y)); + } + if(*HitTest != (USHORT)HTTRANSPARENT) + { + LRESULT Result; - if(*HitTest != (USHORT)HTTRANSPARENT) - { - LRESULT Result; + /* Sending a message to another thread might lock up our own when it's + hung, so just send messages to our own thread */ + if(Window->MessageQueue == ThreadQueue) Result = IntSendMessage(Window->Self, WM_MOUSEACTIVATE, (WPARAM)NtUserGetParent(Window->Self), (LPARAM)MAKELONG(*HitTest, Msg)); - - switch (Result) - { - case MA_NOACTIVATEANDEAT: - *Freed = FALSE; - IntReleaseWindowObject(Window); - return TRUE; - case MA_NOACTIVATE: - break; - case MA_ACTIVATEANDEAT: - IntMouseActivateWindow(Window); - IntReleaseWindowObject(Window); - *Freed = FALSE; - return TRUE; -/* case MA_ACTIVATE: - case 0:*/ - default: - IntMouseActivateWindow(Window); - break; - } - } else { - IntReleaseWindowObject(Window); - if(RemoveWhenFreed) - { - RemoveEntryList(&Message->ListEntry); - } - ExFreePool(Message); - *Freed = TRUE; - return(FALSE); + /* just post WM_MOUSEACTIVATE to the other thread */ + NtUserPostMessage(Window->Self, WM_MOUSEACTIVATE, (WPARAM)NtUserGetParent(Window->Self), (LPARAM)MAKELONG(*HitTest, Msg)); + /* and assume that windows of other threads should always be activated. */ + Result = MA_ACTIVATE; + } + + switch (Result) + { + case MA_NOACTIVATEANDEAT: + *Freed = FALSE; + IntReleaseWindowObject(Window); + return TRUE; + case MA_NOACTIVATE: + break; + case MA_ACTIVATEANDEAT: + IntMouseActivateWindow(Window); + IntReleaseWindowObject(Window); + *Freed = FALSE; + return TRUE; + default: + /* MA_ACTIVATE */ + IntMouseActivateWindow(Window); + break; } } + else + { + IntReleaseWindowObject(Window); + if(RemoveWhenFreed) + { + RemoveEntryList(&Message->ListEntry); + } + ExFreePool(Message); + *Freed = TRUE; + return(FALSE); + } } - } CaptureWin = IntGetCaptureWindow(); @@ -325,8 +333,8 @@ MsqTranslateMouseMessage(HWND hWnd, UINT FilterLow, UINT FilterHigh, { if(!Window) { - *HitTest = WinPosWindowFromPoint(ScopeWin, !FromGlobalQueue, &Message->Msg.pt, &Window); - if(Window && FromGlobalQueue && (PsGetWin32Thread()->MessageQueue == Window->MessageQueue)) + *HitTest = WinPosWindowFromPoint(ScopeWin, ThreadQueue, &Message->Msg.pt, &Window); + if(Window && (ThreadQueue == Window->MessageQueue)) { *HitTest = IntSendMessage(Window->Self, WM_NCHITTEST, 0, MAKELONG(Message->Msg.pt.x, Message->Msg.pt.y)); @@ -358,7 +366,6 @@ MsqTranslateMouseMessage(HWND hWnd, UINT FilterLow, UINT FilterHigh, return(FALSE); } - ThreadQueue = PsGetWin32Thread()->MessageQueue; if (Window->MessageQueue != ThreadQueue) { if (! FromGlobalQueue) @@ -379,70 +386,33 @@ MsqTranslateMouseMessage(HWND hWnd, UINT FilterLow, UINT FilterHigh, ThreadQueue->MouseMoveMsg = NULL; } } + + /* lock the destination message queue, so we don't get in trouble with other + threads, messing with it at the same time */ IntLockHardwareMessageQueue(Window->MessageQueue); - if((Message->Msg.message == WM_MOUSEMOVE) && Window->MessageQueue->MouseMoveMsg) + InsertTailList(&Window->MessageQueue->HardwareMessagesListHead, + &Message->ListEntry); + if(Message->Msg.message == WM_MOUSEMOVE) { - /* we do not hold more than one WM_MOUSEMOVE message in the queue */ - Window->MessageQueue->MouseMoveMsg->Msg = Message->Msg; - if(RemoveWhenFreed && FromGlobalQueue) + if(Window->MessageQueue->MouseMoveMsg) { - RemoveEntryList(&Message->ListEntry); + /* remove the old WM_MOUSEMOVE message, we're processing a more recent + one */ + RemoveEntryList(&Window->MessageQueue->MouseMoveMsg->ListEntry); + ExFreePool(Window->MessageQueue->MouseMoveMsg); } - *Freed = TRUE; - } - else - { - InsertTailList(&Window->MessageQueue->HardwareMessagesListHead, - &Message->ListEntry); - if(Message->Msg.message == WM_MOUSEMOVE) - { - Window->MessageQueue->MouseMoveMsg = Message; - } - *Freed = FALSE; + /* save the pointer to the WM_MOUSEMOVE message in the new queue */ + Window->MessageQueue->MouseMoveMsg = Message; } IntUnLockHardwareMessageQueue(Window->MessageQueue); - if(*Freed) - { - ExFreePool(Message); - } + KeSetEvent(&Window->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE); + *Freed = FALSE; IntReleaseWindowObject(Window); return(FALSE); } - if (hWnd != NULL && Window->Self != hWnd && - !IntIsChildWindow(hWnd, Window->Self)) - { - IntLockHardwareMessageQueue(Window->MessageQueue); - if((Message->Msg.message == WM_MOUSEMOVE) && Window->MessageQueue->MouseMoveMsg) - { - /* we do not hold more than one WM_MOUSEMOVE message in the queue */ - Window->MessageQueue->MouseMoveMsg->Msg = Message->Msg; - if(RemoveWhenFreed) - { - RemoveEntryList(&Message->ListEntry); - } - *Freed = TRUE; - } - else - { - InsertTailList(&Window->MessageQueue->HardwareMessagesListHead, - &Message->ListEntry); - if(Message->Msg.message == WM_MOUSEMOVE) - { - Window->MessageQueue->MouseMoveMsg = Message; - } - *Freed = FALSE; - } - IntUnLockHardwareMessageQueue(Window->MessageQueue); - if(*Freed) - { - ExFreePool(Message); - } - KeSetEvent(&Window->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE); - IntReleaseWindowObject(Window); - return(FALSE); - } + /* From here on, we're in the same message queue as the caller! */ switch (Msg) { @@ -487,7 +457,43 @@ MsqTranslateMouseMessage(HWND hWnd, UINT FilterLow, UINT FilterHigh, } } - /* FIXME: Check message filter. */ + if(hWnd != NULL && Window->Self != hWnd) + { + /* Reject the message because it doesn't match the filter */ + + if(FromGlobalQueue) + { + /* Lock the message queue so no other thread can mess with it. + Our own message queue is not locked while fetching from the global + queue, so we have to make sure nothing interferes! */ + IntLockHardwareMessageQueue(Window->MessageQueue); + /* if we're from the global queue, we need to add our message to our + private queue so we don't loose it! */ + InsertTailList(&Window->MessageQueue->HardwareMessagesListHead, + &Message->ListEntry); + } + + if (Message->Msg.message == WM_MOUSEMOVE) + { + if(Window->MessageQueue->MouseMoveMsg) + { + /* delete the old message */ + RemoveEntryList(&Window->MessageQueue->MouseMoveMsg->ListEntry); + ExFreePool(Window->MessageQueue->MouseMoveMsg); + } + /* always save a pointer to this WM_MOUSEMOVE message here because we're + sure that the message is in the private queue */ + Window->MessageQueue->MouseMoveMsg = Message; + } + if(FromGlobalQueue) + { + IntUnLockHardwareMessageQueue(Window->MessageQueue); + } + + IntReleaseWindowObject(Window); + *Freed = FALSE; + return(FALSE); + } if (Remove) { @@ -496,6 +502,34 @@ MsqTranslateMouseMessage(HWND hWnd, UINT FilterLow, UINT FilterHigh, Message->Msg.lParam = MAKELONG(Point.x, Point.y); } + /* remove the reference to the current WM_MOUSEMOVE message, if this message + is it */ + if (Message->Msg.message == WM_MOUSEMOVE) + { + if(FromGlobalQueue) + { + /* Lock the message queue so no other thread can mess with it. + Our own message queue is not locked while fetching from the global + queue, so we have to make sure nothing interferes! */ + IntLockHardwareMessageQueue(Window->MessageQueue); + if(Window->MessageQueue->MouseMoveMsg) + { + /* delete the WM_MOUSEMOVE message in the private queue, we're dealing + with one that's been sent later */ + RemoveEntryList(&Window->MessageQueue->MouseMoveMsg->ListEntry); + ExFreePool(Window->MessageQueue->MouseMoveMsg); + /* our message is not in the private queue so we can remove the pointer + instead of setting it to the current message we're processing */ + Window->MessageQueue->MouseMoveMsg = NULL; + } + IntUnLockHardwareMessageQueue(Window->MessageQueue); + } + else if(Window->MessageQueue->MouseMoveMsg == Message) + { + Window->MessageQueue->MouseMoveMsg = NULL; + } + } + IntReleaseWindowObject(Window); *Freed = FALSE; return(TRUE); diff --git a/reactos/subsys/win32k/ntuser/window.c b/reactos/subsys/win32k/ntuser/window.c index eb3e9ec7813..31bb7a45ae3 100644 --- a/reactos/subsys/win32k/ntuser/window.c +++ b/reactos/subsys/win32k/ntuser/window.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: window.c,v 1.216 2004/04/13 23:25:54 weiden Exp $ +/* $Id: window.c,v 1.217 2004/04/14 17:19:38 weiden Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -3715,7 +3715,7 @@ NtUserWindowFromPoint(LONG X, LONG Y) pt.x = X; pt.y = Y; - Hit = WinPosWindowFromPoint(DesktopWindow, TRUE, &pt, &Window); + Hit = WinPosWindowFromPoint(DesktopWindow, PsGetWin32Thread()->MessageQueue, &pt, &Window); if(Window) { diff --git a/reactos/subsys/win32k/ntuser/winpos.c b/reactos/subsys/win32k/ntuser/winpos.c index 298fb67cf92..b96ca05b04a 100644 --- a/reactos/subsys/win32k/ntuser/winpos.c +++ b/reactos/subsys/win32k/ntuser/winpos.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: winpos.c,v 1.110 2004/04/13 23:12:30 weiden Exp $ +/* $Id: winpos.c,v 1.111 2004/04/14 17:19:38 weiden Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -1368,7 +1368,7 @@ WinPosShowWindow(HWND Wnd, INT Cmd) } VOID STATIC FASTCALL -WinPosSearchChildren(PWINDOW_OBJECT ScopeWin, BOOL SendHitTestMessage, POINT *Point, +WinPosSearchChildren(PWINDOW_OBJECT ScopeWin, PUSER_MESSAGE_QUEUE OnlyHitTests, POINT *Point, PWINDOW_OBJECT* Window, USHORT *HitTest) { PWINDOW_OBJECT Current; @@ -1400,8 +1400,7 @@ WinPosSearchChildren(PWINDOW_OBJECT ScopeWin, BOOL SendHitTestMessage, POINT *Po return; } - if(SendHitTestMessage && - (Current->MessageQueue == PsGetWin32Thread()->MessageQueue)) + if(OnlyHitTests && (Current->MessageQueue == OnlyHitTests)) { *HitTest = IntSendMessage(Current->Self, WM_NCHITTEST, 0, MAKELONG(Point->x, Point->y)); @@ -1420,7 +1419,7 @@ WinPosSearchChildren(PWINDOW_OBJECT ScopeWin, BOOL SendHitTestMessage, POINT *Po Point->y >= Current->ClientRect.top && Point->y < Current->ClientRect.bottom) { - WinPosSearchChildren(Current, SendHitTestMessage, Point, Window, HitTest); + WinPosSearchChildren(Current, OnlyHitTests, Point, Window, HitTest); ExFreePool(List); return; } @@ -1435,7 +1434,7 @@ WinPosSearchChildren(PWINDOW_OBJECT ScopeWin, BOOL SendHitTestMessage, POINT *Po } USHORT FASTCALL -WinPosWindowFromPoint(PWINDOW_OBJECT ScopeWin, BOOL SendHitTestMessage, POINT *WinPoint, +WinPosWindowFromPoint(PWINDOW_OBJECT ScopeWin, PUSER_MESSAGE_QUEUE OnlyHitTests, POINT *WinPoint, PWINDOW_OBJECT* Window) { HWND DesktopWindowHandle; @@ -1468,7 +1467,7 @@ WinPosWindowFromPoint(PWINDOW_OBJECT ScopeWin, BOOL SendHitTestMessage, POINT *W HitTest = HTNOWHERE; - WinPosSearchChildren(ScopeWin, SendHitTestMessage, &Point, Window, &HitTest); + WinPosSearchChildren(ScopeWin, OnlyHitTests, &Point, Window, &HitTest); return ((*Window) ? HitTest : HTNOWHERE); }