patch 9.2.0529: GTK4: clipboard returns empty after a foreign app takes the selection
Commit: https://github.com/vim/vim/commit/06ef3a54bf0f740d1ada5524599c7d05f0603b20 Author: Yasuhiro Matsumoto <[email protected]> Date: Sun May 24 17:29:04 2026 +0000 patch 9.2.0529: GTK4: clipboard returns empty after a foreign app takes the selection Problem: GTK4: clipboard read returns empty after a foreign app takes the selection (lilydjwg, after v9.2.0501) Solution: Skip the set_content call unless gdk_clipboard_is_local() still says we own the clipboard (Yasuhiro Matsumoto). clipboard_changed_cb calls clip_lose_selection() which cascades into clip_mch_lose_selection(), and that unconditionally called gdk_clipboard_set_content(clipboard, NULL). When the signal fires because *another* app took the selection, this re-claims ownership with NULL content, so the next gdk_clipboard_read_text_async() returns empty and the user sees "Nothing in register *". fixes: #20256 closes: #20261 Co-Authored-by: Claude <[email protected]> Signed-off-by: Yasuhiro Matsumoto <[email protected]> Signed-off-by: Christian Brabandt <[email protected]> diff --git a/src/gui_gtk4.c b/src/gui_gtk4.c index a9c9de7ca..c12256790 100644 --- a/src/gui_gtk4.c +++ b/src/gui_gtk4.c @@ -285,6 +285,7 @@ static void drawarea_unrealize_cb(GtkWidget *widget, gpointer data); static void drawarea_resize_cb(GtkDrawingArea *area, int width, int height, gpointer data); static void drawarea_scale_factor_cb(GObject *object, GParamSpec *pspec, gpointer data); static cairo_surface_t *create_backing_surface(int width, int height); +static void clipboard_changed_cb(GdkClipboard *clipboard, gpointer user_data); /* * Parse the GUI related command-line arguments. Any arguments used are @@ -589,6 +590,19 @@ gui_mch_init(void) // Create a blank (invisible) cursor for hiding the mouse pointer. gui.blank_pointer = gdk_cursor_new_from_name("none", NULL); + { + GdkDisplay *display = gtk_widget_get_display(gui.mainwin); + GdkClipboard *primary = gdk_display_get_primary_clipboard(display); + GdkClipboard *board = gdk_display_get_clipboard(display); + + if (primary != NULL) + g_signal_connect(primary, "changed", + G_CALLBACK(clipboard_changed_cb), &clip_star); + if (board != NULL) + g_signal_connect(board, "changed", + G_CALLBACK(clipboard_changed_cb), &clip_plus); + } + return OK; } @@ -3130,6 +3144,8 @@ clip_mch_request_selection(Clipboard_T *cbd) g_main_context_iteration(NULL, TRUE); } +static int in_clipboard_set = FALSE; + /* * Send the current selection to the clipboard. */ @@ -3174,7 +3190,9 @@ clip_mch_set_selection(Clipboard_T *cbd) { mch_memmove(nul_str, str, len); nul_str[len] = NUL; + in_clipboard_set = TRUE; gdk_clipboard_set_text(clipboard, (const char *)nul_str); + in_clipboard_set = FALSE; vim_free(nul_str); } } @@ -3182,6 +3200,18 @@ clip_mch_set_selection(Clipboard_T *cbd) vim_free(str); } + static void +clipboard_changed_cb(GdkClipboard *clipboard, gpointer user_data) +{ + Clipboard_T *cbd = (Clipboard_T *)user_data; + + if (in_clipboard_set) + return; + if (gdk_clipboard_is_local(clipboard)) + return; + clip_lose_selection(cbd); +} + /* * Own the selection. In GTK4, ownership is implicit when content is set * on the clipboard. Return OK to indicate we can own it. @@ -3205,8 +3235,12 @@ clip_mch_lose_selection(Clipboard_T *cbd) if (clipboard == NULL) return; - // Setting NULL content provider releases ownership. - gdk_clipboard_set_content(clipboard, NULL); + // Only release ownership if we still own it. Otherwise we would + // clobber another application's clipboard content with NULL, which + // happens when this is called from clipboard_changed_cb after a + // foreign app took the selection. + if (gdk_clipboard_is_local(clipboard)) + gdk_clipboard_set_content(clipboard, NULL); } // Balloon eval - use GTK4 tooltip diff --git a/src/version.c b/src/version.c index 19dbebbdb..ca5b3ec12 100644 --- a/src/version.c +++ b/src/version.c @@ -729,6 +729,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 529, /**/ 528, /**/ -- -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1wRCsq-004Pek-7b%40256bit.org.
