summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/backend.h2
-rw-r--r--src/common/events.c2
-rw-r--r--src/common/surface.c24
-rw-r--r--src/common/types.h1
4 files changed, 25 insertions, 4 deletions
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. */