From dec7875a6e23212021e4d9080330a42832dfe02a Mon Sep 17 00:00:00 2001
From: Edward Rudd <urkle@outoforder.cc>
Date: Tue, 15 Jun 2021 01:40:19 +0000
Subject: [PATCH] update SDL soruce to 2.0.14
---
source/src/video/wayland/SDL_waylandevents.c | 267 ++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 213 insertions(+), 54 deletions(-)
diff --git a/source/src/video/wayland/SDL_waylandevents.c b/source/src/video/wayland/SDL_waylandevents.c
index 72e902a..0d57cbf 100644
--- a/source/src/video/wayland/SDL_waylandevents.c
+++ b/source/src/video/wayland/SDL_waylandevents.c
@@ -24,8 +24,7 @@
#if SDL_VIDEO_DRIVER_WAYLAND
#include "SDL_stdinc.h"
-#include "SDL_assert.h"
-#include "SDL_log.h"
+#include "SDL_timer.h"
#include "../../core/unix/SDL_poll.h"
#include "../../events/SDL_sysevents.h"
@@ -43,12 +42,32 @@
#include "xdg-shell-client-protocol.h"
#include "xdg-shell-unstable-v6-client-protocol.h"
+#ifdef SDL_INPUT_LINUXEV
#include <linux/input.h>
+#else
+#define BTN_LEFT (0x110)
+#define BTN_RIGHT (0x111)
+#define BTN_MIDDLE (0x112)
+#define BTN_SIDE (0x113)
+#define BTN_EXTRA (0x114)
+#endif
#include <sys/select.h>
#include <sys/mman.h>
#include <poll.h>
#include <unistd.h>
#include <xkbcommon/xkbcommon.h>
+
+typedef struct {
+ // repeat_rate in range of [1, 1000]
+ int32_t repeat_rate;
+ int32_t repeat_delay;
+ SDL_bool is_initialized;
+
+ SDL_bool is_key_down;
+ uint32_t next_repeat_ms;
+ uint32_t scancode;
+ char text[8];
+} SDL_WaylandKeyboardRepeat;
struct SDL_WaylandInput {
SDL_VideoData *display;
@@ -58,6 +77,8 @@
struct wl_keyboard *keyboard;
SDL_WaylandDataDevice *data_device;
struct zwp_relative_pointer_v1 *relative_pointer;
+ struct zwp_confined_pointer_v1 *confined_pointer;
+ SDL_Window *confined_pointer_window;
SDL_WindowData *pointer_focus;
SDL_WindowData *keyboard_focus;
@@ -81,6 +102,8 @@
SDL_bool is_y_discrete;
float y;
} pointer_curr_axis_info;
+
+ SDL_WaylandKeyboardRepeat keyboard_repeat;
};
struct SDL_WaylandTouchPoint {
@@ -187,13 +210,61 @@
return NULL;
}
+/* Returns the time till next repeat, or 0 if no key is down. */
+static void
+keyboard_repeat_handle(SDL_WaylandKeyboardRepeat* repeat_info, uint32_t now)
+{
+ if (!repeat_info->is_key_down || !repeat_info->is_initialized) {
+ return;
+ }
+ while (repeat_info->next_repeat_ms <= now) {
+ if (repeat_info->scancode != SDL_SCANCODE_UNKNOWN) {
+ SDL_SendKeyboardKey(SDL_PRESSED, repeat_info->scancode);
+ }
+ if (repeat_info->text[0]) {
+ SDL_SendKeyboardText(repeat_info->text);
+ }
+ repeat_info->next_repeat_ms += 1000 / repeat_info->repeat_rate;
+ }
+}
+
+static void
+keyboard_repeat_clear(SDL_WaylandKeyboardRepeat* repeat_info) {
+ if (!repeat_info->is_initialized) {
+ return;
+ }
+ repeat_info->is_key_down = SDL_FALSE;
+}
+
+static void
+keyboard_repeat_set(SDL_WaylandKeyboardRepeat* repeat_info,
+ uint32_t scancode, SDL_bool has_text, char text[8]) {
+ if (!repeat_info->is_initialized) {
+ return;
+ }
+ repeat_info->is_key_down = SDL_TRUE;
+ repeat_info->next_repeat_ms = SDL_GetTicks() + repeat_info->repeat_delay;
+ repeat_info->scancode = scancode;
+ if (has_text) {
+ memcpy(repeat_info->text, text, 8);
+ } else {
+ repeat_info->text[0] = '\0';
+ }
+}
+
void
Wayland_PumpEvents(_THIS)
{
SDL_VideoData *d = _this->driverdata;
+ struct SDL_WaylandInput *input = d->input;
int err;
WAYLAND_wl_display_flush(d->display);
+
+ if (input) {
+ uint32_t now = SDL_GetTicks();
+ keyboard_repeat_handle(&input->keyboard_repeat, now);
+ }
if (SDL_IOReady(WAYLAND_wl_display_get_fd(d->display), SDL_FALSE, 0)) {
err = WAYLAND_wl_display_dispatch(d->display);
@@ -208,6 +279,21 @@
/* Only send a single quit message, as application shutdown might call
* SDL_PumpEvents */
SDL_SendQuit();
+ }
+}
+
+static void
+pointer_handle_motion(void *data, struct wl_pointer *pointer,
+ uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
+{
+ struct SDL_WaylandInput *input = data;
+ SDL_WindowData *window = input->pointer_focus;
+ input->sx_w = sx_w;
+ input->sy_w = sy_w;
+ if (input->pointer_focus) {
+ const int sx = wl_fixed_to_int(sx_w);
+ const int sy = wl_fixed_to_int(sy_w);
+ SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
}
}
@@ -235,6 +321,10 @@
if (window) {
input->pointer_focus = window;
SDL_SetMouseFocus(window->sdlwindow);
+ /* In the case of e.g. a pointer confine warp, we may receive an enter
+ * event with no following motion event, but with the new coordinates
+ * as part of the enter event. */
+ pointer_handle_motion(data, pointer, serial, sx_w, sy_w);
}
}
@@ -247,21 +337,6 @@
if (input->pointer_focus) {
SDL_SetMouseFocus(NULL);
input->pointer_focus = NULL;
- }
-}
-
-static void
-pointer_handle_motion(void *data, struct wl_pointer *pointer,
- uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
-{
- struct SDL_WaylandInput *input = data;
- SDL_WindowData *window = input->pointer_focus;
- input->sx_w = sx_w;
- input->sy_w = sy_w;
- if (input->pointer_focus) {
- const int sx = wl_fixed_to_int(sx_w);
- const int sy = wl_fixed_to_int(sy_w);
- SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
}
}
@@ -352,8 +427,8 @@
default:
return;
}
-
- Wayland_data_device_set_serial(input->data_device, serial);
+
+ Wayland_data_device_set_serial(input->data_device, serial);
SDL_SendMouseButton(window->sdlwindow, 0,
state ? SDL_PRESSED : SDL_RELEASED, sdl_button);
@@ -437,7 +512,7 @@
{
struct SDL_WaylandInput *input = data;
- if(wl_seat_interface.version >= 5)
+ if(wl_seat_get_version(input->seat) >= 5)
pointer_handle_axis_common(input, SDL_FALSE, axis, value);
else
pointer_handle_axis_common_v1(input, time, axis, value);
@@ -638,45 +713,52 @@
SDL_SetKeyboardFocus(NULL);
}
+static SDL_bool
+keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint32_t key)
+{
+ SDL_WindowData *window = input->keyboard_focus;
+ const xkb_keysym_t *syms;
+
+ if (!window || window->keyboard_device != input || !input->xkb.state) {
+ return SDL_FALSE;
+ }
+
+ // TODO can this happen?
+ if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1) {
+ return SDL_FALSE;
+ }
+
+ return WAYLAND_xkb_keysym_to_utf8(syms[0], text, 8) > 0;
+}
+
static void
keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
uint32_t serial, uint32_t time, uint32_t key,
uint32_t state_w)
{
struct SDL_WaylandInput *input = data;
- SDL_WindowData *window = input->keyboard_focus;
enum wl_keyboard_key_state state = state_w;
- const xkb_keysym_t *syms;
- uint32_t scancode;
+ uint32_t scancode = SDL_SCANCODE_UNKNOWN;
char text[8];
- int size;
if (key < SDL_arraysize(xfree86_scancode_table2)) {
scancode = xfree86_scancode_table2[key];
- // TODO when do we get WL_KEYBOARD_KEY_STATE_REPEAT?
- if (scancode != SDL_SCANCODE_UNKNOWN)
+ if (scancode != SDL_SCANCODE_UNKNOWN) {
SDL_SendKeyboardKey(state == WL_KEYBOARD_KEY_STATE_PRESSED ?
SDL_PRESSED : SDL_RELEASED, scancode);
+ }
}
- if (!window || window->keyboard_device != input || !input->xkb.state)
- return;
-
- // TODO can this happen?
- if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1)
- return;
-
- if (state) {
- size = WAYLAND_xkb_keysym_to_utf8(syms[0], text, sizeof text);
-
- if (size > 0) {
- text[size] = 0;
-
+ if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+ SDL_bool has_text = keyboard_input_get_text(text, input, key);
+ if (has_text) {
Wayland_data_device_set_serial(input->data_device, serial);
-
SDL_SendKeyboardText(text);
}
+ keyboard_repeat_set(&input->keyboard_repeat, scancode, has_text, text);
+ } else {
+ keyboard_repeat_clear(&input->keyboard_repeat);
}
}
@@ -696,7 +778,10 @@
keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
int32_t rate, int32_t delay)
{
- /* unimplemented */
+ struct SDL_WaylandInput *input = data;
+ input->keyboard_repeat.repeat_rate = SDL_max(0, SDL_min(rate, 1000));
+ input->keyboard_repeat.repeat_delay = delay;
+ input->keyboard_repeat.is_initialized = SDL_TRUE;
}
static const struct wl_keyboard_listener keyboard_listener = {
@@ -773,13 +858,13 @@
{
Wayland_data_source_send((SDL_WaylandDataSource *)data, mime_type, fd);
}
-
+
static void
data_source_handle_cancelled(void *data, struct wl_data_source *wl_data_source)
{
Wayland_data_source_destroy(data);
}
-
+
static void
data_source_handle_dnd_drop_performed(void *data, struct wl_data_source *wl_data_source)
{
@@ -822,7 +907,7 @@
driver_data->data_device_manager);
}
- if (id == NULL) {
+ if (id == NULL) {
SDL_SetError("Wayland unable to create data source");
} else {
data_source = SDL_calloc(1, sizeof *data_source);
@@ -892,8 +977,8 @@
{
SDL_WaylandDataDevice *data_device = data;
SDL_bool has_mime = SDL_FALSE;
- uint32_t dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
-
+ uint32_t dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+
data_device->drag_serial = serial;
if (id != NULL) {
@@ -946,7 +1031,7 @@
const char *current_uri = NULL;
const char *last_char = NULL;
char *current_char = NULL;
-
+
if (data_device->drag_offer != NULL) {
/* TODO: SDL Support more mime types */
buffer = Wayland_data_offer_receive(data_device->drag_offer,
@@ -972,7 +1057,7 @@
static void
data_device_handle_selection(void *data, struct wl_data_device *wl_data_device,
struct wl_data_offer *id)
-{
+{
SDL_WaylandDataDevice *data_device = data;
SDL_WaylandDataOffer *offer = NULL;
@@ -998,7 +1083,7 @@
};
void
-Wayland_display_add_input(SDL_VideoData *d, uint32_t id)
+Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version)
{
struct SDL_WaylandInput *input;
SDL_WaylandDataDevice *data_device = NULL;
@@ -1008,14 +1093,11 @@
return;
input->display = d;
- if (wl_seat_interface.version >= 5)
- input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 5);
- else
- input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 1);
+ input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, SDL_min(5, version));
input->sx_w = wl_fixed_from_int(0);
input->sy_w = wl_fixed_from_int(0);
d->input = input;
-
+
if (d->data_device_manager != NULL) {
data_device = SDL_calloc(1, sizeof *data_device);
if (data_device == NULL) {
@@ -1202,6 +1284,14 @@
w->locked_pointer = locked_pointer;
}
+static void pointer_confine_destroy(struct SDL_WaylandInput *input)
+{
+ if (input->confined_pointer) {
+ zwp_confined_pointer_v1_destroy(input->confined_pointer);
+ input->confined_pointer = NULL;
+ }
+}
+
int Wayland_input_lock_pointer(struct SDL_WaylandInput *input)
{
SDL_VideoDevice *vd = SDL_GetVideoDevice();
@@ -1217,6 +1307,10 @@
if (!input->pointer)
return -1;
+
+ /* If we have a pointer confine active, we must destroy it here because
+ * creating a locked pointer otherwise would be a protocol error. */
+ pointer_confine_destroy(input);
if (!input->relative_pointer) {
relative_pointer =
@@ -1256,6 +1350,71 @@
d->relative_mouse_mode = 0;
+ if (input->confined_pointer_window)
+ Wayland_input_confine_pointer(input->confined_pointer_window, input);
+
+ return 0;
+}
+
+static void
+confined_pointer_confined(void *data,
+ struct zwp_confined_pointer_v1 *confined_pointer)
+{
+}
+
+static void
+confined_pointer_unconfined(void *data,
+ struct zwp_confined_pointer_v1 *confined_pointer)
+{
+}
+
+static const struct zwp_confined_pointer_v1_listener confined_pointer_listener = {
+ confined_pointer_confined,
+ confined_pointer_unconfined,
+};
+
+int Wayland_input_confine_pointer(SDL_Window *window, struct SDL_WaylandInput *input)
+{
+ SDL_WindowData *w = window->driverdata;
+ SDL_VideoData *d = input->display;
+ struct zwp_confined_pointer_v1 *confined_pointer;
+
+ if (!d->pointer_constraints)
+ return -1;
+
+ if (!input->pointer)
+ return -1;
+
+ /* A confine may already be active, in which case we should destroy it and
+ * create a new one. */
+ if (input->confined_pointer)
+ Wayland_input_unconfine_pointer(input);
+
+ input->confined_pointer_window = window;
+
+ /* We cannot create a confine if the pointer is already locked. Defer until
+ * the pointer is unlocked. */
+ if (d->relative_mouse_mode)
+ return 0;
+
+ confined_pointer =
+ zwp_pointer_constraints_v1_confine_pointer(d->pointer_constraints,
+ w->surface,
+ input->pointer,
+ NULL,
+ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
+ zwp_confined_pointer_v1_add_listener(confined_pointer,
+ &confined_pointer_listener,
+ window);
+
+ input->confined_pointer = confined_pointer;
+ return 0;
+}
+
+int Wayland_input_unconfine_pointer(struct SDL_WaylandInput *input)
+{
+ pointer_confine_destroy(input);
+ input->confined_pointer_window = NULL;
return 0;
}
--
Gitblit v1.9.3