summaryrefslogtreecommitdiff
path: root/src/wayland/pointer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/wayland/pointer.c')
-rw-r--r--src/wayland/pointer.c1275
1 files changed, 0 insertions, 1275 deletions
diff --git a/src/wayland/pointer.c b/src/wayland/pointer.c
deleted file mode 100644
index 90b7ecc..0000000
--- a/src/wayland/pointer.c
+++ /dev/null
@@ -1,1275 +0,0 @@
-#include "internal.h"
-
-#include <math.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#define SCROLL_PX_PER_LINE 10.0
-
-struct tablet_tool {
- struct tablet_tool *next;
- struct seat *seat;
- struct zwp_tablet_tool_v2 *proxy;
- struct wp_cursor_shape_device_v1 *shape_dev;
- uint32_t proximity_serial;
- bool eraser;
-};
-
-struct tablet_device {
- struct tablet_device *next;
- struct zwp_tablet_v2 *proxy;
-};
-
-struct tablet_pad {
- struct tablet_pad *next;
- struct zwp_tablet_pad_v2 *proxy;
-};
-
-static inline int device_px_round(double v)
-{
- return (int)lrint(v);
-}
-
-static struct yasl_vector2i device_from_fixed(const struct wayland_surface *w,
- wl_fixed_t x, wl_fixed_t y)
-{
- return (struct yasl_vector2i){
- .x = device_px_round(wl_fixed_to_double(x) * w->scale_factor),
- .y = device_px_round(wl_fixed_to_double(y) * w->scale_factor),
- };
-}
-
-static inline int motion_button(uint64_t buttons)
-{
- static const uint8_t motion_btn_lut[256] = {
- [0] = 3,
- [1] = 0, [2] = 1, [3] = 0, [4] = 2, [5] = 0, [6] = 1, [7] = 0,
- [8] = 3, [9] = 0, [10] = 1, [11] = 0, [12] = 2, [13] = 0, [14] = 1, [15] = 0,
- [16] = 4, [17] = 0, [18] = 1, [19] = 0, [20] = 2, [21] = 0, [22] = 1, [23] = 0,
- [24] = 3, [25] = 0, [26] = 1, [27] = 0, [28] = 2, [29] = 0, [30] = 1, [31] = 0,
- [32] = 5, [33] = 0, [34] = 1, [35] = 0, [36] = 2, [37] = 0, [38] = 1, [39] = 0,
- [40] = 3, [41] = 0, [42] = 1, [43] = 0, [44] = 2, [45] = 0, [46] = 1, [47] = 0,
- [48] = 4, [49] = 0, [50] = 1, [51] = 0, [52] = 2, [53] = 0, [54] = 1, [55] = 0,
- [56] = 3, [57] = 0, [58] = 1, [59] = 0, [60] = 2, [61] = 0, [62] = 1, [63] = 0,
- [64] = 6, [65] = 0, [66] = 1, [67] = 0, [68] = 2, [69] = 0, [70] = 1, [71] = 0,
- [72] = 3, [73] = 0, [74] = 1, [75] = 0, [76] = 2, [77] = 0, [78] = 1, [79] = 0,
- [80] = 4, [81] = 0, [82] = 1, [83] = 0, [84] = 2, [85] = 0, [86] = 1, [87] = 0,
- [88] = 3, [89] = 0, [90] = 1, [91] = 0, [92] = 2, [93] = 0, [94] = 1, [95] = 0,
- [96] = 5, [97] = 0, [98] = 1, [99] = 0, [100] = 2, [101] = 0, [102] = 1, [103] = 0,
- [104] = 3, [105] = 0, [106] = 1, [107] = 0, [108] = 2, [109] = 0, [110] = 1, [111] = 0,
- [112] = 4, [113] = 0, [114] = 1, [115] = 0, [116] = 2, [117] = 0, [118] = 1, [119] = 0,
- [120] = 3, [121] = 0, [122] = 1, [123] = 0, [124] = 2, [125] = 0, [126] = 1, [127] = 0,
- [128] = 7, [129] = 0, [130] = 1, [131] = 0, [132] = 2, [133] = 0, [134] = 1, [135] = 0,
- [136] = 3, [137] = 0, [138] = 1, [139] = 0, [140] = 2, [141] = 0, [142] = 1, [143] = 0,
- [144] = 4, [145] = 0, [146] = 1, [147] = 0, [148] = 2, [149] = 0, [150] = 1, [151] = 0,
- [152] = 3, [153] = 0, [154] = 1, [155] = 0, [156] = 2, [157] = 0, [158] = 1, [159] = 0,
- [160] = 5, [161] = 0, [162] = 1, [163] = 0, [164] = 2, [165] = 0, [166] = 1, [167] = 0,
- [168] = 3, [169] = 0, [170] = 1, [171] = 0, [172] = 2, [173] = 0, [174] = 1, [175] = 0,
- [176] = 4, [177] = 0, [178] = 1, [179] = 0, [180] = 2, [181] = 0, [182] = 1, [183] = 0,
- [184] = 3, [185] = 0, [186] = 1, [187] = 0, [188] = 2, [189] = 0, [190] = 1, [191] = 0,
- [192] = 6, [193] = 0, [194] = 1, [195] = 0, [196] = 2, [197] = 0, [198] = 1, [199] = 0,
- [200] = 3, [201] = 0, [202] = 1, [203] = 0, [204] = 2, [205] = 0, [206] = 1, [207] = 0,
- [208] = 4, [209] = 0, [210] = 1, [211] = 0, [212] = 2, [213] = 0, [214] = 1, [215] = 0,
- [216] = 3, [217] = 0, [218] = 1, [219] = 0, [220] = 2, [221] = 0, [222] = 1, [223] = 0,
- [224] = 5, [225] = 0, [226] = 1, [227] = 0, [228] = 2, [229] = 0, [230] = 1, [231] = 0,
- [232] = 3, [233] = 0, [234] = 1, [235] = 0, [236] = 2, [237] = 0, [238] = 1, [239] = 0,
- [240] = 4, [241] = 0, [242] = 1, [243] = 0, [244] = 2, [245] = 0, [246] = 1, [247] = 0,
- [248] = 3, [249] = 0, [250] = 1, [251] = 0, [252] = 2, [253] = 0, [254] = 1, [255] = 0,
- };
- return motion_btn_lut[(uint8_t)buttons];
-}
-
-void seat_note_input(struct seat *s, uint32_t serial)
-{
- s->input_serial = serial;
- s->conn->active_seat = s;
-}
-
-struct seat *conn_active_seat(const struct wayland_display *c)
-{
- return c->active_seat ? c->active_seat : c->seats;
-}
-
-static void push_mouse(struct seat *s, struct wayland_surface *w, struct yasl_mouse_event ev)
-{
- ev.mods = (unsigned)seat_modifiers(s);
- struct yasl_input_event input_ev = {
- .kind = YASL_INPUT_MOUSE,
- .surface = &w->base,
- .mouse = ev,
- };
- input_queue_push(&surface_root(w)->input, &input_ev);
-}
-
-static void report_mouse(struct seat *s, struct wayland_surface *w, struct yasl_vector2i pos,
- int button, enum yasl_pointer_kind kind)
-{
- push_mouse(s, w, (struct yasl_mouse_event){
- .pos = pos, .button = button, .kind = kind,
- });
-}
-
-static void report_wheel(struct seat *s, struct wayland_surface *w,
- struct yasl_vector2i pos, double x, double y)
-{
- if ((x == 0 && y == 0) || !isfinite(x) || !isfinite(y)) return;
- push_mouse(s, w, (struct yasl_mouse_event){
- .pos = pos, .kind = YASL_PTR_SCROLL, .scroll = {x, y},
- });
-}
-
-static bool cursor_theme_for(struct wayland_display *c, int scale)
-{
- if (c->cursor_theme && c->cursor_theme_scale == scale)
- return true;
- struct wl_cursor_theme *theme = wl_cursor_theme_load(c->cursor_theme_name,
- c->cursor_size * scale, c->shm);
- if (!theme)
- return c->cursor_theme != NULL;
- if (c->cursor_theme)
- wl_cursor_theme_destroy(c->cursor_theme);
- c->cursor_theme = theme;
- c->cursor_theme_scale = scale;
- return true;
-}
-
-static bool seat_cursor_surface(struct seat *s)
-{
- struct wayland_display *c = s->conn;
- if (s->cursor_surface)
- return true;
- s->cursor_surface = wl_compositor_create_surface(c->compositor);
- if (!s->cursor_surface)
- return false;
- if (c->viewporter)
- s->cursor_viewport = wp_viewporter_get_viewport(c->viewporter, s->cursor_surface);
- return true;
-}
-
-static void set_cursor_theme_fallback(struct seat *s, struct wayland_surface *w,
- enum yasl_cursor shape)
-{
- struct wayland_display *c = s->conn;
- int scale = (int)((w->scale_120 + YASL_SCALE_UNIT - 1) / YASL_SCALE_UNIT);
- if (scale < 1) scale = 1;
- if (!seat_cursor_surface(s) || !cursor_theme_for(c, scale)) return;
- static const char *names[][2] = {
- {"default", "left_ptr"},
- {"text", "xterm"},
- {"pointer", "hand2"},
- {"crosshair", "crosshair"},
- {"move", "move"},
- {"nwse-resize", "nw-resize"},
- {"nesw-resize", "ne-resize"},
- {"ew-resize", "ew-resize"},
- {"ns-resize", "ns-resize"},
- };
- int idx = (unsigned)shape < YASL_CURSOR_HIDDEN ? (int)shape : 0;
- struct wl_cursor *cursor = wl_cursor_theme_get_cursor(c->cursor_theme, names[idx][0]);
- if (!cursor) cursor = wl_cursor_theme_get_cursor(c->cursor_theme, names[idx][1]);
- if (!cursor || !cursor->image_count) return;
- struct wl_cursor_image *img = cursor->images[0];
- struct wl_buffer *buffer = wl_cursor_image_get_buffer(img);
- if (!buffer) return;
-
- int theme_scale = c->cursor_theme_scale;
- if (s->cursor_viewport) {
- wp_viewport_set_destination(s->cursor_viewport,
- logical_px_ceil((int)img->width, (uint32_t)theme_scale * YASL_SCALE_UNIT),
- logical_px_ceil((int)img->height, (uint32_t)theme_scale * YASL_SCALE_UNIT));
- } else {
- if (img->width % (uint32_t)theme_scale || img->height % (uint32_t)theme_scale)
- theme_scale = 1;
- wl_surface_set_buffer_scale(s->cursor_surface, theme_scale);
- }
- int shown = s->cursor_viewport ? c->cursor_theme_scale : theme_scale;
- wl_pointer_set_cursor(s->pointer, s->pointer_serial, s->cursor_surface,
- (int32_t)img->hotspot_x / shown, (int32_t)img->hotspot_y / shown);
- wl_surface_attach(s->cursor_surface, buffer, 0, 0);
- wl_surface_damage_buffer(s->cursor_surface, 0, 0,
- (int32_t)img->width, (int32_t)img->height);
- wl_surface_commit(s->cursor_surface);
-}
-
-static uint32_t cursor_shape_of(enum yasl_cursor shape)
-{
- switch (shape) {
- case YASL_CURSOR_TEXT: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT;
- case YASL_CURSOR_LINK: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER;
- case YASL_CURSOR_CROSSHAIR: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR;
- case YASL_CURSOR_MOVE: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE;
- case YASL_CURSOR_RESIZE_EW: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_EW_RESIZE;
- case YASL_CURSOR_RESIZE_NS: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NS_RESIZE;
- case YASL_CURSOR_RESIZE_NWSE: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NWSE_RESIZE;
- case YASL_CURSOR_RESIZE_NESW: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NESW_RESIZE;
- default: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT;
- }
-}
-
-static void seat_set_cursor(struct seat *s, struct wayland_surface *w, enum yasl_cursor shape)
-{
- if (!s->pointer || !s->pointer_serial || s->pointer_focus != w ||
- s->cursor_shape == (int)shape)
- return;
- if (shape == YASL_CURSOR_HIDDEN)
- wl_pointer_set_cursor(s->pointer, s->pointer_serial, NULL, 0, 0);
- else if (s->cursor_shape_dev)
- wp_cursor_shape_device_v1_set_shape(s->cursor_shape_dev,
- s->pointer_serial, cursor_shape_of(shape));
- else
- set_cursor_theme_fallback(s, w, shape);
- s->cursor_shape = shape;
-}
-
-static void tool_set_cursor(struct tablet_tool *t, enum yasl_cursor shape)
-{
- if (!t->proximity_serial)
- return;
- if (shape == YASL_CURSOR_HIDDEN)
- zwp_tablet_tool_v2_set_cursor(t->proxy, t->proximity_serial, NULL, 0, 0);
- else if (t->shape_dev)
- wp_cursor_shape_device_v1_set_shape(t->shape_dev, t->proximity_serial,
- cursor_shape_of(shape));
-}
-
-void wayland_surface_set_cursor(struct wayland_surface *w, enum yasl_cursor shape)
-{
- if (!w || !w->conn || w->destroyed || (unsigned)shape > YASL_CURSOR_HIDDEN) return;
- w->cursor = shape;
- for (struct seat *s = w->conn->seats; s; s = s->next) {
- seat_set_cursor(s, w, shape);
- if (s->tool && s->tablet_focus == w)
- tool_set_cursor(s->tool, shape);
- }
-}
-
-static void press_queue_flush(struct seat *s, struct press_queue *q,
- struct wayland_surface *only, uint64_t *buttons,
- struct yasl_mouse_event like)
-{
- int kept = 0;
- int count = q->n;
- for (int i = 0; i < count; i++) {
- struct pending_press p = q->ev[(q->head + i) & 7];
- if (only && p.surface != only) {
- q->ev[kept++] = p;
- continue;
- }
- if (!p.surface) continue;
- uint64_t mask = 1ull << p.button;
- *buttons = (*buttons & ~mask) | ((uint64_t)(!p.release) << p.button);
- struct yasl_mouse_event ev = like;
- ev.pos = p.pos;
- ev.button = p.button;
- ev.kind = (enum yasl_pointer_kind)p.release;
- push_mouse(s, p.surface, ev);
- }
- q->head = 0;
- q->n = kept;
-}
-
-static void press_queue_push(struct press_queue *q, struct wayland_surface *w,
- struct yasl_vector2i pos, int button, bool release)
-{
- if (q->n == 8) {
- q->head = (q->head + 1) & 7;
- q->n--;
- }
- q->ev[(q->head + q->n) & 7] = (struct pending_press){
- .surface = w, .pos = pos, .button = button, .release = release,
- };
- q->n++;
-}
-
-static void press_queue_forget(struct press_queue *q, struct wayland_surface *w)
-{
- for (int i = 0; i < q->n; i++) {
- int idx = (q->head + i) & 7;
- if (q->ev[idx].surface == w)
- q->ev[idx].surface = NULL;
- }
-}
-
-void seat_pointer_reset(struct seat *s)
-{
- s->pointer_buttons = 0;
- s->pointer_serial = 0;
- s->motion_pending = false;
- memset(s->axis, 0, sizeof(s->axis));
- memset(s->axis_value120, 0, sizeof(s->axis_value120));
- memset(s->axis_discrete, 0, sizeof(s->axis_discrete));
- memset(s->axis_has_value120, 0, sizeof(s->axis_has_value120));
- memset(s->axis_has_discrete, 0, sizeof(s->axis_has_discrete));
- s->cursor_shape = -1;
-}
-
-static void pointer_frame(void *data, struct wl_pointer *pointer);
-
-static void pointer_event_done(struct seat *s)
-{
- if (s->pointer && wl_pointer_get_version(s->pointer) < WL_POINTER_FRAME_SINCE_VERSION)
- pointer_frame(s, s->pointer);
-}
-
-static void flush_pending_motion(struct seat *s, struct wayland_surface *w)
-{
- if (!s->motion_pending) return;
- s->motion_pending = false;
- report_mouse(s, w, s->pointer_pos, motion_button(s->pointer_buttons), YASL_PTR_MOTION);
-}
-
-static void pointer_enter(void *data, struct wl_pointer *pointer,
- uint32_t serial, struct wl_surface *surface,
- wl_fixed_t surface_x, wl_fixed_t surface_y)
-{
- (void)pointer;
- struct seat *s = data;
- struct wayland_surface *w = conn_surface_for(s->conn, surface);
- s->pointer_focus = w;
- if (!w) return;
- s->pointer_pos = device_from_fixed(w, surface_x, surface_y);
- s->pointer_serial = serial;
- s->cursor_shape = -1;
- seat_set_cursor(s, w, w->cursor);
- s->motion_pending = true;
- pointer_event_done(s);
-}
-
-static void pointer_leave(void *data, struct wl_pointer *pointer,
- uint32_t serial, struct wl_surface *surface)
-{
- (void)pointer; (void)serial; (void)surface;
- struct seat *s = data;
- struct wayland_surface *w = s->pointer_focus;
- s->pointer_focus = NULL;
- if (!w) return;
- if (s->ptr_left)
- pointer_frame(s, s->pointer);
- s->ptr_left = w;
- s->ptr_left_pos = s->pointer_pos;
- s->ptr_left_motion = s->motion_pending;
- s->motion_pending = false;
- pointer_event_done(s);
-}
-
-static void pointer_motion(void *data, struct wl_pointer *pointer,
- uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
-{
- (void)pointer; (void)time;
- struct seat *s = data;
- struct wayland_surface *w = s->pointer_focus;
- if (!w) return;
- s->pointer_pos = device_from_fixed(w, surface_x, surface_y);
- s->motion_pending = true;
- pointer_event_done(s);
-}
-
-static void pointer_button(void *data, struct wl_pointer *pointer,
- uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
-{
- (void)pointer; (void)time;
- struct seat *s = data;
- struct wayland_surface *w = s->pointer_focus;
- if (unlikely(!w)) return;
-
- static const int8_t btn_map[8] = {
- [0] = 0, /* BTN_LEFT (0x110) */
- [1] = 2, /* BTN_RIGHT (0x111) */
- [2] = 1, /* BTN_MIDDLE (0x112) */
- [3] = 3, /* BTN_SIDE (0x113) */
- [4] = 4, /* BTN_EXTRA (0x114) */
- [5] = 4, /* BTN_FORWARD (0x115) */
- [6] = 3, /* BTN_BACK (0x116) */
- [7] = -1,
- };
- unsigned idx = button - 0x110;
- if (unlikely(idx >= 7)) return;
- int b = btn_map[idx];
- if (unlikely(b < 0)) return;
- seat_note_input(s, serial);
- bool release = (state == WL_POINTER_BUTTON_STATE_RELEASED);
- if (!release) {
- s->press_serial = serial;
- s->press_surface = w;
- }
- press_queue_push(&s->ptr_presses, w, s->pointer_pos, b, release);
- pointer_event_done(s);
-}
-
-static void pointer_axis(void *data, struct wl_pointer *pointer,
- uint32_t time, uint32_t axis, wl_fixed_t value)
-{
- (void)pointer; (void)time;
- struct seat *s = data;
- if (unlikely(!s->pointer_focus)) return;
- double v = wl_fixed_to_double(value);
- if (likely(axis < 2)) {
- s->axis[axis] += v;
- }
- pointer_event_done(s);
-}
-
-static void pointer_axis_source(void *data, struct wl_pointer *pointer, uint32_t axis_source)
-{
- (void)pointer;
- (void)data; (void)axis_source;
-}
-
-static void pointer_axis_stop(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis)
-{
- /* A stop ends a gesture, not the offsets already received in this frame. */
- (void)data; (void)pointer; (void)time; (void)axis;
-}
-
-static void pointer_axis_discrete(void *data, struct wl_pointer *pointer, uint32_t axis, int32_t discrete)
-{
- (void)pointer;
- struct seat *s = data;
- if (axis < 2) {
- s->axis_discrete[axis] += discrete;
- s->axis_has_discrete[axis] = true;
- }
-}
-
-static void pointer_axis_value120(void *data, struct wl_pointer *pointer, uint32_t axis, int32_t value120)
-{
- (void)pointer;
- struct seat *s = data;
- if (axis < 2) {
- s->axis_value120[axis] += value120;
- s->axis_has_value120[axis] = true;
- }
-}
-
-static void pointer_frame_scroll(struct seat *s, struct wayland_surface *w)
-{
- double lines[2];
- for (int axis = 0; axis < 2; axis++) {
- /* A wheel may provide all three representations. Pick one, never sum
- * them. value120 preserves high-resolution detents on both axes. */
- lines[axis] = s->axis_has_value120[axis] ? s->axis_value120[axis] / 120.0 :
- s->axis_has_discrete[axis] ? (double)s->axis_discrete[axis] :
- s->axis[axis] / SCROLL_PX_PER_LINE;
- s->axis[axis] = s->axis_value120[axis] = 0;
- s->axis_discrete[axis] = 0;
- s->axis_has_value120[axis] = s->axis_has_discrete[axis] = false;
- }
- report_wheel(s, w, s->pointer_pos, lines[1], lines[0]);
-}
-
-static void pointer_frame(void *data, struct wl_pointer *pointer)
-{
- (void)pointer;
- struct seat *s = data;
- struct wayland_surface *left = s->ptr_left;
- if (left) {
- s->ptr_left = NULL;
- if (s->ptr_left_motion)
- report_mouse(s, left, s->ptr_left_pos, motion_button(s->pointer_buttons), YASL_PTR_MOTION);
- press_queue_flush(s, &s->ptr_presses, left, &s->pointer_buttons, (struct yasl_mouse_event){0});
- report_mouse(s, left, s->ptr_left_pos, 3, YASL_PTR_LEAVE);
- struct yasl_vector2i pos = s->pointer_pos;
- bool motion = s->motion_pending;
- uint32_t serial = s->pointer_focus ? s->pointer_serial : 0;
- int shape = s->pointer_focus ? s->cursor_shape : -1;
- seat_pointer_reset(s);
- s->pointer_pos = pos;
- s->motion_pending = motion;
- s->pointer_serial = serial;
- s->cursor_shape = shape;
- }
- struct wayland_surface *w = s->pointer_focus;
- if (!w) {
- s->ptr_presses.n = 0;
- return;
- }
-
- flush_pending_motion(s, w);
- press_queue_flush(s, &s->ptr_presses, NULL, &s->pointer_buttons, (struct yasl_mouse_event){0});
-
- pointer_frame_scroll(s, w);
-}
-
-static void pointer_axis_relative_direction(void *data, struct wl_pointer *pointer, uint32_t axis, uint32_t direction)
-{ (void)data; (void)pointer; (void)axis; (void)direction; }
-static void pointer_warp(void *data, struct wl_pointer *pointer, wl_fixed_t x, wl_fixed_t y)
-{ (void)data; (void)pointer; (void)x; (void)y; }
-
-static const struct wl_pointer_listener pointer_listener = {
- .axis_relative_direction = pointer_axis_relative_direction,
- .warp = pointer_warp,
- .enter = pointer_enter,
- .leave = pointer_leave,
- .motion = pointer_motion,
- .button = pointer_button,
- .axis = pointer_axis,
- .frame = pointer_frame,
- .axis_source = pointer_axis_source,
- .axis_stop = pointer_axis_stop,
- .axis_discrete = pointer_axis_discrete,
- .axis_value120 = pointer_axis_value120,
-};
-
-static struct touch_point *touch_find(struct seat *s, int32_t id)
-{
- for (int i = 0; i < SEAT_TOUCH_POINTS; i++)
- if (s->touch_points[i].active && s->touch_points[i].id == id)
- return &s->touch_points[i];
- return NULL;
-}
-
-static struct yasl_vector2i touch_pos(const struct touch_point *p)
-{
- double scale = p->surface->scale_factor;
- return (struct yasl_vector2i){
- .x = device_px_round(p->x * scale), .y = device_px_round(p->y * scale),
- };
-}
-
-
-
-static void touch_report(struct seat *s, struct touch_point *p, int button,
- enum yasl_pointer_kind kind)
-{
- push_mouse(s, p->surface, (struct yasl_mouse_event){
- .pos = touch_pos(p), .button = button, .kind = kind,
- .device = YASL_PTR_DEV_TOUCH,
- });
-}
-
-static void touch_down(void *data, struct wl_touch *touch,
- uint32_t serial, uint32_t time, struct wl_surface *surface,
- int32_t id, wl_fixed_t x, wl_fixed_t y)
-{
- (void)touch; (void)time;
- struct seat *s = data;
- struct wayland_surface *w = conn_surface_for(s->conn, surface);
- if (!w || touch_find(s, id)) return;
- struct touch_point *p = NULL;
- for (int i = 0; i < SEAT_TOUCH_POINTS && !p; i++)
- if (!s->touch_points[i].active)
- p = &s->touch_points[i];
- if (!p) return;
- seat_note_input(s, serial);
- s->press_serial = serial;
- s->press_surface = w;
- *p = (struct touch_point){
- .surface = w, .id = id, .active = true, .down = true,
- .x = wl_fixed_to_double(x), .y = wl_fixed_to_double(y),
- };
-}
-
-static void touch_up(void *data, struct wl_touch *touch, uint32_t serial, uint32_t time, int32_t id)
-{
- (void)touch; (void)serial; (void)time;
- struct touch_point *p = touch_find(data, id);
- if (p) p->up = true;
-}
-
-static void touch_motion(void *data, struct wl_touch *touch, uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y)
-{
- (void)touch; (void)time;
- struct touch_point *p = touch_find(data, id);
- if (!p) return;
- p->x = wl_fixed_to_double(x);
- p->y = wl_fixed_to_double(y);
- p->moved = true;
-}
-
-static void touch_frame(void *data, struct wl_touch *touch)
-{
- (void)touch;
- struct seat *s = data;
- int active_n = 0;
- double centroid_sum = 0;
- int centroid_n = 0;
- for (int i = 0; i < SEAT_TOUCH_POINTS; i++) {
- struct touch_point *p = &s->touch_points[i];
- if (!p->active) continue;
- if (p->down && !s->touch_primary && !s->touch_scrolling) {
- s->touch_primary = p;
- s->touch_pressed = true;
- touch_report(s, p, 0, YASL_PTR_PRESS);
- }
- if (!p->up) {
- active_n++;
- if (s->touch_primary && p->surface == s->touch_primary->surface) {
- centroid_sum += p->y;
- centroid_n++;
- }
- }
- }
- struct touch_point *primary = s->touch_primary;
- if (primary && !s->touch_scrolling && active_n >= 2) {
- if (s->touch_pressed)
- touch_report(s, primary, 0, YASL_PTR_RELEASE);
- s->touch_pressed = false;
- s->touch_scrolling = true;
- s->touch_scroll_y = centroid_n ? centroid_sum / centroid_n : 0;
- } else if (s->touch_scrolling && primary && active_n >= 2) {
- double y = centroid_n ? centroid_sum / centroid_n : 0;
- double dy = y - s->touch_scroll_y;
- s->touch_scroll_y = y;
- if (dy != 0.0) {
- double lines = dy / SCROLL_PX_PER_LINE;
- push_mouse(s, primary->surface, (struct yasl_mouse_event){
- .pos = touch_pos(primary), .kind = YASL_PTR_SCROLL,
- .scroll = {0, -lines}, .device = YASL_PTR_DEV_TOUCH,
- });
- }
- } else if (primary && primary->moved && s->touch_pressed) {
- touch_report(s, primary, 0, YASL_PTR_MOTION);
- }
- for (int i = 0; i < SEAT_TOUCH_POINTS; i++) {
- struct touch_point *p = &s->touch_points[i];
- if (!p->active) continue;
- if (p->up) {
- active_n--;
- if (p == s->touch_primary) {
- if (s->touch_pressed)
- touch_report(s, p, 0, YASL_PTR_RELEASE);
- s->touch_pressed = false;
- s->touch_primary = NULL;
- }
- *p = (struct touch_point){0};
- } else {
- p->down = p->moved = false;
- }
- }
- if (active_n <= 0)
- s->touch_scrolling = false;
-}
-
-static void touch_cancel(void *data, struct wl_touch *touch)
-{
- (void)touch;
- struct seat *s = data;
- if (s->touch_primary && s->touch_pressed)
- touch_report(s, s->touch_primary, 0, YASL_PTR_RELEASE);
- memset(s->touch_points, 0, sizeof(s->touch_points));
- s->touch_primary = NULL;
- s->touch_pressed = false;
- s->touch_scrolling = false;
-}
-
-static void touch_shape(void *data, struct wl_touch *touch, int32_t id, wl_fixed_t major, wl_fixed_t minor)
-{ (void)data; (void)touch; (void)id; (void)major; (void)minor; }
-static void touch_orientation(void *data, struct wl_touch *touch, int32_t id, wl_fixed_t orientation)
-{ (void)data; (void)touch; (void)id; (void)orientation; }
-
-static const struct wl_touch_listener touch_listener = {
- .shape = touch_shape, .orientation = touch_orientation,
- .down = touch_down, .up = touch_up, .motion = touch_motion,
- .frame = touch_frame, .cancel = touch_cancel,
-};
-
-static struct yasl_mouse_event tool_event(const struct seat *s)
-{
- return (struct yasl_mouse_event){
- .device = s->tool && s->tool->eraser ? YASL_PTR_DEV_ERASER : YASL_PTR_DEV_PEN,
- .pen = s->pen,
- };
-}
-
-static void tablet_tool_proximity_in(void *data,
- struct zwp_tablet_tool_v2 *tool, uint32_t serial,
- struct zwp_tablet_v2 *tablet, struct wl_surface *surface)
-{
- (void)tool; (void)tablet;
- struct tablet_tool *t = data;
- struct seat *s = t->seat;
- struct wayland_surface *w = conn_surface_for(s->conn, surface);
- s->tablet_focus = w;
- s->tool = t;
- s->tool_buttons = 0;
- s->pen = (struct yasl_pointer_pen){0};
- t->proximity_serial = serial;
- if (!w) return;
- if (s->conn->cursor_shape_mgr && !t->shape_dev)
- t->shape_dev = wp_cursor_shape_manager_v1_get_tablet_tool_v2(
- s->conn->cursor_shape_mgr, t->proxy);
- tool_set_cursor(t, w->cursor);
- s->tool_motion = true;
-}
-
-static void tablet_tool_proximity_out(void *data, struct zwp_tablet_tool_v2 *tool)
-{
- (void)tool;
- struct tablet_tool *t = data;
- struct seat *s = t->seat;
- struct wayland_surface *w = s->tablet_focus;
- if (w) {
- press_queue_flush(s, &s->tool_presses, NULL, &s->tool_buttons, tool_event(s));
- s->pen.pressure = 0;
- struct yasl_mouse_event ev = tool_event(s);
- ev.pos = s->tool_pos;
- ev.button = 3;
- ev.kind = YASL_PTR_LEAVE;
- push_mouse(s, w, ev);
- }
- s->tool_presses.n = 0;
- s->tablet_focus = NULL;
- s->tool = NULL;
- s->tool_motion = false;
- s->tool_wheel = 0;
- s->tool_buttons = 0;
- t->proximity_serial = 0;
-}
-
-static void tablet_tool_down(void *data, struct zwp_tablet_tool_v2 *tool, uint32_t serial)
-{
- (void)tool;
- struct seat *s = ((struct tablet_tool *)data)->seat;
- struct wayland_surface *w = s->tablet_focus;
- if (!w) return;
- seat_note_input(s, serial);
- s->press_serial = serial;
- s->press_surface = w;
- press_queue_push(&s->tool_presses, w, s->tool_pos, 0, false);
-}
-
-static void tablet_tool_up(void *data, struct zwp_tablet_tool_v2 *tool)
-{
- (void)tool;
- struct seat *s = ((struct tablet_tool *)data)->seat;
- struct wayland_surface *w = s->tablet_focus;
- if (!w) return;
- s->pen.pressure = 0;
- press_queue_push(&s->tool_presses, w, s->tool_pos, 0, true);
-}
-
-static void tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *tool, wl_fixed_t x, wl_fixed_t y)
-{
- (void)tool;
- struct seat *s = ((struct tablet_tool *)data)->seat;
- struct wayland_surface *w = s->tablet_focus;
- if (!w) return;
- s->tool_pos = device_from_fixed(w, x, y);
- s->tool_motion = true;
-}
-
-static void tablet_tool_button(void *data, struct zwp_tablet_tool_v2 *tool,
- uint32_t serial, uint32_t button, uint32_t state)
-{
- (void)tool;
- struct seat *s = ((struct tablet_tool *)data)->seat;
- struct wayland_surface *w = s->tablet_focus;
- if (!w) return;
- seat_note_input(s, serial);
- int b;
- switch (button) {
- case BTN_STYLUS: b = 2; break;
- case BTN_STYLUS2: b = 1; break;
- case BTN_STYLUS3: b = 3; break;
- default: return;
- }
- bool release = state == ZWP_TABLET_TOOL_V2_BUTTON_STATE_RELEASED;
- press_queue_push(&s->tool_presses, w, s->tool_pos, b, release);
-}
-
-static void tool_pressure(void *d, struct zwp_tablet_tool_v2 *t, uint32_t v)
-{
- (void)t;
- struct seat *s = ((struct tablet_tool *)d)->seat;
- s->pen.pressure = v > 65535 ? 65535 : (uint16_t)v;
- s->tool_motion = true;
-}
-
-static int8_t tilt_degrees(wl_fixed_t v)
-{
- double d = wl_fixed_to_double(v);
- return (int8_t)(d < -90 ? -90 : d > 90 ? 90 : lround(d));
-}
-
-static void tool_tilt(void *d, struct zwp_tablet_tool_v2 *t, wl_fixed_t x, wl_fixed_t y)
-{
- (void)t;
- struct seat *s = ((struct tablet_tool *)d)->seat;
- s->pen.tilt_x = tilt_degrees(x);
- s->pen.tilt_y = tilt_degrees(y);
- s->tool_motion = true;
-}
-
-static void tool_wheel(void *d, struct zwp_tablet_tool_v2 *t, wl_fixed_t deg, int32_t clicks)
-{
- (void)t; (void)deg;
- ((struct tablet_tool *)d)->seat->tool_wheel += clicks;
-}
-
-static void tool_frame(void *d, struct zwp_tablet_tool_v2 *t, uint32_t time)
-{
- (void)t; (void)time;
- struct seat *s = ((struct tablet_tool *)d)->seat;
- struct wayland_surface *w = s->tablet_focus;
- if (!w) {
- s->tool_presses.n = 0;
- s->tool_wheel = 0;
- return;
- }
- struct yasl_mouse_event like = tool_event(s);
- if (s->tool_motion) {
- struct yasl_mouse_event ev = like;
- ev.pos = s->tool_pos;
- ev.button = motion_button(s->tool_buttons);
- ev.kind = YASL_PTR_MOTION;
- push_mouse(s, w, ev);
- s->tool_motion = false;
- }
- press_queue_flush(s, &s->tool_presses, NULL, &s->tool_buttons, like);
- if (s->tool_wheel) {
- struct yasl_mouse_event ev = like;
- ev.pos = s->tool_pos;
- ev.kind = YASL_PTR_SCROLL;
- ev.scroll.y = s->tool_wheel;
- push_mouse(s, w, ev);
- s->tool_wheel = 0;
- }
-}
-
-static void tablet_tool_removed(void *data, struct zwp_tablet_tool_v2 *tool)
-{
- struct tablet_tool *t = data;
- struct seat *s = t->seat;
- if (s->tool == t) {
- tablet_tool_proximity_out(t, tool);
- }
- struct tablet_tool **link = &s->tablet_tools;
- while (*link && *link != t)
- link = &(*link)->next;
- if (*link)
- *link = t->next;
- if (t->shape_dev)
- wp_cursor_shape_device_v1_destroy(t->shape_dev);
- zwp_tablet_tool_v2_destroy(tool);
- free(t);
-}
-
-static void tool_type(void *d, struct zwp_tablet_tool_v2 *t, uint32_t type)
-{
- (void)t;
- ((struct tablet_tool *)d)->eraser = type == ZWP_TABLET_TOOL_V2_TYPE_ERASER;
-}
-
-static void tool_hardware_serial(void *d, struct zwp_tablet_tool_v2 *t, uint32_t hi, uint32_t lo) { (void)d; (void)t; (void)hi; (void)lo; }
-static void tool_hardware_id_wacom(void *d, struct zwp_tablet_tool_v2 *t, uint32_t hi, uint32_t lo) { (void)d; (void)t; (void)hi; (void)lo; }
-static void tool_capability(void *d, struct zwp_tablet_tool_v2 *t, uint32_t cap) { (void)d; (void)t; (void)cap; }
-static void tool_done(void *d, struct zwp_tablet_tool_v2 *t) { (void)d; (void)t; }
-static void tool_distance(void *d, struct zwp_tablet_tool_v2 *t, uint32_t v) { (void)d; (void)t; (void)v; }
-static void tool_rotation(void *d, struct zwp_tablet_tool_v2 *t, wl_fixed_t deg) { (void)d; (void)t; (void)deg; }
-static void tool_slider(void *d, struct zwp_tablet_tool_v2 *t, int32_t pos) { (void)d; (void)t; (void)pos; }
-
-static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = {
- .type = tool_type, .hardware_serial = tool_hardware_serial,
- .hardware_id_wacom = tool_hardware_id_wacom, .capability = tool_capability,
- .done = tool_done, .removed = tablet_tool_removed,
- .proximity_in = tablet_tool_proximity_in, .proximity_out = tablet_tool_proximity_out,
- .down = tablet_tool_down, .up = tablet_tool_up, .motion = tablet_tool_motion,
- .pressure = tool_pressure, .distance = tool_distance, .tilt = tool_tilt,
- .rotation = tool_rotation, .slider = tool_slider, .wheel = tool_wheel,
- .button = tablet_tool_button, .frame = tool_frame,
-};
-
-static void tablet_name(void *data, struct zwp_tablet_v2 *tablet, const char *name) { (void)data; (void)tablet; (void)name; }
-static void tablet_id(void *data, struct zwp_tablet_v2 *tablet, uint32_t vid, uint32_t pid) { (void)data; (void)tablet; (void)vid; (void)pid; }
-static void tablet_path(void *data, struct zwp_tablet_v2 *tablet, const char *path) { (void)data; (void)tablet; (void)path; }
-static void tablet_done(void *data, struct zwp_tablet_v2 *tablet) { (void)data; (void)tablet; }
-static void tablet_bustype(void *data, struct zwp_tablet_v2 *tablet, uint32_t bustype) { (void)data; (void)tablet; (void)bustype; }
-
-static void tablet_removed(void *data, struct zwp_tablet_v2 *tablet)
-{
- struct seat *s = data;
- struct tablet_device **link = &s->tablet_devices;
- while (*link && (*link)->proxy != tablet)
- link = &(*link)->next;
- if (*link) {
- struct tablet_device *removed = *link;
- *link = removed->next;
- free(removed);
- }
- zwp_tablet_v2_destroy(tablet);
-}
-
-static const struct zwp_tablet_v2_listener tablet_listener = {
- .name = tablet_name, .id = tablet_id, .path = tablet_path,
- .done = tablet_done, .removed = tablet_removed, .bustype = tablet_bustype,
-};
-
-/* yasl does not use pad groups. The group proxy belongs to the client, so
- * destroy it here rather than leak it. */
-static void tablet_pad_group(void *data, struct zwp_tablet_pad_v2 *pad, struct zwp_tablet_pad_group_v2 *group) { (void)data; (void)pad; zwp_tablet_pad_group_v2_destroy(group); }
-static void tablet_pad_path(void *data, struct zwp_tablet_pad_v2 *pad, const char *path) { (void)data; (void)pad; (void)path; }
-static void tablet_pad_buttons(void *data, struct zwp_tablet_pad_v2 *pad, uint32_t buttons) { (void)data; (void)pad; (void)buttons; }
-static void tablet_pad_done(void *data, struct zwp_tablet_pad_v2 *pad) { (void)data; (void)pad; }
-static void tablet_pad_button(void *data, struct zwp_tablet_pad_v2 *pad, uint32_t time, uint32_t button, uint32_t state) { (void)data; (void)pad; (void)time; (void)button; (void)state; }
-static void tablet_pad_enter(void *data, struct zwp_tablet_pad_v2 *pad, uint32_t serial, struct zwp_tablet_v2 *tablet, struct wl_surface *surface) { (void)data; (void)pad; (void)serial; (void)tablet; (void)surface; }
-static void tablet_pad_leave(void *data, struct zwp_tablet_pad_v2 *pad, uint32_t serial, struct wl_surface *surface) { (void)data; (void)pad; (void)serial; (void)surface; }
-
-static void tablet_pad_removed(void *data, struct zwp_tablet_pad_v2 *pad)
-{
- struct seat *s = data;
- struct tablet_pad **link = &s->tablet_pads;
- while (*link && (*link)->proxy != pad)
- link = &(*link)->next;
- if (*link) {
- struct tablet_pad *removed = *link;
- *link = removed->next;
- free(removed);
- }
- zwp_tablet_pad_v2_destroy(pad);
-}
-
-static const struct zwp_tablet_pad_v2_listener tablet_pad_listener = {
- .group = tablet_pad_group, .path = tablet_pad_path, .buttons = tablet_pad_buttons,
- .done = tablet_pad_done, .button = tablet_pad_button, .enter = tablet_pad_enter,
- .leave = tablet_pad_leave, .removed = tablet_pad_removed,
-};
-
-void seat_destroy_tablet(struct seat *s)
-{
- while (s->tablet_tools)
- tablet_tool_removed(s->tablet_tools, s->tablet_tools->proxy);
- while (s->tablet_pads)
- tablet_pad_removed(s, s->tablet_pads->proxy);
- while (s->tablet_devices)
- tablet_removed(s, s->tablet_devices->proxy);
- if (s->tablet_seat) {
- zwp_tablet_seat_v2_destroy(s->tablet_seat);
- s->tablet_seat = NULL;
- }
-}
-
-static void tablet_seat_tablet_added(void *data, struct zwp_tablet_seat_v2 *tablet_seat, struct zwp_tablet_v2 *tablet)
-{
- (void)tablet_seat;
- struct seat *s = data;
- struct tablet_device *owned = calloc(1, sizeof(*owned));
- if (!owned) { zwp_tablet_v2_destroy(tablet); return; }
- owned->proxy = tablet;
- owned->next = s->tablet_devices;
- s->tablet_devices = owned;
- zwp_tablet_v2_add_listener(tablet, &tablet_listener, s);
-}
-
-static void tablet_seat_tool_added(void *data, struct zwp_tablet_seat_v2 *tablet_seat, struct zwp_tablet_tool_v2 *tool)
-{
- (void)tablet_seat;
- struct seat *s = data;
- struct tablet_tool *owned = calloc(1, sizeof(*owned));
- if (!owned) { zwp_tablet_tool_v2_destroy(tool); return; }
- owned->proxy = tool;
- owned->seat = s;
- owned->next = s->tablet_tools;
- s->tablet_tools = owned;
- zwp_tablet_tool_v2_add_listener(tool, &tablet_tool_listener, owned);
-}
-
-static void tablet_seat_pad_added(void *data, struct zwp_tablet_seat_v2 *tablet_seat, struct zwp_tablet_pad_v2 *pad)
-{
- (void)tablet_seat;
- struct seat *s = data;
- struct tablet_pad *owned = calloc(1, sizeof(*owned));
- if (!owned) { zwp_tablet_pad_v2_destroy(pad); return; }
- owned->proxy = pad;
- owned->next = s->tablet_pads;
- s->tablet_pads = owned;
- zwp_tablet_pad_v2_add_listener(pad, &tablet_pad_listener, s);
-}
-
-static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = {
- .tablet_added = tablet_seat_tablet_added,
- .tool_added = tablet_seat_tool_added,
- .pad_added = tablet_seat_pad_added,
-};
-
-static void clipboard_received(const char *text, size_t len, bool uri_list,
- struct wl_surface *on, void *ud)
-{
- struct seat *s = ud;
- struct wayland_display *c = s->conn;
- struct wayland_surface *w = conn_surface_for(c, on);
- if (uri_list) w = surface_root(w);
- if (!w || w->closed) return;
- struct yasl_input_event ev = {
- .surface = &w->base,
- .kind = uri_list ? YASL_INPUT_DROP_FILES : YASL_INPUT_PASTE,
- };
- if (uri_list) {
- ev.drop_files.files = text;
- ev.drop_files.len = len;
- } else {
- ev.paste.text = text;
- ev.paste.len = len;
- }
- input_queue_push(&w->input, &ev);
-}
-
-static void clipboard_drag(enum yasl_drag_event ev, struct wl_surface *on,
- double x, double y, void *ud)
-{
- struct seat *s = ud;
- conn_drag_target(s->conn, ev, on, x, y);
-}
-
-static void clipboard_drop_hover(enum yasl_drop_event ev, struct wl_surface *on,
- double x, double y, void *ud)
-{
- struct seat *s = ud;
- conn_drop_target(s->conn, ev, on, x, y);
-}
-
-void seat_clipboard_ensure(struct seat *s)
-{
- struct wayland_display *c = s->conn;
- if (!c->data_manager || !s->proxy)
- return;
- if (!s->clipboard) {
- s->clipboard = clipboard_create(c->wl, c->data_manager, s->proxy,
- c->loop, clipboard_received, s);
- if (!s->clipboard)
- return;
- clipboard_set_drag_handler(s->clipboard, clipboard_drag, s);
- clipboard_set_drop_handler(s->clipboard, clipboard_drop_hover, s);
- }
- if (c->primary_selection_mgr)
- clipboard_set_primary_manager(s->clipboard, c->primary_selection_mgr);
-}
-
-static void seat_drop_pointer(struct seat *s)
-{
- if (s->cursor_shape_dev) {
- wp_cursor_shape_device_v1_destroy(s->cursor_shape_dev);
- s->cursor_shape_dev = NULL;
- }
- if (s->pointer) {
- if (wl_pointer_get_version(s->pointer) >= WL_POINTER_RELEASE_SINCE_VERSION)
- wl_pointer_release(s->pointer);
- else
- wl_pointer_destroy(s->pointer);
- s->pointer = NULL;
- }
- seat_pointer_reset(s);
- s->pointer_focus = s->ptr_left = NULL;
- s->ptr_presses.n = 0;
-}
-
-static void seat_drop_keyboard(struct seat *s)
-{
- keyboard_repeat_stop(s);
- keyboard_text_reset(s);
- if (s->keyboard) {
- if (wl_keyboard_get_version(s->keyboard) >= WL_KEYBOARD_RELEASE_SINCE_VERSION)
- wl_keyboard_release(s->keyboard);
- else
- wl_keyboard_destroy(s->keyboard);
- s->keyboard = NULL;
- }
- s->repeat_rate = 0;
- struct wayland_surface *w = s->keyboard_focus;
- s->keyboard_focus = NULL;
- if (w && !s->focus_leaving)
- s->focus_leaving = w;
-}
-
-static void seat_drop_touch(struct seat *s)
-{
- if (s->touch) {
- touch_cancel(s, s->touch);
- if (wl_touch_get_version(s->touch) >= WL_TOUCH_RELEASE_SINCE_VERSION)
- wl_touch_release(s->touch);
- else
- wl_touch_destroy(s->touch);
- s->touch = NULL;
- }
-}
-
-static void seat_capabilities(void *data, struct wl_seat *proxy, uint32_t caps)
-{
- struct seat *s = data;
- struct wayland_display *c = s->conn;
- if (caps & WL_SEAT_CAPABILITY_KEYBOARD) {
- if (!s->keyboard) {
- s->keyboard = wl_seat_get_keyboard(proxy);
- if (s->keyboard)
- wl_keyboard_add_listener(s->keyboard, &keyboard_listener, s);
- if (s->keyboard && wl_keyboard_get_version(s->keyboard) <
- WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) {
- s->repeat_rate = 25;
- s->repeat_delay = 600;
- }
- }
- } else if (s->keyboard) {
- seat_drop_keyboard(s);
- }
-
- if (caps & WL_SEAT_CAPABILITY_POINTER) {
- if (!s->pointer) {
- s->pointer = wl_seat_get_pointer(proxy);
- if (s->pointer)
- wl_pointer_add_listener(s->pointer, &pointer_listener, s);
- if (s->pointer && c->cursor_shape_mgr)
- s->cursor_shape_dev = wp_cursor_shape_manager_v1_get_pointer(
- c->cursor_shape_mgr, s->pointer);
- }
- } else if (s->pointer) {
- seat_drop_pointer(s);
- }
-
- if (caps & WL_SEAT_CAPABILITY_TOUCH) {
- if (!s->touch) {
- s->touch = wl_seat_get_touch(proxy);
- if (s->touch)
- wl_touch_add_listener(s->touch, &touch_listener, s);
- }
- } else if (s->touch) {
- seat_drop_touch(s);
- }
-
- if (c->tablet_mgr && !s->tablet_seat) {
- s->tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(c->tablet_mgr, proxy);
- if (s->tablet_seat)
- zwp_tablet_seat_v2_add_listener(s->tablet_seat, &tablet_seat_listener, s);
- }
-
- if (c->text_input_mgr && !s->text_input) {
- s->text_input = zwp_text_input_manager_v3_get_text_input(c->text_input_mgr, proxy);
- if (s->text_input)
- zwp_text_input_v3_add_listener(s->text_input, &text_input_listener, s);
- }
-
- seat_clipboard_ensure(s);
-}
-
-static void seat_name(void *data, struct wl_seat *seat, const char *name)
-{ (void)data; (void)seat; (void)name; }
-
-const struct wl_seat_listener seat_listener = {
- .capabilities = seat_capabilities,
- .name = seat_name,
-};
-
-void seat_bind(struct wayland_display *c, struct wl_registry *registry,
- uint32_t name, uint32_t version)
-{
- struct seat *s = calloc(1, sizeof(*s));
- if (!s) return;
- s->conn = c;
- s->name = name;
- s->repeat_fd = -1;
- s->cursor_shape = -1;
- s->proxy = wl_registry_bind(registry, name, &wl_seat_interface,
- version < 8 ? version : 8);
- if (!s->proxy) {
- free(s);
- return;
- }
- s->next = c->seats;
- c->seats = s;
- wl_seat_add_listener(s->proxy, &seat_listener, s);
- keyboard_repeat_init(s);
-}
-
-void seat_forget_surface(struct seat *s, struct wayland_surface *w)
-{
- clipboard_forget_surface(s->clipboard, w->surface);
- struct wayland_surface **refs[] = {
- &s->pointer_focus, &s->keyboard_focus,
- &s->tablet_focus, &s->ime_focus, &s->focus_leaving, &s->ptr_left,
- &s->press_surface,
- };
- for (size_t i = 0; i < sizeof(refs) / sizeof(refs[0]); i++)
- if (*refs[i] == w)
- *refs[i] = NULL;
- press_queue_forget(&s->ptr_presses, w);
- press_queue_forget(&s->tool_presses, w);
- for (int i = 0; i < SEAT_TOUCH_POINTS; i++) {
- if (s->touch_points[i].active && s->touch_points[i].surface == w) {
- if (s->touch_primary == &s->touch_points[i]) {
- s->touch_primary = NULL;
- s->touch_pressed = false;
- }
- s->touch_points[i] = (struct touch_point){0};
- }
- }
-}
-
-void seat_destroy(struct seat *s)
-{
- struct wayland_display *c = s->conn;
- for (struct seat **link = &c->seats; *link; link = &(*link)->next) {
- if (*link == s) {
- *link = s->next;
- break;
- }
- }
- if (c->active_seat == s)
- c->active_seat = NULL;
- for (struct wayland_surface *w = c->surfaces; w; w = w->conn_next) {
- if (w->ime_seat == s) {
- w->ime_seat = NULL;
- ime_reset(w);
- }
- }
- if (c->drag.seat == s)
- conn_drag_end(c);
- if (s->text_input)
- zwp_text_input_v3_destroy(s->text_input);
- seat_destroy_tablet(s);
- seat_drop_pointer(s);
- seat_drop_keyboard(s);
- struct wayland_surface *left = s->focus_leaving;
- if (left && !conn_keyboard_on(c, left, NULL)) {
- struct yasl_input_event ev = {
- .kind = YASL_INPUT_FOCUS,
- .surface = &left->base,
- .focus = { .focused = false },
- };
- input_queue_push(&left->input, &ev);
- }
- seat_drop_touch(s);
- clipboard_destroy(s->clipboard);
- if (s->repeat_watch > 0) yasl_loop_del_fd(c->loop, s->repeat_watch);
- if (s->repeat_fd >= 0) close(s->repeat_fd);
- if (s->cursor_viewport) wp_viewport_destroy(s->cursor_viewport);
- if (s->cursor_surface) wl_surface_destroy(s->cursor_surface);
- if (s->xkb_state) xkb_state_unref(s->xkb_state);
- if (s->compose) xkb_compose_state_unref(s->compose);
- if (s->xkb_keymap) xkb_keymap_unref(s->xkb_keymap);
- if (s->proxy) {
- if (wl_seat_get_version(s->proxy) >= WL_SEAT_RELEASE_SINCE_VERSION)
- wl_seat_release(s->proxy);
- else
- wl_seat_destroy(s->proxy);
- }
- free(s);
-}
-
-bool seat_remove(struct wayland_display *c, uint32_t name)
-{
- for (struct seat *s = c->seats; s; s = s->next) {
- if (s->name == name) {
- seat_destroy(s);
- return true;
- }
- }
- return false;
-}
-
-int display_input_init(struct wayland_display *c)
-{
- for (struct seat *s = c->seats; s; s = s->next) {
- keyboard_repeat_init(s);
- seat_clipboard_ensure(s);
- }
- return 0;
-}
-
-void surface_init_cursor(struct wayland_display *c)
-{
- if (c->cursor_shape_mgr)
- return;
- const char *env_size = getenv("XCURSOR_SIZE");
- int size = env_size ? atoi(env_size) : 0;
- c->cursor_theme_name = getenv("XCURSOR_THEME");
- c->cursor_size = size > 0 && size <= 512 ? size : 24;
- cursor_theme_for(c, 1);
-}