Fixed GtkWindow/GtkWidget to properly emit hierarchy changed for embedded toplevels

Now GtkWindow takes some measures when setting toplevelness:

  - When a window becomes toplevel after being embedded it saves
    the visibility state and reshow's itself so that the window
    re-realizes and presents itself again automatically

  - When emitting hierarchy-changed, synthetically mark the toplevel
    as not anchored, this allows the hierarchy changed propagation to
    recurse properly.

GtkWidget also takes care to unset the parent window *after* unparenting
the widget and after emitting the heirarhcy changed that leaves a NULL
toplevel.

That means there are now 2 cycles of "hierarchy-changed" when removing
an embedded toplevel from a parent, first one that makes the new toplevel
a NULL one (since the toplevel flag is not yet restored), the second cycle
makes the removed window toplevel again when setting the parent window
to NULL.
This commit is contained in:
Tristan Van Berkom 2010-12-26 19:08:33 +09:00
parent aa787c9dd1
commit 93c8058582
2 changed files with 48 additions and 15 deletions

View File

@ -3721,14 +3721,6 @@ gtk_widget_unparent (GtkWidget *widget)
if (gtk_container_get_focus_child (GTK_CONTAINER (priv->parent)) == widget)
gtk_container_set_focus_child (GTK_CONTAINER (priv->parent), NULL);
/* If we are unanchoring the child, we save around the toplevel
* to emit hierarchy changed
*/
if (priv->parent->priv->anchored)
g_object_ref (toplevel);
else
toplevel = NULL;
gtk_widget_queue_draw_child (widget);
/* Reset the width and height here, to force reallocation if we
@ -3747,11 +3739,13 @@ gtk_widget_unparent (GtkWidget *widget)
gtk_widget_unrealize (widget);
}
/* Need to unset the parent window early, this can result in
* an additional "hierarchy-changed" propagation if we are removing
* a parented GtkWindow from the hierarchy.
/* If we are unanchoring the child, we save around the toplevel
* to emit hierarchy changed
*/
gtk_widget_set_parent_window (widget, NULL);
if (priv->parent->priv->anchored)
g_object_ref (toplevel);
else
toplevel = NULL;
/* Removing a widget from a container restores the child visible
* flag to the default state, so it doesn't affect the child
@ -3775,12 +3769,19 @@ gtk_widget_unparent (GtkWidget *widget)
}
g_signal_emit (widget, widget_signals[PARENT_SET], 0, old_parent);
if (toplevel && gtk_widget_is_toplevel (toplevel))
if (toplevel)
{
_gtk_widget_propagate_hierarchy_changed (widget, toplevel);
g_object_unref (toplevel);
}
/* Now that the parent pointer is nullified and the hierarchy-changed
* already passed, go ahead and unset the parent window, if we are unparenting
* an embeded GtkWindow the window will become toplevel again and hierarchy-changed
* will fire again for the new subhierarchy.
*/
gtk_widget_set_parent_window (widget, NULL);
g_object_notify (G_OBJECT (widget), "parent");
g_object_thaw_notify (G_OBJECT (widget));
if (!priv->parent)

View File

@ -9231,6 +9231,7 @@ _gtk_window_set_is_toplevel (GtkWindow *window,
{
GtkWidget *widget;
GtkWidget *toplevel;
gboolean was_anchored;
widget = GTK_WIDGET (window);
@ -9242,16 +9243,47 @@ _gtk_window_set_is_toplevel (GtkWindow *window,
if (is_toplevel == gtk_widget_is_toplevel (widget))
return;
was_anchored = _gtk_widget_get_anchored (widget);
if (is_toplevel)
{
gboolean was_visible = gtk_widget_get_visible (widget);
/* Pass through regular pathways of an embedded toplevel
* to go through unmapping and hiding the widget before
* becomming a toplevel again.
*/
if (was_visible)
gtk_widget_hide (widget);
/* Save the toplevel this widget was previously anchored into before
* propagating a hierarchy-changed.
*
* Usually this happens by way of gtk_widget_unparent() and we are
* already unanchored at this point, just adding this clause incase
* things happen differently.
*/
toplevel = gtk_widget_get_toplevel (widget);
if (!gtk_widget_is_toplevel (toplevel))
if (!gtk_widget_is_toplevel (widget))
toplevel = NULL;
_gtk_widget_set_is_toplevel (widget, TRUE);
/* When a window becomes toplevel after being embedded and anchored
* into another window we need to unset it's anchored flag so that
* the hierarchy changed signal kicks in properly.
*/
_gtk_widget_set_anchored (widget, FALSE);
_gtk_widget_propagate_hierarchy_changed (widget, toplevel);
_gtk_widget_set_is_toplevel (widget, TRUE);
toplevel_list = g_slist_prepend (toplevel_list, window);
/* If an embedded toplevel gets removed from the hierarchy
* and is still in a visible state, we need to show it again
* so it will be realized as a real toplevel again.
*/
if (was_visible)
gtk_widget_show (widget);
}
else
{