Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55047
Shrinking the clipping rect to make sure we do not ignore the grab causes some issues. Instead, pass the set_cursor flags to the WM_WINE_CLIPCURSOR message, and introduce a new fullscreen window clipping flag.
As described in the WineHQ bug, an alternative fix would be to keep the shrink but disable fullscreen grabs entirely when the option is disabled [*]. This would break the tests when the option is on but it is not the default. I think that this approach with a flag is better as it doesn't modify the clipping rect.
[*] I don't think they are doing anything but I'm maybe missing something. Maybe grabbing the cursor over the entire virtual screen is preventing the cursor from going over host dock bars or something like that?
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/input.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 205b792d784..2311fb359af 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2614,13 +2614,7 @@ BOOL WINAPI NtUserClipCursor( const RECT *rect ) } else req->flags = SET_CURSOR_NOCLIP;
- if ((ret = !wine_server_call( req ))) - { - new_rect.left = reply->new_clip.left; - new_rect.top = reply->new_clip.top; - new_rect.right = reply->new_clip.right; - new_rect.bottom = reply->new_clip.bottom; - } + ret = !wine_server_call( req ); } SERVER_END_REQ;
From: Rémi Bernon rbernon@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55047 --- dlls/win32u/input.c | 6 +++--- dlls/win32u/message.c | 4 +++- dlls/win32u/sysparams.c | 2 +- dlls/win32u/win32u_private.h | 2 +- server/queue.c | 12 ++++++------ server/user.h | 3 ++- server/window.c | 2 +- 7 files changed, 17 insertions(+), 14 deletions(-)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 2311fb359af..8010183d97c 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2544,13 +2544,13 @@ BOOL get_clip_cursor( RECT *rect ) return ret; }
-BOOL process_wine_clipcursor( HWND hwnd, BOOL empty, BOOL reset ) +BOOL process_wine_clipcursor( HWND hwnd, UINT flags, BOOL reset ) { struct user_thread_info *thread_info = get_user_thread_info(); RECT rect, virtual_rect = NtUserGetVirtualScreenRect(); - BOOL was_clipping; + BOOL was_clipping, empty = !!(flags & SET_CURSOR_NOCLIP);
- TRACE( "hwnd %p, empty %u, reset %u\n", hwnd, empty, reset ); + TRACE( "hwnd %p, flags %#x, reset %u\n", hwnd, flags, reset );
if ((was_clipping = thread_info->clipping_cursor)) InterlockedDecrement( &clipping_cursor ); thread_info->clipping_cursor = FALSE; diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index cb44e0037d9..687caef9bfc 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1272,7 +1272,9 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR return call_current_hook( h_extra->handle, HC_ACTION, wparam, h_extra->lparam ); } case WM_WINE_CLIPCURSOR: - if (wparam && lparam) return clip_fullscreen_window( hwnd, FALSE ); + /* non-hardware message, posted on display mode change to trigger fullscreen + clipping or to the desktop window to forcefully release the cursor grabs */ + if (!wparam) return clip_fullscreen_window( hwnd, FALSE ); return process_wine_clipcursor( hwnd, wparam, lparam ); case WM_WINE_SETCURSOR: FIXME( "Unexpected non-hardware WM_WINE_SETCURSOR message\n" ); diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 4f69cac7040..59f624214b7 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2929,7 +2929,7 @@ static LONG apply_display_settings( const WCHAR *devname, const DEVMODEW *devmod MAKELPARAM( current_mode.dmPelsWidth, current_mode.dmPelsHeight ), SMTO_ABORTIFHUNG, 2000, FALSE ); /* post clip_fullscreen_window request to the foreground window */ - NtUserPostMessage( NtUserGetForegroundWindow(), WM_WINE_CLIPCURSOR, TRUE, TRUE ); + NtUserPostMessage( NtUserGetForegroundWindow(), WM_WINE_CLIPCURSOR, 0, 0 ); }
return ret; diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 3bd41a4ffa8..ee117ed2637 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -104,7 +104,7 @@ extern BOOL set_foreground_window( HWND hwnd, BOOL mouse ) DECLSPEC_HIDDEN; extern void toggle_caret( HWND hwnd ) DECLSPEC_HIDDEN; extern void update_mouse_tracking_info( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL get_clip_cursor( RECT *rect ) DECLSPEC_HIDDEN; -extern BOOL process_wine_clipcursor( HWND hwnd, BOOL empty, BOOL reset ) DECLSPEC_HIDDEN; +extern BOOL process_wine_clipcursor( HWND hwnd, UINT flags, BOOL reset ) DECLSPEC_HIDDEN; extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN;
/* menu.c */ diff --git a/server/queue.c b/server/queue.c index ec8ddcbee5c..fcc946ff0cb 100644 --- a/server/queue.c +++ b/server/queue.c @@ -508,7 +508,7 @@ static void get_message_defaults( struct msg_queue *queue, int *x, int *y, unsig }
/* set the cursor clip rectangle */ -void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int reset ) +void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, unsigned int flags, int reset ) { rectangle_t top_rect; int x, y; @@ -532,17 +532,17 @@ void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int r if (x != desktop->cursor.x || y != desktop->cursor.y) set_cursor_pos( desktop, x, y );
/* request clip cursor rectangle reset to the desktop thread */ - if (reset) post_desktop_message( desktop, WM_WINE_CLIPCURSOR, TRUE, FALSE ); + if (reset) post_desktop_message( desktop, WM_WINE_CLIPCURSOR, flags, FALSE );
/* notify foreground thread, of reset, or to apply new cursor clipping rect */ - queue_cursor_message( desktop, 0, WM_WINE_CLIPCURSOR, rect == NULL, reset ); + queue_cursor_message( desktop, 0, WM_WINE_CLIPCURSOR, flags, reset ); }
/* change the foreground input and reset the cursor clip rect */ static void set_foreground_input( struct desktop *desktop, struct thread_input *input ) { if (desktop->foreground_input == input) return; - set_clip_rectangle( desktop, NULL, 1 ); + set_clip_rectangle( desktop, NULL, SET_CURSOR_NOCLIP, 1 ); desktop->foreground_input = input; }
@@ -3383,8 +3383,8 @@ DECL_HANDLER(set_cursor) input->cursor_count += req->show_count; } if (req->flags & SET_CURSOR_POS) set_cursor_pos( desktop, req->x, req->y ); - if (req->flags & SET_CURSOR_CLIP) set_clip_rectangle( desktop, &req->clip, 0 ); - if (req->flags & SET_CURSOR_NOCLIP) set_clip_rectangle( desktop, NULL, 0 ); + if (req->flags & SET_CURSOR_CLIP) set_clip_rectangle( desktop, &req->clip, req->flags, 0 ); + if (req->flags & SET_CURSOR_NOCLIP) set_clip_rectangle( desktop, NULL, SET_CURSOR_NOCLIP, 0 );
if (req->flags & (SET_CURSOR_HANDLE | SET_CURSOR_COUNT)) { diff --git a/server/user.h b/server/user.h index f67e710938f..b6f47bcac1c 100644 --- a/server/user.h +++ b/server/user.h @@ -110,7 +110,8 @@ extern void queue_cleanup_window( struct thread *thread, user_handle_t win ); extern int init_thread_queue( struct thread *thread ); extern int attach_thread_input( struct thread *thread_from, struct thread *thread_to ); extern void detach_thread_input( struct thread *thread_from ); -extern void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, int reset ); +extern void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, + unsigned int flags, int reset ); extern void post_message( user_handle_t win, unsigned int message, lparam_t wparam, lparam_t lparam ); extern void send_notify_message( user_handle_t win, unsigned int message, diff --git a/server/window.c b/server/window.c index 9db8ccbe27e..328e3dfc64c 100644 --- a/server/window.c +++ b/server/window.c @@ -1829,7 +1829,7 @@ static void set_window_pos( struct window *win, struct window *previous, }
/* reset cursor clip rectangle when the desktop changes size */ - if (win == win->desktop->top_window) set_clip_rectangle( win->desktop, NULL, 1 ); + if (win == win->desktop->top_window) set_clip_rectangle( win->desktop, NULL, SET_CURSOR_NOCLIP, 1 );
/* if the window is not visible, everything is easy */ if (!visible) return;
From: Rémi Bernon rbernon@codeweavers.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55047 --- dlls/win32u/input.c | 22 ++++++++++++++++------ dlls/win32u/message.c | 2 +- dlls/win32u/sysparams.c | 2 +- server/protocol.def | 1 + 4 files changed, 19 insertions(+), 8 deletions(-)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 8010183d97c..1dcc439e560 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2470,9 +2470,10 @@ BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) { struct user_thread_info *thread_info = get_user_thread_info(); MONITORINFO monitor_info = {.cbSize = sizeof(MONITORINFO)}; - RECT rect, virtual_rect = NtUserGetVirtualScreenRect(); + RECT rect; HMONITOR monitor; DWORD style; + BOOL ret;
if (hwnd == NtUserGetDesktopWindow()) return FALSE; if (hwnd != NtUserGetForegroundWindow()) return FALSE; @@ -2497,11 +2498,20 @@ BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) if (is_virtual_desktop()) return FALSE; }
- /* shrink the clipping rect to make sure it is not ignored for being fullscreen */ - if (EqualRect( &monitor_info.rcMonitor, &virtual_rect )) InflateRect( &monitor_info.rcMonitor, -1, -1 ); - TRACE( "win %p clipping fullscreen\n", hwnd ); - return NtUserClipCursor( &monitor_info.rcMonitor ); + + SERVER_START_REQ( set_cursor ) + { + req->flags = SET_CURSOR_CLIP | SET_CURSOR_FSCLIP; + req->clip.left = monitor_info.rcMonitor.left; + req->clip.top = monitor_info.rcMonitor.top; + req->clip.right = monitor_info.rcMonitor.right; + req->clip.bottom = monitor_info.rcMonitor.bottom; + ret = !wine_server_call( req ); + } + SERVER_END_REQ; + + return ret; }
/********************************************************************** @@ -2567,7 +2577,7 @@ BOOL process_wine_clipcursor( HWND hwnd, UINT flags, BOOL reset ) get_clip_cursor( &rect ); intersect_rect( &rect, &rect, &virtual_rect ); if (EqualRect( &rect, &virtual_rect )) empty = TRUE; - if (empty) + if (empty && !(flags & SET_CURSOR_FSCLIP)) { /* if currently clipping, check if we should switch to fullscreen clipping */ if (was_clipping && clip_fullscreen_window( hwnd, TRUE )) return TRUE; diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 687caef9bfc..7c90935390f 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1274,7 +1274,7 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR case WM_WINE_CLIPCURSOR: /* non-hardware message, posted on display mode change to trigger fullscreen clipping or to the desktop window to forcefully release the cursor grabs */ - if (!wparam) return clip_fullscreen_window( hwnd, FALSE ); + if (wparam & SET_CURSOR_FSCLIP) return clip_fullscreen_window( hwnd, FALSE ); return process_wine_clipcursor( hwnd, wparam, lparam ); case WM_WINE_SETCURSOR: FIXME( "Unexpected non-hardware WM_WINE_SETCURSOR message\n" ); diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 59f624214b7..b941d01e3b7 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2929,7 +2929,7 @@ static LONG apply_display_settings( const WCHAR *devname, const DEVMODEW *devmod MAKELPARAM( current_mode.dmPelsWidth, current_mode.dmPelsHeight ), SMTO_ABORTIFHUNG, 2000, FALSE ); /* post clip_fullscreen_window request to the foreground window */ - NtUserPostMessage( NtUserGetForegroundWindow(), WM_WINE_CLIPCURSOR, 0, 0 ); + NtUserPostMessage( NtUserGetForegroundWindow(), WM_WINE_CLIPCURSOR, SET_CURSOR_FSCLIP, 0 ); }
return ret; diff --git a/server/protocol.def b/server/protocol.def index cd96858dea9..54059b6b580 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3719,6 +3719,7 @@ struct handle_info #define SET_CURSOR_POS 0x04 #define SET_CURSOR_CLIP 0x08 #define SET_CURSOR_NOCLIP 0x10 +#define SET_CURSOR_FSCLIP 0x20
/* Get the history of the 64 last cursor positions */ @REQ(get_cursor_history)