[gtk/BUG_popover_focus_from_another_window_GTK4] popover: fix focus when inside an unfocused window



commit 23011e3ffee69a5a6e8ff74659757b532c9d7404
Author: Nelson Benítez León <nbenitezl gmail com>
Date:   Fri Aug 30 22:49:15 2019 -0400

    popover: fix focus when inside an unfocused window
    
    Fix popovers to properly gain focus when clicked
    inside an unfocused window.
    
    We use the GTK_PHASE_CAPTURE of the 'pressed' event
    to early detect that the popover is being clicked
    inside an inactive window, this allow us to present
    the window (and be focused) before the normal signal
    handlers for the popover click/pressed events are run
    which would ultimately give focus to popover widget.
    
    This fix works for both modal and 'non modal' popovers,
    although for GTK4 we only benefit from the 'non modal'
    case, as GTK4 (contrary to GTK3) hides the modal popovers
    when the focus is changed to another application's window,
    so it's only possible for a 'non modal' popover to be
    clicked inside an unfocused window.
    
    Fixes issue #1871

 gtk/gtkpopover.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)
---
diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c
index 3c211b0874..83bcb9e42b 100644
--- a/gtk/gtkpopover.c
+++ b/gtk/gtkpopover.c
@@ -110,6 +110,7 @@
 #include "gtknative.h"
 #include "gtkwidgetprivate.h"
 #include "gtkeventcontrollerkey.h"
+#include "gtkgestureclick.h"
 #include "gtkcssnodeprivate.h"
 #include "gtkbindings.h"
 #include "gtkenums.h"
@@ -544,6 +545,20 @@ node_style_changed_cb (GtkCssNode        *node,
     gtk_widget_queue_draw (widget);
 }
 
+static void
+gtk_popover_click_gesture_pressed (GtkGestureClick *gesture,
+                                   gint             n_press,
+                                   gdouble          widget_x,
+                                   gdouble          widget_y,
+                                   GtkPopover      *popover)
+{
+  GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+  GtkWindow *rel_window = GTK_WINDOW (gtk_widget_get_root (priv->relative_to));
+
+  if (!gtk_window_is_active (rel_window) && gtk_widget_is_drawable (GTK_WIDGET (popover)))
+    gtk_window_present_with_time (rel_window, gtk_get_current_event_time ());
+}
+
 static void
 gtk_popover_init (GtkPopover *popover)
 {
@@ -551,6 +566,7 @@ gtk_popover_init (GtkPopover *popover)
   GtkWidget *widget = GTK_WIDGET (popover);
   GtkEventController *controller;
   GtkStyleContext *context;
+  GtkGesture *click_gesture;
 
   priv->position = GTK_POS_BOTTOM;
   priv->final_position = GTK_POS_BOTTOM;
@@ -572,6 +588,15 @@ gtk_popover_init (GtkPopover *popover)
                            G_CALLBACK (node_style_changed_cb), popover, 0);
   g_object_unref (priv->arrow_node);
 
+  click_gesture = gtk_gesture_click_new ();
+  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (click_gesture), 0);
+  gtk_gesture_single_set_exclusive (GTK_GESTURE_SINGLE (click_gesture), TRUE);
+  gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (click_gesture),
+                                              GTK_PHASE_CAPTURE);
+  g_signal_connect (click_gesture, "pressed",
+                    G_CALLBACK (gtk_popover_click_gesture_pressed), popover);
+  gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (click_gesture));
+
   priv->contents_widget = gtk_gizmo_new ("contents",
                                          measure_contents,
                                          allocate_contents,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]