diff --git a/subcompositor.c b/subcompositor.c index effadbb..a228da9 100644 --- a/subcompositor.c +++ b/subcompositor.c @@ -1286,8 +1286,8 @@ ViewSetSubcompositor (View *view, Subcompositor *subcompositor) list = view->link; - /* Attach the subcompositor recursively for all of view's - inferiors. */ + /* Attach the subcompositor recursively for all of view's inferiors. + view should not be attached to a subcompositor. */ do { @@ -1296,7 +1296,7 @@ ViewSetSubcompositor (View *view, Subcompositor *subcompositor) list = list->next; } - while (list != view->inferior); + while (list != view->link); } diff --git a/subsurface.c b/subsurface.c index 956b1ef..ac3f9cb 100644 --- a/subsurface.c +++ b/subsurface.c @@ -912,18 +912,15 @@ Teardown (Surface *surface, Role *role) NoteSubsurfaceTeardown (subsurface); role->surface = NULL; + subcompositor = NULL; if (subsurface->parent) { - subcompositor = ViewGetSubcompositor (surface->view); - - /* Assert that the subcompositor is NULL if the subsurface is - pending. */ - XLAssert (!subsurface->pending || !subcompositor); - - if (subcompositor) + if (!subsurface->pending) { - /* Detach the views if the subcompositor is set. */ + subcompositor = ViewGetSubcompositor (surface->view); + + /* Detach the views if the subsurface is not pending. */ ViewUnparent (surface->view); ViewSetSubcompositor (surface->view, NULL); @@ -1144,22 +1141,19 @@ XLSubsurfaceParentDestroyed (Role *role) Subsurface *subsurface; subsurface = SubsurfaceFromRole (role); - subsurface->parent = NULL; /* The callback is freed with the parent. */ subsurface->commit_callback = NULL; if (subsurface->role.surface) { - /* Set the subcompositor to NULL, as it may no longer be - present. */ - ViewSetSubcompositor (subsurface->role.surface->view, - NULL); - ViewSetSubcompositor (subsurface->role.surface->under, - NULL); + /* Unparent the view. The parent is responsible for clearing + the subcompositor. */ ViewUnparent (subsurface->role.surface->view); ViewUnparent (subsurface->role.surface->under); } + + subsurface->parent = NULL; } void diff --git a/surface.c b/surface.c index 8e5028d..07dd79e 100644 --- a/surface.c +++ b/surface.c @@ -1390,15 +1390,16 @@ HandleSurfaceDestroy (struct wl_resource *resource) surface = wl_resource_get_user_data (resource); - /* Free all subsurfaces. This must come before the subcompositor is - destroyed. */ + if (surface->role) + XLSurfaceReleaseRole (surface, surface->role); + + /* Detach all subsurfaces from the parent. This *must* be done + after the role is torn down, because that is where the toplevel + subcompositor is detached from the roles. */ XLListFree (surface->subsurfaces, NotifySubsurfaceDestroyed); surface->subsurfaces = NULL; - if (surface->role) - XLSurfaceReleaseRole (surface, surface->role); - /* Keep surface->resource around until the role is released; some code (such as dnd.c) assumes that surface->resource will always be available in unmap callbacks. */ diff --git a/tests/subsurface_test.c b/tests/subsurface_test.c index 09907ff..3efca35 100644 --- a/tests/subsurface_test.c +++ b/tests/subsurface_test.c @@ -917,6 +917,27 @@ test_single_step (enum test_kind kind) wait_frame_callback (subsurfaces[0]->surface); sleep_or_verify (); + /* Test that subsurface actions are applied in the right order + for newly unparented (pending) subsurfaces. Destroy and + recreate subsurfaces[9] and subsurfaces[10]. */ + delete_subsurface_role (subsurfaces[9]); + delete_subsurface_role (subsurfaces[10]); + recreate_subsurface (subsurfaces[9], subsurfaces[6]->surface); + recreate_subsurface (subsurfaces[10], subsurfaces[6]->surface); + wl_subsurface_set_position (subsurfaces[9]->subsurface, 600, 600); + wl_subsurface_set_position (subsurfaces[10]->subsurface, 600, 600); + + /* Place subsurfaces[9] above subsurfaces[10]. At this point, + the subsurfaces have not yet been confirmed. */ + wl_subsurface_place_above (subsurfaces[9]->subsurface, + subsurfaces[10]->surface); + + /* Commit the parents. W should now be tinted red. */ + wl_surface_commit (subsurfaces[6]->surface); + wl_surface_commit (subsurfaces[4]->surface); + wait_frame_callback (subsurfaces[0]->surface); + sleep_or_verify (); + break; }