From 4262e8196275630e3fe55deef35216d6b692187b Mon Sep 17 00:00:00 2001 From: buffet Date: Wed, 15 Jan 2020 20:30:37 +0000 Subject: [PATCH] Start layer-shell --- include/desktop/desktop.h | 2 + include/desktop/layer_shell.h | 34 +++ include/desktop/output.h | 2 + include/desktop/view.h | 3 +- kiwmi/desktop/desktop.c | 8 + kiwmi/desktop/layer_shell.c | 353 ++++++++++++++++++++++ kiwmi/desktop/output.c | 90 +++++- kiwmi/desktop/xdg_shell.c | 7 +- kiwmi/meson.build | 1 + protocols/meson.build | 1 + protocols/wlr-layer-shell-unstable-v1.xml | 301 ++++++++++++++++++ 11 files changed, 791 insertions(+), 11 deletions(-) create mode 100644 include/desktop/layer_shell.h create mode 100644 kiwmi/desktop/layer_shell.c create mode 100644 protocols/wlr-layer-shell-unstable-v1.xml diff --git a/include/desktop/desktop.h b/include/desktop/desktop.h index 1995b0c..6d71968 100644 --- a/include/desktop/desktop.h +++ b/include/desktop/desktop.h @@ -14,6 +14,7 @@ struct kiwmi_desktop { struct wlr_compositor *compositor; struct wlr_xdg_shell *xdg_shell; + struct wlr_layer_shell_v1 *layer_shell; struct wlr_data_device_manager *data_device_manager; struct wlr_output_layout *output_layout; struct wl_list outputs; // struct kiwmi_output::link @@ -21,6 +22,7 @@ struct kiwmi_desktop { struct wl_list views; // struct kiwmi_view::link struct wl_listener xdg_shell_new_surface; + struct wl_listener layer_shell_new_surface; struct wl_listener new_output; struct { diff --git a/include/desktop/layer_shell.h b/include/desktop/layer_shell.h new file mode 100644 index 0000000..47f9711 --- /dev/null +++ b/include/desktop/layer_shell.h @@ -0,0 +1,34 @@ +/* Copyright (c), Niclas Meyer + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef KIWMI_DESKTOP_LAYER_SHELL_H +#define KIWMI_DESKTOP_LAYER_SHELL_H + +#include + +#include +#include + +#include "desktop/output.h" + +struct kiwmi_layer { + struct wl_list link; + struct wlr_layer_surface_v1 *layer_surface; + + struct kiwmi_output *output; + + struct wl_listener destroy; + struct wl_listener commit; + + struct wlr_box geom; +}; + +void arrange_layers(struct kiwmi_output *output); + +void layer_shell_new_surface_notify(struct wl_listener *listener, void *data); + +#endif /* KIWMI_DESKTOP_LAYER_SHELL_H */ diff --git a/include/desktop/output.h b/include/desktop/output.h index f8074e4..77a0c98 100644 --- a/include/desktop/output.h +++ b/include/desktop/output.h @@ -19,6 +19,8 @@ struct kiwmi_output { struct wl_listener mode; struct wl_listener transform; + struct wl_list layers[4]; // struct kiwmi_layer_surface::link + struct { struct wl_signal destroy; struct wl_signal resize; diff --git a/include/desktop/view.h b/include/desktop/view.h index 1eef928..6c6cfd8 100644 --- a/include/desktop/view.h +++ b/include/desktop/view.h @@ -54,7 +54,8 @@ struct kiwmi_view_impl { struct kiwmi_view *view, wlr_surface_iterator_func_t iterator, void *user_data); - void (*get_size)(struct kiwmi_view *view, uint32_t *width, uint32_t *height); + void ( + *get_size)(struct kiwmi_view *view, uint32_t *width, uint32_t *height); void (*set_activated)(struct kiwmi_view *view, bool activated); void (*set_size)(struct kiwmi_view *view, uint32_t width, uint32_t height); void (*set_tiled)(struct kiwmi_view *view, enum wlr_edges edges); diff --git a/kiwmi/desktop/desktop.c b/kiwmi/desktop/desktop.c index f9b9c5d..5fa1bc8 100644 --- a/kiwmi/desktop/desktop.c +++ b/kiwmi/desktop/desktop.c @@ -14,10 +14,12 @@ #include #include #include +#include #include #include #include +#include "desktop/layer_shell.h" #include "desktop/output.h" #include "desktop/xdg_shell.h" #include "server.h" @@ -41,6 +43,12 @@ desktop_init(struct kiwmi_desktop *desktop, struct wlr_renderer *renderer) &desktop->xdg_shell->events.new_surface, &desktop->xdg_shell_new_surface); + desktop->layer_shell = wlr_layer_shell_v1_create(server->wl_display); + desktop->layer_shell_new_surface.notify = layer_shell_new_surface_notify; + wl_signal_add( + &desktop->layer_shell->events.new_surface, + &desktop->layer_shell_new_surface); + desktop->focused_view = NULL; wl_list_init(&desktop->outputs); diff --git a/kiwmi/desktop/layer_shell.c b/kiwmi/desktop/layer_shell.c new file mode 100644 index 0000000..8d505a1 --- /dev/null +++ b/kiwmi/desktop/layer_shell.c @@ -0,0 +1,353 @@ +/* Copyright (c), Niclas Meyer + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "desktop/layer_shell.h" + +#include + +#include +#include +#include + +#include "desktop/desktop.h" +#include "wayland-util.h" +#include "wlr-layer-shell-unstable-v1-protocol.h" + +static void +kiwmi_layer_destroy_notify(struct wl_listener *listener, void *UNUSED(data)) +{ + struct kiwmi_layer *layer = wl_container_of(listener, layer, destroy); + + wl_list_remove(&layer->link); + wl_list_remove(&layer->destroy.link); + + wlr_layer_surface_v1_close(layer->layer_surface); + + free(layer); +} + +static void +kiwmi_layer_commit_notify(struct wl_listener *listener, void *UNUSED(data)) +{ + struct kiwmi_layer *surface = wl_container_of(listener, surface, commit); + struct kiwmi_output *output = surface->output; + + arrange_layers(output); +} + +static void +apply_exclusive( + struct wlr_box *usable_area, + uint32_t anchor, + int32_t exclusive, + int32_t margin_top, + int32_t margin_bottom, + int32_t margin_left, + int32_t margin_right) +{ + if (exclusive <= 0) { + return; + } + + struct { + uint32_t anchors; + int *positive_axis; + int *negative_axis; + int margin; + } edges[] = { + { + .anchors = 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, + }, + { + .anchors = 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, + }, + { + .anchors = 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, + }, + { + .anchors = 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, + }, + }; + + size_t nedges = sizeof(edges) / sizeof(edges[0]); + for (size_t i = 0; i < nedges; ++i) { + if ((anchor & edges[i].anchors) == edges[i].anchors + && 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; + } + } + } +} + +static void +arrange_layer( + struct kiwmi_output *output, + struct wl_list *layers, + struct wlr_box *usable_area, + bool exclusive) +{ + struct wlr_box full_area = {0}; + + wlr_output_effective_resolution( + output->wlr_output, &full_area.width, &full_area.height); + + struct kiwmi_layer *layer; + wl_list_for_each_reverse (layer, layers, link) { + struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface; + struct wlr_layer_surface_v1_state *state = &layer_surface->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 arranged_area = { + .width = state->desired_width, + .height = state->desired_height, + }; + + // horizontal + const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT + | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; + + if ((state->anchor & both_horiz) && arranged_area.width == 0) { + arranged_area.x = bounds.x; + arranged_area.width = bounds.width; + } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) { + arranged_area.x = bounds.x; + } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) { + arranged_area.x = bounds.x + (bounds.width - arranged_area.width); + } else { + arranged_area.x = + bounds.x + ((bounds.width / 2) - (arranged_area.width / 2)); + } + + // vertical + const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP + | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; + if ((state->anchor & both_vert) && arranged_area.height == 0) { + arranged_area.y = bounds.y; + arranged_area.height = bounds.height; + } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) { + arranged_area.y = bounds.y; + } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) { + arranged_area.y = bounds.y + (bounds.height - arranged_area.height); + } else { + arranged_area.y = + bounds.y + ((bounds.height / 2) - (arranged_area.height / 2)); + } + + // left and right margin + if ((state->anchor & both_horiz) == both_horiz) { + arranged_area.x += state->margin.left; + arranged_area.width -= state->margin.left + state->margin.right; + } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) { + arranged_area.x += state->margin.left; + } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) { + arranged_area.x -= state->margin.right; + } + + // top and bottom margin + if ((state->anchor & both_vert) == both_vert) { + arranged_area.y += state->margin.top; + arranged_area.height -= state->margin.top + state->margin.bottom; + } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) { + arranged_area.y += state->margin.top; + } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) { + arranged_area.y -= state->margin.bottom; + } + + if (arranged_area.width < 0 || arranged_area.height < 0) { + wlr_log( + WLR_ERROR, + "Bad width/height: %d, %d", + arranged_area.width, + arranged_area.height); + wlr_layer_surface_v1_close(layer_surface); + continue; + } + + layer->geom = arranged_area; + + apply_exclusive( + usable_area, + state->anchor, + state->exclusive_zone, + state->margin.top, + state->margin.bottom, + state->margin.left, + state->margin.right); + + wlr_layer_surface_v1_configure( + layer_surface, arranged_area.width, arranged_area.height); + } +} + +void +arrange_layers(struct kiwmi_output *output) +{ + struct wlr_box usable_area = {0}; + + wlr_output_effective_resolution( + output->wlr_output, &usable_area.width, &usable_area.height); + + // arrange exclusive layers + arrange_layer( + output, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], + &usable_area, + true); + arrange_layer( + output, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], + &usable_area, + true); + arrange_layer( + output, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], + &usable_area, + true); + arrange_layer( + output, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], + &usable_area, + true); + + // arrange non-exclusive layers + arrange_layer( + output, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], + &usable_area, + false); + arrange_layer( + output, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], + &usable_area, + false); + arrange_layer( + output, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], + &usable_area, + false); + arrange_layer( + output, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], + &usable_area, + false); + + 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 kiwmi_layer *layer; + struct kiwmi_layer *topmost = NULL; + for (size_t i = 0; i < nlayers; ++i) { + wl_list_for_each_reverse ( + layer, &output->layers[layers_above_shell[i]], link) { + if (layer->layer_surface->current.keyboard_interactive) { + topmost = layer; + break; + } + } + + if (topmost) { + break; + } + } + + // TODO: focus topmost +} + +void +layer_shell_new_surface_notify(struct wl_listener *listener, void *data) +{ + struct kiwmi_desktop *desktop = + wl_container_of(listener, desktop, layer_shell_new_surface); + struct wlr_layer_surface_v1 *layer_surface = data; + + wlr_log( + WLR_DEBUG, + "New layer_shell surface namespace='%s'", + layer_surface->namespace); + + if (!layer_surface->output) { + // TODO: assign active output + wlr_log(WLR_ERROR, "TODO: assign active output"); + struct kiwmi_output *output; + wl_list_for_each (output, &desktop->outputs, link) { + layer_surface->output = output->wlr_output; + break; + } + } + + struct kiwmi_layer *layer = malloc(sizeof(*layer)); + if (!layer) { + wlr_log(WLR_ERROR, "Failed too allocate kiwmi_layer_shell"); + return; + } + + struct kiwmi_output *output = layer_surface->output->data; + + size_t len = sizeof(output->layers) / sizeof(output->layers[0]); + if (layer_surface->layer >= len) { + wlr_log( + WLR_ERROR, "Bad layer surface layer '%d'", layer_surface->layer); + wlr_layer_surface_v1_close(layer_surface); + free(layer); + return; + } + + layer->layer_surface = layer_surface; + layer->output = output; + + layer->destroy.notify = kiwmi_layer_destroy_notify; + wl_signal_add(&layer_surface->events.destroy, &layer->destroy); + + layer->commit.notify = kiwmi_layer_commit_notify; + wl_signal_add(&layer_surface->surface->events.commit, &layer->commit); + + wl_list_insert(&output->layers[layer_surface->layer], &layer->link); + + // Temporarily set the layer's current state to client_pending + // So that we can easily arrange it + struct wlr_layer_surface_v1_state old_state = layer_surface->current; + layer_surface->current = layer_surface->client_pending; + arrange_layers(output); + layer_surface->current = old_state; +} diff --git a/kiwmi/desktop/output.c b/kiwmi/desktop/output.c index 31fb919..15e6579 100644 --- a/kiwmi/desktop/output.c +++ b/kiwmi/desktop/output.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -20,23 +21,76 @@ #include #include "desktop/desktop.h" +#include "desktop/layer_shell.h" #include "desktop/view.h" #include "input/cursor.h" #include "input/input.h" #include "server.h" +#include "wayland-util.h" struct render_data { struct wlr_output *output; - struct kiwmi_view *view; struct wlr_renderer *renderer; struct timespec *when; + struct wlr_output_layout *output_layout; + void *data; }; +static void +render_layer_surface(struct wlr_surface *surface, int x, int y, void *data) +{ + struct render_data *rdata = data; + struct wlr_output *output = rdata->output; + struct wlr_output_layout *output_layout = rdata->output_layout; + struct wlr_box *geom = rdata->data; + + struct wlr_texture *texture = wlr_surface_get_texture(surface); + if (!texture) { + return; + } + + double ox = 0; + double oy = 0; + wlr_output_layout_output_coords(output_layout, output, &ox, &oy); + + ox += x + geom->x; + oy += y + geom->y; + + struct wlr_box box = { + .x = ox * output->scale, + .y = oy * output->scale, + .width = surface->current.width * output->scale, + .height = surface->current.height * output->scale, + }; + + float matrix[9]; + enum wl_output_transform transform = + wlr_output_transform_invert(surface->current.transform); + wlr_matrix_project_box( + matrix, &box, transform, 0, output->transform_matrix); + + wlr_render_texture_with_matrix(rdata->renderer, texture, matrix, 1); + + wlr_surface_send_frame_done(surface, rdata->when); +} + +static void +render_layer(struct wl_list *layer, struct render_data *rdata) +{ + struct kiwmi_layer *surface; + wl_list_for_each (surface, layer, link) { + rdata->data = &surface->geom; + + wlr_layer_surface_v1_for_each_surface( + surface->layer_surface, render_layer_surface, rdata); + } +} + static void render_surface(struct wlr_surface *surface, int sx, int sy, void *data) { struct render_data *rdata = data; - struct kiwmi_view *view = rdata->view; + struct kiwmi_view *view = rdata->data; struct wlr_output *output = rdata->output; struct wlr_texture *texture = wlr_surface_get_texture(surface); @@ -76,6 +130,7 @@ output_frame_notify(struct wl_listener *listener, void *data) struct kiwmi_output *output = wl_container_of(listener, output, frame); struct wlr_output *wlr_output = data; struct kiwmi_desktop *desktop = output->desktop; + struct wlr_output_layout *output_layout = desktop->output_layout; struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); @@ -95,22 +150,30 @@ output_frame_notify(struct wl_listener *listener, void *data) wlr_renderer_begin(renderer, width, height); wlr_renderer_clear(renderer, (float[]){0.0f, 1.0f, 0.0f, 1.0f}); + struct render_data rdata = { + .output = output->wlr_output, + .renderer = renderer, + .when = &now, + .output_layout = output_layout, + }; + + render_layer(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &rdata); + render_layer(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &rdata); + struct kiwmi_view *view; wl_list_for_each_reverse (view, &desktop->views, link) { if (view->hidden || !view->mapped) { continue; } - struct render_data rdata = { - .output = output->wlr_output, - .view = view, - .renderer = renderer, - .when = &now, - }; + rdata.data = view; view_for_each_surface(view, render_surface, &rdata); } + render_layer(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &rdata); + render_layer(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &rdata); + wlr_output_render_software_cursors(wlr_output, NULL); wlr_renderer_end(renderer); @@ -139,6 +202,8 @@ output_mode_notify(struct wl_listener *listener, void *UNUSED(data)) { struct kiwmi_output *output = wl_container_of(listener, output, mode); + arrange_layers(output); + wl_signal_emit(&output->events.resize, output); } @@ -147,6 +212,8 @@ output_transform_notify(struct wl_listener *listener, void *UNUSED(data)) { struct kiwmi_output *output = wl_container_of(listener, output, transform); + arrange_layers(output); + wl_signal_emit(&output->events.resize, output); } @@ -198,6 +265,8 @@ new_output_notify(struct wl_listener *listener, void *data) return; } + wlr_output->data = output; + struct kiwmi_cursor *cursor = server->input.cursor; wlr_xcursor_manager_load(cursor->xcursor_manager, wlr_output->scale); @@ -208,6 +277,11 @@ new_output_notify(struct wl_listener *listener, void *data) wlr_output_create_global(wlr_output); + size_t len_outputs = sizeof(output->layers) / sizeof(output->layers[0]); + for (size_t i = 0; i < len_outputs; ++i) { + wl_list_init(&output->layers[i]); + } + wl_signal_init(&output->events.destroy); wl_signal_init(&output->events.resize); diff --git a/kiwmi/desktop/xdg_shell.c b/kiwmi/desktop/xdg_shell.c index 6b758fd..fbd79d3 100644 --- a/kiwmi/desktop/xdg_shell.c +++ b/kiwmi/desktop/xdg_shell.c @@ -71,11 +71,14 @@ xdg_shell_view_for_each_surface( } static void -xdg_shell_view_get_size(struct kiwmi_view *view, uint32_t *width, uint32_t *height) +xdg_shell_view_get_size( + struct kiwmi_view *view, + uint32_t *width, + uint32_t *height) { struct wlr_box *geom = &view->xdg_surface->geometry; - *width = geom->width; + *width = geom->width; *height = geom->height; } diff --git a/kiwmi/meson.build b/kiwmi/meson.build index 89b63af..9d4d613 100644 --- a/kiwmi/meson.build +++ b/kiwmi/meson.build @@ -2,6 +2,7 @@ kiwmi_sources = files( 'main.c', 'server.c', 'desktop/desktop.c', + 'desktop/layer_shell.c', 'desktop/output.c', 'desktop/view.c', 'desktop/xdg_shell.c', diff --git a/protocols/meson.build b/protocols/meson.build index 05de04d..3ab9a63 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -4,6 +4,7 @@ wayland_scanner_bin = wayland_scanner.get_pkgconfig_variable('wayland_scanner' protocols_server = [ wayland_protocols_dir / 'stable/xdg-shell/xdg-shell.xml', 'kiwmi-ipc.xml', + 'wlr-layer-shell-unstable-v1.xml', ] protocols_server_src = [] diff --git a/protocols/wlr-layer-shell-unstable-v1.xml b/protocols/wlr-layer-shell-unstable-v1.xml new file mode 100644 index 0000000..adc6a17 --- /dev/null +++ b/protocols/wlr-layer-shell-unstable-v1.xml @@ -0,0 +1,301 @@ + + + + Copyright © 2017 Drew DeVault + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + Clients can use this interface to assign the surface_layer role to + wl_surfaces. Such surfaces are assigned to a "layer" of the output and + rendered with a defined z-depth respective to each other. They may also be + anchored to the edges and corners of a screen and specify input handling + semantics. This interface should be suitable for the implementation of + many desktop shell components, and a broad number of other applications + that interact with the desktop. + + + + + Create a layer surface for an existing surface. This assigns the role of + layer_surface, or raises a protocol error if another role is already + assigned. + + Creating a layer surface from a wl_surface which has a buffer attached + or committed is a client error, and any attempts by a client to attach + or manipulate a buffer prior to the first layer_surface.configure call + must also be treated as errors. + + You may pass NULL for output to allow the compositor to decide which + output to use. Generally this will be the one that the user most + recently interacted with. + + Clients can specify a namespace that defines the purpose of the layer + surface. + + + + + + + + + + + + + + + + + These values indicate which layers a surface can be rendered in. They + are ordered by z depth, bottom-most first. Traditional shell surfaces + will typically be rendered between the bottom and top layers. + Fullscreen shell surfaces are typically rendered at the top layer. + Multiple surfaces can share a single layer, and ordering within a + single layer is undefined. + + + + + + + + + + + + An interface that may be implemented by a wl_surface, for surfaces that + are designed to be rendered as a layer of a stacked desktop-like + environment. + + Layer surface state (layer, size, anchor, exclusive zone, + margin, interactivity) is double-buffered, and will be applied at the + time wl_surface.commit of the corresponding wl_surface is called. + + + + + Sets the size of the surface in surface-local coordinates. The + compositor will display the surface centered with respect to its + anchors. + + If you pass 0 for either value, the compositor will assign it and + inform you of the assignment in the configure event. You must set your + anchor to opposite edges in the dimensions you omit; not doing so is a + protocol error. Both values are 0 by default. + + Size is double-buffered, see wl_surface.commit. + + + + + + + + Requests that the compositor anchor the surface to the specified edges + and corners. If two orthogonal edges are specified (e.g. 'top' and + 'left'), then the anchor point will be the intersection of the edges + (e.g. the top left corner of the output); otherwise the anchor point + will be centered on that edge, or in the center if none is specified. + + Anchor is double-buffered, see wl_surface.commit. + + + + + + + Requests that the compositor avoids occluding an area with other + surfaces. The compositor's use of this information is + implementation-dependent - do not assume that this region will not + actually be occluded. + + A positive value is only meaningful if the surface is anchored to one + edge or an edge and both perpendicular edges. If the surface is not + anchored, anchored to only two perpendicular edges (a corner), anchored + to only two parallel edges or anchored to all edges, a positive value + will be treated the same as zero. + + A positive zone is the distance from the edge in surface-local + coordinates to consider exclusive. + + Surfaces that do not wish to have an exclusive zone may instead specify + how they should interact with surfaces that do. If set to zero, the + surface indicates that it would like to be moved to avoid occluding + surfaces with a positive exclusive zone. If set to -1, the surface + indicates that it would not like to be moved to accommodate for other + surfaces, and the compositor should extend it all the way to the edges + it is anchored to. + + For example, a panel might set its exclusive zone to 10, so that + maximized shell surfaces are not shown on top of it. A notification + might set its exclusive zone to 0, so that it is moved to avoid + occluding the panel, but shell surfaces are shown underneath it. A + wallpaper or lock screen might set their exclusive zone to -1, so that + they stretch below or over the panel. + + The default value is 0. + + Exclusive zone is double-buffered, see wl_surface.commit. + + + + + + + Requests that the surface be placed some distance away from the anchor + point on the output, in surface-local coordinates. Setting this value + for edges you are not anchored to has no effect. + + The exclusive zone includes the margin. + + Margin is double-buffered, see wl_surface.commit. + + + + + + + + + + Set to 1 to request that the seat send keyboard events to this layer + surface. For layers below the shell surface layer, the seat will use + normal focus semantics. For layers above the shell surface layers, the + seat will always give exclusive keyboard focus to the top-most layer + which has keyboard interactivity set to true. + + Layer surfaces receive pointer, touch, and tablet events normally. If + you do not want to receive them, set the input region on your surface + to an empty region. + + Events is double-buffered, see wl_surface.commit. + + + + + + + This assigns an xdg_popup's parent to this layer_surface. This popup + should have been created via xdg_surface::get_popup with the parent set + to NULL, and this request must be invoked before committing the popup's + initial state. + + See the documentation of xdg_popup for more details about what an + xdg_popup is and how it is used. + + + + + + + When a configure event is received, if a client commits the + surface in response to the configure event, then the client + must make an ack_configure request sometime before the commit + request, passing along the serial of the configure event. + + If the client receives multiple configure events before it + can respond to one, it only has to ack the last configure event. + + A client is not required to commit immediately after sending + an ack_configure request - it may even ack_configure several times + before its next surface commit. + + A client may send multiple ack_configure requests before committing, but + only the last request sent before a commit indicates which configure + event the client really is responding to. + + + + + + + This request destroys the layer surface. + + + + + + The configure event asks the client to resize its surface. + + Clients should arrange their surface for the new states, and then send + an ack_configure request with the serial sent in this configure event at + some point before committing the new surface. + + The client is free to dismiss all but the last configure event it + received. + + The width and height arguments specify the size of the window in + surface-local coordinates. + + The size is a hint, in the sense that the client is free to ignore it if + it doesn't resize, pick a smaller size (to satisfy aspect ratio or + resize in steps of NxM pixels). If the client picks a smaller size and + is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the + surface will be centered on this axis. + + If the width or height arguments are zero, it means the client should + decide its own window dimension. + + + + + + + + + The closed event is sent by the compositor when the surface will no + longer be shown. The output may have been destroyed or the user may + have asked for it to be removed. Further changes to the surface will be + ignored. The client should destroy the resource after receiving this + event, and create a new surface if they so choose. + + + + + + + + + + + + + + + + + + + + + Change the layer that the surface is rendered on. + + Layer is double-buffered, see wl_surface.commit. + + + + +