Since the positions of win32 windows and their corresponding Wayland surfaces are not synchronized, there are cases where parts of a window are outside the vscreen boundaries, and thus inaccessible to input events, but still visible and accessible from a user (i.e., Wayland compositor) standpoint. Try to remedy this issue by instructing the Wine server to not clip the Wayland mouse event coordinates to vscreen boundaries.
--
Relevant discussions: * https://gitlab.winehq.org/wine/wine/-/merge_requests/4014#note_47581 * https://gitlab.winehq.org/wine/wine/-/merge_requests/7919
@julliard @rbernon Do you think such an approach (or something along these lines) would have any future in upstream as (a possibly opt-in) workaround for the Wayland input issues?
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Since the positions of win32 windows and their corresponding Wayland surfaces are not synchronized, there are cases where parts of a window are outside the vscreen boundaries, and thus inaccessible to input events, but still visible and accessible from a user (i.e., Wayland compositor) standpoint. Try to remedy this issue by instructing the Wine server to not clip the Wayland mouse event coordinates to vscreen boundaries. --- dlls/winewayland.drv/wayland_pointer.c | 9 +++++---- include/wine/server_protocol.h | 3 ++- server/protocol.def | 1 + server/queue.c | 17 ++++++++++++----- server/user.h | 1 + 5 files changed, 21 insertions(+), 10 deletions(-)
diff --git a/dlls/winewayland.drv/wayland_pointer.c b/dlls/winewayland.drv/wayland_pointer.c index beb9cc06702..f8b995b73a9 100644 --- a/dlls/winewayland.drv/wayland_pointer.c +++ b/dlls/winewayland.drv/wayland_pointer.c @@ -31,6 +31,7 @@
#include "waylanddrv.h" #include "wine/debug.h" +#include "wine/server_protocol.h"
WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv);
@@ -89,7 +90,7 @@ static void pointer_handle_motion_internal(wl_fixed_t sx, wl_fixed_t sy) hwnd, wl_fixed_to_double(sx), wl_fixed_to_double(sy), screen.x, screen.y);
- NtUserSendHardwareInput(hwnd, 0, &input, 0); + NtUserSendHardwareInput(hwnd, SEND_HWMSG_NO_VSCREEN_CLIP, &input, 0); }
static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, @@ -194,7 +195,7 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
TRACE("hwnd=%p button=%#x state=%u\n", hwnd, button, state);
- NtUserSendHardwareInput(hwnd, 0, &input, 0); + NtUserSendHardwareInput(hwnd, SEND_HWMSG_NO_VSCREEN_CLIP, &input, 0); }
static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, @@ -241,7 +242,7 @@ static void pointer_handle_axis_discrete(void *data, struct wl_pointer *wl_point
TRACE("hwnd=%p axis=%u discrete=%d\n", hwnd, axis, discrete);
- NtUserSendHardwareInput(hwnd, 0, &input, 0); + NtUserSendHardwareInput(hwnd, SEND_HWMSG_NO_VSCREEN_CLIP, &input, 0); }
static const struct wl_pointer_listener pointer_listener = @@ -310,7 +311,7 @@ static void relative_pointer_v1_relative_motion(void *private, hwnd, wl_fixed_to_double(dx), wl_fixed_to_double(dy), input.mi.dx, input.mi.dy);
- NtUserSendHardwareInput(hwnd, 0, &input, 0); + NtUserSendHardwareInput(hwnd, SEND_HWMSG_NO_VSCREEN_CLIP, &input, 0); }
static const struct zwp_relative_pointer_v1_listener relative_pointer_v1_listener = diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 3cdc9375e2d..708355e212a 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -3047,6 +3047,7 @@ struct send_hardware_message_reply char __pad_28[4]; }; #define SEND_HWMSG_INJECTED 0x01 +#define SEND_HWMSG_NO_VSCREEN_CLIP 0x02
@@ -6798,6 +6799,6 @@ union generic_reply struct set_keyboard_repeat_reply set_keyboard_repeat_reply; };
-#define SERVER_PROTOCOL_VERSION 863 +#define SERVER_PROTOCOL_VERSION 864
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index 63bb0111473..b500b5b838c 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2315,6 +2315,7 @@ enum message_type int new_y; @END #define SEND_HWMSG_INJECTED 0x01 +#define SEND_HWMSG_NO_VSCREEN_CLIP 0x02
/* Get a message from the current queue */ diff --git a/server/queue.c b/server/queue.c index b4b6069f927..9271840b165 100644 --- a/server/queue.c +++ b/server/queue.c @@ -534,8 +534,11 @@ static int update_desktop_cursor_pos( struct desktop *desktop, user_handle_t win int updated; unsigned int time = get_tick_count();
- x = max( min( x, desktop_shm->cursor.clip.right - 1 ), desktop_shm->cursor.clip.left ); - y = max( min( y, desktop_shm->cursor.clip.bottom - 1 ), desktop_shm->cursor.clip.top ); + if (!(desktop->cursor_flags & SEND_HWMSG_NO_VSCREEN_CLIP) || is_cursor_clipped( desktop )) + { + x = max( min( x, desktop_shm->cursor.clip.right - 1 ), desktop_shm->cursor.clip.left ); + y = max( min( y, desktop_shm->cursor.clip.bottom - 1 ), desktop_shm->cursor.clip.top ); + }
SHARED_WRITE_BEGIN( desktop_shm, desktop_shm_t ) { @@ -635,9 +638,12 @@ void set_clip_rectangle( struct desktop *desktop, const struct rectangle *rect, desktop->clip_flags = flags;
/* warp the mouse to be inside the clip rect */ - x = max( min( desktop_shm->cursor.x, new_rect.right - 1 ), new_rect.left ); - y = max( min( desktop_shm->cursor.y, new_rect.bottom - 1 ), new_rect.top ); - if (x != desktop_shm->cursor.x || y != desktop_shm->cursor.y) set_cursor_pos( desktop, x, y ); + if (!(desktop->cursor_flags & SEND_HWMSG_NO_VSCREEN_CLIP) || is_cursor_clipped( desktop )) + { + x = max( min( desktop_shm->cursor.x, new_rect.right - 1 ), new_rect.left ); + y = max( min( desktop_shm->cursor.y, new_rect.bottom - 1 ), new_rect.top ); + if (x != desktop_shm->cursor.x || y != desktop_shm->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, flags, FALSE ); @@ -3296,6 +3302,7 @@ DECL_HANDLER(send_hardware_message) switch (req->input.type) { case INPUT_MOUSE: + desktop->cursor_flags = req->flags; wait = queue_mouse_message( desktop, req->win, &req->input, origin, sender ); break; case INPUT_KEYBOARD: diff --git a/server/user.h b/server/user.h index ce463b9395d..dbee4b56a4a 100644 --- a/server/user.h +++ b/server/user.h @@ -94,6 +94,7 @@ struct desktop struct key_repeat key_repeat; /* key auto-repeat */ unsigned int clip_flags; /* last cursor clip flags */ user_handle_t cursor_win; /* window that contains the cursor */ + unsigned int cursor_flags; /* last cursor flags */ const desktop_shm_t *shared; /* desktop session shared memory */ };
I don't think that this can work well, although it might for window-relative cursor positions, it probably won't as soon as absolute cursor positions are involved as applications will likely not expect to handle cursor outside of the virtual screen. Moreover, some events such as touch input use a 0-65535 range for their position, corresponding to the virtual screen dimensions. For those, it's simply not possible to have coordinates outside of the virtual screen.
Perhaps a better solution would be to have an option in win32u that can be enabled to constrain windows that are partially outside of the virtual screen, and move them automatically if they can be. Windows that are fully outside of the virtual screen should simply not be displayed.