blob: 3fef423ebc83d544aad8023ca87ab98b030bc849 [file] [log] [blame]
Foxe Chenb90c2392025-06-27 21:10:35 +02001/* vi:set ts=8 sts=4 sw=4 noet:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
Hirohito Higashi73b96502025-06-28 18:18:21 +020011 * wayland.c: Stuff related to Wayland
Foxe Chenb90c2392025-06-27 21:10:35 +020012 */
13
14#include "vim.h"
15
16#ifdef FEAT_WAYLAND
17
18#include <wayland-client.h>
19
20#ifdef FEAT_WAYLAND_CLIPBOARD
21# include "auto/wayland/wlr-data-control-unstable-v1.h"
22# include "auto/wayland/ext-data-control-v1.h"
23# include "auto/wayland/xdg-shell.h"
24# include "auto/wayland/primary-selection-unstable-v1.h"
25#endif
26
27// Struct that represents a seat. (Should be accessed via
28// vwl_get_seat()).
29typedef struct {
30 struct wl_seat *proxy;
31 char *label; // Name of seat as text (e.g. seat0,
32 // seat1...).
33 uint32_t capabilities; // Bitmask of the capabilites of the seat
34 // (pointer, keyboard, touch).
35} vwl_seat_T;
36
37// Global objects
38typedef struct {
39#ifdef FEAT_WAYLAND_CLIPBOARD
40 // Data control protocols
41 struct zwlr_data_control_manager_v1 *zwlr_data_control_manager_v1;
42 struct ext_data_control_manager_v1 *ext_data_control_manager_v1;
43 struct wl_data_device_manager *wl_data_device_manager;
44 struct wl_shm *wl_shm;
45 struct wl_compositor *wl_compositor;
46 struct xdg_wm_base *xdg_wm_base;
47 struct zwp_primary_selection_device_manager_v1
48 *zwp_primary_selection_device_manager_v1;
49#endif
50} vwl_global_objects_T;
51
Hirohito Higashi73b96502025-06-28 18:18:21 +020052// Struct wrapper for Wayland display and registry
Foxe Chenb90c2392025-06-27 21:10:35 +020053typedef struct {
54 struct wl_display *proxy;
55 int fd; // File descriptor for display
56
57 struct {
58 struct wl_registry *proxy;
59 } registry;
60} vwl_display_T;
61
62#ifdef FEAT_WAYLAND_CLIPBOARD
63
64typedef struct {
65 struct wl_shm_pool *pool;
66 int fd;
67
68 struct wl_buffer *buffer;
69 int available;
70
71 int width;
72 int height;
73 int stride;
74 int size;
75} vwl_buffer_store_T;
76
77typedef struct {
78 void *user_data;
79 void (*on_focus)(void *data, uint32_t serial);
80
81 struct wl_surface *surface;
82 struct wl_keyboard *keyboard;
83
84 struct {
85 struct xdg_surface *surface;
86 struct xdg_toplevel *toplevel;
87 } shell;
88
89 int got_focus;
90} vwl_fs_surface_T; // fs = focus steal
91
92// Wayland protocols for accessing the selection
93typedef enum {
94 VWL_DATA_PROTOCOL_NONE,
95 VWL_DATA_PROTOCOL_EXT,
96 VWL_DATA_PROTOCOL_WLR,
97 VWL_DATA_PROTOCOL_CORE,
98 VWL_DATA_PROTOCOL_PRIMARY
99} vwl_data_protocol_T;
100
101// DATA RELATED OBJECT WRAPPERS
102// These wrap around a proxy and act as a generic container.
103// The `data` member is used to pass other needed stuff around such as a
104// vwl_clipboard_selection_T pointer.
105
106typedef struct {
107 void *proxy;
108 void *data; // Is not set when a new offer is created on a
109 // data_offer event. Only set when listening to a
110 // data offer.
111 vwl_data_protocol_T protocol;
112} vwl_data_offer_T;
113
114typedef struct {
115 void *proxy;
116 void *data;
117 vwl_data_protocol_T protocol;
118} vwl_data_source_T;
119
120typedef struct {
121 void *proxy;
122 void *data;
123 vwl_data_protocol_T protocol;
124} vwl_data_device_T;
125
126typedef struct {
127 void *proxy;
128 vwl_data_protocol_T protocol;
129} vwl_data_device_manager_T;
130
131// LISTENER WRAPPERS
132
133typedef struct {
134 void (*data_offer)(vwl_data_device_T *device, vwl_data_offer_T *offer);
135
136 // If the protocol that the data device uses doesn't support a specific
137 // selection, then this callback will never be called with that selection.
138 void (*selection)(
139 vwl_data_device_T *device,
140 vwl_data_offer_T *offer,
141 wayland_selection_T selection);
142
143 // This event is only relevant for data control protocols
144 void (*finished)(vwl_data_device_T *device);
145} vwl_data_device_listener_T;
146
147typedef struct {
148 void (*send)(vwl_data_source_T *source, const char *mime_type, int fd);
149 void (*cancelled)(vwl_data_source_T *source);
150} vwl_data_source_listener_T;
151
152typedef struct {
153 void (*offer)(vwl_data_offer_T *offer, const char *mime_type);
154} vwl_data_offer_listener_T;
155
156typedef struct
157{
158 // What selection this refers to
159 wayland_selection_T selection;
160
161 // Do not destroy here
162 vwl_data_device_manager_T manager;
163
164 vwl_data_device_T device;
165 vwl_data_source_T source;
166 vwl_data_offer_T *offer; // Current offer for the selection
167
168 garray_T mime_types; // Mime types supported by the
169 // current offer
170
171 garray_T tmp_mime_types; // Temporary array for mime
172 // types when we are receiving
173 // them. When the selection
174 // event arrives and it is the
175 // one we want, then copy it
176 // over to mime_types
177
178 // To be populated by callbacks from outside this file
179 wayland_cb_send_data_func_T send_cb;
180 wayland_cb_selection_cancelled_func_T cancelled_cb;
181
182 int requires_focus; // If focus needs to be given to us to work
183} vwl_clipboard_selection_T;
184
185// Holds stuff related to the clipboard/selections
186typedef struct {
187 // Do not destroy here, will be destroyed when vwl_disconnect_display() is
188 // called.
189 vwl_seat_T *seat;
190
191 vwl_clipboard_selection_T regular;
192 vwl_clipboard_selection_T primary;
193
194 vwl_buffer_store_T *fs_buffer;
195} vwl_clipboard_T;
196
197#endif // FEAT_WAYLAND_CLIPBOARD
198
199static int vwl_display_flush(vwl_display_T *display);
200static void vwl_callback_done(void *data, struct wl_callback *callback,
201 uint32_t cb_data);
202static int vwl_display_roundtrip(vwl_display_T *display);
203static int vwl_display_dispatch(vwl_display_T *display);
204static int vwl_display_dispatch_any(vwl_display_T *display);
205
206static void vwl_log_handler(const char *fmt, va_list args);
207static int vwl_connect_display(const char *display);
208static void vwl_disconnect_display(void);
209
210static void vwl_xdg_wm_base_listener_ping(void *data,
211 struct xdg_wm_base *base, uint32_t serial);
212static int vwl_listen_to_registry(void);
213
214static void vwl_registry_listener_global(void *data,
215 struct wl_registry *registry, uint32_t name,
216 const char *interface, uint32_t version);
217static void vwl_registry_listener_global_remove(void *data,
218 struct wl_registry *registry, uint32_t name);
219
220static void vwl_add_seat(struct wl_seat *seat);
221static void vwl_seat_listener_name(void *data, struct wl_seat *seat,
222 const char *name);
223static void vwl_seat_listener_capabilities(void *data, struct wl_seat *seat,
224 uint32_t capabilities);
225static void vwl_destroy_seat(vwl_seat_T *seat);
226
227static vwl_seat_T *vwl_get_seat(const char *label);
228static struct wl_keyboard *vwl_seat_get_keyboard(vwl_seat_T *seat);
229
230#ifdef FEAT_WAYLAND_CLIPBOARD
231
232static int vwl_focus_stealing_available(void);
233static void vwl_xdg_surface_listener_configure(void *data,
234 struct xdg_surface *surface, uint32_t serial);
235
236static void vwl_bs_buffer_listener_release(void *data,
237 struct wl_buffer *buffer);
238static void vwl_destroy_buffer_store(vwl_buffer_store_T *store);
239static vwl_buffer_store_T *vwl_init_buffer_store(int width, int height);
240
241static void vwl_destroy_fs_surface(vwl_fs_surface_T *store);
242static int vwl_init_fs_surface(vwl_seat_T *seat,
243 vwl_buffer_store_T *buffer_store,
244 void (*on_focus)(void *, uint32_t), void *user_data);
245
246static void vwl_fs_keyboard_listener_enter(void *data,
247 struct wl_keyboard *keyboard, uint32_t serial,
248 struct wl_surface *surface, struct wl_array *keys);
249static void vwl_fs_keyboard_listener_keymap(void *data,
250 struct wl_keyboard *keyboard, uint32_t format,
251 int fd, uint32_t size);
252static void vwl_fs_keyboard_listener_leave(void *data,
253 struct wl_keyboard *keyboard, uint32_t serial,
254 struct wl_surface *surface);
255static void vwl_fs_keyboard_listener_key(void *data,
256 struct wl_keyboard *keyboard, uint32_t serial,
257 uint32_t time, uint32_t key, uint32_t state);
258static void vwl_fs_keyboard_listener_modifiers(void *data,
259 struct wl_keyboard *keyboard, uint32_t serial,
260 uint32_t mods_depressed, uint32_t mods_latched,
261 uint32_t mods_locked, uint32_t group);
262static void vwl_fs_keyboard_listener_repeat_info(void *data,
263 struct wl_keyboard *keyboard, int32_t rate, int32_t delay);
264
265static void vwl_gen_data_device_listener_data_offer(void *data,
266 void *offer_proxy);
267static void vwl_gen_data_device_listener_selection(void *data,
268 void *offer_proxy, wayland_selection_T selection,
269 vwl_data_protocol_T protocol);
270
271static void vwl_data_device_destroy(vwl_data_device_T *device, int alloced);
272static void vwl_data_offer_destroy(vwl_data_offer_T *offer, int alloced);
273static void vwl_data_source_destroy(vwl_data_source_T *source, int alloced);
274
275static void vwl_data_device_add_listener(vwl_data_device_T *device,
276 void *data);
277static void vwl_data_source_add_listener(vwl_data_source_T *source,
278 void *data);
279static void vwl_data_offer_add_listener(vwl_data_offer_T *offer,
280 void *data);
281
282static void vwl_data_device_set_selection(vwl_data_device_T *device,
283 vwl_data_source_T *source, uint32_t serial,
284 wayland_selection_T selection);
285static void vwl_data_offer_receive(vwl_data_offer_T *offer,
286 const char *mime_type, int fd);
287static int vwl_get_data_device_manager(vwl_data_device_manager_T *manager,
288 wayland_selection_T selection);
289static void vwl_get_data_device(vwl_data_device_manager_T *manager,
290 vwl_seat_T *seat, vwl_data_device_T *device);
291static void vwl_create_data_source(vwl_data_device_manager_T *manager,
292 vwl_data_source_T *source);
293static void vwl_data_source_offer(vwl_data_source_T *source,
294 const char *mime_type);
295
296static void vwl_clipboard_free_mime_types(
297 vwl_clipboard_selection_T *clip_sel);
298static int vwl_clipboard_selection_is_ready(
299 vwl_clipboard_selection_T *clip_sel);
300
301static void vwl_data_device_listener_data_offer(
302 vwl_data_device_T *device, vwl_data_offer_T *offer);
303static void vwl_data_offer_listener_offer(vwl_data_offer_T *offer,
304 const char *mime_type);
305static void vwl_data_device_listener_selection(vwl_data_device_T *device,
306 vwl_data_offer_T *offer, wayland_selection_T selection);
307static void vwl_data_device_listener_finished(vwl_data_device_T *device);
308
309static void vwl_data_source_listener_send(vwl_data_source_T *source,
310 const char *mime_type, int fd);
311static void vwl_data_source_listener_cancelled(vwl_data_source_T *source);
312
313static void vwl_on_focus_set_selection(void *data, uint32_t serial);
314
315static void wayland_set_display(const char *display);
316
317static vwl_data_device_listener_T vwl_data_device_listener = {
318 .data_offer = vwl_data_device_listener_data_offer,
319 .selection = vwl_data_device_listener_selection,
320 .finished = vwl_data_device_listener_finished
321};
322
323static vwl_data_source_listener_T vwl_data_source_listener = {
324 .send = vwl_data_source_listener_send,
325 .cancelled = vwl_data_source_listener_cancelled
326};
327
328static vwl_data_offer_listener_T vwl_data_offer_listener = {
329 .offer = vwl_data_offer_listener_offer
330};
331
332static struct xdg_wm_base_listener vwl_xdg_wm_base_listener = {
333 .ping = vwl_xdg_wm_base_listener_ping
334};
335
336static struct xdg_surface_listener vwl_xdg_surface_listener = {
337 .configure = vwl_xdg_surface_listener_configure
338};
339
340static struct wl_buffer_listener vwl_cb_buffer_listener = {
341 .release = vwl_bs_buffer_listener_release
342};
343
344static struct wl_keyboard_listener vwl_fs_keyboard_listener = {
345 .enter = vwl_fs_keyboard_listener_enter,
346 .key = vwl_fs_keyboard_listener_key,
347 .keymap = vwl_fs_keyboard_listener_keymap,
348 .leave = vwl_fs_keyboard_listener_leave,
349 .modifiers = vwl_fs_keyboard_listener_modifiers,
350 .repeat_info = vwl_fs_keyboard_listener_repeat_info
351};
352
353#endif // FEAT_WAYLAND_CLIPBOARD
354
355static struct wl_callback_listener vwl_callback_listener = {
356 .done = vwl_callback_done
357};
358
359static struct wl_registry_listener vwl_registry_listener = {
360 .global = vwl_registry_listener_global,
361 .global_remove = vwl_registry_listener_global_remove
362};
363
364static struct wl_seat_listener vwl_seat_listener = {
365 .name = vwl_seat_listener_name,
366 .capabilities = vwl_seat_listener_capabilities
367};
368
369static vwl_display_T vwl_display;
370static vwl_global_objects_T vwl_gobjects;
371static garray_T vwl_seats;
372
373#ifdef FEAT_WAYLAND_CLIPBOARD
374// Make sure to sync this with vwl_cb_uninit since it memsets this to zero
375static vwl_clipboard_T vwl_clipboard = {
376 .regular.selection = WAYLAND_SELECTION_REGULAR,
377 .primary.selection = WAYLAND_SELECTION_PRIMARY,
378};
379
380// Only really used for debugging/testing purposes in order to force focus
381// stealing even when a data control protocol is available.
382static int force_fs = FALSE;
383#endif
384
385/*
386 * Like wl_display_flush but always writes all the data in the buffer to the
387 * display fd. Returns FAIL on failure and OK on success.
388 */
389 static int
390vwl_display_flush(vwl_display_T *display)
391{
392 int ret;
393
394#ifndef HAVE_SELECT
395 struct pollfd fds;
396
397 fds.fd = display->fd;
398 fds.events = POLLOUT;
399#else
400 fd_set wfds;
401 struct timeval tv;
402
403 FD_ZERO(&wfds);
404 FD_SET(display->fd, &wfds);
405
406 tv.tv_sec = 0;
407 tv.tv_usec = p_wtm * 1000;
408#endif
409
410 if (display->proxy == NULL)
411 return FAIL;
412
413 // Send the requests we have made to the compositor, until we have written
414 // all the data. Poll in order to check if the display fd is writable, if
415 // not, then wait until it is and continue writing or until we timeout.
416 while (errno = 0, (ret = wl_display_flush(display->proxy)) == -1
417 && errno == EAGAIN)
418 {
419#ifndef HAVE_SELECT
420 if (poll(&fds, 1, p_wtm) <= 0)
421#else
422 if (select(display->fd + 1, NULL, &wfds, NULL, &tv) <= 0)
423#endif
424 return FAIL;
425 }
426 // Return FAIL on error or timeout
427 if ((errno != 0 && errno != EAGAIN) || ret == -1)
428 return FAIL;
429
430 return OK;
431}
432
433/*
434 * Called when compositor is done processing requests/events.
435 */
436 static void
437vwl_callback_done(void *data, struct wl_callback *callback,
438 uint32_t cb_data UNUSED)
439{
440 *((int*)data) = TRUE;
441 wl_callback_destroy(callback);
442}
443
444/*
445 * Like wl_display_roundtrip but polls the display fd with a timeout. Returns
446 * FAIL on failure and OK on success.
447 */
448 static int
449vwl_display_roundtrip(vwl_display_T *display)
450{
451 struct wl_callback *callback;
452 int ret, done = FALSE;
453 struct timeval start, now;
454
455 if (display->proxy == NULL)
456 return FAIL;
457
458 // Tell compositor to emit 'done' event after processing all requests we
459 // have sent and handling events.
460 callback = wl_display_sync(display->proxy);
461
462 if (callback == NULL)
463 return FAIL;
464
465 wl_callback_add_listener(callback, &vwl_callback_listener, &done);
466
467 gettimeofday(&start, NULL);
468
469 // Wait till we get the done event (which will set `done` to TRUE), unless
470 // we timeout
471 while (TRUE)
472 {
473 ret = vwl_display_dispatch(display);
474
475 if (done || ret == -1)
476 break;
477
478 gettimeofday(&now, NULL);
479
480 if ((now.tv_sec * 1000000 + now.tv_usec) -
481 (start.tv_sec * 1000000 + start.tv_usec) >= p_wtm * 1000)
482 {
483 ret = -1;
484 break;
485 }
486 }
487
488 if (ret == -1)
489 {
490 if (!done)
491 wl_callback_destroy(callback);
492 return FAIL;
493 }
494
495 return OK;
496}
497
498/*
499 * Like wl_display_roundtrip but polls the display fd with a timeout. Returns
500 * number of events dispatched on success else -1 on failure.
501 */
502 static int
503vwl_display_dispatch(vwl_display_T *display)
504{
505#ifndef HAVE_SELECT
506 struct pollfd fds;
507
508 fds.fd = display->fd;
509 fds.events = POLLIN;
510#else
511 fd_set rfds;
512 struct timeval tv;
513
514 FD_ZERO(&rfds);
515 FD_SET(display->fd, &rfds);
516
517 tv.tv_sec = 0;
518 tv.tv_usec = p_wtm * 1000;
519#endif
520
521 if (display->proxy == NULL)
522 return -1;
523
524 while (wl_display_prepare_read(display->proxy) == -1)
525 // Dispatch any queued events so that we can start reading
526 if (wl_display_dispatch_pending(display->proxy) == -1)
527 return -1;
528
529 // Send any requests before we starting blocking to read display fd
530 if (vwl_display_flush(display) == FAIL)
531 {
532 wl_display_cancel_read(display->proxy);
533 return -1;
534 }
535
536 // Poll until there is data to read from the display fd.
537#ifndef HAVE_SELECT
538 if (poll(&fds, 1, p_wtm) <= 0)
539#else
540 if (select(display->fd + 1, &rfds, NULL, NULL, &tv) <= 0)
541#endif
542 {
543 wl_display_cancel_read(display->proxy);
544 return -1;
545 }
546
547 // Read events into the queue
548 if (wl_display_read_events(display->proxy) == -1)
549 return -1;
550
551 // Dispatch those events (call the handlers associated for each event)
552 return wl_display_dispatch_pending(display->proxy);
553}
554
555/*
556 * Same as vwl_display_dispatch but poll/select is never called. This is useful
557 * is poll/select was already called before or if you just want to dispatch any
558 * events that happen to be waiting to be dispatched on the display fd.
559 */
560 static int
561vwl_display_dispatch_any(vwl_display_T *display)
562{
563 if (display->proxy == NULL)
564 return -1;
565
566 while (wl_display_prepare_read(display->proxy) == -1)
567 // Dispatch any queued events so that we can start reading
568 if (wl_display_dispatch_pending(display->proxy) == -1)
569 return -1;
570
571 // Send any requests before we starting blocking to read display fd
572 if (vwl_display_flush(display) == FAIL)
573 {
574 wl_display_cancel_read(display->proxy);
575 return -1;
576 }
577
578 // Read events into the queue
579 if (wl_display_read_events(display->proxy) == -1)
580 return -1;
581
582 // Dispatch those events (call the handlers associated for each event)
583 return wl_display_dispatch_pending(display->proxy);
584}
585
586/*
587 * Redirect libwayland logging to use ch_log + emsg instead.
588 */
589 static void
590vwl_log_handler(const char *fmt, va_list args)
591{
592 // 512 bytes should be big enough
593 char *buf = alloc(512);
594 char *prefix = _("wayland protocol error -> ");
595 size_t len = STRLEN(prefix);
596
597 if (buf == NULL)
598 return;
599
600 vim_strncpy((char_u*)buf, (char_u*)prefix, len);
601 vim_vsnprintf(buf + len, 4096 - len, fmt, args);
602
603 // Remove newline that libwayland puts
604 buf[STRLEN(buf) - 1] = NUL;
605
606 ch_log(NULL, "%s", buf);
607 emsg(buf);
608
609 vim_free(buf);
610}
611
612/*
613 * Connect to the display with name; passing NULL will use libwayland's way of
614 * getting the display. Additionally get the registry object but will not
615 * starting listening. Returns OK on sucess and FAIL on failure.
616 */
617 static int
618vwl_connect_display(const char *display)
619{
620 if (wayland_no_connect)
621 return FAIL;
622
623 // We will get an error if XDG_RUNTIME_DIR is not set.
624 if (mch_getenv("XDG_RUNTIME_DIR") == NULL)
625 return FAIL;
626
627 // Must set log handler before we connect display in order to work.
628 wl_log_set_handler_client(vwl_log_handler);
629
630 vwl_display.proxy = wl_display_connect(display);
631
632 if (vwl_display.proxy == NULL)
633 return FAIL;
634
635 wayland_set_display(display);
636 vwl_display.fd = wl_display_get_fd(vwl_display.proxy);
637
638 vwl_display.registry.proxy = wl_display_get_registry(vwl_display.proxy);
639
640 if (vwl_display.registry.proxy == NULL)
641 {
642 vwl_disconnect_display();
643 return FAIL;
644 }
645
646 return OK;
647}
648
649#define destroy_gobject(object) \
650 if (vwl_gobjects.object != NULL) \
651 { \
652 object##_destroy(vwl_gobjects.object); \
653 vwl_gobjects.object = NULL; \
654 }
655
656/*
657 * Disconnects the display and frees up all resources, including all global
658 * objects.
659 */
660 static void
661vwl_disconnect_display(void)
662{
663
664 destroy_gobject(ext_data_control_manager_v1)
665 destroy_gobject(zwlr_data_control_manager_v1)
666 destroy_gobject(wl_data_device_manager)
667 destroy_gobject(wl_shm)
668 destroy_gobject(wl_compositor)
669 destroy_gobject(xdg_wm_base)
670 destroy_gobject(zwp_primary_selection_device_manager_v1)
671
672 for (int i = 0; i < vwl_seats.ga_len; i++)
673 vwl_destroy_seat(&((vwl_seat_T *)vwl_seats.ga_data)[i]);
674 ga_clear(&vwl_seats);
675 vwl_seats.ga_len = 0;
676
677 if (vwl_display.registry.proxy != NULL)
678 {
679 wl_registry_destroy(vwl_display.registry.proxy);
680 vwl_display.registry.proxy = NULL;
681 }
682 if (vwl_display.proxy != NULL)
683 {
684 wl_display_disconnect(vwl_display.proxy);
685 vwl_display.proxy = NULL;
686 }
687}
688
689/*
690 * Tells the compositor we are still responsive.
691 */
692 static void
693vwl_xdg_wm_base_listener_ping(
694 void *data UNUSED,
695 struct xdg_wm_base *base,
696 uint32_t serial)
697{
698 xdg_wm_base_pong(base, serial);
699}
700
701/*
702 * Start listening to the registry and get initial set of global
703 * objects/interfaces.
704 */
705 static int
706vwl_listen_to_registry(void)
707{
708 // Only meant for debugging/testing purposes
709 char_u *env = mch_getenv("VIM_WAYLAND_FORCE_FS");
710
711 if (env != NULL && STRCMP(env, "1") == 0)
712 force_fs = TRUE;
713 else
714 force_fs = FALSE;
715
716 ga_init2(&vwl_seats, sizeof(vwl_seat_T), 1);
717
718 wl_registry_add_listener(
719 vwl_display.registry.proxy,
720 &vwl_registry_listener,
721 NULL);
722
723 if (vwl_display_roundtrip(&vwl_display) == FAIL)
724 return FAIL;
725
726#ifdef FEAT_WAYLAND_CLIPBOARD
727 // If we have a suitable data control protocol discard the rest. If we only
728 // have wlr data control protocol but its version is 1, then don't discard
729 // globals if we also have the primary selection protocol.
730 if (!force_fs &&
731 (vwl_gobjects.ext_data_control_manager_v1 != NULL ||
732 (vwl_gobjects.zwlr_data_control_manager_v1 != NULL &&
733 zwlr_data_control_manager_v1_get_version(
734 vwl_gobjects.zwlr_data_control_manager_v1) > 1)))
735 {
736 destroy_gobject(wl_data_device_manager)
737 destroy_gobject(wl_shm)
738 destroy_gobject(wl_compositor)
739 destroy_gobject(xdg_wm_base)
740 }
741 else
742 // Be ready for ping events
743 xdg_wm_base_add_listener(
744 vwl_gobjects.xdg_wm_base,
745 &vwl_xdg_wm_base_listener,
746 NULL);
747#endif
748 return OK;
749}
750
751#define SET_GOBJECT(object, min_ver) \
752 do { \
753 chosen_interface = &object##_interface; \
754 object_member = (void*)&vwl_gobjects.object; \
755 min_version = min_ver; \
756 } while (0)
757
758/*
759 * Callback for global event, for each global interface the compositor supports.
760 * Keep in sync with vwl_disconnect_display().
761 */
762 static void
763vwl_registry_listener_global(
764 void *data UNUSED,
765 struct wl_registry *registry UNUSED,
766 uint32_t name,
767 const char *interface,
768 uint32_t version)
769{
770
771 const struct wl_interface *chosen_interface = NULL;
772 void *proxy;
773 uint32_t min_version;
774 void **object_member;
775
776 if (STRCMP(interface, wl_seat_interface.name) == 0)
777 {
778 chosen_interface = &wl_seat_interface;
779 min_version = 2;
780 }
781#ifdef FEAT_WAYLAND_CLIPBOARD
782 else if (STRCMP(interface, zwlr_data_control_manager_v1_interface.name) == 0)
783 SET_GOBJECT(zwlr_data_control_manager_v1, 1);
784
785 else if (STRCMP(interface, ext_data_control_manager_v1_interface.name) == 0)
786 SET_GOBJECT(ext_data_control_manager_v1, 1);
787
788 else if (STRCMP(interface, wl_data_device_manager_interface.name) == 0)
789 SET_GOBJECT(wl_data_device_manager, 1);
790
791 else if (STRCMP(interface, wl_shm_interface.name) == 0)
792 SET_GOBJECT(wl_shm, 1);
793
794 else if (STRCMP(interface, wl_compositor_interface.name) == 0)
795 SET_GOBJECT(wl_compositor, 2);
796
797 else if (STRCMP(interface, xdg_wm_base_interface.name) == 0)
798 SET_GOBJECT(xdg_wm_base, 1);
799
800 else if (STRCMP(interface,
801 zwp_primary_selection_device_manager_v1_interface.name) == 0)
802 SET_GOBJECT(zwp_primary_selection_device_manager_v1, 1);
803#endif
804
805 if (chosen_interface == NULL || version < min_version)
806 return;
807
808 proxy = wl_registry_bind(vwl_display.registry.proxy, name, chosen_interface,
809 version);
810
811 if (chosen_interface == &wl_seat_interface)
812 // Add seat to vwl_seats array, as we can have multiple seats.
813 vwl_add_seat(proxy);
814 else
815 // Hold proxy & name in the vwl_gobject struct
816 *object_member = proxy;
817}
818
819/*
820 * Called when a global object is removed, if so, then do nothing. This is to
821 * avoid a global being removed while it is in the process of being used. Let
822 * the user call :wlrestore in order to reset everything. Requests to that
823 * global will just be ignored on the compositor side.
824 */
825 static void
826vwl_registry_listener_global_remove(
827 void *data UNUSED,
828 struct wl_registry *registry UNUSED,
829 uint32_t name UNUSED)
830{
831}
832
833/*
834 * Add a new seat given its proxy to the global grow array
835 */
836 static void
837vwl_add_seat(struct wl_seat *seat_proxy)
838{
839 vwl_seat_T *seat;
840
841 if (ga_grow(&vwl_seats, 1) == FAIL)
842 return;
843
844 seat = &((vwl_seat_T *)vwl_seats.ga_data)[vwl_seats.ga_len];
845
846 seat->proxy = seat_proxy;
847
848 // Get label and capabilities
849 wl_seat_add_listener(seat_proxy, &vwl_seat_listener, seat);
850
851 if (vwl_display_roundtrip(&vwl_display) == FAIL)
852 return;
853
854 // Check if label has been allocated
855 if (seat->label == NULL)
856 return;
857
858 vwl_seats.ga_len++;
859}
860
861/*
862 * Callback for seat text label/name
863 */
864 static void
865vwl_seat_listener_name(
866 void *data,
867 struct wl_seat *seat_proxy UNUSED,
868 const char *name)
869{
870 vwl_seat_T *seat = data;
871
872 seat->label = (char *)vim_strsave((char_u *)name);
873}
874
875/*
876 * Callback for seat capabilities
877 */
878 static void
879vwl_seat_listener_capabilities(
880 void *data,
881 struct wl_seat *seat_proxy UNUSED,
882 uint32_t capabilities)
883{
884 vwl_seat_T *seat = data;
885
886 seat->capabilities = capabilities;
887}
888
889/*
890 * Destroy/free seat.
891 */
892 static void
893vwl_destroy_seat(vwl_seat_T *seat)
894{
895 if (seat->proxy != NULL)
896 {
897 if (wl_seat_get_version(seat->proxy) >= 5)
898 // Helpful for the compositor
899 wl_seat_release(seat->proxy);
900 else
901 wl_seat_destroy(seat->proxy);
902 seat->proxy = NULL;
903 }
904 vim_free(seat->label);
905 seat->label = NULL;
906}
907
908/*
909 * Return a seat with the give name/label. If none exists then NULL is returned.
Foxe Chen7a4cf4b2025-06-29 18:00:46 +0200910 * If NULL or an empty string is passed as the label then the first available
911 * seat found is used.
Foxe Chenb90c2392025-06-27 21:10:35 +0200912 */
913 static vwl_seat_T *
914vwl_get_seat(const char *label)
915{
916 if ((STRCMP(label, "") == 0 || label == NULL) && vwl_seats.ga_len > 0)
Foxe Chenb90c2392025-06-27 21:10:35 +0200917 return &((vwl_seat_T *)vwl_seats.ga_data)[0];
Foxe Chenb90c2392025-06-27 21:10:35 +0200918
919 for (int i = 0; i < vwl_seats.ga_len; i++)
920 {
921 vwl_seat_T *seat = &((vwl_seat_T *)vwl_seats.ga_data)[i];
922 if (STRCMP(seat->label, label) == 0)
923 return seat;
924 }
925 return NULL;
926}
927
928/*
929 * Get keyboard object from seat and return it. NULL is returned on
930 * failure such as when a keyboard is not available for seat.
931 */
932 static struct wl_keyboard *
933vwl_seat_get_keyboard(vwl_seat_T *seat)
934{
935 if (!(seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD))
936 return NULL;
937
938 return wl_seat_get_keyboard(seat->proxy);
939}
940
941/*
Hirohito Higashi73b96502025-06-28 18:18:21 +0200942 * Connects to the Wayland display with given name and binds to global objects
Foxe Chenb90c2392025-06-27 21:10:35 +0200943 * as needed. If display is NULL then the $WAYLAND_DISPLAY environment variable
944 * will be used (handled by libwayland). Returns FAIL on failure and OK on
945 * success
946 */
947 int
948wayland_init_client(const char *display)
949{
950 wayland_set_display(display);
951
952 if (vwl_connect_display(display) == FAIL ||
953 vwl_listen_to_registry() == FAIL)
954 goto fail;
955
956 wayland_display_fd = vwl_display.fd;
957
958 return OK;
959fail:
960 // Set v:wayland_display to empty string (but not wayland_display_name)
961 wayland_set_display("");
962 return FAIL;
963}
964
965/*
Hirohito Higashi73b96502025-06-28 18:18:21 +0200966 * Disconnect Wayland client and free up all resources used.
Foxe Chenb90c2392025-06-27 21:10:35 +0200967 */
968 void
969wayland_uninit_client(void)
970{
971#ifdef FEAT_WAYLAND_CLIPBOARD
972 wayland_cb_uninit();
973#endif
974 vwl_disconnect_display();
975
976 wayland_set_display("");
977}
978
979/*
Hirohito Higashi73b96502025-06-28 18:18:21 +0200980 * Return TRUE if Wayland display connection is valid and ready.
Foxe Chenb90c2392025-06-27 21:10:35 +0200981 */
982 int
983wayland_client_is_connected(int quiet)
984{
985 if (vwl_display.proxy == NULL)
986 goto error;
987
988 // Display errors are always fatal
989 if (wl_display_get_error(vwl_display.proxy) != 0
990 || vwl_display_flush(&vwl_display) == FAIL)
991 goto error;
992
993 return TRUE;
994error:
995 if (!quiet)
996 emsg(e_wayland_connection_unavailable);
997 return FALSE;
998}
999
1000/*
1001 * Flush requests and process new Wayland events, does not poll the display file
1002 * descriptor.
1003 */
1004 int
1005wayland_client_update(void)
1006{
1007 return vwl_display_dispatch_any(&vwl_display) == -1 ? FAIL : OK;
1008}
1009
1010#ifdef FEAT_WAYLAND_CLIPBOARD
1011
1012/*
1013 * If globals required for focus stealing method is available.
1014 */
1015 static int
1016vwl_focus_stealing_available(void)
1017{
1018 return (p_wst || force_fs) &&
1019 vwl_gobjects.wl_compositor != NULL &&
1020 vwl_gobjects.wl_shm != NULL &&
1021 vwl_gobjects.xdg_wm_base != NULL;
1022}
1023
1024/*
1025 * Configure xdg_surface
1026 */
1027 static void
1028vwl_xdg_surface_listener_configure(
1029 void *data UNUSED,
1030 struct xdg_surface *surface,
1031 uint32_t serial)
1032{
1033 xdg_surface_ack_configure(surface, serial);
1034}
1035
1036/*
1037 * Called when compositor isn't using the buffer anymore, we can reuse it again.
1038 */
1039 static void
1040vwl_bs_buffer_listener_release(
1041 void *data,
1042 struct wl_buffer *buffer UNUSED)
1043{
1044 vwl_buffer_store_T *store = data;
1045
1046 store->available = TRUE;
1047}
1048
1049/*
1050 * Destroy a buffer store structure.
1051 */
1052 static void
1053vwl_destroy_buffer_store(vwl_buffer_store_T *store)
1054{
1055 if (store->buffer != NULL)
1056 wl_buffer_destroy(store->buffer);
1057 if (store->pool != NULL)
1058 wl_shm_pool_destroy(store->pool);
1059
1060 close(store->fd);
1061
1062 vim_free(store);
1063}
1064
1065/*
1066 * Initialize a buffer and its backing memory pool.
1067 */
1068 static vwl_buffer_store_T *
1069vwl_init_buffer_store(int width, int height)
1070{
1071 int fd, r;
1072 vwl_buffer_store_T *store;
1073
1074 if (vwl_gobjects.wl_shm == NULL)
1075 return NULL;
1076
1077 store = alloc(sizeof(*store));
1078
1079 if (store == NULL)
1080 return NULL;
1081
1082 store->available = FALSE;
1083
1084 store->width = width;
1085 store->height = height;
1086 store->stride = store->width * 4;
1087 store->size = store->stride * store->height;
1088
1089 fd = mch_create_anon_file();
1090 r = ftruncate(fd, store->size);
1091
1092 if (r == -1)
1093 {
1094 if (fd >= 0)
1095 close(fd);
1096 return NULL;
1097 }
1098
1099 store->pool = wl_shm_create_pool(vwl_gobjects.wl_shm, fd, store->size);
1100 store->buffer = wl_shm_pool_create_buffer(
1101 store->pool,
1102 0,
1103 store->width,
1104 store->height,
1105 store->stride,
1106 WL_SHM_FORMAT_ARGB8888);
1107
1108 store->fd = fd;
1109
1110 wl_buffer_add_listener(store->buffer, &vwl_cb_buffer_listener, store);
1111
1112 if (vwl_display_roundtrip(&vwl_display) == -1)
1113 {
1114 vwl_destroy_buffer_store(store);
1115 return NULL;
1116 }
1117
1118 store->available = TRUE;
1119
1120 return store;
1121}
1122
1123/*
1124 * Destroy a focus stealing store structure.
1125 */
1126 static void
1127vwl_destroy_fs_surface(vwl_fs_surface_T *store)
1128{
1129 if (store->shell.toplevel != NULL)
1130 xdg_toplevel_destroy(store->shell.toplevel);
1131 if (store->shell.surface != NULL)
1132 xdg_surface_destroy(store->shell.surface);
1133 if (store->surface != NULL)
1134 wl_surface_destroy(store->surface);
1135 if (store->keyboard != NULL)
1136 {
1137 if (wl_keyboard_get_version(store->keyboard) >= 3)
1138 wl_keyboard_release(store->keyboard);
1139 else
1140 wl_keyboard_destroy(store->keyboard);
1141 }
1142 vim_free(store);
1143}
1144
1145/*
1146 * Create an invisible surface in order to gain focus and call on_focus() with
1147 * serial that was given.
1148 */
1149 static int
1150vwl_init_fs_surface(
1151 vwl_seat_T *seat,
1152 vwl_buffer_store_T *buffer_store,
1153 void (*on_focus)(void *, uint32_t),
1154 void *user_data)
1155{
1156 vwl_fs_surface_T *store;
1157
1158 if (vwl_gobjects.wl_compositor == NULL || vwl_gobjects.xdg_wm_base == NULL)
1159 return FAIL;
1160 if (buffer_store == NULL || seat == NULL)
1161 return FAIL;
1162
1163 store = alloc_clear(sizeof(*store));
1164
1165 if (store == NULL)
1166 return FAIL;
1167
1168 // Get keyboard
1169 store->keyboard = vwl_seat_get_keyboard(seat);
1170
1171 if (store->keyboard == NULL)
1172 goto fail;
1173
1174 wl_keyboard_add_listener(store->keyboard, &vwl_fs_keyboard_listener, store);
1175
1176 if (vwl_display_dispatch(&vwl_display) == -1)
1177 goto fail;
1178
1179 store->surface = wl_compositor_create_surface(vwl_gobjects.wl_compositor);
1180 store->shell.surface = xdg_wm_base_get_xdg_surface(
1181 vwl_gobjects.xdg_wm_base, store->surface);
1182 store->shell.toplevel = xdg_surface_get_toplevel(store->shell.surface);
1183
1184 xdg_toplevel_set_title(store->shell.toplevel, "Vim clipboard");
1185
1186 xdg_surface_add_listener(store->shell.surface,
1187 &vwl_xdg_surface_listener, NULL);
1188
1189 wl_surface_commit(store->surface);
1190
1191 store->on_focus = on_focus;
1192 store->user_data = user_data;
1193 store->got_focus = FALSE;
1194
1195 if (vwl_display_roundtrip(&vwl_display) == FAIL)
1196 goto fail;
1197
1198 // We may get the enter event early, if we do then we will set `got_focus`
1199 // to TRUE.
1200 if (store->got_focus)
1201 goto early_exit;
1202
1203 // Buffer hasn't been released yet, abort. This shouldn't happen but still
1204 // check for it.
1205 if (!buffer_store->available)
1206 goto fail;
1207
1208 buffer_store->available = FALSE;
1209
1210 wl_surface_attach(store->surface, buffer_store->buffer, 0, 0);
1211 wl_surface_damage(store->surface, 0, 0,
1212 buffer_store->width, buffer_store->height);
1213 wl_surface_commit(store->surface);
1214
1215 {
1216 // Dispatch events until we receive the enter event. Add a max delay of
1217 // 'p_wtm' when waiting for it (may be longer depending on how long we
1218 // poll when dispatching events)
1219 struct timeval start, now;
1220
1221 gettimeofday(&start, NULL);
1222
1223 while (vwl_display_dispatch(&vwl_display) != -1)
1224 {
1225 if (store->got_focus)
1226 break;
1227
1228 gettimeofday(&now, NULL);
1229
1230 if ((now.tv_sec * 1000000 + now.tv_usec) -
1231 (start.tv_sec * 1000000 + start.tv_usec)
1232 >= p_wtm * 1000)
1233 goto fail;
1234 }
1235 }
1236early_exit:
1237 vwl_destroy_fs_surface(store);
1238 vwl_display_flush(&vwl_display);
1239
1240 return OK;
1241fail:
1242 vwl_destroy_fs_surface(store);
1243 vwl_display_flush(&vwl_display);
1244
1245 return FAIL;
1246}
1247
1248/*
1249 * Called when the keyboard focus is on our surface
1250 */
1251 static void
1252vwl_fs_keyboard_listener_enter(
1253 void *data,
1254 struct wl_keyboard *keyboard UNUSED,
1255 uint32_t serial,
1256 struct wl_surface *surface UNUSED,
1257 struct wl_array *keys UNUSED)
1258{
1259 vwl_fs_surface_T *store = data;
1260
1261 store->got_focus = TRUE;
1262
1263 if (store->on_focus != NULL)
1264 store->on_focus(store->user_data, serial);
1265}
1266
1267// Dummy functions to handle keyboard events we don't care about.
1268
1269 static void
1270vwl_fs_keyboard_listener_keymap(
1271 void *data UNUSED,
1272 struct wl_keyboard *keyboard UNUSED,
1273 uint32_t format UNUSED,
1274 int fd,
1275 uint32_t size UNUSED)
1276{
1277 close(fd);
1278}
1279
1280 static void
1281vwl_fs_keyboard_listener_leave(
1282 void *data UNUSED,
1283 struct wl_keyboard *keyboard UNUSED,
1284 uint32_t serial UNUSED,
1285 struct wl_surface *surface UNUSED)
1286{
1287}
1288
1289 static void
1290vwl_fs_keyboard_listener_key(
1291 void *data UNUSED,
1292 struct wl_keyboard *keyboard UNUSED,
1293 uint32_t serial UNUSED,
1294 uint32_t time UNUSED,
1295 uint32_t key UNUSED,
1296 uint32_t state UNUSED)
1297{
1298}
1299
1300 static void
1301vwl_fs_keyboard_listener_modifiers(
1302 void *data UNUSED,
1303 struct wl_keyboard *keyboard UNUSED,
1304 uint32_t serial UNUSED,
1305 uint32_t mods_depressed UNUSED,
1306 uint32_t mods_latched UNUSED,
1307 uint32_t mods_locked UNUSED,
1308 uint32_t group UNUSED)
1309{
1310}
1311
1312 static void
1313vwl_fs_keyboard_listener_repeat_info(
1314 void *data UNUSED,
1315 struct wl_keyboard *keyboard UNUSED,
1316 int32_t rate UNUSED,
1317 int32_t delay UNUSED)
1318{
1319}
1320
1321#define VWL_CODE_DATA_OBJECT_DESTROY(type) \
1322do { \
1323 if (type == NULL || type->proxy == NULL) \
1324 return; \
1325 switch (type->protocol) \
1326 { \
1327 case VWL_DATA_PROTOCOL_WLR: \
1328 zwlr_data_control_##type##_v1_destroy(type->proxy); \
1329 break; \
1330 case VWL_DATA_PROTOCOL_EXT: \
1331 ext_data_control_##type##_v1_destroy(type->proxy); \
1332 break; \
1333 case VWL_DATA_PROTOCOL_CORE: \
1334 wl_data_##type##_destroy(type->proxy); \
1335 break; \
1336 case VWL_DATA_PROTOCOL_PRIMARY: \
1337 zwp_primary_selection_##type##_v1_destroy(type->proxy); \
1338 break; \
1339 default: \
1340 break; \
1341 } \
1342 if (alloced) \
1343 vim_free(type); \
1344 else \
1345 type->proxy = NULL; \
1346} while (0)
1347
1348 static void
1349vwl_data_device_destroy(vwl_data_device_T *device, int alloced)
1350{
1351 VWL_CODE_DATA_OBJECT_DESTROY(device);
1352}
1353
1354 static void
1355vwl_data_offer_destroy(vwl_data_offer_T *offer, int alloced)
1356{
1357 VWL_CODE_DATA_OBJECT_DESTROY(offer);
1358}
1359
1360 static void
1361vwl_data_source_destroy(vwl_data_source_T *source, int alloced)
1362{
1363 VWL_CODE_DATA_OBJECT_DESTROY(source);
1364}
1365
1366
1367// Used to pass a vwl_data_offer_T struct from the data_offer event to the offer
1368// event and to the selection event.
1369static vwl_data_offer_T *tmp_vwl_offer;
1370
1371// These functions handle the more complicated data_offer and selection events.
1372
1373 static void
1374vwl_gen_data_device_listener_data_offer(void *data, void *offer_proxy)
1375{
1376 vwl_data_device_T *device = data;
1377
1378 tmp_vwl_offer = alloc(sizeof(*tmp_vwl_offer));
1379
1380 if (tmp_vwl_offer != NULL)
1381 {
1382 tmp_vwl_offer->proxy = offer_proxy;
1383 tmp_vwl_offer->protocol = device->protocol;
1384
1385 vwl_data_device_listener.data_offer(device, tmp_vwl_offer);
1386 }
1387}
1388
1389 static void
1390vwl_gen_data_device_listener_selection(
1391 void *data,
1392 void *offer_proxy,
1393 wayland_selection_T selection,
1394 vwl_data_protocol_T protocol)
1395{
1396 if (tmp_vwl_offer == NULL)
1397 {
1398 // Memory allocation failed or selection cleared (data_offer is never
1399 // sent when selection is cleared/empty).
1400 vwl_data_offer_T tmp = {
1401 .proxy = offer_proxy,
1402 .protocol = protocol
1403 };
1404
1405 vwl_data_offer_destroy(&tmp, FALSE);
1406
1407 // If offer proxy is NULL then we know the selection has been cleared.
1408 if (offer_proxy == NULL)
1409 vwl_data_device_listener.selection(data, NULL, selection);
1410 }
1411 else
1412 {
1413 vwl_data_device_listener.selection(data, tmp_vwl_offer, selection);
1414 tmp_vwl_offer = NULL;
1415 }
1416}
1417
1418// Boilerplate macros. Each just calls its respective generic callback.
1419//
1420#define VWL_FUNC_DATA_DEVICE_DATA_OFFER(device_name, offer_name) \
1421 static void device_name##_listener_data_offer( \
1422 void *data, struct device_name *device_proxy UNUSED, \
1423 struct offer_name *offer_proxy) \
1424{ \
1425 vwl_gen_data_device_listener_data_offer(data, offer_proxy); \
1426}
1427#define VWL_FUNC_DATA_DEVICE_SELECTION( \
1428 device_name, offer_name, type, selection_type, protocol) \
1429 static void device_name##_listener_##type( \
1430 void *data, struct device_name *device_proxy UNUSED, \
1431 struct offer_name *offer_proxy UNUSED) \
1432{ \
1433 vwl_gen_data_device_listener_selection( \
1434 data, offer_proxy, selection_type, protocol); \
1435}
1436#define VWL_FUNC_DATA_DEVICE_FINISHED(device_name) \
1437 static void device_name##_listener_finished( \
1438 void *data, struct device_name *device_proxy UNUSED) \
1439{ \
1440 vwl_data_device_listener.finished(data); \
1441}
1442#define VWL_FUNC_DATA_SOURCE_SEND(source_name) \
1443 static void source_name##_listener_send(void *data, \
1444 struct source_name *source_proxy UNUSED, \
1445 const char *mime_type, int fd) \
1446{ \
1447 vwl_data_source_listener.send(data, mime_type, fd); \
1448}
1449#define VWL_FUNC_DATA_SOURCE_CANCELLED(source_name) \
1450 static void source_name##_listener_cancelled(void *data, \
1451 struct source_name *source_proxy UNUSED) \
1452{ \
1453 vwl_data_source_listener.cancelled(data); \
1454}
1455#define VWL_FUNC_DATA_OFFER_OFFER(offer_name) \
1456 static void offer_name##_listener_offer(void *data, \
1457 struct offer_name *offer_proxy UNUSED, \
1458 const char *mime_type) \
1459{ \
1460 vwl_data_offer_listener.offer(data, mime_type); \
1461}
1462
1463VWL_FUNC_DATA_DEVICE_DATA_OFFER(
1464 ext_data_control_device_v1, ext_data_control_offer_v1)
1465VWL_FUNC_DATA_DEVICE_DATA_OFFER(
1466 zwlr_data_control_device_v1, zwlr_data_control_offer_v1)
1467VWL_FUNC_DATA_DEVICE_DATA_OFFER(wl_data_device, wl_data_offer)
1468VWL_FUNC_DATA_DEVICE_DATA_OFFER(
1469 zwp_primary_selection_device_v1, zwp_primary_selection_offer_v1)
1470
1471VWL_FUNC_DATA_DEVICE_SELECTION(
1472 ext_data_control_device_v1, ext_data_control_offer_v1,
1473 selection, WAYLAND_SELECTION_REGULAR, VWL_DATA_PROTOCOL_EXT)
1474VWL_FUNC_DATA_DEVICE_SELECTION(
1475 zwlr_data_control_device_v1, zwlr_data_control_offer_v1,
1476 selection, WAYLAND_SELECTION_REGULAR, VWL_DATA_PROTOCOL_WLR)
1477VWL_FUNC_DATA_DEVICE_SELECTION(
1478 wl_data_device, wl_data_offer, selection,
1479 WAYLAND_SELECTION_REGULAR, VWL_DATA_PROTOCOL_CORE)
1480
1481VWL_FUNC_DATA_DEVICE_SELECTION(
1482 ext_data_control_device_v1, ext_data_control_offer_v1,
1483 primary_selection, WAYLAND_SELECTION_PRIMARY, VWL_DATA_PROTOCOL_EXT)
1484VWL_FUNC_DATA_DEVICE_SELECTION(
1485 zwlr_data_control_device_v1, zwlr_data_control_offer_v1,
1486 primary_selection, WAYLAND_SELECTION_PRIMARY, VWL_DATA_PROTOCOL_WLR)
1487VWL_FUNC_DATA_DEVICE_SELECTION(
1488 zwp_primary_selection_device_v1, zwp_primary_selection_offer_v1,
1489 primary_selection, WAYLAND_SELECTION_PRIMARY, VWL_DATA_PROTOCOL_PRIMARY)
1490
1491VWL_FUNC_DATA_DEVICE_FINISHED(ext_data_control_device_v1)
1492VWL_FUNC_DATA_DEVICE_FINISHED(zwlr_data_control_device_v1)
1493
1494VWL_FUNC_DATA_SOURCE_SEND(ext_data_control_source_v1)
1495VWL_FUNC_DATA_SOURCE_SEND(zwlr_data_control_source_v1)
1496VWL_FUNC_DATA_SOURCE_SEND(wl_data_source)
1497VWL_FUNC_DATA_SOURCE_SEND(zwp_primary_selection_source_v1)
1498
1499VWL_FUNC_DATA_SOURCE_CANCELLED(ext_data_control_source_v1)
1500VWL_FUNC_DATA_SOURCE_CANCELLED(zwlr_data_control_source_v1)
1501VWL_FUNC_DATA_SOURCE_CANCELLED(wl_data_source)
1502VWL_FUNC_DATA_SOURCE_CANCELLED(zwp_primary_selection_source_v1)
1503
1504VWL_FUNC_DATA_OFFER_OFFER(ext_data_control_offer_v1)
1505VWL_FUNC_DATA_OFFER_OFFER(zwlr_data_control_offer_v1)
1506VWL_FUNC_DATA_OFFER_OFFER(wl_data_offer)
1507VWL_FUNC_DATA_OFFER_OFFER(zwp_primary_selection_offer_v1)
1508
1509// Listener handlers
1510
1511// DATA DEVICES
1512struct zwlr_data_control_device_v1_listener
1513zwlr_data_control_device_v1_listener = {
1514 .data_offer = zwlr_data_control_device_v1_listener_data_offer,
1515 .selection = zwlr_data_control_device_v1_listener_selection,
1516 .primary_selection = zwlr_data_control_device_v1_listener_primary_selection,
1517 .finished = zwlr_data_control_device_v1_listener_finished
1518};
1519
1520struct ext_data_control_device_v1_listener
1521ext_data_control_device_v1_listener = {
1522 .data_offer = ext_data_control_device_v1_listener_data_offer,
1523 .selection = ext_data_control_device_v1_listener_selection,
1524 .primary_selection = ext_data_control_device_v1_listener_primary_selection,
1525 .finished = ext_data_control_device_v1_listener_finished
1526};
1527
1528struct wl_data_device_listener wl_data_device_listener = {
1529 .data_offer = wl_data_device_listener_data_offer,
1530 .selection = wl_data_device_listener_selection,
1531};
1532
1533struct zwp_primary_selection_device_v1_listener
1534zwp_primary_selection_device_v1_listener = {
1535 .selection = zwp_primary_selection_device_v1_listener_primary_selection,
1536 .data_offer = zwp_primary_selection_device_v1_listener_data_offer
1537};
1538
1539// DATA SOURCES
1540struct zwlr_data_control_source_v1_listener
1541zwlr_data_control_source_v1_listener = {
1542 .send = zwlr_data_control_source_v1_listener_send,
1543 .cancelled = zwlr_data_control_source_v1_listener_cancelled
1544};
1545
1546struct ext_data_control_source_v1_listener
1547ext_data_control_source_v1_listener = {
1548 .send = ext_data_control_source_v1_listener_send,
1549 .cancelled = ext_data_control_source_v1_listener_cancelled
1550};
1551
1552struct wl_data_source_listener wl_data_source_listener = {
1553 .send = wl_data_source_listener_send,
1554 .cancelled = wl_data_source_listener_cancelled
1555};
1556
1557struct zwp_primary_selection_source_v1_listener
1558zwp_primary_selection_source_v1_listener = {
1559 .send = zwp_primary_selection_source_v1_listener_send,
1560 .cancelled = zwp_primary_selection_source_v1_listener_cancelled,
1561};
1562
1563// OFFERS
1564struct zwlr_data_control_offer_v1_listener
1565zwlr_data_control_offer_v1_listener = {
1566 .offer = zwlr_data_control_offer_v1_listener_offer
1567};
1568
1569struct ext_data_control_offer_v1_listener
1570ext_data_control_offer_v1_listener = {
1571 .offer = ext_data_control_offer_v1_listener_offer
1572};
1573
1574struct wl_data_offer_listener wl_data_offer_listener = {
1575 .offer = wl_data_offer_listener_offer
1576};
1577
1578struct zwp_primary_selection_offer_v1_listener
1579zwp_primary_selection_offer_v1_listener = {
1580 .offer = zwp_primary_selection_offer_v1_listener_offer
1581};
1582
1583// `type` is also used as the user data
1584#define VWL_CODE_DATA_OBJECT_ADD_LISTENER(type) \
1585do { \
1586 if (type->proxy == NULL) \
1587 return; \
1588 type->data = data; \
1589 switch (type->protocol) \
1590 { \
1591 case VWL_DATA_PROTOCOL_WLR: \
1592 zwlr_data_control_##type##_v1_add_listener( type->proxy, \
1593 &zwlr_data_control_##type##_v1_listener, type); \
1594 break; \
1595 case VWL_DATA_PROTOCOL_EXT: \
1596 ext_data_control_##type##_v1_add_listener(type->proxy, \
1597 &ext_data_control_##type##_v1_listener, type); \
1598 break; \
1599 case VWL_DATA_PROTOCOL_CORE: \
1600 wl_data_##type##_add_listener(type->proxy, \
1601 &wl_data_##type##_listener, type); \
1602 break; \
1603 case VWL_DATA_PROTOCOL_PRIMARY: \
1604 zwp_primary_selection_##type##_v1_add_listener(type->proxy, \
1605 &zwp_primary_selection_##type##_v1_listener, type); \
1606 break; \
1607 default: \
1608 break; \
1609 } \
1610} while (0)
1611
1612 static void
1613vwl_data_device_add_listener(vwl_data_device_T *device, void *data)
1614{
1615 VWL_CODE_DATA_OBJECT_ADD_LISTENER(device);
1616}
1617
1618 static void
1619vwl_data_source_add_listener(vwl_data_source_T *source, void *data)
1620{
1621 VWL_CODE_DATA_OBJECT_ADD_LISTENER(source);
1622}
1623
1624 static void
1625vwl_data_offer_add_listener(vwl_data_offer_T *offer, void *data)
1626{
1627 VWL_CODE_DATA_OBJECT_ADD_LISTENER(offer);
1628}
1629
1630/*
1631 * Sets the selection using the given data device with the given selection. If
1632 * the device does not support the selection then nothing happens. For data
1633 * control protocols the serial argument is ignored.
1634 */
1635 static void
1636vwl_data_device_set_selection(
1637 vwl_data_device_T *device,
1638 vwl_data_source_T *source,
1639 uint32_t serial,
1640 wayland_selection_T selection)
1641{
1642 if (selection == WAYLAND_SELECTION_REGULAR)
1643 {
1644 switch (device->protocol)
1645 {
1646 case VWL_DATA_PROTOCOL_WLR:
1647 zwlr_data_control_device_v1_set_selection(
1648 device->proxy, source->proxy);
1649 break;
1650 case VWL_DATA_PROTOCOL_EXT:
1651 ext_data_control_device_v1_set_selection(
1652 device->proxy, source->proxy);
1653 break;
1654 case VWL_DATA_PROTOCOL_CORE:
1655 wl_data_device_set_selection(
1656 device->proxy, source->proxy, serial);
1657 break;
1658 default:
1659 break;
1660 }
1661 }
1662 else if (selection == WAYLAND_SELECTION_PRIMARY)
1663 {
1664 switch (device->protocol)
1665 {
1666 case VWL_DATA_PROTOCOL_WLR:
1667 zwlr_data_control_device_v1_set_primary_selection(
1668 device->proxy, source->proxy);
1669 break;
1670 case VWL_DATA_PROTOCOL_EXT:
1671 ext_data_control_device_v1_set_primary_selection(
1672 device->proxy, source->proxy);
1673 break;
1674 case VWL_DATA_PROTOCOL_PRIMARY:
1675 zwp_primary_selection_device_v1_set_selection(
1676 device->proxy, source->proxy, serial);
1677 break;
1678 default:
1679 break;
1680 }
1681 }
1682}
1683
1684/*
1685 * Start receiving data from offer object, which sends the given fd to the
1686 * source client to write into.
1687 */
1688 static void
1689vwl_data_offer_receive(vwl_data_offer_T *offer, const char *mime_type, int fd)
1690{
1691 switch (offer->protocol)
1692 {
1693 case VWL_DATA_PROTOCOL_WLR:
1694 zwlr_data_control_offer_v1_receive(offer->proxy, mime_type, fd);
1695 break;
1696 case VWL_DATA_PROTOCOL_EXT:
1697 ext_data_control_offer_v1_receive(offer->proxy, mime_type, fd);
1698 break;
1699 case VWL_DATA_PROTOCOL_CORE:
1700 wl_data_offer_receive(offer->proxy, mime_type, fd);
1701 break;
1702 case VWL_DATA_PROTOCOL_PRIMARY:
1703 zwp_primary_selection_offer_v1_receive(offer->proxy, mime_type, fd);
1704 break;
1705 default:
1706 break;
1707 }
1708}
1709
1710#define SET_MANAGER(manager_name, protocol_enum, focus) \
1711 do { \
1712 manager->proxy = vwl_gobjects.manager_name; \
1713 manager->protocol = protocol_enum; \
1714 return focus; \
1715 } while (0)
1716
1717/*
1718 * Get a data device manager that supports the given selection. If none if found
1719 * then the manager protocol is set to VWL_DATA_PROTOCOL_NONE. TRUE is returned
1720 * if the given data device manager requires focus to work else FALSE.
1721 */
1722 static int
1723vwl_get_data_device_manager(
1724 vwl_data_device_manager_T *manager,
1725 wayland_selection_T selection)
1726{
1727 // Prioritize data control protocols first then try using the focus steal
1728 // method with the core protocol data objects.
1729 if (force_fs)
1730 goto focus_steal;
1731
1732 // Ext data control protocol supports both selections, try it first
1733 if (vwl_gobjects.ext_data_control_manager_v1 != NULL)
1734 SET_MANAGER(ext_data_control_manager_v1, VWL_DATA_PROTOCOL_EXT, FALSE);
1735 if (vwl_gobjects.zwlr_data_control_manager_v1 != NULL)
1736 {
1737 int ver = zwlr_data_control_manager_v1_get_version(
1738 vwl_gobjects.zwlr_data_control_manager_v1);
1739
1740 // version 2 or greater supports the primary selection
1741 if ((selection == WAYLAND_SELECTION_PRIMARY && ver >= 2)
1742 || selection == WAYLAND_SELECTION_REGULAR)
1743 SET_MANAGER(zwlr_data_control_manager_v1,
1744 VWL_DATA_PROTOCOL_WLR, FALSE);
1745 }
1746
1747focus_steal:
1748 if (vwl_focus_stealing_available())
1749 {
1750 if (vwl_gobjects.wl_data_device_manager != NULL
1751 && selection == WAYLAND_SELECTION_REGULAR)
1752 SET_MANAGER(wl_data_device_manager, VWL_DATA_PROTOCOL_CORE, TRUE);
1753
1754 else if (vwl_gobjects.zwp_primary_selection_device_manager_v1 != NULL
1755 && selection == WAYLAND_SELECTION_PRIMARY)
1756 SET_MANAGER(zwp_primary_selection_device_manager_v1,
1757 VWL_DATA_PROTOCOL_PRIMARY, TRUE);
1758 }
1759
1760 manager->protocol = VWL_DATA_PROTOCOL_NONE;
1761
1762 return FALSE;
1763}
1764
1765/*
1766 * Get a data device that manages the given seat's selection.
1767 */
1768 static void
1769vwl_get_data_device(
1770 vwl_data_device_manager_T *manager,
1771 vwl_seat_T *seat,
1772 vwl_data_device_T *device)
1773{
1774 switch (manager->protocol)
1775 {
1776 case VWL_DATA_PROTOCOL_WLR:
1777 device->proxy =
1778 zwlr_data_control_manager_v1_get_data_device(
1779 manager->proxy, seat->proxy);
1780 break;
1781 case VWL_DATA_PROTOCOL_EXT:
1782 device->proxy =
1783 ext_data_control_manager_v1_get_data_device(
1784 manager->proxy, seat->proxy);
1785 break;
1786 case VWL_DATA_PROTOCOL_CORE:
1787 device->proxy = wl_data_device_manager_get_data_device(
1788 manager->proxy, seat->proxy);
1789 break;
1790 case VWL_DATA_PROTOCOL_PRIMARY:
1791 device->proxy = zwp_primary_selection_device_manager_v1_get_device(
1792 manager->proxy, seat->proxy);
1793 break;
1794 default:
1795 device->protocol = VWL_DATA_PROTOCOL_NONE;
1796 return;
1797 }
1798 device->protocol = manager->protocol;
1799}
1800
1801/*
1802 * Create a data source
1803 */
1804 static void
1805vwl_create_data_source(
1806 vwl_data_device_manager_T *manager,
1807 vwl_data_source_T *source)
1808{
1809 switch (manager->protocol)
1810 {
1811 case VWL_DATA_PROTOCOL_WLR:
1812 source->proxy =
1813 zwlr_data_control_manager_v1_create_data_source(manager->proxy);
1814 break;
1815 case VWL_DATA_PROTOCOL_EXT:
1816 source->proxy =
1817 ext_data_control_manager_v1_create_data_source(manager->proxy);
1818 break;
1819 case VWL_DATA_PROTOCOL_CORE:
1820 source->proxy =
1821 wl_data_device_manager_create_data_source(manager->proxy);
1822 break;
1823 case VWL_DATA_PROTOCOL_PRIMARY:
1824 source->proxy =
1825 zwp_primary_selection_device_manager_v1_create_source(
1826 manager->proxy);
1827 break;
1828 default:
1829 source->protocol = VWL_DATA_PROTOCOL_NONE;
1830 return;
1831 }
1832 source->protocol = manager->protocol;
1833}
1834
1835/*
1836 * Offer a new mime type to be advertised by us to other clients.
1837 */
1838 static void
1839vwl_data_source_offer(vwl_data_source_T *source, const char *mime_type)
1840{
1841 switch (source->protocol)
1842 {
1843 case VWL_DATA_PROTOCOL_WLR:
1844 zwlr_data_control_source_v1_offer(source->proxy, mime_type);
1845 break;
1846 case VWL_DATA_PROTOCOL_EXT:
1847 ext_data_control_source_v1_offer(source->proxy, mime_type);
1848 break;
1849 case VWL_DATA_PROTOCOL_CORE:
1850 wl_data_source_offer(source->proxy, mime_type);
1851 break;
1852 case VWL_DATA_PROTOCOL_PRIMARY:
1853 zwp_primary_selection_source_v1_offer(source->proxy, mime_type);
1854 break;
1855 default:
1856 break;
1857 }
1858}
1859
1860/*
1861 * Free the mime types grow arrays in the given clip_sel struct.
1862 */
1863 static void
1864vwl_clipboard_free_mime_types(vwl_clipboard_selection_T *clip_sel)
1865{
1866 // Don't want to be double freeing
1867 if (clip_sel->mime_types.ga_data == clip_sel->tmp_mime_types.ga_data)
1868 {
1869 ga_clear_strings(&clip_sel->mime_types);
1870 ga_init(&vwl_clipboard.primary.tmp_mime_types);
1871 }
1872 else
1873 {
1874 ga_clear_strings(&clip_sel->mime_types);
1875 ga_clear_strings(&clip_sel->tmp_mime_types);
1876 }
1877}
1878
1879/*
Hirohito Higashi73b96502025-06-28 18:18:21 +02001880 * Setup required objects to interact with Wayland selections/clipboard on given
Foxe Chenb90c2392025-06-27 21:10:35 +02001881 * seat. Returns OK on success and FAIL on failure.
1882 */
1883 int
1884wayland_cb_init(const char *seat)
1885{
1886 vwl_clipboard.seat = vwl_get_seat(seat);
1887
1888 if (vwl_clipboard.seat == NULL)
1889 return FAIL;
1890
1891 // Get data device managers for each selection. If there wasn't any manager
1892 // that could be found that supports the given selection, then it will be
1893 // unavailable.
1894 vwl_clipboard.regular.requires_focus = vwl_get_data_device_manager(
1895 &vwl_clipboard.regular.manager,
1896 WAYLAND_SELECTION_REGULAR);
1897 vwl_clipboard.primary.requires_focus = vwl_get_data_device_manager(
1898 &vwl_clipboard.primary.manager,
1899 WAYLAND_SELECTION_PRIMARY);
1900
1901 // Initialize shm pool and buffer if core data protocol is available
1902 if (vwl_focus_stealing_available() &&
1903 (vwl_clipboard.regular.requires_focus ||
1904 vwl_clipboard.primary.requires_focus))
1905 vwl_clipboard.fs_buffer = vwl_init_buffer_store(1, 1);
1906
1907 // Get data devices for each selection. If one of the above function calls
1908 // results in an unavailable manager, then the device coming from it will
1909 // have its protocol set to VWL_DATA_PROTOCOL_NONE.
1910 vwl_get_data_device(
1911 &vwl_clipboard.regular.manager,
1912 vwl_clipboard.seat,
1913 &vwl_clipboard.regular.device);
1914 vwl_get_data_device(
1915 &vwl_clipboard.primary.manager,
1916 vwl_clipboard.seat,
1917 &vwl_clipboard.primary.device);
1918
1919 // Initialize grow arrays for the offer mime types.
1920 // I find most applications to have below 10 mime types that they offer.
1921 ga_init2(&vwl_clipboard.regular.tmp_mime_types, sizeof(char*), 10);
1922 ga_init2(&vwl_clipboard.primary.tmp_mime_types, sizeof(char*), 10);
1923
1924 // We dont need to use ga_init2 because tmp_mime_types will be copied over
1925 // to mime_types anyways.
1926 ga_init(&vwl_clipboard.regular.mime_types);
1927 ga_init(&vwl_clipboard.primary.mime_types);
1928
1929 // Start listening for data offers/new selections. Don't do anything when we
1930 // get a new data offer other than saving the mime types and saving the data
1931 // offer. Then when we want the data we use the saved data offer to receive
1932 // data from it along with the saved mime_types. For each new selection just
1933 // destroy the previous offer/free mime_types, if any.
1934 vwl_data_device_add_listener(
1935 &vwl_clipboard.regular.device,
1936 &vwl_clipboard.regular);
1937 vwl_data_device_add_listener(
1938 &vwl_clipboard.primary.device,
1939 &vwl_clipboard.primary);
1940
1941 if (vwl_display_roundtrip(&vwl_display) == FAIL)
1942 {
1943 wayland_cb_uninit();
1944 return FAIL;
1945 }
1946 clip_init(TRUE);
1947
1948 return OK;
1949}
1950
1951/*
1952 * Free up resources used for Wayland selections. Does not destroy global
1953 * objects such as data device managers.
1954 */
1955 void
1956wayland_cb_uninit(void)
1957{
1958 if (vwl_clipboard.fs_buffer != NULL)
1959 {
1960 vwl_destroy_buffer_store(vwl_clipboard.fs_buffer);
1961 vwl_clipboard.fs_buffer = NULL;
1962 }
1963
1964 // Destroy the current offer if it exists
1965 vwl_data_offer_destroy(vwl_clipboard.regular.offer, TRUE);
1966 vwl_data_offer_destroy(vwl_clipboard.primary.offer, TRUE);
1967
1968 // Destroy any devices or sources
1969 vwl_data_device_destroy(&vwl_clipboard.regular.device, FALSE);
1970 vwl_data_device_destroy(&vwl_clipboard.primary.device, FALSE);
1971 vwl_data_source_destroy(&vwl_clipboard.regular.source, FALSE);
1972 vwl_data_source_destroy(&vwl_clipboard.primary.source, FALSE);
1973
1974 // Free mime types
1975 vwl_clipboard_free_mime_types(&vwl_clipboard.regular);
1976 vwl_clipboard_free_mime_types(&vwl_clipboard.primary);
1977
1978 vwl_display_flush(&vwl_display);
1979
1980 vim_memset(&vwl_clipboard, 0, sizeof(vwl_clipboard));
1981 vwl_clipboard.regular.selection = WAYLAND_SELECTION_REGULAR;
1982 vwl_clipboard.primary.selection = WAYLAND_SELECTION_PRIMARY;
1983}
1984
1985/*
1986 * If the given selection can be used.
1987 */
1988 static int
1989vwl_clipboard_selection_is_ready(vwl_clipboard_selection_T *clip_sel)
1990{
1991 return clip_sel->manager.protocol != VWL_DATA_PROTOCOL_NONE &&
1992 clip_sel->device.protocol != VWL_DATA_PROTOCOL_NONE;
1993}
1994
1995/*
1996 * Callback for data offer event. Start listening to the given offer immediately
1997 * in order to get mime types.
1998 */
1999 static void
2000vwl_data_device_listener_data_offer(
2001 vwl_data_device_T *device,
2002 vwl_data_offer_T *offer)
2003{
2004 vwl_clipboard_selection_T *clip_sel = device->data;
2005
2006 // Get mime types and save them so we can use them when we want to paste the
2007 // selection.
2008 if (clip_sel->source.proxy != NULL)
2009 // We own the selection, no point in getting mime types
2010 return;
2011
2012 vwl_data_offer_add_listener(offer, device->data);
2013}
2014
2015/*
2016 * Callback for offer event. Save each mime type given to be used later.
2017 */
2018 static void
2019vwl_data_offer_listener_offer(vwl_data_offer_T *offer, const char *mime_type)
2020{
2021 vwl_clipboard_selection_T *clip_sel = offer->data;
2022
2023 // Save string into temporary grow array, which will be finalized into the
2024 // actual grow array if the selection matches with the selection that the
2025 // device manages.
2026 ga_copy_string(&clip_sel->tmp_mime_types, (char_u*)mime_type);
2027}
2028
2029/*
2030 * Callback for selection event, for either the regular or primary selection.
2031 * Don't try receiving data from the offer, instead destroy the previous offer
2032 * if any and set the current offer to the given offer, along with the
2033 * respective mime types.
2034 */
2035 static void
2036vwl_data_device_listener_selection(
2037 vwl_data_device_T *device UNUSED,
2038 vwl_data_offer_T *offer,
2039 wayland_selection_T selection)
2040{
2041 vwl_clipboard_selection_T *clip_sel = device->data;
2042 vwl_data_offer_T *prev_offer = clip_sel->offer;
2043
2044 // Save offer if it selection and clip_sel match, else discard it
2045 if (clip_sel->selection == selection)
2046 clip_sel->offer = offer;
2047 else
2048 {
2049 // Example: selection event is for the primary selection but this device
2050 // is only for the regular selection, if so then just discard the offer
2051 // and tmp_mime_types.
2052 vwl_data_offer_destroy(offer, TRUE);
2053 tmp_vwl_offer = NULL;
2054 ga_clear_strings(&clip_sel->tmp_mime_types);
2055 return;
2056 }
2057
2058 // There are two cases when clip_sel->offer is NULL
2059 // 1. No one owns the selection
2060 // 2. We own the selection (we'll just access the register directly)
2061 if (offer == NULL)
2062 {
2063 // Selection cleared/empty
2064 ga_clear_strings(&clip_sel->tmp_mime_types);
2065 clip_sel->offer = NULL;
2066 goto exit;
2067 }
2068 else if (clip_sel->source.proxy != NULL)
2069 {
2070 // We own the selection, ignore it
2071 vwl_data_offer_destroy(offer, TRUE);
2072 ga_clear_strings(&clip_sel->tmp_mime_types);
2073 clip_sel->offer = NULL;
2074 goto exit;
2075 }
2076
2077exit:
2078 // Destroy previous offer if any
2079 vwl_data_offer_destroy(prev_offer, TRUE);
2080 ga_clear_strings(&clip_sel->mime_types);
2081
2082 // Copy the grow array over
2083 clip_sel->mime_types = clip_sel->tmp_mime_types;
2084
2085 // Clear tmp_mime_types so next data_offer doesn't try to resize/grow it
2086 // (Don't free it though using ga_clear() because mime_types->ga_data is the
2087 // same pointer)r
2088 if (clip_sel->offer != NULL)
2089 ga_init(&clip_sel->tmp_mime_types);
2090}
2091
2092/*
2093 * Callback for finished event. Destroy device and all related objects/resources
2094 * such as offers and mime types.
2095 */
2096 static void
2097vwl_data_device_listener_finished(vwl_data_device_T *device)
2098{
2099 vwl_clipboard_selection_T *clip_sel = device->data;
2100
2101 vwl_data_device_destroy(device, FALSE);
2102 vwl_data_offer_destroy(clip_sel->offer, TRUE);
2103 vwl_data_source_destroy(&clip_sel->source, FALSE);
2104 vwl_clipboard_free_mime_types(clip_sel);
2105}
2106
2107/*
2108 * Return a pointer to a grow array of mime types that the current offer
2109 * supports sending. If the returned garray has NULL for ga_data or a ga_len of
2110 * 0, then the selection is cleared. If focus stealing is required, a surface
2111 * will be created to steal focus first.
2112 */
2113 garray_T *
2114wayland_cb_get_mime_types(wayland_selection_T selection)
2115{
2116 vwl_clipboard_selection_T *clip_sel;
2117
2118 if (selection == WAYLAND_SELECTION_REGULAR)
2119 clip_sel = &vwl_clipboard.regular;
2120 else if (selection == WAYLAND_SELECTION_PRIMARY)
2121 clip_sel = &vwl_clipboard.primary;
2122 else
2123 return NULL;
2124
2125 if (clip_sel->requires_focus)
2126 {
2127 // We don't care about the on_focus callback since once we gain focus
2128 // the data offer events will come immediately.
2129 if (vwl_init_fs_surface(vwl_clipboard.seat,
2130 vwl_clipboard.fs_buffer, NULL, NULL) == FAIL)
2131 return NULL;
2132 }
2133 else if (vwl_display_roundtrip(&vwl_display) == FAIL)
2134 return NULL;
2135
2136 return &clip_sel->mime_types;
2137}
2138
2139/*
2140 * Receive data from the given selection, and return the fd to read data from.
2141 * On failure -1 is returned.
2142 */
2143 int
2144wayland_cb_receive_data(const char *mime_type, wayland_selection_T selection)
2145{
2146 vwl_clipboard_selection_T *clip_sel;
2147
2148 // Create pipe that source client will write to
2149 int fds[2];
2150
2151 if (selection == WAYLAND_SELECTION_REGULAR)
2152 clip_sel = &vwl_clipboard.regular;
2153 else if (selection == WAYLAND_SELECTION_PRIMARY)
2154 clip_sel = &vwl_clipboard.primary;
2155 else
2156 return -1;
2157
2158 if (!wayland_client_is_connected(FALSE) ||
2159 !vwl_clipboard_selection_is_ready(clip_sel))
2160 return -1;
2161
2162 if (clip_sel->offer == NULL || clip_sel->offer->proxy == NULL)
2163 return -1;
2164
2165 if (pipe(fds) == -1)
2166 return -1;
2167
2168 vwl_data_offer_receive(clip_sel->offer, mime_type, fds[1]);
2169
2170 close(fds[1]); // Close before we read data so that when the source client
2171 // closes their end we receive an EOF.
2172
2173 if (vwl_display_flush(&vwl_display) == OK)
2174 return fds[0];
2175
2176 close(fds[0]);
2177
2178 return -1;
2179}
2180
2181/*
2182 * Callback for send event. Just call the user callback which will handle it
2183 * and do the writing stuff.
2184 */
2185 static void
2186vwl_data_source_listener_send(
2187 vwl_data_source_T *source,
2188 const char *mime_type,
2189 int32_t fd)
2190{
2191 vwl_clipboard_selection_T *clip_sel = source->data;
2192
2193 if (clip_sel->send_cb != NULL)
2194 clip_sel->send_cb(mime_type, fd, clip_sel->selection);
2195 close(fd);
2196}
2197
2198/*
2199 * Callback for cancelled event, just call the user callback.
2200 */
2201 static void
2202vwl_data_source_listener_cancelled(vwl_data_source_T *source)
2203{
2204 vwl_clipboard_selection_T *clip_sel = source->data;
2205
2206 if (clip_sel->send_cb != NULL)
2207 clip_sel->cancelled_cb(clip_sel->selection);
2208 vwl_data_source_destroy(source, FALSE);
2209}
2210
2211/*
2212 * Set the selection when we gain focus
2213 */
2214 static void
2215vwl_on_focus_set_selection(void *data, uint32_t serial)
2216{
2217 vwl_clipboard_selection_T *clip_sel = data;
2218
2219 vwl_data_device_set_selection(
2220 &clip_sel->device,
2221 &clip_sel->source,
2222 serial,
2223 clip_sel->selection);
2224 vwl_display_roundtrip(&vwl_display);
2225}
2226
2227/*
2228 * Become the given selection's owner, and advertise to other clients the mime
2229 * types found in mime_types array. Returns FAIL on failure and OK on success.
2230 */
2231 int
2232wayland_cb_own_selection(
2233 wayland_cb_send_data_func_T send_cb,
2234 wayland_cb_selection_cancelled_func_T cancelled_cb,
2235 const char **mime_types,
2236 int len,
2237 wayland_selection_T selection)
2238{
2239 vwl_clipboard_selection_T *clip_sel;
2240
2241 if (selection == WAYLAND_SELECTION_REGULAR)
2242 clip_sel = &vwl_clipboard.regular;
2243 else if (selection == WAYLAND_SELECTION_PRIMARY)
2244 clip_sel = &vwl_clipboard.primary;
2245 else
2246 return FAIL;
2247
2248 if (clip_sel->source.proxy != NULL)
2249 // We already own the selection
2250 return OK;
2251
2252 if (!wayland_client_is_connected(FALSE) ||
2253 !vwl_clipboard_selection_is_ready(clip_sel))
2254 return FAIL;
2255
2256 clip_sel->send_cb = send_cb;
2257 clip_sel->cancelled_cb = cancelled_cb;
2258
2259 vwl_create_data_source(&clip_sel->manager, &clip_sel->source);
2260
2261 vwl_data_source_add_listener(&clip_sel->source, clip_sel);
2262
2263 // Advertise mime types
2264 for (int i = 0; i < len; i++)
2265 vwl_data_source_offer(&clip_sel->source, mime_types[i]);
2266
2267 if (clip_sel->requires_focus)
2268 {
2269 // Call set_selection later when we gain focus
2270 if (vwl_init_fs_surface(vwl_clipboard.seat, vwl_clipboard.fs_buffer,
2271 vwl_on_focus_set_selection, clip_sel) == FAIL)
2272 goto fail;
2273 }
2274 else
2275 {
2276 vwl_data_device_set_selection(&clip_sel->device,
2277 &clip_sel->source, 0, selection);
2278 if (vwl_display_roundtrip(&vwl_display) == FAIL)
2279 goto fail;
2280 }
2281
2282 return OK;
2283fail:
2284 vwl_data_source_destroy(&clip_sel->source, FALSE);
2285 return FAIL;
2286}
2287
2288/*
2289 * Disown the given selection, so that we are not the source client that other
2290 * clients receive data from.
2291 */
2292 void
2293wayland_cb_lose_selection(wayland_selection_T selection)
2294{
2295 if (selection == WAYLAND_SELECTION_REGULAR)
2296 vwl_data_source_destroy(&vwl_clipboard.regular.source, FALSE);
2297 else if (selection == WAYLAND_SELECTION_PRIMARY)
2298 vwl_data_source_destroy(&vwl_clipboard.primary.source, FALSE);
2299 vwl_display_flush(&vwl_display);
2300}
2301
2302/*
2303 * Return TRUE if the selection is owned by either us or another client.
2304 */
2305 int
2306wayland_cb_selection_is_owned(wayland_selection_T selection)
2307{
2308 vwl_display_roundtrip(&vwl_display);
2309
2310 if (selection == WAYLAND_SELECTION_REGULAR)
2311 return vwl_clipboard.regular.source.proxy != NULL
2312 || vwl_clipboard.regular.offer != NULL;
2313 else if (selection == WAYLAND_SELECTION_PRIMARY)
2314 return vwl_clipboard.primary.source.proxy != NULL
2315 || vwl_clipboard.primary.offer != NULL;
2316 else
2317 return FALSE;
2318}
2319
2320/*
Hirohito Higashi73b96502025-06-28 18:18:21 +02002321 * Return TRUE if the Wayland clipboard/selections are ready to use.
Foxe Chenb90c2392025-06-27 21:10:35 +02002322 */
2323 int
2324wayland_cb_is_ready(void)
2325{
2326 vwl_display_roundtrip(&vwl_display);
2327
2328 // Clipboard is ready if we have at least one selection available
2329 return wayland_client_is_connected(TRUE) &&
2330 (vwl_clipboard_selection_is_ready(&vwl_clipboard.regular) ||
2331 vwl_clipboard_selection_is_ready(&vwl_clipboard.primary));
2332}
2333
2334/*
Hirohito Higashi73b96502025-06-28 18:18:21 +02002335 * Reload Wayland clipboard, useful if changing seat.
Foxe Chenb90c2392025-06-27 21:10:35 +02002336 */
2337 int
2338wayland_cb_reload(void)
2339{
2340 // Lose any selections we own
2341 if (clipmethod == CLIPMETHOD_WAYLAND)
2342 {
2343 if (clip_star.owned)
2344 clip_lose_selection(&clip_star);
2345 if (clip_plus.owned)
2346 clip_lose_selection(&clip_plus);
2347 }
2348
2349 wayland_cb_uninit();
2350
2351 if (wayland_cb_init((char*)p_wse) == FAIL)
2352 return FAIL;
2353
2354 choose_clipmethod();
2355 return OK;
2356}
2357
2358#endif // FEAT_WAYLAND_CLIPBOARD
2359
2360static int wayland_ct_restore_count = 0;
2361
2362/*
2363 * Attempts to restore the Wayland display connection. Returns OK if display
2364 * connection was/is now valid, else FAIL if the display connection is invalid.
2365 */
2366 int
2367wayland_may_restore_connection(void)
2368{
2369 // No point if we still are already connected properly
2370 if (wayland_client_is_connected(TRUE))
2371 return OK;
2372
2373 // No point in restoring the connection if we are exiting or dying.
2374 if (exiting || v_dying || wayland_ct_restore_count <= 0)
2375 {
2376 wayland_set_display("");
2377 return FAIL;
2378 }
2379
2380 --wayland_ct_restore_count;
2381 wayland_uninit_client();
2382
2383 return wayland_init_client(wayland_display_name);
2384}
2385
2386/*
Hirohito Higashi73b96502025-06-28 18:18:21 +02002387 * Disconnect then reconnect Wayland connection, and update clipmethod.
Foxe Chenb90c2392025-06-27 21:10:35 +02002388 */
2389 void
2390ex_wlrestore(exarg_T *eap)
2391{
2392 char *display;
2393
2394 if (eap->arg == NULL || STRLEN(eap->arg) == 0)
2395 // Use current display name if none given
2396 display = wayland_display_name;
2397 else
2398 display = (char*)eap->arg;
2399
2400 // Return early if shebang is not passed, we are still connected, and if not
Hirohito Higashi73b96502025-06-28 18:18:21 +02002401 // changing to a new Wayland display.
Foxe Chenb90c2392025-06-27 21:10:35 +02002402 if (!eap->forceit && wayland_client_is_connected(TRUE) &&
2403 (display == wayland_display_name ||
2404 (wayland_display_name != NULL &&
2405 STRCMP(wayland_display_name, display) == 0)))
2406 return;
2407
2408#ifdef FEAT_WAYLAND_CLIPBOARD
2409 if (clipmethod == CLIPMETHOD_WAYLAND)
2410 {
2411 // Lose any selections we own
2412 if (clip_star.owned)
2413 clip_lose_selection(&clip_star);
2414 if (clip_plus.owned)
2415 clip_lose_selection(&clip_plus);
2416 }
2417#endif
2418
2419
2420 if (display != NULL)
2421 display = (char*)vim_strsave((char_u*)display);
2422
2423 wayland_uninit_client();
2424
2425 // Reset amount of available tries to reconnect the display to 5
2426 wayland_ct_restore_count = 5;
2427
2428 if (wayland_init_client(display) == OK)
2429 {
Hirohito Higashi73b96502025-06-28 18:18:21 +02002430 smsg(_("restoring Wayland display %s"), wayland_display_name);
Foxe Chenb90c2392025-06-27 21:10:35 +02002431
2432#ifdef FEAT_WAYLAND_CLIPBOARD
2433 wayland_cb_init((char*)p_wse);
2434#endif
2435 }
2436 else
Hirohito Higashi73b96502025-06-28 18:18:21 +02002437 msg(_("failed restoring, lost connection to Wayland display"));
Foxe Chenb90c2392025-06-27 21:10:35 +02002438
2439 vim_free(display);
2440
2441 choose_clipmethod();
2442}
2443
2444/*
2445 * Set wayland_display_name to display. Note that this allocate a copy of the
2446 * string, unless NULL is passed. If NULL is passed then v:wayland_display is
2447 * set to $WAYLAND_DISPLAY, but wayland_display_name is set to NULL.
2448 */
2449 static void
2450wayland_set_display(const char *display)
2451{
2452 if (display == NULL)
2453 display = (char*)mch_getenv((char_u*)"WAYLAND_DISPLAY");
2454 else if (display == wayland_display_name)
2455 // Don't want to be freeing vwl_display_strname then trying to copy it
2456 // after.
2457 goto exit;
2458
2459 if (display == NULL)
2460 // $WAYLAND_DISPLAY is not set
2461 display = "";
2462
2463 // Leave unchanged if display is empty (but not NULL)
2464 if (STRCMP(display, "") != 0)
2465 {
2466 vim_free(wayland_display_name);
2467 wayland_display_name = (char*)vim_strsave((char_u*)display);
2468 }
2469
2470exit:
2471#ifdef FEAT_EVAL
2472 set_vim_var_string(VV_WAYLAND_DISPLAY, (char_u*)display, -1);
2473#endif
2474}
2475
2476#endif // FEAT_WAYLAND