summaryrefslogtreecommitdiff
path: root/src/wayland/clipboard.c
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-13 13:44:13 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-13 13:44:13 +0300
commitc059e3aa7f93da470f052a5cd8ee0d8dc969e679 (patch)
tree63ffa378287ed2c606eda2e940501b9edc3d2b8b /src/wayland/clipboard.c
parent87d0bc50d53dc216efb2b04495f090616318bc5c (diff)
rename and simplification
Diffstat (limited to 'src/wayland/clipboard.c')
-rw-r--r--src/wayland/clipboard.c629
1 files changed, 0 insertions, 629 deletions
diff --git a/src/wayland/clipboard.c b/src/wayland/clipboard.c
deleted file mode 100644
index a6922c4..0000000
--- a/src/wayland/clipboard.c
+++ /dev/null
@@ -1,629 +0,0 @@
-#define _GNU_SOURCE
-#include "internal.h"
-#include "clipboard.h"
-
-#define CLIPBOARD_TEXT_MAX (256u * 1024)
-
-struct offer {
- struct offer *next;
- struct wl_data_offer *proxy;
- char *mime;
- bool uri_list;
- bool tab;
-};
-struct primary_offer {
- struct primary_offer *next;
- struct zwp_primary_selection_offer_v1 *proxy;
- char *mime;
-};
-struct transfer {
- struct transfer *next;
- struct clipboard *owner;
- struct offer *drop;
- struct wl_surface *drop_surface;
- int fd, id;
- char *text;
- size_t len, offset, capacity;
- bool sending;
- bool uri_list;
-};
-struct clipboard {
- struct wl_display *display;
- struct wl_data_device_manager *manager;
- struct wl_data_device *device;
- struct zwp_primary_selection_device_manager_v1 *primary_manager;
- struct zwp_primary_selection_device_v1 *primary_device;
- struct zwp_primary_selection_source_v1 *primary_source;
- struct wl_seat *seat;
- struct wl_data_source *source;
- struct offer *selection;
- struct offer *pending_offers;
- struct offer *drag_offer;
- struct primary_offer *primary_selection;
- struct primary_offer *primary_pending_offers;
- struct yasl_loop *loop;
- struct transfer *transfers;
- char *text;
- char *primary_text;
- clipboard_receive_fn receive;
- void *ud;
- clipboard_drag_fn drag;
- void *drag_ud;
- clipboard_drop_fn drop;
- void *drop_ud;
- wl_fixed_t drag_x, drag_y;
- struct wl_surface *drag_surface;
-};
-
-const char *clipboard_drag_mime(void)
-{
- static char mime[64];
- if (!mime[0])
- snprintf(mime, sizeof(mime), "application/x-yasl-tab;pid=%ld", (long)getpid());
- return mime;
-}
-
-static void drag_event(struct clipboard *c, enum yasl_drag_event ev,
- wl_fixed_t x, wl_fixed_t y)
-{
- if (c->drag)
- c->drag(ev, c->drag_surface, wl_fixed_to_double(x), wl_fixed_to_double(y),
- c->drag_ud);
-}
-
-static bool offer_droppable(const struct offer *o)
-{
- return o && !o->tab && (o->uri_list || o->mime);
-}
-
-static void drop_event(struct clipboard *c, enum yasl_drop_event ev)
-{
- if (c->drop && c->drag_surface)
- c->drop(ev, c->drag_surface, wl_fixed_to_double(c->drag_x),
- wl_fixed_to_double(c->drag_y), c->drop_ud);
-}
-
-static void free_offer(struct offer *o);
-
-static void transfer_end(struct transfer *t, bool complete)
-{
- struct transfer **p = &t->owner->transfers;
- while (*p && *p != t) p = &(*p)->next;
- if (*p) *p = t->next;
- yasl_loop_del_fd(t->owner->loop, t->id);
- close(t->fd);
- if (t->drop) {
- if (complete && wl_data_offer_get_version(t->drop->proxy) >=
- WL_DATA_OFFER_FINISH_SINCE_VERSION)
- wl_data_offer_finish(t->drop->proxy);
- free_offer(t->drop);
- wl_display_flush(t->owner->display);
- }
- free(t->text);
- free(t);
-}
-
-static void transfer_destroy(struct transfer *t)
-{
- transfer_end(t, false);
-}
-
-static int transfer_io(int fd, short events, void *ud)
-{
- struct transfer *t = ud;
- if (events & (POLLERR | POLLNVAL)) { transfer_destroy(t); return 0; }
- if (t->sending) {
- ssize_t n = write(fd, t->text + t->offset, t->len - t->offset);
- if (n > 0) t->offset += (size_t)n;
- if (t->offset == t->len || n == 0 ||
- (n < 0 && errno != EAGAIN && errno != EINTR)) transfer_destroy(t);
- } else {
- if (t->capacity - t->len < 4096) {
- size_t capacity = t->capacity ? t->capacity * 2 : 8192;
- if (capacity > CLIPBOARD_TEXT_MAX) capacity = CLIPBOARD_TEXT_MAX;
- if (capacity <= t->len) { transfer_destroy(t); return 0; }
- char *text = realloc(t->text, capacity);
- if (!text) { transfer_destroy(t); return 0; }
- t->text = text;
- t->capacity = capacity;
- }
- ssize_t n = read(fd, t->text + t->len, t->capacity - t->len);
- if (n > 0) {
- t->len += (size_t)n;
- } else if (n == 0) {
- bool valid = yasl_utf8_validate(t->text, t->len);
- if (valid)
- t->owner->receive(t->text ? t->text : "", t->len, t->uri_list,
- t->drop_surface, t->owner->ud);
- transfer_end(t, valid);
- } else if (errno != EAGAIN && errno != EINTR) transfer_destroy(t);
- }
- return 0;
-}
-
-static struct transfer *start_transfer_text(struct clipboard *c, int fd, bool sending,
- bool uri_list, const char *send_text)
-{
- struct transfer *t = calloc(1, sizeof(*t));
- if (!t) { close(fd); return NULL; }
- t->owner = c; t->fd = fd; t->sending = sending; t->uri_list = uri_list;
- fcntl(fd, F_SETFD, FD_CLOEXEC);
- fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
- if (sending) {
- t->text = strdup(send_text ? send_text : "");
- if (!t->text) { close(fd); free(t); return NULL; }
- t->len = strlen(t->text);
- }
- t->id = yasl_loop_add_fd(c->loop, fd, sending ? POLLOUT : POLLIN, transfer_io, t);
- if (t->id < 0) { close(fd); free(t->text); free(t); return NULL; }
- t->next = c->transfers; c->transfers = t;
- return t;
-}
-
-static struct transfer *start_transfer(struct clipboard *c, int fd, bool sending, bool uri_list)
-{
- return start_transfer_text(c, fd, sending, uri_list, c->text);
-}
-
-static const char *match_text_mime(const char *mime)
-{
- if (unlikely(!mime)) return NULL;
- if (likely(!strncasecmp(mime, "text/plain", 10))) {
- if (!strcasecmp(mime, "text/plain;charset=utf-8")) return "text/plain;charset=utf-8";
- if (!strcasecmp(mime, "text/plain;charset=utf8")) return "text/plain;charset=utf8";
- if (!strcasecmp(mime, "text/plain")) return "text/plain";
- }
- if (!strcasecmp(mime, "UTF8_STRING")) return "UTF8_STRING";
- if (!strcasecmp(mime, "STRING")) return "STRING";
- if (!strcasecmp(mime, "TEXT")) return "TEXT";
- return NULL;
-}
-
-static void offer_keep_mime(char **slot, const char *mime)
-{
- char *copy = strdup(mime);
- if (!copy) return;
- free(*slot);
- *slot = copy;
-}
-
-static void offer_mime(void *ud, struct wl_data_offer *proxy, const char *mime)
-{
- (void)proxy;
- struct offer *o = ud;
- if (!strcmp(mime, clipboard_drag_mime())) o->tab = true;
- if (!strcmp(mime, "text/uri-list")) o->uri_list = true;
- const char *match = match_text_mime(mime);
- if (match) {
- if (!o->mime || !strcasecmp(match, "text/plain;charset=utf-8"))
- offer_keep_mime(&o->mime, mime);
- }
-}
-static void offer_source_actions(void *ud, struct wl_data_offer *proxy, uint32_t actions)
-{ (void)ud; (void)proxy; (void)actions; }
-static void offer_action(void *ud, struct wl_data_offer *proxy, uint32_t action)
-{ (void)ud; (void)proxy; (void)action; }
-static const struct wl_data_offer_listener offer_listener = {
- .offer = offer_mime,
- .source_actions = offer_source_actions,
- .action = offer_action,
-};
-static void free_offer(struct offer *o)
-{
- if (o) { wl_data_offer_destroy(o->proxy); free(o->mime); free(o); }
-}
-static void take_pending_offer(struct clipboard *c, struct offer *o)
-{
- if (!o) return;
- struct offer **p = &c->pending_offers;
- while (*p && *p != o) p = &(*p)->next;
- if (*p) *p = o->next;
- o->next = NULL;
-}
-static void clear_pending_offers(struct clipboard *c)
-{
- while (c->pending_offers) {
- struct offer *o = c->pending_offers;
- c->pending_offers = o->next;
- free_offer(o);
- }
-}
-static void data_offer(void *ud, struct wl_data_device *device, struct wl_data_offer *proxy)
-{
- (void)device;
- struct clipboard *c = ud;
- struct offer *o = calloc(1, sizeof(*o));
- if (!o) { wl_data_offer_destroy(proxy); return; }
- o->proxy = proxy;
- wl_data_offer_add_listener(proxy, &offer_listener, o);
- o->next = c->pending_offers;
- c->pending_offers = o;
-}
-static void selection(void *ud, struct wl_data_device *device, struct wl_data_offer *proxy)
-{
- (void)device;
- struct clipboard *c = ud;
- struct offer *o = proxy ? wl_data_offer_get_user_data(proxy) : NULL;
- take_pending_offer(c, o);
- if (c->drag_offer == o) c->drag_offer = NULL;
- if (c->selection != o) free_offer(c->selection);
- c->selection = o;
-}
-static void drag_offer_enter(void *ud, struct wl_data_device *device, uint32_t serial,
- struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *proxy)
-{
- (void)device;
- if (proxy) {
- struct clipboard *c = ud;
- struct offer *o = wl_data_offer_get_user_data(proxy);
- take_pending_offer(c, o);
- if (c->selection == o) c->selection = NULL;
- if (c->drag_offer && c->drag_offer != o) free_offer(c->drag_offer);
- c->drag_offer = o;
- const char *mime = o && o->tab ? clipboard_drag_mime()
- : o && o->uri_list ? "text/uri-list"
- : o ? o->mime : NULL;
- wl_data_offer_accept(proxy, serial, mime);
- if (mime && wl_data_offer_get_version(proxy) >= 3) {
- uint32_t action = o->tab ? WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE
- : WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
- wl_data_offer_set_actions(proxy, action, action);
- }
- c->drag_x = x;
- c->drag_y = y;
- c->drag_surface = surface;
- if (o && o->tab)
- drag_event(c, YASL_DRAG_OVER, x, y);
- else if (offer_droppable(o))
- drop_event(c, YASL_DROP_OVER);
- }
-}
-static void drag_offer_clear(void *ud, struct wl_data_device *device)
-{
- (void)device;
- struct clipboard *c = ud;
- if (c->drag_offer && c->drag_offer->tab)
- drag_event(c, YASL_DRAG_LEAVE, c->drag_x, c->drag_y);
- else if (offer_droppable(c->drag_offer))
- drop_event(c, YASL_DROP_LEAVE);
- free_offer(c->drag_offer);
- c->drag_offer = NULL;
- c->drag_surface = NULL;
-}
-static void drag_motion(void *ud, struct wl_data_device *device, uint32_t time, wl_fixed_t x, wl_fixed_t y)
-{
- (void)device; (void)time;
- struct clipboard *c = ud;
- c->drag_x = x;
- c->drag_y = y;
- if (c->drag_offer && c->drag_offer->tab)
- drag_event(c, YASL_DRAG_OVER, x, y);
- else if (offer_droppable(c->drag_offer))
- drop_event(c, YASL_DROP_OVER);
-}
-static void drag_drop(void *ud, struct wl_data_device *device)
-{
- (void)device;
- struct clipboard *c = ud;
- struct offer *o = c->drag_offer;
- if (!o) return;
- c->drag_offer = NULL;
- bool v3 = wl_data_offer_get_version(o->proxy) >= 3;
- if (o->tab) {
- drag_event(c, YASL_DRAG_DROP, c->drag_x, c->drag_y);
- if (v3)
- wl_data_offer_finish(o->proxy);
- } else if (offer_droppable(o)) {
- drop_event(c, YASL_DROP_LEAVE);
- int fds[2];
- if (pipe2(fds, O_CLOEXEC) == 0) {
- wl_data_offer_receive(o->proxy, o->uri_list ? "text/uri-list" : o->mime, fds[1]);
- close(fds[1]);
- struct transfer *t = start_transfer(c, fds[0], false, o->uri_list);
- if (t) {
- t->drop = o;
- t->drop_surface = c->drag_surface;
- o = NULL;
- }
- wl_display_flush(c->display);
- }
- }
- c->drag_surface = NULL;
- free_offer(o);
-}
-static const struct wl_data_device_listener device_listener = {
- .data_offer = data_offer, .selection = selection, .enter = drag_offer_enter,
- .leave = drag_offer_clear, .motion = drag_motion, .drop = drag_drop
-};
-static void source_target(void *ud, struct wl_data_source *s, const char *mime) { (void)ud; (void)s; (void)mime; }
-static void source_send(void *ud, struct wl_data_source *s, const char *mime, int32_t fd)
-{ (void)s; (void)mime; start_transfer(ud, fd, true, false); }
-static void source_cancelled(void *ud, struct wl_data_source *s)
-{
- struct clipboard *c = ud;
- if (c->source == s) c->source = NULL;
- wl_data_source_destroy(s);
-}
-static void source_dnd_drop_performed(void *ud, struct wl_data_source *s) { (void)ud; (void)s; }
-static void source_dnd_finished(void *ud, struct wl_data_source *s) { (void)ud; (void)s; }
-static void source_action(void *ud, struct wl_data_source *s, uint32_t action) { (void)ud; (void)s; (void)action; }
-static const struct wl_data_source_listener source_listener = {
- .target = source_target, .send = source_send, .cancelled = source_cancelled,
- .dnd_drop_performed = source_dnd_drop_performed,
- .dnd_finished = source_dnd_finished, .action = source_action,
-};
-
-static void free_primary_offer(struct primary_offer *o)
-{
- if (o) { zwp_primary_selection_offer_v1_destroy(o->proxy); free(o->mime); free(o); }
-}
-
-static void take_pending_primary_offer(struct clipboard *c, struct primary_offer *o)
-{
- if (!o) return;
- struct primary_offer **p = &c->primary_pending_offers;
- while (*p && *p != o) p = &(*p)->next;
- if (*p) *p = o->next;
- o->next = NULL;
-}
-
-static void clear_pending_primary_offers(struct clipboard *c)
-{
- while (c->primary_pending_offers) {
- struct primary_offer *o = c->primary_pending_offers;
- c->primary_pending_offers = o->next;
- free_primary_offer(o);
- }
-}
-
-static void primary_offer_mime(void *ud, struct zwp_primary_selection_offer_v1 *proxy, const char *mime)
-{
- (void)proxy;
- struct primary_offer *o = ud;
- const char *match = match_text_mime(mime);
- if (match) {
- if (!o->mime || !strcasecmp(match, "text/plain;charset=utf-8"))
- offer_keep_mime(&o->mime, mime);
- }
-}
-
-static const struct zwp_primary_selection_offer_v1_listener primary_offer_listener = {
- .offer = primary_offer_mime,
-};
-
-static void primary_data_offer(void *ud, struct zwp_primary_selection_device_v1 *device,
- struct zwp_primary_selection_offer_v1 *proxy)
-{
- (void)device;
- struct clipboard *c = ud;
- struct primary_offer *o = calloc(1, sizeof(*o));
- if (!o) { zwp_primary_selection_offer_v1_destroy(proxy); return; }
- o->proxy = proxy;
- zwp_primary_selection_offer_v1_add_listener(proxy, &primary_offer_listener, o);
- o->next = c->primary_pending_offers;
- c->primary_pending_offers = o;
-}
-
-static void primary_selection(void *ud, struct zwp_primary_selection_device_v1 *device,
- struct zwp_primary_selection_offer_v1 *proxy)
-{
- (void)device;
- struct clipboard *c = ud;
- struct primary_offer *o = proxy ? zwp_primary_selection_offer_v1_get_user_data(proxy) : NULL;
- take_pending_primary_offer(c, o);
- if (c->primary_selection != o) free_primary_offer(c->primary_selection);
- c->primary_selection = o;
-}
-
-static const struct zwp_primary_selection_device_v1_listener primary_device_listener = {
- .data_offer = primary_data_offer,
- .selection = primary_selection,
-};
-
-static void primary_source_send(void *ud, struct zwp_primary_selection_source_v1 *s,
- const char *mime, int32_t fd)
-{
- (void)s; (void)mime;
- struct clipboard *c = ud;
- start_transfer_text(c, fd, true, false, c->primary_text);
-}
-
-static void primary_source_cancelled(void *ud, struct zwp_primary_selection_source_v1 *s)
-{
- struct clipboard *c = ud;
- if (c->primary_source == s) c->primary_source = NULL;
- zwp_primary_selection_source_v1_destroy(s);
-}
-
-static const struct zwp_primary_selection_source_v1_listener primary_source_listener = {
- .send = primary_source_send,
- .cancelled = primary_source_cancelled,
-};
-
-void clipboard_set_primary_manager(struct clipboard *c,
- struct zwp_primary_selection_device_manager_v1 *mgr)
-{
- if (!c) return;
- c->primary_manager = mgr;
- if (c->primary_device) {
- zwp_primary_selection_device_v1_destroy(c->primary_device);
- c->primary_device = NULL;
- }
- if (c->primary_manager && c->seat) {
- c->primary_device =
- zwp_primary_selection_device_manager_v1_get_device(c->primary_manager, c->seat);
- if (c->primary_device)
- zwp_primary_selection_device_v1_add_listener(c->primary_device,
- &primary_device_listener, c);
- }
-}
-
-void clipboard_set_drag_handler(struct clipboard *c, clipboard_drag_fn fn, void *ud)
-{
- if (!c) return;
- c->drag = fn;
- c->drag_ud = ud;
-}
-
-void clipboard_set_drop_handler(struct clipboard *c, clipboard_drop_fn fn, void *ud)
-{
- if (!c) return;
- c->drop = fn;
- c->drop_ud = ud;
-}
-
-struct wl_data_device *clipboard_data_device(const struct clipboard *c)
-{
- return c ? c->device : NULL;
-}
-
-struct clipboard *clipboard_create(struct wl_display *display, struct wl_data_device_manager *manager,
- struct wl_seat *seat, struct yasl_loop *loop,
- clipboard_receive_fn receive, void *ud)
-{
- if (!manager || !seat) return NULL;
- struct clipboard *c = calloc(1, sizeof(*c));
- if (!c) return NULL;
- c->display = display; c->manager = manager; c->loop = loop; c->receive = receive; c->ud = ud;
- c->device = wl_data_device_manager_get_data_device(manager, seat);
- if (!c->device) { free(c); return NULL; }
- c->seat = seat;
- wl_data_device_add_listener(c->device, &device_listener, c);
- return c;
-}
-
-bool clipboard_set_seat(struct clipboard *c, struct wl_seat *seat)
-{
- if (!c || c->seat == seat) return false;
- c->seat = seat;
- drag_offer_clear(c, c->device);
- if (c->device) {
- wl_data_device_destroy(c->device);
- c->device = NULL;
- }
- free_offer(c->selection);
- c->selection = NULL;
- clear_pending_offers(c);
- if (c->source) {
- wl_data_source_destroy(c->source);
- c->source = NULL;
- }
- if (c->primary_device) {
- zwp_primary_selection_device_v1_destroy(c->primary_device);
- c->primary_device = NULL;
- }
- free_primary_offer(c->primary_selection);
- c->primary_selection = NULL;
- clear_pending_primary_offers(c);
- if (c->primary_source) {
- zwp_primary_selection_source_v1_destroy(c->primary_source);
- c->primary_source = NULL;
- }
- if (!seat) return true;
- if (c->manager) {
- c->device = wl_data_device_manager_get_data_device(c->manager, seat);
- if (c->device)
- wl_data_device_add_listener(c->device, &device_listener, c);
- }
- if (c->primary_manager) {
- c->primary_device =
- zwp_primary_selection_device_manager_v1_get_device(c->primary_manager, seat);
- if (c->primary_device)
- zwp_primary_selection_device_v1_add_listener(c->primary_device,
- &primary_device_listener, c);
- }
- return true;
-}
-
-void clipboard_copy(struct clipboard *c, const char *text, uint32_t serial)
-{
- if (!c || !c->device || !text || !serial) return;
- char *copy = strdup(text);
- if (!copy) return;
- if (c->source) wl_data_source_destroy(c->source);
- free(c->text); c->text = copy;
- c->source = wl_data_device_manager_create_data_source(c->manager);
- if (!c->source) return;
- wl_data_source_add_listener(c->source, &source_listener, c);
- wl_data_source_offer(c->source, "text/plain;charset=utf-8");
- wl_data_source_offer(c->source, "text/plain");
- wl_data_source_offer(c->source, "UTF8_STRING");
- wl_data_source_offer(c->source, "STRING");
- wl_data_source_offer(c->source, "TEXT");
- wl_data_device_set_selection(c->device, c->source, serial);
-}
-
-void clipboard_paste(struct clipboard *c, struct wl_surface *target)
-{
- if (!c || !c->device || !c->selection || !c->selection->mime) return;
- int fds[2];
- if (pipe2(fds, O_CLOEXEC) < 0) return;
- wl_data_offer_receive(c->selection->proxy, c->selection->mime, fds[1]);
- close(fds[1]);
- struct transfer *t = start_transfer(c, fds[0], false, false);
- if (t) t->drop_surface = target;
- wl_display_flush(c->display);
-}
-
-void clipboard_copy_primary(struct clipboard *c, const char *text, uint32_t serial)
-{
- if (!c || !text || !serial) return;
- if (!c->primary_device || !c->primary_manager) return;
- char *copy = strdup(text);
- if (!copy) return;
- if (c->primary_source) zwp_primary_selection_source_v1_destroy(c->primary_source);
- free(c->primary_text); c->primary_text = copy;
- c->primary_source = zwp_primary_selection_device_manager_v1_create_source(c->primary_manager);
- if (!c->primary_source) return;
- zwp_primary_selection_source_v1_add_listener(c->primary_source, &primary_source_listener, c);
- zwp_primary_selection_source_v1_offer(c->primary_source, "text/plain;charset=utf-8");
- zwp_primary_selection_source_v1_offer(c->primary_source, "text/plain");
- zwp_primary_selection_source_v1_offer(c->primary_source, "UTF8_STRING");
- zwp_primary_selection_source_v1_offer(c->primary_source, "STRING");
- zwp_primary_selection_source_v1_offer(c->primary_source, "TEXT");
- zwp_primary_selection_device_v1_set_selection(c->primary_device, c->primary_source, serial);
-}
-
-void clipboard_paste_primary(struct clipboard *c, struct wl_surface *target)
-{
- if (!c) return;
- if (c->primary_device && c->primary_selection && c->primary_selection->mime) {
- int fds[2];
- if (pipe2(fds, O_CLOEXEC) < 0) return;
- zwp_primary_selection_offer_v1_receive(c->primary_selection->proxy,
- c->primary_selection->mime, fds[1]);
- close(fds[1]);
- struct transfer *t = start_transfer(c, fds[0], false, false);
- if (t) t->drop_surface = target;
- wl_display_flush(c->display);
- return;
- }
-}
-
-void clipboard_forget_surface(struct clipboard *c, struct wl_surface *surface)
-{
- if (!c || !surface) return;
- for (struct transfer *t = c->transfers, *next; t; t = next) {
- next = t->next;
- if (t->drop_surface == surface) transfer_destroy(t);
- }
- if (c->drag_surface == surface) c->drag_surface = NULL;
-}
-
-void clipboard_destroy(struct clipboard *c)
-{
- if (!c) return;
- while (c->transfers)
- transfer_destroy(c->transfers);
- free_offer(c->selection);
- clear_pending_offers(c);
- free_offer(c->drag_offer);
- free_primary_offer(c->primary_selection);
- clear_pending_primary_offers(c);
- if (c->primary_source) zwp_primary_selection_source_v1_destroy(c->primary_source);
- if (c->primary_device) zwp_primary_selection_device_v1_destroy(c->primary_device);
- free(c->primary_text);
- if (c->source) wl_data_source_destroy(c->source);
- if (c->device) wl_data_device_destroy(c->device);
- free(c->text); free(c);
-}