|
@@ -66,6 +66,7 @@
|
|
#include <xkbcommon/xkbcommon-compose.h>
|
|
#include <xkbcommon/xkbcommon-compose.h>
|
|
#include <xkbcommon/xkbcommon.h>
|
|
#include <xkbcommon/xkbcommon.h>
|
|
#include "cursor-shape-v1-client-protocol.h"
|
|
#include "cursor-shape-v1-client-protocol.h"
|
|
|
|
+#include "viewporter-client-protocol.h"
|
|
|
|
|
|
// Weston uses a ratio of 10 units per scroll tick
|
|
// Weston uses a ratio of 10 units per scroll tick
|
|
#define WAYLAND_WHEEL_AXIS_UNIT 10
|
|
#define WAYLAND_WHEEL_AXIS_UNIT 10
|
|
@@ -81,10 +82,14 @@
|
|
// Keyboard and mouse names to match XWayland
|
|
// Keyboard and mouse names to match XWayland
|
|
#define WAYLAND_DEFAULT_KEYBOARD_NAME "Virtual core keyboard"
|
|
#define WAYLAND_DEFAULT_KEYBOARD_NAME "Virtual core keyboard"
|
|
#define WAYLAND_DEFAULT_POINTER_NAME "Virtual core pointer"
|
|
#define WAYLAND_DEFAULT_POINTER_NAME "Virtual core pointer"
|
|
|
|
+#define WAYLAND_DEFAULT_TOUCH_NAME "Virtual core touch"
|
|
|
|
|
|
// Focus clickthrough timeout
|
|
// Focus clickthrough timeout
|
|
#define WAYLAND_FOCUS_CLICK_TIMEOUT_NS SDL_MS_TO_NS(10)
|
|
#define WAYLAND_FOCUS_CLICK_TIMEOUT_NS SDL_MS_TO_NS(10)
|
|
|
|
|
|
|
|
+// Scoped function declarations
|
|
|
|
+static void Wayland_SeatUpdateKeyboardGrab(SDL_WaylandSeat *seat);
|
|
|
|
+
|
|
struct SDL_WaylandTouchPoint
|
|
struct SDL_WaylandTouchPoint
|
|
{
|
|
{
|
|
SDL_TouchID id;
|
|
SDL_TouchID id;
|
|
@@ -95,9 +100,7 @@ struct SDL_WaylandTouchPoint
|
|
struct wl_list link;
|
|
struct wl_list link;
|
|
};
|
|
};
|
|
|
|
|
|
-static struct wl_list touch_points;
|
|
|
|
-
|
|
|
|
-static void touch_add(SDL_TouchID id, wl_fixed_t fx, wl_fixed_t fy, struct wl_surface *surface)
|
|
|
|
|
|
+static void Wayland_SeatAddTouch(SDL_WaylandSeat *seat, SDL_TouchID id, wl_fixed_t fx, wl_fixed_t fy, struct wl_surface *surface)
|
|
{
|
|
{
|
|
struct SDL_WaylandTouchPoint *tp = SDL_malloc(sizeof(struct SDL_WaylandTouchPoint));
|
|
struct SDL_WaylandTouchPoint *tp = SDL_malloc(sizeof(struct SDL_WaylandTouchPoint));
|
|
|
|
|
|
@@ -107,14 +110,14 @@ static void touch_add(SDL_TouchID id, wl_fixed_t fx, wl_fixed_t fy, struct wl_su
|
|
tp->fy = fy;
|
|
tp->fy = fy;
|
|
tp->surface = surface;
|
|
tp->surface = surface;
|
|
|
|
|
|
- WAYLAND_wl_list_insert(&touch_points, &tp->link);
|
|
|
|
|
|
+ WAYLAND_wl_list_insert(&seat->touch.points, &tp->link);
|
|
}
|
|
}
|
|
|
|
|
|
-static void touch_update(SDL_TouchID id, wl_fixed_t fx, wl_fixed_t fy, struct wl_surface **surface)
|
|
|
|
|
|
+static void Wayland_SeatUpdateTouch(SDL_WaylandSeat *seat, SDL_TouchID id, wl_fixed_t fx, wl_fixed_t fy, struct wl_surface **surface)
|
|
{
|
|
{
|
|
struct SDL_WaylandTouchPoint *tp;
|
|
struct SDL_WaylandTouchPoint *tp;
|
|
|
|
|
|
- wl_list_for_each (tp, &touch_points, link) {
|
|
|
|
|
|
+ wl_list_for_each (tp, &seat->touch.points, link) {
|
|
if (tp->id == id) {
|
|
if (tp->id == id) {
|
|
tp->fx = fx;
|
|
tp->fx = fx;
|
|
tp->fy = fy;
|
|
tp->fy = fy;
|
|
@@ -126,11 +129,11 @@ static void touch_update(SDL_TouchID id, wl_fixed_t fx, wl_fixed_t fy, struct wl
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static void touch_del(SDL_TouchID id, wl_fixed_t *fx, wl_fixed_t *fy, struct wl_surface **surface)
|
|
|
|
|
|
+static void Wayland_SeatRemoveTouch(SDL_WaylandSeat *seat, SDL_TouchID id, wl_fixed_t *fx, wl_fixed_t *fy, struct wl_surface **surface)
|
|
{
|
|
{
|
|
struct SDL_WaylandTouchPoint *tp;
|
|
struct SDL_WaylandTouchPoint *tp;
|
|
|
|
|
|
- wl_list_for_each (tp, &touch_points, link) {
|
|
|
|
|
|
+ wl_list_for_each (tp, &seat->touch.points, link) {
|
|
if (tp->id == id) {
|
|
if (tp->id == id) {
|
|
if (fx) {
|
|
if (fx) {
|
|
*fx = tp->fx;
|
|
*fx = tp->fx;
|
|
@@ -149,19 +152,33 @@ static void touch_del(SDL_TouchID id, wl_fixed_t *fx, wl_fixed_t *fy, struct wl_
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static bool Wayland_SurfaceHasActiveTouches(struct wl_surface *surface)
|
|
|
|
|
|
+static bool Wayland_SurfaceHasActiveTouches(SDL_VideoData *display, struct wl_surface *surface)
|
|
{
|
|
{
|
|
struct SDL_WaylandTouchPoint *tp;
|
|
struct SDL_WaylandTouchPoint *tp;
|
|
|
|
+ SDL_WaylandSeat *seat;
|
|
|
|
|
|
- wl_list_for_each (tp, &touch_points, link) {
|
|
|
|
- if (tp->surface == surface) {
|
|
|
|
- return true;
|
|
|
|
|
|
+ // Check all seats for active touches on the surface.
|
|
|
|
+ wl_list_for_each (seat, &display->seat_list, link) {
|
|
|
|
+ wl_list_for_each (tp, &seat->touch.points, link) {
|
|
|
|
+ if (tp->surface == surface) {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void Wayland_GetScaledMouseRect(SDL_Window *window, SDL_Rect *scaled_rect)
|
|
|
|
+{
|
|
|
|
+ SDL_WindowData *window_data = window->internal;
|
|
|
|
+
|
|
|
|
+ scaled_rect->x = (int)SDL_floor(window->mouse_rect.x / window_data->pointer_scale.x);
|
|
|
|
+ scaled_rect->y = (int)SDL_floor(window->mouse_rect.y / window_data->pointer_scale.y);
|
|
|
|
+ scaled_rect->w = (int)SDL_ceil(window->mouse_rect.w / window_data->pointer_scale.x);
|
|
|
|
+ scaled_rect->h = (int)SDL_ceil(window->mouse_rect.h / window_data->pointer_scale.y);
|
|
|
|
+}
|
|
|
|
+
|
|
static Uint64 Wayland_GetEventTimestamp(Uint64 nsTimestamp)
|
|
static Uint64 Wayland_GetEventTimestamp(Uint64 nsTimestamp)
|
|
{
|
|
{
|
|
static Uint64 last;
|
|
static Uint64 last;
|
|
@@ -187,85 +204,99 @@ static Uint64 Wayland_GetEventTimestamp(Uint64 nsTimestamp)
|
|
return nsTimestamp;
|
|
return nsTimestamp;
|
|
}
|
|
}
|
|
|
|
|
|
-static void Wayland_input_timestamp_listener(void *data, struct zwp_input_timestamps_v1 *zwp_input_timestamps_v1,
|
|
|
|
|
|
+static void input_timestamp_listener(void *data, struct zwp_input_timestamps_v1 *zwp_input_timestamps_v1,
|
|
uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec)
|
|
uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec)
|
|
{
|
|
{
|
|
*((Uint64 *)data) = ((((Uint64)tv_sec_hi << 32) | (Uint64)tv_sec_lo) * SDL_NS_PER_SECOND) + tv_nsec;
|
|
*((Uint64 *)data) = ((((Uint64)tv_sec_hi << 32) | (Uint64)tv_sec_lo) * SDL_NS_PER_SECOND) + tv_nsec;
|
|
}
|
|
}
|
|
|
|
|
|
static const struct zwp_input_timestamps_v1_listener timestamp_listener = {
|
|
static const struct zwp_input_timestamps_v1_listener timestamp_listener = {
|
|
- Wayland_input_timestamp_listener
|
|
|
|
|
|
+ input_timestamp_listener
|
|
};
|
|
};
|
|
|
|
|
|
-static Uint64 Wayland_GetKeyboardTimestamp(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms)
|
|
|
|
|
|
+static Uint64 Wayland_GetKeyboardTimestamp(SDL_WaylandSeat *seat, Uint32 wl_timestamp_ms)
|
|
{
|
|
{
|
|
if (wl_timestamp_ms) {
|
|
if (wl_timestamp_ms) {
|
|
- return Wayland_GetEventTimestamp(input->keyboard_timestamp_ns ? input->keyboard_timestamp_ns : SDL_MS_TO_NS(wl_timestamp_ms));
|
|
|
|
|
|
+ return Wayland_GetEventTimestamp(seat->keyboard.highres_timestamp_ns ? seat->keyboard.highres_timestamp_ns : SDL_MS_TO_NS(wl_timestamp_ms));
|
|
}
|
|
}
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static Uint64 Wayland_GetKeyboardTimestampRaw(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms)
|
|
|
|
|
|
+static Uint64 Wayland_GetKeyboardTimestampRaw(SDL_WaylandSeat *seat, Uint32 wl_timestamp_ms)
|
|
{
|
|
{
|
|
if (wl_timestamp_ms) {
|
|
if (wl_timestamp_ms) {
|
|
- return input->keyboard_timestamp_ns ? input->keyboard_timestamp_ns : SDL_MS_TO_NS(wl_timestamp_ms);
|
|
|
|
|
|
+ return seat->keyboard.highres_timestamp_ns ? seat->keyboard.highres_timestamp_ns : SDL_MS_TO_NS(wl_timestamp_ms);
|
|
}
|
|
}
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static Uint64 Wayland_GetPointerTimestamp(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms)
|
|
|
|
|
|
+static Uint64 Wayland_GetPointerTimestamp(SDL_WaylandSeat *seat, Uint32 wl_timestamp_ms)
|
|
{
|
|
{
|
|
if (wl_timestamp_ms) {
|
|
if (wl_timestamp_ms) {
|
|
- return Wayland_GetEventTimestamp(input->pointer_timestamp_ns ? input->pointer_timestamp_ns : SDL_MS_TO_NS(wl_timestamp_ms));
|
|
|
|
|
|
+ return Wayland_GetEventTimestamp(seat->pointer.highres_timestamp_ns ? seat->pointer.highres_timestamp_ns : SDL_MS_TO_NS(wl_timestamp_ms));
|
|
}
|
|
}
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-Uint64 Wayland_GetTouchTimestamp(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms)
|
|
|
|
|
|
+Uint64 Wayland_GetTouchTimestamp(SDL_WaylandSeat *seat, Uint32 wl_timestamp_ms)
|
|
{
|
|
{
|
|
if (wl_timestamp_ms) {
|
|
if (wl_timestamp_ms) {
|
|
- return Wayland_GetEventTimestamp(input->touch_timestamp_ns ? input->touch_timestamp_ns : SDL_MS_TO_NS(wl_timestamp_ms));
|
|
|
|
|
|
+ return Wayland_GetEventTimestamp(seat->touch.highres_timestamp_ns ? seat->touch.highres_timestamp_ns : SDL_MS_TO_NS(wl_timestamp_ms));
|
|
}
|
|
}
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-void Wayland_RegisterTimestampListeners(struct SDL_WaylandInput *input)
|
|
|
|
|
|
+static void Wayland_SeatRegisterInputTimestampListeners(SDL_WaylandSeat *seat)
|
|
{
|
|
{
|
|
- SDL_VideoData *viddata = input->display;
|
|
|
|
-
|
|
|
|
- if (viddata->input_timestamps_manager) {
|
|
|
|
- if (input->keyboard && !input->keyboard_timestamps) {
|
|
|
|
- input->keyboard_timestamps = zwp_input_timestamps_manager_v1_get_keyboard_timestamps(viddata->input_timestamps_manager, input->keyboard);
|
|
|
|
- zwp_input_timestamps_v1_add_listener(input->keyboard_timestamps, ×tamp_listener, &input->keyboard_timestamp_ns);
|
|
|
|
|
|
+ if (seat->display->input_timestamps_manager) {
|
|
|
|
+ if (seat->keyboard.wl_keyboard && !seat->keyboard.timestamps) {
|
|
|
|
+ seat->keyboard.timestamps = zwp_input_timestamps_manager_v1_get_keyboard_timestamps(seat->display->input_timestamps_manager, seat->keyboard.wl_keyboard);
|
|
|
|
+ zwp_input_timestamps_v1_add_listener(seat->keyboard.timestamps, ×tamp_listener, &seat->keyboard.highres_timestamp_ns);
|
|
}
|
|
}
|
|
|
|
|
|
- if (input->pointer && !input->pointer_timestamps) {
|
|
|
|
- input->pointer_timestamps = zwp_input_timestamps_manager_v1_get_pointer_timestamps(viddata->input_timestamps_manager, input->pointer);
|
|
|
|
- zwp_input_timestamps_v1_add_listener(input->pointer_timestamps, ×tamp_listener, &input->pointer_timestamp_ns);
|
|
|
|
|
|
+ if (seat->pointer.wl_pointer && !seat->pointer.timestamps) {
|
|
|
|
+ seat->pointer.timestamps = zwp_input_timestamps_manager_v1_get_pointer_timestamps(seat->display->input_timestamps_manager, seat->pointer.wl_pointer);
|
|
|
|
+ zwp_input_timestamps_v1_add_listener(seat->pointer.timestamps, ×tamp_listener, &seat->pointer.highres_timestamp_ns);
|
|
}
|
|
}
|
|
|
|
|
|
- if (input->touch && !input->touch_timestamps) {
|
|
|
|
- input->touch_timestamps = zwp_input_timestamps_manager_v1_get_touch_timestamps(viddata->input_timestamps_manager, input->touch);
|
|
|
|
- zwp_input_timestamps_v1_add_listener(input->touch_timestamps, ×tamp_listener, &input->touch_timestamp_ns);
|
|
|
|
|
|
+ if (seat->touch.wl_touch && !seat->touch.timestamps) {
|
|
|
|
+ seat->touch.timestamps = zwp_input_timestamps_manager_v1_get_touch_timestamps(seat->display->input_timestamps_manager, seat->touch.wl_touch);
|
|
|
|
+ zwp_input_timestamps_v1_add_listener(seat->touch.timestamps, ×tamp_listener, &seat->touch.highres_timestamp_ns);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-void Wayland_CreateCursorShapeDevice(struct SDL_WaylandInput *input)
|
|
|
|
|
|
+void Wayland_DisplayInitInputTimestampManager(SDL_VideoData *display)
|
|
{
|
|
{
|
|
- SDL_VideoData *viddata = input->display;
|
|
|
|
|
|
+ if (display->input_timestamps_manager) {
|
|
|
|
+ SDL_WaylandSeat *seat;
|
|
|
|
+ wl_list_for_each (seat, &display->seat_list, link) {
|
|
|
|
+ Wayland_SeatRegisterInputTimestampListeners(seat);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
- if (viddata->cursor_shape_manager) {
|
|
|
|
- if (input->pointer && !input->cursor_shape) {
|
|
|
|
- input->cursor_shape = wp_cursor_shape_manager_v1_get_pointer(viddata->cursor_shape_manager, input->pointer);
|
|
|
|
|
|
+static void Wayland_SeatCreateCursorShape(SDL_WaylandSeat *seat)
|
|
|
|
+{
|
|
|
|
+ if (seat->display->cursor_shape_manager) {
|
|
|
|
+ if (seat->pointer.wl_pointer && !seat->pointer.cursor_shape) {
|
|
|
|
+ seat->pointer.cursor_shape = wp_cursor_shape_manager_v1_get_pointer(seat->display->cursor_shape_manager, seat->pointer.wl_pointer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void Wayland_DisplayInitCursorShapeManager(SDL_VideoData *display)
|
|
|
|
+{
|
|
|
|
+ SDL_WaylandSeat *seat;
|
|
|
|
+ wl_list_for_each (seat, &display->seat_list, link) {
|
|
|
|
+ Wayland_SeatCreateCursorShape(seat);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
// Returns true if a key repeat event was due
|
|
// Returns true if a key repeat event was due
|
|
static bool keyboard_repeat_handle(SDL_WaylandKeyboardRepeat *repeat_info, Uint64 elapsed)
|
|
static bool keyboard_repeat_handle(SDL_WaylandKeyboardRepeat *repeat_info, Uint64 elapsed)
|
|
{
|
|
{
|
|
@@ -381,7 +412,7 @@ static int dispatch_queued_events(SDL_VideoData *viddata)
|
|
int Wayland_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS)
|
|
int Wayland_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS)
|
|
{
|
|
{
|
|
SDL_VideoData *d = _this->internal;
|
|
SDL_VideoData *d = _this->internal;
|
|
- struct SDL_WaylandInput *input = d->input;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat;
|
|
bool key_repeat_active = false;
|
|
bool key_repeat_active = false;
|
|
|
|
|
|
WAYLAND_wl_display_flush(d->display);
|
|
WAYLAND_wl_display_flush(d->display);
|
|
@@ -398,19 +429,26 @@ int Wayland_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS)
|
|
#endif
|
|
#endif
|
|
|
|
|
|
// If key repeat is active, we'll need to cap our maximum wait time to handle repeats
|
|
// If key repeat is active, we'll need to cap our maximum wait time to handle repeats
|
|
- if (input && keyboard_repeat_is_set(&input->keyboard_repeat)) {
|
|
|
|
- const Uint64 elapsed = SDL_GetTicksNS() - input->keyboard_repeat.sdl_press_time_ns;
|
|
|
|
- if (keyboard_repeat_handle(&input->keyboard_repeat, elapsed)) {
|
|
|
|
- // A repeat key event was already due
|
|
|
|
- return 1;
|
|
|
|
- } else {
|
|
|
|
- const Uint64 next_repeat_wait_time = (input->keyboard_repeat.next_repeat_ns - elapsed) + 1;
|
|
|
|
- if (timeoutNS >= 0) {
|
|
|
|
- timeoutNS = SDL_min(timeoutNS, next_repeat_wait_time);
|
|
|
|
|
|
+ wl_list_for_each (seat, &d->seat_list, link) {
|
|
|
|
+ if (keyboard_repeat_is_set(&seat->keyboard.repeat)) {
|
|
|
|
+ if (seat->keyboard.sdl_keymap != SDL_GetCurrentKeymap()) {
|
|
|
|
+ SDL_SetKeymap(seat->keyboard.sdl_keymap, true);
|
|
|
|
+ SDL_SetModState(seat->keyboard.pressed_modifiers | seat->keyboard.locked_modifiers);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const Uint64 elapsed = SDL_GetTicksNS() - seat->keyboard.repeat.sdl_press_time_ns;
|
|
|
|
+ if (keyboard_repeat_handle(&seat->keyboard.repeat, elapsed)) {
|
|
|
|
+ // A repeat key event was already due
|
|
|
|
+ return 1;
|
|
} else {
|
|
} else {
|
|
- timeoutNS = next_repeat_wait_time;
|
|
|
|
|
|
+ const Uint64 next_repeat_wait_time = (seat->keyboard.repeat.next_repeat_ns - elapsed) + 1;
|
|
|
|
+ if (timeoutNS >= 0) {
|
|
|
|
+ timeoutNS = SDL_min(timeoutNS, next_repeat_wait_time);
|
|
|
|
+ } else {
|
|
|
|
+ timeoutNS = next_repeat_wait_time;
|
|
|
|
+ }
|
|
|
|
+ key_repeat_active = true;
|
|
}
|
|
}
|
|
- key_repeat_active = true;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -424,18 +462,27 @@ int Wayland_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS)
|
|
WAYLAND_wl_display_read_events(d->display);
|
|
WAYLAND_wl_display_read_events(d->display);
|
|
return dispatch_queued_events(d);
|
|
return dispatch_queued_events(d);
|
|
} else if (err == 0) {
|
|
} else if (err == 0) {
|
|
|
|
+ int ret = 0;
|
|
|
|
+
|
|
// No events available within the timeout
|
|
// No events available within the timeout
|
|
WAYLAND_wl_display_cancel_read(d->display);
|
|
WAYLAND_wl_display_cancel_read(d->display);
|
|
|
|
|
|
// If key repeat is active, we might have woken up to generate a key event
|
|
// If key repeat is active, we might have woken up to generate a key event
|
|
if (key_repeat_active) {
|
|
if (key_repeat_active) {
|
|
- const Uint64 elapsed = SDL_GetTicksNS() - input->keyboard_repeat.sdl_press_time_ns;
|
|
|
|
- if (keyboard_repeat_handle(&input->keyboard_repeat, elapsed)) {
|
|
|
|
- return 1;
|
|
|
|
|
|
+ wl_list_for_each (seat, &d->seat_list, link) {
|
|
|
|
+ if (seat->keyboard.sdl_keymap != SDL_GetCurrentKeymap()) {
|
|
|
|
+ SDL_SetKeymap(seat->keyboard.sdl_keymap, true);
|
|
|
|
+ SDL_SetModState(seat->keyboard.pressed_modifiers | seat->keyboard.locked_modifiers);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const Uint64 elapsed = SDL_GetTicksNS() - seat->keyboard.repeat.sdl_press_time_ns;
|
|
|
|
+ if (keyboard_repeat_handle(&seat->keyboard.repeat, elapsed)) {
|
|
|
|
+ ++ret;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- return 0;
|
|
|
|
|
|
+ return ret;
|
|
} else {
|
|
} else {
|
|
// Error returned from poll()/select()
|
|
// Error returned from poll()/select()
|
|
WAYLAND_wl_display_cancel_read(d->display);
|
|
WAYLAND_wl_display_cancel_read(d->display);
|
|
@@ -457,7 +504,7 @@ int Wayland_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS)
|
|
void Wayland_PumpEvents(SDL_VideoDevice *_this)
|
|
void Wayland_PumpEvents(SDL_VideoDevice *_this)
|
|
{
|
|
{
|
|
SDL_VideoData *d = _this->internal;
|
|
SDL_VideoData *d = _this->internal;
|
|
- struct SDL_WaylandInput *input = d->input;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat;
|
|
int err;
|
|
int err;
|
|
|
|
|
|
#ifdef SDL_USE_IME
|
|
#ifdef SDL_USE_IME
|
|
@@ -492,9 +539,16 @@ void Wayland_PumpEvents(SDL_VideoDevice *_this)
|
|
// Dispatch any pre-existing pending events or new events we may have read
|
|
// Dispatch any pre-existing pending events or new events we may have read
|
|
err = WAYLAND_wl_display_dispatch_pending(d->display);
|
|
err = WAYLAND_wl_display_dispatch_pending(d->display);
|
|
|
|
|
|
- if (input && keyboard_repeat_is_set(&input->keyboard_repeat)) {
|
|
|
|
- const Uint64 elapsed = SDL_GetTicksNS() - input->keyboard_repeat.sdl_press_time_ns;
|
|
|
|
- keyboard_repeat_handle(&input->keyboard_repeat, elapsed);
|
|
|
|
|
|
+ wl_list_for_each (seat, &d->seat_list, link) {
|
|
|
|
+ if (keyboard_repeat_is_set(&seat->keyboard.repeat)) {
|
|
|
|
+ if (seat->keyboard.sdl_keymap != SDL_GetCurrentKeymap()) {
|
|
|
|
+ SDL_SetKeymap(seat->keyboard.sdl_keymap, true);
|
|
|
|
+ SDL_SetModState(seat->keyboard.pressed_modifiers | seat->keyboard.locked_modifiers);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const Uint64 elapsed = SDL_GetTicksNS() - seat->keyboard.repeat.sdl_press_time_ns;
|
|
|
|
+ keyboard_repeat_handle(&seat->keyboard.repeat, elapsed);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
if (err < 0 && !d->display_disconnected) {
|
|
if (err < 0 && !d->display_disconnected) {
|
|
@@ -519,28 +573,37 @@ void Wayland_PumpEvents(SDL_VideoDevice *_this)
|
|
static void pointer_handle_motion(void *data, struct wl_pointer *pointer,
|
|
static void pointer_handle_motion(void *data, struct wl_pointer *pointer,
|
|
uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
|
|
uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = data;
|
|
|
|
- SDL_WindowData *window_data = input->pointer_focus;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = data;
|
|
|
|
+ SDL_WindowData *window_data = seat->pointer.focus;
|
|
SDL_Window *window = window_data ? window_data->sdlwindow : NULL;
|
|
SDL_Window *window = window_data ? window_data->sdlwindow : NULL;
|
|
|
|
|
|
- input->sx_w = sx_w;
|
|
|
|
- input->sy_w = sy_w;
|
|
|
|
- if (input->pointer_focus) {
|
|
|
|
|
|
+ if (window_data) {
|
|
const float sx = (float)(wl_fixed_to_double(sx_w) * window_data->pointer_scale.x);
|
|
const float sx = (float)(wl_fixed_to_double(sx_w) * window_data->pointer_scale.x);
|
|
const float sy = (float)(wl_fixed_to_double(sy_w) * window_data->pointer_scale.y);
|
|
const float sy = (float)(wl_fixed_to_double(sy_w) * window_data->pointer_scale.y);
|
|
- SDL_SendMouseMotion(Wayland_GetPointerTimestamp(input, time), window_data->sdlwindow, input->pointer_id, false, sx, sy);
|
|
|
|
- }
|
|
|
|
|
|
+ SDL_SendMouseMotion(Wayland_GetPointerTimestamp(seat, time), window_data->sdlwindow, seat->pointer.sdl_id, false, sx, sy);
|
|
|
|
|
|
- if (window && window->hit_test) {
|
|
|
|
- const SDL_Point point = { (int)SDL_floor(wl_fixed_to_double(sx_w) * window_data->pointer_scale.x),
|
|
|
|
- (int)SDL_floor(wl_fixed_to_double(sy_w) * window_data->pointer_scale.y) };
|
|
|
|
- SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
|
|
|
|
- if (rc == window_data->hit_test_result) {
|
|
|
|
- return;
|
|
|
|
|
|
+ seat->pointer.last_motion.x = (int)SDL_floorf(sx);
|
|
|
|
+ seat->pointer.last_motion.y = (int)SDL_floorf(sy);
|
|
|
|
+
|
|
|
|
+ /* Pointer confinement regions are created only when the pointer actually enters the region via
|
|
|
|
+ * a motion event received from the compositor.
|
|
|
|
+ */
|
|
|
|
+ if (!SDL_RectEmpty(&window->mouse_rect) && !seat->pointer.confined_pointer) {
|
|
|
|
+ SDL_Rect scaled_mouse_rect;
|
|
|
|
+ Wayland_GetScaledMouseRect(window, &scaled_mouse_rect);
|
|
|
|
+
|
|
|
|
+ if (SDL_PointInRect(&seat->pointer.last_motion, &scaled_mouse_rect)) {
|
|
|
|
+ Wayland_SeatUpdatePointerGrab(seat);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- Wayland_SetHitTestCursor(rc);
|
|
|
|
- window_data->hit_test_result = rc;
|
|
|
|
|
|
+ if (window->hit_test) {
|
|
|
|
+ SDL_HitTestResult rc = window->hit_test(window, &seat->pointer.last_motion, window->hit_test_data);
|
|
|
|
+ if (rc != window_data->hit_test_result) {
|
|
|
|
+ window_data->hit_test_result = rc;
|
|
|
|
+ Wayland_SeatUpdateCursor(seat);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -548,79 +611,93 @@ static void pointer_handle_enter(void *data, struct wl_pointer *pointer,
|
|
uint32_t serial, struct wl_surface *surface,
|
|
uint32_t serial, struct wl_surface *surface,
|
|
wl_fixed_t sx_w, wl_fixed_t sy_w)
|
|
wl_fixed_t sx_w, wl_fixed_t sy_w)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = data;
|
|
|
|
- SDL_WindowData *window;
|
|
|
|
-
|
|
|
|
if (!surface) {
|
|
if (!surface) {
|
|
- // enter event for a window we've just destroyed
|
|
|
|
|
|
+ // Enter event for a destroyed surface.
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- /* This handler will be called twice in Wayland 1.4
|
|
|
|
- * Once for the window surface which has valid user data
|
|
|
|
- * and again for the mouse cursor surface which does not have valid user data
|
|
|
|
- * We ignore the later
|
|
|
|
|
|
+ SDL_WindowData *window = Wayland_GetWindowDataForOwnedSurface(surface);
|
|
|
|
+ if (!window) {
|
|
|
|
+ // Not a surface owned by SDL.
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ SDL_WaylandSeat *seat = (SDL_WaylandSeat *)data;
|
|
|
|
+ seat->pointer.focus = window;
|
|
|
|
+ seat->pointer.enter_serial = serial;
|
|
|
|
+ ++window->pointer_focus_count;
|
|
|
|
+ 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.
|
|
|
|
+ *
|
|
|
|
+ * FIXME: This causes a movement event with an anomalous timestamp when
|
|
|
|
+ * the cursor enters the window.
|
|
*/
|
|
*/
|
|
- window = Wayland_GetWindowDataForOwnedSurface(surface);
|
|
|
|
|
|
+ pointer_handle_motion(data, pointer, 0, sx_w, sy_w);
|
|
|
|
|
|
- if (window) {
|
|
|
|
- input->pointer_focus = window;
|
|
|
|
- input->pointer_enter_serial = serial;
|
|
|
|
- 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.
|
|
|
|
- *
|
|
|
|
- * FIXME: This causes a movement event with an anomalous timestamp when
|
|
|
|
- * the cursor enters the window.
|
|
|
|
- */
|
|
|
|
- pointer_handle_motion(data, pointer, 0, sx_w, sy_w);
|
|
|
|
- /* If the cursor was changed while our window didn't have pointer
|
|
|
|
- * focus, we might need to trigger another call to
|
|
|
|
- * wl_pointer_set_cursor() for the new cursor to be displayed. */
|
|
|
|
- Wayland_SetHitTestCursor(window->hit_test_result);
|
|
|
|
- }
|
|
|
|
|
|
+ // Update the pointer grab state.
|
|
|
|
+ Wayland_SeatUpdatePointerGrab(seat);
|
|
|
|
+
|
|
|
|
+ /* If the cursor was changed while our window didn't have pointer
|
|
|
|
+ * focus, we might need to trigger another call to
|
|
|
|
+ * wl_pointer_set_cursor() for the new cursor to be displayed.
|
|
|
|
+ *
|
|
|
|
+ * This will also update the cursor if a second pointer entered a
|
|
|
|
+ * window that already has focus, as the focus change sequence
|
|
|
|
+ * won't be run.
|
|
|
|
+ */
|
|
|
|
+ Wayland_SeatUpdateCursor(seat);
|
|
}
|
|
}
|
|
|
|
|
|
static void pointer_handle_leave(void *data, struct wl_pointer *pointer,
|
|
static void pointer_handle_leave(void *data, struct wl_pointer *pointer,
|
|
uint32_t serial, struct wl_surface *surface)
|
|
uint32_t serial, struct wl_surface *surface)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = data;
|
|
|
|
-
|
|
|
|
if (!surface) {
|
|
if (!surface) {
|
|
|
|
+ // Leave event for a destroyed surface.
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- if (input->pointer_focus) {
|
|
|
|
- SDL_WindowData *wind = Wayland_GetWindowDataForOwnedSurface(surface);
|
|
|
|
|
|
+ SDL_WindowData *window = Wayland_GetWindowDataForOwnedSurface(surface);
|
|
|
|
+ if (!window) {
|
|
|
|
+ // Not a surface owned by SDL.
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- if (wind) {
|
|
|
|
- // Clear the capture flag and raise all buttons
|
|
|
|
- wind->sdlwindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
|
|
|
|
|
|
+ // Clear the capture flag and raise all buttons
|
|
|
|
+ window->sdlwindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
|
|
|
|
|
|
- input->buttons_pressed = 0;
|
|
|
|
- SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, 0), wind->sdlwindow, input->pointer_id, SDL_BUTTON_LEFT, false);
|
|
|
|
- SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, 0), wind->sdlwindow, input->pointer_id, SDL_BUTTON_RIGHT, false);
|
|
|
|
- SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, 0), wind->sdlwindow, input->pointer_id, SDL_BUTTON_MIDDLE, false);
|
|
|
|
- SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, 0), wind->sdlwindow, input->pointer_id, SDL_BUTTON_X1, false);
|
|
|
|
- SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, 0), wind->sdlwindow, input->pointer_id, SDL_BUTTON_X2, false);
|
|
|
|
- }
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = (SDL_WaylandSeat *)data;
|
|
|
|
+ seat->pointer.focus = NULL;
|
|
|
|
+ seat->pointer.buttons_pressed = 0;
|
|
|
|
+ SDL_SendMouseButton(Wayland_GetPointerTimestamp(seat, 0), window->sdlwindow, seat->pointer.sdl_id, SDL_BUTTON_LEFT, false);
|
|
|
|
+ SDL_SendMouseButton(Wayland_GetPointerTimestamp(seat, 0), window->sdlwindow, seat->pointer.sdl_id, SDL_BUTTON_RIGHT, false);
|
|
|
|
+ SDL_SendMouseButton(Wayland_GetPointerTimestamp(seat, 0), window->sdlwindow, seat->pointer.sdl_id, SDL_BUTTON_MIDDLE, false);
|
|
|
|
+ SDL_SendMouseButton(Wayland_GetPointerTimestamp(seat, 0), window->sdlwindow, seat->pointer.sdl_id, SDL_BUTTON_X1, false);
|
|
|
|
+ SDL_SendMouseButton(Wayland_GetPointerTimestamp(seat, 0), window->sdlwindow, seat->pointer.sdl_id, SDL_BUTTON_X2, false);
|
|
|
|
|
|
- /* A pointer leave event may be emitted if the compositor hides the pointer in response to receiving a touch event.
|
|
|
|
- * Don't relinquish focus if the surface has active touches, as the compositor is just transitioning from mouse to touch mode.
|
|
|
|
- */
|
|
|
|
- if (!Wayland_SurfaceHasActiveTouches(surface)) {
|
|
|
|
- SDL_SetMouseFocus(NULL);
|
|
|
|
- }
|
|
|
|
- input->pointer_focus = NULL;
|
|
|
|
|
|
+ /* A pointer leave event may be emitted if the compositor hides the pointer in response to receiving a touch event.
|
|
|
|
+ * Don't relinquish focus if the surface has active touches, as the compositor is just transitioning from mouse to touch mode.
|
|
|
|
+ */
|
|
|
|
+ SDL_Window *mouse_focus = SDL_GetMouseFocus();
|
|
|
|
+ const bool had_focus = mouse_focus && window->sdlwindow == mouse_focus;
|
|
|
|
+ if (!--window->pointer_focus_count && had_focus && !Wayland_SurfaceHasActiveTouches(seat->display, surface)) {
|
|
|
|
+ SDL_SetMouseFocus(NULL);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ Wayland_SeatUpdatePointerGrab(seat);
|
|
|
|
+ Wayland_SeatUpdateCursor(seat);
|
|
}
|
|
}
|
|
|
|
|
|
-static bool ProcessHitTest(SDL_WindowData *window_data,
|
|
|
|
- struct wl_seat *seat,
|
|
|
|
- wl_fixed_t sx_w, wl_fixed_t sy_w,
|
|
|
|
- uint32_t serial)
|
|
|
|
|
|
+static bool Wayland_ProcessHitTest(SDL_WaylandSeat *seat, Uint32 serial)
|
|
{
|
|
{
|
|
|
|
+ // Locked in relative mode, do nothing.
|
|
|
|
+ if (seat->pointer.locked_pointer) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ SDL_WindowData *window_data = seat->pointer.focus;
|
|
SDL_Window *window = window_data->sdlwindow;
|
|
SDL_Window *window = window_data->sdlwindow;
|
|
|
|
|
|
if (window->hit_test) {
|
|
if (window->hit_test) {
|
|
@@ -646,7 +723,7 @@ static bool ProcessHitTest(SDL_WindowData *window_data,
|
|
if (window_data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) {
|
|
if (window_data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) {
|
|
if (window_data->shell_surface.libdecor.frame) {
|
|
if (window_data->shell_surface.libdecor.frame) {
|
|
libdecor_frame_move(window_data->shell_surface.libdecor.frame,
|
|
libdecor_frame_move(window_data->shell_surface.libdecor.frame,
|
|
- seat,
|
|
|
|
|
|
+ seat->wl_seat,
|
|
serial);
|
|
serial);
|
|
}
|
|
}
|
|
} else
|
|
} else
|
|
@@ -654,7 +731,7 @@ static bool ProcessHitTest(SDL_WindowData *window_data,
|
|
if (window_data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL) {
|
|
if (window_data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL) {
|
|
if (window_data->shell_surface.xdg.toplevel.xdg_toplevel) {
|
|
if (window_data->shell_surface.xdg.toplevel.xdg_toplevel) {
|
|
xdg_toplevel_move(window_data->shell_surface.xdg.toplevel.xdg_toplevel,
|
|
xdg_toplevel_move(window_data->shell_surface.xdg.toplevel.xdg_toplevel,
|
|
- seat,
|
|
|
|
|
|
+ seat->wl_seat,
|
|
serial);
|
|
serial);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -672,7 +749,7 @@ static bool ProcessHitTest(SDL_WindowData *window_data,
|
|
if (window_data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) {
|
|
if (window_data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) {
|
|
if (window_data->shell_surface.libdecor.frame) {
|
|
if (window_data->shell_surface.libdecor.frame) {
|
|
libdecor_frame_resize(window_data->shell_surface.libdecor.frame,
|
|
libdecor_frame_resize(window_data->shell_surface.libdecor.frame,
|
|
- seat,
|
|
|
|
|
|
+ seat->wl_seat,
|
|
serial,
|
|
serial,
|
|
directions_libdecor[window_data->hit_test_result - SDL_HITTEST_RESIZE_TOPLEFT]);
|
|
directions_libdecor[window_data->hit_test_result - SDL_HITTEST_RESIZE_TOPLEFT]);
|
|
}
|
|
}
|
|
@@ -681,7 +758,7 @@ static bool ProcessHitTest(SDL_WindowData *window_data,
|
|
if (window_data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL) {
|
|
if (window_data->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL) {
|
|
if (window_data->shell_surface.xdg.toplevel.xdg_toplevel) {
|
|
if (window_data->shell_surface.xdg.toplevel.xdg_toplevel) {
|
|
xdg_toplevel_resize(window_data->shell_surface.xdg.toplevel.xdg_toplevel,
|
|
xdg_toplevel_resize(window_data->shell_surface.xdg.toplevel.xdg_toplevel,
|
|
- seat,
|
|
|
|
|
|
+ seat->wl_seat,
|
|
serial,
|
|
serial,
|
|
directions[window_data->hit_test_result - SDL_HITTEST_RESIZE_TOPLEFT]);
|
|
directions[window_data->hit_test_result - SDL_HITTEST_RESIZE_TOPLEFT]);
|
|
}
|
|
}
|
|
@@ -696,12 +773,12 @@ static bool ProcessHitTest(SDL_WindowData *window_data,
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
-static void pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial,
|
|
|
|
|
|
+static void pointer_handle_button_common(SDL_WaylandSeat *seat, uint32_t serial,
|
|
uint32_t time, uint32_t button, uint32_t state_w)
|
|
uint32_t time, uint32_t button, uint32_t state_w)
|
|
{
|
|
{
|
|
- SDL_WindowData *window = input->pointer_focus;
|
|
|
|
|
|
+ SDL_WindowData *window = seat->pointer.focus;
|
|
enum wl_pointer_button_state state = state_w;
|
|
enum wl_pointer_button_state state = state_w;
|
|
- Uint64 timestamp = Wayland_GetPointerTimestamp(input, time);
|
|
|
|
|
|
+ Uint64 timestamp = Wayland_GetPointerTimestamp(seat, time);
|
|
Uint8 sdl_button;
|
|
Uint8 sdl_button;
|
|
const bool down = (state != 0);
|
|
const bool down = (state != 0);
|
|
|
|
|
|
@@ -726,18 +803,16 @@ static void pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_
|
|
}
|
|
}
|
|
|
|
|
|
if (window) {
|
|
if (window) {
|
|
- SDL_VideoData *viddata = window->waylandData;
|
|
|
|
bool ignore_click = false;
|
|
bool ignore_click = false;
|
|
|
|
|
|
if (state) {
|
|
if (state) {
|
|
- Wayland_UpdateImplicitGrabSerial(input, serial);
|
|
|
|
- input->buttons_pressed |= SDL_BUTTON_MASK(sdl_button);
|
|
|
|
|
|
+ Wayland_UpdateImplicitGrabSerial(seat, serial);
|
|
|
|
+ seat->pointer.buttons_pressed |= SDL_BUTTON_MASK(sdl_button);
|
|
} else {
|
|
} else {
|
|
- input->buttons_pressed &= ~(SDL_BUTTON_MASK(sdl_button));
|
|
|
|
|
|
+ seat->pointer.buttons_pressed &= ~(SDL_BUTTON_MASK(sdl_button));
|
|
}
|
|
}
|
|
|
|
|
|
- if (sdl_button == SDL_BUTTON_LEFT &&
|
|
|
|
- ProcessHitTest(input->pointer_focus, input->seat, input->sx_w, input->sy_w, serial)) {
|
|
|
|
|
|
+ if (sdl_button == SDL_BUTTON_LEFT && Wayland_ProcessHitTest(seat, serial)) {
|
|
return; // don't pass this event on to app.
|
|
return; // don't pass this event on to app.
|
|
}
|
|
}
|
|
|
|
|
|
@@ -758,8 +833,8 @@ static void pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_
|
|
*
|
|
*
|
|
* The mouse is not captured in relative mode.
|
|
* The mouse is not captured in relative mode.
|
|
*/
|
|
*/
|
|
- if (!viddata->relative_mouse_mode) {
|
|
|
|
- if (input->buttons_pressed != 0) {
|
|
|
|
|
|
+ if (!seat->display->relative_mode_enabled || !Wayland_SeatHasRelativePointerFocus(seat)) {
|
|
|
|
+ if (seat->pointer.buttons_pressed != 0) {
|
|
window->sdlwindow->flags |= SDL_WINDOW_MOUSE_CAPTURE;
|
|
window->sdlwindow->flags |= SDL_WINDOW_MOUSE_CAPTURE;
|
|
} else {
|
|
} else {
|
|
window->sdlwindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
|
|
window->sdlwindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE;
|
|
@@ -767,7 +842,7 @@ static void pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_
|
|
}
|
|
}
|
|
|
|
|
|
if (!ignore_click) {
|
|
if (!ignore_click) {
|
|
- SDL_SendMouseButton(timestamp, window->sdlwindow, input->pointer_id, sdl_button, down);
|
|
|
|
|
|
+ SDL_SendMouseButton(timestamp, window->sdlwindow, seat->pointer.sdl_id, sdl_button, down);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -775,19 +850,19 @@ static void pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_
|
|
static void pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
|
|
static void pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,
|
|
uint32_t time, uint32_t button, uint32_t state_w)
|
|
uint32_t time, uint32_t button, uint32_t state_w)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = data;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = data;
|
|
|
|
|
|
- pointer_handle_button_common(input, serial, time, button, state_w);
|
|
|
|
|
|
+ pointer_handle_button_common(seat, serial, time, button, state_w);
|
|
}
|
|
}
|
|
|
|
|
|
-static void pointer_handle_axis_common_v1(struct SDL_WaylandInput *input,
|
|
|
|
|
|
+static void pointer_handle_axis_common_v1(SDL_WaylandSeat *seat,
|
|
uint32_t time, uint32_t axis, wl_fixed_t value)
|
|
uint32_t time, uint32_t axis, wl_fixed_t value)
|
|
{
|
|
{
|
|
- SDL_WindowData *window = input->pointer_focus;
|
|
|
|
- const Uint64 timestamp = Wayland_GetPointerTimestamp(input, time);
|
|
|
|
|
|
+ SDL_WindowData *window = seat->pointer.focus;
|
|
|
|
+ const Uint64 timestamp = Wayland_GetPointerTimestamp(seat, time);
|
|
const enum wl_pointer_axis a = axis;
|
|
const enum wl_pointer_axis a = axis;
|
|
|
|
|
|
- if (input->pointer_focus) {
|
|
|
|
|
|
+ if (seat->pointer.focus) {
|
|
float x, y;
|
|
float x, y;
|
|
|
|
|
|
switch (a) {
|
|
switch (a) {
|
|
@@ -806,16 +881,16 @@ static void pointer_handle_axis_common_v1(struct SDL_WaylandInput *input,
|
|
x /= WAYLAND_WHEEL_AXIS_UNIT;
|
|
x /= WAYLAND_WHEEL_AXIS_UNIT;
|
|
y /= WAYLAND_WHEEL_AXIS_UNIT;
|
|
y /= WAYLAND_WHEEL_AXIS_UNIT;
|
|
|
|
|
|
- SDL_SendMouseWheel(timestamp, window->sdlwindow, input->pointer_id, x, y, SDL_MOUSEWHEEL_NORMAL);
|
|
|
|
|
|
+ SDL_SendMouseWheel(timestamp, window->sdlwindow, seat->pointer.sdl_id, x, y, SDL_MOUSEWHEEL_NORMAL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static void pointer_handle_axis_common(struct SDL_WaylandInput *input, enum SDL_WaylandAxisEvent type,
|
|
|
|
|
|
+static void pointer_handle_axis_common(SDL_WaylandSeat *seat, enum SDL_WaylandAxisEvent type,
|
|
uint32_t axis, wl_fixed_t value)
|
|
uint32_t axis, wl_fixed_t value)
|
|
{
|
|
{
|
|
const enum wl_pointer_axis a = axis;
|
|
const enum wl_pointer_axis a = axis;
|
|
|
|
|
|
- if (input->pointer_focus) {
|
|
|
|
|
|
+ if (seat->pointer.focus) {
|
|
switch (a) {
|
|
switch (a) {
|
|
case WL_POINTER_AXIS_VERTICAL_SCROLL:
|
|
case WL_POINTER_AXIS_VERTICAL_SCROLL:
|
|
switch (type) {
|
|
switch (type) {
|
|
@@ -824,26 +899,26 @@ static void pointer_handle_axis_common(struct SDL_WaylandInput *input, enum SDL_
|
|
* High resolution scroll event. The spec doesn't state that axis_value120
|
|
* High resolution scroll event. The spec doesn't state that axis_value120
|
|
* events are limited to one per frame, so the values are accumulated.
|
|
* events are limited to one per frame, so the values are accumulated.
|
|
*/
|
|
*/
|
|
- if (input->pointer_curr_axis_info.y_axis_type != AXIS_EVENT_VALUE120) {
|
|
|
|
- input->pointer_curr_axis_info.y_axis_type = AXIS_EVENT_VALUE120;
|
|
|
|
- input->pointer_curr_axis_info.y = 0.0f;
|
|
|
|
|
|
+ if (seat->pointer.current_axis_info.y_axis_type != AXIS_EVENT_VALUE120) {
|
|
|
|
+ seat->pointer.current_axis_info.y_axis_type = AXIS_EVENT_VALUE120;
|
|
|
|
+ seat->pointer.current_axis_info.y = 0.0f;
|
|
}
|
|
}
|
|
- input->pointer_curr_axis_info.y += 0 - (float)wl_fixed_to_double(value);
|
|
|
|
|
|
+ seat->pointer.current_axis_info.y += 0 - (float)wl_fixed_to_double(value);
|
|
break;
|
|
break;
|
|
case AXIS_EVENT_DISCRETE:
|
|
case AXIS_EVENT_DISCRETE:
|
|
/*
|
|
/*
|
|
* This is a discrete axis event, so we process it and set the
|
|
* This is a discrete axis event, so we process it and set the
|
|
* flag to ignore future continuous axis events in this frame.
|
|
* flag to ignore future continuous axis events in this frame.
|
|
*/
|
|
*/
|
|
- if (input->pointer_curr_axis_info.y_axis_type != AXIS_EVENT_DISCRETE) {
|
|
|
|
- input->pointer_curr_axis_info.y_axis_type = AXIS_EVENT_DISCRETE;
|
|
|
|
- input->pointer_curr_axis_info.y = 0 - (float)wl_fixed_to_double(value);
|
|
|
|
|
|
+ if (seat->pointer.current_axis_info.y_axis_type != AXIS_EVENT_DISCRETE) {
|
|
|
|
+ seat->pointer.current_axis_info.y_axis_type = AXIS_EVENT_DISCRETE;
|
|
|
|
+ seat->pointer.current_axis_info.y = 0 - (float)wl_fixed_to_double(value);
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
case AXIS_EVENT_CONTINUOUS:
|
|
case AXIS_EVENT_CONTINUOUS:
|
|
// Only process continuous events if no discrete events have been received.
|
|
// Only process continuous events if no discrete events have been received.
|
|
- if (input->pointer_curr_axis_info.y_axis_type == AXIS_EVENT_CONTINUOUS) {
|
|
|
|
- input->pointer_curr_axis_info.y = 0 - (float)wl_fixed_to_double(value);
|
|
|
|
|
|
+ if (seat->pointer.current_axis_info.y_axis_type == AXIS_EVENT_CONTINUOUS) {
|
|
|
|
+ seat->pointer.current_axis_info.y = 0 - (float)wl_fixed_to_double(value);
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -855,26 +930,26 @@ static void pointer_handle_axis_common(struct SDL_WaylandInput *input, enum SDL_
|
|
* High resolution scroll event. The spec doesn't state that axis_value120
|
|
* High resolution scroll event. The spec doesn't state that axis_value120
|
|
* events are limited to one per frame, so the values are accumulated.
|
|
* events are limited to one per frame, so the values are accumulated.
|
|
*/
|
|
*/
|
|
- if (input->pointer_curr_axis_info.x_axis_type != AXIS_EVENT_VALUE120) {
|
|
|
|
- input->pointer_curr_axis_info.x_axis_type = AXIS_EVENT_VALUE120;
|
|
|
|
- input->pointer_curr_axis_info.x = 0.0f;
|
|
|
|
|
|
+ if (seat->pointer.current_axis_info.x_axis_type != AXIS_EVENT_VALUE120) {
|
|
|
|
+ seat->pointer.current_axis_info.x_axis_type = AXIS_EVENT_VALUE120;
|
|
|
|
+ seat->pointer.current_axis_info.x = 0.0f;
|
|
}
|
|
}
|
|
- input->pointer_curr_axis_info.x += (float)wl_fixed_to_double(value);
|
|
|
|
|
|
+ seat->pointer.current_axis_info.x += (float)wl_fixed_to_double(value);
|
|
break;
|
|
break;
|
|
case AXIS_EVENT_DISCRETE:
|
|
case AXIS_EVENT_DISCRETE:
|
|
/*
|
|
/*
|
|
* This is a discrete axis event, so we process it and set the
|
|
* This is a discrete axis event, so we process it and set the
|
|
* flag to ignore future continuous axis events in this frame.
|
|
* flag to ignore future continuous axis events in this frame.
|
|
*/
|
|
*/
|
|
- if (input->pointer_curr_axis_info.x_axis_type != AXIS_EVENT_DISCRETE) {
|
|
|
|
- input->pointer_curr_axis_info.x_axis_type = AXIS_EVENT_DISCRETE;
|
|
|
|
- input->pointer_curr_axis_info.x = (float)wl_fixed_to_double(value);
|
|
|
|
|
|
+ if (seat->pointer.current_axis_info.x_axis_type != AXIS_EVENT_DISCRETE) {
|
|
|
|
+ seat->pointer.current_axis_info.x_axis_type = AXIS_EVENT_DISCRETE;
|
|
|
|
+ seat->pointer.current_axis_info.x = (float)wl_fixed_to_double(value);
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
case AXIS_EVENT_CONTINUOUS:
|
|
case AXIS_EVENT_CONTINUOUS:
|
|
// Only process continuous events if no discrete events have been received.
|
|
// Only process continuous events if no discrete events have been received.
|
|
- if (input->pointer_curr_axis_info.x_axis_type == AXIS_EVENT_CONTINUOUS) {
|
|
|
|
- input->pointer_curr_axis_info.x = (float)wl_fixed_to_double(value);
|
|
|
|
|
|
+ if (seat->pointer.current_axis_info.x_axis_type == AXIS_EVENT_CONTINUOUS) {
|
|
|
|
+ seat->pointer.current_axis_info.x = (float)wl_fixed_to_double(value);
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -886,76 +961,76 @@ static void pointer_handle_axis_common(struct SDL_WaylandInput *input, enum SDL_
|
|
static void pointer_handle_axis(void *data, struct wl_pointer *pointer,
|
|
static void pointer_handle_axis(void *data, struct wl_pointer *pointer,
|
|
uint32_t time, uint32_t axis, wl_fixed_t value)
|
|
uint32_t time, uint32_t axis, wl_fixed_t value)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = data;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = data;
|
|
|
|
|
|
- if (wl_seat_get_version(input->seat) >= WL_POINTER_FRAME_SINCE_VERSION) {
|
|
|
|
- input->pointer_curr_axis_info.timestamp_ns = Wayland_GetPointerTimestamp(input, time);
|
|
|
|
- pointer_handle_axis_common(input, AXIS_EVENT_CONTINUOUS, axis, value);
|
|
|
|
|
|
+ if (wl_seat_get_version(seat->wl_seat) >= WL_POINTER_FRAME_SINCE_VERSION) {
|
|
|
|
+ seat->pointer.current_axis_info.timestamp_ns = Wayland_GetPointerTimestamp(seat, time);
|
|
|
|
+ pointer_handle_axis_common(seat, AXIS_EVENT_CONTINUOUS, axis, value);
|
|
} else {
|
|
} else {
|
|
- pointer_handle_axis_common_v1(input, time, axis, value);
|
|
|
|
|
|
+ pointer_handle_axis_common_v1(seat, time, axis, value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void pointer_handle_axis_relative_direction(void *data, struct wl_pointer *pointer,
|
|
static void pointer_handle_axis_relative_direction(void *data, struct wl_pointer *pointer,
|
|
uint32_t axis, uint32_t axis_relative_direction)
|
|
uint32_t axis, uint32_t axis_relative_direction)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = data;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = data;
|
|
if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL) {
|
|
if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
switch (axis_relative_direction) {
|
|
switch (axis_relative_direction) {
|
|
case WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL:
|
|
case WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL:
|
|
- input->pointer_curr_axis_info.direction = SDL_MOUSEWHEEL_NORMAL;
|
|
|
|
|
|
+ seat->pointer.current_axis_info.direction = SDL_MOUSEWHEEL_NORMAL;
|
|
break;
|
|
break;
|
|
case WL_POINTER_AXIS_RELATIVE_DIRECTION_INVERTED:
|
|
case WL_POINTER_AXIS_RELATIVE_DIRECTION_INVERTED:
|
|
- input->pointer_curr_axis_info.direction = SDL_MOUSEWHEEL_FLIPPED;
|
|
|
|
|
|
+ seat->pointer.current_axis_info.direction = SDL_MOUSEWHEEL_FLIPPED;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void pointer_handle_frame(void *data, struct wl_pointer *pointer)
|
|
static void pointer_handle_frame(void *data, struct wl_pointer *pointer)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = data;
|
|
|
|
- SDL_WindowData *window = input->pointer_focus;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = data;
|
|
|
|
+ SDL_WindowData *window = seat->pointer.focus;
|
|
float x, y;
|
|
float x, y;
|
|
- SDL_MouseWheelDirection direction = input->pointer_curr_axis_info.direction;
|
|
|
|
|
|
+ SDL_MouseWheelDirection direction = seat->pointer.current_axis_info.direction;
|
|
|
|
|
|
- switch (input->pointer_curr_axis_info.x_axis_type) {
|
|
|
|
|
|
+ switch (seat->pointer.current_axis_info.x_axis_type) {
|
|
case AXIS_EVENT_CONTINUOUS:
|
|
case AXIS_EVENT_CONTINUOUS:
|
|
- x = input->pointer_curr_axis_info.x / WAYLAND_WHEEL_AXIS_UNIT;
|
|
|
|
|
|
+ x = seat->pointer.current_axis_info.x / WAYLAND_WHEEL_AXIS_UNIT;
|
|
break;
|
|
break;
|
|
case AXIS_EVENT_DISCRETE:
|
|
case AXIS_EVENT_DISCRETE:
|
|
- x = input->pointer_curr_axis_info.x;
|
|
|
|
|
|
+ x = seat->pointer.current_axis_info.x;
|
|
break;
|
|
break;
|
|
case AXIS_EVENT_VALUE120:
|
|
case AXIS_EVENT_VALUE120:
|
|
- x = input->pointer_curr_axis_info.x / 120.0f;
|
|
|
|
|
|
+ x = seat->pointer.current_axis_info.x / 120.0f;
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
x = 0.0f;
|
|
x = 0.0f;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
- switch (input->pointer_curr_axis_info.y_axis_type) {
|
|
|
|
|
|
+ switch (seat->pointer.current_axis_info.y_axis_type) {
|
|
case AXIS_EVENT_CONTINUOUS:
|
|
case AXIS_EVENT_CONTINUOUS:
|
|
- y = input->pointer_curr_axis_info.y / WAYLAND_WHEEL_AXIS_UNIT;
|
|
|
|
|
|
+ y = seat->pointer.current_axis_info.y / WAYLAND_WHEEL_AXIS_UNIT;
|
|
break;
|
|
break;
|
|
case AXIS_EVENT_DISCRETE:
|
|
case AXIS_EVENT_DISCRETE:
|
|
- y = input->pointer_curr_axis_info.y;
|
|
|
|
|
|
+ y = seat->pointer.current_axis_info.y;
|
|
break;
|
|
break;
|
|
case AXIS_EVENT_VALUE120:
|
|
case AXIS_EVENT_VALUE120:
|
|
- y = input->pointer_curr_axis_info.y / 120.0f;
|
|
|
|
|
|
+ y = seat->pointer.current_axis_info.y / 120.0f;
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
y = 0.0f;
|
|
y = 0.0f;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
- // clear pointer_curr_axis_info for next frame
|
|
|
|
- SDL_memset(&input->pointer_curr_axis_info, 0, sizeof(input->pointer_curr_axis_info));
|
|
|
|
|
|
+ // clear pointer.current_axis_info for next frame
|
|
|
|
+ SDL_memset(&seat->pointer.current_axis_info, 0, sizeof(seat->pointer.current_axis_info));
|
|
|
|
|
|
if (x != 0.0f || y != 0.0f) {
|
|
if (x != 0.0f || y != 0.0f) {
|
|
- SDL_SendMouseWheel(input->pointer_curr_axis_info.timestamp_ns,
|
|
|
|
- window->sdlwindow, input->pointer_id, x, y, direction);
|
|
|
|
|
|
+ SDL_SendMouseWheel(seat->pointer.current_axis_info.timestamp_ns,
|
|
|
|
+ window->sdlwindow, seat->pointer.sdl_id, x, y, direction);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -974,17 +1049,17 @@ static void pointer_handle_axis_stop(void *data, struct wl_pointer *pointer,
|
|
static void pointer_handle_axis_discrete(void *data, struct wl_pointer *pointer,
|
|
static void pointer_handle_axis_discrete(void *data, struct wl_pointer *pointer,
|
|
uint32_t axis, int32_t discrete)
|
|
uint32_t axis, int32_t discrete)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = data;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = data;
|
|
|
|
|
|
- pointer_handle_axis_common(input, AXIS_EVENT_DISCRETE, axis, wl_fixed_from_int(discrete));
|
|
|
|
|
|
+ pointer_handle_axis_common(seat, AXIS_EVENT_DISCRETE, axis, wl_fixed_from_int(discrete));
|
|
}
|
|
}
|
|
|
|
|
|
static void pointer_handle_axis_value120(void *data, struct wl_pointer *pointer,
|
|
static void pointer_handle_axis_value120(void *data, struct wl_pointer *pointer,
|
|
uint32_t axis, int32_t value120)
|
|
uint32_t axis, int32_t value120)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = data;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = data;
|
|
|
|
|
|
- pointer_handle_axis_common(input, AXIS_EVENT_VALUE120, axis, wl_fixed_from_int(value120));
|
|
|
|
|
|
+ pointer_handle_axis_common(seat, AXIS_EVENT_VALUE120, axis, wl_fixed_from_int(value120));
|
|
}
|
|
}
|
|
|
|
|
|
static const struct wl_pointer_listener pointer_listener = {
|
|
static const struct wl_pointer_listener pointer_listener = {
|
|
@@ -1010,26 +1085,30 @@ static void relative_pointer_handle_relative_motion(void *data,
|
|
wl_fixed_t dx_unaccel_w,
|
|
wl_fixed_t dx_unaccel_w,
|
|
wl_fixed_t dy_unaccel_w)
|
|
wl_fixed_t dy_unaccel_w)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = data;
|
|
|
|
- SDL_VideoData *d = input->display;
|
|
|
|
- SDL_WindowData *window = input->pointer_focus;
|
|
|
|
- SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = data;
|
|
|
|
|
|
- // Relative pointer event times are in microsecond granularity.
|
|
|
|
- const Uint64 timestamp = Wayland_GetEventTimestamp(SDL_US_TO_NS(((Uint64)time_hi << 32) | (Uint64)time_lo));
|
|
|
|
|
|
+ if (seat->display->relative_mode_enabled) {
|
|
|
|
+ SDL_WindowData *window = seat->pointer.focus;
|
|
|
|
|
|
- if (input->pointer_focus && d->relative_mouse_mode) {
|
|
|
|
- double dx;
|
|
|
|
- double dy;
|
|
|
|
- if (mouse->InputTransform || !mouse->enable_relative_system_scale) {
|
|
|
|
- dx = wl_fixed_to_double(dx_unaccel_w);
|
|
|
|
- dy = wl_fixed_to_double(dy_unaccel_w);
|
|
|
|
- } else {
|
|
|
|
- dx = wl_fixed_to_double(dx_w) * window->pointer_scale.x;
|
|
|
|
- dy = wl_fixed_to_double(dy_w) * window->pointer_scale.y;
|
|
|
|
- }
|
|
|
|
|
|
+ // Relative motion follows keyboard focus.
|
|
|
|
+ if (Wayland_SeatHasRelativePointerFocus(seat)) {
|
|
|
|
+ SDL_Mouse *mouse = SDL_GetMouse();
|
|
|
|
+
|
|
|
|
+ // Relative pointer event times are in microsecond granularity.
|
|
|
|
+ const Uint64 timestamp = Wayland_GetEventTimestamp(SDL_US_TO_NS(((Uint64)time_hi << 32) | (Uint64)time_lo));
|
|
|
|
|
|
- SDL_SendMouseMotion(timestamp, window->sdlwindow, input->pointer_id, true, (float)dx, (float)dy);
|
|
|
|
|
|
+ double dx;
|
|
|
|
+ double dy;
|
|
|
|
+ if (mouse->InputTransform || !mouse->enable_relative_system_scale) {
|
|
|
|
+ dx = wl_fixed_to_double(dx_unaccel_w);
|
|
|
|
+ dy = wl_fixed_to_double(dy_unaccel_w);
|
|
|
|
+ } else {
|
|
|
|
+ dx = wl_fixed_to_double(dx_w) * window->pointer_scale.x;
|
|
|
|
+ dy = wl_fixed_to_double(dy_w) * window->pointer_scale.y;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ SDL_SendMouseMotion(timestamp, window->sdlwindow, seat->pointer.sdl_id, true, (float)dx, (float)dy);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1052,58 +1131,6 @@ static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = {
|
|
locked_pointer_unlocked,
|
|
locked_pointer_unlocked,
|
|
};
|
|
};
|
|
|
|
|
|
-bool Wayland_input_lock_pointer(struct SDL_WaylandInput *input, SDL_Window *window)
|
|
|
|
-{
|
|
|
|
- SDL_WindowData *w = window->internal;
|
|
|
|
- SDL_VideoData *d = input->display;
|
|
|
|
-
|
|
|
|
- if (!d->pointer_constraints || !input->pointer) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (!w->locked_pointer) {
|
|
|
|
- if (w->confined_pointer) {
|
|
|
|
- // If the pointer is already confined to the surface, the lock will fail with a protocol error.
|
|
|
|
- Wayland_input_unconfine_pointer(input, window);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- w->locked_pointer = zwp_pointer_constraints_v1_lock_pointer(d->pointer_constraints,
|
|
|
|
- w->surface,
|
|
|
|
- input->pointer,
|
|
|
|
- NULL,
|
|
|
|
- ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
|
|
|
|
- zwp_locked_pointer_v1_add_listener(w->locked_pointer,
|
|
|
|
- &locked_pointer_listener,
|
|
|
|
- window);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return true;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-bool Wayland_input_unlock_pointer(struct SDL_WaylandInput *input, SDL_Window *window)
|
|
|
|
-{
|
|
|
|
- SDL_WindowData *w = window->internal;
|
|
|
|
-
|
|
|
|
- if (w->locked_pointer) {
|
|
|
|
- zwp_locked_pointer_v1_destroy(w->locked_pointer);
|
|
|
|
- w->locked_pointer = NULL;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Restore existing pointer confinement.
|
|
|
|
- Wayland_input_confine_pointer(input, window);
|
|
|
|
-
|
|
|
|
- return true;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void pointer_confine_destroy(SDL_Window *window)
|
|
|
|
-{
|
|
|
|
- SDL_WindowData *w = window->internal;
|
|
|
|
- if (w->confined_pointer) {
|
|
|
|
- zwp_confined_pointer_v1_destroy(w->confined_pointer);
|
|
|
|
- w->confined_pointer = NULL;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static void confined_pointer_confined(void *data,
|
|
static void confined_pointer_confined(void *data,
|
|
struct zwp_confined_pointer_v1 *confined_pointer)
|
|
struct zwp_confined_pointer_v1 *confined_pointer)
|
|
{
|
|
{
|
|
@@ -1123,7 +1150,7 @@ static void touch_handler_down(void *data, struct wl_touch *touch, uint32_t seri
|
|
uint32_t timestamp, struct wl_surface *surface,
|
|
uint32_t timestamp, struct wl_surface *surface,
|
|
int id, wl_fixed_t fx, wl_fixed_t fy)
|
|
int id, wl_fixed_t fx, wl_fixed_t fy)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = (struct SDL_WaylandInput *)data;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = (SDL_WaylandSeat *)data;
|
|
SDL_WindowData *window_data;
|
|
SDL_WindowData *window_data;
|
|
|
|
|
|
// Check that this surface is valid.
|
|
// Check that this surface is valid.
|
|
@@ -1131,8 +1158,8 @@ static void touch_handler_down(void *data, struct wl_touch *touch, uint32_t seri
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- touch_add(id, fx, fy, surface);
|
|
|
|
- Wayland_UpdateImplicitGrabSerial(input, serial);
|
|
|
|
|
|
+ Wayland_SeatAddTouch(seat, id, fx, fy, surface);
|
|
|
|
+ Wayland_UpdateImplicitGrabSerial(seat, serial);
|
|
window_data = Wayland_GetWindowDataForOwnedSurface(surface);
|
|
window_data = Wayland_GetWindowDataForOwnedSurface(surface);
|
|
|
|
|
|
if (window_data) {
|
|
if (window_data) {
|
|
@@ -1151,7 +1178,7 @@ static void touch_handler_down(void *data, struct wl_touch *touch, uint32_t seri
|
|
|
|
|
|
SDL_SetMouseFocus(window_data->sdlwindow);
|
|
SDL_SetMouseFocus(window_data->sdlwindow);
|
|
|
|
|
|
- SDL_SendTouch(Wayland_GetTouchTimestamp(input, timestamp), (SDL_TouchID)(uintptr_t)touch,
|
|
|
|
|
|
+ SDL_SendTouch(Wayland_GetTouchTimestamp(seat, timestamp), (SDL_TouchID)(uintptr_t)touch,
|
|
(SDL_FingerID)(id + 1), window_data->sdlwindow, SDL_EVENT_FINGER_DOWN, x, y, 1.0f);
|
|
(SDL_FingerID)(id + 1), window_data->sdlwindow, SDL_EVENT_FINGER_DOWN, x, y, 1.0f);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1159,11 +1186,11 @@ static void touch_handler_down(void *data, struct wl_touch *touch, uint32_t seri
|
|
static void touch_handler_up(void *data, struct wl_touch *touch, uint32_t serial,
|
|
static void touch_handler_up(void *data, struct wl_touch *touch, uint32_t serial,
|
|
uint32_t timestamp, int id)
|
|
uint32_t timestamp, int id)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = (struct SDL_WaylandInput *)data;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = (SDL_WaylandSeat *)data;
|
|
wl_fixed_t fx = 0, fy = 0;
|
|
wl_fixed_t fx = 0, fy = 0;
|
|
struct wl_surface *surface = NULL;
|
|
struct wl_surface *surface = NULL;
|
|
|
|
|
|
- touch_del(id, &fx, &fy, &surface);
|
|
|
|
|
|
+ Wayland_SeatRemoveTouch(seat, id, &fx, &fy, &surface);
|
|
|
|
|
|
if (surface) {
|
|
if (surface) {
|
|
SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(surface);
|
|
SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(surface);
|
|
@@ -1172,14 +1199,14 @@ static void touch_handler_up(void *data, struct wl_touch *touch, uint32_t serial
|
|
const float x = (float)wl_fixed_to_double(fx) / window_data->current.logical_width;
|
|
const float x = (float)wl_fixed_to_double(fx) / window_data->current.logical_width;
|
|
const float y = (float)wl_fixed_to_double(fy) / window_data->current.logical_height;
|
|
const float y = (float)wl_fixed_to_double(fy) / window_data->current.logical_height;
|
|
|
|
|
|
- SDL_SendTouch(Wayland_GetTouchTimestamp(input, timestamp), (SDL_TouchID)(uintptr_t)touch,
|
|
|
|
|
|
+ SDL_SendTouch(Wayland_GetTouchTimestamp(seat, timestamp), (SDL_TouchID)(uintptr_t)touch,
|
|
(SDL_FingerID)(id + 1), window_data->sdlwindow, SDL_EVENT_FINGER_UP, x, y, 0.0f);
|
|
(SDL_FingerID)(id + 1), window_data->sdlwindow, SDL_EVENT_FINGER_UP, x, y, 0.0f);
|
|
|
|
|
|
- /* If the seat lacks pointer focus, the seat's keyboard focus is another window or NULL, this window currently
|
|
|
|
- * has mouse focus, and the surface has no active touch events, consider mouse focus to be lost.
|
|
|
|
|
|
+ /* If the window currently has mouse focus, the keyboard focus is another window or NULL, the window has no
|
|
|
|
+ * pointers active on it, and the surface has no active touch events, then consider mouse focus to be lost.
|
|
*/
|
|
*/
|
|
- if (!input->pointer_focus && input->keyboard_focus != window_data &&
|
|
|
|
- SDL_GetMouseFocus() == window_data->sdlwindow && !Wayland_SurfaceHasActiveTouches(surface)) {
|
|
|
|
|
|
+ if (SDL_GetMouseFocus() == window_data->sdlwindow && seat->keyboard.focus != window_data &&
|
|
|
|
+ !window_data->pointer_focus_count && !Wayland_SurfaceHasActiveTouches(seat->display, surface)) {
|
|
SDL_SetMouseFocus(NULL);
|
|
SDL_SetMouseFocus(NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1189,10 +1216,10 @@ static void touch_handler_up(void *data, struct wl_touch *touch, uint32_t serial
|
|
static void touch_handler_motion(void *data, struct wl_touch *touch, uint32_t timestamp,
|
|
static void touch_handler_motion(void *data, struct wl_touch *touch, uint32_t timestamp,
|
|
int id, wl_fixed_t fx, wl_fixed_t fy)
|
|
int id, wl_fixed_t fx, wl_fixed_t fy)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = (struct SDL_WaylandInput *)data;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = (SDL_WaylandSeat *)data;
|
|
struct wl_surface *surface = NULL;
|
|
struct wl_surface *surface = NULL;
|
|
|
|
|
|
- touch_update(id, fx, fy, &surface);
|
|
|
|
|
|
+ Wayland_SeatUpdateTouch(seat, id, fx, fy, &surface);
|
|
|
|
|
|
if (surface) {
|
|
if (surface) {
|
|
SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(surface);
|
|
SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(surface);
|
|
@@ -1201,7 +1228,7 @@ static void touch_handler_motion(void *data, struct wl_touch *touch, uint32_t ti
|
|
const float x = (float)wl_fixed_to_double(fx) / window_data->current.logical_width;
|
|
const float x = (float)wl_fixed_to_double(fx) / window_data->current.logical_width;
|
|
const float y = (float)wl_fixed_to_double(fy) / window_data->current.logical_height;
|
|
const float y = (float)wl_fixed_to_double(fy) / window_data->current.logical_height;
|
|
|
|
|
|
- SDL_SendTouchMotion(Wayland_GetPointerTimestamp(input, timestamp), (SDL_TouchID)(uintptr_t)touch,
|
|
|
|
|
|
+ SDL_SendTouchMotion(Wayland_GetPointerTimestamp(seat, timestamp), (SDL_TouchID)(uintptr_t)touch,
|
|
(SDL_FingerID)(id + 1), window_data->sdlwindow, x, y, 1.0f);
|
|
(SDL_FingerID)(id + 1), window_data->sdlwindow, x, y, 1.0f);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1213,10 +1240,10 @@ static void touch_handler_frame(void *data, struct wl_touch *touch)
|
|
|
|
|
|
static void touch_handler_cancel(void *data, struct wl_touch *touch)
|
|
static void touch_handler_cancel(void *data, struct wl_touch *touch)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = (struct SDL_WaylandInput *)data;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = (SDL_WaylandSeat *)data;
|
|
struct SDL_WaylandTouchPoint *tp, *temp;
|
|
struct SDL_WaylandTouchPoint *tp, *temp;
|
|
|
|
|
|
- wl_list_for_each_safe (tp, temp, &touch_points, link) {
|
|
|
|
|
|
+ wl_list_for_each_safe (tp, temp, &seat->touch.points, link) {
|
|
bool removed = false;
|
|
bool removed = false;
|
|
|
|
|
|
if (tp->surface) {
|
|
if (tp->surface) {
|
|
@@ -1233,11 +1260,11 @@ static void touch_handler_cancel(void *data, struct wl_touch *touch)
|
|
WAYLAND_wl_list_remove(&tp->link);
|
|
WAYLAND_wl_list_remove(&tp->link);
|
|
removed = true;
|
|
removed = true;
|
|
|
|
|
|
- /* If the seat lacks pointer focus, the seat's keyboard focus is another window or NULL, this window currently
|
|
|
|
- * has mouse focus, and the surface has no active touch events, consider mouse focus to be lost.
|
|
|
|
|
|
+ /* If the window currently has mouse focus, the keyboard focus is another window or NULL, the window has no
|
|
|
|
+ * pointers active on it, and the surface has no active touch events, then consider mouse focus to be lost.
|
|
*/
|
|
*/
|
|
- if (!input->pointer_focus && input->keyboard_focus != window_data &&
|
|
|
|
- SDL_GetMouseFocus() == window_data->sdlwindow && !Wayland_SurfaceHasActiveTouches(tp->surface)) {
|
|
|
|
|
|
+ if (SDL_GetMouseFocus() == window_data->sdlwindow && seat->keyboard.focus != window_data &&
|
|
|
|
+ !window_data->pointer_focus_count && !Wayland_SurfaceHasActiveTouches(seat->display, tp->surface)) {
|
|
SDL_SetMouseFocus(NULL);
|
|
SDL_SetMouseFocus(NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1250,26 +1277,34 @@ static void touch_handler_cancel(void *data, struct wl_touch *touch)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void touch_handler_shape(void *data, struct wl_touch *wl_touch, int32_t id, wl_fixed_t major, wl_fixed_t minor)
|
|
|
|
+{
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void touch_handler_orientation(void *data, struct wl_touch *wl_touch, int32_t id, wl_fixed_t orientation)
|
|
|
|
+{
|
|
|
|
+}
|
|
|
|
+
|
|
static const struct wl_touch_listener touch_listener = {
|
|
static const struct wl_touch_listener touch_listener = {
|
|
touch_handler_down,
|
|
touch_handler_down,
|
|
touch_handler_up,
|
|
touch_handler_up,
|
|
touch_handler_motion,
|
|
touch_handler_motion,
|
|
touch_handler_frame,
|
|
touch_handler_frame,
|
|
touch_handler_cancel,
|
|
touch_handler_cancel,
|
|
- NULL, // shape
|
|
|
|
- NULL, // orientation
|
|
|
|
|
|
+ touch_handler_shape, // Version 6
|
|
|
|
+ touch_handler_orientation // Version 6
|
|
};
|
|
};
|
|
|
|
|
|
-typedef struct Wayland_Keymap
|
|
|
|
|
|
+typedef struct Wayland_KeymapBuilderState
|
|
{
|
|
{
|
|
SDL_Keymap *keymap;
|
|
SDL_Keymap *keymap;
|
|
struct xkb_state *state;
|
|
struct xkb_state *state;
|
|
SDL_Keymod modstate;
|
|
SDL_Keymod modstate;
|
|
-} Wayland_Keymap;
|
|
|
|
|
|
+} Wayland_KeymapBuilderState;
|
|
|
|
|
|
static void Wayland_keymap_iter(struct xkb_keymap *keymap, xkb_keycode_t key, void *data)
|
|
static void Wayland_keymap_iter(struct xkb_keymap *keymap, xkb_keycode_t key, void *data)
|
|
{
|
|
{
|
|
- Wayland_Keymap *sdlKeymap = (Wayland_Keymap *)data;
|
|
|
|
|
|
+ Wayland_KeymapBuilderState *sdlKeymap = (Wayland_KeymapBuilderState *)data;
|
|
const xkb_keysym_t *syms;
|
|
const xkb_keysym_t *syms;
|
|
const SDL_Scancode scancode = SDL_GetScancodeFromTable(SDL_SCANCODE_TABLE_XFREE86_2, (key - 8));
|
|
const SDL_Scancode scancode = SDL_GetScancodeFromTable(SDL_SCANCODE_TABLE_XFREE86_2, (key - 8));
|
|
if (scancode == SDL_SCANCODE_UNKNOWN) {
|
|
if (scancode == SDL_SCANCODE_UNKNOWN) {
|
|
@@ -1303,7 +1338,7 @@ static void Wayland_keymap_iter(struct xkb_keymap *keymap, xkb_keycode_t key, vo
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static void Wayland_UpdateKeymap(struct SDL_WaylandInput *input)
|
|
|
|
|
|
+static void Wayland_UpdateKeymap(SDL_WaylandSeat *seat)
|
|
{
|
|
{
|
|
struct Keymod_masks
|
|
struct Keymod_masks
|
|
{
|
|
{
|
|
@@ -1311,32 +1346,32 @@ static void Wayland_UpdateKeymap(struct SDL_WaylandInput *input)
|
|
xkb_mod_mask_t xkb_mask;
|
|
xkb_mod_mask_t xkb_mask;
|
|
} const keymod_masks[] = {
|
|
} const keymod_masks[] = {
|
|
{ SDL_KMOD_NONE, 0 },
|
|
{ SDL_KMOD_NONE, 0 },
|
|
- { SDL_KMOD_SHIFT, input->xkb.idx_shift },
|
|
|
|
- { SDL_KMOD_CAPS, input->xkb.idx_caps },
|
|
|
|
- { SDL_KMOD_SHIFT | SDL_KMOD_CAPS, input->xkb.idx_shift | input->xkb.idx_caps },
|
|
|
|
- { SDL_KMOD_MODE, input->xkb.idx_mod5 },
|
|
|
|
- { SDL_KMOD_MODE | SDL_KMOD_SHIFT, input->xkb.idx_mod5 | input->xkb.idx_shift },
|
|
|
|
- { SDL_KMOD_MODE | SDL_KMOD_CAPS, input->xkb.idx_mod5 | input->xkb.idx_caps },
|
|
|
|
- { SDL_KMOD_MODE | SDL_KMOD_SHIFT | SDL_KMOD_CAPS, input->xkb.idx_mod5 | input->xkb.idx_shift | input->xkb.idx_caps },
|
|
|
|
- { SDL_KMOD_LEVEL5, input->xkb.idx_mod3 },
|
|
|
|
- { SDL_KMOD_LEVEL5 | SDL_KMOD_SHIFT, input->xkb.idx_mod3 | input->xkb.idx_shift },
|
|
|
|
- { SDL_KMOD_LEVEL5 | SDL_KMOD_CAPS, input->xkb.idx_mod3 | input->xkb.idx_caps },
|
|
|
|
- { SDL_KMOD_LEVEL5 | SDL_KMOD_SHIFT | SDL_KMOD_CAPS, input->xkb.idx_mod3 | input->xkb.idx_shift | input->xkb.idx_caps },
|
|
|
|
- { SDL_KMOD_LEVEL5 | SDL_KMOD_MODE, input->xkb.idx_mod3 | input->xkb.idx_mod5 },
|
|
|
|
- { SDL_KMOD_LEVEL5 | SDL_KMOD_MODE | SDL_KMOD_SHIFT, input->xkb.idx_mod3 | input->xkb.idx_mod5 | input->xkb.idx_shift },
|
|
|
|
- { SDL_KMOD_LEVEL5 | SDL_KMOD_MODE | SDL_KMOD_CAPS, input->xkb.idx_mod3 | input->xkb.idx_mod5 | input->xkb.idx_caps },
|
|
|
|
- { SDL_KMOD_LEVEL5 | SDL_KMOD_MODE | SDL_KMOD_SHIFT | SDL_KMOD_CAPS, input->xkb.idx_mod3 | input->xkb.idx_mod5 | input->xkb.idx_shift | input->xkb.idx_caps },
|
|
|
|
|
|
+ { SDL_KMOD_SHIFT, seat->keyboard.xkb.idx_shift },
|
|
|
|
+ { SDL_KMOD_CAPS, seat->keyboard.xkb.idx_caps },
|
|
|
|
+ { SDL_KMOD_SHIFT | SDL_KMOD_CAPS, seat->keyboard.xkb.idx_shift | seat->keyboard.xkb.idx_caps },
|
|
|
|
+ { SDL_KMOD_MODE, seat->keyboard.xkb.idx_mod5 },
|
|
|
|
+ { SDL_KMOD_MODE | SDL_KMOD_SHIFT, seat->keyboard.xkb.idx_mod5 | seat->keyboard.xkb.idx_shift },
|
|
|
|
+ { SDL_KMOD_MODE | SDL_KMOD_CAPS, seat->keyboard.xkb.idx_mod5 | seat->keyboard.xkb.idx_caps },
|
|
|
|
+ { SDL_KMOD_MODE | SDL_KMOD_SHIFT | SDL_KMOD_CAPS, seat->keyboard.xkb.idx_mod5 | seat->keyboard.xkb.idx_shift | seat->keyboard.xkb.idx_caps },
|
|
|
|
+ { SDL_KMOD_LEVEL5, seat->keyboard.xkb.idx_mod3 },
|
|
|
|
+ { SDL_KMOD_LEVEL5 | SDL_KMOD_SHIFT, seat->keyboard.xkb.idx_mod3 | seat->keyboard.xkb.idx_shift },
|
|
|
|
+ { SDL_KMOD_LEVEL5 | SDL_KMOD_CAPS, seat->keyboard.xkb.idx_mod3 | seat->keyboard.xkb.idx_caps },
|
|
|
|
+ { SDL_KMOD_LEVEL5 | SDL_KMOD_SHIFT | SDL_KMOD_CAPS, seat->keyboard.xkb.idx_mod3 | seat->keyboard.xkb.idx_shift | seat->keyboard.xkb.idx_caps },
|
|
|
|
+ { SDL_KMOD_LEVEL5 | SDL_KMOD_MODE, seat->keyboard.xkb.idx_mod3 | seat->keyboard.xkb.idx_mod5 },
|
|
|
|
+ { SDL_KMOD_LEVEL5 | SDL_KMOD_MODE | SDL_KMOD_SHIFT, seat->keyboard.xkb.idx_mod3 | seat->keyboard.xkb.idx_mod5 | seat->keyboard.xkb.idx_shift },
|
|
|
|
+ { SDL_KMOD_LEVEL5 | SDL_KMOD_MODE | SDL_KMOD_CAPS, seat->keyboard.xkb.idx_mod3 | seat->keyboard.xkb.idx_mod5 | seat->keyboard.xkb.idx_caps },
|
|
|
|
+ { SDL_KMOD_LEVEL5 | SDL_KMOD_MODE | SDL_KMOD_SHIFT | SDL_KMOD_CAPS, seat->keyboard.xkb.idx_mod3 | seat->keyboard.xkb.idx_mod5 | seat->keyboard.xkb.idx_shift | seat->keyboard.xkb.idx_caps },
|
|
};
|
|
};
|
|
|
|
|
|
- if (!input->keyboard_is_virtual) {
|
|
|
|
- Wayland_Keymap keymap;
|
|
|
|
|
|
+ if (!seat->keyboard.is_virtual) {
|
|
|
|
+ Wayland_KeymapBuilderState keymap;
|
|
|
|
|
|
- keymap.keymap = SDL_CreateKeymap();
|
|
|
|
|
|
+ keymap.keymap = SDL_CreateKeymap(false);
|
|
if (!keymap.keymap) {
|
|
if (!keymap.keymap) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- keymap.state = WAYLAND_xkb_state_new(input->xkb.keymap);
|
|
|
|
|
|
+ keymap.state = WAYLAND_xkb_state_new(seat->keyboard.xkb.keymap);
|
|
if (!keymap.state) {
|
|
if (!keymap.state) {
|
|
SDL_SetError("failed to create XKB state");
|
|
SDL_SetError("failed to create XKB state");
|
|
SDL_DestroyKeymap(keymap.keymap);
|
|
SDL_DestroyKeymap(keymap.keymap);
|
|
@@ -1346,25 +1381,29 @@ static void Wayland_UpdateKeymap(struct SDL_WaylandInput *input)
|
|
for (int i = 0; i < SDL_arraysize(keymod_masks); ++i) {
|
|
for (int i = 0; i < SDL_arraysize(keymod_masks); ++i) {
|
|
keymap.modstate = keymod_masks[i].sdl_mask;
|
|
keymap.modstate = keymod_masks[i].sdl_mask;
|
|
WAYLAND_xkb_state_update_mask(keymap.state,
|
|
WAYLAND_xkb_state_update_mask(keymap.state,
|
|
- keymod_masks[i].xkb_mask & (input->xkb.idx_shift | input->xkb.idx_mod5 | input->xkb.idx_mod3), 0, keymod_masks[i].xkb_mask & input->xkb.idx_caps,
|
|
|
|
- 0, 0, input->xkb.current_group);
|
|
|
|
- WAYLAND_xkb_keymap_key_for_each(input->xkb.keymap,
|
|
|
|
|
|
+ keymod_masks[i].xkb_mask & (seat->keyboard.xkb.idx_shift | seat->keyboard.xkb.idx_mod5 | seat->keyboard.xkb.idx_mod3), 0, keymod_masks[i].xkb_mask & seat->keyboard.xkb.idx_caps,
|
|
|
|
+ 0, 0, seat->keyboard.xkb.current_group);
|
|
|
|
+ WAYLAND_xkb_keymap_key_for_each(seat->keyboard.xkb.keymap,
|
|
Wayland_keymap_iter,
|
|
Wayland_keymap_iter,
|
|
&keymap);
|
|
&keymap);
|
|
}
|
|
}
|
|
|
|
|
|
WAYLAND_xkb_state_unref(keymap.state);
|
|
WAYLAND_xkb_state_unref(keymap.state);
|
|
SDL_SetKeymap(keymap.keymap, true);
|
|
SDL_SetKeymap(keymap.keymap, true);
|
|
|
|
+ SDL_DestroyKeymap(seat->keyboard.sdl_keymap);
|
|
|
|
+ seat->keyboard.sdl_keymap = keymap.keymap;
|
|
} else {
|
|
} else {
|
|
// Virtual keyboards use the default keymap.
|
|
// Virtual keyboards use the default keymap.
|
|
SDL_SetKeymap(NULL, true);
|
|
SDL_SetKeymap(NULL, true);
|
|
|
|
+ SDL_DestroyKeymap(seat->keyboard.sdl_keymap);
|
|
|
|
+ seat->keyboard.sdl_keymap = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
|
|
static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
|
|
uint32_t format, int fd, uint32_t size)
|
|
uint32_t format, int fd, uint32_t size)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = data;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = data;
|
|
char *map_str;
|
|
char *map_str;
|
|
const char *locale;
|
|
const char *locale;
|
|
|
|
|
|
@@ -1384,49 +1423,49 @@ static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- if (input->xkb.keymap != NULL) {
|
|
|
|
|
|
+ if (seat->keyboard.xkb.keymap != NULL) {
|
|
/* if there's already a keymap loaded, throw it away rather than leaking it before
|
|
/* if there's already a keymap loaded, throw it away rather than leaking it before
|
|
* parsing the new one
|
|
* parsing the new one
|
|
*/
|
|
*/
|
|
- WAYLAND_xkb_keymap_unref(input->xkb.keymap);
|
|
|
|
- input->xkb.keymap = NULL;
|
|
|
|
|
|
+ WAYLAND_xkb_keymap_unref(seat->keyboard.xkb.keymap);
|
|
|
|
+ seat->keyboard.xkb.keymap = NULL;
|
|
}
|
|
}
|
|
- input->xkb.keymap = WAYLAND_xkb_keymap_new_from_string(input->display->xkb_context,
|
|
|
|
|
|
+ seat->keyboard.xkb.keymap = WAYLAND_xkb_keymap_new_from_string(seat->display->xkb_context,
|
|
map_str,
|
|
map_str,
|
|
XKB_KEYMAP_FORMAT_TEXT_V1,
|
|
XKB_KEYMAP_FORMAT_TEXT_V1,
|
|
0);
|
|
0);
|
|
munmap(map_str, size);
|
|
munmap(map_str, size);
|
|
close(fd);
|
|
close(fd);
|
|
|
|
|
|
- if (!input->xkb.keymap) {
|
|
|
|
|
|
+ if (!seat->keyboard.xkb.keymap) {
|
|
SDL_SetError("failed to compile keymap");
|
|
SDL_SetError("failed to compile keymap");
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
#define GET_MOD_INDEX(mod) \
|
|
#define GET_MOD_INDEX(mod) \
|
|
- WAYLAND_xkb_keymap_mod_get_index(input->xkb.keymap, XKB_MOD_NAME_##mod)
|
|
|
|
- input->xkb.idx_shift = 1 << GET_MOD_INDEX(SHIFT);
|
|
|
|
- input->xkb.idx_ctrl = 1 << GET_MOD_INDEX(CTRL);
|
|
|
|
- input->xkb.idx_alt = 1 << GET_MOD_INDEX(ALT);
|
|
|
|
- input->xkb.idx_gui = 1 << GET_MOD_INDEX(LOGO);
|
|
|
|
- input->xkb.idx_mod3 = 1 << GET_MOD_INDEX(MOD3);
|
|
|
|
- input->xkb.idx_mod5 = 1 << GET_MOD_INDEX(MOD5);
|
|
|
|
- input->xkb.idx_num = 1 << GET_MOD_INDEX(NUM);
|
|
|
|
- input->xkb.idx_caps = 1 << GET_MOD_INDEX(CAPS);
|
|
|
|
|
|
+ WAYLAND_xkb_keymap_mod_get_index(seat->keyboard.xkb.keymap, XKB_MOD_NAME_##mod)
|
|
|
|
+ seat->keyboard.xkb.idx_shift = 1 << GET_MOD_INDEX(SHIFT);
|
|
|
|
+ seat->keyboard.xkb.idx_ctrl = 1 << GET_MOD_INDEX(CTRL);
|
|
|
|
+ seat->keyboard.xkb.idx_alt = 1 << GET_MOD_INDEX(ALT);
|
|
|
|
+ seat->keyboard.xkb.idx_gui = 1 << GET_MOD_INDEX(LOGO);
|
|
|
|
+ seat->keyboard.xkb.idx_mod3 = 1 << GET_MOD_INDEX(MOD3);
|
|
|
|
+ seat->keyboard.xkb.idx_mod5 = 1 << GET_MOD_INDEX(MOD5);
|
|
|
|
+ seat->keyboard.xkb.idx_num = 1 << GET_MOD_INDEX(NUM);
|
|
|
|
+ seat->keyboard.xkb.idx_caps = 1 << GET_MOD_INDEX(CAPS);
|
|
#undef GET_MOD_INDEX
|
|
#undef GET_MOD_INDEX
|
|
|
|
|
|
- if (input->xkb.state != NULL) {
|
|
|
|
|
|
+ if (seat->keyboard.xkb.state != NULL) {
|
|
/* if there's already a state, throw it away rather than leaking it before
|
|
/* if there's already a state, throw it away rather than leaking it before
|
|
* trying to create a new one with the new keymap.
|
|
* trying to create a new one with the new keymap.
|
|
*/
|
|
*/
|
|
- WAYLAND_xkb_state_unref(input->xkb.state);
|
|
|
|
- input->xkb.state = NULL;
|
|
|
|
|
|
+ WAYLAND_xkb_state_unref(seat->keyboard.xkb.state);
|
|
|
|
+ seat->keyboard.xkb.state = NULL;
|
|
}
|
|
}
|
|
- input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap);
|
|
|
|
- if (!input->xkb.state) {
|
|
|
|
|
|
+ seat->keyboard.xkb.state = WAYLAND_xkb_state_new(seat->keyboard.xkb.keymap);
|
|
|
|
+ if (!seat->keyboard.xkb.state) {
|
|
SDL_SetError("failed to create XKB state");
|
|
SDL_SetError("failed to create XKB state");
|
|
- WAYLAND_xkb_keymap_unref(input->xkb.keymap);
|
|
|
|
- input->xkb.keymap = NULL;
|
|
|
|
|
|
+ WAYLAND_xkb_keymap_unref(seat->keyboard.xkb.keymap);
|
|
|
|
+ seat->keyboard.xkb.keymap = NULL;
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1434,11 +1473,11 @@ static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
|
|
* Assume that a nameless layout implies a virtual keyboard with an arbitrary layout.
|
|
* Assume that a nameless layout implies a virtual keyboard with an arbitrary layout.
|
|
* TODO: Use a better method of detection?
|
|
* TODO: Use a better method of detection?
|
|
*/
|
|
*/
|
|
- input->keyboard_is_virtual = WAYLAND_xkb_keymap_layout_get_name(input->xkb.keymap, 0) == NULL;
|
|
|
|
|
|
+ seat->keyboard.is_virtual = WAYLAND_xkb_keymap_layout_get_name(seat->keyboard.xkb.keymap, 0) == NULL;
|
|
|
|
|
|
// Update the keymap if changed.
|
|
// Update the keymap if changed.
|
|
- if (input->xkb.current_group != XKB_GROUP_INVALID) {
|
|
|
|
- Wayland_UpdateKeymap(input);
|
|
|
|
|
|
+ if (seat->keyboard.xkb.current_group != XKB_GROUP_INVALID) {
|
|
|
|
+ Wayland_UpdateKeymap(seat);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -1459,24 +1498,24 @@ static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
|
|
}
|
|
}
|
|
|
|
|
|
// Set up XKB compose table
|
|
// Set up XKB compose table
|
|
- if (input->xkb.compose_table != NULL) {
|
|
|
|
- WAYLAND_xkb_compose_table_unref(input->xkb.compose_table);
|
|
|
|
- input->xkb.compose_table = NULL;
|
|
|
|
|
|
+ if (seat->keyboard.xkb.compose_table != NULL) {
|
|
|
|
+ WAYLAND_xkb_compose_table_unref(seat->keyboard.xkb.compose_table);
|
|
|
|
+ seat->keyboard.xkb.compose_table = NULL;
|
|
}
|
|
}
|
|
- input->xkb.compose_table = WAYLAND_xkb_compose_table_new_from_locale(input->display->xkb_context,
|
|
|
|
|
|
+ seat->keyboard.xkb.compose_table = WAYLAND_xkb_compose_table_new_from_locale(seat->display->xkb_context,
|
|
locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
|
|
locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
|
|
- if (input->xkb.compose_table) {
|
|
|
|
|
|
+ if (seat->keyboard.xkb.compose_table) {
|
|
// Set up XKB compose state
|
|
// Set up XKB compose state
|
|
- if (input->xkb.compose_state != NULL) {
|
|
|
|
- WAYLAND_xkb_compose_state_unref(input->xkb.compose_state);
|
|
|
|
- input->xkb.compose_state = NULL;
|
|
|
|
|
|
+ if (seat->keyboard.xkb.compose_state != NULL) {
|
|
|
|
+ WAYLAND_xkb_compose_state_unref(seat->keyboard.xkb.compose_state);
|
|
|
|
+ seat->keyboard.xkb.compose_state = NULL;
|
|
}
|
|
}
|
|
- input->xkb.compose_state = WAYLAND_xkb_compose_state_new(input->xkb.compose_table,
|
|
|
|
|
|
+ seat->keyboard.xkb.compose_state = WAYLAND_xkb_compose_state_new(seat->keyboard.xkb.compose_table,
|
|
XKB_COMPOSE_STATE_NO_FLAGS);
|
|
XKB_COMPOSE_STATE_NO_FLAGS);
|
|
- if (!input->xkb.compose_state) {
|
|
|
|
|
|
+ if (!seat->keyboard.xkb.compose_state) {
|
|
SDL_SetError("could not create XKB compose state");
|
|
SDL_SetError("could not create XKB compose state");
|
|
- WAYLAND_xkb_compose_table_unref(input->xkb.compose_table);
|
|
|
|
- input->xkb.compose_table = NULL;
|
|
|
|
|
|
+ WAYLAND_xkb_compose_table_unref(seat->keyboard.xkb.compose_table);
|
|
|
|
+ seat->keyboard.xkb.compose_table = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1485,15 +1524,15 @@ static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
|
|
* Virtual keyboards can have arbitrary layouts, arbitrary scancodes/keycodes, etc...
|
|
* Virtual keyboards can have arbitrary layouts, arbitrary scancodes/keycodes, etc...
|
|
* Key presses from these devices must be looked up by their keysym value.
|
|
* Key presses from these devices must be looked up by their keysym value.
|
|
*/
|
|
*/
|
|
-static SDL_Scancode Wayland_GetScancodeForKey(struct SDL_WaylandInput *input, uint32_t key)
|
|
|
|
|
|
+static SDL_Scancode Wayland_GetScancodeForKey(SDL_WaylandSeat *seat, uint32_t key)
|
|
{
|
|
{
|
|
SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
|
|
SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
|
|
|
|
|
|
- if (!input->keyboard_is_virtual) {
|
|
|
|
|
|
+ if (!seat->keyboard.is_virtual) {
|
|
scancode = SDL_GetScancodeFromTable(SDL_SCANCODE_TABLE_XFREE86_2, key);
|
|
scancode = SDL_GetScancodeFromTable(SDL_SCANCODE_TABLE_XFREE86_2, key);
|
|
} else {
|
|
} else {
|
|
const xkb_keysym_t *syms;
|
|
const xkb_keysym_t *syms;
|
|
- if (WAYLAND_xkb_keymap_key_get_syms_by_level(input->xkb.keymap, key + 8, input->xkb.current_group, 0, &syms) > 0) {
|
|
|
|
|
|
+ if (WAYLAND_xkb_keymap_key_get_syms_by_level(seat->keyboard.xkb.keymap, key + 8, seat->keyboard.xkb.current_group, 0, &syms) > 0) {
|
|
scancode = SDL_GetScancodeFromKeySym(syms[0], key);
|
|
scancode = SDL_GetScancodeFromKeySym(syms[0], key);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1501,7 +1540,7 @@ static SDL_Scancode Wayland_GetScancodeForKey(struct SDL_WaylandInput *input, ui
|
|
return scancode;
|
|
return scancode;
|
|
}
|
|
}
|
|
|
|
|
|
-static void Wayland_ReconcileModifiers(struct SDL_WaylandInput *input, bool key_pressed)
|
|
|
|
|
|
+static void Wayland_ReconcileModifiers(SDL_WaylandSeat *seat, bool key_pressed)
|
|
{
|
|
{
|
|
/* Handle explicit pressed modifier state. This will correct the modifier state
|
|
/* Handle explicit pressed modifier state. This will correct the modifier state
|
|
* if common modifier keys were remapped and the modifiers presumed to be set
|
|
* if common modifier keys were remapped and the modifiers presumed to be set
|
|
@@ -1509,55 +1548,55 @@ static void Wayland_ReconcileModifiers(struct SDL_WaylandInput *input, bool key_
|
|
* pressed state via means other than pressing the physical key.
|
|
* pressed state via means other than pressing the physical key.
|
|
*/
|
|
*/
|
|
if (!key_pressed) {
|
|
if (!key_pressed) {
|
|
- if (input->xkb.wl_pressed_modifiers & input->xkb.idx_shift) {
|
|
|
|
- if (!(input->pressed_modifiers & SDL_KMOD_SHIFT)) {
|
|
|
|
- input->pressed_modifiers |= SDL_KMOD_SHIFT;
|
|
|
|
|
|
+ if (seat->keyboard.xkb.wl_pressed_modifiers & seat->keyboard.xkb.idx_shift) {
|
|
|
|
+ if (!(seat->keyboard.pressed_modifiers & SDL_KMOD_SHIFT)) {
|
|
|
|
+ seat->keyboard.pressed_modifiers |= SDL_KMOD_SHIFT;
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
- input->pressed_modifiers &= ~SDL_KMOD_SHIFT;
|
|
|
|
|
|
+ seat->keyboard.pressed_modifiers &= ~SDL_KMOD_SHIFT;
|
|
}
|
|
}
|
|
|
|
|
|
- if (input->xkb.wl_pressed_modifiers & input->xkb.idx_ctrl) {
|
|
|
|
- if (!(input->pressed_modifiers & SDL_KMOD_CTRL)) {
|
|
|
|
- input->pressed_modifiers |= SDL_KMOD_CTRL;
|
|
|
|
|
|
+ if (seat->keyboard.xkb.wl_pressed_modifiers & seat->keyboard.xkb.idx_ctrl) {
|
|
|
|
+ if (!(seat->keyboard.pressed_modifiers & SDL_KMOD_CTRL)) {
|
|
|
|
+ seat->keyboard.pressed_modifiers |= SDL_KMOD_CTRL;
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
- input->pressed_modifiers &= ~SDL_KMOD_CTRL;
|
|
|
|
|
|
+ seat->keyboard.pressed_modifiers &= ~SDL_KMOD_CTRL;
|
|
}
|
|
}
|
|
|
|
|
|
- if (input->xkb.wl_pressed_modifiers & input->xkb.idx_alt) {
|
|
|
|
- if (!(input->pressed_modifiers & SDL_KMOD_ALT)) {
|
|
|
|
- input->pressed_modifiers |= SDL_KMOD_ALT;
|
|
|
|
|
|
+ if (seat->keyboard.xkb.wl_pressed_modifiers & seat->keyboard.xkb.idx_alt) {
|
|
|
|
+ if (!(seat->keyboard.pressed_modifiers & SDL_KMOD_ALT)) {
|
|
|
|
+ seat->keyboard.pressed_modifiers |= SDL_KMOD_ALT;
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
- input->pressed_modifiers &= ~SDL_KMOD_ALT;
|
|
|
|
|
|
+ seat->keyboard.pressed_modifiers &= ~SDL_KMOD_ALT;
|
|
}
|
|
}
|
|
|
|
|
|
- if (input->xkb.wl_pressed_modifiers & input->xkb.idx_gui) {
|
|
|
|
- if (!(input->pressed_modifiers & SDL_KMOD_GUI)) {
|
|
|
|
- input->pressed_modifiers |= SDL_KMOD_GUI;
|
|
|
|
|
|
+ if (seat->keyboard.xkb.wl_pressed_modifiers & seat->keyboard.xkb.idx_gui) {
|
|
|
|
+ if (!(seat->keyboard.pressed_modifiers & SDL_KMOD_GUI)) {
|
|
|
|
+ seat->keyboard.pressed_modifiers |= SDL_KMOD_GUI;
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
- input->pressed_modifiers &= ~SDL_KMOD_GUI;
|
|
|
|
|
|
+ seat->keyboard.pressed_modifiers &= ~SDL_KMOD_GUI;
|
|
}
|
|
}
|
|
|
|
|
|
/* Note: This is not backwards: in the default keymap, Mod5 is typically
|
|
/* Note: This is not backwards: in the default keymap, Mod5 is typically
|
|
* level 3 shift, and Mod3 is typically level 5 shift.
|
|
* level 3 shift, and Mod3 is typically level 5 shift.
|
|
*/
|
|
*/
|
|
- if (input->xkb.wl_pressed_modifiers & input->xkb.idx_mod3) {
|
|
|
|
- if (!(input->pressed_modifiers & SDL_KMOD_LEVEL5)) {
|
|
|
|
- input->pressed_modifiers |= SDL_KMOD_LEVEL5;
|
|
|
|
|
|
+ if (seat->keyboard.xkb.wl_pressed_modifiers & seat->keyboard.xkb.idx_mod3) {
|
|
|
|
+ if (!(seat->keyboard.pressed_modifiers & SDL_KMOD_LEVEL5)) {
|
|
|
|
+ seat->keyboard.pressed_modifiers |= SDL_KMOD_LEVEL5;
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
- input->pressed_modifiers &= ~SDL_KMOD_LEVEL5;
|
|
|
|
|
|
+ seat->keyboard.pressed_modifiers &= ~SDL_KMOD_LEVEL5;
|
|
}
|
|
}
|
|
|
|
|
|
- if (input->xkb.wl_pressed_modifiers & input->xkb.idx_mod5) {
|
|
|
|
- if (!(input->pressed_modifiers & SDL_KMOD_MODE)) {
|
|
|
|
- input->pressed_modifiers |= SDL_KMOD_MODE;
|
|
|
|
|
|
+ if (seat->keyboard.xkb.wl_pressed_modifiers & seat->keyboard.xkb.idx_mod5) {
|
|
|
|
+ if (!(seat->keyboard.pressed_modifiers & SDL_KMOD_MODE)) {
|
|
|
|
+ seat->keyboard.pressed_modifiers |= SDL_KMOD_MODE;
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
- input->pressed_modifiers &= ~SDL_KMOD_MODE;
|
|
|
|
|
|
+ seat->keyboard.pressed_modifiers &= ~SDL_KMOD_MODE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1568,80 +1607,80 @@ static void Wayland_ReconcileModifiers(struct SDL_WaylandInput *input, bool key_
|
|
* The modifier will remain active until the latch/lock is released by
|
|
* The modifier will remain active until the latch/lock is released by
|
|
* the system.
|
|
* the system.
|
|
*/
|
|
*/
|
|
- if (input->xkb.wl_locked_modifiers & input->xkb.idx_shift) {
|
|
|
|
- if (input->pressed_modifiers & SDL_KMOD_SHIFT) {
|
|
|
|
- input->locked_modifiers &= ~SDL_KMOD_SHIFT;
|
|
|
|
- input->locked_modifiers |= (input->pressed_modifiers & SDL_KMOD_SHIFT);
|
|
|
|
- } else if (!(input->locked_modifiers & SDL_KMOD_SHIFT)) {
|
|
|
|
- input->locked_modifiers |= SDL_KMOD_SHIFT;
|
|
|
|
|
|
+ if (seat->keyboard.xkb.wl_locked_modifiers & seat->keyboard.xkb.idx_shift) {
|
|
|
|
+ if (seat->keyboard.pressed_modifiers & SDL_KMOD_SHIFT) {
|
|
|
|
+ seat->keyboard.locked_modifiers &= ~SDL_KMOD_SHIFT;
|
|
|
|
+ seat->keyboard.locked_modifiers |= (seat->keyboard.pressed_modifiers & SDL_KMOD_SHIFT);
|
|
|
|
+ } else if (!(seat->keyboard.locked_modifiers & SDL_KMOD_SHIFT)) {
|
|
|
|
+ seat->keyboard.locked_modifiers |= SDL_KMOD_SHIFT;
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
- input->locked_modifiers &= ~SDL_KMOD_SHIFT;
|
|
|
|
|
|
+ seat->keyboard.locked_modifiers &= ~SDL_KMOD_SHIFT;
|
|
}
|
|
}
|
|
|
|
|
|
- if (input->xkb.wl_locked_modifiers & input->xkb.idx_ctrl) {
|
|
|
|
- if (input->pressed_modifiers & SDL_KMOD_CTRL) {
|
|
|
|
- input->locked_modifiers &= ~SDL_KMOD_CTRL;
|
|
|
|
- input->locked_modifiers |= (input->pressed_modifiers & SDL_KMOD_CTRL);
|
|
|
|
- } else if (!(input->locked_modifiers & SDL_KMOD_CTRL)) {
|
|
|
|
- input->locked_modifiers |= SDL_KMOD_CTRL;
|
|
|
|
|
|
+ if (seat->keyboard.xkb.wl_locked_modifiers & seat->keyboard.xkb.idx_ctrl) {
|
|
|
|
+ if (seat->keyboard.pressed_modifiers & SDL_KMOD_CTRL) {
|
|
|
|
+ seat->keyboard.locked_modifiers &= ~SDL_KMOD_CTRL;
|
|
|
|
+ seat->keyboard.locked_modifiers |= (seat->keyboard.pressed_modifiers & SDL_KMOD_CTRL);
|
|
|
|
+ } else if (!(seat->keyboard.locked_modifiers & SDL_KMOD_CTRL)) {
|
|
|
|
+ seat->keyboard.locked_modifiers |= SDL_KMOD_CTRL;
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
- input->locked_modifiers &= ~SDL_KMOD_CTRL;
|
|
|
|
|
|
+ seat->keyboard.locked_modifiers &= ~SDL_KMOD_CTRL;
|
|
}
|
|
}
|
|
|
|
|
|
- if (input->xkb.wl_locked_modifiers & input->xkb.idx_alt) {
|
|
|
|
- if (input->pressed_modifiers & SDL_KMOD_ALT) {
|
|
|
|
- input->locked_modifiers &= ~SDL_KMOD_ALT;
|
|
|
|
- input->locked_modifiers |= (input->pressed_modifiers & SDL_KMOD_ALT);
|
|
|
|
- } else if (!(input->locked_modifiers & SDL_KMOD_ALT)) {
|
|
|
|
- input->locked_modifiers |= SDL_KMOD_ALT;
|
|
|
|
|
|
+ if (seat->keyboard.xkb.wl_locked_modifiers & seat->keyboard.xkb.idx_alt) {
|
|
|
|
+ if (seat->keyboard.pressed_modifiers & SDL_KMOD_ALT) {
|
|
|
|
+ seat->keyboard.locked_modifiers &= ~SDL_KMOD_ALT;
|
|
|
|
+ seat->keyboard.locked_modifiers |= (seat->keyboard.pressed_modifiers & SDL_KMOD_ALT);
|
|
|
|
+ } else if (!(seat->keyboard.locked_modifiers & SDL_KMOD_ALT)) {
|
|
|
|
+ seat->keyboard.locked_modifiers |= SDL_KMOD_ALT;
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
- input->locked_modifiers &= ~SDL_KMOD_ALT;
|
|
|
|
|
|
+ seat->keyboard.locked_modifiers &= ~SDL_KMOD_ALT;
|
|
}
|
|
}
|
|
|
|
|
|
- if (input->xkb.wl_locked_modifiers & input->xkb.idx_gui) {
|
|
|
|
- if (input->pressed_modifiers & SDL_KMOD_GUI) {
|
|
|
|
- input->locked_modifiers &= ~SDL_KMOD_GUI;
|
|
|
|
- input->locked_modifiers |= (input->pressed_modifiers & SDL_KMOD_GUI);
|
|
|
|
- } else if (!(input->locked_modifiers & SDL_KMOD_GUI)) {
|
|
|
|
- input->locked_modifiers |= SDL_KMOD_GUI;
|
|
|
|
|
|
+ if (seat->keyboard.xkb.wl_locked_modifiers & seat->keyboard.xkb.idx_gui) {
|
|
|
|
+ if (seat->keyboard.pressed_modifiers & SDL_KMOD_GUI) {
|
|
|
|
+ seat->keyboard.locked_modifiers &= ~SDL_KMOD_GUI;
|
|
|
|
+ seat->keyboard.locked_modifiers |= (seat->keyboard.pressed_modifiers & SDL_KMOD_GUI);
|
|
|
|
+ } else if (!(seat->keyboard.locked_modifiers & SDL_KMOD_GUI)) {
|
|
|
|
+ seat->keyboard.locked_modifiers |= SDL_KMOD_GUI;
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
- input->locked_modifiers &= ~SDL_KMOD_GUI;
|
|
|
|
|
|
+ seat->keyboard.locked_modifiers &= ~SDL_KMOD_GUI;
|
|
}
|
|
}
|
|
|
|
|
|
// As above, this is correct: Mod3 is typically level 5 shift, and Mod5 is typically level 3 shift.
|
|
// As above, this is correct: Mod3 is typically level 5 shift, and Mod5 is typically level 3 shift.
|
|
- if (input->xkb.wl_locked_modifiers & input->xkb.idx_mod3) {
|
|
|
|
- input->locked_modifiers |= SDL_KMOD_LEVEL5;
|
|
|
|
|
|
+ if (seat->keyboard.xkb.wl_locked_modifiers & seat->keyboard.xkb.idx_mod3) {
|
|
|
|
+ seat->keyboard.locked_modifiers |= SDL_KMOD_LEVEL5;
|
|
} else {
|
|
} else {
|
|
- input->locked_modifiers &= ~SDL_KMOD_LEVEL5;
|
|
|
|
|
|
+ seat->keyboard.locked_modifiers &= ~SDL_KMOD_LEVEL5;
|
|
}
|
|
}
|
|
|
|
|
|
- if (input->xkb.wl_locked_modifiers & input->xkb.idx_mod5) {
|
|
|
|
- input->locked_modifiers |= SDL_KMOD_MODE;
|
|
|
|
|
|
+ if (seat->keyboard.xkb.wl_locked_modifiers & seat->keyboard.xkb.idx_mod5) {
|
|
|
|
+ seat->keyboard.locked_modifiers |= SDL_KMOD_MODE;
|
|
} else {
|
|
} else {
|
|
- input->locked_modifiers &= ~SDL_KMOD_MODE;
|
|
|
|
|
|
+ seat->keyboard.locked_modifiers &= ~SDL_KMOD_MODE;
|
|
}
|
|
}
|
|
|
|
|
|
// Capslock and Numlock can only be locked, not pressed.
|
|
// Capslock and Numlock can only be locked, not pressed.
|
|
- if (input->xkb.wl_locked_modifiers & input->xkb.idx_caps) {
|
|
|
|
- input->locked_modifiers |= SDL_KMOD_CAPS;
|
|
|
|
|
|
+ if (seat->keyboard.xkb.wl_locked_modifiers & seat->keyboard.xkb.idx_caps) {
|
|
|
|
+ seat->keyboard.locked_modifiers |= SDL_KMOD_CAPS;
|
|
} else {
|
|
} else {
|
|
- input->locked_modifiers &= ~SDL_KMOD_CAPS;
|
|
|
|
|
|
+ seat->keyboard.locked_modifiers &= ~SDL_KMOD_CAPS;
|
|
}
|
|
}
|
|
|
|
|
|
- if (input->xkb.wl_locked_modifiers & input->xkb.idx_num) {
|
|
|
|
- input->locked_modifiers |= SDL_KMOD_NUM;
|
|
|
|
|
|
+ if (seat->keyboard.xkb.wl_locked_modifiers & seat->keyboard.xkb.idx_num) {
|
|
|
|
+ seat->keyboard.locked_modifiers |= SDL_KMOD_NUM;
|
|
} else {
|
|
} else {
|
|
- input->locked_modifiers &= ~SDL_KMOD_NUM;
|
|
|
|
|
|
+ seat->keyboard.locked_modifiers &= ~SDL_KMOD_NUM;
|
|
}
|
|
}
|
|
|
|
|
|
- SDL_SetModState(input->pressed_modifiers | input->locked_modifiers);
|
|
|
|
|
|
+ SDL_SetModState(seat->keyboard.pressed_modifiers | seat->keyboard.locked_modifiers);
|
|
}
|
|
}
|
|
|
|
|
|
-static void Wayland_HandleModifierKeys(struct SDL_WaylandInput *input, SDL_Scancode scancode, bool pressed)
|
|
|
|
|
|
+static void Wayland_HandleModifierKeys(SDL_WaylandSeat *seat, SDL_Scancode scancode, bool pressed)
|
|
{
|
|
{
|
|
const SDL_Keycode keycode = SDL_GetKeyFromScancode(scancode, SDL_KMOD_NONE, false);
|
|
const SDL_Keycode keycode = SDL_GetKeyFromScancode(scancode, SDL_KMOD_NONE, false);
|
|
SDL_Keymod mod;
|
|
SDL_Keymod mod;
|
|
@@ -1688,41 +1727,47 @@ static void Wayland_HandleModifierKeys(struct SDL_WaylandInput *input, SDL_Scanc
|
|
}
|
|
}
|
|
|
|
|
|
if (pressed) {
|
|
if (pressed) {
|
|
- input->pressed_modifiers |= mod;
|
|
|
|
|
|
+ seat->keyboard.pressed_modifiers |= mod;
|
|
} else {
|
|
} else {
|
|
- input->pressed_modifiers &= ~mod;
|
|
|
|
|
|
+ seat->keyboard.pressed_modifiers &= ~mod;
|
|
}
|
|
}
|
|
|
|
|
|
- Wayland_ReconcileModifiers(input, true);
|
|
|
|
|
|
+ Wayland_ReconcileModifiers(seat, true);
|
|
}
|
|
}
|
|
|
|
|
|
static void keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
|
|
static void keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
|
|
uint32_t serial, struct wl_surface *surface,
|
|
uint32_t serial, struct wl_surface *surface,
|
|
struct wl_array *keys)
|
|
struct wl_array *keys)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = data;
|
|
|
|
- SDL_WindowData *window;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = data;
|
|
uint32_t *key;
|
|
uint32_t *key;
|
|
|
|
|
|
if (!surface) {
|
|
if (!surface) {
|
|
- // enter event for a window we've just destroyed
|
|
|
|
|
|
+ // Enter event for a destroyed surface.
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- window = Wayland_GetWindowDataForOwnedSurface(surface);
|
|
|
|
-
|
|
|
|
|
|
+ SDL_WindowData *window = Wayland_GetWindowDataForOwnedSurface(surface);
|
|
if (!window) {
|
|
if (!window) {
|
|
|
|
+ // Not a surface owned by SDL.
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- input->keyboard_focus = window;
|
|
|
|
- window->keyboard_device = input;
|
|
|
|
|
|
+ ++window->keyboard_focus_count;
|
|
|
|
+ seat->keyboard.focus = window;
|
|
|
|
|
|
// Restore the keyboard focus to the child popup that was holding it
|
|
// Restore the keyboard focus to the child popup that was holding it
|
|
SDL_SetKeyboardFocus(window->keyboard_focus ? window->keyboard_focus : window->sdlwindow);
|
|
SDL_SetKeyboardFocus(window->keyboard_focus ? window->keyboard_focus : window->sdlwindow);
|
|
|
|
|
|
|
|
+ // Update the keyboard grab and any relative pointer grabs related to this keyboard focus.
|
|
|
|
+ Wayland_SeatUpdateKeyboardGrab(seat);
|
|
|
|
+ Wayland_DisplayUpdatePointerGrabs(seat->display, window);
|
|
|
|
+
|
|
|
|
+ // Update text input and IME focus.
|
|
|
|
+ Wayland_UpdateTextInput(seat->display);
|
|
|
|
+
|
|
#ifdef SDL_USE_IME
|
|
#ifdef SDL_USE_IME
|
|
- if (!input->text_input) {
|
|
|
|
|
|
+ if (!seat->text_input.zwp_text_input) {
|
|
SDL_IME_SetFocus(true);
|
|
SDL_IME_SetFocus(true);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
@@ -1730,8 +1775,12 @@ static void keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
|
|
Uint64 timestamp = SDL_GetTicksNS();
|
|
Uint64 timestamp = SDL_GetTicksNS();
|
|
window->last_focus_event_time_ns = timestamp;
|
|
window->last_focus_event_time_ns = timestamp;
|
|
|
|
|
|
|
|
+ if (SDL_GetCurrentKeymap() != seat->keyboard.sdl_keymap) {
|
|
|
|
+ SDL_SetKeymap(seat->keyboard.sdl_keymap, true);
|
|
|
|
+ }
|
|
|
|
+
|
|
wl_array_for_each (key, keys) {
|
|
wl_array_for_each (key, keys) {
|
|
- const SDL_Scancode scancode = Wayland_GetScancodeForKey(input, *key);
|
|
|
|
|
|
+ const SDL_Scancode scancode = Wayland_GetScancodeForKey(seat, *key);
|
|
const SDL_Keycode keycode = SDL_GetKeyFromScancode(scancode, SDL_KMOD_NONE, false);
|
|
const SDL_Keycode keycode = SDL_GetKeyFromScancode(scancode, SDL_KMOD_NONE, false);
|
|
|
|
|
|
switch (keycode) {
|
|
switch (keycode) {
|
|
@@ -1745,8 +1794,8 @@ static void keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
|
|
case SDLK_RGUI:
|
|
case SDLK_RGUI:
|
|
case SDLK_MODE:
|
|
case SDLK_MODE:
|
|
case SDLK_LEVEL5_SHIFT:
|
|
case SDLK_LEVEL5_SHIFT:
|
|
- Wayland_HandleModifierKeys(input, scancode, true);
|
|
|
|
- SDL_SendKeyboardKeyIgnoreModifiers(timestamp, input->keyboard_id, *key, scancode, true);
|
|
|
|
|
|
+ Wayland_HandleModifierKeys(seat, scancode, true);
|
|
|
|
+ SDL_SendKeyboardKeyIgnoreModifiers(timestamp, seat->keyboard.sdl_id, *key, scancode, true);
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
break;
|
|
break;
|
|
@@ -1757,58 +1806,74 @@ static void keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
|
|
static void keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
|
|
static void keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
|
|
uint32_t serial, struct wl_surface *surface)
|
|
uint32_t serial, struct wl_surface *surface)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = data;
|
|
|
|
- SDL_WindowData *wind;
|
|
|
|
- SDL_Window *window = NULL;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = (SDL_WaylandSeat *)data;
|
|
|
|
|
|
if (!surface) {
|
|
if (!surface) {
|
|
|
|
+ // Leave event for a destroyed surface.
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- wind = Wayland_GetWindowDataForOwnedSurface(surface);
|
|
|
|
- if (!wind) {
|
|
|
|
|
|
+ SDL_WindowData *window = Wayland_GetWindowDataForOwnedSurface(surface);
|
|
|
|
+ if (!window) {
|
|
|
|
+ // Not a surface owned by SDL.
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- wind->keyboard_device = NULL;
|
|
|
|
- window = wind->sdlwindow;
|
|
|
|
-
|
|
|
|
// Stop key repeat before clearing keyboard focus
|
|
// Stop key repeat before clearing keyboard focus
|
|
- keyboard_repeat_clear(&input->keyboard_repeat);
|
|
|
|
|
|
+ keyboard_repeat_clear(&seat->keyboard.repeat);
|
|
|
|
+
|
|
|
|
+ SDL_Window *keyboard_focus = SDL_GetKeyboardFocus();
|
|
|
|
+
|
|
|
|
+ // The keyboard focus may be a child popup
|
|
|
|
+ while (keyboard_focus && SDL_WINDOW_IS_POPUP(keyboard_focus)) {
|
|
|
|
+ keyboard_focus = keyboard_focus->parent;
|
|
|
|
+ }
|
|
|
|
|
|
- // This will release any keys still pressed
|
|
|
|
- SDL_SetKeyboardFocus(NULL);
|
|
|
|
- input->keyboard_focus = NULL;
|
|
|
|
|
|
+ const bool had_focus = keyboard_focus && window->sdlwindow == keyboard_focus;
|
|
|
|
+ seat->keyboard.focus = NULL;
|
|
|
|
+ --window->keyboard_focus_count;
|
|
|
|
+
|
|
|
|
+ // Only relinquish focus if this window has the active focus, and no other keyboards have focus on the window.
|
|
|
|
+ if (!window->keyboard_focus_count && had_focus) {
|
|
|
|
+ SDL_SetKeyboardFocus(NULL);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Release the keyboard grab and any relative pointer grabs related to this keyboard focus.
|
|
|
|
+ Wayland_SeatUpdateKeyboardGrab(seat);
|
|
|
|
+ Wayland_DisplayUpdatePointerGrabs(seat->display, window);
|
|
|
|
|
|
// Clear the pressed modifiers.
|
|
// Clear the pressed modifiers.
|
|
- input->pressed_modifiers = SDL_KMOD_NONE;
|
|
|
|
|
|
+ seat->keyboard.pressed_modifiers = SDL_KMOD_NONE;
|
|
|
|
+
|
|
|
|
+ // Update text input and IME focus.
|
|
|
|
+ Wayland_UpdateTextInput(seat->display);
|
|
|
|
|
|
#ifdef SDL_USE_IME
|
|
#ifdef SDL_USE_IME
|
|
- if (!input->text_input) {
|
|
|
|
|
|
+ if (!seat->text_input.zwp_text_input && !window->keyboard_focus_count) {
|
|
SDL_IME_SetFocus(false);
|
|
SDL_IME_SetFocus(false);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
- /* If the surface had a pointer leave event while still having active touch events, it retained mouse focus.
|
|
|
|
- * Clear it now if all touch events are raised.
|
|
|
|
|
|
+ /* If the window has mouse focus, has no pointers within it, and no active touches, consider
|
|
|
|
+ * mouse focus to be lost.
|
|
*/
|
|
*/
|
|
- if (!input->pointer_focus && SDL_GetMouseFocus() == window && !Wayland_SurfaceHasActiveTouches(surface)) {
|
|
|
|
|
|
+ if (SDL_GetMouseFocus() == window->sdlwindow && !window->pointer_focus_count &&
|
|
|
|
+ !Wayland_SurfaceHasActiveTouches(seat->display, surface)) {
|
|
SDL_SetMouseFocus(NULL);
|
|
SDL_SetMouseFocus(NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static bool keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint32_t key, bool down, bool *handled_by_ime)
|
|
|
|
|
|
+static bool keyboard_input_get_text(char text[8], const SDL_WaylandSeat *seat, uint32_t key, bool down, bool *handled_by_ime)
|
|
{
|
|
{
|
|
- SDL_WindowData *window = input->keyboard_focus;
|
|
|
|
const xkb_keysym_t *syms;
|
|
const xkb_keysym_t *syms;
|
|
xkb_keysym_t sym;
|
|
xkb_keysym_t sym;
|
|
|
|
|
|
- if (!window || window->keyboard_device != input || !input->xkb.state) {
|
|
|
|
|
|
+ if (!seat->keyboard.focus || !seat->keyboard.xkb.state) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
// TODO: Can this happen?
|
|
// TODO: Can this happen?
|
|
- if (WAYLAND_xkb_state_key_get_syms(input->xkb.state, key + 8, &syms) != 1) {
|
|
|
|
|
|
+ if (WAYLAND_xkb_state_key_get_syms(seat->keyboard.xkb.state, key + 8, &syms) != 1) {
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
sym = syms[0];
|
|
sym = syms[0];
|
|
@@ -1826,8 +1891,8 @@ static bool keyboard_input_get_text(char text[8], const struct SDL_WaylandInput
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
- if (input->xkb.compose_state && WAYLAND_xkb_compose_state_feed(input->xkb.compose_state, sym) == XKB_COMPOSE_FEED_ACCEPTED) {
|
|
|
|
- switch (WAYLAND_xkb_compose_state_get_status(input->xkb.compose_state)) {
|
|
|
|
|
|
+ if (seat->keyboard.xkb.compose_state && WAYLAND_xkb_compose_state_feed(seat->keyboard.xkb.compose_state, sym) == XKB_COMPOSE_FEED_ACCEPTED) {
|
|
|
|
+ switch (WAYLAND_xkb_compose_state_get_status(seat->keyboard.xkb.compose_state)) {
|
|
case XKB_COMPOSE_COMPOSING:
|
|
case XKB_COMPOSE_COMPOSING:
|
|
if (handled_by_ime) {
|
|
if (handled_by_ime) {
|
|
*handled_by_ime = true;
|
|
*handled_by_ime = true;
|
|
@@ -1840,7 +1905,7 @@ static bool keyboard_input_get_text(char text[8], const struct SDL_WaylandInput
|
|
case XKB_COMPOSE_NOTHING:
|
|
case XKB_COMPOSE_NOTHING:
|
|
break;
|
|
break;
|
|
case XKB_COMPOSE_COMPOSED:
|
|
case XKB_COMPOSE_COMPOSED:
|
|
- sym = WAYLAND_xkb_compose_state_get_one_sym(input->xkb.compose_state);
|
|
|
|
|
|
+ sym = WAYLAND_xkb_compose_state_get_one_sym(seat->keyboard.xkb.compose_state);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1852,38 +1917,43 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
|
|
uint32_t serial, uint32_t time, uint32_t key,
|
|
uint32_t serial, uint32_t time, uint32_t key,
|
|
uint32_t state_w)
|
|
uint32_t state_w)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = data;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = data;
|
|
enum wl_keyboard_key_state state = state_w;
|
|
enum wl_keyboard_key_state state = state_w;
|
|
char text[8];
|
|
char text[8];
|
|
bool has_text = false;
|
|
bool has_text = false;
|
|
bool handled_by_ime = false;
|
|
bool handled_by_ime = false;
|
|
- const Uint64 timestamp_raw_ns = Wayland_GetKeyboardTimestampRaw(input, time);
|
|
|
|
|
|
+ const Uint64 timestamp_raw_ns = Wayland_GetKeyboardTimestampRaw(seat, time);
|
|
|
|
|
|
- Wayland_UpdateImplicitGrabSerial(input, serial);
|
|
|
|
|
|
+ Wayland_UpdateImplicitGrabSerial(seat, serial);
|
|
|
|
+
|
|
|
|
+ if (seat->keyboard.sdl_keymap != SDL_GetCurrentKeymap()) {
|
|
|
|
+ SDL_SetKeymap(seat->keyboard.sdl_keymap, true);
|
|
|
|
+ SDL_SetModState(seat->keyboard.pressed_modifiers | seat->keyboard.locked_modifiers);
|
|
|
|
+ }
|
|
|
|
|
|
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
|
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
|
SDL_Window *keyboard_focus = SDL_GetKeyboardFocus();
|
|
SDL_Window *keyboard_focus = SDL_GetKeyboardFocus();
|
|
if (keyboard_focus && SDL_TextInputActive(keyboard_focus)) {
|
|
if (keyboard_focus && SDL_TextInputActive(keyboard_focus)) {
|
|
- has_text = keyboard_input_get_text(text, input, key, true, &handled_by_ime);
|
|
|
|
|
|
+ has_text = keyboard_input_get_text(text, seat, key, true, &handled_by_ime);
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
- if (keyboard_repeat_key_is_set(&input->keyboard_repeat, key)) {
|
|
|
|
|
|
+ if (keyboard_repeat_key_is_set(&seat->keyboard.repeat, key)) {
|
|
/* Send any due key repeat events before stopping the repeat and generating the key up event.
|
|
/* Send any due key repeat events before stopping the repeat and generating the key up event.
|
|
* Compute time based on the Wayland time, as it reports when the release event happened.
|
|
* Compute time based on the Wayland time, as it reports when the release event happened.
|
|
* Using SDL_GetTicks would be wrong, as it would report when the release event is processed,
|
|
* Using SDL_GetTicks would be wrong, as it would report when the release event is processed,
|
|
* which may be off if the application hasn't pumped events for a while.
|
|
* which may be off if the application hasn't pumped events for a while.
|
|
*/
|
|
*/
|
|
- keyboard_repeat_handle(&input->keyboard_repeat, timestamp_raw_ns - input->keyboard_repeat.wl_press_time_ns);
|
|
|
|
- keyboard_repeat_clear(&input->keyboard_repeat);
|
|
|
|
|
|
+ keyboard_repeat_handle(&seat->keyboard.repeat, timestamp_raw_ns - seat->keyboard.repeat.wl_press_time_ns);
|
|
|
|
+ keyboard_repeat_clear(&seat->keyboard.repeat);
|
|
}
|
|
}
|
|
- keyboard_input_get_text(text, input, key, false, &handled_by_ime);
|
|
|
|
|
|
+ keyboard_input_get_text(text, seat, key, false, &handled_by_ime);
|
|
}
|
|
}
|
|
|
|
|
|
- const SDL_Scancode scancode = Wayland_GetScancodeForKey(input, key);
|
|
|
|
- Wayland_HandleModifierKeys(input, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED);
|
|
|
|
- Uint64 timestamp = Wayland_GetKeyboardTimestamp(input, time);
|
|
|
|
|
|
+ const SDL_Scancode scancode = Wayland_GetScancodeForKey(seat, key);
|
|
|
|
+ Wayland_HandleModifierKeys(seat, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED);
|
|
|
|
+ Uint64 timestamp = Wayland_GetKeyboardTimestamp(seat, time);
|
|
|
|
|
|
- SDL_SendKeyboardKeyIgnoreModifiers(timestamp, input->keyboard_id, key, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED);
|
|
|
|
|
|
+ SDL_SendKeyboardKeyIgnoreModifiers(timestamp, seat->keyboard.sdl_id, key, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED);
|
|
|
|
|
|
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
|
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
|
if (has_text && !(SDL_GetModState() & (SDL_KMOD_CTRL | SDL_KMOD_ALT))) {
|
|
if (has_text && !(SDL_GetModState() & (SDL_KMOD_CTRL | SDL_KMOD_ALT))) {
|
|
@@ -1891,8 +1961,8 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
|
|
SDL_SendKeyboardText(text);
|
|
SDL_SendKeyboardText(text);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- if (input->xkb.keymap && WAYLAND_xkb_keymap_key_repeats(input->xkb.keymap, key + 8)) {
|
|
|
|
- keyboard_repeat_set(&input->keyboard_repeat, input->keyboard_id, key, timestamp_raw_ns, scancode, has_text, text);
|
|
|
|
|
|
+ if (seat->keyboard.xkb.keymap && WAYLAND_xkb_keymap_key_repeats(seat->keyboard.xkb.keymap, key + 8)) {
|
|
|
|
+ keyboard_repeat_set(&seat->keyboard.repeat, seat->keyboard.sdl_id, key, timestamp_raw_ns, scancode, has_text, text);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1902,48 +1972,48 @@ static void keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
|
|
uint32_t mods_latched, uint32_t mods_locked,
|
|
uint32_t mods_latched, uint32_t mods_locked,
|
|
uint32_t group)
|
|
uint32_t group)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = data;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = data;
|
|
|
|
|
|
- if (input->xkb.state == NULL) {
|
|
|
|
|
|
+ if (seat->keyboard.xkb.state == NULL) {
|
|
/* if we get a modifier notification before the keymap, there's nothing we can do with the information
|
|
/* if we get a modifier notification before the keymap, there's nothing we can do with the information
|
|
*/
|
|
*/
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
|
|
|
|
|
|
+ WAYLAND_xkb_state_update_mask(seat->keyboard.xkb.state, mods_depressed, mods_latched,
|
|
mods_locked, 0, 0, group);
|
|
mods_locked, 0, 0, group);
|
|
|
|
|
|
- input->xkb.wl_pressed_modifiers = mods_depressed;
|
|
|
|
- input->xkb.wl_locked_modifiers = mods_latched | mods_locked;
|
|
|
|
|
|
+ seat->keyboard.xkb.wl_pressed_modifiers = mods_depressed;
|
|
|
|
+ seat->keyboard.xkb.wl_locked_modifiers = mods_latched | mods_locked;
|
|
|
|
|
|
- Wayland_ReconcileModifiers(input, false);
|
|
|
|
|
|
+ Wayland_ReconcileModifiers(seat, false);
|
|
|
|
|
|
// If a key is repeating, update the text to apply the modifier.
|
|
// If a key is repeating, update the text to apply the modifier.
|
|
- if (keyboard_repeat_is_set(&input->keyboard_repeat)) {
|
|
|
|
|
|
+ if (keyboard_repeat_is_set(&seat->keyboard.repeat)) {
|
|
char text[8];
|
|
char text[8];
|
|
- const uint32_t key = keyboard_repeat_get_key(&input->keyboard_repeat);
|
|
|
|
|
|
+ const uint32_t key = keyboard_repeat_get_key(&seat->keyboard.repeat);
|
|
|
|
|
|
- if (keyboard_input_get_text(text, input, key, true, NULL)) {
|
|
|
|
- keyboard_repeat_set_text(&input->keyboard_repeat, text);
|
|
|
|
|
|
+ if (keyboard_input_get_text(text, seat, key, true, NULL)) {
|
|
|
|
+ keyboard_repeat_set_text(&seat->keyboard.repeat, text);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- if (group == input->xkb.current_group) {
|
|
|
|
|
|
+ if (group == seat->keyboard.xkb.current_group) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
// The layout changed, remap and fire an event. Virtual keyboards use the default keymap.
|
|
// The layout changed, remap and fire an event. Virtual keyboards use the default keymap.
|
|
- input->xkb.current_group = group;
|
|
|
|
- Wayland_UpdateKeymap(input);
|
|
|
|
|
|
+ seat->keyboard.xkb.current_group = group;
|
|
|
|
+ Wayland_UpdateKeymap(seat);
|
|
}
|
|
}
|
|
|
|
|
|
static void keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
|
|
static void keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
|
|
int32_t rate, int32_t delay)
|
|
int32_t rate, int32_t delay)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = data;
|
|
|
|
- input->keyboard_repeat.repeat_rate = SDL_clamp(rate, 0, 1000);
|
|
|
|
- input->keyboard_repeat.repeat_delay_ms = delay;
|
|
|
|
- input->keyboard_repeat.is_initialized = true;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = data;
|
|
|
|
+ seat->keyboard.repeat.repeat_rate = SDL_clamp(rate, 0, 1000);
|
|
|
|
+ seat->keyboard.repeat.repeat_delay_ms = delay;
|
|
|
|
+ seat->keyboard.repeat.is_initialized = true;
|
|
}
|
|
}
|
|
|
|
|
|
static const struct wl_keyboard_listener keyboard_listener = {
|
|
static const struct wl_keyboard_listener keyboard_listener = {
|
|
@@ -1955,96 +2025,243 @@ static const struct wl_keyboard_listener keyboard_listener = {
|
|
keyboard_handle_repeat_info, // Version 4
|
|
keyboard_handle_repeat_info, // Version 4
|
|
};
|
|
};
|
|
|
|
|
|
-void Wayland_input_init_relative_pointer(SDL_VideoData *d)
|
|
|
|
|
|
+static void Wayland_SeatCreateRelativePointer(SDL_WaylandSeat *seat)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = d->input;
|
|
|
|
|
|
+ if (seat->display->relative_pointer_manager) {
|
|
|
|
+ if (seat->pointer.wl_pointer && !seat->pointer.relative_pointer) {
|
|
|
|
+ seat->pointer.relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(seat->display->relative_pointer_manager, seat->pointer.wl_pointer);
|
|
|
|
+ zwp_relative_pointer_v1_add_listener(seat->pointer.relative_pointer,
|
|
|
|
+ &relative_pointer_listener,
|
|
|
|
+ seat);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
- if (!d->relative_pointer_manager) {
|
|
|
|
- return;
|
|
|
|
|
|
+void Wayland_DisplayInitRelativePointerManager(SDL_VideoData *display)
|
|
|
|
+{
|
|
|
|
+ SDL_WaylandSeat *seat;
|
|
|
|
+ wl_list_for_each(seat, &display->seat_list, link) {
|
|
|
|
+ Wayland_SeatCreateRelativePointer(seat);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void Wayland_SeatDestroyPointer(SDL_WaylandSeat *seat, bool send_event)
|
|
|
|
+{
|
|
|
|
+ // Make sure focus is removed from a surface before the pointer is destroyed.
|
|
|
|
+ if (seat->pointer.focus) {
|
|
|
|
+ pointer_handle_leave(seat, seat->pointer.wl_pointer, 0, seat->pointer.focus->surface);
|
|
}
|
|
}
|
|
|
|
|
|
- if (input->pointer && !input->relative_pointer) {
|
|
|
|
- input->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(input->display->relative_pointer_manager, input->pointer);
|
|
|
|
- zwp_relative_pointer_v1_add_listener(input->relative_pointer,
|
|
|
|
- &relative_pointer_listener,
|
|
|
|
- input);
|
|
|
|
|
|
+ SDL_RemoveMouse(seat->pointer.sdl_id, send_event);
|
|
|
|
+
|
|
|
|
+ if (seat->pointer.confined_pointer) {
|
|
|
|
+ zwp_confined_pointer_v1_destroy(seat->pointer.confined_pointer);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (seat->pointer.locked_pointer) {
|
|
|
|
+ zwp_locked_pointer_v1_destroy(seat->pointer.locked_pointer);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (seat->pointer.relative_pointer) {
|
|
|
|
+ zwp_relative_pointer_v1_destroy(seat->pointer.relative_pointer);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (seat->pointer.timestamps) {
|
|
|
|
+ zwp_input_timestamps_v1_destroy(seat->pointer.timestamps);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (seat->pointer.cursor_state.frame_callback) {
|
|
|
|
+ wl_callback_destroy(seat->pointer.cursor_state.frame_callback);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (seat->pointer.cursor_state.surface) {
|
|
|
|
+ wl_surface_destroy(seat->pointer.cursor_state.surface);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ if (seat->pointer.cursor_state.viewport) {
|
|
|
|
+ wp_viewport_destroy(seat->pointer.cursor_state.viewport);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (seat->pointer.cursor_shape) {
|
|
|
|
+ wp_cursor_shape_device_v1_destroy(seat->pointer.cursor_shape);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (seat->pointer.wl_pointer) {
|
|
|
|
+ if (wl_pointer_get_version(seat->pointer.wl_pointer) >= WL_POINTER_RELEASE_SINCE_VERSION) {
|
|
|
|
+ wl_pointer_release(seat->pointer.wl_pointer);
|
|
|
|
+ } else {
|
|
|
|
+ wl_pointer_destroy(seat->pointer.wl_pointer);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ SDL_zero(seat->pointer);
|
|
}
|
|
}
|
|
|
|
|
|
-static void seat_handle_capabilities(void *data, struct wl_seat *seat,
|
|
|
|
- enum wl_seat_capability caps)
|
|
|
|
|
|
+static void Wayland_SeatDestroyKeyboard(SDL_WaylandSeat *seat, bool send_event)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = data;
|
|
|
|
|
|
+ // Make sure focus is removed from a surface before the keyboard is destroyed.
|
|
|
|
+ if (seat->keyboard.focus) {
|
|
|
|
+ keyboard_handle_leave(seat, seat->keyboard.wl_keyboard, 0, seat->keyboard.focus->surface);
|
|
|
|
+ }
|
|
|
|
|
|
- if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
|
|
|
|
- input->pointer = wl_seat_get_pointer(seat);
|
|
|
|
- SDL_memset(&input->pointer_curr_axis_info, 0, sizeof(input->pointer_curr_axis_info));
|
|
|
|
- input->display->pointer = input->pointer;
|
|
|
|
|
|
+ SDL_RemoveKeyboard(seat->keyboard.sdl_id, send_event);
|
|
|
|
|
|
- Wayland_CreateCursorShapeDevice(input);
|
|
|
|
|
|
+ if (seat->keyboard.sdl_keymap) {
|
|
|
|
+ if (seat->keyboard.sdl_keymap == SDL_GetCurrentKeymap()) {
|
|
|
|
+ SDL_SetKeymap(NULL, false);
|
|
|
|
+ }
|
|
|
|
+ SDL_DestroyKeymap(seat->keyboard.sdl_keymap);
|
|
|
|
+ }
|
|
|
|
|
|
- wl_pointer_set_user_data(input->pointer, input);
|
|
|
|
- wl_pointer_add_listener(input->pointer, &pointer_listener, input);
|
|
|
|
|
|
+ if (seat->keyboard.key_inhibitor) {
|
|
|
|
+ zwp_keyboard_shortcuts_inhibitor_v1_destroy(seat->keyboard.key_inhibitor);
|
|
|
|
+ }
|
|
|
|
|
|
- Wayland_input_init_relative_pointer(input->display);
|
|
|
|
|
|
+ if (seat->keyboard.timestamps) {
|
|
|
|
+ zwp_input_timestamps_v1_destroy(seat->keyboard.timestamps);
|
|
|
|
+ }
|
|
|
|
|
|
- input->pointer_id = SDL_GetNextObjectID();
|
|
|
|
- SDL_AddMouse(input->pointer_id, WAYLAND_DEFAULT_POINTER_NAME, !input->display->initializing);
|
|
|
|
- } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
|
|
|
|
- if (input->relative_pointer) {
|
|
|
|
- zwp_relative_pointer_v1_destroy(input->relative_pointer);
|
|
|
|
- input->relative_pointer = NULL;
|
|
|
|
|
|
+ if (seat->keyboard.wl_keyboard) {
|
|
|
|
+ if (wl_keyboard_get_version(seat->keyboard.wl_keyboard) >= WL_KEYBOARD_RELEASE_SINCE_VERSION) {
|
|
|
|
+ wl_keyboard_release(seat->keyboard.wl_keyboard);
|
|
|
|
+ } else {
|
|
|
|
+ wl_keyboard_destroy(seat->keyboard.wl_keyboard);
|
|
}
|
|
}
|
|
- if (input->cursor_shape) {
|
|
|
|
- wp_cursor_shape_device_v1_destroy(input->cursor_shape);
|
|
|
|
- input->cursor_shape = NULL;
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (seat->keyboard.xkb.compose_state) {
|
|
|
|
+ WAYLAND_xkb_compose_state_unref(seat->keyboard.xkb.compose_state);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (seat->keyboard.xkb.compose_table) {
|
|
|
|
+ WAYLAND_xkb_compose_table_unref(seat->keyboard.xkb.compose_table);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (seat->keyboard.xkb.state) {
|
|
|
|
+ WAYLAND_xkb_state_unref(seat->keyboard.xkb.state);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (seat->keyboard.xkb.keymap) {
|
|
|
|
+ WAYLAND_xkb_keymap_unref(seat->keyboard.xkb.keymap);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ SDL_zero(seat->keyboard);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void Wayland_SeatDestroyTouch(SDL_WaylandSeat *seat)
|
|
|
|
+{
|
|
|
|
+ // Cancel any active touches before the touch object is destroyed.
|
|
|
|
+ if (seat->touch.wl_touch) {
|
|
|
|
+ touch_handler_cancel(seat, seat->touch.wl_touch);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ SDL_DelTouch((SDL_TouchID)(uintptr_t)seat->touch.wl_touch);
|
|
|
|
+
|
|
|
|
+ if (seat->touch.timestamps) {
|
|
|
|
+ zwp_input_timestamps_v1_destroy(seat->touch.timestamps);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (seat->touch.wl_touch) {
|
|
|
|
+ if (wl_touch_get_version(seat->touch.wl_touch) >= WL_TOUCH_RELEASE_SINCE_VERSION) {
|
|
|
|
+ wl_touch_release(seat->touch.wl_touch);
|
|
|
|
+ } else {
|
|
|
|
+ wl_touch_destroy(seat->touch.wl_touch);
|
|
}
|
|
}
|
|
- if (wl_pointer_get_version(input->pointer) >= WL_POINTER_RELEASE_SINCE_VERSION) {
|
|
|
|
- wl_pointer_release(input->pointer);
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ SDL_zero(seat->touch);
|
|
|
|
+ WAYLAND_wl_list_init(&seat->touch.points);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, enum wl_seat_capability capabilities)
|
|
|
|
+{
|
|
|
|
+ SDL_WaylandSeat *seat = (SDL_WaylandSeat *)data;
|
|
|
|
+ char name_fmt[256];
|
|
|
|
+
|
|
|
|
+ if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && !seat->pointer.wl_pointer) {
|
|
|
|
+ seat->pointer.wl_pointer = wl_seat_get_pointer(wl_seat);
|
|
|
|
+ SDL_memset(&seat->pointer.current_axis_info, 0, sizeof(seat->pointer.current_axis_info));
|
|
|
|
+
|
|
|
|
+ Wayland_SeatCreateCursorShape(seat);
|
|
|
|
+
|
|
|
|
+ wl_pointer_set_user_data(seat->pointer.wl_pointer, seat);
|
|
|
|
+ wl_pointer_add_listener(seat->pointer.wl_pointer, &pointer_listener, seat);
|
|
|
|
+
|
|
|
|
+ Wayland_SeatCreateRelativePointer(seat);
|
|
|
|
+
|
|
|
|
+ seat->pointer.sdl_id = SDL_GetNextObjectID();
|
|
|
|
+
|
|
|
|
+ if (seat->name) {
|
|
|
|
+ SDL_snprintf(name_fmt, sizeof(name_fmt), "%s (%s)", WAYLAND_DEFAULT_POINTER_NAME, seat->name);
|
|
} else {
|
|
} else {
|
|
- wl_pointer_destroy(input->pointer);
|
|
|
|
|
|
+ SDL_snprintf(name_fmt, sizeof(name_fmt), "%s %" SDL_PRIu32, WAYLAND_DEFAULT_POINTER_NAME, seat->pointer.sdl_id);
|
|
}
|
|
}
|
|
- input->pointer = NULL;
|
|
|
|
- input->display->pointer = NULL;
|
|
|
|
|
|
|
|
- SDL_RemoveMouse(input->pointer_id, true);
|
|
|
|
- input->pointer_id = 0;
|
|
|
|
|
|
+ SDL_AddMouse(seat->pointer.sdl_id, name_fmt, !seat->display->initializing);
|
|
|
|
+ } else if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && seat->pointer.wl_pointer) {
|
|
|
|
+ Wayland_SeatDestroyPointer(seat, true);
|
|
}
|
|
}
|
|
|
|
|
|
- if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) {
|
|
|
|
- input->touch = wl_seat_get_touch(seat);
|
|
|
|
- SDL_AddTouch((SDL_TouchID)(uintptr_t)input->touch, SDL_TOUCH_DEVICE_DIRECT, "wayland_touch");
|
|
|
|
- wl_touch_set_user_data(input->touch, input);
|
|
|
|
- wl_touch_add_listener(input->touch, &touch_listener,
|
|
|
|
- input);
|
|
|
|
- } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) {
|
|
|
|
- SDL_DelTouch((SDL_TouchID)(intptr_t)input->touch);
|
|
|
|
- wl_touch_destroy(input->touch);
|
|
|
|
- input->touch = NULL;
|
|
|
|
|
|
+ if ((capabilities & WL_SEAT_CAPABILITY_TOUCH) && !seat->touch.wl_touch) {
|
|
|
|
+ seat->touch.wl_touch = wl_seat_get_touch(wl_seat);
|
|
|
|
+ wl_touch_set_user_data(seat->touch.wl_touch, seat);
|
|
|
|
+ wl_touch_add_listener(seat->touch.wl_touch, &touch_listener, seat);
|
|
|
|
+
|
|
|
|
+ if (seat->name) {
|
|
|
|
+ SDL_snprintf(name_fmt, sizeof(name_fmt), "%s (%s)", WAYLAND_DEFAULT_TOUCH_NAME, seat->name);
|
|
|
|
+ } else {
|
|
|
|
+ SDL_snprintf(name_fmt, sizeof(name_fmt), "%s %" SDL_PRIu64, WAYLAND_DEFAULT_TOUCH_NAME, (SDL_TouchID)(uintptr_t)seat->touch.wl_touch);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ SDL_AddTouch((SDL_TouchID)(uintptr_t)seat->touch.wl_touch, SDL_TOUCH_DEVICE_DIRECT, name_fmt);
|
|
|
|
+ } else if (!(capabilities & WL_SEAT_CAPABILITY_TOUCH) && seat->touch.wl_touch) {
|
|
|
|
+ Wayland_SeatDestroyTouch(seat);
|
|
}
|
|
}
|
|
|
|
|
|
- if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
|
|
|
|
- input->keyboard = wl_seat_get_keyboard(seat);
|
|
|
|
- wl_keyboard_set_user_data(input->keyboard, input);
|
|
|
|
- wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
|
|
|
|
- input);
|
|
|
|
|
|
+ if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && !seat->keyboard.wl_keyboard) {
|
|
|
|
+ seat->keyboard.wl_keyboard = wl_seat_get_keyboard(wl_seat);
|
|
|
|
+ wl_keyboard_set_user_data(seat->keyboard.wl_keyboard, seat);
|
|
|
|
+ wl_keyboard_add_listener(seat->keyboard.wl_keyboard, &keyboard_listener, seat);
|
|
|
|
+
|
|
|
|
+ seat->keyboard.sdl_id = SDL_GetNextObjectID();
|
|
|
|
|
|
- input->keyboard_id = SDL_GetNextObjectID();
|
|
|
|
- SDL_AddKeyboard(input->keyboard_id, WAYLAND_DEFAULT_KEYBOARD_NAME, !input->display->initializing);
|
|
|
|
- } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
|
|
|
|
- wl_keyboard_destroy(input->keyboard);
|
|
|
|
- input->keyboard = NULL;
|
|
|
|
|
|
+ if (seat->name) {
|
|
|
|
+ SDL_snprintf(name_fmt, sizeof(name_fmt), "%s (%s)", WAYLAND_DEFAULT_KEYBOARD_NAME, seat->name);
|
|
|
|
+ } else {
|
|
|
|
+ SDL_snprintf(name_fmt, sizeof(name_fmt), "%s %" SDL_PRIu32, WAYLAND_DEFAULT_KEYBOARD_NAME, seat->keyboard.sdl_id);
|
|
|
|
+ }
|
|
|
|
|
|
- SDL_RemoveKeyboard(input->keyboard_id, true);
|
|
|
|
- input->keyboard_id = 0;
|
|
|
|
|
|
+ SDL_AddKeyboard(seat->keyboard.sdl_id, name_fmt, !seat->display->initializing);
|
|
|
|
+ } else if (!(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && seat->keyboard.wl_keyboard) {
|
|
|
|
+ Wayland_SeatDestroyKeyboard(seat, true);
|
|
}
|
|
}
|
|
|
|
|
|
- Wayland_RegisterTimestampListeners(input);
|
|
|
|
|
|
+ Wayland_SeatRegisterInputTimestampListeners(seat);
|
|
}
|
|
}
|
|
|
|
|
|
static void seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name)
|
|
static void seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name)
|
|
{
|
|
{
|
|
- // unimplemented
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = (SDL_WaylandSeat *)data;
|
|
|
|
+ char name_fmt[256];
|
|
|
|
+
|
|
|
|
+ if (name && *name != '\0') {
|
|
|
|
+ seat->name = SDL_strdup(name);
|
|
|
|
+
|
|
|
|
+ if (seat->keyboard.wl_keyboard) {
|
|
|
|
+ SDL_snprintf(name_fmt, sizeof(name_fmt), "%s (%s)", WAYLAND_DEFAULT_KEYBOARD_NAME, seat->name);
|
|
|
|
+ SDL_SetKeyboardName(seat->keyboard.sdl_id, name_fmt);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (seat->pointer.wl_pointer) {
|
|
|
|
+ SDL_snprintf(name_fmt, sizeof(name_fmt), "%s (%s)", WAYLAND_DEFAULT_POINTER_NAME, seat->name);
|
|
|
|
+ SDL_SetMouseName(seat->pointer.sdl_id, name_fmt);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (seat->touch.wl_touch) {
|
|
|
|
+ SDL_snprintf(name_fmt, sizeof(name_fmt), "%s (%s)", WAYLAND_DEFAULT_TOUCH_NAME, seat->name);
|
|
|
|
+ SDL_SetTouchName((SDL_TouchID)(uintptr_t)seat->touch.wl_touch, name_fmt);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
static const struct wl_seat_listener seat_listener = {
|
|
static const struct wl_seat_listener seat_listener = {
|
|
@@ -2230,8 +2447,10 @@ static void data_device_handle_data_offer(void *data, struct wl_data_device *wl_
|
|
{
|
|
{
|
|
SDL_WaylandDataOffer *data_offer = SDL_calloc(1, sizeof(*data_offer));
|
|
SDL_WaylandDataOffer *data_offer = SDL_calloc(1, sizeof(*data_offer));
|
|
if (data_offer) {
|
|
if (data_offer) {
|
|
|
|
+ SDL_WaylandDataDevice *data_device = (SDL_WaylandDataDevice *)data;
|
|
|
|
+ data_device->seat->display->last_incoming_data_offer_seat = data_device->seat;
|
|
data_offer->offer = id;
|
|
data_offer->offer = id;
|
|
- data_offer->data_device = data;
|
|
|
|
|
|
+ data_offer->data_device = data_device;
|
|
WAYLAND_wl_list_init(&(data_offer->mimes));
|
|
WAYLAND_wl_list_init(&(data_offer->mimes));
|
|
wl_data_offer_set_user_data(id, data_offer);
|
|
wl_data_offer_set_user_data(id, data_offer);
|
|
wl_data_offer_add_listener(id, &data_offer_listener, data_offer);
|
|
wl_data_offer_add_listener(id, &data_offer_listener, data_offer);
|
|
@@ -2543,8 +2762,10 @@ static void primary_selection_device_handle_offer(void *data, struct zwp_primary
|
|
{
|
|
{
|
|
SDL_WaylandPrimarySelectionOffer *primary_selection_offer = SDL_calloc(1, sizeof(*primary_selection_offer));
|
|
SDL_WaylandPrimarySelectionOffer *primary_selection_offer = SDL_calloc(1, sizeof(*primary_selection_offer));
|
|
if (primary_selection_offer) {
|
|
if (primary_selection_offer) {
|
|
|
|
+ SDL_WaylandPrimarySelectionDevice *primary_selection_device = (SDL_WaylandPrimarySelectionDevice *)data;
|
|
|
|
+ primary_selection_device->seat->display->last_incoming_primary_selection_seat = primary_selection_device->seat;
|
|
primary_selection_offer->offer = id;
|
|
primary_selection_offer->offer = id;
|
|
- primary_selection_offer->primary_selection_device = data;
|
|
|
|
|
|
+ primary_selection_offer->primary_selection_device = primary_selection_device;
|
|
WAYLAND_wl_list_init(&(primary_selection_offer->mimes));
|
|
WAYLAND_wl_list_init(&(primary_selection_offer->mimes));
|
|
zwp_primary_selection_offer_v1_set_user_data(id, primary_selection_offer);
|
|
zwp_primary_selection_offer_v1_set_user_data(id, primary_selection_offer);
|
|
zwp_primary_selection_offer_v1_add_listener(id, &primary_selection_offer_listener, primary_selection_offer);
|
|
zwp_primary_selection_offer_v1_add_listener(id, &primary_selection_offer_listener, primary_selection_offer);
|
|
@@ -2598,8 +2819,8 @@ static void text_input_preedit_string(void *data,
|
|
int32_t cursor_begin,
|
|
int32_t cursor_begin,
|
|
int32_t cursor_end)
|
|
int32_t cursor_end)
|
|
{
|
|
{
|
|
- SDL_WaylandTextInput *text_input = data;
|
|
|
|
- text_input->has_preedit = true;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = (SDL_WaylandSeat *)data;
|
|
|
|
+ seat->text_input.has_preedit = true;
|
|
if (text) {
|
|
if (text) {
|
|
int cursor_begin_utf8 = cursor_begin >= 0 ? (int)SDL_utf8strnlen(text, cursor_begin) : -1;
|
|
int cursor_begin_utf8 = cursor_begin >= 0 ? (int)SDL_utf8strnlen(text, cursor_begin) : -1;
|
|
int cursor_end_utf8 = cursor_end >= 0 ? (int)SDL_utf8strnlen(text, cursor_end) : -1;
|
|
int cursor_end_utf8 = cursor_end >= 0 ? (int)SDL_utf8strnlen(text, cursor_end) : -1;
|
|
@@ -2638,11 +2859,11 @@ static void text_input_done(void *data,
|
|
struct zwp_text_input_v3 *zwp_text_input_v3,
|
|
struct zwp_text_input_v3 *zwp_text_input_v3,
|
|
uint32_t serial)
|
|
uint32_t serial)
|
|
{
|
|
{
|
|
- SDL_WaylandTextInput *text_input = data;
|
|
|
|
- if (!text_input->has_preedit) {
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = (SDL_WaylandSeat *)data;
|
|
|
|
+ if (!seat->text_input.has_preedit) {
|
|
SDL_SendEditingText("", 0, 0);
|
|
SDL_SendEditingText("", 0, 0);
|
|
}
|
|
}
|
|
- text_input->has_preedit = false;
|
|
|
|
|
|
+ seat->text_input.has_preedit = false;
|
|
}
|
|
}
|
|
|
|
|
|
static const struct zwp_text_input_v3_listener text_input_listener = {
|
|
static const struct zwp_text_input_v3_listener text_input_listener = {
|
|
@@ -2654,23 +2875,20 @@ static const struct zwp_text_input_v3_listener text_input_listener = {
|
|
text_input_done
|
|
text_input_done
|
|
};
|
|
};
|
|
|
|
|
|
-void Wayland_create_data_device(SDL_VideoData *d)
|
|
|
|
|
|
+static void Wayland_SeatCreateDataDevice(SDL_WaylandSeat *seat)
|
|
{
|
|
{
|
|
- SDL_WaylandDataDevice *data_device = NULL;
|
|
|
|
-
|
|
|
|
- if (!d->input->seat) {
|
|
|
|
- // No seat yet, will be initialized later.
|
|
|
|
|
|
+ if (!seat->display->data_device_manager) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- data_device = SDL_calloc(1, sizeof(*data_device));
|
|
|
|
|
|
+ SDL_WaylandDataDevice *data_device = SDL_calloc(1, sizeof(*data_device));
|
|
if (!data_device) {
|
|
if (!data_device) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
data_device->data_device = wl_data_device_manager_get_data_device(
|
|
data_device->data_device = wl_data_device_manager_get_data_device(
|
|
- d->data_device_manager, d->input->seat);
|
|
|
|
- data_device->video_data = d;
|
|
|
|
|
|
+ seat->display->data_device_manager, seat->wl_seat);
|
|
|
|
+ data_device->seat = seat;
|
|
|
|
|
|
if (!data_device->data_device) {
|
|
if (!data_device->data_device) {
|
|
SDL_free(data_device);
|
|
SDL_free(data_device);
|
|
@@ -2678,27 +2896,32 @@ void Wayland_create_data_device(SDL_VideoData *d)
|
|
wl_data_device_set_user_data(data_device->data_device, data_device);
|
|
wl_data_device_set_user_data(data_device->data_device, data_device);
|
|
wl_data_device_add_listener(data_device->data_device,
|
|
wl_data_device_add_listener(data_device->data_device,
|
|
&data_device_listener, data_device);
|
|
&data_device_listener, data_device);
|
|
- d->input->data_device = data_device;
|
|
|
|
|
|
+ seat->data_device = data_device;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-void Wayland_create_primary_selection_device(SDL_VideoData *d)
|
|
|
|
|
|
+void Wayland_DisplayInitDataDeviceManager(SDL_VideoData *display)
|
|
{
|
|
{
|
|
- SDL_WaylandPrimarySelectionDevice *primary_selection_device = NULL;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat;
|
|
|
|
+ wl_list_for_each (seat, &display->seat_list, link) {
|
|
|
|
+ Wayland_SeatCreateDataDevice(seat);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
- if (!d->input->seat) {
|
|
|
|
- // No seat yet, will be initialized later.
|
|
|
|
|
|
+static void Wayland_SeatCreatePrimarySelectionDevice(SDL_WaylandSeat *seat)
|
|
|
|
+{
|
|
|
|
+ if (!seat->display->primary_selection_device_manager) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- primary_selection_device = SDL_calloc(1, sizeof(*primary_selection_device));
|
|
|
|
|
|
+ SDL_WaylandPrimarySelectionDevice *primary_selection_device = SDL_calloc(1, sizeof(*primary_selection_device));
|
|
if (!primary_selection_device) {
|
|
if (!primary_selection_device) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
primary_selection_device->primary_selection_device = zwp_primary_selection_device_manager_v1_get_device(
|
|
primary_selection_device->primary_selection_device = zwp_primary_selection_device_manager_v1_get_device(
|
|
- d->primary_selection_device_manager, d->input->seat);
|
|
|
|
- primary_selection_device->video_data = d;
|
|
|
|
|
|
+ seat->display->primary_selection_device_manager, seat->wl_seat);
|
|
|
|
+ primary_selection_device->seat = seat;
|
|
|
|
|
|
if (!primary_selection_device->primary_selection_device) {
|
|
if (!primary_selection_device->primary_selection_device) {
|
|
SDL_free(primary_selection_device);
|
|
SDL_free(primary_selection_device);
|
|
@@ -2707,38 +2930,32 @@ void Wayland_create_primary_selection_device(SDL_VideoData *d)
|
|
primary_selection_device);
|
|
primary_selection_device);
|
|
zwp_primary_selection_device_v1_add_listener(primary_selection_device->primary_selection_device,
|
|
zwp_primary_selection_device_v1_add_listener(primary_selection_device->primary_selection_device,
|
|
&primary_selection_device_listener, primary_selection_device);
|
|
&primary_selection_device_listener, primary_selection_device);
|
|
- d->input->primary_selection_device = primary_selection_device;
|
|
|
|
|
|
+ seat->primary_selection_device = primary_selection_device;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static void Wayland_create_text_input(SDL_VideoData *d)
|
|
|
|
|
|
+void Wayland_DisplayInitPrimarySelectionDeviceManager(SDL_VideoData *display)
|
|
{
|
|
{
|
|
- SDL_WaylandTextInput *text_input = NULL;
|
|
|
|
-
|
|
|
|
- if (!d->input->seat) {
|
|
|
|
- // No seat yet, will be initialized later.
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- text_input = SDL_calloc(1, sizeof(*text_input));
|
|
|
|
- if (!text_input) {
|
|
|
|
- return;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat;
|
|
|
|
+ wl_list_for_each (seat, &display->seat_list, link) {
|
|
|
|
+ Wayland_SeatCreatePrimarySelectionDevice(seat);
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
|
|
- text_input->text_input = zwp_text_input_manager_v3_get_text_input(
|
|
|
|
- d->text_input_manager, d->input->seat);
|
|
|
|
|
|
+static void Wayland_SeatCreateTextInput(SDL_WaylandSeat *seat)
|
|
|
|
+{
|
|
|
|
+ if (seat->display->text_input_manager) {
|
|
|
|
+ seat->text_input.zwp_text_input = zwp_text_input_manager_v3_get_text_input(seat->display->text_input_manager, seat->wl_seat);
|
|
|
|
|
|
- if (!text_input->text_input) {
|
|
|
|
- SDL_free(text_input);
|
|
|
|
- } else {
|
|
|
|
- zwp_text_input_v3_set_user_data(text_input->text_input, text_input);
|
|
|
|
- zwp_text_input_v3_add_listener(text_input->text_input,
|
|
|
|
- &text_input_listener, text_input);
|
|
|
|
- d->input->text_input = text_input;
|
|
|
|
|
|
+ if (seat->text_input.zwp_text_input) {
|
|
|
|
+ zwp_text_input_v3_set_user_data(seat->text_input.zwp_text_input, seat);
|
|
|
|
+ zwp_text_input_v3_add_listener(seat->text_input.zwp_text_input,
|
|
|
|
+ &text_input_listener, seat);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-void Wayland_create_text_input_manager(SDL_VideoData *d, uint32_t id)
|
|
|
|
|
|
+void Wayland_DisplayCreateTextInputManager(SDL_VideoData *d, uint32_t id)
|
|
{
|
|
{
|
|
#ifdef HAVE_FCITX
|
|
#ifdef HAVE_FCITX
|
|
const char *im_module = SDL_getenv("SDL_IM_MODULE");
|
|
const char *im_module = SDL_getenv("SDL_IM_MODULE");
|
|
@@ -2753,7 +2970,11 @@ void Wayland_create_text_input_manager(SDL_VideoData *d, uint32_t id)
|
|
#endif
|
|
#endif
|
|
|
|
|
|
d->text_input_manager = wl_registry_bind(d->registry, id, &zwp_text_input_manager_v3_interface, 1);
|
|
d->text_input_manager = wl_registry_bind(d->registry, id, &zwp_text_input_manager_v3_interface, 1);
|
|
- Wayland_create_text_input(d);
|
|
|
|
|
|
+
|
|
|
|
+ SDL_WaylandSeat *seat;
|
|
|
|
+ wl_list_for_each(seat, &d->seat_list, link) {
|
|
|
|
+ Wayland_SeatCreateTextInput(seat);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
// Pen/Tablet support...
|
|
// Pen/Tablet support...
|
|
@@ -2771,6 +2992,7 @@ typedef struct SDL_WaylandPenTool // a stylus, etc, on a tablet.
|
|
Uint32 frame_axes_set;
|
|
Uint32 frame_axes_set;
|
|
int frame_pen_down;
|
|
int frame_pen_down;
|
|
int frame_buttons[3];
|
|
int frame_buttons[3];
|
|
|
|
+ struct wl_list link;
|
|
} SDL_WaylandPenTool;
|
|
} SDL_WaylandPenTool;
|
|
|
|
|
|
static void tablet_tool_handle_type(void *data, struct zwp_tablet_tool_v2 *tool, uint32_t type)
|
|
static void tablet_tool_handle_type(void *data, struct zwp_tablet_tool_v2 *tool, uint32_t type)
|
|
@@ -2825,6 +3047,7 @@ static void tablet_tool_handle_removed(void *data, struct zwp_tablet_tool_v2 *to
|
|
SDL_RemovePenDevice(0, sdltool->instance_id);
|
|
SDL_RemovePenDevice(0, sdltool->instance_id);
|
|
}
|
|
}
|
|
zwp_tablet_tool_v2_destroy(tool);
|
|
zwp_tablet_tool_v2_destroy(tool);
|
|
|
|
+ WAYLAND_wl_list_remove(&sdltool->link);
|
|
SDL_free(sdltool);
|
|
SDL_free(sdltool);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -3025,13 +3248,14 @@ static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = {
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
-static void tablet_seat_handle_tablet_added(void *data, struct zwp_tablet_seat_v2 *seat, struct zwp_tablet_v2 *tablet)
|
|
|
|
|
|
+static void tablet_seat_handle_tablet_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_v2 *tablet)
|
|
{
|
|
{
|
|
// don't care atm.
|
|
// don't care atm.
|
|
}
|
|
}
|
|
|
|
|
|
-static void tablet_seat_handle_tool_added(void *data, struct zwp_tablet_seat_v2 *seat, struct zwp_tablet_tool_v2 *tool)
|
|
|
|
|
|
+static void tablet_seat_handle_tool_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_tool_v2 *tool)
|
|
{
|
|
{
|
|
|
|
+ SDL_WaylandSeat *seat = (SDL_WaylandSeat *)data;
|
|
SDL_WaylandPenTool *sdltool = SDL_calloc(1, sizeof(*sdltool));
|
|
SDL_WaylandPenTool *sdltool = SDL_calloc(1, sizeof(*sdltool));
|
|
|
|
|
|
if (sdltool) { // if allocation failed, oh well, we won't report this device.
|
|
if (sdltool) { // if allocation failed, oh well, we won't report this device.
|
|
@@ -3042,6 +3266,7 @@ static void tablet_seat_handle_tool_added(void *data, struct zwp_tablet_seat_v2
|
|
for (int i = 0; i < SDL_arraysize(sdltool->frame_buttons); i++) {
|
|
for (int i = 0; i < SDL_arraysize(sdltool->frame_buttons); i++) {
|
|
sdltool->frame_buttons[i] = -1;
|
|
sdltool->frame_buttons[i] = -1;
|
|
}
|
|
}
|
|
|
|
+ WAYLAND_wl_list_insert(&seat->tablet.tool_list, &sdltool->link);
|
|
|
|
|
|
// this will send a bunch of zwp_tablet_tool_v2 events right up front to tell
|
|
// this will send a bunch of zwp_tablet_tool_v2 events right up front to tell
|
|
// us device details, with a "done" event to let us know we have everything.
|
|
// us device details, with a "done" event to let us know we have everything.
|
|
@@ -3049,7 +3274,7 @@ static void tablet_seat_handle_tool_added(void *data, struct zwp_tablet_seat_v2
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static void tablet_seat_handle_pad_added(void *data, struct zwp_tablet_seat_v2 *seat, struct zwp_tablet_pad_v2 *pad)
|
|
|
|
|
|
+static void tablet_seat_handle_pad_added(void *data, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_pad_v2 *pad)
|
|
{
|
|
{
|
|
// we don't care atm.
|
|
// we don't care atm.
|
|
}
|
|
}
|
|
@@ -3060,23 +3285,19 @@ static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = {
|
|
tablet_seat_handle_pad_added
|
|
tablet_seat_handle_pad_added
|
|
};
|
|
};
|
|
|
|
|
|
-void Wayland_input_init_tablet_support(struct SDL_WaylandInput *input, struct zwp_tablet_manager_v2 *tablet_manager)
|
|
|
|
|
|
+static void Wayland_SeatInitTabletSupport(SDL_WaylandSeat *seat)
|
|
{
|
|
{
|
|
- if (!tablet_manager || !input->seat) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ WAYLAND_wl_list_init(&seat->tablet.tool_list);
|
|
|
|
+ seat->tablet.wl_tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(seat->display->tablet_manager, seat->wl_seat);
|
|
|
|
+ zwp_tablet_seat_v2_add_listener(seat->tablet.wl_tablet_seat, &tablet_seat_listener, seat);
|
|
|
|
+}
|
|
|
|
|
|
- SDL_WaylandTabletInput *tablet_input = SDL_calloc(1, sizeof(*tablet_input));
|
|
|
|
- if (!tablet_input) {
|
|
|
|
- return;
|
|
|
|
|
|
+void Wayland_DisplayInitTabletManager(SDL_VideoData *display)
|
|
|
|
+{
|
|
|
|
+ SDL_WaylandSeat *seat;
|
|
|
|
+ wl_list_for_each (seat, &display->seat_list, link) {
|
|
|
|
+ Wayland_SeatInitTabletSupport(seat);
|
|
}
|
|
}
|
|
-
|
|
|
|
- tablet_input->input = input;
|
|
|
|
- tablet_input->seat = zwp_tablet_manager_v2_get_tablet_seat(tablet_manager, input->seat);
|
|
|
|
-
|
|
|
|
- zwp_tablet_seat_v2_add_listener(tablet_input->seat, &tablet_seat_listener, tablet_input);
|
|
|
|
-
|
|
|
|
- input->tablet_input = tablet_input;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
static void Wayland_remove_all_pens_callback(SDL_PenID instance_id, void *handle, void *userdata)
|
|
static void Wayland_remove_all_pens_callback(SDL_PenID instance_id, void *handle, void *userdata)
|
|
@@ -3086,338 +3307,302 @@ static void Wayland_remove_all_pens_callback(SDL_PenID instance_id, void *handle
|
|
SDL_free(sdltool);
|
|
SDL_free(sdltool);
|
|
}
|
|
}
|
|
|
|
|
|
-void Wayland_input_quit_tablet_support(struct SDL_WaylandInput *input)
|
|
|
|
|
|
+static void Wayland_SeatDestroyTablet(SDL_WaylandSeat *seat, bool send_events)
|
|
{
|
|
{
|
|
- SDL_RemoveAllPenDevices(Wayland_remove_all_pens_callback, NULL);
|
|
|
|
|
|
+ if (send_events) {
|
|
|
|
+ SDL_WaylandPenTool *pen, *temp;
|
|
|
|
+ wl_list_for_each_safe (pen, temp, &seat->tablet.tool_list, link) {
|
|
|
|
+ // Remove all tools for this seat, sending PROXIMITY_OUT events.
|
|
|
|
+ tablet_tool_handle_removed(pen, pen->wltool);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ // Shutting down, just delete everything.
|
|
|
|
+ SDL_RemoveAllPenDevices(Wayland_remove_all_pens_callback, NULL);
|
|
|
|
+ }
|
|
|
|
|
|
- if (input && input->tablet_input) {
|
|
|
|
- zwp_tablet_seat_v2_destroy(input->tablet_input->seat);
|
|
|
|
- SDL_free(input->tablet_input);
|
|
|
|
- input->tablet_input = NULL;
|
|
|
|
|
|
+ if (seat && seat->tablet.wl_tablet_seat) {
|
|
|
|
+ zwp_tablet_seat_v2_destroy(seat->tablet.wl_tablet_seat);
|
|
|
|
+ seat->tablet.wl_tablet_seat = NULL;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ SDL_zero(seat->tablet);
|
|
|
|
+ WAYLAND_wl_list_init(&seat->tablet.tool_list);
|
|
}
|
|
}
|
|
|
|
|
|
-void Wayland_input_initialize_seat(SDL_VideoData *d)
|
|
|
|
|
|
+void Wayland_DisplayCreateSeat(SDL_VideoData *display, struct wl_seat *wl_seat, Uint32 id)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = d->input;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat = SDL_calloc(1, sizeof(SDL_WaylandSeat));
|
|
|
|
+ if (!seat) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- WAYLAND_wl_list_init(&touch_points);
|
|
|
|
|
|
+ // Keep the seats in the order in which they were added.
|
|
|
|
+ WAYLAND_wl_list_insert(display->seat_list.prev, &seat->link);
|
|
|
|
|
|
- if (d->data_device_manager) {
|
|
|
|
- Wayland_create_data_device(d);
|
|
|
|
- }
|
|
|
|
- if (d->primary_selection_device_manager) {
|
|
|
|
- Wayland_create_primary_selection_device(d);
|
|
|
|
- }
|
|
|
|
- if (d->text_input_manager) {
|
|
|
|
- Wayland_create_text_input(d);
|
|
|
|
- }
|
|
|
|
|
|
+ WAYLAND_wl_list_init(&seat->touch.points);
|
|
|
|
+ seat->wl_seat = wl_seat;
|
|
|
|
+ seat->display = display;
|
|
|
|
+ seat->registry_id = id;
|
|
|
|
+ seat->keyboard.xkb.current_group = XKB_GROUP_INVALID;
|
|
|
|
|
|
- wl_seat_add_listener(input->seat, &seat_listener, input);
|
|
|
|
- wl_seat_set_user_data(input->seat, input);
|
|
|
|
|
|
+ Wayland_SeatCreateDataDevice(seat);
|
|
|
|
+ Wayland_SeatCreatePrimarySelectionDevice(seat);
|
|
|
|
+ Wayland_SeatCreateTextInput(seat);
|
|
|
|
|
|
- if (d->tablet_manager) {
|
|
|
|
- Wayland_input_init_tablet_support(d->input, d->tablet_manager);
|
|
|
|
|
|
+ wl_seat_set_user_data(seat->wl_seat, seat);
|
|
|
|
+ wl_seat_add_listener(seat->wl_seat, &seat_listener, seat);
|
|
|
|
+
|
|
|
|
+ if (display->tablet_manager) {
|
|
|
|
+ Wayland_SeatInitTabletSupport(seat);
|
|
}
|
|
}
|
|
|
|
|
|
- WAYLAND_wl_display_flush(d->display);
|
|
|
|
|
|
+ WAYLAND_wl_display_flush(display->display);
|
|
}
|
|
}
|
|
|
|
|
|
-void Wayland_display_destroy_input(SDL_VideoData *d)
|
|
|
|
|
|
+void Wayland_SeatDestroy(SDL_WaylandSeat *seat, bool send_events)
|
|
{
|
|
{
|
|
- struct SDL_WaylandInput *input = d->input;
|
|
|
|
-
|
|
|
|
- if (input->keyboard_timestamps) {
|
|
|
|
- zwp_input_timestamps_v1_destroy(input->keyboard_timestamps);
|
|
|
|
- }
|
|
|
|
- if (input->pointer_timestamps) {
|
|
|
|
- zwp_input_timestamps_v1_destroy(input->pointer_timestamps);
|
|
|
|
- }
|
|
|
|
- if (input->touch_timestamps) {
|
|
|
|
- zwp_input_timestamps_v1_destroy(input->touch_timestamps);
|
|
|
|
|
|
+ if (!seat) {
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
- if (input->data_device) {
|
|
|
|
- Wayland_data_device_clear_selection(input->data_device);
|
|
|
|
- if (input->data_device->selection_offer) {
|
|
|
|
- Wayland_data_offer_destroy(input->data_device->selection_offer);
|
|
|
|
|
|
+ SDL_free(seat->name);
|
|
|
|
+
|
|
|
|
+ if (seat->data_device) {
|
|
|
|
+ Wayland_data_device_clear_selection(seat->data_device);
|
|
|
|
+ if (seat->data_device->selection_offer) {
|
|
|
|
+ Wayland_data_offer_destroy(seat->data_device->selection_offer);
|
|
}
|
|
}
|
|
- if (input->data_device->drag_offer) {
|
|
|
|
- Wayland_data_offer_destroy(input->data_device->drag_offer);
|
|
|
|
|
|
+ if (seat->data_device->drag_offer) {
|
|
|
|
+ Wayland_data_offer_destroy(seat->data_device->drag_offer);
|
|
}
|
|
}
|
|
- if (input->data_device->data_device) {
|
|
|
|
- if (wl_data_device_get_version(input->data_device->data_device) >= WL_DATA_DEVICE_RELEASE_SINCE_VERSION) {
|
|
|
|
- wl_data_device_release(input->data_device->data_device);
|
|
|
|
|
|
+ if (seat->data_device->data_device) {
|
|
|
|
+ if (wl_data_device_get_version(seat->data_device->data_device) >= WL_DATA_DEVICE_RELEASE_SINCE_VERSION) {
|
|
|
|
+ wl_data_device_release(seat->data_device->data_device);
|
|
} else {
|
|
} else {
|
|
- wl_data_device_destroy(input->data_device->data_device);
|
|
|
|
|
|
+ wl_data_device_destroy(seat->data_device->data_device);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- SDL_free(input->data_device);
|
|
|
|
|
|
+ SDL_free(seat->data_device);
|
|
}
|
|
}
|
|
|
|
|
|
- if (input->primary_selection_device) {
|
|
|
|
- if (input->primary_selection_device->selection_offer) {
|
|
|
|
- Wayland_primary_selection_offer_destroy(input->primary_selection_device->selection_offer);
|
|
|
|
|
|
+ if (seat->primary_selection_device) {
|
|
|
|
+ if (seat->primary_selection_device->selection_offer) {
|
|
|
|
+ Wayland_primary_selection_offer_destroy(seat->primary_selection_device->selection_offer);
|
|
}
|
|
}
|
|
- if (input->primary_selection_device->selection_source) {
|
|
|
|
- Wayland_primary_selection_source_destroy(input->primary_selection_device->selection_source);
|
|
|
|
|
|
+ if (seat->primary_selection_device->selection_source) {
|
|
|
|
+ Wayland_primary_selection_source_destroy(seat->primary_selection_device->selection_source);
|
|
}
|
|
}
|
|
- if (input->primary_selection_device->primary_selection_device) {
|
|
|
|
- zwp_primary_selection_device_v1_destroy(input->primary_selection_device->primary_selection_device);
|
|
|
|
|
|
+ if (seat->primary_selection_device->primary_selection_device) {
|
|
|
|
+ zwp_primary_selection_device_v1_destroy(seat->primary_selection_device->primary_selection_device);
|
|
}
|
|
}
|
|
- SDL_free(input->primary_selection_device);
|
|
|
|
|
|
+ SDL_free(seat->primary_selection_device);
|
|
}
|
|
}
|
|
|
|
|
|
- if (input->text_input) {
|
|
|
|
- zwp_text_input_v3_destroy(input->text_input->text_input);
|
|
|
|
- SDL_free(input->text_input);
|
|
|
|
|
|
+ if (seat->text_input.zwp_text_input) {
|
|
|
|
+ zwp_text_input_v3_destroy(seat->text_input.zwp_text_input);
|
|
}
|
|
}
|
|
|
|
|
|
- if (input->keyboard) {
|
|
|
|
- if (wl_keyboard_get_version(input->keyboard) >= WL_KEYBOARD_RELEASE_SINCE_VERSION) {
|
|
|
|
- wl_keyboard_release(input->keyboard);
|
|
|
|
- } else {
|
|
|
|
- wl_keyboard_destroy(input->keyboard);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ Wayland_SeatDestroyKeyboard(seat, send_events);
|
|
|
|
+ Wayland_SeatDestroyPointer(seat, send_events);
|
|
|
|
+ Wayland_SeatDestroyTouch(seat);
|
|
|
|
+ Wayland_SeatDestroyTablet(seat, send_events);
|
|
|
|
|
|
- if (input->relative_pointer) {
|
|
|
|
- zwp_relative_pointer_v1_destroy(input->relative_pointer);
|
|
|
|
|
|
+ if (wl_seat_get_version(seat->wl_seat) >= WL_SEAT_RELEASE_SINCE_VERSION) {
|
|
|
|
+ wl_seat_release(seat->wl_seat);
|
|
|
|
+ } else {
|
|
|
|
+ wl_seat_destroy(seat->wl_seat);
|
|
}
|
|
}
|
|
|
|
|
|
- if (input->cursor_shape) {
|
|
|
|
- wp_cursor_shape_device_v1_destroy(input->cursor_shape);
|
|
|
|
- }
|
|
|
|
|
|
+ WAYLAND_wl_list_remove(&seat->link);
|
|
|
|
+ SDL_free(seat);
|
|
|
|
+}
|
|
|
|
|
|
- if (input->pointer) {
|
|
|
|
- if (wl_pointer_get_version(input->pointer) >= WL_POINTER_RELEASE_SINCE_VERSION) {
|
|
|
|
- wl_pointer_release(input->pointer);
|
|
|
|
- } else {
|
|
|
|
- wl_pointer_destroy(input->pointer);
|
|
|
|
- }
|
|
|
|
|
|
+bool Wayland_SeatHasRelativePointerFocus(SDL_WaylandSeat *seat)
|
|
|
|
+{
|
|
|
|
+ /* If a seat has both keyboard and pointer capabilities, relative focus will follow the keyboard
|
|
|
|
+ * attached to that seat. Otherwise, relative focus will be gained if any other seat has keyboard
|
|
|
|
+ * focus on the window with pointer focus.
|
|
|
|
+ */
|
|
|
|
+ if (seat->keyboard.wl_keyboard) {
|
|
|
|
+ return seat->keyboard.focus && seat->keyboard.focus == seat->pointer.focus;
|
|
|
|
+ } else {
|
|
|
|
+ return seat->pointer.focus && seat->pointer.focus->keyboard_focus_count != 0;
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
|
|
- if (input->touch) {
|
|
|
|
- struct SDL_WaylandTouchPoint *tp, *tmp;
|
|
|
|
-
|
|
|
|
- SDL_DelTouch(1);
|
|
|
|
- if (wl_touch_get_version(input->touch) >= WL_TOUCH_RELEASE_SINCE_VERSION) {
|
|
|
|
- wl_touch_release(input->touch);
|
|
|
|
- } else {
|
|
|
|
- wl_touch_destroy(input->touch);
|
|
|
|
- }
|
|
|
|
|
|
+static void Wayland_SeatUpdateKeyboardGrab(SDL_WaylandSeat *seat)
|
|
|
|
+{
|
|
|
|
+ SDL_VideoData *display = seat->display;
|
|
|
|
|
|
- wl_list_for_each_safe (tp, tmp, &touch_points, link) {
|
|
|
|
- WAYLAND_wl_list_remove(&tp->link);
|
|
|
|
- SDL_free(tp);
|
|
|
|
|
|
+ if (display->key_inhibitor_manager) {
|
|
|
|
+ // Destroy the existing key inhibitor.
|
|
|
|
+ if (seat->keyboard.key_inhibitor) {
|
|
|
|
+ zwp_keyboard_shortcuts_inhibitor_v1_destroy(seat->keyboard.key_inhibitor);
|
|
|
|
+ seat->keyboard.key_inhibitor = NULL;
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
|
|
- if (input->tablet_input) {
|
|
|
|
- Wayland_input_quit_tablet_support(input);
|
|
|
|
- }
|
|
|
|
|
|
+ if (seat->keyboard.wl_keyboard) {
|
|
|
|
+ SDL_WindowData *w = seat->keyboard.focus;
|
|
|
|
+ if (w) {
|
|
|
|
+ SDL_Window *window = w->sdlwindow;
|
|
|
|
|
|
- if (input->seat) {
|
|
|
|
- if (wl_seat_get_version(input->seat) >= WL_SEAT_RELEASE_SINCE_VERSION) {
|
|
|
|
- wl_seat_release(input->seat);
|
|
|
|
- } else {
|
|
|
|
- wl_seat_destroy(input->seat);
|
|
|
|
|
|
+ // Don't grab the keyboard if it shouldn't be grabbed.
|
|
|
|
+ if (window->flags & SDL_WINDOW_KEYBOARD_GRABBED) {
|
|
|
|
+ seat->keyboard.key_inhibitor =
|
|
|
|
+ zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts(display->key_inhibitor_manager, w->surface, seat->wl_seat);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
- if (input->xkb.compose_state) {
|
|
|
|
- WAYLAND_xkb_compose_state_unref(input->xkb.compose_state);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (input->xkb.compose_table) {
|
|
|
|
- WAYLAND_xkb_compose_table_unref(input->xkb.compose_table);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (input->xkb.state) {
|
|
|
|
- WAYLAND_xkb_state_unref(input->xkb.state);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (input->xkb.keymap) {
|
|
|
|
- WAYLAND_xkb_keymap_unref(input->xkb.keymap);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- SDL_free(input);
|
|
|
|
- d->input = NULL;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-bool Wayland_input_enable_relative_pointer(struct SDL_WaylandInput *input)
|
|
|
|
|
|
+void Wayland_SeatUpdatePointerGrab(SDL_WaylandSeat *seat)
|
|
{
|
|
{
|
|
- SDL_VideoDevice *vd = SDL_GetVideoDevice();
|
|
|
|
- SDL_VideoData *d = input->display;
|
|
|
|
- SDL_Window *window;
|
|
|
|
-
|
|
|
|
- if (!d->relative_pointer_manager) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
|
|
+ SDL_VideoData *display = seat->display;
|
|
|
|
|
|
- if (!d->pointer_constraints) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
|
|
+ if (display->pointer_constraints) {
|
|
|
|
+ const bool has_relative_focus = Wayland_SeatHasRelativePointerFocus(seat);
|
|
|
|
|
|
- if (!input->pointer) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
|
|
+ if (seat->pointer.locked_pointer && (!display->relative_mode_enabled || !has_relative_focus)) {
|
|
|
|
+ zwp_locked_pointer_v1_destroy(seat->pointer.locked_pointer);
|
|
|
|
+ seat->pointer.locked_pointer = NULL;
|
|
|
|
|
|
- /* If we have a pointer confine active, we must destroy it here because
|
|
|
|
- * creating a locked pointer otherwise would be a protocol error.
|
|
|
|
- */
|
|
|
|
- for (window = vd->windows; window; window = window->next) {
|
|
|
|
- pointer_confine_destroy(window);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- for (window = vd->windows; window; window = window->next) {
|
|
|
|
- Wayland_input_lock_pointer(input, window);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- d->relative_mouse_mode = 1;
|
|
|
|
-
|
|
|
|
- return true;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-bool Wayland_input_disable_relative_pointer(struct SDL_WaylandInput *input)
|
|
|
|
-{
|
|
|
|
- SDL_VideoDevice *vd = SDL_GetVideoDevice();
|
|
|
|
- SDL_VideoData *d = input->display;
|
|
|
|
- SDL_Window *window;
|
|
|
|
-
|
|
|
|
- for (window = vd->windows; window; window = window->next) {
|
|
|
|
- Wayland_input_unlock_pointer(input, window);
|
|
|
|
- }
|
|
|
|
|
|
+ // Update the cursor after destroying a relative move lock.
|
|
|
|
+ Wayland_SeatUpdateCursor(seat);
|
|
|
|
+ }
|
|
|
|
|
|
- d->relative_mouse_mode = 0;
|
|
|
|
|
|
+ if (seat->pointer.wl_pointer) {
|
|
|
|
+ // If relative mode is active, and the pointer focus matches the keyboard focus, lock it.
|
|
|
|
+ if (seat->display->relative_mode_enabled && has_relative_focus) {
|
|
|
|
+ if (!seat->pointer.locked_pointer) {
|
|
|
|
+ // Creating a lock on a surface with an active confinement region on the same seat is a protocol error.
|
|
|
|
+ if (seat->pointer.confined_pointer) {
|
|
|
|
+ zwp_confined_pointer_v1_destroy(seat->pointer.confined_pointer);
|
|
|
|
+ seat->pointer.confined_pointer = NULL;
|
|
|
|
+ }
|
|
|
|
|
|
- for (window = vd->windows; window; window = window->next) {
|
|
|
|
- Wayland_input_confine_pointer(input, window);
|
|
|
|
- }
|
|
|
|
|
|
+ seat->pointer.locked_pointer = zwp_pointer_constraints_v1_lock_pointer(display->pointer_constraints,
|
|
|
|
+ seat->pointer.focus->surface,
|
|
|
|
+ seat->pointer.wl_pointer, NULL,
|
|
|
|
+ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
|
|
|
|
+ zwp_locked_pointer_v1_add_listener(seat->pointer.locked_pointer, &locked_pointer_listener, seat);
|
|
|
|
|
|
- return true;
|
|
|
|
-}
|
|
|
|
|
|
+ // Ensure that the relative pointer is hidden, if required.
|
|
|
|
+ Wayland_SeatUpdateCursor(seat);
|
|
|
|
+ }
|
|
|
|
|
|
-bool Wayland_input_confine_pointer(struct SDL_WaylandInput *input, SDL_Window *window)
|
|
|
|
-{
|
|
|
|
- SDL_WindowData *w = window->internal;
|
|
|
|
- SDL_VideoData *d = input->display;
|
|
|
|
- struct wl_region *confine_rect;
|
|
|
|
|
|
+ // Locked the cursor for relative mode, nothing more to do.
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- if (!d->pointer_constraints) {
|
|
|
|
- return SDL_SetError("Failed to confine pointer: compositor lacks support for the required zwp_pointer_constraints_v1 protocol");
|
|
|
|
- }
|
|
|
|
|
|
+ /* A confine may already be active, in which case we should destroy it and create a new one
|
|
|
|
+ * in case it changed size.
|
|
|
|
+ */
|
|
|
|
+ if (seat->pointer.confined_pointer) {
|
|
|
|
+ zwp_confined_pointer_v1_destroy(seat->pointer.confined_pointer);
|
|
|
|
+ seat->pointer.confined_pointer = NULL;
|
|
|
|
+ }
|
|
|
|
|
|
- if (!input->pointer) {
|
|
|
|
- return SDL_SetError("No pointer to confine");
|
|
|
|
- }
|
|
|
|
|
|
+ SDL_WindowData *w = seat->pointer.focus;
|
|
|
|
+ if (!w) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- // The confinement region will be created when the window is mapped.
|
|
|
|
- if (w->shell_surface_status != WAYLAND_SHELL_SURFACE_STATUS_SHOWN) {
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
|
|
+ SDL_Window *window = w->sdlwindow;
|
|
|
|
|
|
- /* A confine may already be active, in which case we should destroy it and
|
|
|
|
- * create a new one.
|
|
|
|
- */
|
|
|
|
- pointer_confine_destroy(window);
|
|
|
|
|
|
+ // Don't confine the pointer if the window doesn't have input focus, or it shouldn't be confined.
|
|
|
|
+ if (!(window->flags & SDL_WINDOW_INPUT_FOCUS) ||
|
|
|
|
+ (!(window->flags & SDL_WINDOW_MOUSE_GRABBED) && SDL_RectEmpty(&window->mouse_rect))) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- /* We cannot create a confine if the pointer is already locked. Defer until
|
|
|
|
- * the pointer is unlocked.
|
|
|
|
- */
|
|
|
|
- if (d->relative_mouse_mode) {
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
|
|
+ struct wl_region *confine_rect = NULL;
|
|
|
|
+ if (!SDL_RectEmpty(&window->mouse_rect)) {
|
|
|
|
+ SDL_Rect scaled_mouse_rect;
|
|
|
|
+ Wayland_GetScaledMouseRect(window, &scaled_mouse_rect);
|
|
|
|
|
|
- // Don't confine the pointer if it shouldn't be confined.
|
|
|
|
- if (SDL_RectEmpty(&window->mouse_rect) && !(window->flags & SDL_WINDOW_MOUSE_GRABBED)) {
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
|
|
+ /* Some compositors will only confine the pointer to an arbitrary region if the pointer
|
|
|
|
+ * is already within the confinement area when it is created.
|
|
|
|
+ */
|
|
|
|
+ if (SDL_PointInRect(&seat->pointer.last_motion, &scaled_mouse_rect)) {
|
|
|
|
+ confine_rect = wl_compositor_create_region(display->compositor);
|
|
|
|
+ wl_region_add(confine_rect,
|
|
|
|
+ scaled_mouse_rect.x,
|
|
|
|
+ scaled_mouse_rect.y,
|
|
|
|
+ scaled_mouse_rect.w,
|
|
|
|
+ scaled_mouse_rect.h);
|
|
|
|
+ } else {
|
|
|
|
+ /* Warp the pointer to the closest point within the confinement zone if outside,
|
|
|
|
+ * The confinement region will be created when a true position event is received.
|
|
|
|
+ */
|
|
|
|
+ int closest_x = seat->pointer.last_motion.x;
|
|
|
|
+ int closest_y = seat->pointer.last_motion.y;
|
|
|
|
|
|
- if (SDL_RectEmpty(&window->mouse_rect)) {
|
|
|
|
- confine_rect = NULL;
|
|
|
|
- } else {
|
|
|
|
- SDL_Rect scaled_mouse_rect;
|
|
|
|
|
|
+ if (closest_x < scaled_mouse_rect.x) {
|
|
|
|
+ closest_x = scaled_mouse_rect.x;
|
|
|
|
+ } else if (closest_x >= scaled_mouse_rect.x + scaled_mouse_rect.w) {
|
|
|
|
+ closest_x = (scaled_mouse_rect.x + scaled_mouse_rect.w) - 1;
|
|
|
|
+ }
|
|
|
|
|
|
- scaled_mouse_rect.x = (int)SDL_floor(window->mouse_rect.x / w->pointer_scale.x);
|
|
|
|
- scaled_mouse_rect.y = (int)SDL_floor(window->mouse_rect.y / w->pointer_scale.y);
|
|
|
|
- scaled_mouse_rect.w = (int)SDL_ceil(window->mouse_rect.w / w->pointer_scale.x);
|
|
|
|
- scaled_mouse_rect.h = (int)SDL_ceil(window->mouse_rect.h / w->pointer_scale.y);
|
|
|
|
|
|
+ if (closest_y < scaled_mouse_rect.y) {
|
|
|
|
+ closest_y = scaled_mouse_rect.y;
|
|
|
|
+ } else if (closest_y >= scaled_mouse_rect.y + scaled_mouse_rect.h) {
|
|
|
|
+ closest_y = (scaled_mouse_rect.y + scaled_mouse_rect.h) - 1;
|
|
|
|
+ }
|
|
|
|
|
|
- confine_rect = wl_compositor_create_region(d->compositor);
|
|
|
|
- wl_region_add(confine_rect,
|
|
|
|
- scaled_mouse_rect.x,
|
|
|
|
- scaled_mouse_rect.y,
|
|
|
|
- scaled_mouse_rect.w,
|
|
|
|
- scaled_mouse_rect.h);
|
|
|
|
- }
|
|
|
|
|
|
+ Wayland_SeatWarpMouse(seat, w, closest_x, closest_y);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
- struct zwp_confined_pointer_v1 *confined_pointer =
|
|
|
|
- zwp_pointer_constraints_v1_confine_pointer(d->pointer_constraints,
|
|
|
|
- w->surface,
|
|
|
|
- input->pointer,
|
|
|
|
- confine_rect,
|
|
|
|
- ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
|
|
|
|
- zwp_confined_pointer_v1_add_listener(confined_pointer,
|
|
|
|
- &confined_pointer_listener,
|
|
|
|
- window);
|
|
|
|
|
|
+ if (confine_rect || (window->flags & SDL_WINDOW_MOUSE_GRABBED)) {
|
|
|
|
+ seat->pointer.confined_pointer =
|
|
|
|
+ zwp_pointer_constraints_v1_confine_pointer(display->pointer_constraints,
|
|
|
|
+ w->surface,
|
|
|
|
+ seat->pointer.wl_pointer,
|
|
|
|
+ confine_rect,
|
|
|
|
+ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
|
|
|
|
+ zwp_confined_pointer_v1_add_listener(seat->pointer.confined_pointer,
|
|
|
|
+ &confined_pointer_listener,
|
|
|
|
+ window);
|
|
|
|
+
|
|
|
|
+ if (confine_rect) {
|
|
|
|
+ wl_region_destroy(confine_rect);
|
|
|
|
+ }
|
|
|
|
|
|
- if (confine_rect) {
|
|
|
|
- wl_region_destroy(confine_rect);
|
|
|
|
|
|
+ // Commit the new confinement region immediately.
|
|
|
|
+ wl_surface_commit(w->surface);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
-
|
|
|
|
- // Commit the double-buffered confinement region.
|
|
|
|
- wl_surface_commit(w->surface);
|
|
|
|
-
|
|
|
|
- w->confined_pointer = confined_pointer;
|
|
|
|
- return true;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-bool Wayland_input_unconfine_pointer(struct SDL_WaylandInput *input, SDL_Window *window)
|
|
|
|
-{
|
|
|
|
- pointer_confine_destroy(window);
|
|
|
|
- return true;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-bool Wayland_input_grab_keyboard(SDL_Window *window, struct SDL_WaylandInput *input)
|
|
|
|
|
|
+void Wayland_DisplayUpdatePointerGrabs(SDL_VideoData *display, SDL_WindowData *window)
|
|
{
|
|
{
|
|
- SDL_WindowData *w = window->internal;
|
|
|
|
- SDL_VideoData *d = input->display;
|
|
|
|
-
|
|
|
|
- if (!d->key_inhibitor_manager) {
|
|
|
|
- return SDL_SetError("Failed to grab keyboard: compositor lacks support for the required zwp_keyboard_shortcuts_inhibit_manager_v1 protocol");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (w->key_inhibitor) {
|
|
|
|
- return true;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat;
|
|
|
|
+ wl_list_for_each (seat, &display->seat_list, link) {
|
|
|
|
+ if (!window || seat->pointer.focus == window) {
|
|
|
|
+ Wayland_SeatUpdatePointerGrab(seat);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
-
|
|
|
|
- w->key_inhibitor =
|
|
|
|
- zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts(d->key_inhibitor_manager,
|
|
|
|
- w->surface,
|
|
|
|
- input->seat);
|
|
|
|
-
|
|
|
|
- return true;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-bool Wayland_input_ungrab_keyboard(SDL_Window *window)
|
|
|
|
|
|
+void Wayland_DisplayUpdateKeyboardGrabs(SDL_VideoData *display, SDL_WindowData *window)
|
|
{
|
|
{
|
|
- SDL_WindowData *w = window->internal;
|
|
|
|
-
|
|
|
|
- if (w->key_inhibitor) {
|
|
|
|
- zwp_keyboard_shortcuts_inhibitor_v1_destroy(w->key_inhibitor);
|
|
|
|
- w->key_inhibitor = NULL;
|
|
|
|
|
|
+ SDL_WaylandSeat *seat;
|
|
|
|
+ wl_list_for_each (seat, &display->seat_list, link) {
|
|
|
|
+ if (!window || seat->keyboard.focus == window) {
|
|
|
|
+ Wayland_SeatUpdateKeyboardGrab(seat);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
-
|
|
|
|
- return true;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-void Wayland_UpdateImplicitGrabSerial(struct SDL_WaylandInput *input, Uint32 serial)
|
|
|
|
|
|
+void Wayland_UpdateImplicitGrabSerial(SDL_WaylandSeat *seat, Uint32 serial)
|
|
{
|
|
{
|
|
- if (serial > input->last_implicit_grab_serial) {
|
|
|
|
- input->last_implicit_grab_serial = serial;
|
|
|
|
- Wayland_data_device_set_serial(input->data_device, serial);
|
|
|
|
- Wayland_primary_selection_device_set_serial(input->primary_selection_device, serial);
|
|
|
|
|
|
+ if (serial > seat->last_implicit_grab_serial) {
|
|
|
|
+ seat->last_implicit_grab_serial = serial;
|
|
|
|
+ seat->display->last_implicit_grab_seat = seat;
|
|
|
|
+ Wayland_data_device_set_serial(seat->data_device, serial);
|
|
|
|
+ Wayland_primary_selection_device_set_serial(seat->primary_selection_device, serial);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|