Commit 93c80585 authored by Tristan Van Berkom's avatar Tristan Van Berkom

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.
parent aa787c9d
......@@ -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)
......
......@@ -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
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment