mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2025-01-16 07:04:29 +00:00
popover: Track toplevel focus changes
Make the popover temporarily undo the GTK+ grab, so it remains modal to its window, but does not attempt to steal focus on other non-modal windows that get the focus. This was most confusing with keyboard navigation, as the focus would remain stuck on the popover, and not move to the newly focused window after the popover was dismissed. It didn't have as much effect on pointer operations as only the first click would be consumed in order to hide the popover.
This commit is contained in:
parent
08e9c93b17
commit
dcba77fcc4
@ -102,6 +102,7 @@ struct _GtkPopoverPrivate
|
||||
guint modal : 1;
|
||||
guint button_pressed : 1;
|
||||
guint apply_shape : 1;
|
||||
guint grab_notify_blocked : 1;
|
||||
};
|
||||
|
||||
static GQuark quark_widget_popovers = 0;
|
||||
@ -254,6 +255,52 @@ gtk_popover_realize (GtkWidget *widget)
|
||||
gtk_widget_set_realized (widget, TRUE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
window_focus_in (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GtkPopover *popover)
|
||||
{
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
|
||||
/* Regain the grab when the window is focused */
|
||||
if (priv->modal &&
|
||||
gtk_widget_is_drawable (GTK_WIDGET (popover)))
|
||||
{
|
||||
GtkWidget *focus;
|
||||
|
||||
gtk_grab_add (GTK_WIDGET (popover));
|
||||
|
||||
focus = gtk_window_get_focus (GTK_WINDOW (widget));
|
||||
|
||||
if (!gtk_widget_is_ancestor (focus, GTK_WIDGET (popover)))
|
||||
gtk_widget_grab_focus (GTK_WIDGET (popover));
|
||||
|
||||
if (priv->grab_notify_blocked)
|
||||
g_signal_handler_unblock (priv->widget, priv->grab_notify_id);
|
||||
|
||||
priv->grab_notify_blocked = FALSE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
window_focus_out (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GtkPopover *popover)
|
||||
{
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
|
||||
/* Temporarily remove the grab when unfocused */
|
||||
if (priv->modal &&
|
||||
gtk_widget_is_drawable (GTK_WIDGET (popover)))
|
||||
{
|
||||
g_signal_handler_block (priv->widget, priv->grab_notify_id);
|
||||
gtk_grab_remove (GTK_WIDGET (popover));
|
||||
priv->grab_notify_blocked = TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_popover_apply_modality (GtkPopover *popover,
|
||||
gboolean modal)
|
||||
@ -270,9 +317,15 @@ gtk_popover_apply_modality (GtkPopover *popover,
|
||||
g_object_ref (prev_focus);
|
||||
gtk_grab_add (GTK_WIDGET (popover));
|
||||
gtk_widget_grab_focus (GTK_WIDGET (popover));
|
||||
|
||||
g_signal_connect (priv->window, "focus-in-event",
|
||||
G_CALLBACK (window_focus_in), popover);
|
||||
g_signal_connect (priv->window, "focus-out-event",
|
||||
G_CALLBACK (window_focus_out), popover);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_signal_handlers_disconnect_by_data (priv->window, popover);
|
||||
gtk_grab_remove (GTK_WIDGET (popover));
|
||||
|
||||
if (priv->prev_focus_widget)
|
||||
|
Loading…
Reference in New Issue
Block a user