Merge branch 'subsurface_visibility' into 'master'

wlr_scene: Introduce visibily to subsurface_tree

See merge request wlroots/wlroots!4735
This commit is contained in:
Alexander Orzechowski 2024-08-13 02:22:33 +00:00
commit 3e14d467de
6 changed files with 155 additions and 120 deletions

View file

@ -131,6 +131,22 @@ struct wlr_scene_surface {
struct wl_listener surface_commit; struct wl_listener surface_commit;
}; };
struct wlr_scene_subsurface_tree_surface;
struct wlr_scene_subsurface_tree {
struct wlr_scene_tree *tree;
bool is_visible;
struct {
struct wl_signal visibility;
} events;
// private state
struct wl_list surfaces;
uint16_t visible_surfaces;
struct wlr_scene_subsurface_tree_surface *root;
};
/** A scene-graph node displaying a solid-colored rectangle */ /** A scene-graph node displaying a solid-colored rectangle */
struct wlr_scene_rect { struct wlr_scene_rect {
struct wlr_scene_node node; struct wlr_scene_node node;
@ -240,6 +256,7 @@ struct wlr_scene_timer {
/** A layer shell scene helper */ /** A layer shell scene helper */
struct wlr_scene_layer_surface_v1 { struct wlr_scene_layer_surface_v1 {
struct wlr_scene_tree *tree; struct wlr_scene_tree *tree;
struct wlr_scene_subsurface_tree *surface_tree;
struct wlr_layer_surface_v1 *layer_surface; struct wlr_layer_surface_v1 *layer_surface;
// private state // private state
@ -250,6 +267,18 @@ struct wlr_scene_layer_surface_v1 {
struct wl_listener layer_surface_unmap; struct wl_listener layer_surface_unmap;
}; };
struct wlr_scene_xdg_surface {
struct wlr_scene_tree *tree;
struct wlr_xdg_surface *xdg_surface;
struct wlr_scene_subsurface_tree *surface_tree;
// private state
struct wl_listener tree_destroy;
struct wl_listener xdg_surface_destroy;
struct wl_listener xdg_surface_commit;
};
/** /**
* Immediately destroy the scene-graph node. * Immediately destroy the scene-graph node.
*/ */
@ -596,7 +625,7 @@ void wlr_scene_output_layout_add_output(struct wlr_scene_output_layout *sol,
* Add a node displaying a surface and all of its sub-surfaces to the * Add a node displaying a surface and all of its sub-surfaces to the
* scene-graph. * scene-graph.
*/ */
struct wlr_scene_tree *wlr_scene_subsurface_tree_create( struct wlr_scene_subsurface_tree *wlr_scene_subsurface_tree_create(
struct wlr_scene_tree *parent, struct wlr_surface *surface); struct wlr_scene_tree *parent, struct wlr_surface *surface);
/** /**
@ -606,7 +635,7 @@ struct wlr_scene_tree *wlr_scene_subsurface_tree_create(
* *
* A NULL or empty clip will disable clipping * A NULL or empty clip will disable clipping
*/ */
void wlr_scene_subsurface_tree_set_clip(struct wlr_scene_node *node, void wlr_scene_subsurface_tree_set_clip(struct wlr_scene_subsurface_tree *tree,
const struct wlr_box *clip); const struct wlr_box *clip);
/** /**
@ -616,7 +645,7 @@ void wlr_scene_subsurface_tree_set_clip(struct wlr_scene_node *node,
* The origin of the returned scene-graph node will match the top-left corner * The origin of the returned scene-graph node will match the top-left corner
* of the xdg_surface window geometry. * of the xdg_surface window geometry.
*/ */
struct wlr_scene_tree *wlr_scene_xdg_surface_create( struct wlr_scene_xdg_surface *wlr_scene_xdg_surface_create(
struct wlr_scene_tree *parent, struct wlr_xdg_surface *xdg_surface); struct wlr_scene_tree *parent, struct wlr_xdg_surface *xdg_surface);
/** /**

View file

@ -82,7 +82,7 @@ struct tinywl_toplevel {
struct wl_list link; struct wl_list link;
struct tinywl_server *server; struct tinywl_server *server;
struct wlr_xdg_toplevel *xdg_toplevel; struct wlr_xdg_toplevel *xdg_toplevel;
struct wlr_scene_tree *scene_tree; struct wlr_scene_xdg_surface *scene;
struct wl_listener map; struct wl_listener map;
struct wl_listener unmap; struct wl_listener unmap;
struct wl_listener commit; struct wl_listener commit;
@ -135,7 +135,7 @@ static void focus_toplevel(struct tinywl_toplevel *toplevel, struct wlr_surface
} }
struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat); struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat);
/* Move the toplevel to the front */ /* Move the toplevel to the front */
wlr_scene_node_raise_to_top(&toplevel->scene_tree->node); wlr_scene_node_raise_to_top(&toplevel->scene->tree->node);
wl_list_remove(&toplevel->link); wl_list_remove(&toplevel->link);
wl_list_insert(&server->toplevels, &toplevel->link); wl_list_insert(&server->toplevels, &toplevel->link);
/* Activate the new surface */ /* Activate the new surface */
@ -380,7 +380,7 @@ static void reset_cursor_mode(struct tinywl_server *server) {
static void process_cursor_move(struct tinywl_server *server, uint32_t time) { static void process_cursor_move(struct tinywl_server *server, uint32_t time) {
/* Move the grabbed toplevel to the new position. */ /* Move the grabbed toplevel to the new position. */
struct tinywl_toplevel *toplevel = server->grabbed_toplevel; struct tinywl_toplevel *toplevel = server->grabbed_toplevel;
wlr_scene_node_set_position(&toplevel->scene_tree->node, wlr_scene_node_set_position(&toplevel->scene->tree->node,
server->cursor->x - server->grab_x, server->cursor->x - server->grab_x,
server->cursor->y - server->grab_y); server->cursor->y - server->grab_y);
} }
@ -429,7 +429,7 @@ static void process_cursor_resize(struct tinywl_server *server, uint32_t time) {
struct wlr_box geo_box; struct wlr_box geo_box;
wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box); wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box);
wlr_scene_node_set_position(&toplevel->scene_tree->node, wlr_scene_node_set_position(&toplevel->scene->tree->node,
new_left - geo_box.x, new_top - geo_box.y); new_left - geo_box.x, new_top - geo_box.y);
int new_width = new_right - new_left; int new_width = new_right - new_left;
@ -724,22 +724,22 @@ static void begin_interactive(struct tinywl_toplevel *toplevel,
server->cursor_mode = mode; server->cursor_mode = mode;
if (mode == TINYWL_CURSOR_MOVE) { if (mode == TINYWL_CURSOR_MOVE) {
server->grab_x = server->cursor->x - toplevel->scene_tree->node.x; server->grab_x = server->cursor->x - toplevel->scene->tree->node.x;
server->grab_y = server->cursor->y - toplevel->scene_tree->node.y; server->grab_y = server->cursor->y - toplevel->scene->tree->node.y;
} else { } else {
struct wlr_box geo_box; struct wlr_box geo_box;
wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box); wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box);
double border_x = (toplevel->scene_tree->node.x + geo_box.x) + double border_x = (toplevel->scene->tree->node.x + geo_box.x) +
((edges & WLR_EDGE_RIGHT) ? geo_box.width : 0); ((edges & WLR_EDGE_RIGHT) ? geo_box.width : 0);
double border_y = (toplevel->scene_tree->node.y + geo_box.y) + double border_y = (toplevel->scene->tree->node.y + geo_box.y) +
((edges & WLR_EDGE_BOTTOM) ? geo_box.height : 0); ((edges & WLR_EDGE_BOTTOM) ? geo_box.height : 0);
server->grab_x = server->cursor->x - border_x; server->grab_x = server->cursor->x - border_x;
server->grab_y = server->cursor->y - border_y; server->grab_y = server->cursor->y - border_y;
server->grab_geobox = geo_box; server->grab_geobox = geo_box;
server->grab_geobox.x += toplevel->scene_tree->node.x; server->grab_geobox.x += toplevel->scene->tree->node.x;
server->grab_geobox.y += toplevel->scene_tree->node.y; server->grab_geobox.y += toplevel->scene->tree->node.y;
server->resize_edges = edges; server->resize_edges = edges;
} }
@ -803,10 +803,10 @@ static void server_new_xdg_toplevel(struct wl_listener *listener, void *data) {
struct tinywl_toplevel *toplevel = calloc(1, sizeof(*toplevel)); struct tinywl_toplevel *toplevel = calloc(1, sizeof(*toplevel));
toplevel->server = server; toplevel->server = server;
toplevel->xdg_toplevel = xdg_toplevel; toplevel->xdg_toplevel = xdg_toplevel;
toplevel->scene_tree = toplevel->scene =
wlr_scene_xdg_surface_create(&toplevel->server->scene->tree, xdg_toplevel->base); wlr_scene_xdg_surface_create(&toplevel->server->scene->tree, xdg_toplevel->base);
toplevel->scene_tree->node.data = toplevel; toplevel->scene->tree->node.data = toplevel;
xdg_toplevel->base->data = toplevel->scene_tree; xdg_toplevel->base->data = toplevel->scene->tree;
/* Listen to the various events it can emit */ /* Listen to the various events it can emit */
toplevel->map.notify = xdg_toplevel_map; toplevel->map.notify = xdg_toplevel_map;

View file

@ -5,7 +5,7 @@
struct wlr_scene_drag_icon { struct wlr_scene_drag_icon {
struct wlr_scene_tree *tree; struct wlr_scene_tree *tree;
struct wlr_scene_tree *surface_tree; struct wlr_scene_subsurface_tree *surface_tree;
struct wlr_drag_icon *drag_icon; struct wlr_drag_icon *drag_icon;
struct wl_listener tree_destroy; struct wl_listener tree_destroy;
@ -17,7 +17,7 @@ static void drag_icon_handle_surface_commit(struct wl_listener *listener, void *
struct wlr_scene_drag_icon *icon = struct wlr_scene_drag_icon *icon =
wl_container_of(listener, icon, drag_icon_surface_commit); wl_container_of(listener, icon, drag_icon_surface_commit);
struct wlr_surface *surface = icon->drag_icon->surface; struct wlr_surface *surface = icon->drag_icon->surface;
struct wlr_scene_node *node = &icon->surface_tree->node; struct wlr_scene_node *node = &icon->surface_tree->tree->node;
wlr_scene_node_set_position(node, wlr_scene_node_set_position(node,
node->x + surface->current.dx, node->y + surface->current.dy); node->x + surface->current.dx, node->y + surface->current.dy);
} }

View file

@ -142,9 +142,9 @@ struct wlr_scene_layer_surface_v1 *wlr_scene_layer_surface_v1_create(
return NULL; return NULL;
} }
struct wlr_scene_tree *surface_tree = wlr_scene_subsurface_tree_create( scene_layer_surface->surface_tree = wlr_scene_subsurface_tree_create(
scene_layer_surface->tree, layer_surface->surface); scene_layer_surface->tree, layer_surface->surface);
if (surface_tree == NULL) { if (scene_layer_surface->surface_tree == NULL) {
wlr_scene_node_destroy(&scene_layer_surface->tree->node); wlr_scene_node_destroy(&scene_layer_surface->tree->node);
free(scene_layer_surface); free(scene_layer_surface);
return NULL; return NULL;

View file

@ -11,22 +11,25 @@
* *
* `tree` contains `scene_surface` and one node per sub-surface. * `tree` contains `scene_surface` and one node per sub-surface.
*/ */
struct wlr_scene_subsurface_tree { struct wlr_scene_subsurface_tree_surface {
struct wlr_scene_tree *tree; struct wlr_scene_tree *tree;
struct wlr_surface *surface; struct wlr_surface *surface;
struct wlr_scene_surface *scene_surface; struct wlr_scene_surface *scene_surface;
struct wlr_scene_subsurface_tree *subsurface_tree;
struct wl_listener surface_destroy; struct wl_listener surface_destroy;
struct wl_listener surface_commit; struct wl_listener surface_commit;
struct wl_listener surface_map; struct wl_listener surface_map;
struct wl_listener surface_unmap; struct wl_listener surface_unmap;
struct wl_listener surface_new_subsurface; struct wl_listener surface_new_subsurface;
struct wl_listener scene_outputs_update;
struct wl_listener scene_destroy;
struct wlr_scene_subsurface_tree *parent; // NULL for the top-level surface struct wlr_scene_subsurface_tree_surface *parent; // NULL for the top-level surface
struct wlr_addon scene_addon;
struct wlr_box clip; struct wlr_box clip;
struct wl_list link;
bool is_visible;
// Only valid if the surface is a sub-surface // Only valid if the surface is a sub-surface
@ -35,38 +38,64 @@ struct wlr_scene_subsurface_tree {
struct wl_listener subsurface_destroy; struct wl_listener subsurface_destroy;
}; };
static void subsurface_tree_addon_destroy(struct wlr_addon *addon) { static void subsurface_tree_handle_update_visibility(
struct wlr_scene_subsurface_tree *subsurface_tree = struct wlr_scene_subsurface_tree_surface *tree, bool is_destroying) {
wl_container_of(addon, subsurface_tree, scene_addon); bool is_visible = tree->scene_surface->buffer->primary_output && !is_destroying;
if (is_visible && !tree->is_visible) {
tree->subsurface_tree->visible_surfaces++;
} else if (!is_visible && tree->is_visible) {
assert(tree->subsurface_tree->visible_surfaces > 0);
tree->subsurface_tree->visible_surfaces--;
}
tree->is_visible = is_visible;
bool is_tree_visible = tree->subsurface_tree->visible_surfaces > 0;
if (is_tree_visible != tree->subsurface_tree->is_visible) {
tree->subsurface_tree->is_visible = is_tree_visible;
wl_signal_emit_mutable(&tree->subsurface_tree->events.visibility, NULL);
}
}
static void subsurface_tree_handle_scene_destroy(struct wl_listener *listener, void *data) {
struct wlr_scene_subsurface_tree_surface *subsurface_tree =
wl_container_of(listener, subsurface_tree, scene_destroy);
subsurface_tree_handle_update_visibility(subsurface_tree, true);
// tree and scene_surface will be cleaned up by scene_node_finish // tree and scene_surface will be cleaned up by scene_node_finish
if (subsurface_tree->parent) { if (subsurface_tree->parent) {
wlr_addon_finish(&subsurface_tree->surface_addon); wlr_addon_finish(&subsurface_tree->surface_addon);
wl_list_remove(&subsurface_tree->subsurface_destroy.link); wl_list_remove(&subsurface_tree->subsurface_destroy.link);
} else {
free(subsurface_tree->subsurface_tree);
} }
wlr_addon_finish(&subsurface_tree->scene_addon);
wl_list_remove(&subsurface_tree->surface_destroy.link); wl_list_remove(&subsurface_tree->surface_destroy.link);
wl_list_remove(&subsurface_tree->surface_commit.link); wl_list_remove(&subsurface_tree->surface_commit.link);
wl_list_remove(&subsurface_tree->surface_map.link); wl_list_remove(&subsurface_tree->surface_map.link);
wl_list_remove(&subsurface_tree->surface_unmap.link); wl_list_remove(&subsurface_tree->surface_unmap.link);
wl_list_remove(&subsurface_tree->surface_new_subsurface.link); wl_list_remove(&subsurface_tree->surface_new_subsurface.link);
wl_list_remove(&subsurface_tree->scene_destroy.link);
wl_list_remove(&subsurface_tree->link);
free(subsurface_tree); free(subsurface_tree);
} }
static const struct wlr_addon_interface subsurface_tree_surface_addon_impl; static const struct wlr_addon_interface subsurface_tree_surface_addon_impl;
static struct wlr_scene_subsurface_tree *subsurface_tree_from_subsurface( static struct wlr_scene_subsurface_tree_surface *subsurface_tree_from_subsurface(
struct wlr_scene_subsurface_tree *parent, struct wlr_scene_subsurface_tree_surface *parent,
struct wlr_subsurface *subsurface) { struct wlr_subsurface *subsurface) {
struct wlr_addon *addon = wlr_addon_find(&subsurface->surface->addons, struct wlr_addon *addon = wlr_addon_find(&subsurface->surface->addons,
parent, &subsurface_tree_surface_addon_impl); parent, &subsurface_tree_surface_addon_impl);
assert(addon != NULL); assert(addon != NULL);
struct wlr_scene_subsurface_tree *subsurface_tree = struct wlr_scene_subsurface_tree_surface *subsurface_tree =
wl_container_of(addon, subsurface_tree, surface_addon); wl_container_of(addon, subsurface_tree, surface_addon);
return subsurface_tree; return subsurface_tree;
} }
static bool subsurface_tree_reconfigure_clip( static bool subsurface_tree_reconfigure_clip(
struct wlr_scene_subsurface_tree *subsurface_tree) { struct wlr_scene_subsurface_tree_surface *subsurface_tree) {
if (subsurface_tree->parent) { if (subsurface_tree->parent) {
subsurface_tree->clip = (struct wlr_box){ subsurface_tree->clip = (struct wlr_box){
.x = subsurface_tree->parent->clip.x - subsurface_tree->tree->node.x, .x = subsurface_tree->parent->clip.x - subsurface_tree->tree->node.x,
@ -102,7 +131,7 @@ static bool subsurface_tree_reconfigure_clip(
} }
static void subsurface_tree_reconfigure( static void subsurface_tree_reconfigure(
struct wlr_scene_subsurface_tree *subsurface_tree) { struct wlr_scene_subsurface_tree_surface *subsurface_tree) {
bool has_clip = subsurface_tree_reconfigure_clip(subsurface_tree); bool has_clip = subsurface_tree_reconfigure_clip(subsurface_tree);
struct wlr_surface *surface = subsurface_tree->surface; struct wlr_surface *surface = subsurface_tree->surface;
@ -111,7 +140,7 @@ static void subsurface_tree_reconfigure(
struct wlr_subsurface *subsurface; struct wlr_subsurface *subsurface;
wl_list_for_each(subsurface, &surface->current.subsurfaces_below, wl_list_for_each(subsurface, &surface->current.subsurfaces_below,
current.link) { current.link) {
struct wlr_scene_subsurface_tree *child = struct wlr_scene_subsurface_tree_surface *child =
subsurface_tree_from_subsurface(subsurface_tree, subsurface); subsurface_tree_from_subsurface(subsurface_tree, subsurface);
if (prev != NULL) { if (prev != NULL) {
wlr_scene_node_place_above(&child->tree->node, prev); wlr_scene_node_place_above(&child->tree->node, prev);
@ -133,7 +162,7 @@ static void subsurface_tree_reconfigure(
wl_list_for_each(subsurface, &surface->current.subsurfaces_above, wl_list_for_each(subsurface, &surface->current.subsurfaces_above,
current.link) { current.link) {
struct wlr_scene_subsurface_tree *child = struct wlr_scene_subsurface_tree_surface *child =
subsurface_tree_from_subsurface(subsurface_tree, subsurface); subsurface_tree_from_subsurface(subsurface_tree, subsurface);
wlr_scene_node_place_above(&child->tree->node, prev); wlr_scene_node_place_above(&child->tree->node, prev);
prev = &child->tree->node; prev = &child->tree->node;
@ -149,14 +178,14 @@ static void subsurface_tree_reconfigure(
static void subsurface_tree_handle_surface_destroy(struct wl_listener *listener, static void subsurface_tree_handle_surface_destroy(struct wl_listener *listener,
void *data) { void *data) {
struct wlr_scene_subsurface_tree *subsurface_tree = struct wlr_scene_subsurface_tree_surface *subsurface_tree =
wl_container_of(listener, subsurface_tree, surface_destroy); wl_container_of(listener, subsurface_tree, surface_destroy);
wlr_scene_node_destroy(&subsurface_tree->tree->node); wlr_scene_node_destroy(&subsurface_tree->tree->node);
} }
static void subsurface_tree_handle_surface_commit(struct wl_listener *listener, static void subsurface_tree_handle_surface_commit(struct wl_listener *listener,
void *data) { void *data) {
struct wlr_scene_subsurface_tree *subsurface_tree = struct wlr_scene_subsurface_tree_surface *subsurface_tree =
wl_container_of(listener, subsurface_tree, surface_commit); wl_container_of(listener, subsurface_tree, surface_commit);
// TODO: only do this on subsurface order or position change // TODO: only do this on subsurface order or position change
@ -165,14 +194,14 @@ static void subsurface_tree_handle_surface_commit(struct wl_listener *listener,
static void subsurface_tree_handle_subsurface_destroy(struct wl_listener *listener, static void subsurface_tree_handle_subsurface_destroy(struct wl_listener *listener,
void *data) { void *data) {
struct wlr_scene_subsurface_tree *subsurface_tree = struct wlr_scene_subsurface_tree_surface *subsurface_tree =
wl_container_of(listener, subsurface_tree, subsurface_destroy); wl_container_of(listener, subsurface_tree, subsurface_destroy);
wlr_scene_node_destroy(&subsurface_tree->tree->node); wlr_scene_node_destroy(&subsurface_tree->tree->node);
} }
static void subsurface_tree_handle_surface_map(struct wl_listener *listener, static void subsurface_tree_handle_surface_map(struct wl_listener *listener,
void *data) { void *data) {
struct wlr_scene_subsurface_tree *subsurface_tree = struct wlr_scene_subsurface_tree_surface *subsurface_tree =
wl_container_of(listener, subsurface_tree, surface_map); wl_container_of(listener, subsurface_tree, surface_map);
wlr_scene_node_set_enabled(&subsurface_tree->tree->node, true); wlr_scene_node_set_enabled(&subsurface_tree->tree->node, true);
@ -180,31 +209,32 @@ static void subsurface_tree_handle_surface_map(struct wl_listener *listener,
static void subsurface_tree_handle_surface_unmap(struct wl_listener *listener, static void subsurface_tree_handle_surface_unmap(struct wl_listener *listener,
void *data) { void *data) {
struct wlr_scene_subsurface_tree *subsurface_tree = struct wlr_scene_subsurface_tree_surface *subsurface_tree =
wl_container_of(listener, subsurface_tree, surface_unmap); wl_container_of(listener, subsurface_tree, surface_unmap);
wlr_scene_node_set_enabled(&subsurface_tree->tree->node, false); wlr_scene_node_set_enabled(&subsurface_tree->tree->node, false);
} }
static void subsurface_tree_surface_addon_destroy(struct wlr_addon *addon) { static void subsurface_tree_surface_addon_destroy(struct wlr_addon *addon) {
struct wlr_scene_subsurface_tree *subsurface_tree = struct wlr_scene_subsurface_tree_surface *subsurface_tree =
wl_container_of(addon, subsurface_tree, surface_addon); wl_container_of(addon, subsurface_tree, surface_addon);
wlr_scene_node_destroy(&subsurface_tree->tree->node); wlr_scene_node_destroy(&subsurface_tree->tree->node);
} }
static const struct wlr_addon_interface subsurface_tree_surface_addon_impl = { static const struct wlr_addon_interface subsurface_tree_surface_addon_impl = {
.name = "wlr_scene_subsurface_tree", .name = "wlr_scene_subsurface_tree_surface",
.destroy = subsurface_tree_surface_addon_destroy, .destroy = subsurface_tree_surface_addon_destroy,
}; };
static struct wlr_scene_subsurface_tree *scene_surface_tree_create( static struct wlr_scene_subsurface_tree_surface *scene_surface_tree_create_surface(
struct wlr_scene_subsurface_tree *tree,
struct wlr_scene_tree *parent, struct wlr_surface *surface); struct wlr_scene_tree *parent, struct wlr_surface *surface);
static bool subsurface_tree_create_subsurface( static bool subsurface_tree_create_subsurface(
struct wlr_scene_subsurface_tree *parent, struct wlr_scene_subsurface_tree_surface *parent,
struct wlr_subsurface *subsurface) { struct wlr_subsurface *subsurface) {
struct wlr_scene_subsurface_tree *child = scene_surface_tree_create( struct wlr_scene_subsurface_tree_surface *child = scene_surface_tree_create_surface(
parent->tree, subsurface->surface); parent->subsurface_tree, parent->tree, subsurface->surface);
if (child == NULL) { if (child == NULL) {
return false; return false;
} }
@ -222,7 +252,7 @@ static bool subsurface_tree_create_subsurface(
static void subsurface_tree_handle_surface_new_subsurface( static void subsurface_tree_handle_surface_new_subsurface(
struct wl_listener *listener, void *data) { struct wl_listener *listener, void *data) {
struct wlr_scene_subsurface_tree *subsurface_tree = struct wlr_scene_subsurface_tree_surface *subsurface_tree =
wl_container_of(listener, subsurface_tree, surface_new_subsurface); wl_container_of(listener, subsurface_tree, surface_new_subsurface);
struct wlr_subsurface *subsurface = data; struct wlr_subsurface *subsurface = data;
if (!subsurface_tree_create_subsurface(subsurface_tree, subsurface)) { if (!subsurface_tree_create_subsurface(subsurface_tree, subsurface)) {
@ -230,19 +260,23 @@ static void subsurface_tree_handle_surface_new_subsurface(
} }
} }
static const struct wlr_addon_interface subsurface_tree_addon_impl = { static void subsurface_tree_handle_scene_outputs_update(
.name = "wlr_scene_subsurface_tree", struct wl_listener *listener, void *data) {
.destroy = subsurface_tree_addon_destroy, struct wlr_scene_subsurface_tree_surface *subsurface_tree =
}; wl_container_of(listener, subsurface_tree, scene_outputs_update);
subsurface_tree_handle_update_visibility(subsurface_tree, false);
}
static struct wlr_scene_subsurface_tree *scene_surface_tree_create( static struct wlr_scene_subsurface_tree_surface *scene_surface_tree_create_surface(
struct wlr_scene_subsurface_tree *tree,
struct wlr_scene_tree *parent, struct wlr_surface *surface) { struct wlr_scene_tree *parent, struct wlr_surface *surface) {
struct wlr_scene_subsurface_tree *subsurface_tree = struct wlr_scene_subsurface_tree_surface *subsurface_tree =
calloc(1, sizeof(*subsurface_tree)); calloc(1, sizeof(*subsurface_tree));
if (subsurface_tree == NULL) { if (subsurface_tree == NULL) {
return NULL; return NULL;
} }
subsurface_tree->subsurface_tree = tree;
subsurface_tree->tree = wlr_scene_tree_create(parent); subsurface_tree->tree = wlr_scene_tree_create(parent);
if (subsurface_tree->tree == NULL) { if (subsurface_tree->tree == NULL) {
goto error_surface_tree; goto error_surface_tree;
@ -270,10 +304,15 @@ static struct wlr_scene_subsurface_tree *scene_surface_tree_create(
} }
} }
wl_list_insert(&tree->surfaces, &subsurface_tree->link);
subsurface_tree_reconfigure(subsurface_tree); subsurface_tree_reconfigure(subsurface_tree);
wlr_addon_init(&subsurface_tree->scene_addon, &subsurface_tree->tree->node.addons, subsurface_tree->scene_destroy.notify = subsurface_tree_handle_scene_destroy;
NULL, &subsurface_tree_addon_impl); wl_signal_add(&subsurface_tree->tree->node.events.destroy, &subsurface_tree->scene_destroy);
subsurface_tree->scene_outputs_update.notify = subsurface_tree_handle_scene_outputs_update;
wl_signal_add(&subsurface_tree->scene_surface->buffer->events.outputs_update,
&subsurface_tree->scene_outputs_update);
subsurface_tree->surface_destroy.notify = subsurface_tree_handle_surface_destroy; subsurface_tree->surface_destroy.notify = subsurface_tree_handle_surface_destroy;
wl_signal_add(&surface->events.destroy, &subsurface_tree->surface_destroy); wl_signal_add(&surface->events.destroy, &subsurface_tree->surface_destroy);
@ -293,6 +332,7 @@ static struct wlr_scene_subsurface_tree *scene_surface_tree_create(
&subsurface_tree->surface_new_subsurface); &subsurface_tree->surface_new_subsurface);
wlr_scene_node_set_enabled(&subsurface_tree->tree->node, surface->mapped); wlr_scene_node_set_enabled(&subsurface_tree->tree->node, surface->mapped);
subsurface_tree_handle_update_visibility(subsurface_tree, false);
return subsurface_tree; return subsurface_tree;
@ -303,68 +343,44 @@ error_surface_tree:
return NULL; return NULL;
} }
struct wlr_scene_tree *wlr_scene_subsurface_tree_create( struct wlr_scene_subsurface_tree *wlr_scene_subsurface_tree_create(
struct wlr_scene_tree *parent, struct wlr_surface *surface) { struct wlr_scene_tree *parent, struct wlr_surface *surface) {
struct wlr_scene_subsurface_tree *subsurface_tree = struct wlr_scene_subsurface_tree *subsurface_tree = calloc(1, sizeof(*subsurface_tree));
scene_surface_tree_create(parent, surface); if (!subsurface_tree) {
if (subsurface_tree == NULL) {
return NULL;
}
return subsurface_tree->tree;
}
static struct wlr_scene_subsurface_tree *get_subsurface_tree_from_node(
struct wlr_scene_node *node) {
struct wlr_addon *addon = wlr_addon_find(&node->addons, NULL, &subsurface_tree_addon_impl);
if (!addon) {
return NULL; return NULL;
} }
struct wlr_scene_subsurface_tree *tree = wl_list_init(&subsurface_tree->surfaces);
wl_container_of(addon, tree, scene_addon); wl_signal_init(&subsurface_tree->events.visibility);
return tree;
struct wlr_scene_subsurface_tree_surface *subsurface_tree_surface =
scene_surface_tree_create_surface(subsurface_tree, parent, surface);
if (subsurface_tree_surface == NULL) {
free(subsurface_tree);
return NULL;
}
subsurface_tree->root = subsurface_tree_surface;
subsurface_tree->tree = subsurface_tree_surface->tree;
return subsurface_tree;
} }
static bool subsurface_tree_set_clip(struct wlr_scene_node *node, void wlr_scene_subsurface_tree_set_clip(struct wlr_scene_subsurface_tree *tree,
const struct wlr_box *clip) { const struct wlr_box *clip) {
if (node->type != WLR_SCENE_NODE_TREE) { if (wlr_box_equal(&tree->root->clip, clip)) {
return false; return;
} }
bool discovered_subsurface_tree = false; if (clip) {
struct wlr_scene_subsurface_tree *tree = get_subsurface_tree_from_node(node); tree->root->clip = *clip;
if (tree) { } else {
if (tree->parent == NULL) { tree->root->clip = (struct wlr_box){0};
if (wlr_box_equal(&tree->clip, clip)) {
return true;
}
if (clip) {
tree->clip = *clip;
} else {
tree->clip = (struct wlr_box){0};
}
}
discovered_subsurface_tree = true;
subsurface_tree_reconfigure_clip(tree);
} }
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node); // iterate in reverse because children of parent subsurface will appear
struct wlr_scene_node *child; // earlier in the list.
wl_list_for_each(child, &scene_tree->children, link) { struct wlr_scene_subsurface_tree_surface *surface;
discovered_subsurface_tree |= subsurface_tree_set_clip(child, clip); wl_list_for_each_reverse(surface, &tree->surfaces, link) {
subsurface_tree_reconfigure_clip(surface);
} }
return discovered_subsurface_tree;
}
void wlr_scene_subsurface_tree_set_clip(struct wlr_scene_node *node,
const struct wlr_box *clip) {
#ifndef NDEBUG
bool found =
#endif
subsurface_tree_set_clip(node, clip);
assert(found);
} }

View file

@ -2,16 +2,6 @@
#include <wlr/types/wlr_scene.h> #include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_xdg_shell.h> #include <wlr/types/wlr_xdg_shell.h>
struct wlr_scene_xdg_surface {
struct wlr_scene_tree *tree;
struct wlr_xdg_surface *xdg_surface;
struct wlr_scene_tree *surface_tree;
struct wl_listener tree_destroy;
struct wl_listener xdg_surface_destroy;
struct wl_listener xdg_surface_commit;
};
static void scene_xdg_surface_handle_tree_destroy(struct wl_listener *listener, static void scene_xdg_surface_handle_tree_destroy(struct wl_listener *listener,
void *data) { void *data) {
struct wlr_scene_xdg_surface *scene_xdg_surface = struct wlr_scene_xdg_surface *scene_xdg_surface =
@ -36,7 +26,7 @@ static void scene_xdg_surface_update_position(
struct wlr_box geo = {0}; struct wlr_box geo = {0};
wlr_xdg_surface_get_geometry(xdg_surface, &geo); wlr_xdg_surface_get_geometry(xdg_surface, &geo);
wlr_scene_node_set_position(&scene_xdg_surface->surface_tree->node, wlr_scene_node_set_position(&scene_xdg_surface->surface_tree->tree->node,
-geo.x, -geo.y); -geo.x, -geo.y);
if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) {
@ -55,7 +45,7 @@ static void scene_xdg_surface_handle_xdg_surface_commit(struct wl_listener *list
scene_xdg_surface_update_position(scene_xdg_surface); scene_xdg_surface_update_position(scene_xdg_surface);
} }
struct wlr_scene_tree *wlr_scene_xdg_surface_create( struct wlr_scene_xdg_surface *wlr_scene_xdg_surface_create(
struct wlr_scene_tree *parent, struct wlr_xdg_surface *xdg_surface) { struct wlr_scene_tree *parent, struct wlr_xdg_surface *xdg_surface) {
struct wlr_scene_xdg_surface *scene_xdg_surface = struct wlr_scene_xdg_surface *scene_xdg_surface =
calloc(1, sizeof(*scene_xdg_surface)); calloc(1, sizeof(*scene_xdg_surface));
@ -95,5 +85,5 @@ struct wlr_scene_tree *wlr_scene_xdg_surface_create(
scene_xdg_surface_update_position(scene_xdg_surface); scene_xdg_surface_update_position(scene_xdg_surface);
return scene_xdg_surface->tree; return scene_xdg_surface;
} }