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



commit 58f57aeb3bc92280c8e2ded2901aaa553dd6b34d
Author: Nelson Benítez León <nbenitezl gmail com>
Date:   Fri Aug 30 21:14:17 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
    when being clicked inside unfocused windows.
    
    Fixes issue #1871

 gtk/gtkpopover.c | 47 +++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 39 insertions(+), 8 deletions(-)
---
diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c
index 59d1bc8587..a2d47b6281 100644
--- a/gtk/gtkpopover.c
+++ b/gtk/gtkpopover.c
@@ -159,6 +159,7 @@ struct _GtkPopoverPrivate
   GdkRectangle pointing_to;
   GtkPopoverConstraint constraint;
   GtkProgressTracker tracker;
+  GtkGesture *multipress_gesture;
   guint prev_focus_unmap_id;
   guint hierarchy_changed_id;
   guint size_allocate_id;
@@ -199,6 +200,12 @@ static void gtk_popover_apply_modality     (GtkPopover *popover,
 static void gtk_popover_set_scrollable_full (GtkPopover    *popover,
                                              GtkScrollable *scrollable);
 
+static void gtk_popover_multipress_gesture_pressed (GtkGestureMultiPress *gesture,
+                                                    gint                  n_press,
+                                                    gdouble               widget_x,
+                                                    gdouble               widget_y,
+                                                    GtkPopover            *popover);
+
 G_DEFINE_TYPE_WITH_PRIVATE (GtkPopover, gtk_popover, GTK_TYPE_BIN)
 
 static void
@@ -206,17 +213,26 @@ gtk_popover_init (GtkPopover *popover)
 {
   GtkWidget *widget;
   GtkStyleContext *context;
+  GtkPopoverPrivate *priv;
 
   widget = GTK_WIDGET (popover);
   gtk_widget_set_has_window (widget, TRUE);
-  popover->priv = gtk_popover_get_instance_private (popover);
-  popover->priv->modal = TRUE;
-  popover->priv->tick_id = 0;
-  popover->priv->state = STATE_HIDDEN;
-  popover->priv->visible = FALSE;
-  popover->priv->transitions_enabled = TRUE;
-  popover->priv->preferred_position = GTK_POS_TOP;
-  popover->priv->constraint = GTK_POPOVER_CONSTRAINT_WINDOW;
+  priv = popover->priv = gtk_popover_get_instance_private (popover);
+  priv->modal = TRUE;
+  priv->tick_id = 0;
+  priv->state = STATE_HIDDEN;
+  priv->visible = FALSE;
+  priv->transitions_enabled = TRUE;
+  priv->preferred_position = GTK_POS_TOP;
+  priv->constraint = GTK_POPOVER_CONSTRAINT_WINDOW;
+
+  priv->multipress_gesture = gtk_gesture_multi_press_new (widget);
+  g_signal_connect (priv->multipress_gesture, "pressed",
+                    G_CALLBACK (gtk_popover_multipress_gesture_pressed), popover);
+  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->multipress_gesture), 0);
+  gtk_gesture_single_set_exclusive (GTK_GESTURE_SINGLE (priv->multipress_gesture), TRUE);
+  gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (priv->multipress_gesture),
+                                              GTK_PHASE_CAPTURE);
 
   context = gtk_widget_get_style_context (GTK_WIDGET (popover));
   gtk_style_context_add_class (context, GTK_STYLE_CLASS_BACKGROUND);
@@ -336,6 +352,8 @@ gtk_popover_finalize (GObject *object)
   if (priv->widget)
     gtk_popover_update_relative_to (popover, NULL);
 
+  g_clear_object (&priv->multipress_gesture);
+
   G_OBJECT_CLASS (gtk_popover_parent_class)->finalize (object);
 }
 
@@ -2178,6 +2196,19 @@ gtk_popover_update_preferred_position (GtkPopover      *popover,
   g_object_notify_by_pspec (G_OBJECT (popover), properties[PROP_POSITION]);
 }
 
+static void
+gtk_popover_multipress_gesture_pressed (GtkGestureMultiPress *gesture,
+                                        gint                  n_press,
+                                        gdouble               widget_x,
+                                        gdouble               widget_y,
+                                        GtkPopover           *popover)
+{
+  GtkPopoverPrivate *priv = popover->priv;
+
+  if (!gtk_window_is_active (priv->window) && gtk_widget_is_drawable (GTK_WIDGET (popover)))
+    gtk_window_present_with_time (priv->window, gtk_get_current_event_time ());
+}
+
 /**
  * gtk_popover_new:
  * @relative_to: (allow-none): #GtkWidget the popover is related to


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