layer-shell: initial layer shell v1 implementation

This commit is contained in:
Jente Hidskes 2020-03-12 21:15:07 +01:00
parent ddead86366
commit d9f132ee5d
2 changed files with 164 additions and 0 deletions

View file

@ -9,10 +9,120 @@
#include "layer_shell_v1.h"
#include "server.h"
#include <stdlib.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/util/log.h>
static void
handle_output_destroy(struct wl_listener *listener, void *data)
{
struct cg_layer_surface *cg_layer = wl_container_of(listener, cg_layer, output_destroy);
wl_list_remove(&cg_layer->output_destroy.link);
wl_list_remove(&cg_layer->link);
wl_list_init(&cg_layer->link);
cg_layer->layer_surface->output = NULL;
wlr_layer_surface_v1_destroy(cg_layer->layer_surface);
}
static void
unmap(struct cg_layer_surface *cg_layer)
{
struct wlr_output *wlr_output = cg_layer->layer_surface->output;
if (!wlr_output) {
return;
}
struct cg_output *output = wlr_output->data;
if (!output) {
return;
}
wlr_scene_node_destroy(cg_layer->scene_node);
}
static void
handle_destroy(struct wl_listener *listener, void *data)
{
struct cg_layer_surface *cg_layer = wl_container_of(listener, cg_layer, destroy);
wlr_log(WLR_DEBUG, "Layer surface destroyed (%s)", cg_layer->layer_surface->namespace);
if (cg_layer->layer_surface->mapped) {
unmap(cg_layer);
}
wl_list_remove(&cg_layer->link);
wl_list_remove(&cg_layer->map.link);
wl_list_remove(&cg_layer->unmap.link);
wl_list_remove(&cg_layer->surface_commit.link);
wl_list_remove(&cg_layer->destroy.link);
if (cg_layer->layer_surface->output) {
wl_list_remove(&cg_layer->output_destroy.link);
cg_layer->layer_surface->output = NULL;
}
free(cg_layer);
}
static void
handle_surface_commit(struct wl_listener *listener, void *data)
{
struct cg_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;
if (!wlr_output) {
return;
}
struct cg_output *output = wlr_output->data;
struct wlr_box old_geometry = layer->geometry;
bool geometry_changed = memcmp(&old_geometry, &layer->geometry, sizeof(struct wlr_box)) != 0;
bool layer_changed = false;
if (layer_surface->current.committed != 0) {
layer_changed = layer->layer != layer_surface->current.layer;
if (layer_changed) {
wl_list_remove(&layer->link);
wl_list_insert(&output->layers[layer_surface->current.layer], &layer->link);
layer->layer = layer_surface->current.layer;
}
}
if (geometry_changed || layer_changed) {
// wlr_scene_node_set_position(layer->scene_node, layer->geometry.x, layer->geometry.y);
}
}
static void
handle_unmap(struct wl_listener *listener, void *data)
{
struct cg_layer_surface *cg_layer = wl_container_of(listener, cg_layer, unmap);
unmap(cg_layer);
}
static void
handle_map(struct wl_listener *listener, void *data)
{
struct cg_layer_surface *cg_layer = wl_container_of(listener, cg_layer, map);
struct wlr_surface *wlr_surface = cg_layer->layer_surface->surface;
cg_layer->scene_node = wlr_scene_subsurface_tree_create(&cg_layer->server->scene->node, wlr_surface);
if (!cg_layer->scene_node) {
wl_resource_post_no_memory(wlr_surface->resource);
return;
}
cg_layer->scene_node->data = cg_layer;
wlr_surface_send_enter(cg_layer->layer_surface->surface, cg_layer->layer_surface->output);
}
void
handle_layer_shell_v1_surface_new(struct wl_listener *listener, void *data)
{
@ -24,4 +134,38 @@ handle_layer_shell_v1_surface_new(struct wl_listener *listener, void *data)
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 the layer surface doesn't specify an output, we assign the first output. */
// TODO: make this the output the user last interacted with, or the one that
// currently has input focus.
if (!layer_surface->output) {
struct cg_output *output = wl_container_of(server->outputs.prev, output, link);
layer_surface->output = output->wlr_output;
}
struct cg_layer_surface *cg_layer = calloc(1, sizeof(struct cg_layer_surface));
if (!cg_layer) {
wlr_log(WLR_ERROR, "Failed to allocate layer shell");
return;
}
cg_layer->server = server;
cg_layer->layer_surface = layer_surface;
layer_surface->data = cg_layer;
cg_layer->map.notify = handle_map;
wl_signal_add(&layer_surface->events.map, &cg_layer->map);
cg_layer->unmap.notify = handle_unmap;
wl_signal_add(&layer_surface->events.unmap, &cg_layer->unmap);
cg_layer->surface_commit.notify = handle_surface_commit;
wl_signal_add(&layer_surface->surface->events.commit, &cg_layer->surface_commit);
cg_layer->destroy.notify = handle_destroy;
wl_signal_add(&layer_surface->events.destroy, &cg_layer->destroy);
// TODO: new popup, new subsurface
struct cg_output *output = layer_surface->output->data;
cg_layer->output_destroy.notify = handle_output_destroy;
wl_signal_add(&output->wlr_output->events.destroy, &cg_layer->output_destroy);
wl_list_insert(&output->layers[layer_surface->pending.layer], &cg_layer->link);
}

View file

@ -2,6 +2,26 @@
#define CG_LAYER_SHELL_V1_H
#include <wayland-server-core.h>
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/util/box.h>
struct cg_layer_surface {
struct cg_server *server;
struct wlr_layer_surface_v1 *layer_surface;
struct wlr_scene_node *scene_node;
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 wlr_box geometry;
enum zwlr_layer_shell_v1_layer layer;
};
void handle_layer_shell_v1_surface_new(struct wl_listener *listener, void *data);