The server's idea of the cursor position is never really initialized. Normally that's not a problem, since the first mouse movement and a number of other X events will update it. But in the case where the user never moves the mouse, it can remain out of sync. That manifests as `GetCursorPos` bouncing between the server's incorrect value and the real one from the user driver, depending on the age of the position on the server.
I've marked this as a draft for two reasons: 1. I don't quite know where this belongs. We want to do it early in the lifespan of a user driver but after there's a desktop, so I've put it behind a `pthread_once` called from `get_desktop_window`. 2. I'm calling `NtUserSetCursorPos` to update the server, rather than a direct `set_cursor` request, because it contains some DPI logic. That has the side effect of potentially warping the cursor. That's not desirable or necessary, but it shouldn't be a problem. It's easily factored around if we want to avoid it.
Any guidance would be greatly appreciated!
From: Tim Clem tclem@codeweavers.com
Until the user moves the mouse, the server's idea of the cursor position is likely incorrect. Very early in the lifespan of a user driver (after desktop creation), sync the server with the result of the driver's GetCursorPos. --- dlls/win32u/input.c | 29 +++++++++++++++++++++++++++++ dlls/win32u/win32u_private.h | 1 + dlls/win32u/winstation.c | 1 + 3 files changed, 31 insertions(+)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 5ba7d151f57..d4f5c1c8abb 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -30,6 +30,7 @@ #pragma makedep unix #endif
+#include <pthread.h> #include "ntstatus.h" #define WIN32_NO_STATUS #include "win32u_private.h" @@ -39,6 +40,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(win); WINE_DECLARE_DEBUG_CHANNEL(keyboard); +WINE_DECLARE_DEBUG_CHANNEL(cursor);
static const WCHAR keyboard_layouts_keyW[] = { @@ -2149,3 +2151,30 @@ void toggle_caret( HWND hwnd )
if (ret && !hidden) display_caret( hwnd, &r ); } + +static void sync_cursor_pos(void) +{ + POINT pt = { 0 }; + if (user_driver->pGetCursorPos( &pt )) + { + TRACE_(cursor)( "syncing initial cursor position at (%d, %d)\n", pt.x, pt.y ); + NtUserSetCursorPos( pt.x, pt.y ); + } + else + { + WARN_(cursor)( "initial GetCursorPos failed; cursor may be out of sync with the server\n" ); + } +} + +/*********************************************************************** + * sync_cursor_pos + * + * Update the server's cursor location with the actual value from the + * user driver. Until the user moves the mouse, the server's location + * is likely incorrect. + */ +void init_server_cursor_pos(void) +{ + static pthread_once_t init_once = PTHREAD_ONCE_INIT; + pthread_once( &init_once, sync_cursor_pos ); +} diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 4be068b968d..5800804f6cc 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -272,6 +272,7 @@ extern HWND get_capture(void) DECLSPEC_HIDDEN; extern BOOL get_cursor_pos( POINT *pt ) DECLSPEC_HIDDEN; extern HWND get_focus(void) DECLSPEC_HIDDEN; extern DWORD get_input_state(void) DECLSPEC_HIDDEN; +extern void init_server_cursor_pos(void) DECLSPEC_HIDDEN; extern BOOL WINAPI release_capture(void) DECLSPEC_HIDDEN; extern BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ) DECLSPEC_HIDDEN; extern BOOL set_caret_blink_time( unsigned int time ) DECLSPEC_HIDDEN; diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index e606047a79c..33a3b7f65c8 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -501,6 +501,7 @@ HWND get_desktop_window(void) ERR_(win)( "failed to create desktop window\n" );
register_builtin_classes(); + init_server_cursor_pos(); return UlongToHandle( thread_info->top_window ); }
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=125734
Your paranoid android.
=== debian11 (32 bit report) ===
urlmon: protocol.c:3682: Test failed: wait timed out protocol: Timeout