diff --git a/LICENSE b/LICENSE index b23aa92..da0053e 100644 --- a/LICENSE +++ b/LICENSE @@ -2,8 +2,6 @@ dwl - dwm for Wayland Copyright © 2020 Devin J. Pohly -See also the files LICENSE.tinywl and LICENSE.dwm. - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or diff --git a/Makefile b/Makefile index aeb4bf5..3788782 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ WAYLAND_PROTOCOLS=$(shell pkg-config --variable=pkgdatadir wayland-protocols) WAYLAND_SCANNER=$(shell pkg-config --variable=wayland_scanner wayland-scanner) -CFLAGS ?= -g -Wall -Wextra -Wno-unused-parameter -Wno-sign-compare +CFLAGS ?= -g -O0 -Wall -Wextra -Wno-unused-parameter -Wno-sign-compare CFLAGS += -Werror -I. -DWLR_USE_UNSTABLE -PKGS = wlroots wayland-server xkbcommon +PKGS = wlroots wayland-server xkbcommon wayland-client CFLAGS += $(foreach p,$(PKGS),$(shell pkg-config --cflags $(p))) LDLIBS += $(foreach p,$(PKGS),$(shell pkg-config --libs $(p))) @@ -12,25 +12,35 @@ LDLIBS += $(foreach p,$(PKGS),$(shell pkg-config --libs $(p))) # wayland-scanner is a tool which generates C headers and rigging for Wayland # protocols, which are specified in XML. wlroots requires you to rig these up # to your build system yourself and provide them in the include path. -xdg-shell-protocol.h: - $(WAYLAND_SCANNER) server-header \ - $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ +# xdg-shell-protocol.h: +# $(WAYLAND_SCANNER) server-header \ +# $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ xdg-shell-protocol.c: $(WAYLAND_SCANNER) private-code \ $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ -xdg-shell-protocol.o: xdg-shell-protocol.h +xdg-shell-protocol.h: + $(WAYLAND_SCANNER) server-header \ + $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ + +%-protocol.c: protocol/%.xml + $(WAYLAND_SCANNER) private-code $^ $@ + +%-protocol.h: protocol/%.xml + $(WAYLAND_SCANNER) server-header $^ $@ config.h: | config.def.h cp config.def.h $@ -dwl.o: config.h xdg-shell-protocol.h +dwl.o: config.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h -dwl: xdg-shell-protocol.o +dwl: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o clean: - rm -f dwl *.o xdg-shell-protocol.h xdg-shell-protocol.c + rm -f dwl *.o xdg-shell-protocol.h xdg-shell-protocol.c wlr-layer-shell-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.c -.DEFAULT_GOAL=dwl -.PHONY: clean +.DEFAULT_GOAL=all +.PHONY: all clean + +all: dwl diff --git a/README.md b/README.md index 5da6f6c..d5cdc61 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ serve a similar function to `.xinitrc`: starting a service manager or other startup applications. Unlike `.xinitrc`, the display server will not shut down when this process terminates. Instead, as dwl is shutting down, it will send this process a SIGTERM and wait for it to terminate (if it hasn't already). -This makes it ideal not only for initialization but also for execing into a +This make it ideal not only for initialization but also for execing into a user-level service manager like s6 or `systemd --user`. diff --git a/config.def.h b/config.def.h index 9f8c2e3..b5ce5ec 100644 --- a/config.def.h +++ b/config.def.h @@ -1,7 +1,11 @@ /* appearance */ -static const int sloppyfocus = 1; /* focus follows mouse */ -static const unsigned int borderpx = 1; /* border pixel of windows */ -static const float rootcolor[] = {0.3, 0.3, 0.3, 1.0}; +static const int sloppyfocus = 1; /* focus follows mouse */ +static const unsigned int borderpx = 1; /* border pixel of windows */ +static const unsigned int topgap = 22; /* gap at top of screen */ +static const char menufont[] = "Fantasque Sans Mono 13"; +static const char normfgcolor[] = "#babdb6"; +static const char normbgcolor[] = "#000000"; +static const float rootcolor[] = {0.1, 0.1, 0.3, 1.0}; static const float bordercolor[] = {0.5, 0.5, 0.5, 1.0}; /* tagging */ @@ -40,10 +44,13 @@ static const struct xkb_rule_names xkb_rules = { { MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,SKEY,toggletag, {.ui = 1 << TAG} } /* commands */ +static char menumon[2] = "0"; /* component of menucmd, manipulated in spawn() */ +static const char *menucmd[] = { "bemenu-run", "-p", "", "-m", menumon, "--fn", menufont, "--nb", normbgcolor, "--nf", normfgcolor, "--hb", normfgcolor, "--hf", normbgcolor, NULL }; static const char *termcmd[] = { "kitty", "-o", "linux_display_server=wayland", NULL }; static const Key keys[] = { /* modifier key function argument */ + { MODKEY, XKB_KEY_p, spawn, {.v = menucmd} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} }, { MODKEY, XKB_KEY_j, focusstack, {.i = +1} }, { MODKEY, XKB_KEY_k, focusstack, {.i = -1} }, diff --git a/dwl.c b/dwl.c index a37bceb..7ea1037 100644 --- a/dwl.c +++ b/dwl.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,8 @@ #include #include +#include "wlr-layer-shell-unstable-v1-protocol.h" + /* macros */ #define MAX(A, B) ((A) > (B) ? (A) : (B)) #define MIN(A, B) ((A) < (B) ? (A) : (B)) @@ -87,6 +90,16 @@ typedef struct { struct wl_listener key; } Keyboard; +typedef struct { + struct wl_list link; + struct wlr_layer_surface_v1 *layer_surface; + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener destroy; + bool mapped; /* XXX do away with this? can we? */ + int x, y; /* layout-relative */ +} LayerShell; + typedef struct { const char *symbol; void (*arrange)(Monitor *); @@ -98,6 +111,9 @@ struct Monitor { struct wl_listener frame; struct wlr_box m; /* monitor area, layout-relative */ struct wlr_box w; /* window area, layout-relative */ + + struct wl_list layers[4]; + Client *sel; /* optimization: first VISIBLEON(m) client in fstack */ const Layout *lt[2]; unsigned int seltags; unsigned int sellt; @@ -115,6 +131,15 @@ typedef struct { enum wl_output_transform rr; } MonitorRule; +typedef struct { + const char *class; + const char *instance; + const char *title; + unsigned int tags; + int isfloating; + int monitor; +} Rule; + /* Used to move all of the data necessary to render a surface from the top-level * frame handler to the per-surface render function. */ struct render_data { @@ -130,10 +155,12 @@ static void axisnotify(struct wl_listener *listener, void *data); static void buttonpress(struct wl_listener *listener, void *data); static void chvt(const Arg *arg); static void createkeyboard(struct wlr_input_device *device); +static void createlayer(struct wl_listener *listener, void *data); static void createmon(struct wl_listener *listener, void *data); static void createnotify(struct wl_listener *listener, void *data); static void createpointer(struct wlr_input_device *device); static void cursorframe(struct wl_listener *listener, void *data); +static void destroylayer(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); static Monitor *dirtomon(int dir); static void focusclient(Client *c, struct wlr_surface *surface, int lift); @@ -144,6 +171,7 @@ static void inputdevice(struct wl_listener *listener, void *data); static bool keybinding(uint32_t mods, xkb_keysym_t sym); static void keypress(struct wl_listener *listener, void *data); static void keypressmod(struct wl_listener *listener, void *data); +static void maplayer(struct wl_listener *listener, void *data); static void maprequest(struct wl_listener *listener, void *data); static void motionabsolute(struct wl_listener *listener, void *data); static void motionnotify(uint32_t time); @@ -155,11 +183,12 @@ static void quit(const Arg *arg); static void refocus(void); static void render(struct wlr_surface *surface, int sx, int sy, void *data); static void renderclients(Monitor *m, struct timespec *now); +static void renderlayer(Monitor *m, enum zwlr_layer_shell_v1_layer layer, + struct timespec *now); static void rendermon(struct wl_listener *listener, void *data); static void resize(Client *c, int x, int y, int w, int h, int interact); static void run(char *startup_cmd); static void scalebox(struct wlr_box *box, float scale); -static Client *selclient(void); static void setcursor(struct wl_listener *listener, void *data); static void setfloating(Client *c, int floating); static void setlayout(const Arg *arg); @@ -173,6 +202,7 @@ static void tile(Monitor *m); static void togglefloating(const Arg *arg); static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); +static void unmaplayer(struct wl_listener *listener, void *data); static void unmapnotify(struct wl_listener *listener, void *data); static void view(const Arg *arg); static Client *xytoclient(double x, double y, @@ -186,6 +216,8 @@ static struct wlr_renderer *drw; static struct wlr_xdg_shell *xdg_shell; static struct wl_listener new_xdg_surface; +static struct wlr_layer_shell_v1 *layer_shell; +static struct wl_listener new_layer_surface; static struct wl_list clients; /* tiling order */ static struct wl_list fstack; /* focus order */ static struct wl_list stack; /* stacking z-order */ @@ -238,6 +270,8 @@ arrange(Monitor *m) /* Get effective monitor geometry to use for window area */ m->m = *wlr_output_layout_get_box(output_layout, m->wlr_output); m->w = m->m; + m->w.y += topgap; + m->w.height -= topgap; if (m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); /* XXX recheck pointer focus here... or in resize()? */ @@ -335,6 +369,50 @@ createkeyboard(struct wlr_input_device *device) wl_list_insert(&keyboards, &kb->link); } +void +createlayer(struct wl_listener *listener, void *data) +{ + struct wlr_layer_surface_v1 *layer_surface = data; + LayerShell *l; + + wlr_log(WLR_DEBUG, "new layer surface: namespace %s layer %d anchor %d " + "size %dx%d margin %d,%d,%d,%d", + layer_surface->namespace, + layer_surface->client_pending.layer, + layer_surface->client_pending.anchor, + layer_surface->client_pending.desired_width, + layer_surface->client_pending.desired_height, + layer_surface->client_pending.margin.top, + layer_surface->client_pending.margin.right, + layer_surface->client_pending.margin.bottom, + layer_surface->client_pending.margin.left); + + if (!layer_surface->output) + layer_surface->output = selmon->wlr_output; + + /* Allocate a LayerShell for this surface */ + if (!(l = calloc(1, sizeof(*l)))) + return; + l->layer_surface = layer_surface; + + /* Listen to the various events it can emit */ + l->destroy.notify = destroylayer; + wl_signal_add(&layer_surface->events.destroy, &l->destroy); + l->map.notify = maplayer; + wl_signal_add(&layer_surface->events.map, &l->map); + l->unmap.notify = unmaplayer; + wl_signal_add(&layer_surface->events.unmap, &l->unmap); + + /* Add it to the corresponding layer. */ + wl_list_insert(&selmon->layers[layer_surface->client_pending.layer], + &l->link); + + /* Configure the surface */ + wlr_layer_surface_v1_configure(layer_surface, + layer_surface->client_pending.desired_width, + layer_surface->client_pending.desired_height); +} + void createmon(struct wl_listener *listener, void *data) { @@ -358,6 +436,8 @@ createmon(struct wl_listener *listener, void *data) /* Allocates and configures monitor state using configured rules */ Monitor *m = wlr_output->data = calloc(1, sizeof(*m)); m->wlr_output = wlr_output; + for (int i = 0; i < 4; i++) + wl_list_init(&m->layers[i]); m->tagset[0] = m->tagset[1] = 1; int i; for (i = 0; i < LENGTH(monrules); i++) @@ -436,6 +516,15 @@ cursorframe(struct wl_listener *listener, void *data) wlr_seat_pointer_notify_frame(seat); } +void +destroylayer(struct wl_listener *listener, void *data) +{ + /* Called when the surface is destroyed and should never be shown again. */ + LayerShell *l = wl_container_of(listener, l, destroy); + wl_list_remove(&l->link); + free(l); +} + void destroynotify(struct wl_listener *listener, void *data) { @@ -471,6 +560,7 @@ focusclient(Client *c, struct wlr_surface *surface, int lift) /* Focus the correct monitor as well */ selmon = c->mon; } + selmon->sel = c; /* XXX Need to understand xdg toplevel/popups to know if there's more * simplification that can be done in this function */ @@ -525,19 +615,18 @@ void focusstack(const Arg *arg) { /* Focus the next or previous client (in tiling order) on selmon */ - Client *sel = selclient(); - if (!sel) + Client *c = NULL; + if (!selmon->sel) return; - Client *c; if (arg->i > 0) { - wl_list_for_each(c, &sel->link, link) { + wl_list_for_each(c, &selmon->sel->link, link) { if (&c->link == &clients) continue; /* wrap past the sentinel node */ if (VISIBLEON(c, selmon)) break; /* found it */ } } else { - wl_list_for_each_reverse(c, &sel->link, link) { + wl_list_for_each_reverse(c, &selmon->sel->link, link) { if (&c->link == &clients) continue; /* wrap past the sentinel node */ if (VISIBLEON(c, selmon)) @@ -648,6 +737,14 @@ keypressmod(struct wl_listener *listener, void *data) &kb->device->keyboard->modifiers); } +void +maplayer(struct wl_listener *listener, void *data) +{ + /* Called when the surface is mapped, or ready to display on-screen. */ + LayerShell *l = wl_container_of(listener, l, map); + l->mapped = true; +} + void maprequest(struct wl_listener *listener, void *data) { @@ -703,6 +800,7 @@ motionnotify(uint32_t time) /* Otherwise, find the client under the pointer and send the event along. */ double sx = 0, sy = 0; struct wlr_surface *surface = NULL; + /* XXX handle cursor over LayerShell surface as well */ Client *c = xytoclient(cursor->x, cursor->y, &surface, &sx, &sy); /* If there's no client under the cursor, set the cursor image to a * default. This is what makes the cursor image appear when you move it @@ -815,20 +913,14 @@ render(struct wlr_surface *surface, int sx, int sy, void *data) if (!texture) return; - /* The client has a position in layout coordinates. If you have two displays, - * one next to the other, both 1080p, a client on the rightmost display might - * have layout coordinates of 2000,100. We need to translate that to - * output-local coordinates, or (2000 - 1920). */ - double ox = 0, oy = 0; - wlr_output_layout_output_coords( - output_layout, output, &ox, &oy); - ox += rdata->x + sx, oy += rdata->y + sy; + double ox = rdata->x, oy = rdata->y; + wlr_output_layout_output_coords(output_layout, output, &ox, &oy); /* We also have to apply the scale factor for HiDPI outputs. This is only * part of the puzzle, dwl does not fully support HiDPI. */ struct wlr_box obox = { - .x = ox, - .y = oy, + .x = ox + sx, + .y = oy + sy, .width = surface->current.width, .height = surface->current.height, }; @@ -902,6 +994,25 @@ renderclients(Monitor *m, struct timespec *now) } } +void +renderlayer(Monitor *m, enum zwlr_layer_shell_v1_layer layer, + struct timespec *now) +{ + LayerShell *shell; + wl_list_for_each_reverse(shell, &m->layers[layer], link) { + if (!shell->mapped) + continue; + struct render_data rdata = { + .output = m->wlr_output, + .when = now, + .x = shell->x, + .y = shell->y, + }; + wlr_layer_surface_v1_for_each_surface(shell->layer_surface, + render, &rdata); + } +} + void rendermon(struct wl_listener *listener, void *data) { @@ -920,7 +1031,12 @@ rendermon(struct wl_listener *listener, void *data) wlr_renderer_begin(drw, m->wlr_output->width, m->wlr_output->height); wlr_renderer_clear(drw, rootcolor); + /* Render layers and clients in the correct order */ + renderlayer(m, ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND, &now); + renderlayer(m, ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, &now); renderclients(m, &now); + renderlayer(m, ZWLR_LAYER_SHELL_V1_LAYER_TOP, &now); + renderlayer(m, ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, &now); /* Hardware cursors are rendered by the GPU on a separate plane, and can be * moved around without re-rendering what's beneath them - which is more @@ -988,6 +1104,7 @@ run(char *startup_cmd) /* Set the WAYLAND_DISPLAY environment variable to our socket and run the * startup command if requested. */ + unsetenv("DISPLAY"); setenv("WAYLAND_DISPLAY", socket, true); if (startup_cmd) { startup_pid = fork(); @@ -1026,15 +1143,6 @@ scalebox(struct wlr_box *box, float scale) box->height *= scale; } -Client * -selclient(void) -{ - Client *c = wl_container_of(fstack.next, c, flink); - if (wl_list_empty(&fstack) || !VISIBLEON(c, selmon)) - return NULL; - return c; -} - void setcursor(struct wl_listener *listener, void *data) { @@ -1094,7 +1202,7 @@ setmon(Client *c, Monitor *m) { if (c->mon == m) return; - int hadfocus = (c == selclient()); + int hadfocus = (c == selmon->sel); Monitor *oldmon = c->mon; c->mon = m; /* XXX leave/enter is not optimal but works */ @@ -1110,7 +1218,7 @@ setmon(Client *c, Monitor *m) arrange(m); } /* Focus can change if c is the top of selmon before or after */ - if (hadfocus || c == selclient()) + if (hadfocus || c == selmon->sel) refocus(); } @@ -1164,6 +1272,11 @@ setup(void) wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface); + layer_shell = wlr_layer_shell_v1_create(dpy); + new_layer_surface.notify = createlayer; + wl_signal_add(&layer_shell->events.new_surface, + &new_layer_surface); + /* * Creates a cursor, which is a wlroots utility for tracking the cursor * image shown on screen. @@ -1219,6 +1332,8 @@ setup(void) void spawn(const Arg *arg) { + if (arg->v == menucmd) + menumon[0] = '1'; /* XXX '0' + selmon->num; */ if (fork() == 0) { setsid(); execvp(((char **)arg->v)[0], (char **)arg->v); @@ -1231,9 +1346,8 @@ spawn(const Arg *arg) void tag(const Arg *arg) { - Client *sel = selclient(); - if (sel && arg->ui & TAGMASK) { - sel->tags = arg->ui & TAGMASK; + if (selmon->sel && arg->ui & TAGMASK) { + selmon->sel->tags = arg->ui & TAGMASK; refocus(); arrange(selmon); } @@ -1242,10 +1356,9 @@ tag(const Arg *arg) void tagmon(const Arg *arg) { - Client *sel = selclient(); - if (!sel) + if (!selmon->sel) return; - setmon(sel, dirtomon(arg->i)); + setmon(selmon->sel, dirtomon(arg->i)); } void @@ -1285,23 +1398,22 @@ tile(Monitor *m) void togglefloating(const Arg *arg) { - Client *sel = selclient(); - if (!sel) + if (!selmon->sel) return; /* return if fullscreen */ - setfloating(sel, !sel->isfloating /* || sel->isfixed */); + setfloating(selmon->sel, !selmon->sel->isfloating /* || selmon->sel->isfixed */); } void toggletag(const Arg *arg) { unsigned int newtags; - Client *sel = selclient(); - if (!sel) + + if (!selmon->sel) return; - newtags = sel->tags ^ (arg->ui & TAGMASK); + newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); if (newtags) { - sel->tags = newtags; + selmon->sel->tags = newtags; refocus(); arrange(selmon); } @@ -1319,6 +1431,14 @@ toggleview(const Arg *arg) } } +void +unmaplayer(struct wl_listener *listener, void *data) +{ + /* Called when the surface is unmapped, and should no longer be shown. */ + LayerShell *l = wl_container_of(listener, l, unmap); + l->mapped = false; +} + void unmapnotify(struct wl_listener *listener, void *data) { diff --git a/protocol/wlr-layer-shell-unstable-v1.xml b/protocol/wlr-layer-shell-unstable-v1.xml new file mode 100644 index 0000000..adc6a17 --- /dev/null +++ b/protocol/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. + + + + +