scene/output-layout: improve ownership logic

This commit ensures that outputs that weren't created by the output
layout helper aren't destroyed on the output layout change.

Consider the following piece of logic:

// struct wlr_output *o1, *o2;
// struct wlr_scene *scene;
// struct wlr_output_layout *layout;
wlr_scene_attach_output_layout(scene, layout);
wlr_output_layout_add_auto(layout, o1);
struct wlr_scene_output *so2 = wlr_scene_output_create(scene, o2);
wlr_output_layout_move(layout, o1, 100, 200);
// so2 is invalid now
This commit is contained in:
Kirill Primak 2022-05-31 21:40:03 +03:00 committed by Isaac Freund
parent d3bc17d5d1
commit 0c2eed533e
2 changed files with 80 additions and 36 deletions

View file

@ -406,8 +406,10 @@ struct wlr_scene_output *wlr_scene_get_scene_output(struct wlr_scene *scene,
/** /**
* Attach an output layout to a scene. * Attach an output layout to a scene.
* *
* Outputs in the output layout are automatically added to the scene. Any * Adding, removing, or repositioning an output in the output layout
* change to the output layout is mirrored to the scene-graph outputs. * will respectively add, remove or reposition a corresponding
* scene-graph output. When the output layout is destroyed, scene-graph
* outputs which were created by this helper will be destroyed.
*/ */
bool wlr_scene_attach_output_layout(struct wlr_scene *scene, bool wlr_scene_attach_output_layout(struct wlr_scene *scene,
struct wlr_output_layout *output_layout); struct wlr_output_layout *output_layout);

View file

@ -6,36 +6,58 @@ struct wlr_scene_output_layout {
struct wlr_output_layout *layout; struct wlr_output_layout *layout;
struct wlr_scene *scene; struct wlr_scene *scene;
struct wl_list outputs; // wlr_scene_output_layout_output.link
struct wl_listener layout_add; struct wl_listener layout_add;
struct wl_listener layout_change; struct wl_listener layout_change;
struct wl_listener layout_destroy; struct wl_listener layout_destroy;
struct wl_listener scene_destroy; struct wl_listener scene_destroy;
}; };
static void scene_output_layout_destroy(struct wlr_scene_output_layout *sol) { struct wlr_scene_output_layout_output {
wl_list_remove(&sol->layout_destroy.link); struct wlr_output_layout_output *layout_output;
wl_list_remove(&sol->layout_add.link); struct wlr_scene_output *scene_output;
wl_list_remove(&sol->layout_change.link);
wl_list_remove(&sol->scene_destroy.link); struct wl_list link; // wlr_scene_output_layout.outputs
free(sol);
struct wl_listener layout_output_destroy;
struct wl_listener scene_output_destroy;
};
static void scene_output_layout_output_destroy(
struct wlr_scene_output_layout_output *solo) {
wlr_scene_output_destroy(solo->scene_output);
wl_list_remove(&solo->layout_output_destroy.link);
wl_list_remove(&solo->scene_output_destroy.link);
wl_list_remove(&solo->link);
free(solo);
} }
static void scene_output_layout_handle_layout_destroy( static void scene_output_layout_output_handle_layout_output_destroy(
struct wl_listener *listener, void *data) { struct wl_listener *listener, void *data) {
struct wlr_scene_output_layout *sol = struct wlr_scene_output_layout_output *solo =
wl_container_of(listener, sol, layout_destroy); wl_container_of(listener, solo, layout_output_destroy);
scene_output_layout_output_destroy(solo);
}
// Remove all outputs managed by the output layout static void scene_output_layout_output_handle_scene_output_destroy(
struct wlr_scene_output *scene_output, *tmp; struct wl_listener *listener, void *data) {
wl_list_for_each_safe(scene_output, tmp, &sol->scene->outputs, link) { struct wlr_scene_output_layout_output *solo =
struct wlr_output_layout_output *lo = wl_container_of(listener, solo, scene_output_destroy);
wlr_output_layout_get(sol->layout, scene_output->output); solo->scene_output = NULL;
if (lo != NULL) { scene_output_layout_output_destroy(solo);
wlr_scene_output_destroy(scene_output); }
}
static void scene_output_layout_destroy(struct wlr_scene_output_layout *sol) {
struct wlr_scene_output_layout_output *solo, *tmp;
wl_list_for_each_safe(solo, tmp, &sol->outputs, link) {
scene_output_layout_output_destroy(solo);
} }
wl_list_remove(&sol->layout_add.link);
scene_output_layout_destroy(sol); wl_list_remove(&sol->layout_change.link);
wl_list_remove(&sol->layout_destroy.link);
wl_list_remove(&sol->scene_destroy.link);
free(sol);
} }
static void scene_output_layout_handle_layout_change( static void scene_output_layout_handle_layout_change(
@ -43,17 +65,10 @@ static void scene_output_layout_handle_layout_change(
struct wlr_scene_output_layout *sol = struct wlr_scene_output_layout *sol =
wl_container_of(listener, sol, layout_change); wl_container_of(listener, sol, layout_change);
struct wlr_scene_output *scene_output, *tmp; struct wlr_scene_output_layout_output *solo;
wl_list_for_each_safe(scene_output, tmp, &sol->scene->outputs, link) { wl_list_for_each(solo, &sol->outputs, link) {
struct wlr_output_layout_output *lo = wlr_scene_output_set_position(solo->scene_output,
wlr_output_layout_get(sol->layout, scene_output->output); solo->layout_output->x, solo->layout_output->y);
if (lo == NULL) {
// Output has been removed from the layout
wlr_scene_output_destroy(scene_output);
continue;
}
wlr_scene_output_set_position(scene_output, lo->x, lo->y);
} }
} }
@ -63,13 +78,38 @@ static void scene_output_layout_handle_layout_add(
wl_container_of(listener, sol, layout_add); wl_container_of(listener, sol, layout_add);
struct wlr_output_layout_output *lo = data; struct wlr_output_layout_output *lo = data;
struct wlr_scene_output *scene_output = struct wlr_scene_output_layout_output *solo = calloc(1, sizeof(*solo));
wlr_scene_output_create(sol->scene, lo->output); if (solo == NULL) {
if (scene_output == NULL) {
return; return;
} }
wlr_scene_output_set_position(scene_output, lo->x, lo->y); solo->scene_output = wlr_scene_output_create(sol->scene, lo->output);
if (solo->scene_output == NULL) {
free(solo);
return;
}
solo->layout_output = lo;
solo->layout_output_destroy.notify =
scene_output_layout_output_handle_layout_output_destroy;
wl_signal_add(&lo->events.destroy, &solo->layout_output_destroy);
solo->scene_output_destroy.notify =
scene_output_layout_output_handle_scene_output_destroy;
wl_signal_add(&solo->scene_output->events.destroy,
&solo->scene_output_destroy);
wl_list_insert(&sol->outputs, &solo->link);
wlr_scene_output_set_position(solo->scene_output, lo->x, lo->y);
}
static void scene_output_layout_handle_layout_destroy(
struct wl_listener *listener, void *data) {
struct wlr_scene_output_layout *sol =
wl_container_of(listener, sol, layout_destroy);
scene_output_layout_destroy(sol);
} }
static void scene_output_layout_handle_scene_destroy( static void scene_output_layout_handle_scene_destroy(
@ -89,6 +129,8 @@ bool wlr_scene_attach_output_layout(struct wlr_scene *scene,
sol->scene = scene; sol->scene = scene;
sol->layout = output_layout; sol->layout = output_layout;
wl_list_init(&sol->outputs);
sol->layout_destroy.notify = scene_output_layout_handle_layout_destroy; sol->layout_destroy.notify = scene_output_layout_handle_layout_destroy;
wl_signal_add(&output_layout->events.destroy, &sol->layout_destroy); wl_signal_add(&output_layout->events.destroy, &sol->layout_destroy);