mirror of
				https://gitlab.freedesktop.org/wlroots/wlroots.git
				synced 2025-11-03 09:01:40 -05:00 
			
		
		
		
	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:
		
							parent
							
								
									d3bc17d5d1
								
							
						
					
					
						commit
						0c2eed533e
					
				
					 2 changed files with 80 additions and 36 deletions
				
			
		| 
						 | 
					@ -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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
					}
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	scene_output_layout_destroy(sol);
 | 
					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);
 | 
				
			||||||
 | 
						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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue