commit c0535b2945febca81e79faa47599cc5d54c30047
parent df1c12f9829acdb73ff714cc2598138e4e03ca74
Author: Drew DeVault <sir@cmpwn.com>
Date: Tue, 30 Apr 2019 19:49:18 -0400
Add basic implementation of wlr layer shell
Diffstat:
8 files changed, 664 insertions(+), 1 deletion(-)
diff --git a/include/layers.h b/include/layers.h
@@ -0,0 +1,23 @@
+#ifndef _WIO_LAYERS_H
+#define _WIO_LAYERS_H
+#include <wlr/types/wlr_layer_shell_v1.h>
+#include <wayland-server.h>
+
+struct wio_server;
+
+struct wio_layer_surface {
+ struct wlr_layer_surface_v1 *layer_surface;
+ struct wio_server *server;
+ struct wl_list link;
+
+ struct wl_listener destroy;
+ struct wl_listener map;
+ struct wl_listener surface_commit;
+ struct wl_listener output_destroy;
+
+ struct wlr_box geo;
+};
+
+void server_new_layer_surface(struct wl_listener *listener, void *data);
+
+#endif
diff --git a/include/server.h b/include/server.h
@@ -42,6 +42,7 @@ struct wio_server {
struct wlr_seat *seat;
struct wlr_xcursor_manager *cursor_mgr;
struct wlr_xdg_shell *xdg_shell;
+ struct wlr_layer_shell_v1 *layer_shell;
struct wl_list outputs;
struct wl_list output_configs;
@@ -61,6 +62,7 @@ struct wio_server {
struct wl_listener request_cursor;
struct wl_listener new_xdg_surface;
+ struct wl_listener new_layer_surface;
struct {
int x, y;
@@ -83,6 +85,7 @@ struct wio_output {
struct wio_server *server;
struct wlr_output *wlr_output;
+ struct wl_list layers[4];
struct wl_listener frame;
};
diff --git a/layers.c b/layers.c
@@ -0,0 +1,285 @@
+#include <stdlib.h>
+#include <string.h>
+#include <wayland-server.h>
+#include <wlr/types/wlr_layer_shell_v1.h>
+#include "layers.h"
+#include "server.h"
+
+static void apply_exclusive(struct wlr_box *usable_area,
+ uint32_t anchor, int32_t exclusive,
+ int32_t margin_top, int32_t margin_right,
+ int32_t margin_bottom, int32_t margin_left) {
+ 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,
+ },
+ };
+ for (size_t i = 0; i < sizeof(edges) / sizeof(edges[0]); ++i) {
+ if ((anchor & edges[i].anchors) == edges[i].anchors) {
+ 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 wlr_output *output,
+ struct wl_list *list /* struct *wio_layer_surface */,
+ struct wlr_box *usable_area, bool exclusive) {
+ struct wio_layer_surface *wio_surface;
+ struct wlr_box full_area = { 0 };
+ wlr_output_effective_resolution(output,
+ &full_area.width, &full_area.height);
+ wl_list_for_each_reverse(wio_surface, list, link) {
+ struct wlr_layer_surface_v1 *layer = wio_surface->layer_surface;
+ struct wlr_layer_surface_v1_state *state = &layer->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 box = {
+ .width = state->desired_width,
+ .height = state->desired_height
+ };
+ // Horizontal axis
+ const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
+ | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
+ if ((state->anchor & both_horiz) && box.width == 0) {
+ box.x = bounds.x;
+ box.width = bounds.width;
+ } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) {
+ box.x = bounds.x;
+ } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) {
+ box.x = bounds.x + (bounds.width - box.width);
+ } else {
+ box.x = bounds.x + ((bounds.width / 2) - (box.width / 2));
+ }
+ // Vertical axis
+ const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP
+ | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
+ if ((state->anchor & both_vert) && box.height == 0) {
+ box.y = bounds.y;
+ box.height = bounds.height;
+ } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) {
+ box.y = bounds.y;
+ } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) {
+ box.y = bounds.y + (bounds.height - box.height);
+ } else {
+ box.y = bounds.y + ((bounds.height / 2) - (box.height / 2));
+ }
+ // Margin
+ if ((state->anchor & both_horiz) == both_horiz) {
+ box.x += state->margin.left;
+ box.width -= state->margin.left + state->margin.right;
+ } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) {
+ box.x += state->margin.left;
+ } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) {
+ box.x -= state->margin.right;
+ }
+ if ((state->anchor & both_vert) == both_vert) {
+ box.y += state->margin.top;
+ box.height -= state->margin.top + state->margin.bottom;
+ } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) {
+ box.y += state->margin.top;
+ } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) {
+ box.y -= state->margin.bottom;
+ }
+ if (box.width < 0 || box.height < 0) {
+ // TODO: Bubble up a protocol error?
+ wlr_layer_surface_v1_close(layer);
+ continue;
+ }
+
+ // Apply
+ wio_surface->geo = box;
+ apply_exclusive(usable_area, state->anchor, state->exclusive_zone,
+ state->margin.top, state->margin.right,
+ state->margin.bottom, state->margin.left);
+ wlr_layer_surface_v1_configure(layer, box.width, box.height);
+ }
+}
+
+void arrange_layers(struct wio_output *output) {
+ struct wlr_box usable_area = { 0 };
+ wlr_output_effective_resolution(output->wlr_output,
+ &usable_area.width, &usable_area.height);
+
+ // Arrange exclusive surfaces from top->bottom
+ arrange_layer(output->wlr_output,
+ &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
+ &usable_area, true);
+ arrange_layer(output->wlr_output,
+ &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
+ &usable_area, true);
+ arrange_layer(output->wlr_output,
+ &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
+ &usable_area, true);
+ arrange_layer(output->wlr_output,
+ &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
+ &usable_area, true);
+
+ // Arrange non-exlusive surfaces from top->bottom
+ arrange_layer(output->wlr_output,
+ &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
+ &usable_area, false);
+ arrange_layer(output->wlr_output,
+ &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
+ &usable_area, false);
+ arrange_layer(output->wlr_output,
+ &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
+ &usable_area, false);
+ arrange_layer(output->wlr_output,
+ &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
+ &usable_area, false);
+
+ // Find topmost keyboard interactive layer, if such a layer exists
+ 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 wio_layer_surface *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 != NULL) {
+ break;
+ }
+ }
+
+ // TODO: Focus topmost layer
+}
+
+static void handle_output_destroy(struct wl_listener *listener, void *data) {
+ struct wio_layer_surface *layer =
+ wl_container_of(listener, layer, output_destroy);
+ layer->layer_surface->output = NULL;
+ wl_list_remove(&layer->output_destroy.link);
+ wlr_layer_surface_v1_close(layer->layer_surface);
+}
+
+static void handle_surface_commit(struct wl_listener *listener, void *data) {
+ struct wio_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 != NULL) {
+ struct wio_output *output = wlr_output->data;
+ arrange_layers(output);
+ }
+}
+
+static void handle_destroy(struct wl_listener *listener, void *data) {
+ struct wio_layer_surface *layer = wl_container_of(
+ listener, layer, destroy);
+ wl_list_remove(&layer->link);
+ wl_list_remove(&layer->destroy.link);
+ wl_list_remove(&layer->map.link);
+ wl_list_remove(&layer->surface_commit.link);
+ if (layer->layer_surface->output) {
+ wl_list_remove(&layer->output_destroy.link);
+ arrange_layers((struct wio_output *)layer->layer_surface->output->data);
+ }
+ free(layer);
+}
+
+static void handle_map(struct wl_listener *listener, void *data) {
+ struct wlr_layer_surface_v1 *layer_surface = data;
+ wlr_surface_send_enter(layer_surface->surface, layer_surface->output);
+}
+
+void server_new_layer_surface(struct wl_listener *listener, void *data) {
+ struct wio_server *server = wl_container_of(
+ listener, server, new_layer_surface);
+ struct wlr_layer_surface_v1 *layer_surface = data;
+ if (!layer_surface->output) {
+ struct wlr_output *output = wlr_output_layout_output_at(
+ server->output_layout, server->cursor->x, server->cursor->y);
+ layer_surface->output = output;
+ }
+
+ struct wio_output *output = layer_surface->output->data;
+ struct wio_layer_surface *wio_surface =
+ calloc(1, sizeof(struct wio_layer_surface));
+ if (!wio_surface) {
+ return;
+ }
+ wio_surface->layer_surface = layer_surface;
+ layer_surface->data = wio_surface;
+ wio_surface->server = server;
+
+ wio_surface->surface_commit.notify = handle_surface_commit;
+ wl_signal_add(&layer_surface->surface->events.commit,
+ &wio_surface->surface_commit);
+ wio_surface->output_destroy.notify = handle_output_destroy;
+ wl_signal_add(&layer_surface->output->events.destroy,
+ &wio_surface->output_destroy);
+ wio_surface->destroy.notify = handle_destroy;
+ wl_signal_add(&layer_surface->events.destroy, &wio_surface->destroy);
+ wio_surface->map.notify = handle_map;
+ wl_signal_add(&layer_surface->events.map, &wio_surface->map);
+ // TODO: popups
+
+ // TODO: Listen for subsurfaces
+ wl_list_insert(&output->layers[layer_surface->layer], &wio_surface->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/main.c b/main.c
@@ -16,6 +16,7 @@
#include <wlr/types/wlr_gamma_control_v1.h>
#include <wlr/types/wlr_gamma_control.h>
#include <wlr/types/wlr_gtk_primary_selection.h>
+#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_primary_selection_v1.h>
#include <wlr/types/wlr_screencopy_v1.h>
#include <wlr/types/wlr_seat.h>
@@ -23,6 +24,7 @@
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/types/wlr_xdg_output_v1.h>
#include <wlr/util/log.h>
+#include "layers.h"
#include "server.h"
#include "view.h"
@@ -217,6 +219,11 @@ int main(int argc, char **argv) {
wl_list_init(&server.new_views);
+ server.layer_shell = wlr_layer_shell_v1_create(server.wl_display);
+ server.new_layer_surface.notify = server_new_layer_surface;
+ wl_signal_add(&server.layer_shell->events.new_surface,
+ &server.new_layer_surface);
+
server.menu.x = server.menu.y = -1;
gen_menu_textures(&server);
server.input_state = INPUT_STATE_NONE;
diff --git a/meson.build b/meson.build
@@ -47,6 +47,7 @@ subdir('protocols')
wio_sources = files(
'main.c',
+ 'layers.c',
'input.c',
'output.c',
'view.c',
diff --git a/output.c b/output.c
@@ -8,6 +8,7 @@
#include <wlr/types/wlr_output.h>
#include <wlr/render/wlr_renderer.h>
#include "colors.h"
+#include "layers.h"
#include "server.h"
#include "view.h"
@@ -219,6 +220,51 @@ static void render_view_border(struct wlr_renderer *renderer,
wlr_render_rect(renderer, &borders, color, wlr_output->transform_matrix);
}
+struct render_data_layer {
+ struct wlr_output *output;
+ struct wlr_renderer *renderer;
+ struct wio_view *view;
+ struct timespec *when;
+};
+
+static void render_layer_surface(struct wlr_surface *surface,
+ int sx, int sy, void *data) {
+ struct wio_layer_surface *layer_surface = data;
+ struct wlr_texture *texture = wlr_surface_get_texture(surface);
+ if (texture == NULL) {
+ return;
+ }
+ struct wlr_output *output = layer_surface->layer_surface->output;
+ double ox = 0, oy = 0;
+ wlr_output_layout_output_coords(
+ layer_surface->server->output_layout, output, &ox, &oy);
+ ox += layer_surface->geo.x + sx, oy += layer_surface->geo.y + sy;
+ float matrix[9];
+ enum wl_output_transform transform =
+ wlr_output_transform_invert(surface->current.transform);
+ struct wlr_box box;
+ memcpy(&box, &layer_surface->geo, sizeof(struct wlr_box));
+ wlr_matrix_project_box(matrix, &box, transform, 0,
+ output->transform_matrix);
+ wlr_render_texture_with_matrix(layer_surface->server->renderer,
+ texture, matrix, 1);
+ // Hack because I'm too lazy to fish through a new rdata struct
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ wlr_surface_send_frame_done(surface, &now);
+}
+
+static void render_layer(
+ struct wio_output *output, struct wl_list *layer_surfaces) {
+ struct wio_layer_surface *layer_surface;
+ wl_list_for_each(layer_surface, layer_surfaces, link) {
+ struct wlr_layer_surface_v1 *wlr_layer_surface_v1 =
+ layer_surface->layer_surface;
+ wlr_surface_for_each_surface(wlr_layer_surface_v1->surface,
+ render_layer_surface, layer_surface);
+ }
+}
+
static void output_frame(struct wl_listener *listener, void *data) {
struct wio_output *output = wl_container_of(listener, output, frame);
struct wio_server *server = output->server;
@@ -235,6 +281,9 @@ static void output_frame(struct wl_listener *listener, void *data) {
wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
wlr_renderer_clear(renderer, background);
+ render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]);
+ render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
+
struct wio_view *view;
wl_list_for_each_reverse(view, &server->views, link) {
if (!view->xdg_surface->mapped) {
@@ -273,10 +322,14 @@ static void output_frame(struct wl_listener *listener, void *data) {
break;
}
+ render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]);
+
if (server->menu.x != -1 && server->menu.y != -1) {
render_menu(output);
}
+ render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]);
+
wlr_output_render_software_cursors(wlr_output, NULL);
wlr_renderer_end(renderer);
wlr_output_commit(wlr_output);
@@ -287,13 +340,18 @@ void server_new_output(struct wl_listener *listener, void *data) {
wl_container_of(listener, server, new_output);
struct wlr_output *wlr_output = data;
-
struct wio_output *output = calloc(1, sizeof(struct wio_output));
output->wlr_output = wlr_output;
output->server = server;
output->frame.notify = output_frame;
wl_signal_add(&wlr_output->events.frame, &output->frame);
wl_list_insert(&server->outputs, &output->link);
+ wlr_output->data = output;
+
+ wl_list_init(&output->layers[0]);
+ wl_list_init(&output->layers[1]);
+ wl_list_init(&output->layers[2]);
+ wl_list_init(&output->layers[3]);
struct wio_output_config *_config, *config = NULL;
wl_list_for_each(_config, &server->output_configs, link) {
diff --git a/protocols/meson.build b/protocols/meson.build
@@ -23,6 +23,7 @@ wayland_scanner_server = generator(
server_protocols = [
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
+ ['wlr-layer-shell-unstable-v1.xml'],
]
server_protos_src = []
diff --git a/protocols/wlr-layer-shell-unstable-v1.xml b/protocols/wlr-layer-shell-unstable-v1.xml
@@ -0,0 +1,285 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="wlr_layer_shell_unstable_v1">
+ <copyright>
+ 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.
+ </copyright>
+
+ <interface name="zwlr_layer_shell_v1" version="1">
+ <description summary="create surfaces that are layers of the desktop">
+ 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.
+ </description>
+
+ <request name="get_layer_surface">
+ <description summary="create a layer_surface from a surface">
+ 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.
+ </description>
+ <arg name="id" type="new_id" interface="zwlr_layer_surface_v1"/>
+ <arg name="surface" type="object" interface="wl_surface"/>
+ <arg name="output" type="object" interface="wl_output" allow-null="true"/>
+ <arg name="layer" type="uint" enum="layer" summary="layer to add this surface to"/>
+ <arg name="namespace" type="string" summary="namespace for the layer surface"/>
+ </request>
+
+ <enum name="error">
+ <entry name="role" value="0" summary="wl_surface has another role"/>
+ <entry name="invalid_layer" value="1" summary="layer value is invalid"/>
+ <entry name="already_constructed" value="2" summary="wl_surface has a buffer attached or committed"/>
+ </enum>
+
+ <enum name="layer">
+ <description summary="available layers for surfaces">
+ 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.
+ </description>
+
+ <entry name="background" value="0"/>
+ <entry name="bottom" value="1"/>
+ <entry name="top" value="2"/>
+ <entry name="overlay" value="3"/>
+ </enum>
+ </interface>
+
+ <interface name="zwlr_layer_surface_v1" version="1">
+ <description summary="layer metadata interface">
+ 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 (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.
+ </description>
+
+ <request name="set_size">
+ <description summary="sets the size of the surface">
+ 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.
+ </description>
+ <arg name="width" type="uint"/>
+ <arg name="height" type="uint"/>
+ </request>
+
+ <request name="set_anchor">
+ <description summary="configures the anchor point of the surface">
+ 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.
+ </description>
+ <arg name="anchor" type="uint" enum="anchor"/>
+ </request>
+
+ <request name="set_exclusive_zone">
+ <description summary="configures the exclusive geometry of this surface">
+ Requests that the compositor avoids occluding an area of the surface
+ 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 an
+ edge, rather than a corner. The zone is the number of surface-local
+ coordinates from the edge that is considered 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.
+ </description>
+ <arg name="zone" type="int"/>
+ </request>
+
+ <request name="set_margin">
+ <description summary="sets a margin from the anchor point">
+ 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.
+ </description>
+ <arg name="top" type="int"/>
+ <arg name="right" type="int"/>
+ <arg name="bottom" type="int"/>
+ <arg name="left" type="int"/>
+ </request>
+
+ <request name="set_keyboard_interactivity">
+ <description summary="requests keyboard events">
+ 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.
+ </description>
+ <arg name="keyboard_interactivity" type="uint"/>
+ </request>
+
+ <request name="get_popup">
+ <description summary="assign this layer_surface as an xdg_popup parent">
+ 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.
+ </description>
+ <arg name="popup" type="object" interface="xdg_popup"/>
+ </request>
+
+ <request name="ack_configure">
+ <description summary="ack a configure event">
+ 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.
+ </description>
+ <arg name="serial" type="uint" summary="the serial from the configure event"/>
+ </request>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the layer_surface">
+ This request destroys the layer surface.
+ </description>
+ </request>
+
+ <event name="configure">
+ <description summary="suggest a surface change">
+ 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.
+ </description>
+ <arg name="serial" type="uint"/>
+ <arg name="width" type="uint"/>
+ <arg name="height" type="uint"/>
+ </event>
+
+ <event name="closed">
+ <description summary="surface should be closed">
+ 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.
+ </description>
+ </event>
+
+ <enum name="error">
+ <entry name="invalid_surface_state" value="0" summary="provided surface state is invalid"/>
+ <entry name="invalid_size" value="1" summary="size is invalid"/>
+ <entry name="invalid_anchor" value="2" summary="anchor bitfield is invalid"/>
+ </enum>
+
+ <enum name="anchor" bitfield="true">
+ <entry name="top" value="1" summary="the top edge of the anchor rectangle"/>
+ <entry name="bottom" value="2" summary="the bottom edge of the anchor rectangle"/>
+ <entry name="left" value="4" summary="the left edge of the anchor rectangle"/>
+ <entry name="right" value="8" summary="the right edge of the anchor rectangle"/>
+ </enum>
+ </interface>
+</protocol>