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.

Raspunde prin e-mail lui