patch 9.1.1485: missing Wayland clipboard support
Problem: missing Wayland clipboard support
Solution: make it work (Foxe Chen)
fixes: #5157
closes: #17097
Signed-off-by: Foxe Chen <chen.foxe@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/os_unix.c b/src/os_unix.c
index f5dea37..bf07b38 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -26,6 +26,12 @@
#include "os_unixx.h" // unix includes for os_unix.c only
+#ifdef HAVE_SHM_OPEN
+# include <sys/mman.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+#endif
+
#ifdef USE_XSMP
# include <X11/SM/SMlib.h>
#endif
@@ -135,7 +141,6 @@
# include <X11/StringDefs.h>
static Widget xterm_Shell = (Widget)0;
static void clip_update(void);
-static void xterm_update(void);
# endif
Window x11_window = 0;
@@ -1303,33 +1308,43 @@
}
#endif
-#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
-# ifdef USE_SYSTEM
+#if defined(FEAT_CLIPBOARD)
+# if defined(USE_SYSTEM) && (defined(FEAT_X11) \
+ || defined(FEAT_WAYLAND_CLIPBOARD))
static void *clip_star_save = NULL;
static void *clip_plus_save = NULL;
# endif
+# if defined(FEAT_CLIPBOARD) && (defined(FEAT_X11) \
+ || defined(FEAT_WAYLAND_CLIPBOARD))
/*
* Called when Vim is going to sleep or execute a shell command.
- * We can't respond to requests for the X selections. Lose them, otherwise
- * other applications will hang. But first copy the text to cut buffer 0.
+ * We can't respond to requests for the X or wayland selections.
+ * Lose them, otherwise other applications will hang. But first
+ * copy the text to cut buffer 0 (for X11). Wayland users must have
+ * a clipboard manager to replicate such behaviour.
*/
static void
loose_clipboard(void)
{
if (clip_star.owned || clip_plus.owned)
{
+#ifdef FEAT_X11
x11_export_final_selection();
+#endif
if (clip_star.owned)
clip_lose_selection(&clip_star);
if (clip_plus.owned)
clip_lose_selection(&clip_plus);
+#ifdef FEAT_X11
if (x11_display != NULL)
XFlush(x11_display);
+#endif
}
}
+#endif
-# ifdef USE_SYSTEM
+# if defined(USE_SYSTEM) && (defined(FEAT_X11) || defined(FEAT_WAYLAND_CLIPBOARD))
/*
* Save clipboard text to restore later.
*/
@@ -1343,7 +1358,7 @@
}
/*
- * Restore clipboard text if no one own the X selection.
+ * Restore clipboard text if no one own the X/Wayland selection.
*/
static void
restore_clipboard(void)
@@ -1385,7 +1400,8 @@
settmode(TMODE_COOK);
out_flush(); // needed to disable mouse on some systems
-# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
+# if defined(FEAT_CLIPBOARD) && (defined(FEAT_X11) \
+ || defined(FEAT_WAYLAND_CLIPBOARD))
loose_clipboard();
# endif
# if defined(SIGCONT)
@@ -1810,7 +1826,7 @@
* (e.g. through tmux).
*/
static void
-may_restore_clipboard(void)
+may_restore_x11_clipboard(void)
{
// No point in restoring the connecting if we are exiting or dying.
if (!exiting && !v_dying && xterm_dpy_retry_count > 0)
@@ -1844,13 +1860,14 @@
xterm_display = (char *)vim_strnsave(eap->arg, arglen);
xterm_display_allocated = TRUE;
}
- smsg(_("restoring display %s"), xterm_display == NULL
+ smsg(_("restoring X11 display %s"), xterm_display == NULL
? (char *)mch_getenv((char_u *)"DISPLAY") : xterm_display);
clear_xterm_clip();
x11_window = 0;
xterm_dpy_retry_count = 5; // Try reconnecting five times
- may_restore_clipboard();
+ may_restore_x11_clipboard();
+ choose_clipmethod();
}
#endif
@@ -4836,8 +4853,11 @@
if (options & SHELL_COOKED)
settmode(TMODE_COOK); // set to normal mode
-# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
+# if defined(FEAT_CLIPBOARD) && (defined(FEAT_X11) \
+ || defined(FEAT_WAYLAND_CLIPBOARD))
+# if defined(FEAT_X11) || defined(FEAT_WAYLAND_CLIPBOARD)
save_clipboard();
+#endif
loose_clipboard();
# endif
@@ -4899,7 +4919,8 @@
settmode(TMODE_RAW); // set to raw mode
}
resettitle();
-# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
+# if defined(FEAT_CLIPBOARD) && (defined(FEAT_X11) \
+ || defined(FEAT_WAYLAND_CLIPBOARD))
restore_clipboard();
# endif
return x;
@@ -5168,7 +5189,7 @@
* different on different machines. This may cause a warning
* message with strict compilers, don't worry about it.
* Call _exit() instead of exit() to avoid closing the connection
- * to the X server (esp. with GTK, which uses atexit()).
+ * to the X/Wayland server (esp. with GTK, which uses atexit()).
*/
execvp(argv[0], argv);
_exit(EXEC_FAILED); // exec failed, return failure code
@@ -5586,6 +5607,11 @@
// Handle any X events, e.g. serving the clipboard.
clip_update();
# endif
+#ifdef FEAT_WAYLAND
+ // Handle wayland events such as sending data as the source
+ // client.
+ wayland_client_update();
+#endif
}
finished:
p_more = p_more_save;
@@ -5612,7 +5638,7 @@
close(toshell_fd);
close(fromshell_fd);
}
-# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
+# if (defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)) || defined(FEAT_WAYLAND)
else
{
long delay_msec = 1;
@@ -5623,8 +5649,8 @@
out_str_t_TE();
/*
- * Similar to the loop above, but only handle X events, no
- * I/O.
+ * Similar to the loop above, but only handle X and Wayland
+ * events, no I/O.
*/
for (;;)
{
@@ -5651,8 +5677,15 @@
break;
}
+#if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
// Handle any X events, e.g. serving the clipboard.
clip_update();
+#endif
+#ifdef FEAT_WAYLAND
+ // Handle wayland events such as sending data as the source
+ // client.
+ wayland_client_update();
+#endif
// Wait for 1 to 10 msec. 1 is faster but gives the child
// less time, gradually wait longer.
@@ -6505,8 +6538,11 @@
#endif
#ifndef HAVE_SELECT
// each channel may use in, out and err
- struct pollfd fds[6 + 3 * MAX_OPEN_CHANNELS];
+ struct pollfd fds[7 + 3 * MAX_OPEN_CHANNELS];
int nfd;
+# ifdef FEAT_WAYLAND_CLIPBOARD
+ int wayland_idx = -1;
+# endif
# ifdef FEAT_XCLIPBOARD
int xterm_idx = -1;
# endif
@@ -6530,6 +6566,15 @@
fds[0].events = POLLIN;
nfd = 1;
+# ifdef FEAT_WAYLAND_CLIPBOARD
+ if (wayland_may_restore_connection())
+ {
+ wayland_idx = nfd;
+ fds[nfd].fd = vwl_display_fd;
+ fds[nfd].events = POLLIN;
+ nfd++;
+ }
+# endif
# ifdef FEAT_XCLIPBOARD
may_restore_clipboard();
if (xterm_Shell != (Widget)0)
@@ -6558,9 +6603,9 @@
nfd++;
}
# endif
-#ifdef FEAT_JOB_CHANNEL
+# ifdef FEAT_JOB_CHANNEL
nfd = channel_poll_setup(nfd, &fds, &towait);
-#endif
+# endif
if (interrupted != NULL)
*interrupted = FALSE;
@@ -6576,6 +6621,15 @@
finished = FALSE;
# endif
+# ifdef FEAT_WAYLAND_CLIPBOARD
+ // Technically we should first call wl_display_prepare_read() before
+ // polling the fd, then read and dispatch after we poll. However that is
+ // only needed for multi threaded environments to prevent deadlocks so
+ // we are fine.
+ if (fds[wayland_idx].revents & POLLIN)
+ wayland_client_update();
+# endif
+
# ifdef FEAT_XCLIPBOARD
if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
{
@@ -6608,11 +6662,11 @@
finished = FALSE; // Try again
}
# endif
-#ifdef FEAT_JOB_CHANNEL
+# ifdef FEAT_JOB_CHANNEL
// also call when ret == 0, we may be polling a keep-open channel
if (ret >= 0)
channel_poll_check(ret, &fds);
-#endif
+# endif
#else // HAVE_SELECT
@@ -6656,8 +6710,19 @@
# endif
maxfd = fd;
+# ifdef FEAT_WAYLAND_CLIPBOARD
+
+ if (wayland_may_restore_connection())
+ {
+ FD_SET(wayland_display_fd, &rfds);
+
+ if (maxfd < wayland_display_fd)
+ maxfd = wayland_display_fd;
+ }
+# endif
+
# ifdef FEAT_XCLIPBOARD
- may_restore_clipboard();
+ may_restore_x11_clipboard();
if (xterm_Shell != (Widget)0)
{
FD_SET(ConnectionNumber(xterm_dpy), &rfds);
@@ -6745,6 +6810,15 @@
finished = FALSE;
# endif
+# ifdef FEAT_WAYLAND_CLIPBOARD
+ // Technically we should first call wl_display_prepare_read() before
+ // polling the fd, then read and dispatch after we poll. However that is
+ // only needed for multi threaded environments to prevent deadlocks so
+ // we are fine.
+ if (ret > 0 && FD_ISSET(wayland_display_fd, &rfds))
+ wayland_client_update();
+# endif
+
# ifdef FEAT_XCLIPBOARD
if (ret > 0 && xterm_Shell != (Widget)0
&& FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
@@ -6789,11 +6863,11 @@
}
}
# endif
-#ifdef FEAT_JOB_CHANNEL
+# ifdef FEAT_JOB_CHANNEL
// also call when ret == 0, we may be polling a keep-open channel
if (ret >= 0)
(void)channel_select_check(ret, &rfds, &wfds);
-#endif
+# endif
#endif // HAVE_SELECT
@@ -8295,7 +8369,7 @@
* nothing in the X event queue (& no timers pending), then we return
* immediately.
*/
- static void
+ void
xterm_update(void)
{
XEvent event;
@@ -8846,3 +8920,33 @@
}
# endif // PROF_NSEC
#endif // FEAT_RELTIME
+
+/*
+ * Create an anonymous/temporary file/object and return its file descriptor.
+ * Returns -1 on error.
+ */
+ int
+mch_create_anon_file(void)
+{
+ int fd = -1;
+#ifdef HAVE_SHM_OPEN
+ const char template[] = "/vimXXXXXX";
+
+ for (int i = 0; i < 100; i++)
+ {
+ mch_get_random((char_u*)template + 4, 6);
+
+ errno = 0;
+ fd = shm_open(template, O_CREAT | O_RDWR | O_EXCL, 0600);
+
+ if (fd >= 0 || errno != EEXIST)
+ break; }
+ // Remove object name from namespace
+ shm_unlink(template);
+#endif
+ if (fd == -1)
+ // Last resort
+ fd = fileno(tmpfile());
+
+ return fd;
+}