From f600364b8a575e03f140ab18eeabaeffb8f0b392 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Sat, 6 Aug 2022 09:19:52 -0400
Subject: [PATCH] wayland: Mark window as MOUSE_CAPTURE while a mouse button is
down.
Wayland works like SDL's "auto capture" feature already, tracking the mouse
globally only while a drag is occuring, and this is the only way to get mouse
input outside the window.
Setting this flag ourselves lets SDL_CaptureMouse() work in the most common
use case without actually implementing CaptureMouse for the backend, including
SDL's auto capture feature.
Fixes #6010.
---
src/video/wayland/SDL_waylandevents.c | 25 ++++++++++++++++++++++++-
src/video/wayland/SDL_waylandevents_c.h | 2 ++
2 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
index 2b547faf673..14a28430c98 100644
--- a/src/video/wayland/SDL_waylandevents.c
+++ b/src/video/wayland/SDL_waylandevents.c
@@ -545,7 +545,7 @@ pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial,
enum wl_pointer_button_state state = state_w;
uint32_t sdl_button;
- if (input->pointer_focus) {
+ if (window) {
switch (button) {
case BTN_LEFT:
sdl_button = SDL_BUTTON_LEFT;
@@ -569,6 +569,23 @@ pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial,
return;
}
+ /* Wayland won't let you "capture" the mouse, but it will
+ automatically track the mouse outside the window if you
+ drag outside of it, until you let go of all buttons (even
+ if you add or remove presses outside the window, as long
+ as any button is still down, the capture remains) */
+ if (state) { /* update our mask of currently-pressed buttons */
+ input->buttons_pressed |= SDL_BUTTON(sdl_button);
+ } else {
+ input->buttons_pressed &= ~(SDL_BUTTON(sdl_button));
+ }
+
+ if (input->buttons_pressed != 0) {
+ window->sdlwindow->flags |= SDL_WINDOW_MOUSE_CAPTURE;
+ } else {
+ window->sdlwindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
+ }
+
Wayland_data_device_set_serial(input->data_device, serial);
SDL_SendMouseButton(window->sdlwindow, 0,
@@ -913,11 +930,17 @@ keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
uint32_t serial, struct wl_surface *surface)
{
struct SDL_WaylandInput *input = data;
+ SDL_WindowData *window;
if (!surface || !SDL_WAYLAND_own_surface(surface)) {
return;
}
+ window = wl_surface_get_user_data(surface);
+ if (window) {
+ window->sdlwindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
+ }
+
/* Stop key repeat before clearing keyboard focus */
keyboard_repeat_clear(&input->keyboard_repeat);
diff --git a/src/video/wayland/SDL_waylandevents_c.h b/src/video/wayland/SDL_waylandevents_c.h
index 59dc0c8afaa..9bcb2c9b155 100644
--- a/src/video/wayland/SDL_waylandevents_c.h
+++ b/src/video/wayland/SDL_waylandevents_c.h
@@ -88,6 +88,8 @@ struct SDL_WaylandInput {
wl_fixed_t sx_w;
wl_fixed_t sy_w;
+ uint32_t buttons_pressed;
+
double dx_frac;
double dy_frac;