diff options
| author | Alexander Orzechowski <alex@ozal.ski> | 2024-01-18 10:04:51 -0500 | 
|---|---|---|
| committer | Kirill Primak <vyivel@eclair.cafe> | 2024-01-18 18:36:54 +0300 | 
| commit | 188811f80861caacd016b857b0d07f6d2d62d15a (patch) | |
| tree | dc68ea00b707b25ce398c71fe1ad996f0eb820ea /sway | |
| parent | 5b8b505af5d5925ae9e617ee8f3c7a0f9c43409d (diff) | |
| download | sway-188811f80861caacd016b857b0d07f6d2d62d15a.tar.xz | |
scene_graph: Port layer_shell
Diffstat (limited to 'sway')
| -rw-r--r-- | sway/desktop/layer_shell.c | 720 | ||||
| -rw-r--r-- | sway/desktop/output.c | 85 | ||||
| -rw-r--r-- | sway/input/cursor.c | 6 | ||||
| -rw-r--r-- | sway/tree/output.c | 13 | ||||
| -rw-r--r-- | sway/tree/root.c | 5 | 
5 files changed, 237 insertions, 592 deletions
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 6480d7ce..a52d27fa 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -6,6 +6,7 @@  #include <wlr/types/wlr_output.h>  #include <wlr/types/wlr_subcompositor.h>  #include "log.h" +#include "sway/scene_descriptor.h"  #include "sway/desktop/transaction.h"  #include "sway/input/cursor.h"  #include "sway/input/input-manager.h" @@ -16,6 +17,7 @@  #include "sway/surface.h"  #include "sway/tree/arrange.h"  #include "sway/tree/workspace.h" +#include <wlr/types/wlr_scene.h>  struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(  		struct wlr_surface *surface) { @@ -50,165 +52,22 @@ struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(  	} while (true);  } -static void apply_exclusive(struct wlr_box *usable_area, -		uint32_t anchor, int32_t exclusive, -		int32_t margin_top, int32_t margin_right, -		int32_t margin_bottom, int32_t margin_left) { -	if (exclusive <= 0) { -		return; -	} -	struct { -		uint32_t singular_anchor; -		uint32_t anchor_triplet; -		int *positive_axis; -		int *negative_axis; -		int margin; -	} edges[] = { -		// Top -		{ -			.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, -			.anchor_triplet = -				ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | -				ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | -				ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, -			.positive_axis = &usable_area->y, -			.negative_axis = &usable_area->height, -			.margin = margin_top, -		}, -		// Bottom -		{ -			.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, -			.anchor_triplet = -				ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | -				ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | -				ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, -			.positive_axis = NULL, -			.negative_axis = &usable_area->height, -			.margin = margin_bottom, -		}, -		// Left -		{ -			.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT, -			.anchor_triplet = -				ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | -				ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | -				ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, -			.positive_axis = &usable_area->x, -			.negative_axis = &usable_area->width, -			.margin = margin_left, -		}, -		// Right -		{ -			.singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, -			.anchor_triplet = -				ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | -				ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | -				ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, -			.positive_axis = NULL, -			.negative_axis = &usable_area->width, -			.margin = margin_right, -		}, -	}; -	for (size_t i = 0; i < sizeof(edges) / sizeof(edges[0]); ++i) { -		if ((anchor  == edges[i].singular_anchor || anchor == edges[i].anchor_triplet) -				&& exclusive + edges[i].margin > 0) { -			if (edges[i].positive_axis) { -				*edges[i].positive_axis += exclusive + edges[i].margin; -			} -			if (edges[i].negative_axis) { -				*edges[i].negative_axis -= exclusive + edges[i].margin; -			} -			break; +static void arrange_surface(struct sway_output *output, const struct wlr_box *full_area, +		struct wlr_box *usable_area, struct wlr_scene_tree *tree) { +	struct wlr_scene_node *node; +	wl_list_for_each(node, &tree->children, link) { +		struct sway_layer_surface *surface = scene_descriptor_try_get(node, +			SWAY_SCENE_DESC_LAYER_SHELL); +		// surface could be null during destruction +		if (!surface) { +			continue;  		} -	} -} -static void arrange_layer(struct sway_output *output, struct wl_list *list, -		struct wlr_box *usable_area, bool exclusive) { -	struct sway_layer_surface *sway_layer; -	struct wlr_box full_area = { 0 }; -	wlr_output_effective_resolution(output->wlr_output, -			&full_area.width, &full_area.height); -	wl_list_for_each(sway_layer, list, link) { -		struct wlr_layer_surface_v1 *layer = sway_layer->layer_surface; -		if (!layer->initialized) { +		if (!surface->scene->layer_surface->initialized) {  			return;  		} -		struct wlr_layer_surface_v1_state *state = &layer->current; -		if (exclusive != (state->exclusive_zone > 0)) { -			continue; -		} -		struct wlr_box bounds; -		if (state->exclusive_zone == -1) { -			bounds = full_area; -		} else { -			bounds = *usable_area; -		} -		struct wlr_box box = { -			.width = state->desired_width, -			.height = state->desired_height -		}; -		// Horizontal axis -		const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT -			| ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; -		if (box.width == 0) { -			box.x = bounds.x; -		} else if ((state->anchor & both_horiz) == both_horiz) { -			box.x = bounds.x + ((bounds.width / 2) - (box.width / 2)); -		} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { -			box.x = bounds.x; -		} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { -			box.x = bounds.x + (bounds.width - box.width); -		} else { -			box.x = bounds.x + ((bounds.width / 2) - (box.width / 2)); -		} -		// Vertical axis -		const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP -			| ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; -		if (box.height == 0) { -			box.y = bounds.y; -		} else if ((state->anchor & both_vert) == both_vert) { -			box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); -		} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { -			box.y = bounds.y; -		} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { -			box.y = bounds.y + (bounds.height - box.height); -		} else { -			box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); -		} -		// Margin -		if (box.width == 0) { -			box.x += state->margin.left; -			box.width = bounds.width - -				(state->margin.left + state->margin.right); -		} else if ((state->anchor & both_horiz) == both_horiz) { -			// don't apply margins -		} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { -			box.x += state->margin.left; -		} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { -			box.x -= state->margin.right; -		} -		if (box.height == 0) { -			box.y += state->margin.top; -			box.height = bounds.height - -				(state->margin.top + state->margin.bottom); -		} else if ((state->anchor & both_vert) == both_vert) { -			// don't apply margins -		} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { -			box.y += state->margin.top; -		} else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { -			box.y -= state->margin.bottom; -		} -		if (!sway_assert(box.width >= 0 && box.height >= 0, -				"Expected layer surface to have positive size")) { -			continue; -		} -		// Apply -		sway_layer->geo = box; -		apply_exclusive(usable_area, state->anchor, state->exclusive_zone, -				state->margin.top, state->margin.right, -				state->margin.bottom, state->margin.left); -		wlr_layer_surface_v1_configure(layer, box.width, box.height); + +		wlr_scene_layer_surface_v1_configure(surface->scene, full_area, usable_area);  	}  } @@ -216,83 +75,78 @@ void arrange_layers(struct sway_output *output) {  	struct wlr_box usable_area = { 0 };  	wlr_output_effective_resolution(output->wlr_output,  			&usable_area.width, &usable_area.height); +	const struct wlr_box full_area = usable_area; -	// Arrange exclusive surfaces from top->bottom -	arrange_layer(output, &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], -			&usable_area, true); -	arrange_layer(output, &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], -			&usable_area, true); -	arrange_layer(output, &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], -			&usable_area, true); -	arrange_layer(output, &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], -			&usable_area, true); - -	if (memcmp(&usable_area, &output->usable_area, -				sizeof(struct wlr_box)) != 0) { +	arrange_surface(output, &full_area, &usable_area, output->layers.shell_background); +	arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom); +	arrange_surface(output, &full_area, &usable_area, output->layers.shell_top); +	arrange_surface(output, &full_area, &usable_area, output->layers.shell_overlay); + +	if (!wlr_box_equal(&usable_area, &output->usable_area)) {  		sway_log(SWAY_DEBUG, "Usable area changed, rearranging output"); -		memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box)); +		output->usable_area = usable_area;  		arrange_output(output);  	} +} -	// Arrange non-exclusive surfaces from top->bottom -	arrange_layer(output, &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], -			&usable_area, false); -	arrange_layer(output, &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], -			&usable_area, false); -	arrange_layer(output, &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], -			&usable_area, false); -	arrange_layer(output, &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], -			&usable_area, false); - -	// Find topmost keyboard interactive layer, if such a layer exists -	uint32_t layers_above_shell[] = { -		ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, -		ZWLR_LAYER_SHELL_V1_LAYER_TOP, -	}; -	size_t nlayers = sizeof(layers_above_shell) / sizeof(layers_above_shell[0]); -	struct sway_layer_surface *layer, *topmost = NULL; -	for (size_t i = 0; i < nlayers; ++i) { -		wl_list_for_each_reverse(layer, -				&output->shell_layers[layers_above_shell[i]], link) { -			if (layer->layer_surface->current.keyboard_interactive && -					layer->layer_surface->surface->mapped) { -				topmost = layer; -				break; -			} -		} -		if (topmost != NULL) { -			break; -		} +static struct wlr_scene_tree *sway_layer_get_scene(struct sway_output *output, +		enum zwlr_layer_shell_v1_layer type) { +	switch (type) { +	case ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND: +		return output->layers.shell_background; +	case ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM: +		return output->layers.shell_bottom; +	case ZWLR_LAYER_SHELL_V1_LAYER_TOP: +		return output->layers.shell_top; +	case ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY: +		return output->layers.shell_overlay;  	} -	struct sway_seat *seat; -	wl_list_for_each(seat, &server.input->seats, link) { -		seat->has_exclusive_layer = false; -		if (topmost != NULL) { -			seat_set_focus_layer(seat, topmost->layer_surface); -		} else if (seat->focused_layer && -				seat->focused_layer->current.keyboard_interactive -					!= ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) { -			seat_set_focus_layer(seat, NULL); -		} +	sway_assert(false, "unreachable"); +	return NULL; +} + +static struct sway_layer_surface *sway_layer_surface_create( +		struct wlr_scene_layer_surface_v1 *scene) { +	struct sway_layer_surface *surface = calloc(1, sizeof(*surface)); +	if (!surface) { +		sway_log(SWAY_ERROR, "Could not allocate a scene_layer surface"); +		return NULL;  	} + +	struct wlr_scene_tree *popups = wlr_scene_tree_create(root->layers.popup); +	if (!popups) { +		sway_log(SWAY_ERROR, "Could not allocate a scene_layer popup node"); +		free(surface); +		return NULL; +	} + +	surface->tree = scene->tree; +	surface->scene = scene; +	surface->layer_surface = scene->layer_surface; +	surface->popups = popups; + +	return surface;  }  static struct sway_layer_surface *find_mapped_layer_by_client( -		struct wl_client *client, struct wlr_output *ignore_output) { +		struct wl_client *client, struct sway_output *ignore_output) {  	for (int i = 0; i < root->outputs->length; ++i) {  		struct sway_output *output = root->outputs->items[i]; -		if (output->wlr_output == ignore_output) { +		if (output == ignore_output) {  			continue;  		}  		// For now we'll only check the overlay layer -		struct sway_layer_surface *lsurface; -		wl_list_for_each(lsurface, -				&output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], link) { -			struct wl_resource *resource = lsurface->layer_surface->resource; +		struct wlr_scene_node *node; +		wl_list_for_each (node, &output->layers.shell_overlay->children, link) { +			struct sway_layer_surface *surface = scene_descriptor_try_get(node, +				SWAY_SCENE_DESC_LAYER_SHELL); + +			struct wlr_layer_surface_v1 *layer_surface = surface->layer_surface; +			struct wl_resource *resource = layer_surface->resource;  			if (wl_resource_get_client(resource) == client -					&& lsurface->layer_surface->surface->mapped) { -				return lsurface; +					&& layer_surface->surface->mapped) { +				return surface;  			}  		}  	} @@ -300,262 +154,144 @@ static struct sway_layer_surface *find_mapped_layer_by_client(  }  static void handle_output_destroy(struct wl_listener *listener, void *data) { -	struct sway_layer_surface *sway_layer = -		wl_container_of(listener, sway_layer, output_destroy); +	struct sway_layer_surface *layer = +		wl_container_of(listener, layer, output_destroy); + +	layer->output = NULL; +	wlr_scene_node_destroy(&layer->scene->tree->node); +} + +static void handle_node_destroy(struct wl_listener *listener, void *data) { +	struct sway_layer_surface *layer = +		wl_container_of(listener, layer, node_destroy); + +	// destroy the scene descriptor straight away if it exists, otherwise +	// we will try to reflow still considering the destroyed node. +	scene_descriptor_destroy(&layer->tree->node, SWAY_SCENE_DESC_LAYER_SHELL); +  	// Determine if this layer is being used by an exclusive client. If it is,  	// try and find another layer owned by this client to pass focus to.  	struct sway_seat *seat = input_manager_get_default_seat();  	struct wl_client *client = -		wl_resource_get_client(sway_layer->layer_surface->resource); - -	if (!server.session_lock.locked) { -		struct sway_layer_surface *layer = -			find_mapped_layer_by_client(client, sway_layer->layer_surface->output); -		if (layer) { -			seat_set_focus_layer(seat, layer->layer_surface); +		wl_resource_get_client(layer->layer_surface->resource); +	if (!server.session_lock.lock) { +		struct sway_layer_surface *consider_layer = +			find_mapped_layer_by_client(client, layer->output); +		if (consider_layer) { +			seat_set_focus_layer(seat, consider_layer->layer_surface);  		}  	} -	wlr_layer_surface_v1_destroy(sway_layer->layer_surface); +	if (layer->output) { +		arrange_layers(layer->output); +		transaction_commit_dirty(); +	} + +	wlr_scene_node_destroy(&layer->popups->node); + +	wl_list_remove(&layer->map.link); +	wl_list_remove(&layer->unmap.link); +	wl_list_remove(&layer->surface_commit.link); +	wl_list_remove(&layer->node_destroy.link); +	wl_list_remove(&layer->output_destroy.link); + +	free(layer);  }  static void handle_surface_commit(struct wl_listener *listener, void *data) { -	struct sway_layer_surface *layer = -		wl_container_of(listener, layer, surface_commit); -	struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface; -	struct wlr_output *wlr_output = layer_surface->output; -	sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); -	struct sway_output *output = wlr_output->data; - -	if (layer_surface->initial_commit) { -		surface_enter_output(layer_surface->surface, output); -	} else if (!layer_surface->initialized) { +	struct sway_layer_surface *surface = +		wl_container_of(listener, surface, surface_commit); + +	struct wlr_layer_surface_v1 *layer_surface = surface->layer_surface; +	if (!layer_surface->initialized) {  		return;  	} -	struct wlr_box old_extent = layer->extent; - -	bool layer_changed = false; -	if (layer_surface->initial_commit || layer_surface->current.committed != 0 -			|| layer->mapped != layer_surface->surface->mapped) { -		layer->mapped = layer_surface->surface->mapped; -		layer_changed = layer->layer != layer_surface->current.layer; -		if (layer_changed) { -			wl_list_remove(&layer->link); -			wl_list_insert(&output->shell_layers[layer_surface->current.layer], -				&layer->link); -			layer->layer = layer_surface->current.layer; -		} -		arrange_layers(output); +	uint32_t committed = layer_surface->current.committed; +	if (committed & WLR_LAYER_SURFACE_V1_STATE_LAYER) { +		enum zwlr_layer_shell_v1_layer layer_type = layer_surface->current.layer; +		struct wlr_scene_tree *output_layer = sway_layer_get_scene( +			surface->output, layer_type); +		wlr_scene_node_reparent(&surface->scene->tree->node, output_layer);  	} -	wlr_surface_get_extends(layer_surface->surface, &layer->extent); -	layer->extent.x += layer->geo.x; -	layer->extent.y += layer->geo.y; - -	bool extent_changed = -		memcmp(&old_extent, &layer->extent, sizeof(struct wlr_box)) != 0; -	if (extent_changed || layer_changed) { -		old_extent.x += output->lx; -		old_extent.y += output->ly; -		output_damage_box(output, &old_extent); -		output_damage_surface(output, layer->geo.x, layer->geo.y, -			layer_surface->surface, true); -	} else { -		output_damage_surface(output, layer->geo.x, layer->geo.y, -			layer_surface->surface, false); +	if (layer_surface->initial_commit || committed || layer_surface->surface->mapped != surface->mapped) { +		surface->mapped = layer_surface->surface->mapped; +		arrange_layers(surface->output); +		transaction_commit_dirty();  	} -	transaction_commit_dirty(); +	int lx, ly; +	wlr_scene_node_coords(&surface->scene->tree->node, &lx, &ly); +	wlr_scene_node_set_position(&surface->popups->node, lx, ly);  } -static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface); - -static void handle_destroy(struct wl_listener *listener, void *data) { -	struct sway_layer_surface *sway_layer = -		wl_container_of(listener, sway_layer, destroy); -	sway_log(SWAY_DEBUG, "Layer surface destroyed (%s)", -		sway_layer->layer_surface->namespace); - -	struct sway_layer_subsurface *subsurface, *subsurface_tmp; -	wl_list_for_each_safe(subsurface, subsurface_tmp, &sway_layer->subsurfaces, link) { -		layer_subsurface_destroy(subsurface); +static void handle_map(struct wl_listener *listener, void *data) { +	struct sway_layer_surface *surface = wl_container_of(listener, +			surface, map); + +	struct wlr_layer_surface_v1 *layer_surface = +				surface->scene->layer_surface; + +	// focus on new surface +	if (layer_surface->current.keyboard_interactive && +			(layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY || +			layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP)) { +		struct sway_seat *seat; +		wl_list_for_each(seat, &server.input->seats, link) { +			// but only if the currently focused layer has a lower precedence +			if (!seat->focused_layer || +					seat->focused_layer->current.layer >= layer_surface->current.layer) { +				seat_set_focus_layer(seat, layer_surface); +			} +		} +		arrange_layers(surface->output);  	} -	wl_list_remove(&sway_layer->link); -	wl_list_remove(&sway_layer->destroy.link); -	wl_list_remove(&sway_layer->map.link); -	wl_list_remove(&sway_layer->unmap.link); -	wl_list_remove(&sway_layer->surface_commit.link); -	wl_list_remove(&sway_layer->new_popup.link); -	wl_list_remove(&sway_layer->new_subsurface.link); - -	struct wlr_output *wlr_output = sway_layer->layer_surface->output; -	sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); -	struct sway_output *output = wlr_output->data; -	arrange_layers(output); -	transaction_commit_dirty(); -	wl_list_remove(&sway_layer->output_destroy.link); -	sway_layer->layer_surface->output = NULL; - -	free(sway_layer); -} - -static void handle_map(struct wl_listener *listener, void *data) { -	struct sway_layer_surface *sway_layer = wl_container_of(listener, -			sway_layer, map); -	struct wlr_output *wlr_output = sway_layer->layer_surface->output; -	sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); -	struct sway_output *output = wlr_output->data; -	output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y, -		sway_layer->layer_surface->surface, true);  	cursor_rebase_all();  }  static void handle_unmap(struct wl_listener *listener, void *data) { -	struct sway_layer_surface *sway_layer = wl_container_of( -			listener, sway_layer, unmap); +	struct sway_layer_surface *surface = wl_container_of( +			listener, surface, unmap);  	struct sway_seat *seat;  	wl_list_for_each(seat, &server.input->seats, link) { -		if (seat->focused_layer == sway_layer->layer_surface) { +		if (seat->focused_layer == surface->layer_surface) {  			seat_set_focus_layer(seat, NULL);  		}  	}  	cursor_rebase_all(); - -	struct wlr_output *wlr_output = sway_layer->layer_surface->output; -	sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); -	struct sway_output *output = wlr_output->data; -	output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y, -		sway_layer->layer_surface->surface, true); -} - -static void subsurface_damage(struct sway_layer_subsurface *subsurface, -		bool whole) { -	struct sway_layer_surface *layer = subsurface->layer_surface; -	struct wlr_output *wlr_output = layer->layer_surface->output; -	sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); -	struct sway_output *output = wlr_output->data; -	int ox = subsurface->wlr_subsurface->current.x + layer->geo.x; -	int oy = subsurface->wlr_subsurface->current.y + layer->geo.y; -	output_damage_surface( -			output, ox, oy, subsurface->wlr_subsurface->surface, whole);  } -static void subsurface_handle_unmap(struct wl_listener *listener, void *data) { -	struct sway_layer_subsurface *subsurface = -			wl_container_of(listener, subsurface, unmap); -	subsurface_damage(subsurface, true); -} - -static void subsurface_handle_map(struct wl_listener *listener, void *data) { -	struct sway_layer_subsurface *subsurface = -			wl_container_of(listener, subsurface, map); -	subsurface_damage(subsurface, true); -} - -static void subsurface_handle_commit(struct wl_listener *listener, void *data) { -	struct sway_layer_subsurface *subsurface = -			wl_container_of(listener, subsurface, commit); -	subsurface_damage(subsurface, false); -} - -static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface) { -	wl_list_remove(&subsurface->link); -	wl_list_remove(&subsurface->map.link); -	wl_list_remove(&subsurface->unmap.link); -	wl_list_remove(&subsurface->destroy.link); -	wl_list_remove(&subsurface->commit.link); -	free(subsurface); -} - -static void subsurface_handle_destroy(struct wl_listener *listener, -		void *data) { -	struct sway_layer_subsurface *subsurface = -			wl_container_of(listener, subsurface, destroy); -	layer_subsurface_destroy(subsurface); -} - -static struct sway_layer_subsurface *create_subsurface( -		struct wlr_subsurface *wlr_subsurface, -		struct sway_layer_surface *layer_surface) { -	struct sway_layer_subsurface *subsurface = -			calloc(1, sizeof(struct sway_layer_subsurface)); -	if (subsurface == NULL) { -		return NULL; -	} - -	subsurface->wlr_subsurface = wlr_subsurface; -	subsurface->layer_surface = layer_surface; -	wl_list_insert(&layer_surface->subsurfaces, &subsurface->link); - -	subsurface->map.notify = subsurface_handle_map; -	wl_signal_add(&wlr_subsurface->surface->events.map, &subsurface->map); -	subsurface->unmap.notify = subsurface_handle_unmap; -	wl_signal_add(&wlr_subsurface->surface->events.unmap, &subsurface->unmap); -	subsurface->destroy.notify = subsurface_handle_destroy; -	wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy); -	subsurface->commit.notify = subsurface_handle_commit; -	wl_signal_add(&wlr_subsurface->surface->events.commit, &subsurface->commit); - -	return subsurface; -} - -static void handle_new_subsurface(struct wl_listener *listener, void *data) { -	struct sway_layer_surface *sway_layer_surface = -			wl_container_of(listener, sway_layer_surface, new_subsurface); -	struct wlr_subsurface *wlr_subsurface = data; -	create_subsurface(wlr_subsurface, sway_layer_surface); -} - - -static struct sway_layer_surface *popup_get_layer( -		struct sway_layer_popup *popup) { -	while (popup->parent_type == LAYER_PARENT_POPUP) { -		popup = popup->parent_popup; -	} -	return popup->parent_layer; -} +static void popup_handle_destroy(struct wl_listener *listener, void *data) { +	struct sway_layer_popup *popup = +		wl_container_of(listener, popup, destroy); -static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) { -	struct wlr_xdg_popup *popup = layer_popup->wlr_popup; -	struct wlr_surface *surface = popup->base->surface; -	int popup_sx = popup->current.geometry.x - popup->base->current.geometry.x; -	int popup_sy = popup->current.geometry.y - popup->base->current.geometry.y; -	int ox = popup_sx, oy = popup_sy; -	struct sway_layer_surface *layer; -	while (true) { -		if (layer_popup->parent_type == LAYER_PARENT_POPUP) { -			layer_popup = layer_popup->parent_popup; -			ox += layer_popup->wlr_popup->current.geometry.x; -			oy += layer_popup->wlr_popup->current.geometry.y; -		} else { -			layer = layer_popup->parent_layer; -			ox += layer->geo.x; -			oy += layer->geo.y; -			break; -		} -	} -	struct wlr_output *wlr_output = layer->layer_surface->output; -	sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); -	struct sway_output *output = wlr_output->data; -	output_damage_surface(output, ox, oy, surface, whole); +	wl_list_remove(&popup->destroy.link); +	wl_list_remove(&popup->new_popup.link); +	wl_list_remove(&popup->commit.link); +	free(popup);  }  static void popup_unconstrain(struct sway_layer_popup *popup) { -	struct sway_layer_surface *layer = popup_get_layer(popup);  	struct wlr_xdg_popup *wlr_popup = popup->wlr_popup; +	struct sway_output *output = popup->toplevel->output; + +	// if a client tries to create a popup while we are in the process of destroying +	// its output, don't crash. +	if (!output) { +		return; +	} -	struct wlr_output *wlr_output = layer->layer_surface->output; -	sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); -	struct sway_output *output = wlr_output->data; +	int lx, ly; +	wlr_scene_node_coords(&popup->toplevel->scene->tree->node, &lx, &ly);  	// the output box expressed in the coordinate system of the toplevel parent  	// of the popup  	struct wlr_box output_toplevel_sx_box = { -		.x = -layer->geo.x, -		.y = -layer->geo.y, +		.x = output->lx - lx, +		.y = output->ly - ly,  		.width = output->width,  		.height = output->height,  	}; @@ -563,63 +299,38 @@ static void popup_unconstrain(struct sway_layer_popup *popup) {  	wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box);  } -static void popup_handle_map(struct wl_listener *listener, void *data) { -	struct sway_layer_popup *popup = wl_container_of(listener, popup, map); -	struct sway_layer_surface *layer = popup_get_layer(popup); -	struct wlr_output *wlr_output = layer->layer_surface->output; -	sway_assert(wlr_output, "wlr_layer_surface_v1 has null output"); -	surface_enter_output(popup->wlr_popup->base->surface, wlr_output->data); -	popup_damage(popup, true); -} - -static void popup_handle_unmap(struct wl_listener *listener, void *data) { -	struct sway_layer_popup *popup = wl_container_of(listener, popup, unmap); -	popup_damage(popup, true); -} -  static void popup_handle_commit(struct wl_listener *listener, void *data) {  	struct sway_layer_popup *popup = wl_container_of(listener, popup, commit);  	if (popup->wlr_popup->base->initial_commit) {  		popup_unconstrain(popup);  	} -	popup_damage(popup, false); -} - -static void popup_handle_destroy(struct wl_listener *listener, void *data) { -	struct sway_layer_popup *popup = -		wl_container_of(listener, popup, destroy); - -	wl_list_remove(&popup->map.link); -	wl_list_remove(&popup->unmap.link); -	wl_list_remove(&popup->destroy.link); -	wl_list_remove(&popup->commit.link); -	free(popup);  }  static void popup_handle_new_popup(struct wl_listener *listener, void *data);  static struct sway_layer_popup *create_popup(struct wlr_xdg_popup *wlr_popup, -		enum layer_parent parent_type, void *parent) { -	struct sway_layer_popup *popup = -		calloc(1, sizeof(struct sway_layer_popup)); +		struct sway_layer_surface *toplevel, struct wlr_scene_tree *parent) { +	struct sway_layer_popup *popup = calloc(1, sizeof(*popup));  	if (popup == NULL) {  		return NULL;  	} +	popup->toplevel = toplevel;  	popup->wlr_popup = wlr_popup; -	popup->parent_type = parent_type; -	popup->parent_layer = parent; +	popup->scene = wlr_scene_xdg_surface_create(parent, +		wlr_popup->base); + +	if (!popup->scene) { +		free(popup); +		return NULL; +	} -	popup->map.notify = popup_handle_map; -	wl_signal_add(&wlr_popup->base->surface->events.map, &popup->map); -	popup->unmap.notify = popup_handle_unmap; -	wl_signal_add(&wlr_popup->base->surface->events.unmap, &popup->unmap);  	popup->destroy.notify = popup_handle_destroy;  	wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); -	popup->commit.notify = popup_handle_commit; -	wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit);  	popup->new_popup.notify = popup_handle_new_popup;  	wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup); +	popup->commit.notify = popup_handle_commit; +	wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit);  	return popup;  } @@ -628,19 +339,14 @@ static void popup_handle_new_popup(struct wl_listener *listener, void *data) {  	struct sway_layer_popup *sway_layer_popup =  		wl_container_of(listener, sway_layer_popup, new_popup);  	struct wlr_xdg_popup *wlr_popup = data; -	create_popup(wlr_popup, LAYER_PARENT_POPUP, sway_layer_popup); +	create_popup(wlr_popup, sway_layer_popup->toplevel, sway_layer_popup->scene);  }  static void handle_new_popup(struct wl_listener *listener, void *data) {  	struct sway_layer_surface *sway_layer_surface =  		wl_container_of(listener, sway_layer_surface, new_popup);  	struct wlr_xdg_popup *wlr_popup = data; -	create_popup(wlr_popup, LAYER_PARENT_LAYER, sway_layer_surface); -} - -struct sway_layer_surface *layer_from_wlr_layer_surface_v1( -		struct wlr_layer_surface_v1 *layer_surface) { -	return layer_surface->data; +	create_popup(wlr_popup, sway_layer_surface, sway_layer_surface->popups);  }  void handle_layer_shell_surface(struct wl_listener *listener, void *data) { @@ -672,10 +378,6 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {  				sway_log(SWAY_ERROR,  						"no output to auto-assign layer surface '%s' to",  						layer_surface->namespace); -				// Note that layer_surface->output can be NULL -				// here, but none of our destroy callbacks are -				// registered yet so we don't have to make them -				// handle that case.  				wlr_layer_surface_v1_destroy(layer_surface);  				return;  			} @@ -684,37 +386,51 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {  		layer_surface->output = output->wlr_output;  	} -	struct sway_layer_surface *sway_layer = -		calloc(1, sizeof(struct sway_layer_surface)); -	if (!sway_layer) { +	struct sway_output *output = layer_surface->output->data; + +	enum zwlr_layer_shell_v1_layer layer_type = layer_surface->pending.layer; +	struct wlr_scene_tree *output_layer = sway_layer_get_scene( +		output, layer_type); +	struct wlr_scene_layer_surface_v1 *scene_surface = +		wlr_scene_layer_surface_v1_create(output_layer, layer_surface); +	if (!scene_surface) { +		sway_log(SWAY_ERROR, "Could not allocate a layer_surface_v1");  		return;  	} -	wl_list_init(&sway_layer->subsurfaces); +	struct sway_layer_surface *surface = +		sway_layer_surface_create(scene_surface); +	if (!surface) { +		wlr_layer_surface_v1_destroy(layer_surface); -	sway_layer->surface_commit.notify = handle_surface_commit; -	wl_signal_add(&layer_surface->surface->events.commit, -		&sway_layer->surface_commit); - -	sway_layer->destroy.notify = handle_destroy; -	wl_signal_add(&layer_surface->events.destroy, &sway_layer->destroy); -	sway_layer->map.notify = handle_map; -	wl_signal_add(&layer_surface->surface->events.map, &sway_layer->map); -	sway_layer->unmap.notify = handle_unmap; -	wl_signal_add(&layer_surface->surface->events.unmap, &sway_layer->unmap); -	sway_layer->new_popup.notify = handle_new_popup; -	wl_signal_add(&layer_surface->events.new_popup, &sway_layer->new_popup); -	sway_layer->new_subsurface.notify = handle_new_subsurface; -	wl_signal_add(&layer_surface->surface->events.new_subsurface, -			&sway_layer->new_subsurface); - -	sway_layer->layer_surface = layer_surface; -	layer_surface->data = sway_layer; +		sway_log(SWAY_ERROR, "Could not allocate a sway_layer_surface"); +		return; +	} -	struct sway_output *output = layer_surface->output->data; -	sway_layer->output_destroy.notify = handle_output_destroy; -	wl_signal_add(&output->events.disable, &sway_layer->output_destroy); +	if (!scene_descriptor_assign(&scene_surface->tree->node, +			SWAY_SCENE_DESC_LAYER_SHELL, surface)) { +		sway_log(SWAY_ERROR, "Failed to allocate a layer surface descriptor"); +		// destroying the layer_surface will also destroy its corresponding +		// scene node +		wlr_layer_surface_v1_destroy(layer_surface); +		return; +	} -	wl_list_insert(&output->shell_layers[layer_surface->pending.layer], -			&sway_layer->link); +	surface->output = output; + +	surface->surface_commit.notify = handle_surface_commit; +	wl_signal_add(&layer_surface->surface->events.commit, +		&surface->surface_commit); +	surface->map.notify = handle_map; +	wl_signal_add(&layer_surface->surface->events.map, &surface->map); +	surface->unmap.notify = handle_unmap; +	wl_signal_add(&layer_surface->surface->events.unmap, &surface->unmap); +	surface->new_popup.notify = handle_new_popup; +	wl_signal_add(&layer_surface->events.new_popup, &surface->new_popup); + +	surface->output_destroy.notify = handle_output_destroy; +	wl_signal_add(&output->events.disable, &surface->output_destroy); + +	surface->node_destroy.notify = handle_node_destroy; +	wl_signal_add(&scene_surface->tree->node.events.destroy, &surface->node_destroy);  } diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 1e4474ce..942bc780 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -182,66 +182,6 @@ void output_view_for_each_popup_surface(struct sway_output *output,  	view_for_each_popup_surface(view, output_for_each_surface_iterator, &data);  } -void output_layer_for_each_surface(struct sway_output *output, -		struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator, -		void *user_data) { -	struct sway_layer_surface *layer_surface; -	wl_list_for_each(layer_surface, layer_surfaces, link) { -		struct wlr_layer_surface_v1 *wlr_layer_surface_v1 = -			layer_surface->layer_surface; -		struct wlr_surface *surface = wlr_layer_surface_v1->surface; -		struct surface_iterator_data data = { -			.user_iterator = iterator, -			.user_data = user_data, -			.output = output, -			.view = NULL, -			.ox = layer_surface->geo.x, -			.oy = layer_surface->geo.y, -			.width = surface->current.width, -			.height = surface->current.height, -		}; -		wlr_layer_surface_v1_for_each_surface(wlr_layer_surface_v1, -			output_for_each_surface_iterator, &data); -	} -} - -void output_layer_for_each_toplevel_surface(struct sway_output *output, -		struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator, -		void *user_data) { -	struct sway_layer_surface *layer_surface; -	wl_list_for_each(layer_surface, layer_surfaces, link) { -		struct wlr_layer_surface_v1 *wlr_layer_surface_v1 = -			layer_surface->layer_surface; -		output_surface_for_each_surface(output, wlr_layer_surface_v1->surface, -			layer_surface->geo.x, layer_surface->geo.y, iterator, -			user_data); -	} -} - - -void output_layer_for_each_popup_surface(struct sway_output *output, -		struct wl_list *layer_surfaces, sway_surface_iterator_func_t iterator, -		void *user_data) { -	struct sway_layer_surface *layer_surface; -	wl_list_for_each(layer_surface, layer_surfaces, link) { -		struct wlr_layer_surface_v1 *wlr_layer_surface_v1 = -			layer_surface->layer_surface; -		struct wlr_surface *surface = wlr_layer_surface_v1->surface; -		struct surface_iterator_data data = { -			.user_iterator = iterator, -			.user_data = user_data, -			.output = output, -			.view = NULL, -			.ox = layer_surface->geo.x, -			.oy = layer_surface->geo.y, -			.width = surface->current.width, -			.height = surface->current.height, -		}; -		wlr_layer_surface_v1_for_each_popup_surface(wlr_layer_surface_v1, -			output_for_each_surface_iterator, &data); -	} -} -  #if HAVE_XWAYLAND  void output_unmanaged_for_each_surface(struct sway_output *output,  		struct wl_list *unmanaged, sway_surface_iterator_func_t iterator, @@ -282,31 +222,6 @@ struct sway_workspace *output_get_active_workspace(struct sway_output *output) {  	return focus->sway_workspace;  } -bool output_has_opaque_overlay_layer_surface(struct sway_output *output) { -	struct sway_layer_surface *sway_layer_surface; -	wl_list_for_each(sway_layer_surface, -			&output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], link) { -		struct wlr_surface *wlr_surface = sway_layer_surface->layer_surface->surface; -		pixman_box32_t output_box = { -			.x2 = output->width, -			.y2 = output->height, -		}; -		pixman_region32_t surface_opaque_box; -		pixman_region32_init(&surface_opaque_box); -		pixman_region32_copy(&surface_opaque_box, &wlr_surface->opaque_region); -		pixman_region32_translate(&surface_opaque_box, -			sway_layer_surface->geo.x, sway_layer_surface->geo.y); -		pixman_region_overlap_t contains = -			pixman_region32_contains_rectangle(&surface_opaque_box, &output_box); -		pixman_region32_fini(&surface_opaque_box); - -		if (contains == PIXMAN_REGION_IN) { -			return true; -		} -	} -	return false; -} -  struct send_frame_done_data {  	struct timespec when;  	int msec_until_refresh; diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 79373e40..30df76f4 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -94,6 +94,12 @@ struct sway_node *node_at_coords(  				}  			} +			if (scene_descriptor_try_get(current, SWAY_SCENE_DESC_LAYER_SHELL)) { +				// We don't want to feed through the current workspace on +				// layer shells +				return NULL; +			} +  			if (!current->parent) {  				break;  			} diff --git a/sway/tree/output.c b/sway/tree/output.c index 64ca3d75..3c8823dc 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -93,8 +93,12 @@ static void destroy_scene_layers(struct sway_output *output) {  	scene_node_disown_children(output->layers.tiling);  	scene_node_disown_children(output->layers.fullscreen); +	wlr_scene_node_destroy(&output->layers.shell_background->node); +	wlr_scene_node_destroy(&output->layers.shell_bottom->node);  	wlr_scene_node_destroy(&output->layers.tiling->node);  	wlr_scene_node_destroy(&output->layers.fullscreen->node); +	wlr_scene_node_destroy(&output->layers.shell_top->node); +	wlr_scene_node_destroy(&output->layers.shell_overlay->node);  	wlr_scene_node_destroy(&output->layers.session_lock->node);  } @@ -103,8 +107,12 @@ struct sway_output *output_create(struct wlr_output *wlr_output) {  	node_init(&output->node, N_OUTPUT, output);  	bool failed = false; +	output->layers.shell_background = alloc_scene_tree(root->staging, &failed); +	output->layers.shell_bottom = alloc_scene_tree(root->staging, &failed);  	output->layers.tiling = alloc_scene_tree(root->staging, &failed);  	output->layers.fullscreen = alloc_scene_tree(root->staging, &failed); +	output->layers.shell_top = alloc_scene_tree(root->staging, &failed); +	output->layers.shell_overlay = alloc_scene_tree(root->staging, &failed);  	output->layers.session_lock = alloc_scene_tree(root->staging, &failed);  	if (!failed) { @@ -136,11 +144,6 @@ struct sway_output *output_create(struct wlr_output *wlr_output) {  	output->workspaces = create_list();  	output->current.workspaces = create_list(); -	size_t len = sizeof(output->shell_layers) / sizeof(output->shell_layers[0]); -	for (size_t i = 0; i < len; ++i) { -		wl_list_init(&output->shell_layers[i]); -	} -  	return output;  } diff --git a/sway/tree/root.c b/sway/tree/root.c index fbdd9a96..7c8f9ea6 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c @@ -47,10 +47,15 @@ struct sway_root *root_create(struct wl_display *wl_display) {  	root->staging = alloc_scene_tree(&root_scene->tree, &failed);  	root->layer_tree = alloc_scene_tree(&root_scene->tree, &failed); +	root->layers.shell_background = alloc_scene_tree(root->layer_tree, &failed); +	root->layers.shell_bottom = alloc_scene_tree(root->layer_tree, &failed);  	root->layers.tiling = alloc_scene_tree(root->layer_tree, &failed);  	root->layers.floating = alloc_scene_tree(root->layer_tree, &failed); +	root->layers.shell_top = alloc_scene_tree(root->layer_tree, &failed);  	root->layers.fullscreen = alloc_scene_tree(root->layer_tree, &failed);  	root->layers.fullscreen_global = alloc_scene_tree(root->layer_tree, &failed); +	root->layers.shell_overlay = alloc_scene_tree(root->layer_tree, &failed); +	root->layers.popup = alloc_scene_tree(root->layer_tree, &failed);  	root->layers.seat = alloc_scene_tree(root->layer_tree, &failed);  	root->layers.session_lock = alloc_scene_tree(root->layer_tree, &failed);  | 
