summaryrefslogtreecommitdiff
path: root/src/platform/wayland/pointer.c
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-13 23:41:31 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-13 23:41:31 +0300
commit76073fe5fad8799e5850805f2f090af2cb62c741 (patch)
tree9658019babe4760a3634bdab4da0731a10e42e68 /src/platform/wayland/pointer.c
parentdd1775a9927922c14f8679ccbc4d3ca8d5917e20 (diff)
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 <noreply@anthropic.com>
Diffstat (limited to 'src/platform/wayland/pointer.c')
-rw-r--r--src/platform/wayland/pointer.c398
1 files changed, 300 insertions, 98 deletions
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);