From 6f017eb4c18ea53cbc2782df10e078f5b939e87c Mon Sep 17 00:00:00 2001 From: Berke Güzel Date: Fri, 16 Oct 2026 13:26:20 +0300 Subject: End every drag with one event A drag that dropped on no YASL surface, such as one dropped on the desktop or canceled, ended unheard: the public drag start set no end listener. An application then waited for the drag's end forever. The public layer now listens for the end. When no surface got the drop, the origin gets DRAG with the new action YASL_DROP_CANCEL. Co-Authored-By: Claude Opus 5.5 --- src/common/backend.h | 2 ++ src/common/events.c | 2 ++ src/common/surface.c | 24 ++++++++++++++++++++---- src/common/types.h | 1 + 4 files changed, 25 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/common/backend.h b/src/common/backend.h index a9076e4..6d0388c 100644 --- a/src/common/backend.h +++ b/src/common/backend.h @@ -30,6 +30,8 @@ struct yasl_private_display { struct yasl_surface *surfaces; /* Set by the backend: a lost connection comes back (Wayland). */ bool reconnects; + /* The drag in progress dropped on one of the display's surfaces. */ + bool drag_dropped; /* Set by the public layer, or NULL. pending: an event is ready that the * queue does not hold, such as an owed REFRESH. deliver: hand queued events * to the application during the loop step. */ diff --git a/src/common/events.c b/src/common/events.c index c310f06..a9557c9 100644 --- a/src/common/events.c +++ b/src/common/events.c @@ -304,6 +304,8 @@ void yasl_private_surface_notify_state(struct yasl_surface *s, uint32_t flags) void yasl_private_surface_notify_drag(struct yasl_surface *s, enum yasl_private_drag_event action, struct yasl_private_vector2i pos) { struct yasl_private_event event = {.type = YASL_PRIVATE_EVENT_DRAG, .surface = s, .drag = {action, pos}}; + if (action == YASL_PRIVATE_DRAG_DROP) + s->display->drag_dropped = true; yasl_private_events_push(s->display, s, &event); } diff --git a/src/common/surface.c b/src/common/surface.c index 6b805be..683bbaa 100644 --- a/src/common/surface.c +++ b/src/common/surface.c @@ -669,6 +669,18 @@ int yasl_clipboard_request(yasl_surface *s, enum yasl_selection selection) return -errno; return STATUS(yasl_private_clipboard_request(s, (enum yasl_private_selection)selection) != 0); } +/* A drag that drops on no surface would end unheard, so its origin hears + * the end. ud is the origin's id: the origin may be gone by then. */ +static void drag_ended(void *ud, enum yasl_private_drag_end how) +{ + (void)how; + if (!display || display->drag_dropped) + return; + yasl_surface *origin = yasl_private_events_find(display, (uint64_t)(uintptr_t)ud); + if (origin) + yasl_private_surface_notify_drag(origin, YASL_PRIVATE_DRAG_CANCEL, + (struct yasl_private_vector2i){0, 0}); +} int yasl_drag_start(yasl_surface *s, const struct yasl_drag_image *source) { if (!yasl_public_connected(s)) @@ -679,7 +691,10 @@ int yasl_drag_start(yasl_surface *s, const struct yasl_drag_image *source) .pixels = source->pixels, .size = {source->pixel_width, source->pixel_height}, .hotspot = {source->hotspot_x, source->hotspot_y}}; - return STATUS(yasl_private_display_drag_start(display, s, source ? &image : NULL, NULL, NULL)); + display->drag_dropped = false; + const struct yasl_private_drag_listener listener = {.end = drag_ended}; + return STATUS(yasl_private_display_drag_start(display, s, source ? &image : NULL, &listener, + (void *)(uintptr_t)s->id)); } int yasl_drag_cancel(void) { @@ -886,9 +901,10 @@ static bool convert_event(const struct yasl_private_event *p, yasl_event *e) return true; case YASL_PRIVATE_EVENT_DRAG: e->type = YASL_EVENT_DRAG; - e->action = p->drag.action == YASL_PRIVATE_DRAG_OVER ? YASL_DROP_OVER - : p->drag.action == YASL_PRIVATE_DRAG_LEAVE ? YASL_DROP_LEAVE - : YASL_DROP_RELEASE; + e->action = p->drag.action == YASL_PRIVATE_DRAG_OVER ? YASL_DROP_OVER + : p->drag.action == YASL_PRIVATE_DRAG_LEAVE ? YASL_DROP_LEAVE + : p->drag.action == YASL_PRIVATE_DRAG_CANCEL ? YASL_DROP_CANCEL + : YASL_DROP_RELEASE; e->x = p->drag.pos.x / scale; e->y = p->drag.pos.y / scale; return true; diff --git a/src/common/types.h b/src/common/types.h index 67aaaa3..034e6fd 100644 --- a/src/common/types.h +++ b/src/common/types.h @@ -231,6 +231,7 @@ enum yasl_private_drag_event { YASL_PRIVATE_DRAG_OVER, /**< Surface drag entered or moved over the target. */ YASL_PRIVATE_DRAG_LEAVE, /**< Surface drag left the target. */ YASL_PRIVATE_DRAG_DROP, /**< Surface drag dropped on the target. */ + YASL_PRIVATE_DRAG_CANCEL, /**< Surface drag ended on no target; sent to its origin. */ }; /** External text/file drag hover notifications; completed data arrives through input. */ -- cgit v1.2.3