From 76073fe5fad8799e5850805f2f090af2cb62c741 Mon Sep 17 00:00:00 2001 From: Berke Güzel Date: Tue, 13 Oct 2026 23:41:31 +0300 Subject: Simplify the public event and CPU API Applications now need far less ceremony: hello.c is a 20-line loop that handles REFRESH, CLOSE and QUIT and draws into the surface's own pixels. - Fold GEOMETRY, STATE and FOCUS into one WINDOW event carrying size, scale and state; unchanged values send nothing. - Guarantee REFRESH once a window has a size and after every resize, never at size zero. - Merge DROP_HOVER into DROP with over/leave/data actions and give drag and drop actions enums. - Keep event strings valid until the next wait and drop yasl_event_release; empty or failed waits report NONE. - Replace copy-in presentation with a lent pixel buffer: yasl_cpu_pixels and yasl_cpu_present. - Remove yasl_poll_event, yasl_cpu_read_pixels, unused event fields and comments that restated names. - Wayland: resize floating windows in request_size instead of reporting it unsupported, and stop marking new GPU surfaces as Vulkan so yasl_vulkan_create_surface no longer fails with NATIVE_WINDOW_IN_USE. Also includes the in-progress public API refactor that was uncommitted in the tree (removal of the app/loop layer, new surface, GL and Vulkan entry points). Co-Authored-By: Claude Opus 5.5 --- src/platform/wayland/pointer.c | 398 +++++++++++++++++++++++++++++++---------- 1 file changed, 300 insertions(+), 98 deletions(-) (limited to 'src/platform/wayland/pointer.c') diff --git a/src/platform/wayland/pointer.c b/src/platform/wayland/pointer.c index da666da..5f486ae 100644 --- a/src/platform/wayland/pointer.c +++ b/src/platform/wayland/pointer.c @@ -12,12 +12,22 @@ struct tablet_tool { struct zwp_tablet_tool_v2 *proxy; struct wp_cursor_shape_device_v1 *shape_dev; uint32_t proximity_serial; + uint64_t device_id, tool_id; + uint32_t axes_valid, axes_changed, capability_mask; + double x, y; + double pressure, tilt_x, tilt_y, rotation, distance, tangential, wheel_degrees; + unsigned changed_button; + unsigned pending_actions[8], pending_buttons[8], pending_action_count; + bool pending_contacts[8]; + unsigned kind; + bool in_contact, pen_in_proximity; bool eraser; }; struct tablet_device { struct tablet_device *next; struct zwp_tablet_v2 *proxy; + uint64_t id; }; struct tablet_pad { @@ -25,10 +35,10 @@ struct tablet_pad { struct zwp_tablet_pad_v2 *proxy; }; -static struct yasl_vector2i device_from_fixed(const struct wayland_surface *w, +static struct yasl_private_vector2i device_from_fixed(const struct wayland_surface *w, wl_fixed_t x, wl_fixed_t y) { - return (struct yasl_vector2i){ + return (struct yasl_private_vector2i){ .x = (int)lrint(wl_fixed_to_double(x) * w->scale_factor), .y = (int)lrint(wl_fixed_to_double(y) * w->scale_factor), }; @@ -41,10 +51,10 @@ void seat_note_input(struct seat *s, uint32_t serial) } static void push_pointer(struct seat *s, struct wayland_surface *w, - enum yasl_event_type type, struct yasl_pointer_event ev) + enum yasl_private_event_type type, struct yasl_private_pointer_event ev) { ev.mods = (uint32_t)seat_modifiers(s); - struct yasl_event input_ev = { + struct yasl_private_event input_ev = { .type = type, .surface = &w->base, .pointer = ev, @@ -52,13 +62,15 @@ static void push_pointer(struct seat *s, struct wayland_surface *w, input_queue_push(&surface_root(w)->input, &input_ev); } -static void report_wheel(struct seat *s, struct wayland_surface *w, - struct yasl_vector2i pos, double x, double y) +static unsigned scroll_source_of(uint32_t source) { - if ((x == 0 && y == 0) || !isfinite(x) || !isfinite(y)) return; - push_pointer(s, w, YASL_EVENT_POINTER_SCROLL, (struct yasl_pointer_event){ - .pos = pos, .scroll = {x, y}, - }); + switch (source) { + case WL_POINTER_AXIS_SOURCE_WHEEL: return 1; + case WL_POINTER_AXIS_SOURCE_WHEEL_TILT: return 1; + case WL_POINTER_AXIS_SOURCE_FINGER: return 2; + case WL_POINTER_AXIS_SOURCE_CONTINUOUS: return 3; + default: return 0; + } } static bool cursor_theme_for(struct wayland_display *c, int scale) @@ -90,10 +102,10 @@ static bool seat_cursor_surface(struct seat *s) } static void set_cursor_theme_fallback(struct seat *s, struct wayland_surface *w, - enum yasl_cursor shape) + enum yasl_private_cursor shape) { struct wayland_display *c = s->conn; - int scale = (int)((w->scale_120 + YASL_SCALE_UNIT - 1) / YASL_SCALE_UNIT); + int scale = (int)((w->scale_120 + YASL_PRIVATE_SCALE_UNIT - 1) / YASL_PRIVATE_SCALE_UNIT); if (scale < 1) scale = 1; if (!seat_cursor_surface(s) || !cursor_theme_for(c, scale)) return; static const char *names[][2] = { @@ -107,7 +119,7 @@ static void set_cursor_theme_fallback(struct seat *s, struct wayland_surface *w, {"ew-resize", "ew-resize"}, {"ns-resize", "ns-resize"}, }; - int idx = (unsigned)shape < YASL_CURSOR_HIDDEN ? (int)shape : 0; + int idx = (unsigned)shape < YASL_PRIVATE_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; @@ -117,11 +129,11 @@ static void set_cursor_theme_fallback(struct seat *s, struct wayland_surface *w, int theme_scale = c->cursor_theme_scale; if (s->cursor_viewport) { - uint32_t scale_120 = (uint32_t)theme_scale * YASL_SCALE_UNIT; + uint32_t scale_120 = (uint32_t)theme_scale * YASL_PRIVATE_SCALE_UNIT; wp_viewport_set_destination(s->cursor_viewport, - (int)(((int64_t)(int)img->width * YASL_SCALE_UNIT + scale_120 - 1) / + (int)(((int64_t)(int)img->width * YASL_PRIVATE_SCALE_UNIT + scale_120 - 1) / scale_120), - (int)(((int64_t)(int)img->height * YASL_SCALE_UNIT + scale_120 - 1) / + (int)(((int64_t)(int)img->height * YASL_PRIVATE_SCALE_UNIT + scale_120 - 1) / scale_120)); } else { if (img->width % (uint32_t)theme_scale || img->height % (uint32_t)theme_scale) @@ -137,17 +149,17 @@ static void set_cursor_theme_fallback(struct seat *s, struct wayland_surface *w, wl_surface_commit(s->cursor_surface); } -static uint32_t cursor_shape_of(enum yasl_cursor shape) +static uint32_t cursor_shape_of(enum yasl_private_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; + case YASL_PRIVATE_CURSOR_TEXT: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT; + case YASL_PRIVATE_CURSOR_LINK: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER; + case YASL_PRIVATE_CURSOR_CROSSHAIR: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR; + case YASL_PRIVATE_CURSOR_MOVE: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE; + case YASL_PRIVATE_CURSOR_RESIZE_EW: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_EW_RESIZE; + case YASL_PRIVATE_CURSOR_RESIZE_NS: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NS_RESIZE; + case YASL_PRIVATE_CURSOR_RESIZE_NWSE: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NWSE_RESIZE; + case YASL_PRIVATE_CURSOR_RESIZE_NESW: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NESW_RESIZE; default: return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT; } } @@ -155,11 +167,11 @@ static uint32_t cursor_shape_of(enum yasl_cursor shape) /* Relative mode hides the pointer but keeps w->cursor for the return to NORMAL. */ static void seat_set_cursor(struct seat *s, struct wayland_surface *w) { - enum yasl_cursor shape = w->relative ? YASL_CURSOR_HIDDEN : w->cursor; + enum yasl_private_cursor shape = w->relative ? YASL_PRIVATE_CURSOR_HIDDEN : w->cursor; if (!s->pointer || !s->pointer_serial || s->pointer_focus != w || s->cursor_shape == (int)shape) return; - if (shape == YASL_CURSOR_HIDDEN) + if (shape == YASL_PRIVATE_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, @@ -169,20 +181,20 @@ static void seat_set_cursor(struct seat *s, struct wayland_surface *w) s->cursor_shape = shape; } -static void tool_set_cursor(struct tablet_tool *t, enum yasl_cursor shape) +static void tool_set_cursor(struct tablet_tool *t, enum yasl_private_cursor shape) { if (!t->proximity_serial) return; - if (shape == YASL_CURSOR_HIDDEN) + if (shape == YASL_PRIVATE_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) +void wayland_surface_set_cursor(struct wayland_surface *w, enum yasl_private_cursor shape) { - if (!w || !w->conn || w->destroyed || (unsigned)shape > YASL_CURSOR_HIDDEN) return; + if (!w || !w->conn || w->destroyed || (unsigned)shape > YASL_PRIVATE_CURSOR_HIDDEN) return; w->cursor = shape; for (struct seat *s = w->conn->seats; s; s = s->next) { seat_set_cursor(s, w); @@ -193,7 +205,7 @@ void wayland_surface_set_cursor(struct wayland_surface *w, enum yasl_cursor shap static void press_queue_flush(struct seat *s, struct press_queue *q, struct wayland_surface *only, uint64_t *buttons, - struct yasl_pointer_event like) + struct yasl_private_pointer_event like) { int kept = 0; int count = q->n; @@ -206,10 +218,10 @@ static void press_queue_flush(struct seat *s, struct press_queue *q, if (!p.surface) continue; uint64_t mask = 1ull << p.button; *buttons = (*buttons & ~mask) | ((uint64_t)(!p.release) << p.button); - struct yasl_pointer_event ev = like; + struct yasl_private_pointer_event ev = like; ev.pos = p.pos; - ev.button = (enum yasl_pointer_button)p.button; - enum yasl_event_type type = p.release ? YASL_EVENT_POINTER_UP : YASL_EVENT_POINTER_DOWN; + ev.button = (enum yasl_private_pointer_button)p.button; + enum yasl_private_event_type type = p.release ? YASL_PRIVATE_EVENT_POINTER_UP : YASL_PRIVATE_EVENT_POINTER_DOWN; push_pointer(s, p.surface, type, ev); } q->head = 0; @@ -217,7 +229,7 @@ static void press_queue_flush(struct seat *s, struct press_queue *q, } static void press_queue_push(struct press_queue *q, struct wayland_surface *w, - struct yasl_vector2i pos, int button, bool release) + struct yasl_private_vector2i pos, int button, bool release) { if (q->n == 8) { q->head = (q->head + 1) & 7; @@ -244,10 +256,15 @@ void seat_pointer_reset(struct seat *s) s->pointer_serial = 0; s->motion_pending = false; memset(s->axis, 0, sizeof(s->axis)); + memset(s->axis_pixels, 0, sizeof(s->axis_pixels)); 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->axis_stop_pending = false; + s->scroll_gesture = false; + s->axis_phase = 0; + s->axis_source = WL_POINTER_AXIS_SOURCE_WHEEL; s->cursor_shape = -1; } @@ -263,7 +280,7 @@ static void flush_pending_motion(struct seat *s, struct wayland_surface *w) { if (!s->motion_pending) return; s->motion_pending = false; - push_pointer(s, w, YASL_EVENT_POINTER_MOTION, (struct yasl_pointer_event){ + push_pointer(s, w, YASL_PRIVATE_EVENT_POINTER_MOTION, (struct yasl_private_pointer_event){ .pos = s->pointer_pos, }); } @@ -356,6 +373,13 @@ static void pointer_axis(void *data, struct wl_pointer *pointer, double v = wl_fixed_to_double(value); if (likely(axis < 2)) { s->axis[axis] += v; + s->axis_pixels[axis] += v; + if (s->axis_source == WL_POINTER_AXIS_SOURCE_FINGER || + s->axis_source == WL_POINTER_AXIS_SOURCE_CONTINUOUS) { + if (!s->scroll_gesture) s->axis_phase = 1u; + else if (s->axis_phase != 1u) s->axis_phase = 2u; + s->scroll_gesture = true; + } } pointer_event_done(s); } @@ -363,13 +387,14 @@ static void pointer_axis(void *data, struct wl_pointer *pointer, static void pointer_axis_source(void *data, struct wl_pointer *pointer, uint32_t axis_source) { (void)pointer; - (void)data; (void)axis_source; + ((struct seat *)data)->axis_source = 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; + (void)pointer; (void)time; (void)axis; + ((struct seat *)data)->axis_stop_pending = true; } static void pointer_axis_discrete(void *data, struct wl_pointer *pointer, uint32_t axis, int32_t discrete) @@ -405,7 +430,28 @@ static void pointer_frame_scroll(struct seat *s, struct wayland_surface *w) 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]); + bool stopped = s->axis_stop_pending; + unsigned source = scroll_source_of(s->axis_source); + unsigned phase = source == 2 || source == 3 + ? (stopped ? 3u : s->axis_phase) : 0u; + bool has_pixels = (source == 2 || source == 3) && + (s->axis_pixels[0] != 0 || s->axis_pixels[1] != 0); + if (lines[0] != 0 || lines[1] != 0 || stopped) { + push_pointer(s, w, YASL_PRIVATE_EVENT_POINTER_SCROLL, + (struct yasl_private_pointer_event){ + .pos = s->pointer_pos, + .scroll = {lines[1], lines[0]}, + .pixel_scroll = {s->axis_pixels[1] * w->scale_factor, + s->axis_pixels[0] * w->scale_factor}, + .scroll_valid = 1u | (has_pixels ? 2u : 0u), + .scroll_source = source, + .scroll_phase = phase, + }); + } + memset(s->axis_pixels, 0, sizeof(s->axis_pixels)); + s->axis_stop_pending = false; + if (stopped) s->scroll_gesture = false; + s->axis_phase = 0; } static void pointer_frame(void *data, struct wl_pointer *pointer) @@ -416,14 +462,14 @@ static void pointer_frame(void *data, struct wl_pointer *pointer) if (left) { s->ptr_left = NULL; if (s->ptr_left_motion) - push_pointer(s, left, YASL_EVENT_POINTER_MOTION, (struct yasl_pointer_event){ + push_pointer(s, left, YASL_PRIVATE_EVENT_POINTER_MOTION, (struct yasl_private_pointer_event){ .pos = s->ptr_left_pos, }); - press_queue_flush(s, &s->ptr_presses, left, &s->pointer_buttons, (struct yasl_pointer_event){0}); - push_pointer(s, left, YASL_EVENT_POINTER_LEAVE, (struct yasl_pointer_event){ + press_queue_flush(s, &s->ptr_presses, left, &s->pointer_buttons, (struct yasl_private_pointer_event){0}); + push_pointer(s, left, YASL_PRIVATE_EVENT_POINTER_LEAVE, (struct yasl_private_pointer_event){ .pos = s->ptr_left_pos, }); - struct yasl_vector2i pos = s->pointer_pos; + struct yasl_private_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; @@ -440,7 +486,7 @@ static void pointer_frame(void *data, struct wl_pointer *pointer) } flush_pending_motion(s, w); - press_queue_flush(s, &s->ptr_presses, NULL, &s->pointer_buttons, (struct yasl_pointer_event){0}); + press_queue_flush(s, &s->ptr_presses, NULL, &s->pointer_buttons, (struct yasl_private_pointer_event){0}); pointer_frame_scroll(s, w); } @@ -460,7 +506,7 @@ static void relative_motion(void *data, struct zwp_relative_pointer_v1 *pointer, /* Unlocked movement arrives as wl_pointer.motion; the queue derives its delta. */ if (!w || !w->pointer_locked || w->lock_seat != s) return; flush_pending_motion(s, w); - push_pointer(s, w, YASL_EVENT_POINTER_MOTION, (struct yasl_pointer_event){ + push_pointer(s, w, YASL_PRIVATE_EVENT_POINTER_MOTION, (struct yasl_private_pointer_event){ .pos = s->pointer_pos, .delta = {wl_fixed_to_double(dx) * w->scale_factor, wl_fixed_to_double(dy) * w->scale_factor}, @@ -525,12 +571,12 @@ static void seat_lock_surfaces(struct seat *s) surface_lock_pointer(w, s); } -bool wayland_surface_set_pointer_mode(struct wayland_surface *w, enum yasl_pointer_mode mode) +bool wayland_surface_set_pointer_mode(struct wayland_surface *w, enum yasl_private_pointer_mode mode) { if (!w || !w->conn || w->destroyed) return false; struct wayland_display *c = w->conn; - bool relative = mode == YASL_POINTER_RELATIVE; + bool relative = mode == YASL_PRIVATE_POINTER_RELATIVE; if (relative && (!c->relative_pointer_mgr || !c->pointer_constraints)) return false; w->relative = relative; @@ -572,10 +618,10 @@ static struct touch_point *touch_find(struct seat *s, int32_t id) return NULL; } -static struct yasl_vector2i touch_pos(const struct touch_point *p) +static struct yasl_private_vector2i touch_pos(const struct touch_point *p) { double scale = p->surface->scale_factor; - return (struct yasl_vector2i){ + return (struct yasl_private_vector2i){ .x = (int)lrint(p->x * scale), .y = (int)lrint(p->y * scale), }; } @@ -583,11 +629,11 @@ static struct yasl_vector2i touch_pos(const struct touch_point *p) static void touch_report(struct seat *s, struct touch_point *p, int button, - enum yasl_event_type type) + enum yasl_private_event_type type) { - push_pointer(s, p->surface, type, (struct yasl_pointer_event){ - .pos = touch_pos(p), .button = (enum yasl_pointer_button)button, - .device = YASL_PTR_DEV_TOUCH, + push_pointer(s, p->surface, type, (struct yasl_private_pointer_event){ + .pos = touch_pos(p), .button = (enum yasl_private_pointer_button)button, + .device = YASL_PRIVATE_PTR_DEV_TOUCH, }); } @@ -644,7 +690,7 @@ static void touch_frame(void *data, struct wl_touch *touch) if (p->down && !s->touch_primary && !s->touch_scrolling) { s->touch_primary = p; s->touch_pressed = true; - touch_report(s, p, 0, YASL_EVENT_POINTER_DOWN); + touch_report(s, p, 0, YASL_PRIVATE_EVENT_POINTER_DOWN); } if (!p->up) { active_n++; @@ -657,7 +703,7 @@ static void touch_frame(void *data, struct wl_touch *touch) 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_EVENT_POINTER_UP); + touch_report(s, primary, 0, YASL_PRIVATE_EVENT_POINTER_UP); s->touch_pressed = false; s->touch_scrolling = true; s->touch_scroll_y = centroid_n ? centroid_sum / centroid_n : 0; @@ -667,14 +713,14 @@ static void touch_frame(void *data, struct wl_touch *touch) s->touch_scroll_y = y; if (dy != 0.0) { double lines = dy / SCROLL_PX_PER_LINE; - push_pointer(s, primary->surface, YASL_EVENT_POINTER_SCROLL, (struct yasl_pointer_event){ + push_pointer(s, primary->surface, YASL_PRIVATE_EVENT_POINTER_SCROLL, (struct yasl_private_pointer_event){ .pos = touch_pos(primary), .scroll = {0, -lines}, - .device = YASL_PTR_DEV_TOUCH, + .device = YASL_PRIVATE_PTR_DEV_TOUCH, }); } } else if (primary && primary->moved && s->touch_pressed) { - touch_report(s, primary, 0, YASL_EVENT_POINTER_MOTION); + touch_report(s, primary, 0, YASL_PRIVATE_EVENT_POINTER_MOTION); } for (int i = 0; i < SEAT_TOUCH_POINTS; i++) { struct touch_point *p = &s->touch_points[i]; @@ -683,7 +729,7 @@ static void touch_frame(void *data, struct wl_touch *touch) active_n--; if (p == s->touch_primary) { if (s->touch_pressed) - touch_report(s, p, 0, YASL_EVENT_POINTER_UP); + touch_report(s, p, 0, YASL_PRIVATE_EVENT_POINTER_UP); s->touch_pressed = false; s->touch_primary = NULL; } @@ -701,7 +747,7 @@ 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_EVENT_POINTER_UP); + touch_report(s, s->touch_primary, 0, YASL_PRIVATE_EVENT_POINTER_UP); memset(s->touch_points, 0, sizeof(s->touch_points)); s->touch_primary = NULL; s->touch_pressed = false; @@ -719,29 +765,100 @@ static const struct wl_touch_listener touch_listener = { .frame = touch_frame, .cancel = touch_cancel, }; -static struct yasl_pointer_event tool_event(const struct seat *s) +static struct yasl_private_pointer_event tool_event(const struct seat *s) { - return (struct yasl_pointer_event){ - .device = s->tool && s->tool->eraser ? YASL_PTR_DEV_ERASER : YASL_PTR_DEV_PEN, + return (struct yasl_private_pointer_event){ + .device = s->tool && s->tool->eraser ? YASL_PRIVATE_PTR_DEV_ERASER : YASL_PRIVATE_PTR_DEV_PEN, .pen = s->pen, }; } +static void push_pen_sample(struct tablet_tool *tool, struct wayland_surface *w, + unsigned action, uint32_t changed) +{ + struct seat *s = tool->seat; + if (!w) return; + uint64_t buttons = s->tool_buttons; + for (int i = 0; i < s->tool_presses.n; i++) { + const struct pending_press *press = &s->tool_presses.ev[(s->tool_presses.head + i) & 7]; + if (press->surface && press->button >= 0 && press->button < 32) { + uint64_t bit = 1ull << press->button; + buttons = (buttons & ~bit) | ((uint64_t)!press->release << press->button); + } + } + if (action == YASL_PRIVATE_PEN_LEAVE || action == YASL_PRIVATE_PEN_CANCEL) + buttons = 0; + struct yasl_private_event ev = { + .type = YASL_PRIVATE_EVENT_PEN, + .surface = &w->base, + .pen = { + .device_id = tool->device_id, + .tool_id = tool->tool_id, + .x = tool->x, + .y = tool->y, + .pressure = tool->pressure, + .tilt_x = tool->tilt_x, + .tilt_y = tool->tilt_y, + .rotation = tool->rotation, + .distance = tool->distance, + .tangential = tool->tangential, + .wheel_degrees = tool->wheel_degrees, + .axes_valid = tool->axes_valid, + .axes_changed = changed, + .buttons = (uint32_t)buttons, + .changed_button = tool->changed_button, + .in_contact = tool->in_contact, + .tool = tool->kind, + .action = action, + }, + }; + input_queue_push(&surface_root(w)->input, &ev); +} + +static void pen_action_push(struct tablet_tool *tool, unsigned action, unsigned button) +{ + if (tool->pending_action_count == 8) { + memmove(tool->pending_actions, tool->pending_actions + 1, + 7 * sizeof(tool->pending_actions[0])); + memmove(tool->pending_buttons, tool->pending_buttons + 1, + 7 * sizeof(tool->pending_buttons[0])); + memmove(tool->pending_contacts, tool->pending_contacts + 1, + 7 * sizeof(tool->pending_contacts[0])); + tool->pending_action_count--; + } + unsigned i = tool->pending_action_count++; + tool->pending_actions[i] = action; + tool->pending_buttons[i] = button; + tool->pending_contacts[i] = tool->in_contact; +} + 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; + (void)tool; struct tablet_tool *t = data; struct seat *s = t->seat; struct wayland_surface *w = surface ? (struct wayland_surface *)wl_surface_get_user_data(surface) : NULL; s->tablet_focus = w; s->tool = t; + t->device_id = 0; + for (struct tablet_device *device = s->tablet_devices; device; device = device->next) + if (device->proxy == tablet) { t->device_id = device->id; break; } + t->pen_in_proximity = true; + t->in_contact = false; + t->pending_action_count = 0; + pen_action_push(t, YASL_PRIVATE_PEN_ENTER, 0); + t->axes_changed = 0; + t->pressure = t->tilt_x = t->tilt_y = t->rotation = t->distance = 0; + t->tangential = t->wheel_degrees = 0; s->tool_buttons = 0; - s->pen = (struct yasl_pointer_pen){0}; + s->pen = (struct yasl_private_pointer_pen){0}; t->proximity_serial = serial; if (!w) return; + t->x = s->tool_pos.x; + t->y = s->tool_pos.y; 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); @@ -756,11 +873,14 @@ static void tablet_tool_proximity_out(void *data, struct zwp_tablet_tool_v2 *too struct seat *s = t->seat; struct wayland_surface *w = s->tablet_focus; if (w) { + t->in_contact = false; + t->pressure = 0; + push_pen_sample(t, w, YASL_PRIVATE_PEN_LEAVE, 0); press_queue_flush(s, &s->tool_presses, NULL, &s->tool_buttons, tool_event(s)); s->pen.pressure = 0; - struct yasl_pointer_event ev = tool_event(s); + struct yasl_private_pointer_event ev = tool_event(s); ev.pos = s->tool_pos; - push_pointer(s, w, YASL_EVENT_POINTER_LEAVE, ev); + push_pointer(s, w, YASL_PRIVATE_EVENT_POINTER_LEAVE, ev); } s->tool_presses.n = 0; s->tablet_focus = NULL; @@ -769,28 +889,38 @@ static void tablet_tool_proximity_out(void *data, struct zwp_tablet_tool_v2 *too s->tool_wheel = 0; s->tool_buttons = 0; t->proximity_serial = 0; + t->pen_in_proximity = false; + t->in_contact = false; } 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 tablet_tool *t = data; + struct seat *s = t->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); + t->in_contact = true; + pen_action_push(t, YASL_PRIVATE_PEN_DOWN, 0); } static void tablet_tool_up(void *data, struct zwp_tablet_tool_v2 *tool) { (void)tool; struct seat *s = ((struct tablet_tool *)data)->seat; + struct tablet_tool *t = data; 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); + t->pressure = 0; + t->in_contact = false; + pen_action_push(t, YASL_PRIVATE_PEN_UP, 0); + t->axes_changed |= YASL_PRIVATE_PEN_PRESSURE; } static void tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *tool, wl_fixed_t x, wl_fixed_t y) @@ -800,6 +930,9 @@ static void tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *tool, wl_f struct wayland_surface *w = s->tablet_focus; if (!w) return; s->tool_pos = device_from_fixed(w, x, y); + struct tablet_tool *owned = data; + owned->x = wl_fixed_to_double(x) * w->scale_factor; + owned->y = wl_fixed_to_double(y) * w->scale_factor; s->tool_motion = true; } @@ -807,7 +940,8 @@ 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 tablet_tool *t = data; + struct seat *s = t->seat; struct wayland_surface *w = s->tablet_focus; if (!w) return; seat_note_input(s, serial); @@ -820,13 +954,18 @@ static void tablet_tool_button(void *data, struct zwp_tablet_tool_v2 *tool, } bool release = state == ZWP_TABLET_TOOL_V2_BUTTON_STATE_RELEASED; press_queue_push(&s->tool_presses, w, s->tool_pos, b, release); + pen_action_push(t, YASL_PRIVATE_PEN_BUTTON, (unsigned)b); } 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; + struct tablet_tool *owned = d; s->pen.pressure = v > 65535 ? 65535 : (uint16_t)v; + owned->pressure = (double)(v > 65535 ? 65535 : v) / 65535.0; + owned->axes_valid |= YASL_PRIVATE_PEN_PRESSURE; + owned->axes_changed |= YASL_PRIVATE_PEN_PRESSURE; s->tool_motion = true; } @@ -840,40 +979,68 @@ static void tool_tilt(void *d, struct zwp_tablet_tool_v2 *t, wl_fixed_t x, wl_fi { (void)t; struct seat *s = ((struct tablet_tool *)d)->seat; + struct tablet_tool *owned = d; s->pen.tilt_x = tilt_degrees(x); s->pen.tilt_y = tilt_degrees(y); + owned->tilt_x = wl_fixed_to_double(x); + owned->tilt_y = wl_fixed_to_double(y); + owned->axes_valid |= YASL_PRIVATE_PEN_TILT; + owned->axes_changed |= YASL_PRIVATE_PEN_TILT; 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; + (void)t; + struct tablet_tool *owned = d; + owned->seat->tool_wheel += clicks; + owned->wheel_degrees += wl_fixed_to_double(deg); + owned->axes_valid |= YASL_PRIVATE_PEN_WHEEL; + owned->axes_changed |= YASL_PRIVATE_PEN_WHEEL; } 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 tablet_tool *owned = d; struct wayland_surface *w = s->tablet_focus; if (!w) { s->tool_presses.n = 0; s->tool_wheel = 0; return; } - struct yasl_pointer_event like = tool_event(s); + struct yasl_private_pointer_event like = tool_event(s); + if (owned->pending_action_count) { + unsigned actions = owned->pending_action_count; + bool contact = owned->in_contact; + for (unsigned i = 0; i < actions; i++) { + owned->changed_button = owned->pending_buttons[i]; + owned->in_contact = owned->pending_contacts[i]; + push_pen_sample(owned, w, owned->pending_actions[i], + i + 1 == actions ? owned->axes_changed : 0); + } + owned->in_contact = contact; + owned->pending_action_count = 0; + owned->axes_changed = 0; + owned->changed_button = 0; + } else if (s->tool_motion || owned->axes_changed) { + push_pen_sample(owned, w, YASL_PRIVATE_PEN_MOVE, owned->axes_changed); + owned->axes_changed = 0; + owned->changed_button = 0; + } if (s->tool_motion) { - struct yasl_pointer_event ev = like; + struct yasl_private_pointer_event ev = like; ev.pos = s->tool_pos; - push_pointer(s, w, YASL_EVENT_POINTER_MOTION, ev); + push_pointer(s, w, YASL_PRIVATE_EVENT_POINTER_MOTION, ev); s->tool_motion = false; } press_queue_flush(s, &s->tool_presses, NULL, &s->tool_buttons, like); if (s->tool_wheel) { - struct yasl_pointer_event ev = like; + struct yasl_private_pointer_event ev = like; ev.pos = s->tool_pos; ev.scroll.y = s->tool_wheel; - push_pointer(s, w, YASL_EVENT_POINTER_SCROLL, ev); + push_pointer(s, w, YASL_PRIVATE_EVENT_POINTER_SCROLL, ev); s->tool_wheel = 0; } } @@ -899,16 +1066,43 @@ static void tablet_tool_removed(void *data, struct zwp_tablet_tool_v2 *tool) 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; + struct tablet_tool *tool = d; + tool->eraser = type == ZWP_TABLET_TOOL_V2_TYPE_ERASER; + switch (type) { + case ZWP_TABLET_TOOL_V2_TYPE_PEN: tool->kind = 1; break; + case ZWP_TABLET_TOOL_V2_TYPE_ERASER: tool->kind = 2; break; + case ZWP_TABLET_TOOL_V2_TYPE_BRUSH: tool->kind = 3; break; + case ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH: tool->kind = 4; break; + case ZWP_TABLET_TOOL_V2_TYPE_PENCIL: tool->kind = 5; break; + default: tool->kind = 0; break; + } } -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_serial(void *d, struct zwp_tablet_tool_v2 *t, uint32_t hi, uint32_t lo) +{ (void)t; struct tablet_tool *tool = d; uint64_t id = ((uint64_t)hi << 32) | lo; if (id) tool->tool_id = id; } 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_capability(void *d, struct zwp_tablet_tool_v2 *t, uint32_t cap) +{ + (void)t; + struct tablet_tool *tool = d; + tool->capability_mask |= 1u << cap; + switch (cap) { + case ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE: tool->axes_valid |= YASL_PRIVATE_PEN_PRESSURE; break; + case ZWP_TABLET_TOOL_V2_CAPABILITY_TILT: tool->axes_valid |= YASL_PRIVATE_PEN_TILT; break; + case ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION: tool->axes_valid |= YASL_PRIVATE_PEN_ROTATION; break; + case ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE: tool->axes_valid |= YASL_PRIVATE_PEN_DISTANCE; break; + case ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER: tool->axes_valid |= YASL_PRIVATE_PEN_TANGENTIAL; break; + case ZWP_TABLET_TOOL_V2_CAPABILITY_WHEEL: tool->axes_valid |= YASL_PRIVATE_PEN_WHEEL; break; + default: break; + } +} 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 void tool_distance(void *d, struct zwp_tablet_tool_v2 *t, uint32_t v) +{ (void)t; struct tablet_tool *tool = d; tool->distance = (double)(v > 65535 ? 65535 : v) / 65535.0; tool->axes_valid |= YASL_PRIVATE_PEN_DISTANCE; tool->axes_changed |= YASL_PRIVATE_PEN_DISTANCE; } +static void tool_rotation(void *d, struct zwp_tablet_tool_v2 *t, wl_fixed_t deg) +{ (void)t; struct tablet_tool *tool = d; tool->rotation = wl_fixed_to_double(deg); tool->axes_valid |= YASL_PRIVATE_PEN_ROTATION; tool->axes_changed |= YASL_PRIVATE_PEN_ROTATION; } +static void tool_slider(void *d, struct zwp_tablet_tool_v2 *t, int32_t pos) +{ (void)t; struct tablet_tool *tool = d; tool->tangential = pos / 65535.0; if (tool->tangential < -1) tool->tangential = -1; if (tool->tangential > 1) tool->tangential = 1; tool->axes_valid |= YASL_PRIVATE_PEN_TANGENTIAL; tool->axes_changed |= YASL_PRIVATE_PEN_TANGENTIAL; } static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = { .type = tool_type, .hardware_serial = tool_hardware_serial, @@ -997,6 +1191,7 @@ static void tablet_seat_tablet_added(void *data, struct zwp_tablet_seat_v2 *tabl struct tablet_device *owned = calloc(1, sizeof(*owned)); if (!owned) { zwp_tablet_v2_destroy(tablet); return; } owned->proxy = tablet; + owned->id = ++s->conn->next_tool_id; owned->next = s->tablet_devices; s->tablet_devices = owned; zwp_tablet_v2_add_listener(tablet, &tablet_listener, s); @@ -1010,6 +1205,7 @@ static void tablet_seat_tool_added(void *data, struct zwp_tablet_seat_v2 *tablet if (!owned) { zwp_tablet_tool_v2_destroy(tool); return; } owned->proxy = tool; owned->seat = s; + owned->tool_id = ++s->conn->next_tool_id; owned->next = s->tablet_tools; s->tablet_tools = owned; zwp_tablet_tool_v2_add_listener(tool, &tablet_tool_listener, owned); @@ -1035,7 +1231,7 @@ static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = { static void clipboard_received(const char *text, size_t len, bool uri_list, struct wl_surface *on, uint64_t request_id, - enum yasl_transfer_status status, void *ud) + enum yasl_private_transfer_status status, void *ud) { (void)ud; struct wayland_surface *w = on ? @@ -1043,13 +1239,13 @@ static void clipboard_received(const char *text, size_t len, bool uri_list, if (uri_list) w = surface_root(w); if (!w || w->closed || w->destroyed) return; if (!uri_list) { - yasl_surface_complete_paste(&w->base, request_id, status, text, len); + yasl_private_surface_complete_paste(&w->base, request_id, status, text, len); return; } - if (status != YASL_TRANSFER_OK) return; - struct yasl_event ev = { + if (status != YASL_PRIVATE_TRANSFER_OK) return; + struct yasl_private_event ev = { .surface = &w->base, - .type = uri_list ? YASL_EVENT_DROP : YASL_EVENT_PASTE, + .type = uri_list ? YASL_PRIVATE_EVENT_DROP : YASL_PRIVATE_EVENT_PASTE, .text = { .data = text, .len = len, @@ -1058,14 +1254,14 @@ static void clipboard_received(const char *text, size_t len, bool uri_list, input_queue_push(&w->input, &ev); } -static void clipboard_drag(enum yasl_drag_event ev, struct wl_surface *on, +static void clipboard_drag(enum yasl_private_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, +static void clipboard_drop_hover(enum yasl_private_drop_event ev, struct wl_surface *on, double x, double y, void *ud) { struct seat *s = ud; @@ -1152,6 +1348,16 @@ static void seat_drop_touch(struct seat *s) } } +void seat_ensure_text_input(struct seat *s) +{ + if (!s || !s->conn->text_input_mgr || s->text_input || !s->proxy) + return; + s->text_input = zwp_text_input_manager_v3_get_text_input( + s->conn->text_input_mgr, s->proxy); + if (s->text_input) + zwp_text_input_v3_add_listener(s->text_input, &text_input_listener, s); +} + static void seat_capabilities(void *data, struct wl_seat *proxy, uint32_t caps) { struct seat *s = data; @@ -1209,11 +1415,7 @@ static void seat_capabilities(void *data, struct wl_seat *proxy, uint32_t caps) 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_ensure_text_input(s); seat_clipboard_ensure(s); } @@ -1297,8 +1499,8 @@ void seat_destroy(struct seat *s) seat_drop_keyboard(s); struct wayland_surface *left = s->focus_leaving; if (left && !conn_keyboard_on(c, left, NULL)) { - struct yasl_event ev = { - .type = YASL_EVENT_FOCUS, + struct yasl_private_event ev = { + .type = YASL_PRIVATE_EVENT_FOCUS, .surface = &left->base, .focus = { .focused = false }, }; @@ -1306,7 +1508,7 @@ void seat_destroy(struct seat *s) } 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_watch > 0) yasl_private_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); -- cgit v1.2.3