diff options
| -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. */ |
