From 1f7b6c1d6f822ee660b8cca3b08a2bcc1c48b359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Wed, 10 Aug 2016 18:28:14 +0200 Subject: [PATCH] GtkPopover: Add gtk_popover_popdown/popup Since not chaining up in gtk_widget_show/gtk_widget_hide is not allowed, we can't just implicitly delay the hiding in GtkPopover's hide implementation. Fix this by introducing gtk_popover_popup() and gtk_popover_popdown() to show or hide a popover with transition and revert GtkPopover's show/hide implementation to apply their effect without the transition. https://bugzilla.gnome.org/show_bug.cgi?id=769706 --- docs/reference/gtk/gtk3-sections.txt | 2 + gtk/gtkpopover.c | 146 +++++++++++++++++++++------ gtk/gtkpopover.h | 7 ++ 3 files changed, 124 insertions(+), 31 deletions(-) diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt index a049638ab7..b1a81c71c1 100644 --- a/docs/reference/gtk/gtk3-sections.txt +++ b/docs/reference/gtk/gtk3-sections.txt @@ -8159,6 +8159,8 @@ GtkPopover gtk_popover_new gtk_popover_new_from_model gtk_popover_bind_model +gtk_popover_popup +gtk_popover_popdown gtk_popover_set_relative_to gtk_popover_get_relative_to gtk_popover_set_pointing_to diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c index 3e5e6e7ce4..48be0efafa 100644 --- a/gtk/gtkpopover.c +++ b/gtk/gtkpopover.c @@ -208,6 +208,8 @@ gtk_popover_init (GtkPopover *popover) 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; @@ -295,6 +297,30 @@ transitions_enabled (GtkPopover *popover) priv->transitions_enabled; } +static void +gtk_popover_hide_internal (GtkPopover *popover) +{ + GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover); + GtkWidget *widget = GTK_WIDGET (popover); + + if (!priv->visible) + return; + + priv->visible = FALSE; + g_signal_emit (widget, signals[CLOSED], 0); + + if (priv->modal) + gtk_popover_apply_modality (popover, FALSE); + + if (gtk_widget_get_realized (widget)) + { + cairo_region_t *region = cairo_region_create (); + gdk_window_input_shape_combine_region (gtk_widget_get_parent_window (widget), + region, 0, 0); + cairo_region_destroy (region); + } +} + static void gtk_popover_finalize (GObject *object) { @@ -550,12 +576,27 @@ show_animate_cb (GtkWidget *widget, gtk_popover_set_state (popover, STATE_HIDING); } else - gtk_popover_set_state (popover, STATE_HIDDEN); + { + gtk_widget_hide (widget); + } - return FALSE; + priv->tick_id = 0; + return G_SOURCE_REMOVE; } else - return TRUE; + return G_SOURCE_CONTINUE; +} + +static void +gtk_popover_stop_transition (GtkPopover *popover) +{ + GtkPopoverPrivate *priv = popover->priv; + + if (priv->tick_id != 0) + { + gtk_widget_remove_tick_callback (GTK_WIDGET (popover), priv->tick_id); + priv->tick_id = 0; + } } static void @@ -593,11 +634,7 @@ gtk_popover_set_state (GtkPopover *popover, gtk_popover_start_transition (popover); else { - if (priv->tick_id) - { - gtk_widget_remove_tick_callback (GTK_WIDGET (popover), priv->tick_id); - priv->tick_id = 0; - } + gtk_popover_stop_transition (popover); gtk_widget_set_visible (GTK_WIDGET (popover), state == STATE_SHOWN); } @@ -1483,10 +1520,12 @@ gtk_popover_button_release (GtkWidget *widget, event->x > child_alloc.x + child_alloc.width || event->y < child_alloc.y || event->y > child_alloc.y + child_alloc.height) - gtk_widget_hide (widget); + gtk_popover_popdown (popover); } else if (!gtk_widget_is_ancestor (event_widget, widget)) - gtk_widget_hide (widget); + { + gtk_popover_popdown (popover); + } return GDK_EVENT_PROPAGATE; } @@ -1583,7 +1622,7 @@ gtk_popover_show (GtkWidget *widget) if (priv->modal) gtk_popover_apply_modality (GTK_POPOVER (widget), TRUE); - gtk_popover_set_state (GTK_POPOVER (widget), STATE_SHOWING); + priv->state = STATE_SHOWN; if (gtk_widget_get_realized (widget)) gdk_window_input_shape_combine_region (gtk_widget_get_parent_window (widget), @@ -1594,29 +1633,17 @@ static void gtk_popover_hide (GtkWidget *widget) { GtkPopoverPrivate *priv = GTK_POPOVER (widget)->priv; - cairo_region_t *region; - if (priv->visible) - { - priv->visible = FALSE; - g_signal_emit (widget, signals[CLOSED], 0); + gtk_popover_hide_internal (GTK_POPOVER (widget)); - if (priv->modal) - gtk_popover_apply_modality (GTK_POPOVER (widget), FALSE); - } + gtk_popover_stop_transition (GTK_POPOVER (widget)); + priv->state = STATE_HIDDEN; + priv->transition_diff = 0; + gtk_progress_tracker_finish (&priv->tracker); + gtk_widget_set_opacity (widget, 1.0); - if (gtk_widget_get_realized (widget)) - { - region = cairo_region_create (); - gdk_window_input_shape_combine_region (gtk_widget_get_parent_window (widget), - region, 0, 0); - cairo_region_destroy (region); - } - if (!priv->window || priv->state == STATE_HIDDEN) - GTK_WIDGET_CLASS (gtk_popover_parent_class)->hide (widget); - else if (priv->state != STATE_SHOWING) - gtk_popover_set_state (GTK_POPOVER (widget), STATE_HIDING); + GTK_WIDGET_CLASS (gtk_popover_parent_class)->hide (widget); } static void @@ -1827,7 +1854,7 @@ _gtk_popover_parent_grab_notify (GtkWidget *widget, grab_widget = gtk_grab_get_current (); if (!grab_widget || !GTK_IS_POPOVER (grab_widget)) - gtk_widget_hide (GTK_WIDGET (popover)); + gtk_popover_popdown (popover); } } @@ -2569,3 +2596,60 @@ gtk_popover_get_constrain_to (GtkPopover *popover) return priv->constraint; } + +/** + * gtk_popover_popup: + * @popover: a #GtkPopover + * + * Pops @popover up. This is different than a gtk_widget_show() call + * in that it shows the popover with a transition. If you want to show + * the popover without a transition, use gtk_widget_show(). + * + * Since: 3.22 + */ +void +gtk_popover_popup (GtkPopover *popover) +{ + GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover); + + g_return_if_fail (GTK_IS_POPOVER (popover)); + + if (priv->state == STATE_SHOWING || + priv->state == STATE_SHOWN) + return; + + gtk_widget_show (GTK_WIDGET (popover)); + + if (transitions_enabled (popover)) + gtk_popover_set_state (popover, STATE_SHOWING); +} + +/** + * gtk_popover_popdown: + * @popover: a #GtkPopover + * + * Pops @popover down.This is different than a gtk_widget_hide() call + * in that it shows the popover with a transition. If you want to hide + * the popover without a transition, use gtk_widget_hide(). + * + * Since: 3.22 + */ +void +gtk_popover_popdown (GtkPopover *popover) +{ + GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover); + + g_return_if_fail (GTK_IS_POPOVER (popover)); + + if (priv->state == STATE_HIDING || + priv->state == STATE_HIDDEN) + return; + + + if (!transitions_enabled (popover)) + gtk_widget_hide (GTK_WIDGET (popover)); + else + gtk_popover_set_state (popover, STATE_HIDING); + + gtk_popover_hide_internal (popover); +} diff --git a/gtk/gtkpopover.h b/gtk/gtkpopover.h index 61bcd92703..af8359c59e 100644 --- a/gtk/gtkpopover.h +++ b/gtk/gtkpopover.h @@ -116,6 +116,13 @@ void gtk_popover_set_constrain_to (GtkPopover *popover GDK_AVAILABLE_IN_3_20 GtkPopoverConstraint gtk_popover_get_constrain_to (GtkPopover *popover); +GDK_AVAILABLE_IN_3_22 +void gtk_popover_popup (GtkPopover *popover); + +GDK_AVAILABLE_IN_3_22 +void gtk_popover_popdown (GtkPopover *popover); + + G_END_DECLS #endif /* __GTK_POPOVER_H__ */