mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2025-01-13 22:10:08 +00:00
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:
parent
aa787c9dd1
commit
93c8058582
@ -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
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user