diff --git a/layer_shell_v1.c b/layer_shell_v1.c index c66ef056..c1ee2547 100644 --- a/layer_shell_v1.c +++ b/layer_shell_v1.c @@ -7,21 +7,90 @@ */ #include "layer_shell_v1.h" +#include "output.h" #include "server.h" +#include +#include #include +#include #include #include +static struct wlr_scene_tree * +cg_layer_get_scene(struct cg_output *output, enum zwlr_layer_shell_v1_layer layer_type) +{ + assert(layer_type <= NUM_LAYERS); + switch (layer_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; + } + return NULL; +} + void handle_layer_shell_v1_surface_new(struct wl_listener *listener, void *data) { struct cg_server *server = wl_container_of(listener, server, new_layer_shell_v1_surface); + struct cg_seat *seat = server->seat; struct wlr_layer_surface_v1 *layer_surface = data; - wlr_log(WLR_DEBUG, "New layer shell surface: namespace %s layer %d anchor %d size %dx%d margin %d,%d,%d,%d", + wlr_log(WLR_DEBUG, + "New layer shell surface: namespace %s layer %d anchor %" PRIu32 " size %" PRIu32 "x%" PRIu32 + " margin %" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",", layer_surface->namespace, layer_surface->pending.layer, layer_surface->pending.anchor, layer_surface->pending.desired_width, layer_surface->pending.desired_height, layer_surface->pending.margin.top, layer_surface->pending.margin.right, layer_surface->pending.margin.bottom, layer_surface->pending.margin.left); + + if (layer_surface->output) { + struct wlr_output *wlr_output = + wlr_output_layout_output_at(server->output_layout, seat->cursor->x, seat->cursor->y); + if (wlr_output) { + layer_surface->output = wlr_output; + } else { + struct cg_output *output = wl_container_of(server->outputs.prev, output, link); + layer_surface->output = output->wlr_output; + } + } + struct cg_output *output = layer_surface->output->data; + + enum zwlr_layer_shell_v1_layer layer_type = layer_surface->pending.layer; + struct wlr_scene_tree *output_layer = cg_layer_get_scene(output, layer_type); + + struct cg_layer_surface *cg_surface = calloc(1, sizeof(*cg_surface)); + if (!cg_surface) { + wlr_layer_surface_v1_destroy(layer_surface); + wlr_log(WLR_ERROR, "Failed to allocate layer shell"); + return; + } + + struct wlr_scene_layer_surface_v1 *scene = wlr_scene_layer_surface_v1_create(output_layer, layer_surface); + if (!scene) { + wlr_log(WLR_ERROR, "Could not allocate a layer_surface_v1"); + return; + } + + cg_surface->server = server; + cg_surface->layer_surface = scene->layer_surface; + cg_surface->scene = scene; + cg_surface->tree = scene->tree; + cg_surface->layer_surface->data = cg_surface; + cg_surface->output = output; + + cg_surface->map.notify = handle_map; + wl_signal_add(&layer_surface->surface->events.map, &cg_surface->map); + cg_surface->unmap.notify = handle_unmap; + wl_signal_add(&layer_surface->surface->events.unmap, &cg_surface->unmap); + cg_surface->surface_commit.notify = handle_surface_commit; + wl_signal_add(&layer_surface->surface->events.commit, &cg_surface->surface_commit); + + cg_surface->output_destroy.notify = handle_output_destroy; + wl_signal_add(&output->events.disable, &surface->output_destroy); } diff --git a/layer_shell_v1.h b/layer_shell_v1.h index d7ade6ef..23796765 100644 --- a/layer_shell_v1.h +++ b/layer_shell_v1.h @@ -2,7 +2,26 @@ #define CG_LAYER_SHELL_V1_H #include +#include +#include void handle_layer_shell_v1_surface_new(struct wl_listener *listener, void *data); +struct cg_layer_surface { + struct cg_server *server; + struct wl_list link; // cg_output::layers + + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener surface_commit; +// struct wl_listener destroy; + + struct wl_listener output_destroy; + + struct cg_output *output; + struct wlr_scene_tree *tree; + struct wlr_scene_layer_surface_v1 *scene; + struct wlr_layer_surface_v1 *layer_surface; +}; + #endif diff --git a/output.c b/output.c index 6eb2472b..d6f5222b 100644 --- a/output.c +++ b/output.c @@ -235,6 +235,11 @@ output_destroy(struct cg_output *output) wl_list_remove(&output->frame.link); wl_list_remove(&output->link); + wlr_scene_node_destroy(&output->layers.shell_background->node); + wlr_scene_node_destroy(&output->layers.shell_bottom->node); + wlr_scene_node_destroy(&output->layers.shell_top->node); + wlr_scene_node_destroy(&output->layers.shell_overlay->node); + output_layout_remove(output); free(output); @@ -255,6 +260,18 @@ handle_output_destroy(struct wl_listener *listener, void *data) output_destroy(output); } +static struct wlr_scene_tree * +create_layer_for_output(struct cg_output *output) +{ + struct cg_server *server = output->server; + struct wlr_scene_tree *layer = wlr_scene_tree_create(&server->scene->tree); + if (layer == NULL) { + return NULL; + } + layer->node.data = output->wlr_output; + return layer; +} + void handle_new_output(struct wl_listener *listener, void *data) { @@ -320,6 +337,11 @@ handle_new_output(struct wl_listener *listener, void *data) output_disable(next); } + output->layers.shell_background = create_layer_for_output(output); + output->layers.shell_bottom = create_layer_for_output(output); + output->layers.shell_top = create_layer_for_output(output); + output->layers.shell_overlay = create_layer_for_output(output); + if (!wlr_xcursor_manager_load(server->seat->xcursor_manager, wlr_output->scale)) { wlr_log(WLR_ERROR, "Cannot load XCursor theme for output '%s' with scale %f", wlr_output->name, wlr_output->scale); diff --git a/output.h b/output.h index fa725452..29453486 100644 --- a/output.h +++ b/output.h @@ -17,6 +17,15 @@ struct cg_output { struct wl_listener destroy; struct wl_listener frame; + struct { + struct wlr_scene_tree *shell_background; + struct wlr_scene_tree *shell_bottom; + struct wlr_scene_tree *shell_top; + struct wlr_scene_tree *shell_overlay; + } layers; + + struct wlr_box usable_area; + struct wl_list link; // cg_server::outputs };