After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 675867 - actor: Hide children before ourselves
actor: Hide children before ourselves
Status: RESOLVED FIXED
Product: clutter-gtk
Classification: Platform
Component: general
unspecified
Other All
: Normal normal
: ---
Assigned To: clutter-gtk maintainer(s)
clutter-gtk maintainer(s)
: 656577 (view as bug list)
Depends on:
Blocks:
 
 
Reported: 2012-05-11 10:54 UTC by Bastien Nocera
Modified: 2012-05-22 14:46 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
actor: Hide children before ourselves (1.41 KB, patch)
2012-05-11 10:54 UTC, Bastien Nocera
rejected Details | Review
actor: Hide children before ourselves (1.08 KB, patch)
2012-05-11 12:23 UTC, Bastien Nocera
committed Details | Review
Don't explicitly unrealize widget in clutter_actor_unrealize (1.01 KB, patch)
2012-05-22 10:03 UTC, Alexander Larsson
committed Details | Review

Description Bastien Nocera 2012-05-11 10:54:19 UTC
.
Comment 1 Bastien Nocera 2012-05-11 10:54:21 UTC
Created attachment 213859 [details] [review]
actor: Hide children before ourselves

Fixes errors like:
Gtk-WARNING **: GtkClutterEmbed 0x11a3300 is mapped but visible child GtkClutterOffscreen 0x15d0490 is not mapped
when destroying a GtkClutterActor.

GTK+'s invariants checks expect children to not be visible anymore
if they're not mapped. This can happen if we hide the container before
telling the children that they're hidden.
Comment 2 Emmanuele Bassi (:ebassi) 2012-05-11 10:56:19 UTC
Review of attachment 213859 [details] [review]:

looks good to me
Comment 3 Bastien Nocera 2012-05-11 12:23:49 UTC
Created attachment 213861 [details] [review]
actor: Hide children before ourselves

Fixes errors like:
Gtk-WARNING **: GtkClutterEmbed 0x11a3300 is mapped but visible child GtkClutterOffscreen 0x15d0490 is not mapped
when destroying a GtkClutterActor.

GTK+'s invariants checks expect children to not be visible anymore
if they're not mapped. This can happen if we don't forcefully hide the
GtkClutterActor's widget before unrealizing it.
Comment 4 Bastien Nocera 2012-05-11 12:28:20 UTC
Comment on attachment 213859 [details] [review]
actor: Hide children before ourselves

Right path, but incorrect fix. Not sure how I managed to make this pass my tests...
Comment 5 Bastien Nocera 2012-05-11 12:36:49 UTC
*** Bug 656577 has been marked as a duplicate of this bug. ***
Comment 6 Emmanuele Bassi (:ebassi) 2012-05-11 12:52:18 UTC
Review of attachment 213861 [details] [review]:

