patch 9.2.0588: GTK4: drawing area loses focus after closing a menubar popover

Commit: 
https://github.com/vim/vim/commit/f1ed84158ab80240c42c9f2356767cad448ca151
Author: Yasuhiro Matsumoto <[email protected]>
Date:   Tue Jun 2 18:36:26 2026 +0000

    patch 9.2.0588: GTK4: drawing area loses focus after closing a menubar 
popover
    
    Problem:  After a menubar popover (e.g. File, Edit) was opened and then
              dismissed without selecting an item, keyboard focus remained
              outside the drawing area, leaving the cursor stuck in the
              unfocused (outline) shape until the pointer was moved over the
              drawarea (Foxe Chen)
    Solution: Install an emission hook on GtkPopover::closed and, when a
              popover that descends from gui.menubar closes, queue an idle
              callback that grabs focus back to the drawing area. The grab
              must be deferred because GTK is still completing the close
              transition when the signal fires (Yasuhiro Matsumoto).
    
    fixes:  #20274
    closes: #20291
    
    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 20390879a..c3c6f6cc6 100644
--- a/src/gui_gtk4.c
+++ b/src/gui_gtk4.c
@@ -275,6 +275,9 @@ static void leave_notify_event(GtkEventControllerMotion 
*controller, gpointer da
 static gboolean scroll_event(GtkEventControllerScroll *controller, double dx, 
double dy, gpointer data);
 static void focus_in_event(GtkEventControllerFocus *controller, gpointer data);
 static void focus_out_event(GtkEventControllerFocus *controller, gpointer 
data);
+#ifdef FEAT_MENU
+static gboolean menubar_popover_closed_hook(GSignalInvocationHint *ihint, 
guint n_param_values, const GValue *param_values, gpointer data);
+#endif
 #ifdef FEAT_DND
 static gboolean drop_cb(GtkDropTarget *target, const GValue *value, double x, 
double y, gpointer data);
 #endif
@@ -476,6 +479,20 @@ gui_mch_init(void)
        gtk_widget_set_visible(gui.menubar, FALSE);
        gtk_box_append(GTK_BOX(vbox), gui.menubar);
     }
+    // Return keyboard focus to the drawing area when a menubar popover
+    // closes (issue #20274).  GtkPopoverMenuBar owns its popovers
+    // privately, so attach via an emission hook on GtkPopover::closed
+    // and filter for popovers under our menubar inside the callback.
+    {
+       GTypeClass *cls = g_type_class_ref(GTK_TYPE_POPOVER);
+       guint sig_id = g_signal_lookup("closed", GTK_TYPE_POPOVER);
+
+       if (sig_id != 0)
+           g_signal_add_emission_hook(sig_id, 0,
+                   menubar_popover_closed_hook, NULL, NULL);
+       if (cls != NULL)
+           g_type_class_unref(cls);
+    }
 #endif
 
 #ifdef FEAT_TOOLBAR
@@ -1924,6 +1941,48 @@ focus_out_event(GtkEventControllerFocus *controller 
UNUSED,
        gui_mch_stop_blink(TRUE);
 }
 
+#ifdef FEAT_MENU
+    static gboolean
+grab_drawarea_focus_idle(gpointer data UNUSED)
+{
+    if (gui.drawarea != NULL && !gtk_widget_has_focus(gui.drawarea))
+       gtk_widget_grab_focus(gui.drawarea);
+    return G_SOURCE_REMOVE;
+}
+
+    static gboolean
+menubar_popover_closed_hook(GSignalInvocationHint *ihint UNUSED,
+       guint n_param_values, const GValue *param_values,
+       gpointer data UNUSED)
+{
+    GObject    *obj;
+    GtkWidget  *popover;
+    GtkWidget  *parent;
+
+    if (n_param_values < 1 || gui.menubar == NULL || gui.drawarea == NULL)
+       return TRUE;
+    obj = g_value_get_object(&param_values[0]);
+    if (!GTK_IS_POPOVER(obj))
+       return TRUE;
+    popover = GTK_WIDGET(obj);
+
+    // Only react to popovers that descend from the menubar.
+    for (parent = gtk_widget_get_parent(popover);
+           parent != NULL;
+           parent = gtk_widget_get_parent(parent))
+    {
+       if (parent != gui.menubar)
+           continue;
+       // Defer the grab to the next main loop iteration; calling it
+       // synchronously while GTK is still completing the popover close
+       // has no effect (issue #20274).
+       g_idle_add(grab_drawarea_focus_idle, NULL);
+       break;
+    }
+    return TRUE;       // keep the emission hook installed
+}
+#endif
+
     static void
 drawarea_realize_cb(GtkWidget *widget UNUSED, gpointer data UNUSED)
 {
diff --git a/src/version.c b/src/version.c
index 676c515f9..a7031b84b 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 */
+/**/
+    588,
 /**/
     587,
 /**/

-- 
-- 
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/E1wUU6q-0028zJ-01%40256bit.org.

Raspunde prin e-mail lui