diff options
Diffstat (limited to 'sway/desktop/layer_shell.c')
| -rw-r--r-- | sway/desktop/layer_shell.c | 130 | 
1 files changed, 128 insertions, 2 deletions
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 34ba5592..f1f79c1b 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -320,6 +320,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) {  	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);  	if (sway_layer->layer_surface->output != NULL) {  		struct sway_output *output = sway_layer->layer_surface->output->data;  		if (output != NULL) { @@ -338,7 +339,6 @@ static void handle_map(struct wl_listener *listener, void *data) {  	struct sway_output *output = sway_layer->layer_surface->output->data;  	output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,  		sway_layer->layer_surface->surface, true); -	// TODO: send enter to subsurfaces and popups  	wlr_surface_send_enter(sway_layer->layer_surface->surface,  		sway_layer->layer_surface->output);  	cursor_rebase_all(); @@ -350,6 +350,131 @@ static void handle_unmap(struct wl_listener *listener, void *data) {  	unmap(sway_layer);  } +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_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->geometry.x - popup->base->geometry.x; +	int popup_sy = popup->geometry.y - popup->base->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->base->geometry.x + +				layer_popup->wlr_popup->geometry.x; +			oy += layer_popup->wlr_popup->base->geometry.y + +				layer_popup->wlr_popup->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; +	struct sway_output *output = wlr_output->data; +	output_damage_surface(output, ox, oy, surface, whole); +} + +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; +	wlr_surface_send_enter(popup->wlr_popup->base->surface, wlr_output); +	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); +	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_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 = layer->layer_surface->output->data; + +	// 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, +		.width = output->width, +		.height = output->height, +	}; + +	wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); +} + +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)); +	if (popup == NULL) { +		return NULL; +	} + +	popup->wlr_popup = wlr_popup; +	popup->parent_type = parent_type; +	popup->parent_layer = parent; + +	popup->map.notify = popup_handle_map; +	wl_signal_add(&wlr_popup->base->events.map, &popup->map); +	popup->unmap.notify = popup_handle_unmap; +	wl_signal_add(&wlr_popup->base->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_unconstrain(popup); + +	return popup; +} + +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); +} + +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; @@ -406,7 +531,8 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {  	wl_signal_add(&layer_surface->events.map, &sway_layer->map);  	sway_layer->unmap.notify = handle_unmap;  	wl_signal_add(&layer_surface->events.unmap, &sway_layer->unmap); -	// TODO: Listen for subsurfaces +	sway_layer->new_popup.notify = handle_new_popup; +	wl_signal_add(&layer_surface->events.new_popup, &sway_layer->new_popup);  	sway_layer->layer_surface = layer_surface;  	layer_surface->data = sway_layer;  | 
