diff options
| author | Berke Güzel <wenekar1@gmail.com> | 2026-10-16 13:26:20 +0300 |
|---|---|---|
| committer | Berke Güzel <wenekar1@gmail.com> | 2026-10-16 13:26:20 +0300 |
| commit | 6f017eb4c18ea53cbc2782df10e078f5b939e87c (patch) | |
| tree | 412b145bf1c9adac770a94e5aba2cd34baf3d742 | |
| parent | 12d2735115528d741ebf47b6738c88b7c182b85b (diff) | |
End every drag with one eventone-loop
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 <noreply@anthropic.com>
| -rw-r--r-- | include/yasl/yasl.h | 7 | ||||
| -rw-r--r-- | src/common/backend.h | 2 | ||||
| -rw-r--r-- | src/common/events.c | 2 | ||||
| -rw-r--r-- | src/common/surface.c | 24 | ||||
| -rw-r--r-- | src/common/types.h | 1 |
5 files changed, 30 insertions, 6 deletions
diff --git a/include/yasl/yasl.h b/include/yasl/yasl.h index 6139bc3..931cf7f 100644 --- a/include/yasl/yasl.h +++ b/include/yasl/yasl.h @@ -216,7 +216,9 @@ enum yasl_event_type { YASL_EVENT_CLIPBOARD, /**< text; action is a yasl_transfer. */ YASL_EVENT_DROP, /**< External data: x, y; action is a yasl_drop_action; * text on RELEASE is a text/uri-list. */ - YASL_EVENT_DRAG, /**< A yasl_drag_start drag: x, y; action is a yasl_drop_action. */ + YASL_EVENT_DRAG, /**< A yasl_drag_start drag: x, y; action is a yasl_drop_action. + * Each drag ends once: RELEASE on the surface it drops on, + * or CANCEL on its origin when it ends anywhere else. */ /** The display server went away; action is a yasl_lost. Before the next * wait, or before returning to the loop, destroy Vulkan surfaces and detach * GL contexts on every thread; popups close. On RECONNECTING, DISPLAY_RESTORED @@ -239,7 +241,8 @@ enum yasl_pen_axis { enum yasl_scroll_source { YASL_SCROLL_UNKNOWN, YASL_SCROLL_WHEEL, YASL_SCROLL_FINGER, YASL_SCROLL_CONTINUOUS }; enum yasl_scroll_phase { YASL_SCROLL_PHASE_NONE, YASL_SCROLL_BEGIN, YASL_SCROLL_UPDATE, YASL_SCROLL_END }; enum yasl_transfer { YASL_TRANSFER_OK, YASL_TRANSFER_UNAVAILABLE, YASL_TRANSFER_FAILED }; -enum yasl_drop_action { YASL_DROP_OVER, YASL_DROP_LEAVE, YASL_DROP_RELEASE }; +/** CANCEL ends a drag that dropped on no YASL surface, or was canceled; x and y are 0. */ +enum yasl_drop_action { YASL_DROP_OVER, YASL_DROP_LEAVE, YASL_DROP_RELEASE, YASL_DROP_CANCEL }; enum yasl_lost { YASL_LOST_RECONNECTING, YASL_LOST_FINAL }; /** Physical key, layout labels (codepoint unshifted, shifted; 0 if none) and the 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. */ |
