Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 2e59002

Browse files
emersionifreund
authored andcommitted
scene: add wlr_scene_subsurface_tree_create
1 parent 597ba2b commit 2e59002

File tree

3 files changed

+226
-0
lines changed

3 files changed

+226
-0
lines changed

include/wlr/types/wlr_scene.h

+7
Original file line numberDiff line numberDiff line change
@@ -224,4 +224,11 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output);
224224
bool wlr_scene_attach_output_layout(struct wlr_scene *scene,
225225
struct wlr_output_layout *output_layout);
226226

227+
/**
228+
* Add a node displaying a surface and all of its sub-surfaces to the
229+
* scene-graph.
230+
*/
231+
struct wlr_scene_node *wlr_scene_subsurface_tree_create(
232+
struct wlr_scene_node *parent, struct wlr_surface *surface);
233+
227234
#endif

types/meson.build

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ wlr_files += files(
33
'data_device/wlr_data_offer.c',
44
'data_device/wlr_data_source.c',
55
'data_device/wlr_drag.c',
6+
'scene/subsurface_tree.c',
67
'scene/wlr_scene.c',
78
'scene/output_layout.c',
89
'seat/wlr_seat_keyboard.c',

types/scene/subsurface_tree.c

+218
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
#include <wlr/types/wlr_scene.h>
4+
#include <wlr/util/addon.h>
5+
6+
/**
7+
* A tree for a surface and all of its child sub-surfaces.
8+
*
9+
* `tree` contains `scene_surface` and one node per sub-surface.
10+
*/
11+
struct wlr_scene_subsurface_tree {
12+
struct wlr_scene_tree *tree;
13+
struct wlr_surface *surface;
14+
struct wlr_scene_surface *scene_surface;
15+
16+
struct wlr_scene_subsurface_tree *parent; // NULL for the top-level surface
17+
struct wlr_addon surface_addon; // only set if there's a parent
18+
19+
struct wl_listener tree_destroy;
20+
struct wl_listener surface_destroy;
21+
struct wl_listener surface_commit;
22+
struct wl_listener surface_new_subsurface;
23+
};
24+
25+
static void subsurface_tree_destroy(struct wlr_scene_subsurface_tree *subsurface_tree) {
26+
// tree and scene_surface will be cleaned up by scene_node_finish
27+
if (subsurface_tree->parent) {
28+
wlr_addon_finish(&subsurface_tree->surface_addon);
29+
}
30+
wl_list_remove(&subsurface_tree->tree_destroy.link);
31+
wl_list_remove(&subsurface_tree->surface_destroy.link);
32+
wl_list_remove(&subsurface_tree->surface_commit.link);
33+
wl_list_remove(&subsurface_tree->surface_new_subsurface.link);
34+
free(subsurface_tree);
35+
}
36+
37+
static void subsurface_tree_handle_tree_destroy(struct wl_listener *listener,
38+
void *data) {
39+
struct wlr_scene_subsurface_tree *subsurface_tree =
40+
wl_container_of(listener, subsurface_tree, tree_destroy);
41+
subsurface_tree_destroy(subsurface_tree);
42+
}
43+
44+
static void subsurface_tree_handle_surface_destroy(struct wl_listener *listener,
45+
void *data) {
46+
struct wlr_scene_subsurface_tree *subsurface_tree =
47+
wl_container_of(listener, subsurface_tree, surface_destroy);
48+
wlr_scene_node_destroy(&subsurface_tree->tree->node);
49+
}
50+
51+
static const struct wlr_addon_interface subsurface_tree_addon_impl;
52+
53+
static struct wlr_scene_subsurface_tree *subsurface_tree_from_subsurface(
54+
struct wlr_scene_subsurface_tree *parent,
55+
struct wlr_subsurface *subsurface) {
56+
struct wlr_addon *addon = wlr_addon_find(&subsurface->surface->addons,
57+
parent, &subsurface_tree_addon_impl);
58+
assert(addon != NULL);
59+
struct wlr_scene_subsurface_tree *subsurface_tree =
60+
wl_container_of(addon, subsurface_tree, surface_addon);
61+
return subsurface_tree;
62+
}
63+
64+
static void subsurface_tree_reconfigure(
65+
struct wlr_scene_subsurface_tree *subsurface_tree) {
66+
struct wlr_surface *surface = subsurface_tree->surface;
67+
68+
struct wlr_scene_node *prev = NULL;
69+
struct wlr_subsurface *subsurface;
70+
wl_list_for_each(subsurface, &surface->current.subsurfaces_below,
71+
current.link) {
72+
struct wlr_scene_subsurface_tree *child =
73+
subsurface_tree_from_subsurface(subsurface_tree, subsurface);
74+
if (prev != NULL) {
75+
wlr_scene_node_place_above(&child->tree->node, prev);
76+
}
77+
prev = &child->tree->node;
78+
79+
wlr_scene_node_set_position(&child->tree->node,
80+
subsurface->current.x, subsurface->current.y);
81+
}
82+
83+
if (prev != NULL) {
84+
wlr_scene_node_place_above(&subsurface_tree->scene_surface->node, prev);
85+
}
86+
prev = &subsurface_tree->scene_surface->node;
87+
88+
wl_list_for_each(subsurface, &surface->current.subsurfaces_above,
89+
current.link) {
90+
struct wlr_scene_subsurface_tree *child =
91+
subsurface_tree_from_subsurface(subsurface_tree, subsurface);
92+
wlr_scene_node_place_above(&child->tree->node, prev);
93+
prev = &child->tree->node;
94+
95+
wlr_scene_node_set_position(&child->tree->node,
96+
subsurface->current.x, subsurface->current.y);
97+
}
98+
}
99+
100+
static void subsurface_tree_handle_surface_commit(struct wl_listener *listener,
101+
void *data) {
102+
struct wlr_scene_subsurface_tree *subsurface_tree =
103+
wl_container_of(listener, subsurface_tree, surface_commit);
104+
105+
// TODO: only do this on subsurface order or position change
106+
subsurface_tree_reconfigure(subsurface_tree);
107+
}
108+
109+
static void subsurface_tree_addon_destroy(struct wlr_addon *addon) {
110+
struct wlr_scene_subsurface_tree *subsurface_tree =
111+
wl_container_of(addon, subsurface_tree, surface_addon);
112+
wlr_scene_node_destroy(&subsurface_tree->tree->node);
113+
}
114+
115+
static const struct wlr_addon_interface subsurface_tree_addon_impl = {
116+
.name = "wlr_scene_subsurface_tree",
117+
.destroy = subsurface_tree_addon_destroy,
118+
};
119+
120+
static struct wlr_scene_subsurface_tree *scene_surface_tree_create(
121+
struct wlr_scene_node *parent, struct wlr_surface *surface);
122+
123+
static bool subsurface_tree_create_subsurface(
124+
struct wlr_scene_subsurface_tree *parent,
125+
struct wlr_subsurface *subsurface) {
126+
struct wlr_scene_subsurface_tree *child = scene_surface_tree_create(
127+
&parent->tree->node, subsurface->surface);
128+
if (child == NULL) {
129+
return false;
130+
}
131+
132+
child->parent = parent;
133+
wlr_addon_init(&child->surface_addon, &subsurface->surface->addons,
134+
parent, &subsurface_tree_addon_impl);
135+
136+
return true;
137+
}
138+
139+
static void subsurface_tree_handle_surface_new_subsurface(
140+
struct wl_listener *listener, void *data) {
141+
struct wlr_scene_subsurface_tree *subsurface_tree =
142+
wl_container_of(listener, subsurface_tree, surface_new_subsurface);
143+
struct wlr_subsurface *subsurface = data;
144+
if (!subsurface_tree_create_subsurface(subsurface_tree, subsurface)) {
145+
wl_resource_post_no_memory(subsurface->resource);
146+
}
147+
}
148+
149+
static struct wlr_scene_subsurface_tree *scene_surface_tree_create(
150+
struct wlr_scene_node *parent, struct wlr_surface *surface) {
151+
struct wlr_scene_subsurface_tree *subsurface_tree =
152+
calloc(1, sizeof(*subsurface_tree));
153+
if (subsurface_tree == NULL) {
154+
return NULL;
155+
}
156+
157+
subsurface_tree->tree = wlr_scene_tree_create(parent);
158+
if (subsurface_tree->tree == NULL) {
159+
goto error_surface_tree;
160+
}
161+
162+
subsurface_tree->scene_surface =
163+
wlr_scene_surface_create(&subsurface_tree->tree->node, surface);
164+
if (subsurface_tree->scene_surface == NULL) {
165+
goto error_scene_surface;
166+
}
167+
168+
subsurface_tree->surface = surface;
169+
170+
struct wlr_subsurface *subsurface;
171+
wl_list_for_each(subsurface, &surface->current.subsurfaces_below,
172+
current.link) {
173+
if (!subsurface_tree_create_subsurface(subsurface_tree, subsurface)) {
174+
goto error_scene_surface;
175+
}
176+
}
177+
wl_list_for_each(subsurface, &surface->current.subsurfaces_above,
178+
current.link) {
179+
if (!subsurface_tree_create_subsurface(subsurface_tree, subsurface)) {
180+
goto error_scene_surface;
181+
}
182+
}
183+
184+
subsurface_tree_reconfigure(subsurface_tree);
185+
186+
subsurface_tree->tree_destroy.notify = subsurface_tree_handle_tree_destroy;
187+
wl_signal_add(&subsurface_tree->tree->node.events.destroy,
188+
&subsurface_tree->tree_destroy);
189+
190+
subsurface_tree->surface_destroy.notify = subsurface_tree_handle_surface_destroy;
191+
wl_signal_add(&surface->events.destroy, &subsurface_tree->surface_destroy);
192+
193+
subsurface_tree->surface_commit.notify = subsurface_tree_handle_surface_commit;
194+
wl_signal_add(&surface->events.commit, &subsurface_tree->surface_commit);
195+
196+
subsurface_tree->surface_new_subsurface.notify =
197+
subsurface_tree_handle_surface_new_subsurface;
198+
wl_signal_add(&surface->events.new_subsurface,
199+
&subsurface_tree->surface_new_subsurface);
200+
201+
return subsurface_tree;
202+
203+
error_scene_surface:
204+
wlr_scene_node_destroy(&subsurface_tree->tree->node);
205+
error_surface_tree:
206+
free(subsurface_tree);
207+
return NULL;
208+
}
209+
210+
struct wlr_scene_node *wlr_scene_subsurface_tree_create(
211+
struct wlr_scene_node *parent, struct wlr_surface *surface) {
212+
struct wlr_scene_subsurface_tree *subsurface_tree =
213+
scene_surface_tree_create(parent, surface);
214+
if (subsurface_tree == NULL) {
215+
return NULL;
216+
}
217+
return &subsurface_tree->tree->node;
218+
}

0 commit comments

Comments
 (0)