looks good
Comment 7 Bastien Nocera 2012-05-11 13:03:46 UTC
Attachment 213861 [details] pushed as e70da5b - actor: Hide children before ourselves
Comment 8 Christophe Fergeau 2012-05-15 13:25:41 UTC
This breaks gnome-boxes (which is getting these warnings), with this patch applied its top toolbar becomes invisible during VM creation.
Comment 9 Bastien Nocera 2012-05-15 13:33:20 UTC
(In reply to comment #8)
> This breaks gnome-boxes (which is getting these warnings), with this patch
> applied its top toolbar becomes invisible during VM creation.

I don't see how this could not be a problem in your app, the widget is _unrealized_ the line after.
Comment 10 Christophe Fergeau 2012-05-15 21:34:46 UTC
I didn't get to the bottom of this yet, but here is what I've found so far. Boxes uses a ClutterBox containing notebooks and various other UI elements. In particular it has a 'topbar' actor. When moving through the various UI states, this actor gets removed from the box and then readded. When it's removed, gtk_clutter_actor_unrealize gets called, and the widget gets hidden with gtk_widget_hide. When it's readded, it's not unhidden.

If I get a backtrace of the unrealize call, I get
 
Breakpoint 10, gtk_clutter_actor_unrealize (actor=0x160c740) at ./gtk-clutter-actor.c:160
160       GtkClutterActor *clutter = GTK_CLUTTER_ACTOR (actor);
(gdb) bt
  • #0 gtk_clutter_actor_unrealize
    at ./gtk-clutter-actor.c line 160
  • #1 g_cclosure_marshal_VOID__VOIDv
    at gmarshal.c line 115
  • #2 g_type_class_meta_marshalv
    at gclosure.c line 997
  • #3 _g_closure_invoke_va
    at gclosure.c line 840
  • #4 g_signal_emit_valist
    at gsignal.c line 3207
  • #5 g_signal_emit
    at gsignal.c line 3352
  • #6 unrealize_actor_before_children_cb
    at ./clutter-actor.c line 1910
  • #7 _clutter_actor_traverse_depth
    at ./clutter-actor.c line 16052
  • #8 _clutter_actor_traverse
    at ./clutter-actor.c line 16113
  • #9 clutter_actor_unrealize_not_hiding
    at ./clutter-actor.c line 1955
  • #10 clutter_actor_update_map_state
    at ./clutter-actor.c line 1351
  • #11 clutter_actor_remove_child_internal
    at ./clutter-actor.c line 3897
  • #12 clutter_actor_remove_child
    at ./clutter-actor.c line 11732
  • #13 container_real_remove
    at ./clutter-container.c line 120
  • #14 container_remove_actor
    at ./clutter-container.c line 330
  • #15 container_remove_valist
    at ./clutter-container.c line 356
  • #16 clutter_container_remove
    at ./clutter-container.c line 483
  • #17 boxes_actor_remove
    at util.c line 1648

In particular, there's a clutter_actor_unrealize_not_hiding call in the backtrace whose doc says: "
 * This function is separate from clutter_actor_unrealize() because it
 * does not automatically hide the actor.
 * Actors need not be hidden to be unrealized, they just need to
 * be unmapped. In fact we don't want to mess up the application's
 * setting of the "visible" flag, so hiding is very undesirable.
 "

Well, I need to look more into this after getting some sleep ;)
Comment 11 Bastien Nocera 2012-05-16 01:14:10 UTC
The GTK+ semantics are different though. You can't show an unrealized widget. Unrealizing it means it's not connected to the display anymore, so it cannot show.
Comment 12 Emmanuele Bassi (:ebassi) 2012-05-16 06:37:58 UTC
the semantics of Clutter are the same: a mapped widget (i.e.: visible and associated with a mapped parent) has to be realized as well (even though, in Clutter terms, there's nothing going on inside the ::realize virtual).

if you're removing a child from an actor and then add it back, it should be shown - unless you called hide() while the former child did not have a parent; adding a child to an actor should cause the show() method to be called, which will ensure that the state is correct - realize -> map -> show. since the widget is visible when it's removed, show() will short-circuit out, and will most likely not cause one of the virtual functions in GtkClutterActor to be called - which would explicitly show the GtkWidget.

calling gtk_widget_hide() inside GtkClutterActor::unrealize is, thus, not entirely correct, but it works because the invariant is not that the unrealized widget has to be !visibile: the invariant is that the widget being unrealized is !mapped.

what happens when you replace gtk_widget_hide() with gtk_widget_unmap()?
Comment 13 Emmanuele Bassi (:ebassi) 2012-05-16 06:39:45 UTC
the other thing to understand is why removing the actor from the ClutterBox (which, by the way, is deprecated and you should not be using it) does not cause unmap() on itself to be called - thus leading to a gtk_widget_unmap() on the widget.
Comment 14 Bastien Nocera 2012-05-16 13:00:46 UTC
Reverted and added a testcase.

commit 9df4f174c42176ea879d3216181a606362041811
Author: Bastien Nocera <hadess@hadess.net>
Date:   Wed May 16 13:10:26 2012 +0100

    examples: Add/remove actors at run-time
    
    When animating, every 3 seconds, remove an actor from the
    animation or create a new one so we always have 3 or 4 actors
    spinning.

commit ab0625eefc39906ebf1e8d94799cd4636de50d6a
Author: Bastien Nocera <hadess@hadess.net>
Date:   Wed May 16 12:46:12 2012 +0100

    Revert "actor: Hide children before ourselves"
    
    This reverts commit e70da5bea9a3aa91b5950a3ad9d3f58b69ad12fc.
Comment 15 Christophe Fergeau 2012-05-16 16:23:40 UTC
(In reply to comment #12)
> what happens when you replace gtk_widget_hide() with gtk_widget_unmap()?

If I change this in gtk_clutter_actor_unrealize, the toolbar does not get hidden, but I still get the warnings in the console.
Comment 16 Alexander Larsson 2012-05-22 09:56:35 UTC
I added map/unmap implementations to gtk-clutter-actor.c, but it doesn't seem to really make a difference (although we should still probably do this).

Here is what is happening:

We're removing the GtkClutterActor actor from its parent. This will cause us to unmap, unrealize and finally remove the widget from the GtkClutterEmbed container. At the end of that we'll have a mapped previous parent (GtkClutterEmbed) and an unmapped unrealized GtkClutterActor that has no parent. This is a valid state.

However, during the intermediate state where we just unmapped or unrealized the GtkClutterActor we'll have a stage with a mapped parent (GtkClutterEmbed) with a non-mapped yet still showed child, which breaks the Gtk+ invariants.

Gtk itself handles this by postponing invariant checks when inside gtk_widget_unparent (), but this is not public API so we can't do that ourselves.
However, I think the solution is to drop the explicit widget_unmap and widget_unrealize calls from GtkClutterActor and just rely on the implicit unmap and unrealize that happens in gtk_widget_unparent.
Comment 17 Alexander Larsson 2012-05-22 10:03:18 UTC
Created attachment 214643 [details] [review]
Don't explicitly unrealize widget in clutter_actor_unrealize

We rely on the implicit unrealize in the gtk_container_remove call as
otherwise we'll temporarily be in a state where we can breaking the
gtk+ invariant that the child (GtkClutterActor) is visible but
non-mapped while the parent (GtkClutterEmbed) is mapped.
Comment 18 Emmanuele Bassi (:ebassi) 2012-05-22 10:31:04 UTC
Review of attachment 214643 [details] [review]:

looks good to me; other clutter-gtk users may want to chime in and test the patch.
Comment 19 Bastien Nocera 2012-05-22 13:21:07 UTC
gnome-control-center also has a working solution. If it works in the testcase, it's fine by me. I would add a reference to the explanation, or the explanation itself in the function though.
Comment 20 Emmanuele Bassi (:ebassi) 2012-05-22 14:46:16 UTC
Attachment 214643 [details] pushed as 154cdc9 - Don't explicitly unrealize widget in clutter_actor_unrealize