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; |