scene: add wlr_scene_subsurface_tree_create
This commit is contained in:
		
							parent
							
								
									597ba2b932
								
							
						
					
					
						commit
						2e590026e9
					
				|  | @ -224,4 +224,11 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output); | |||
| bool wlr_scene_attach_output_layout(struct wlr_scene *scene, | ||||
| 	struct wlr_output_layout *output_layout); | ||||
| 
 | ||||
| /**
 | ||||
|  * Add a node displaying a surface and all of its sub-surfaces to the | ||||
|  * scene-graph. | ||||
|  */ | ||||
| struct wlr_scene_node *wlr_scene_subsurface_tree_create( | ||||
| 	struct wlr_scene_node *parent, struct wlr_surface *surface); | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ wlr_files += files( | |||
| 	'data_device/wlr_data_offer.c', | ||||
| 	'data_device/wlr_data_source.c', | ||||
| 	'data_device/wlr_drag.c', | ||||
| 	'scene/subsurface_tree.c', | ||||
| 	'scene/wlr_scene.c', | ||||
| 	'scene/output_layout.c', | ||||
| 	'seat/wlr_seat_keyboard.c', | ||||
|  |  | |||
|  | @ -0,0 +1,218 @@ | |||
| #include <assert.h> | ||||
| #include <stdlib.h> | ||||
| #include <wlr/types/wlr_scene.h> | ||||
| #include <wlr/util/addon.h> | ||||
| 
 | ||||
| /**
 | ||||
|  * A tree for a surface and all of its child sub-surfaces. | ||||
|  * | ||||
|  * `tree` contains `scene_surface` and one node per sub-surface. | ||||
|  */ | ||||
| struct wlr_scene_subsurface_tree { | ||||
| 	struct wlr_scene_tree *tree; | ||||
| 	struct wlr_surface *surface; | ||||
| 	struct wlr_scene_surface *scene_surface; | ||||
| 
 | ||||
| 	struct wlr_scene_subsurface_tree *parent; // NULL for the top-level surface
 | ||||
| 	struct wlr_addon surface_addon; // only set if there's a parent
 | ||||
| 
 | ||||
| 	struct wl_listener tree_destroy; | ||||
| 	struct wl_listener surface_destroy; | ||||
| 	struct wl_listener surface_commit; | ||||
| 	struct wl_listener surface_new_subsurface; | ||||
| }; | ||||
| 
 | ||||
| static void subsurface_tree_destroy(struct wlr_scene_subsurface_tree *subsurface_tree) { | ||||
| 	// tree and scene_surface will be cleaned up by scene_node_finish
 | ||||
| 	if (subsurface_tree->parent) { | ||||
| 		wlr_addon_finish(&subsurface_tree->surface_addon); | ||||
| 	} | ||||
| 	wl_list_remove(&subsurface_tree->tree_destroy.link); | ||||
| 	wl_list_remove(&subsurface_tree->surface_destroy.link); | ||||
| 	wl_list_remove(&subsurface_tree->surface_commit.link); | ||||
| 	wl_list_remove(&subsurface_tree->surface_new_subsurface.link); | ||||
| 	free(subsurface_tree); | ||||
| } | ||||
| 
 | ||||
| static void subsurface_tree_handle_tree_destroy(struct wl_listener *listener, | ||||
| 		void *data) { | ||||
| 	struct wlr_scene_subsurface_tree *subsurface_tree = | ||||
| 		wl_container_of(listener, subsurface_tree, tree_destroy); | ||||
| 	subsurface_tree_destroy(subsurface_tree); | ||||
| } | ||||
| 
 | ||||
| static void subsurface_tree_handle_surface_destroy(struct wl_listener *listener, | ||||
| 		void *data) { | ||||
| 	struct wlr_scene_subsurface_tree *subsurface_tree = | ||||
| 		wl_container_of(listener, subsurface_tree, surface_destroy); | ||||
| 	wlr_scene_node_destroy(&subsurface_tree->tree->node); | ||||
| } | ||||
| 
 | ||||
| static const struct wlr_addon_interface subsurface_tree_addon_impl; | ||||
| 
 | ||||
| static struct wlr_scene_subsurface_tree *subsurface_tree_from_subsurface( | ||||
| 		struct wlr_scene_subsurface_tree *parent, | ||||
| 		struct wlr_subsurface *subsurface) { | ||||
| 	struct wlr_addon *addon = wlr_addon_find(&subsurface->surface->addons, | ||||
| 		parent, &subsurface_tree_addon_impl); | ||||
| 	assert(addon != NULL); | ||||
| 	struct wlr_scene_subsurface_tree *subsurface_tree = | ||||
| 		wl_container_of(addon, subsurface_tree, surface_addon); | ||||
| 	return subsurface_tree; | ||||
| } | ||||
| 
 | ||||
| static void subsurface_tree_reconfigure( | ||||
| 		struct wlr_scene_subsurface_tree *subsurface_tree) { | ||||
| 	struct wlr_surface *surface = subsurface_tree->surface; | ||||
| 
 | ||||
| 	struct wlr_scene_node *prev = NULL; | ||||
| 	struct wlr_subsurface *subsurface; | ||||
| 	wl_list_for_each(subsurface, &surface->current.subsurfaces_below, | ||||
| 			current.link) { | ||||
| 		struct wlr_scene_subsurface_tree *child = | ||||
| 			subsurface_tree_from_subsurface(subsurface_tree, subsurface); | ||||
| 		if (prev != NULL) { | ||||
| 			wlr_scene_node_place_above(&child->tree->node, prev); | ||||
| 		} | ||||
| 		prev = &child->tree->node; | ||||
| 
 | ||||
| 		wlr_scene_node_set_position(&child->tree->node, | ||||
| 			subsurface->current.x, subsurface->current.y); | ||||
| 	} | ||||
| 
 | ||||
| 	if (prev != NULL) { | ||||
| 		wlr_scene_node_place_above(&subsurface_tree->scene_surface->node, prev); | ||||
| 	} | ||||
| 	prev = &subsurface_tree->scene_surface->node; | ||||
| 
 | ||||
| 	wl_list_for_each(subsurface, &surface->current.subsurfaces_above, | ||||
| 			current.link) { | ||||
| 		struct wlr_scene_subsurface_tree *child = | ||||
| 			subsurface_tree_from_subsurface(subsurface_tree, subsurface); | ||||
| 		wlr_scene_node_place_above(&child->tree->node, prev); | ||||
| 		prev = &child->tree->node; | ||||
| 
 | ||||
| 		wlr_scene_node_set_position(&child->tree->node, | ||||
| 			subsurface->current.x, subsurface->current.y); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void subsurface_tree_handle_surface_commit(struct wl_listener *listener, | ||||
| 		void *data) { | ||||
| 	struct wlr_scene_subsurface_tree *subsurface_tree = | ||||
| 		wl_container_of(listener, subsurface_tree, surface_commit); | ||||
| 
 | ||||
| 	// TODO: only do this on subsurface order or position change
 | ||||
| 	subsurface_tree_reconfigure(subsurface_tree); | ||||
| } | ||||
| 
 | ||||
| static void subsurface_tree_addon_destroy(struct wlr_addon *addon) { | ||||
| 	struct wlr_scene_subsurface_tree *subsurface_tree = | ||||
| 		wl_container_of(addon, subsurface_tree, surface_addon); | ||||
| 	wlr_scene_node_destroy(&subsurface_tree->tree->node); | ||||
| } | ||||
| 
 | ||||
| static const struct wlr_addon_interface subsurface_tree_addon_impl = { | ||||
| 	.name = "wlr_scene_subsurface_tree", | ||||
| 	.destroy = subsurface_tree_addon_destroy, | ||||
| }; | ||||
| 
 | ||||
| static struct wlr_scene_subsurface_tree *scene_surface_tree_create( | ||||
| 	struct wlr_scene_node *parent, struct wlr_surface *surface); | ||||
| 
 | ||||
| static bool subsurface_tree_create_subsurface( | ||||
| 		struct wlr_scene_subsurface_tree *parent, | ||||
| 		struct wlr_subsurface *subsurface) { | ||||
| 	struct wlr_scene_subsurface_tree *child = scene_surface_tree_create( | ||||
| 		&parent->tree->node, subsurface->surface); | ||||
| 	if (child == NULL) { | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	child->parent = parent; | ||||
| 	wlr_addon_init(&child->surface_addon, &subsurface->surface->addons, | ||||
| 		parent, &subsurface_tree_addon_impl); | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static void subsurface_tree_handle_surface_new_subsurface( | ||||
| 		struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_scene_subsurface_tree *subsurface_tree = | ||||
| 		wl_container_of(listener, subsurface_tree, surface_new_subsurface); | ||||
| 	struct wlr_subsurface *subsurface = data; | ||||
| 	if (!subsurface_tree_create_subsurface(subsurface_tree, subsurface)) { | ||||
| 		wl_resource_post_no_memory(subsurface->resource); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static struct wlr_scene_subsurface_tree *scene_surface_tree_create( | ||||
| 		struct wlr_scene_node *parent, struct wlr_surface *surface) { | ||||
| 	struct wlr_scene_subsurface_tree *subsurface_tree = | ||||
| 		calloc(1, sizeof(*subsurface_tree)); | ||||
| 	if (subsurface_tree == NULL) { | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	subsurface_tree->tree = wlr_scene_tree_create(parent); | ||||
| 	if (subsurface_tree->tree == NULL) { | ||||
| 		goto error_surface_tree; | ||||
| 	} | ||||
| 
 | ||||
| 	subsurface_tree->scene_surface = | ||||
| 		wlr_scene_surface_create(&subsurface_tree->tree->node, surface); | ||||
| 	if (subsurface_tree->scene_surface == NULL) { | ||||
| 		goto error_scene_surface; | ||||
| 	} | ||||
| 
 | ||||
| 	subsurface_tree->surface = surface; | ||||
| 
 | ||||
| 	struct wlr_subsurface *subsurface; | ||||
| 	wl_list_for_each(subsurface, &surface->current.subsurfaces_below, | ||||
| 			current.link) { | ||||
| 		if (!subsurface_tree_create_subsurface(subsurface_tree, subsurface)) { | ||||
| 			goto error_scene_surface; | ||||
| 		} | ||||
| 	} | ||||
| 	wl_list_for_each(subsurface, &surface->current.subsurfaces_above, | ||||
| 			current.link) { | ||||
| 		if (!subsurface_tree_create_subsurface(subsurface_tree, subsurface)) { | ||||
| 			goto error_scene_surface; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	subsurface_tree_reconfigure(subsurface_tree); | ||||
| 
 | ||||
| 	subsurface_tree->tree_destroy.notify = subsurface_tree_handle_tree_destroy; | ||||
| 	wl_signal_add(&subsurface_tree->tree->node.events.destroy, | ||||
| 		&subsurface_tree->tree_destroy); | ||||
| 
 | ||||
| 	subsurface_tree->surface_destroy.notify = subsurface_tree_handle_surface_destroy; | ||||
| 	wl_signal_add(&surface->events.destroy, &subsurface_tree->surface_destroy); | ||||
| 
 | ||||
| 	subsurface_tree->surface_commit.notify = subsurface_tree_handle_surface_commit; | ||||
| 	wl_signal_add(&surface->events.commit, &subsurface_tree->surface_commit); | ||||
| 
 | ||||
| 	subsurface_tree->surface_new_subsurface.notify = | ||||
| 		subsurface_tree_handle_surface_new_subsurface; | ||||
| 	wl_signal_add(&surface->events.new_subsurface, | ||||
| 		&subsurface_tree->surface_new_subsurface); | ||||
| 
 | ||||
| 	return subsurface_tree; | ||||
| 
 | ||||
| error_scene_surface: | ||||
| 	wlr_scene_node_destroy(&subsurface_tree->tree->node); | ||||
| error_surface_tree: | ||||
| 	free(subsurface_tree); | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| struct wlr_scene_node *wlr_scene_subsurface_tree_create( | ||||
| 		struct wlr_scene_node *parent, struct wlr_surface *surface) { | ||||
| 	struct wlr_scene_subsurface_tree *subsurface_tree = | ||||
| 		scene_surface_tree_create(parent, surface); | ||||
| 	if (subsurface_tree == NULL) { | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	return &subsurface_tree->tree->node; | ||||
| } | ||||
		Loading…
	
		Reference in New Issue