summaryrefslogtreecommitdiff
path: root/src/common/surface.c
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-16 13:26:20 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-16 13:26:20 +0300
commit6f017eb4c18ea53cbc2782df10e078f5b939e87c (patch)
tree412b145bf1c9adac770a94e5aba2cd34baf3d742 /src/common/surface.c
parent12d2735115528d741ebf47b6738c88b7c182b85b (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>
Diffstat (limited to 'src/common/surface.c')
-rw-r--r--src/common/surface.c24
1 files changed, 20 insertions, 4 deletions
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;