From 5206933399775e5ff46baefbbb3a776c2a9bb84c Mon Sep 17 00:00:00 2001 From: Berke Güzel Date: Mon, 12 Oct 2026 10:53:22 +0300 Subject: feat: add type-safe native platform headers and portable drag support - Add include/yasl/native/{wayland,cocoa,x11}.h with type-safe handle accessors. - Unify drag-and-drop and window carry support across Wayland, X11, and Cocoa. - Preserve full ABI compatibility for capability flags. - Install native headers conditionally based on enabled backend. - Include missing tablet example and backend test suites. --- src/x11/window.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) (limited to 'src/x11/window.c') diff --git a/src/x11/window.c b/src/x11/window.c index 85f1d22..5e3dba9 100644 --- a/src/x11/window.c +++ b/src/x11/window.c @@ -89,6 +89,14 @@ struct x11_display { bool xi2; Atom abs_pressure, abs_tilt_x, abs_tilt_y, tool_type, eraser; struct x11_pointer *pointers; + struct { + bool active; + struct x11_surface *origin; + struct x11_surface *carried; + struct yasl_vector2i carry_offset; + struct yasl_drag_listener listener; + void *ud; + } drag; }; static struct x11_display *display_of(const struct yasl_surface *s) @@ -96,6 +104,10 @@ static struct x11_display *display_of(const struct yasl_surface *s) return (struct x11_display *)s->display; } +static bool place(struct yasl_surface *base, struct yasl_vector2i at); +static void drag_end(struct x11_display *d, enum yasl_drag_end how); +static void drag_cancel(struct yasl_display *base); + static void leave(struct x11_display *d) { if (--d->depth) return; @@ -284,6 +296,10 @@ static void xi_event(struct x11_display *d, XGenericEventCookie *cookie) cookie->evtype != XI_ButtonRelease) return; Window window = crossing ? ((XIEnterEvent *)cookie->data)->event : ((XIDeviceEvent *)cookie->data)->event; + if (cookie->evtype == XI_Motion && d->drag.active && d->drag.carried) + place(&d->drag.carried->base, d->drag.carry_offset); + else if (cookie->evtype == XI_ButtonRelease && d->drag.active) + drag_end(d, YASL_DRAG_DROPPED); struct x11_surface *s = d->surfaces; while (s && s->window != window) s = s->next; if (!s) return; @@ -357,6 +373,8 @@ static void surface_destroy(struct yasl_surface *base) struct x11_surface *s = (struct x11_surface *)base; if (s->destroyed) return; struct x11_display *d = display_of(base); + if (d->drag.active && (d->drag.origin == s || d->drag.carried == s)) + drag_end(d, YASL_DRAG_CANCELLED); s->destroyed = true; for (struct x11_surface **p = &d->surfaces; *p; p = &(*p)->next) { if (*p == s) { *p = s->next; break; } @@ -648,6 +666,8 @@ static void dispatch(struct yasl_display *base) mouse.pos = (struct yasl_vector2i){event.xmotion.x, event.xmotion.y}; mouse.kind = YASL_PTR_MOTION; state = event.xmotion.state; + if (d->drag.active && d->drag.carried) + place(&d->drag.carried->base, d->drag.carry_offset); } else if (event.type == LeaveNotify) { mouse.pos = (struct yasl_vector2i){event.xcrossing.x, event.xcrossing.y}; mouse.kind = YASL_PTR_LEAVE; @@ -663,6 +683,8 @@ static void dispatch(struct yasl_display *base) } else { mouse.kind = event.type == ButtonPress ? YASL_PTR_PRESS : YASL_PTR_RELEASE; mouse.button = pointer_button(button); + if (event.type == ButtonRelease && d->drag.active) + drag_end(d, YASL_DRAG_DROPPED); } } d->mods = mouse.mods = modifiers(state); @@ -849,6 +871,7 @@ static void display_close(struct yasl_display *base) { struct x11_display *d = (struct x11_display *)base; assert(!d->surfaces && "destroy every surface before its display"); + drag_cancel(base); cancel_pastes(d, NULL); if (d->loop && d->watch > 0) yasl_loop_del_fd(d->loop, d->watch); if (d->owns_loop && d->loop) { @@ -868,7 +891,8 @@ static void display_close(struct yasl_display *base) static uint32_t caps(const struct yasl_display *d) { - return YASL_CAP_PLACE_WINDOW | YASL_CAP_PRIMARY_SELECTION | + return YASL_CAP_DRAG | YASL_CAP_DRAG_CARRY | YASL_CAP_PLACE_WINDOW | + YASL_CAP_PRIMARY_SELECTION | (((const struct x11_display *)d)->xi2 ? YASL_CAP_TABLET : 0); } @@ -984,6 +1008,49 @@ static bool place(struct yasl_surface *base, struct yasl_vector2i at) return true; } +static void drag_end(struct x11_display *d, enum yasl_drag_end how) +{ + if (!d || !d->drag.active) return; + struct yasl_drag_listener l = d->drag.listener; + void *ud = d->drag.ud; + d->drag.active = false; + d->drag.origin = NULL; + d->drag.carried = NULL; + if (l.end) + l.end(ud, how); +} + +static bool drag_start(struct yasl_display *base, struct yasl_surface *origin, + const struct yasl_drag_image *image, + const struct yasl_drag_listener *l, void *ud) +{ + (void)image; + struct x11_display *d = (struct x11_display *)base; + if (!d || !origin || d->drag.active || !l) + return false; + d->drag.active = true; + d->drag.origin = (struct x11_surface *)origin; + d->drag.carried = NULL; + d->drag.listener = *l; + d->drag.ud = ud; + return true; +} + +static void drag_cancel(struct yasl_display *base) +{ + drag_end((struct x11_display *)base, YASL_DRAG_CANCELLED); +} + +static bool drag_carry(struct yasl_surface *base, struct yasl_vector2i offset) +{ + struct x11_display *d = display_of(base); + if (!d || !d->drag.active) + return false; + d->drag.carried = (struct x11_surface *)base; + d->drag.carry_offset = offset; + return place(base, offset); +} + static bool interactive_move(struct yasl_surface *base) { struct x11_surface *s = (struct x11_surface *)base; @@ -1008,6 +1075,8 @@ const struct yasl_backend_ops yasl_x11_backend = { .display_modifiers = mods, .display_copy = copy, .display_paste = paste, + .display_drag_start = drag_start, + .display_drag_cancel = drag_cancel, .surface_create_toplevel = create_toplevel, .surface_destroy = surface_destroy, .surface_display = surface_display, @@ -1021,6 +1090,7 @@ const struct yasl_backend_ops yasl_x11_backend = { .surface_timing = timing, .surface_frame_time_ns = frame_time, .surface_set_cursor = cursor, + .surface_drag_carry = drag_carry, .surface_place_under_pointer = place, .surface_start_interactive_move = interactive_move, .display_get_native_handle = native_display, -- cgit v1.2.3