diff --git a/reactos/subsystems/win32/win32k/include/cursoricon.h b/reactos/subsystems/win32/win32k/include/cursoricon.h index f60023c5805..2b3d703bb97 100644 --- a/reactos/subsystems/win32/win32k/include/cursoricon.h +++ b/reactos/subsystems/win32/win32k/include/cursoricon.h @@ -71,8 +71,6 @@ PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon); BOOL UserSetCursorPos( INT x, INT y, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook); -int UserShowCursor(BOOL bShow); - PSYSTEM_CURSORINFO IntGetSysCursorInfo(VOID); #define IntReleaseCurIconObject(CurIconObj) \ diff --git a/reactos/subsystems/win32/win32k/include/msgqueue.h b/reactos/subsystems/win32/win32k/include/msgqueue.h index fd11f162409..691c814f1ce 100644 --- a/reactos/subsystems/win32/win32k/include/msgqueue.h +++ b/reactos/subsystems/win32/win32k/include/msgqueue.h @@ -1,6 +1,7 @@ #pragma once #include "hook.h" +#include "cursoricon.h" #define MSQ_HUNG 5000 #define MSQ_NORMAL 0 @@ -59,8 +60,6 @@ typedef struct _USER_MESSAGE_QUEUE LIST_ENTRY PostedMessagesListHead; /* Queue for hardware messages for the queue. */ LIST_ENTRY HardwareMessagesListHead; - /* Lock for the hardware message list. */ - KMUTEX HardwareLock; /* True if a WM_MOUSEMOVE is pending */ BOOLEAN MouseMoved; /* Current WM_MOUSEMOVE message */ @@ -111,6 +110,11 @@ typedef struct _USER_MESSAGE_QUEUE /* state of each key */ UCHAR KeyState[256]; + /* showing cursor counter (value>=0 - cursor visible, value<0 - cursor hidden) */ + INT ShowingCursor; + /* cursor object */ + PCURICON_OBJECT CursorObject; + /* messages that are currently dispatched by other threads */ LIST_ENTRY DispatchingMessagesHead; /* messages that are currently dispatched by this message queue, required for cleanup */ @@ -322,4 +326,10 @@ UINT FASTCALL GetWakeMask(UINT, UINT); VOID FASTCALL MsqWakeQueue(PUSER_MESSAGE_QUEUE,DWORD,BOOL); VOID FASTCALL ClearMsgBitsMask(PUSER_MESSAGE_QUEUE,UINT); +int UserShowCursor(BOOL bShow); +PCURICON_OBJECT +FASTCALL +UserSetCursor(PCURICON_OBJECT NewCursor, + BOOL ForceChange); + /* EOF */ diff --git a/reactos/subsystems/win32/win32k/ntuser/cursoricon.c b/reactos/subsystems/win32/win32k/ntuser/cursoricon.c index 7daa480494c..0b3c419ed1f 100644 --- a/reactos/subsystems/win32/win32k/ntuser/cursoricon.c +++ b/reactos/subsystems/win32/win32k/ntuser/cursoricon.c @@ -99,80 +99,14 @@ PCURICON_OBJECT FASTCALL UserGetCurIconObject(HCURSOR hCurIcon) return CurIcon; } -PCURICON_OBJECT -FASTCALL -UserSetCursor( - PCURICON_OBJECT NewCursor, - BOOL ForceChange) -{ - PSYSTEM_CURSORINFO CurInfo; - PCURICON_OBJECT OldCursor; - HDC hdcScreen; - - CurInfo = IntGetSysCursorInfo(); - - OldCursor = CurInfo->CurrentCursorObject; - - /* Is the new cursor the same as the old cursor? */ - if (OldCursor == NewCursor) - { - /* Nothing to to do in this case */ - return OldCursor; - } - - /* Get the screen DC */ - if(!(hdcScreen = IntGetScreenDC())) - { - return (HCURSOR)0; - } - - /* Do we have a new cursor? */ - if (NewCursor) - { - CurInfo->ShowingCursor = 0; - CurInfo->CurrentCursorObject = NewCursor; - - /* Call GDI to set the new screen cursor */ - GreSetPointerShape(hdcScreen, - NewCursor->IconInfo.hbmMask, - NewCursor->IconInfo.hbmColor, - NewCursor->IconInfo.xHotspot, - NewCursor->IconInfo.yHotspot, - gpsi->ptCursor.x, - gpsi->ptCursor.y); - } - else - { - /* Check if were diplaying a cursor */ - if (OldCursor && CurInfo->ShowingCursor >= 0) - { - /* Remove the cursor */ - GreMovePointer(hdcScreen, -1, -1); - DPRINT("Removing pointer!\n"); - } - - CurInfo->CurrentCursorObject = NULL; - CurInfo->ShowingCursor = -1; - } - - /* Return the old cursor */ - return OldCursor; -} - BOOL UserSetCursorPos( INT x, INT y, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook) { PWND DesktopWindow; PSYSTEM_CURSORINFO CurInfo; - HDC hDC; MSG Msg; RECTL rcClip; POINT pt; - if(!(hDC = IntGetScreenDC())) - { - return FALSE; - } - if(!(DesktopWindow = UserGetDesktopWindow())) { return FALSE; @@ -194,58 +128,19 @@ BOOL UserSetCursorPos( INT x, INT y, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Ho pt.x = x; pt.y = y; - /* 3. Generate a mouse move message, this sets the htEx and Track Window too. */ + /* 1. Generate a mouse move message, this sets the htEx and Track Window too. */ Msg.message = WM_MOUSEMOVE; Msg.wParam = CurInfo->ButtonsDown; Msg.lParam = MAKELPARAM(x, y); Msg.pt = pt; co_MsqInsertMouseMessage(&Msg, flags, dwExtraInfo, Hook); - /* 1. Store the new cursor position */ + /* 2. Store the new cursor position */ gpsi->ptCursor = pt; - /* 2. Move the mouse pointer */ - GreMovePointer(hDC, x, y); - return TRUE; } -/* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR - * User32 macro NtUserShowCursor */ -int UserShowCursor(BOOL bShow) -{ - PSYSTEM_CURSORINFO CurInfo = IntGetSysCursorInfo(); - HDC hdcScreen; - - if (!(hdcScreen = IntGetScreenDC())) - { - return -1; /* No mouse */ - } - - if (bShow == FALSE) - { - /* Check if were diplaying a cursor */ - if (CurInfo->ShowingCursor == 0) - { - /* Remove the pointer */ - GreMovePointer(hdcScreen, -1, -1); - DPRINT("Removing pointer!\n"); - } - CurInfo->ShowingCursor--; - } - else - { - if (CurInfo->ShowingCursor == -1) - { - /*Show the pointer*/ - GreMovePointer(hdcScreen, gpsi->ptCursor.x, gpsi->ptCursor.y); - } - CurInfo->ShowingCursor++; - } - - return CurInfo->ShowingCursor; -} - /* * We have to register that this object is in use by the current * process. The only way to do that seems to be to walk the list diff --git a/reactos/subsystems/win32/win32k/ntuser/display.c b/reactos/subsystems/win32/win32k/ntuser/display.c index 76c0d25f315..b5ea068167a 100644 --- a/reactos/subsystems/win32/win32k/ntuser/display.c +++ b/reactos/subsystems/win32/win32k/ntuser/display.c @@ -634,7 +634,6 @@ NtUserEnumDisplaySettings( BOOL APIENTRY UserClipCursor(RECTL *prcl); VOID APIENTRY UserRedrawDesktop(); -HCURSOR FASTCALL UserSetCursor(PCURICON_OBJECT NewCursor, BOOL ForceChange); LONG APIENTRY diff --git a/reactos/subsystems/win32/win32k/ntuser/msgqueue.c b/reactos/subsystems/win32/win32k/ntuser/msgqueue.c index 8b2a73f99d6..befa9bb81d4 100644 --- a/reactos/subsystems/win32/win32k/ntuser/msgqueue.c +++ b/reactos/subsystems/win32/win32k/ntuser/msgqueue.c @@ -43,6 +43,151 @@ MsqInitializeImpl(VOID) return(STATUS_SUCCESS); } +PWND FASTCALL +IntTopLevelWindowFromPoint(INT x, INT y) +{ + PWND pWnd, pwndDesktop; + + /* Get the desktop window */ + pwndDesktop = UserGetDesktopWindow(); + if (!pwndDesktop) + return NULL; + + /* Loop all top level windows */ + for (pWnd = pwndDesktop->spwndChild; + pWnd != NULL; + pWnd = pWnd->spwndNext) + { + if (pWnd->state2 & WNDS2_INDESTROY || pWnd->state & WNDS_DESTROYED) + { + DPRINT("The Window is in DESTROY!\n"); + continue; + } + + if ((pWnd->style & WS_VISIBLE) && IntPtInWindow(pWnd, x, y)) + return pWnd; + } + + /* Window has not been found */ + return NULL; +} + +PCURICON_OBJECT +FASTCALL +UserSetCursor( + PCURICON_OBJECT NewCursor, + BOOL ForceChange) +{ + PCURICON_OBJECT OldCursor; + HDC hdcScreen; + PTHREADINFO pti; + PUSER_MESSAGE_QUEUE MessageQueue; + PWND pWnd; + + pti = PsGetCurrentThreadWin32Thread(); + MessageQueue = pti->MessageQueue; + + /* Get the screen DC */ + if(!(hdcScreen = IntGetScreenDC())) + { + return (HCURSOR)0; + } + + OldCursor = MessageQueue->CursorObject; + + /* Check if cursors are different */ + if (OldCursor == NewCursor) + return OldCursor; + + /* Update cursor for this message queue */ + MessageQueue->CursorObject = NewCursor; + + /* If cursor is not visible we have nothing to do */ + if (MessageQueue->ShowingCursor < 0) + return OldCursor; + + /* Update cursor if this message queue controls it */ + pWnd = IntTopLevelWindowFromPoint(gpsi->ptCursor.x, gpsi->ptCursor.y); + if (pWnd && pWnd->head.pti->MessageQueue == MessageQueue) + { + if (NewCursor) + { + /* Call GDI to set the new screen cursor */ + GreSetPointerShape(hdcScreen, + NewCursor->IconInfo.hbmMask, + NewCursor->IconInfo.hbmColor, + NewCursor->IconInfo.xHotspot, + NewCursor->IconInfo.yHotspot, + gpsi->ptCursor.x, + gpsi->ptCursor.y); + } + else /* Note: OldCursor != NewCursor so we have to hide cursor */ + { + /* Remove the cursor */ + GreMovePointer(hdcScreen, -1, -1); + DPRINT1("Removing pointer!\n"); + DbgBreakPoint(); + } + IntGetSysCursorInfo()->CurrentCursorObject = NewCursor; + } + + /* Return the old cursor */ + return OldCursor; +} + +/* Called from NtUserCallOneParam with Routine ONEPARAM_ROUTINE_SHOWCURSOR + * User32 macro NtUserShowCursor */ +int UserShowCursor(BOOL bShow) +{ + HDC hdcScreen; + PTHREADINFO pti; + PUSER_MESSAGE_QUEUE MessageQueue; + PWND pWnd; + + if (!(hdcScreen = IntGetScreenDC())) + { + return -1; /* No mouse */ + } + + pti = PsGetCurrentThreadWin32Thread(); + MessageQueue = pti->MessageQueue; + + /* Update counter */ + MessageQueue->ShowingCursor += bShow ? 1 : -1; + + /* Check for trivial cases */ + if ((bShow && MessageQueue->ShowingCursor != 0) || + (!bShow && MessageQueue->ShowingCursor != -1)) + { + /* Note: w don't update global info here because it is used only + internally to check if cursor is visible */ + return MessageQueue->ShowingCursor; + } + + /* Check if cursor is above window owned by this MessageQueue */ + pWnd = IntTopLevelWindowFromPoint(gpsi->ptCursor.x, gpsi->ptCursor.y); + if (pWnd && pWnd->head.pti->MessageQueue == MessageQueue) + { + if (bShow) + { + /* Show the pointer */ + GreMovePointer(hdcScreen, gpsi->ptCursor.x, gpsi->ptCursor.y); + DPRINT1("Showing pointer!\n"); + } + else + { + /* Remove the pointer */ + GreMovePointer(hdcScreen, -1, -1); + DPRINT1("Removing pointer!\n"); + } + + /* Update global info */ + IntGetSysCursorInfo()->ShowingCursor = MessageQueue->ShowingCursor; + } + + return MessageQueue->ShowingCursor; +} + DWORD FASTCALL UserGetKeyState(DWORD key) { DWORD ret = 0; @@ -307,13 +452,15 @@ co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook MSLLHOOKSTRUCT MouseHookData; PDESKTOP pDesk; PWND pwnd, pwndDesktop; + HDC hdcScreen; + PSYSTEM_CURSORINFO CurInfo; KeQueryTickCount(&LargeTickCount); Msg->time = MsqCalculateMessageTime(&LargeTickCount); MouseHookData.pt.x = LOWORD(Msg->lParam); MouseHookData.pt.y = HIWORD(Msg->lParam); - switch(Msg->message) + switch (Msg->message) { case WM_MOUSEWHEEL: MouseHookData.mouseData = MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg->wParam)); @@ -344,7 +491,7 @@ co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook /* Get the desktop window */ pwndDesktop = UserGetDesktopWindow(); - if(!pwndDesktop) + if (!pwndDesktop) return; /* Set hit somewhere on the desktop */ @@ -354,7 +501,7 @@ co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook /* Check if the mouse is captured */ Msg->hwnd = IntGetCaptureWindow(); - if(Msg->hwnd != NULL) + if (Msg->hwnd != NULL) { pwnd = UserGetWindowObject(Msg->hwnd); if ((pwnd->style & WS_VISIBLE) && @@ -366,35 +513,54 @@ co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook } else { - /* Loop all top level windows to find which one should receive input */ - for( pwnd = pwndDesktop->spwndChild; - pwnd != NULL; - pwnd = pwnd->spwndNext ) + pwnd = IntTopLevelWindowFromPoint(Msg->pt.x, Msg->pt.y); + if (pwnd) { - if ( pwnd->state2 & WNDS2_INDESTROY || pwnd->state & WNDS_DESTROYED ) - { - DPRINT("The Window is in DESTROY!\n"); - continue; - } - - if((pwnd->style & WS_VISIBLE) && - IntPtInWindow(pwnd, Msg->pt.x, Msg->pt.y)) - { - Msg->hwnd = pwnd->head.h; - pDesk->htEx = HTCLIENT; - pDesk->spwndTrack = pwnd; - break; - } + Msg->hwnd = pwnd->head.h; + pDesk->htEx = HTCLIENT; + pDesk->spwndTrack = pwnd; } } + hdcScreen = IntGetScreenDC(); + CurInfo = IntGetSysCursorInfo(); + /* Check if we found a window */ - if(Msg->hwnd != NULL && pwnd != NULL) + if (Msg->hwnd != NULL && pwnd != NULL) { - if(Msg->message == WM_MOUSEMOVE) + if (Msg->message == WM_MOUSEMOVE) { - /* Mouse move is a special case*/ - MsqPostMouseMove(pwnd->head.pti->MessageQueue, Msg); + PUSER_MESSAGE_QUEUE MessageQueue = pwnd->head.pti->MessageQueue; + + /* Check if cursor should be visible */ + if(hdcScreen && + MessageQueue->CursorObject && + MessageQueue->ShowingCursor >= 0) + { + /* Check if shape has changed */ + if(CurInfo->CurrentCursorObject != MessageQueue->CursorObject) + { + /* Call GDI to set the new screen cursor */ + GreSetPointerShape(hdcScreen, + MessageQueue->CursorObject->IconInfo.hbmMask, + MessageQueue->CursorObject->IconInfo.hbmColor, + MessageQueue->CursorObject->IconInfo.xHotspot, + MessageQueue->CursorObject->IconInfo.yHotspot, + gpsi->ptCursor.x, + gpsi->ptCursor.y); + } else + GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y); + } + /* Check if w have to hide cursor */ + else if (CurInfo->ShowingCursor >= 0) + GreMovePointer(hdcScreen, -1, -1); + + /* Update global cursor info */ + CurInfo->ShowingCursor = MessageQueue->ShowingCursor; + CurInfo->CurrentCursorObject = MessageQueue->CursorObject; + + /* Mouse move is a special case */ + MsqPostMouseMove(MessageQueue, Msg); } else { @@ -402,6 +568,12 @@ co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook MsqPostMessage(pwnd->head.pti->MessageQueue, Msg, TRUE, QS_MOUSEBUTTON); } } + else if (hdcScreen) + { + /* always show cursor on background; FIXME: set default pointer */ + GreMovePointer(hdcScreen, Msg->pt.x, Msg->pt.y); + CurInfo->ShowingCursor = 0; + } /* Do GetMouseMovePointsEx FIFO. */ MouseHistoryOfMoves[gcur_count].x = Msg->pt.x; @@ -1601,13 +1773,14 @@ MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQu InitializeListHead(&MessageQueue->HardwareMessagesListHead); InitializeListHead(&MessageQueue->DispatchingMessagesHead); InitializeListHead(&MessageQueue->LocalDispatchingMessagesHead); - KeInitializeMutex(&MessageQueue->HardwareLock, 0); MessageQueue->QuitPosted = FALSE; MessageQueue->QuitExitCode = 0; KeQueryTickCount(&LargeTickCount); MessageQueue->LastMsgRead = LargeTickCount.u.LowPart; MessageQueue->FocusWindow = NULL; MessageQueue->NewMessagesHandle = NULL; + MessageQueue->ShowingCursor = 0; + MessageQueue->CursorObject = NULL; Status = ZwCreateEvent(&MessageQueue->NewMessagesHandle, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE); @@ -1763,6 +1936,18 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue) MessageQueue->nCntsQBits[QSRosPostMessage] = 0; MessageQueue->nCntsQBits[QSRosSendMessage] = 0; MessageQueue->nCntsQBits[QSRosHotKey] = 0; + + if (MessageQueue->CursorObject) + { + PCURICON_OBJECT pCursor = MessageQueue->CursorObject; + + /* Change to another cursor if we going to dereference current one */ + if (IntGetSysCursorInfo()->CurrentCursorObject == pCursor) + UserSetCursor(NULL, TRUE); + + UserDereferenceObject(pCursor); + } + } PUSER_MESSAGE_QUEUE FASTCALL @@ -1989,5 +2174,4 @@ NtUserSetKeyboardState(LPBYTE lpKeyState) return ret; } - /* EOF */