commit db413b4

wf  ·  2026-06-02 14:31:10 +0000 UTC
parent db413b4
Initial
7 files changed,  +2521, -0
+3, -0
1@@ -0,0 +1,3 @@
2+proto/*.c
3+proto/*.h
4+panko
+42, -0
 1@@ -0,0 +1,42 @@
 2+PKG_CONFIG ?= pkg-config
 3+PKGS = wayland-client wld scfg
 4+CLIBS  != $(PKG_CONFIG) --cflags $(PKGS)
 5+LDLIBS != $(PKG_CONFIG) --libs $(PKGS)
 6+
 7+PREFIX = /usr/local
 8+VERSION = 0.1.0
 9+
10+CFLAGS += -g -O0 -Wall -Wextra -Wno-unused-parameter -pedantic -std=c99 -Oz -fcolor-diagnostics -DVERSION=\"$(VERSION)\" -D_POSIX_C_SOURCE=200809L -Iproto/ $(CLIBS)
11+LDFLAGS += $(LDLIBS)
12+
13+SHELL_PROTO = proto/xdg-shell-protocol.h
14+LAYER_PROTO = proto/wlr-layer-shell-unstable-v1.h
15+
16+SRC = $(SHELL_PROTO:.h=.c) $(LAYER_PROTO:.h=.c) src/panko.c
17+OUT = panko
18+
19+all: $(SHELL_PROTO) $(SHELL_PROTO:.h=.c) $(LAYER_PROTO) $(LAYER_PROTO:.h=.c) $(OUT)
20+
21+# ugh
22+$(SHELL_PROTO): proto/xdg-shell.xml
23+	wayland-scanner client-header $^ $@
24+$(SHELL_PROTO:.h=.c): proto/xdg-shell.xml
25+	wayland-scanner private-code $^ $@
26+$(LAYER_PROTO): proto/wlr-layer-shell-unstable-v1.xml
27+	wayland-scanner client-header $^ $@
28+$(LAYER_PROTO:.h=.c): proto/wlr-layer-shell-unstable-v1.xml
29+	wayland-scanner private-code $^ $@
30+
31+$(OUT): $(SRC)
32+	$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
33+
34+install: $(OUT)
35+	install -Dm755 $(OUT) $(PREFIX)/bin/$(OUT)
36+
37+uninstall:
38+	rm -f $(PREFIX)/bin/$(OUT)
39+
40+clean:
41+	rm -f $(SHELL_PROTO) $(SHELL_PROTO:.h=.c) $(LAYER_PROTO) $(LAYER_PROTO:.h=.c) $(OUT)
42+
43+.PHONY: all install uninstall clean
+18, -0
 1@@ -0,0 +1,18 @@
 2+panko
 3+=====
 4+
 5+An attempt at a module-based panel/bar for Wayland.
 6+
 7+Notes
 8+-----
 9+
10+It doesn't compile because I was changing the prototypes for the strings and forgot to change the string ops accordingly.
11+
12+Plus the config parsing is disgustingly implemented, but there's no better way (not that I can immediately think of).
13+
14+Dependencies
15+------------
16+
17+* libwayland-client
18+* neuwld
19+* libscfg
+65, -0
 1@@ -0,0 +1,65 @@
 2+Outline:
 3+
 4+The content is drawn based on 'modules' (ala tint2, polybar, etc.),
 5+which can be any sort of styled or otherwise configurable text.
 6+The configuration is in one singular .scfg file, where modules,
 7+alongside other bar variables, are defined. Here is an example of the
 8+configuration file:
 9+
10+```scfg
11+# Bar width/height
12+width 1920
13+height 30
14+
15+# Screen edges to align the bar to (top, right, bottom, left)
16+anchor bottom
17+
18+# Margins relative to the screen edges, in the format of [top right bottom left] (all mandatory)
19+margins 0 0 10 0
20+
21+# Padding relative to the edges of the bar, in the same format as the margins
22+padding 2 10 2 10
23+
24+# Whether the compositor should reserve space for the bar (true/false)
25+exclusive true
26+
27+# Bar style keys, same as modules with the exception of borders. Colors can be hex or named (e.g. Azure)
28+style {
29+	foreground "#ff00ff"
30+	background "#121212"
31+	font "Terminus"
32+}
33+
34+# An example module definiton
35+module "time" {
36+	# Source command for the text
37+	command "date +'%a %R'"
38+	# Interval at which to execute the source command (seconds)
39+	interval 10
40+
41+	# Module margins, in the format of [top right bottom left] (all mandatory)
42+	margins 5 0 5 0
43+	padding 5 5 5 5
44+	# Implicit geometry for the module (if it's not set, then it's inferred from text size)
45+	width 60
46+	height 30
47+
48+	# Style keys, unset ones are inherited from bar
49+	style {
50+		foreground "#ffffff"
51+		background "#000000"
52+		font "monospace:size=10"
53+		border-width 2
54+		border-color "#ff0000"
55+	}
56+}
57+
58+# Modules to display on the left/middle/right side of the bar
59+modules-left ""
60+modules-middle ""
61+modules-right "time"
62+```
63+
64+Things like importing other files and on-the-fly reloading are possible,
65+but not in the scope of this program and could easily be done with a tiny
66+bit of shell glue.
+407, -0
  1@@ -0,0 +1,407 @@
  2+<?xml version="1.0" encoding="UTF-8"?>
  3+<protocol name="wlr_layer_shell_unstable_v1">
  4+  <copyright>
  5+    Copyright © 2017 Drew DeVault
  6+
  7+    Permission to use, copy, modify, distribute, and sell this
  8+    software and its documentation for any purpose is hereby granted
  9+    without fee, provided that the above copyright notice appear in
 10+    all copies and that both that copyright notice and this permission
 11+    notice appear in supporting documentation, and that the name of
 12+    the copyright holders not be used in advertising or publicity
 13+    pertaining to distribution of the software without specific,
 14+    written prior permission.  The copyright holders make no
 15+    representations about the suitability of this software for any
 16+    purpose.  It is provided "as is" without express or implied
 17+    warranty.
 18+
 19+    THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
 20+    SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 21+    FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
 22+    SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 23+    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 24+    AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 25+    ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 26+    THIS SOFTWARE.
 27+  </copyright>
 28+
 29+  <interface name="zwlr_layer_shell_v1" version="5">
 30+    <description summary="create surfaces that are layers of the desktop">
 31+      Clients can use this interface to assign the surface_layer role to
 32+      wl_surfaces. Such surfaces are assigned to a "layer" of the output and
 33+      rendered with a defined z-depth respective to each other. They may also be
 34+      anchored to the edges and corners of a screen and specify input handling
 35+      semantics. This interface should be suitable for the implementation of
 36+      many desktop shell components, and a broad number of other applications
 37+      that interact with the desktop.
 38+    </description>
 39+
 40+    <request name="get_layer_surface">
 41+      <description summary="create a layer_surface from a surface">
 42+        Create a layer surface for an existing surface. This assigns the role of
 43+        layer_surface, or raises a protocol error if another role is already
 44+        assigned.
 45+
 46+        Creating a layer surface from a wl_surface which has a buffer attached
 47+        or committed is a client error, and any attempts by a client to attach
 48+        or manipulate a buffer prior to the first layer_surface.configure call
 49+        must also be treated as errors.
 50+
 51+        After creating a layer_surface object and setting it up, the client
 52+        must perform an initial commit without any buffer attached.
 53+        The compositor will reply with a layer_surface.configure event.
 54+        The client must acknowledge it and is then allowed to attach a buffer
 55+        to map the surface.
 56+
 57+        You may pass NULL for output to allow the compositor to decide which
 58+        output to use. Generally this will be the one that the user most
 59+        recently interacted with.
 60+
 61+        Clients can specify a namespace that defines the purpose of the layer
 62+        surface.
 63+      </description>
 64+      <arg name="id" type="new_id" interface="zwlr_layer_surface_v1"/>
 65+      <arg name="surface" type="object" interface="wl_surface"/>
 66+      <arg name="output" type="object" interface="wl_output" allow-null="true"/>
 67+      <arg name="layer" type="uint" enum="layer" summary="layer to add this surface to"/>
 68+      <arg name="namespace" type="string" summary="namespace for the layer surface"/>
 69+    </request>
 70+
 71+    <enum name="error">
 72+      <entry name="role" value="0" summary="wl_surface has another role"/>
 73+      <entry name="invalid_layer" value="1" summary="layer value is invalid"/>
 74+      <entry name="already_constructed" value="2" summary="wl_surface has a buffer attached or committed"/>
 75+    </enum>
 76+
 77+    <enum name="layer">
 78+      <description summary="available layers for surfaces">
 79+        These values indicate which layers a surface can be rendered in. They
 80+        are ordered by z depth, bottom-most first. Traditional shell surfaces
 81+        will typically be rendered between the bottom and top layers.
 82+        Fullscreen shell surfaces are typically rendered at the top layer.
 83+        Multiple surfaces can share a single layer, and ordering within a
 84+        single layer is undefined.
 85+      </description>
 86+
 87+      <entry name="background" value="0"/>
 88+      <entry name="bottom" value="1"/>
 89+      <entry name="top" value="2"/>
 90+      <entry name="overlay" value="3"/>
 91+    </enum>
 92+
 93+    <!-- Version 3 additions -->
 94+
 95+    <request name="destroy" type="destructor" since="3">
 96+      <description summary="destroy the layer_shell object">
 97+        This request indicates that the client will not use the layer_shell
 98+        object any more. Objects that have been created through this instance
 99+        are not affected.
100+      </description>
101+    </request>
102+  </interface>
103+
104+  <interface name="zwlr_layer_surface_v1" version="5">
105+    <description summary="layer metadata interface">
106+      An interface that may be implemented by a wl_surface, for surfaces that
107+      are designed to be rendered as a layer of a stacked desktop-like
108+      environment.
109+
110+      Layer surface state (layer, size, anchor, exclusive zone,
111+      margin, interactivity) is double-buffered, and will be applied at the
112+      time wl_surface.commit of the corresponding wl_surface is called.
113+
114+      Attaching a null buffer to a layer surface unmaps it.
115+
116+      Unmapping a layer_surface means that the surface cannot be shown by the
117+      compositor until it is explicitly mapped again. The layer_surface
118+      returns to the state it had right after layer_shell.get_layer_surface.
119+      The client can re-map the surface by performing a commit without any
120+      buffer attached, waiting for a configure event and handling it as usual.
121+    </description>
122+
123+    <request name="set_size">
124+      <description summary="sets the size of the surface">
125+        Sets the size of the surface in surface-local coordinates. The
126+        compositor will display the surface centered with respect to its
127+        anchors.
128+
129+        If you pass 0 for either value, the compositor will assign it and
130+        inform you of the assignment in the configure event. You must set your
131+        anchor to opposite edges in the dimensions you omit; not doing so is a
132+        protocol error. Both values are 0 by default.
133+
134+        Size is double-buffered, see wl_surface.commit.
135+      </description>
136+      <arg name="width" type="uint"/>
137+      <arg name="height" type="uint"/>
138+    </request>
139+
140+    <request name="set_anchor">
141+      <description summary="configures the anchor point of the surface">
142+        Requests that the compositor anchor the surface to the specified edges
143+        and corners. If two orthogonal edges are specified (e.g. 'top' and
144+        'left'), then the anchor point will be the intersection of the edges
145+        (e.g. the top left corner of the output); otherwise the anchor point
146+        will be centered on that edge, or in the center if none is specified.
147+
148+        Anchor is double-buffered, see wl_surface.commit.
149+      </description>
150+      <arg name="anchor" type="uint" enum="anchor"/>
151+    </request>
152+
153+    <request name="set_exclusive_zone">
154+      <description summary="configures the exclusive geometry of this surface">
155+        Requests that the compositor avoids occluding an area with other
156+        surfaces. The compositor's use of this information is
157+        implementation-dependent - do not assume that this region will not
158+        actually be occluded.
159+
160+        A positive value is only meaningful if the surface is anchored to one
161+        edge or an edge and both perpendicular edges. If the surface is not
162+        anchored, anchored to only two perpendicular edges (a corner), anchored
163+        to only two parallel edges or anchored to all edges, a positive value
164+        will be treated the same as zero.
165+
166+        A positive zone is the distance from the edge in surface-local
167+        coordinates to consider exclusive.
168+
169+        Surfaces that do not wish to have an exclusive zone may instead specify
170+        how they should interact with surfaces that do. If set to zero, the
171+        surface indicates that it would like to be moved to avoid occluding
172+        surfaces with a positive exclusive zone. If set to -1, the surface
173+        indicates that it would not like to be moved to accommodate for other
174+        surfaces, and the compositor should extend it all the way to the edges
175+        it is anchored to.
176+
177+        For example, a panel might set its exclusive zone to 10, so that
178+        maximized shell surfaces are not shown on top of it. A notification
179+        might set its exclusive zone to 0, so that it is moved to avoid
180+        occluding the panel, but shell surfaces are shown underneath it. A
181+        wallpaper or lock screen might set their exclusive zone to -1, so that
182+        they stretch below or over the panel.
183+
184+        The default value is 0.
185+
186+        Exclusive zone is double-buffered, see wl_surface.commit.
187+      </description>
188+      <arg name="zone" type="int"/>
189+    </request>
190+
191+    <request name="set_margin">
192+      <description summary="sets a margin from the anchor point">
193+        Requests that the surface be placed some distance away from the anchor
194+        point on the output, in surface-local coordinates. Setting this value
195+        for edges you are not anchored to has no effect.
196+
197+        The exclusive zone includes the margin.
198+
199+        Margin is double-buffered, see wl_surface.commit.
200+      </description>
201+      <arg name="top" type="int"/>
202+      <arg name="right" type="int"/>
203+      <arg name="bottom" type="int"/>
204+      <arg name="left" type="int"/>
205+    </request>
206+
207+    <enum name="keyboard_interactivity">
208+      <description summary="types of keyboard interaction possible for a layer shell surface">
209+        Types of keyboard interaction possible for layer shell surfaces. The
210+        rationale for this is twofold: (1) some applications are not interested
211+        in keyboard events and not allowing them to be focused can improve the
212+        desktop experience; (2) some applications will want to take exclusive
213+        keyboard focus.
214+      </description>
215+
216+      <entry name="none" value="0">
217+        <description summary="no keyboard focus is possible">
218+          This value indicates that this surface is not interested in keyboard
219+          events and the compositor should never assign it the keyboard focus.
220+
221+          This is the default value, set for newly created layer shell surfaces.
222+
223+          This is useful for e.g. desktop widgets that display information or
224+          only have interaction with non-keyboard input devices.
225+        </description>
226+      </entry>
227+      <entry name="exclusive" value="1">
228+        <description summary="request exclusive keyboard focus">
229+          Request exclusive keyboard focus if this surface is above the shell surface layer.
230+
231+          For the top and overlay layers, the seat will always give
232+          exclusive keyboard focus to the top-most layer which has keyboard
233+          interactivity set to exclusive. If this layer contains multiple
234+          surfaces with keyboard interactivity set to exclusive, the compositor
235+          determines the one receiving keyboard events in an implementation-
236+          defined manner. In this case, no guarantee is made when this surface
237+          will receive keyboard focus (if ever).
238+
239+          For the bottom and background layers, the compositor is allowed to use
240+          normal focus semantics.
241+
242+          This setting is mainly intended for applications that need to ensure
243+          they receive all keyboard events, such as a lock screen or a password
244+          prompt.
245+        </description>
246+      </entry>
247+      <entry name="on_demand" value="2" since="4">
248+        <description summary="request regular keyboard focus semantics">
249+          This requests the compositor to allow this surface to be focused and
250+          unfocused by the user in an implementation-defined manner. The user
251+          should be able to unfocus this surface even regardless of the layer
252+          it is on.
253+
254+          Typically, the compositor will want to use its normal mechanism to
255+          manage keyboard focus between layer shell surfaces with this setting
256+          and regular toplevels on the desktop layer (e.g. click to focus).
257+          Nevertheless, it is possible for a compositor to require a special
258+          interaction to focus or unfocus layer shell surfaces (e.g. requiring
259+          a click even if focus follows the mouse normally, or providing a
260+          keybinding to switch focus between layers).
261+
262+          This setting is mainly intended for desktop shell components (e.g.
263+          panels) that allow keyboard interaction. Using this option can allow
264+          implementing a desktop shell that can be fully usable without the
265+          mouse.
266+        </description>
267+      </entry>
268+    </enum>
269+
270+    <request name="set_keyboard_interactivity">
271+      <description summary="requests keyboard events">
272+        Set how keyboard events are delivered to this surface. By default,
273+        layer shell surfaces do not receive keyboard events; this request can
274+        be used to change this.
275+
276+        This setting is inherited by child surfaces set by the get_popup
277+        request.
278+
279+        Layer surfaces receive pointer, touch, and tablet events normally. If
280+        you do not want to receive them, set the input region on your surface
281+        to an empty region.
282+
283+        Keyboard interactivity is double-buffered, see wl_surface.commit.
284+      </description>
285+      <arg name="keyboard_interactivity" type="uint" enum="keyboard_interactivity"/>
286+    </request>
287+
288+    <request name="get_popup">
289+      <description summary="assign this layer_surface as an xdg_popup parent">
290+        This assigns an xdg_popup's parent to this layer_surface.  This popup
291+        should have been created via xdg_surface::get_popup with the parent set
292+        to NULL, and this request must be invoked before committing the popup's
293+        initial state.
294+
295+        See the documentation of xdg_popup for more details about what an
296+        xdg_popup is and how it is used.
297+      </description>
298+      <arg name="popup" type="object" interface="xdg_popup"/>
299+    </request>
300+
301+    <request name="ack_configure">
302+      <description summary="ack a configure event">
303+        When a configure event is received, if a client commits the
304+        surface in response to the configure event, then the client
305+        must make an ack_configure request sometime before the commit
306+        request, passing along the serial of the configure event.
307+
308+        If the client receives multiple configure events before it
309+        can respond to one, it only has to ack the last configure event.
310+
311+        A client is not required to commit immediately after sending
312+        an ack_configure request - it may even ack_configure several times
313+        before its next surface commit.
314+
315+        A client may send multiple ack_configure requests before committing, but
316+        only the last request sent before a commit indicates which configure
317+        event the client really is responding to.
318+      </description>
319+      <arg name="serial" type="uint" summary="the serial from the configure event"/>
320+    </request>
321+
322+    <request name="destroy" type="destructor">
323+      <description summary="destroy the layer_surface">
324+        This request destroys the layer surface.
325+      </description>
326+    </request>
327+
328+    <event name="configure">
329+      <description summary="suggest a surface change">
330+        The configure event asks the client to resize its surface.
331+
332+        Clients should arrange their surface for the new states, and then send
333+        an ack_configure request with the serial sent in this configure event at
334+        some point before committing the new surface.
335+
336+        The client is free to dismiss all but the last configure event it
337+        received.
338+
339+        The width and height arguments specify the size of the window in
340+        surface-local coordinates.
341+
342+        The size is a hint, in the sense that the client is free to ignore it if
343+        it doesn't resize, pick a smaller size (to satisfy aspect ratio or
344+        resize in steps of NxM pixels). If the client picks a smaller size and
345+        is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the
346+        surface will be centered on this axis.
347+
348+        If the width or height arguments are zero, it means the client should
349+        decide its own window dimension.
350+      </description>
351+      <arg name="serial" type="uint"/>
352+      <arg name="width" type="uint"/>
353+      <arg name="height" type="uint"/>
354+    </event>
355+
356+    <event name="closed">
357+      <description summary="surface should be closed">
358+        The closed event is sent by the compositor when the surface will no
359+        longer be shown. The output may have been destroyed or the user may
360+        have asked for it to be removed. Further changes to the surface will be
361+        ignored. The client should destroy the resource after receiving this
362+        event, and create a new surface if they so choose.
363+      </description>
364+    </event>
365+
366+    <enum name="error">
367+      <entry name="invalid_surface_state" value="0" summary="provided surface state is invalid"/>
368+      <entry name="invalid_size" value="1" summary="size is invalid"/>
369+      <entry name="invalid_anchor" value="2" summary="anchor bitfield is invalid"/>
370+      <entry name="invalid_keyboard_interactivity" value="3" summary="keyboard interactivity is invalid"/>
371+      <entry name="invalid_exclusive_edge" value="4" summary="exclusive edge is invalid given the surface anchors"/>
372+    </enum>
373+
374+    <enum name="anchor" bitfield="true">
375+      <entry name="top" value="1" summary="the top edge of the anchor rectangle"/>
376+      <entry name="bottom" value="2" summary="the bottom edge of the anchor rectangle"/>
377+      <entry name="left" value="4" summary="the left edge of the anchor rectangle"/>
378+      <entry name="right" value="8" summary="the right edge of the anchor rectangle"/>
379+    </enum>
380+
381+    <!-- Version 2 additions -->
382+
383+    <request name="set_layer" since="2">
384+      <description summary="change the layer of the surface">
385+        Change the layer that the surface is rendered on.
386+
387+        Layer is double-buffered, see wl_surface.commit.
388+      </description>
389+      <arg name="layer" type="uint" enum="zwlr_layer_shell_v1.layer" summary="layer to move this surface to"/>
390+    </request>
391+
392+    <!-- Version 5 additions -->
393+
394+    <request name="set_exclusive_edge" since="5">
395+      <description summary="set the edge the exclusive zone will be applied to">
396+        Requests an edge for the exclusive zone to apply. The exclusive
397+        edge will be automatically deduced from anchor points when possible,
398+        but when the surface is anchored to a corner, it will be necessary
399+        to set it explicitly to disambiguate, as it is not possible to deduce
400+        which one of the two corner edges should be used.
401+
402+        The edge must be one the surface is anchored to, otherwise the
403+        invalid_exclusive_edge protocol error will be raised.
404+      </description>
405+      <arg name="edge" type="uint" enum="anchor"/>
406+    </request>
407+  </interface>
408+</protocol>
+1418, -0
   1@@ -0,0 +1,1418 @@
   2+<?xml version="1.0" encoding="UTF-8"?>
   3+<protocol name="xdg_shell">
   4+
   5+  <copyright>
   6+    Copyright © 2008-2013 Kristian Høgsberg
   7+    Copyright © 2013      Rafael Antognolli
   8+    Copyright © 2013      Jasper St. Pierre
   9+    Copyright © 2010-2013 Intel Corporation
  10+    Copyright © 2015-2017 Samsung Electronics Co., Ltd
  11+    Copyright © 2015-2017 Red Hat Inc.
  12+
  13+    Permission is hereby granted, free of charge, to any person obtaining a
  14+    copy of this software and associated documentation files (the "Software"),
  15+    to deal in the Software without restriction, including without limitation
  16+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
  17+    and/or sell copies of the Software, and to permit persons to whom the
  18+    Software is furnished to do so, subject to the following conditions:
  19+
  20+    The above copyright notice and this permission notice (including the next
  21+    paragraph) shall be included in all copies or substantial portions of the
  22+    Software.
  23+
  24+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  25+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  26+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  27+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  28+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  29+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  30+    DEALINGS IN THE SOFTWARE.
  31+  </copyright>
  32+
  33+  <interface name="xdg_wm_base" version="7">
  34+    <description summary="create desktop-style surfaces">
  35+      The xdg_wm_base interface is exposed as a global object enabling clients
  36+      to turn their wl_surfaces into windows in a desktop environment. It
  37+      defines the basic functionality needed for clients and the compositor to
  38+      create windows that can be dragged, resized, maximized, etc, as well as
  39+      creating transient windows such as popup menus.
  40+    </description>
  41+
  42+    <enum name="error">
  43+      <entry name="role" value="0" summary="given wl_surface has another role"/>
  44+      <entry name="defunct_surfaces" value="1"
  45+	     summary="xdg_wm_base was destroyed before children"/>
  46+      <entry name="not_the_topmost_popup" value="2"
  47+	     summary="the client tried to map or destroy a non-topmost popup"/>
  48+      <entry name="invalid_popup_parent" value="3"
  49+	     summary="the client specified an invalid popup parent surface"/>
  50+      <entry name="invalid_surface_state" value="4"
  51+	     summary="the client provided an invalid surface state"/>
  52+      <entry name="invalid_positioner" value="5"
  53+	     summary="the client provided an invalid positioner"/>
  54+      <entry name="unresponsive" value="6"
  55+	     summary="the client didn’t respond to a ping event in time"/>
  56+    </enum>
  57+
  58+    <request name="destroy" type="destructor">
  59+      <description summary="destroy xdg_wm_base">
  60+	Destroy this xdg_wm_base object.
  61+
  62+	Destroying a bound xdg_wm_base object while there are surfaces
  63+	still alive created by this xdg_wm_base object instance is illegal
  64+	and will result in a defunct_surfaces error.
  65+      </description>
  66+    </request>
  67+
  68+    <request name="create_positioner">
  69+      <description summary="create a positioner object">
  70+	Create a positioner object. A positioner object is used to position
  71+	surfaces relative to some parent surface. See the interface description
  72+	and xdg_surface.get_popup for details.
  73+      </description>
  74+      <arg name="id" type="new_id" interface="xdg_positioner"/>
  75+    </request>
  76+
  77+    <request name="get_xdg_surface">
  78+      <description summary="create a shell surface from a surface">
  79+	This creates an xdg_surface for the given surface. While xdg_surface
  80+	itself is not a role, the corresponding surface may only be assigned
  81+	a role extending xdg_surface, such as xdg_toplevel or xdg_popup. It is
  82+	illegal to create an xdg_surface for a wl_surface which already has an
  83+	assigned role and this will result in a role error.
  84+
  85+	This creates an xdg_surface for the given surface. An xdg_surface is
  86+	used as basis to define a role to a given surface, such as xdg_toplevel
  87+	or xdg_popup. It also manages functionality shared between xdg_surface
  88+	based surface roles.
  89+
  90+	See the documentation of xdg_surface for more details about what an
  91+	xdg_surface is and how it is used.
  92+      </description>
  93+      <arg name="id" type="new_id" interface="xdg_surface"/>
  94+      <arg name="surface" type="object" interface="wl_surface"/>
  95+    </request>
  96+
  97+    <request name="pong">
  98+      <description summary="respond to a ping event">
  99+	A client must respond to a ping event with a pong request or
 100+	the client may be deemed unresponsive. See xdg_wm_base.ping
 101+	and xdg_wm_base.error.unresponsive.
 102+      </description>
 103+      <arg name="serial" type="uint" summary="serial of the ping event"/>
 104+    </request>
 105+
 106+    <event name="ping">
 107+      <description summary="check if the client is alive">
 108+	The ping event asks the client if it's still alive. Pass the
 109+	serial specified in the event back to the compositor by sending
 110+	a "pong" request back with the specified serial. See xdg_wm_base.pong.
 111+
 112+	Compositors can use this to determine if the client is still
 113+	alive. It's unspecified what will happen if the client doesn't
 114+	respond to the ping request, or in what timeframe. Clients should
 115+	try to respond in a reasonable amount of time. The “unresponsive”
 116+	error is provided for compositors that wish to disconnect unresponsive
 117+	clients.
 118+
 119+	A compositor is free to ping in any way it wants, but a client must
 120+	always respond to any xdg_wm_base object it created.
 121+      </description>
 122+      <arg name="serial" type="uint" summary="pass this to the pong request"/>
 123+    </event>
 124+  </interface>
 125+
 126+  <interface name="xdg_positioner" version="7">
 127+    <description summary="child surface positioner">
 128+      The xdg_positioner provides a collection of rules for the placement of a
 129+      child surface relative to a parent surface. Rules can be defined to ensure
 130+      the child surface remains within the visible area's borders, and to
 131+      specify how the child surface changes its position, such as sliding along
 132+      an axis, or flipping around a rectangle. These positioner-created rules are
 133+      constrained by the requirement that a child surface must intersect with or
 134+      be at least partially adjacent to its parent surface.
 135+
 136+      See the various requests for details about possible rules.
 137+
 138+      At the time of the request, the compositor makes a copy of the rules
 139+      specified by the xdg_positioner. Thus, after the request is complete the
 140+      xdg_positioner object can be destroyed or reused; further changes to the
 141+      object will have no effect on previous usages.
 142+
 143+      For an xdg_positioner object to be considered complete, it must have a
 144+      non-zero size set by set_size, and a non-zero anchor rectangle set by
 145+      set_anchor_rect. Passing an incomplete xdg_positioner object when
 146+      positioning a surface raises an invalid_positioner error.
 147+    </description>
 148+
 149+    <enum name="error">
 150+      <entry name="invalid_input" value="0" summary="invalid input provided"/>
 151+    </enum>
 152+
 153+    <request name="destroy" type="destructor">
 154+      <description summary="destroy the xdg_positioner object">
 155+	Notify the compositor that the xdg_positioner will no longer be used.
 156+      </description>
 157+    </request>
 158+
 159+    <request name="set_size">
 160+      <description summary="set the size of the to-be positioned rectangle">
 161+	Set the size of the surface that is to be positioned with the positioner
 162+	object. The size is in surface-local coordinates and corresponds to the
 163+	window geometry. See xdg_surface.set_window_geometry.
 164+
 165+	If a zero or negative size is set the invalid_input error is raised.
 166+      </description>
 167+      <arg name="width" type="int" summary="width of positioned rectangle"/>
 168+      <arg name="height" type="int" summary="height of positioned rectangle"/>
 169+    </request>
 170+
 171+    <request name="set_anchor_rect">
 172+      <description summary="set the anchor rectangle within the parent surface">
 173+	Specify the anchor rectangle within the parent surface that the child
 174+	surface will be placed relative to. The rectangle is relative to the
 175+	window geometry as defined by xdg_surface.set_window_geometry of the
 176+	parent surface.
 177+
 178+	When the xdg_positioner object is used to position a child surface, the
 179+	anchor rectangle may not extend outside the window geometry of the
 180+	positioned child's parent surface.
 181+
 182+	If a negative size is set the invalid_input error is raised.
 183+      </description>
 184+      <arg name="x" type="int" summary="x position of anchor rectangle"/>
 185+      <arg name="y" type="int" summary="y position of anchor rectangle"/>
 186+      <arg name="width" type="int" summary="width of anchor rectangle"/>
 187+      <arg name="height" type="int" summary="height of anchor rectangle"/>
 188+    </request>
 189+
 190+    <enum name="anchor">
 191+      <entry name="none" value="0"/>
 192+      <entry name="top" value="1"/>
 193+      <entry name="bottom" value="2"/>
 194+      <entry name="left" value="3"/>
 195+      <entry name="right" value="4"/>
 196+      <entry name="top_left" value="5"/>
 197+      <entry name="bottom_left" value="6"/>
 198+      <entry name="top_right" value="7"/>
 199+      <entry name="bottom_right" value="8"/>
 200+    </enum>
 201+
 202+    <request name="set_anchor">
 203+      <description summary="set anchor rectangle anchor">
 204+	Defines the anchor point for the anchor rectangle. The specified anchor
 205+	is used derive an anchor point that the child surface will be
 206+	positioned relative to. If a corner anchor is set (e.g. 'top_left' or
 207+	'bottom_right'), the anchor point will be at the specified corner;
 208+	otherwise, the derived anchor point will be centered on the specified
 209+	edge, or in the center of the anchor rectangle if no edge is specified.
 210+      </description>
 211+      <arg name="anchor" type="uint" enum="anchor"
 212+	   summary="anchor"/>
 213+    </request>
 214+
 215+    <enum name="gravity">
 216+      <entry name="none" value="0"/>
 217+      <entry name="top" value="1"/>
 218+      <entry name="bottom" value="2"/>
 219+      <entry name="left" value="3"/>
 220+      <entry name="right" value="4"/>
 221+      <entry name="top_left" value="5"/>
 222+      <entry name="bottom_left" value="6"/>
 223+      <entry name="top_right" value="7"/>
 224+      <entry name="bottom_right" value="8"/>
 225+    </enum>
 226+
 227+    <request name="set_gravity">
 228+      <description summary="set child surface gravity">
 229+	Defines in what direction a surface should be positioned, relative to
 230+	the anchor point of the parent surface. If a corner gravity is
 231+	specified (e.g. 'bottom_right' or 'top_left'), then the child surface
 232+	will be placed towards the specified gravity; otherwise, the child
 233+	surface will be centered over the anchor point on any axis that had no
 234+	gravity specified. If the gravity is not in the ‘gravity’ enum, an
 235+	invalid_input error is raised.
 236+      </description>
 237+      <arg name="gravity" type="uint" enum="gravity"
 238+	   summary="gravity direction"/>
 239+    </request>
 240+
 241+    <enum name="constraint_adjustment" bitfield="true">
 242+      <description summary="constraint adjustments">
 243+	The constraint adjustment value define ways the compositor will adjust
 244+	the position of the surface, if the unadjusted position would result
 245+	in the surface being partly constrained.
 246+
 247+	Whether a surface is considered 'constrained' is left to the compositor
 248+	to determine. For example, the surface may be partly outside the
 249+	compositor's defined 'work area', thus necessitating the child surface's
 250+	position be adjusted until it is entirely inside the work area.
 251+
 252+	The adjustments can be combined, according to a defined precedence: 1)
 253+	Flip, 2) Slide, 3) Resize.
 254+      </description>
 255+      <entry name="none" value="0">
 256+	<description summary="don't move the child surface when constrained">
 257+	  Don't alter the surface position even if it is constrained on some
 258+	  axis, for example partially outside the edge of an output.
 259+	</description>
 260+      </entry>
 261+      <entry name="slide_x" value="1">
 262+	<description summary="move along the x axis until unconstrained">
 263+	  Slide the surface along the x axis until it is no longer constrained.
 264+
 265+	  First try to slide towards the direction of the gravity on the x axis
 266+	  until either the edge in the opposite direction of the gravity is
 267+	  unconstrained or the edge in the direction of the gravity is
 268+	  constrained.
 269+
 270+	  Then try to slide towards the opposite direction of the gravity on the
 271+	  x axis until either the edge in the direction of the gravity is
 272+	  unconstrained or the edge in the opposite direction of the gravity is
 273+	  constrained.
 274+	</description>
 275+      </entry>
 276+      <entry name="slide_y" value="2">
 277+	<description summary="move along the y axis until unconstrained">
 278+	  Slide the surface along the y axis until it is no longer constrained.
 279+
 280+	  First try to slide towards the direction of the gravity on the y axis
 281+	  until either the edge in the opposite direction of the gravity is
 282+	  unconstrained or the edge in the direction of the gravity is
 283+	  constrained.
 284+
 285+	  Then try to slide towards the opposite direction of the gravity on the
 286+	  y axis until either the edge in the direction of the gravity is
 287+	  unconstrained or the edge in the opposite direction of the gravity is
 288+	  constrained.
 289+	</description>
 290+      </entry>
 291+      <entry name="flip_x" value="4">
 292+	<description summary="invert the anchor and gravity on the x axis">
 293+	  Invert the anchor and gravity on the x axis if the surface is
 294+	  constrained on the x axis. For example, if the left edge of the
 295+	  surface is constrained, the gravity is 'left' and the anchor is
 296+	  'left', change the gravity to 'right' and the anchor to 'right'.
 297+
 298+	  If the adjusted position also ends up being constrained, the resulting
 299+	  position of the flip_x adjustment will be the one before the
 300+	  adjustment.
 301+	</description>
 302+      </entry>
 303+      <entry name="flip_y" value="8">
 304+	<description summary="invert the anchor and gravity on the y axis">
 305+	  Invert the anchor and gravity on the y axis if the surface is
 306+	  constrained on the y axis. For example, if the bottom edge of the
 307+	  surface is constrained, the gravity is 'bottom' and the anchor is
 308+	  'bottom', change the gravity to 'top' and the anchor to 'top'.
 309+
 310+	  The adjusted position is calculated given the original anchor
 311+	  rectangle and offset, but with the new flipped anchor and gravity
 312+	  values.
 313+
 314+	  If the adjusted position also ends up being constrained, the resulting
 315+	  position of the flip_y adjustment will be the one before the
 316+	  adjustment.
 317+	</description>
 318+      </entry>
 319+      <entry name="resize_x" value="16">
 320+	<description summary="horizontally resize the surface">
 321+	  Resize the surface horizontally so that it is completely
 322+	  unconstrained.
 323+	</description>
 324+      </entry>
 325+      <entry name="resize_y" value="32">
 326+	<description summary="vertically resize the surface">
 327+	  Resize the surface vertically so that it is completely unconstrained.
 328+	</description>
 329+      </entry>
 330+    </enum>
 331+
 332+    <request name="set_constraint_adjustment">
 333+      <description summary="set the adjustment to be done when constrained">
 334+	Specify how the window should be positioned if the originally intended
 335+	position caused the surface to be constrained, meaning at least
 336+	partially outside positioning boundaries set by the compositor. The
 337+	adjustment is set by constructing a bitmask describing the adjustment to
 338+	be made when the surface is constrained on that axis.
 339+
 340+	If no bit for one axis is set, the compositor will assume that the child
 341+	surface should not change its position on that axis when constrained.
 342+
 343+	If more than one bit for one axis is set, the order of how adjustments
 344+	are applied is specified in the corresponding adjustment descriptions.
 345+
 346+	The default adjustment is none.
 347+      </description>
 348+      <arg name="constraint_adjustment" type="uint" enum="constraint_adjustment"
 349+	   summary="bit mask of constraint adjustments"/>
 350+    </request>
 351+
 352+    <request name="set_offset">
 353+      <description summary="set surface position offset">
 354+	Specify the surface position offset relative to the position of the
 355+	anchor on the anchor rectangle and the anchor on the surface. For
 356+	example if the anchor of the anchor rectangle is at (x, y), the surface
 357+	has the gravity bottom|right, and the offset is (ox, oy), the calculated
 358+	surface position will be (x + ox, y + oy). The offset position of the
 359+	surface is the one used for constraint testing. See
 360+	set_constraint_adjustment.
 361+
 362+	An example use case is placing a popup menu on top of a user interface
 363+	element, while aligning the user interface element of the parent surface
 364+	with some user interface element placed somewhere in the popup surface.
 365+      </description>
 366+      <arg name="x" type="int" summary="surface position x offset"/>
 367+      <arg name="y" type="int" summary="surface position y offset"/>
 368+    </request>
 369+
 370+    <!-- Version 3 additions -->
 371+
 372+    <request name="set_reactive" since="3">
 373+      <description summary="continuously reconstrain the surface">
 374+	When set reactive, the surface is reconstrained if the conditions used
 375+	for constraining changed, e.g. the parent window moved.
 376+
 377+	If the conditions changed and the popup was reconstrained, an
 378+	xdg_popup.configure event is sent with updated geometry, followed by an
 379+	xdg_surface.configure event.
 380+      </description>
 381+    </request>
 382+
 383+    <request name="set_parent_size" since="3">
 384+      <description summary="">
 385+	Set the parent window geometry the compositor should use when
 386+	positioning the popup. The compositor may use this information to
 387+	determine the future state the popup should be constrained using. If
 388+	this doesn't match the dimension of the parent the popup is eventually
 389+	positioned against, the behavior is undefined.
 390+
 391+	The arguments are given in the surface-local coordinate space.
 392+      </description>
 393+      <arg name="parent_width" type="int"
 394+	   summary="future window geometry width of parent"/>
 395+      <arg name="parent_height" type="int"
 396+	   summary="future window geometry height of parent"/>
 397+    </request>
 398+
 399+    <request name="set_parent_configure" since="3">
 400+      <description summary="set parent configure this is a response to">
 401+	Set the serial of an xdg_surface.configure event this positioner will be
 402+	used in response to. The compositor may use this information together
 403+	with set_parent_size to determine what future state the popup should be
 404+	constrained using.
 405+      </description>
 406+      <arg name="serial" type="uint"
 407+	   summary="serial of parent configure event"/>
 408+    </request>
 409+  </interface>
 410+
 411+  <interface name="xdg_surface" version="7">
 412+    <description summary="desktop user interface surface base interface">
 413+      An interface that may be implemented by a wl_surface, for
 414+      implementations that provide a desktop-style user interface.
 415+
 416+      It provides a base set of functionality required to construct user
 417+      interface elements requiring management by the compositor, such as
 418+      toplevel windows, menus, etc. The types of functionality are split into
 419+      xdg_surface roles.
 420+
 421+      Creating an xdg_surface does not set the role for a wl_surface. In order
 422+      to map an xdg_surface, the client must create a role-specific object
 423+      using, e.g., get_toplevel, get_popup. The wl_surface for any given
 424+      xdg_surface can have at most one role, and may not be assigned any role
 425+      not based on xdg_surface.
 426+
 427+      A role must be assigned before any other requests are made to the
 428+      xdg_surface object.
 429+
 430+      The client must call wl_surface.commit on the corresponding wl_surface
 431+      for the xdg_surface state to take effect.
 432+
 433+      Creating an xdg_surface from a wl_surface which has a buffer attached or
 434+      committed is a client error, and any attempts by a client to attach or
 435+      manipulate a buffer prior to the first xdg_surface.configure call must
 436+      also be treated as errors.
 437+
 438+      After creating a role-specific object and setting it up (e.g. by sending
 439+      the title, app ID, size constraints, parent, etc), the client must
 440+      perform an initial commit without any buffer attached. The compositor
 441+      will reply with initial wl_surface state such as
 442+      wl_surface.preferred_buffer_scale followed by an xdg_surface.configure
 443+      event. The client must acknowledge it and is then allowed to attach a
 444+      buffer to map the surface.
 445+
 446+      Mapping an xdg_surface-based role surface is defined as making it
 447+      possible for the surface to be shown by the compositor. Note that
 448+      a mapped surface is not guaranteed to be visible once it is mapped.
 449+
 450+      For an xdg_surface to be mapped by the compositor, the following
 451+      conditions must be met:
 452+      (1) the client has assigned an xdg_surface-based role to the surface
 453+      (2) the client has set and committed the xdg_surface state and the
 454+	  role-dependent state to the surface
 455+      (3) the client has committed a buffer to the surface
 456+
 457+      A newly-unmapped surface is considered to have met condition (1) out
 458+      of the 3 required conditions for mapping a surface if its role surface
 459+      has not been destroyed, i.e. the client must perform the initial commit
 460+      again before attaching a buffer.
 461+    </description>
 462+
 463+    <enum name="error">
 464+      <entry name="not_constructed" value="1"
 465+	     summary="Surface was not fully constructed"/>
 466+      <entry name="already_constructed" value="2"
 467+	     summary="Surface was already constructed"/>
 468+      <entry name="unconfigured_buffer" value="3"
 469+	     summary="Attaching a buffer to an unconfigured surface"/>
 470+      <entry name="invalid_serial" value="4"
 471+	     summary="Invalid serial number when acking a configure event"/>
 472+      <entry name="invalid_size" value="5"
 473+	     summary="Width or height was zero or negative"/>
 474+      <entry name="defunct_role_object" value="6"
 475+	     summary="Surface was destroyed before its role object"/>
 476+    </enum>
 477+
 478+    <request name="destroy" type="destructor">
 479+      <description summary="destroy the xdg_surface">
 480+	Destroy the xdg_surface object. An xdg_surface must only be destroyed
 481+	after its role object has been destroyed, otherwise
 482+	a defunct_role_object error is raised.
 483+      </description>
 484+    </request>
 485+
 486+    <request name="get_toplevel">
 487+      <description summary="assign the xdg_toplevel surface role">
 488+	This creates an xdg_toplevel object for the given xdg_surface and gives
 489+	the associated wl_surface the xdg_toplevel role.
 490+
 491+	See the documentation of xdg_toplevel for more details about what an
 492+	xdg_toplevel is and how it is used.
 493+      </description>
 494+      <arg name="id" type="new_id" interface="xdg_toplevel"/>
 495+    </request>
 496+
 497+    <request name="get_popup">
 498+      <description summary="assign the xdg_popup surface role">
 499+	This creates an xdg_popup object for the given xdg_surface and gives
 500+	the associated wl_surface the xdg_popup role.
 501+
 502+	If null is passed as a parent, a parent surface must be specified using
 503+	some other protocol, before committing the initial state.
 504+
 505+	See the documentation of xdg_popup for more details about what an
 506+	xdg_popup is and how it is used.
 507+      </description>
 508+      <arg name="id" type="new_id" interface="xdg_popup"/>
 509+      <arg name="parent" type="object" interface="xdg_surface" allow-null="true"/>
 510+      <arg name="positioner" type="object" interface="xdg_positioner"/>
 511+    </request>
 512+
 513+    <request name="set_window_geometry">
 514+      <description summary="set the new window geometry">
 515+	The window geometry of a surface is its "visible bounds" from the
 516+	user's perspective. Client-side decorations often have invisible
 517+	portions like drop-shadows which should be ignored for the
 518+	purposes of aligning, placing and constraining windows. Note that
 519+	in some situations, compositors may clip rendering to the window
 520+	geometry, so the client should avoid putting functional elements
 521+	outside of it.
 522+
 523+	The window geometry is double-buffered state, see wl_surface.commit.
 524+
 525+	When maintaining a position, the compositor should treat the (x, y)
 526+	coordinate of the window geometry as the top left corner of the window.
 527+	A client changing the (x, y) window geometry coordinate should in
 528+	general not alter the position of the window.
 529+
 530+	Once the window geometry of the surface is set, it is not possible to
 531+	unset it, and it will remain the same until set_window_geometry is
 532+	called again, even if a new subsurface or buffer is attached.
 533+
 534+	If never set, the value is the full bounds of the surface,
 535+	including any subsurfaces. This updates dynamically on every
 536+	commit. This unset is meant for extremely simple clients.
 537+
 538+	The arguments are given in the surface-local coordinate space of
 539+	the wl_surface associated with this xdg_surface, and may extend outside
 540+	of the wl_surface itself to mark parts of the subsurface tree as part of
 541+	the window geometry.
 542+
 543+	When applied, the effective window geometry will be the set window
 544+	geometry clamped to the bounding rectangle of the combined
 545+	geometry of the surface of the xdg_surface and the associated
 546+	subsurfaces.
 547+
 548+	The effective geometry will not be recalculated unless a new call to
 549+	set_window_geometry is done and the new pending surface state is
 550+	subsequently applied.
 551+
 552+	The width and height of the effective window geometry must be
 553+	greater than zero. Setting an invalid size will raise an
 554+	invalid_size error.
 555+      </description>
 556+      <arg name="x" type="int"/>
 557+      <arg name="y" type="int"/>
 558+      <arg name="width" type="int"/>
 559+      <arg name="height" type="int"/>
 560+    </request>
 561+
 562+    <request name="ack_configure">
 563+      <description summary="ack a configure event">
 564+	When a configure event is received, if a client commits the
 565+	surface in response to the configure event, then the client
 566+	must make an ack_configure request sometime before the commit
 567+	request, passing along the serial of the configure event.
 568+
 569+	For instance, for toplevel surfaces the compositor might use this
 570+	information to move a surface to the top left only when the client has
 571+	drawn itself for the maximized or fullscreen state.
 572+
 573+	If the client receives multiple configure events before it
 574+	can respond to one, it only has to ack the last configure event.
 575+	Acking a configure event that was never sent raises an invalid_serial
 576+	error.
 577+
 578+	A client is not required to commit immediately after sending
 579+	an ack_configure request - it may even ack_configure several times
 580+	before its next surface commit.
 581+
 582+	A client may send multiple ack_configure requests before committing, but
 583+	only the last request sent before a commit indicates which configure
 584+	event the client really is responding to.
 585+
 586+	Sending an ack_configure request consumes the serial number sent with
 587+	the request, as well as serial numbers sent by all configure events
 588+	sent on this xdg_surface prior to the configure event referenced by
 589+	the committed serial.
 590+
 591+	It is an error to issue multiple ack_configure requests referencing a
 592+	serial from the same configure event, or to issue an ack_configure
 593+	request referencing a serial from a configure event issued before the
 594+	event identified by the last ack_configure request for the same
 595+	xdg_surface. Doing so will raise an invalid_serial error.
 596+      </description>
 597+      <arg name="serial" type="uint" summary="the serial from the configure event"/>
 598+    </request>
 599+
 600+    <event name="configure">
 601+      <description summary="suggest a surface change">
 602+	The configure event marks the end of a configure sequence. A configure
 603+	sequence is a set of one or more events configuring the state of the
 604+	xdg_surface, including the final xdg_surface.configure event.
 605+
 606+	Where applicable, xdg_surface surface roles will during a configure
 607+	sequence extend this event as a latched state sent as events before the
 608+	xdg_surface.configure event. Such events should be considered to make up
 609+	a set of atomically applied configuration states, where the
 610+	xdg_surface.configure commits the accumulated state.
 611+
 612+	Clients should arrange their surface for the new states, and then send
 613+	an ack_configure request with the serial sent in this configure event at
 614+	some point before committing the new surface.
 615+
 616+	If the client receives multiple configure events before it can respond
 617+	to one, it is free to discard all but the last event it received.
 618+      </description>
 619+      <arg name="serial" type="uint" summary="serial of the configure event"/>
 620+    </event>
 621+
 622+  </interface>
 623+
 624+  <interface name="xdg_toplevel" version="7">
 625+    <description summary="toplevel surface">
 626+      This interface defines an xdg_surface role which allows a surface to,
 627+      among other things, set window-like properties such as maximize,
 628+      fullscreen, and minimize, set application-specific metadata like title and
 629+      id, and well as trigger user interactive operations such as interactive
 630+      resize and move.
 631+
 632+      A xdg_toplevel by default is responsible for providing the full intended
 633+      visual representation of the toplevel, which depending on the window
 634+      state, may mean things like a title bar, window controls and drop shadow.
 635+
 636+      Unmapping an xdg_toplevel means that the surface cannot be shown
 637+      by the compositor until it is explicitly mapped again.
 638+      All active operations (e.g., move, resize) are canceled and all
 639+      attributes (e.g. title, state, stacking, ...) are discarded for
 640+      an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to
 641+      the state it had right after xdg_surface.get_toplevel. The client
 642+      can re-map the toplevel by performing a commit without any buffer
 643+      attached, waiting for a configure event and handling it as usual (see
 644+      xdg_surface description).
 645+
 646+      Attaching a null buffer to a toplevel unmaps the surface.
 647+    </description>
 648+
 649+    <request name="destroy" type="destructor">
 650+      <description summary="destroy the xdg_toplevel">
 651+	This request destroys the role surface and unmaps the surface;
 652+	see "Unmapping" behavior in interface section for details.
 653+      </description>
 654+    </request>
 655+
 656+    <enum name="error">
 657+      <entry name="invalid_resize_edge" value="0" summary="provided value is
 658+        not a valid variant of the resize_edge enum"/>
 659+      <entry name="invalid_parent" value="1"
 660+        summary="invalid parent toplevel"/>
 661+      <entry name="invalid_size" value="2"
 662+	summary="client provided an invalid min or max size"/>
 663+    </enum>
 664+
 665+    <request name="set_parent">
 666+      <description summary="set the parent of this surface">
 667+	Set the "parent" of this surface. This surface should be stacked
 668+	above the parent surface and all other ancestor surfaces.
 669+
 670+	Parent surfaces should be set on dialogs, toolboxes, or other
 671+	"auxiliary" surfaces, so that the parent is raised when the dialog
 672+	is raised.
 673+
 674+	Setting a null parent for a child surface unsets its parent. Setting
 675+	a null parent for a surface which currently has no parent is a no-op.
 676+
 677+	Only mapped surfaces can have child surfaces. Setting a parent which
 678+	is not mapped is equivalent to setting a null parent. If a surface
 679+	becomes unmapped, its children's parent is set to the parent of
 680+	the now-unmapped surface. If the now-unmapped surface has no parent,
 681+	its children's parent is unset. If the now-unmapped surface becomes
 682+	mapped again, its parent-child relationship is not restored.
 683+
 684+	The parent toplevel must not be one of the child toplevel's
 685+	descendants, and the parent must be different from the child toplevel,
 686+	otherwise the invalid_parent protocol error is raised.
 687+      </description>
 688+      <arg name="parent" type="object" interface="xdg_toplevel" allow-null="true"/>
 689+    </request>
 690+
 691+    <request name="set_title">
 692+      <description summary="set surface title">
 693+	Set a short title for the surface.
 694+
 695+	This string may be used to identify the surface in a task bar,
 696+	window list, or other user interface elements provided by the
 697+	compositor.
 698+
 699+	The string must be encoded in UTF-8.
 700+      </description>
 701+      <arg name="title" type="string"/>
 702+    </request>
 703+
 704+    <request name="set_app_id">
 705+      <description summary="set application ID">
 706+	Set an application identifier for the surface.
 707+
 708+	The app ID identifies the general class of applications to which
 709+	the surface belongs. The compositor can use this to group multiple
 710+	surfaces together, or to determine how to launch a new application.
 711+
 712+	For D-Bus activatable applications, the app ID is used as the D-Bus
 713+	service name.
 714+
 715+	The compositor shell will try to group application surfaces together
 716+	by their app ID. As a best practice, it is suggested to select app
 717+	ID's that match the basename of the application's .desktop file.
 718+	For example, "org.freedesktop.FooViewer" where the .desktop file is
 719+	"org.freedesktop.FooViewer.desktop".
 720+
 721+	Like other properties, a set_app_id request can be sent after the
 722+	xdg_toplevel has been mapped to update the property.
 723+
 724+	See the desktop-entry specification [0] for more details on
 725+	application identifiers and how they relate to well-known D-Bus
 726+	names and .desktop files.
 727+
 728+	[0] https://standards.freedesktop.org/desktop-entry-spec/
 729+      </description>
 730+      <arg name="app_id" type="string"/>
 731+    </request>
 732+
 733+    <request name="show_window_menu">
 734+      <description summary="show the window menu">
 735+	Clients implementing client-side decorations might want to show
 736+	a context menu when right-clicking on the decorations, giving the
 737+	user a menu that they can use to maximize or minimize the window.
 738+
 739+	This request asks the compositor to pop up such a window menu at
 740+	the given position, relative to the local surface coordinates of
 741+	the parent surface. There are no guarantees as to what menu items
 742+	the window menu contains, or even if a window menu will be drawn
 743+	at all.
 744+
 745+	This request must be used in response to some sort of user action
 746+	like a button press, key press, or touch down event.
 747+      </description>
 748+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
 749+      <arg name="serial" type="uint" summary="the serial of the user event"/>
 750+      <arg name="x" type="int" summary="the x position to pop up the window menu at"/>
 751+      <arg name="y" type="int" summary="the y position to pop up the window menu at"/>
 752+    </request>
 753+
 754+    <request name="move">
 755+      <description summary="start an interactive move">
 756+	Start an interactive, user-driven move of the surface.
 757+
 758+	This request must be used in response to some sort of user action
 759+	like a button press, key press, or touch down event. The passed
 760+	serial is used to determine the type of interactive move (touch,
 761+	pointer, etc).
 762+
 763+	The server may ignore move requests depending on the state of
 764+	the surface (e.g. fullscreen or maximized), or if the passed serial
 765+	is no longer valid.
 766+
 767+	If triggered, the surface will lose the focus of the device
 768+	(wl_pointer, wl_touch, etc) used for the move. It is up to the
 769+	compositor to visually indicate that the move is taking place, such as
 770+	updating a pointer cursor, during the move. There is no guarantee
 771+	that the device focus will return when the move is completed.
 772+      </description>
 773+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
 774+      <arg name="serial" type="uint" summary="the serial of the user event"/>
 775+    </request>
 776+
 777+    <enum name="resize_edge">
 778+      <description summary="edge values for resizing">
 779+	These values are used to indicate which edge of a surface
 780+	is being dragged in a resize operation.
 781+      </description>
 782+      <entry name="none" value="0"/>
 783+      <entry name="top" value="1"/>
 784+      <entry name="bottom" value="2"/>
 785+      <entry name="left" value="4"/>
 786+      <entry name="top_left" value="5"/>
 787+      <entry name="bottom_left" value="6"/>
 788+      <entry name="right" value="8"/>
 789+      <entry name="top_right" value="9"/>
 790+      <entry name="bottom_right" value="10"/>
 791+    </enum>
 792+
 793+    <request name="resize">
 794+      <description summary="start an interactive resize">
 795+	Start a user-driven, interactive resize of the surface.
 796+
 797+	This request must be used in response to some sort of user action
 798+	like a button press, key press, or touch down event. The passed
 799+	serial is used to determine the type of interactive resize (touch,
 800+	pointer, etc).
 801+
 802+	The server may ignore resize requests depending on the state of
 803+	the surface (e.g. fullscreen or maximized).
 804+
 805+	If triggered, the client will receive configure events with the
 806+	"resize" state enum value and the expected sizes. See the "resize"
 807+	enum value for more details about what is required. The client
 808+	must also acknowledge configure events using "ack_configure". After
 809+	the resize is completed, the client will receive another "configure"
 810+	event without the resize state.
 811+
 812+	If triggered, the surface also will lose the focus of the device
 813+	(wl_pointer, wl_touch, etc) used for the resize. It is up to the
 814+	compositor to visually indicate that the resize is taking place,
 815+	such as updating a pointer cursor, during the resize. There is no
 816+	guarantee that the device focus will return when the resize is
 817+	completed.
 818+
 819+	The edges parameter specifies how the surface should be resized, and
 820+	is one of the values of the resize_edge enum. Values not matching
 821+	a variant of the enum will cause the invalid_resize_edge protocol error.
 822+	The compositor may use this information to update the surface position
 823+	for example when dragging the top left corner. The compositor may also
 824+	use this information to adapt its behavior, e.g. choose an appropriate
 825+	cursor image.
 826+      </description>
 827+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
 828+      <arg name="serial" type="uint" summary="the serial of the user event"/>
 829+      <arg name="edges" type="uint" enum="resize_edge" summary="which edge or corner is being dragged"/>
 830+    </request>
 831+
 832+    <enum name="state">
 833+      <description summary="types of state on the surface">
 834+	The different state values used on the surface. This is designed for
 835+	state values like maximized, fullscreen. It is paired with the
 836+	configure event to ensure that both the client and the compositor
 837+	setting the state can be synchronized.
 838+
 839+	States set in this way are double-buffered, see wl_surface.commit.
 840+      </description>
 841+      <entry name="maximized" value="1" summary="the surface is maximized">
 842+	<description summary="the surface is maximized">
 843+	  The surface is maximized. The window geometry specified in the configure
 844+	  event must be obeyed by the client, or the xdg_wm_base.invalid_surface_state
 845+	  error is raised.
 846+
 847+	  The client should draw without shadow or other
 848+	  decoration outside of the window geometry.
 849+	</description>
 850+      </entry>
 851+      <entry name="fullscreen" value="2" summary="the surface is fullscreen">
 852+	<description summary="the surface is fullscreen">
 853+	  The surface is fullscreen. The window geometry specified in the
 854+	  configure event is a maximum; the client cannot resize beyond it. For
 855+	  a surface to cover the whole fullscreened area, the geometry
 856+	  dimensions must be obeyed by the client. For more details, see
 857+	  xdg_toplevel.set_fullscreen.
 858+	</description>
 859+      </entry>
 860+      <entry name="resizing" value="3" summary="the surface is being resized">
 861+	<description summary="the surface is being resized">
 862+	  The surface is being resized. The window geometry specified in the
 863+	  configure event is a maximum; the client cannot resize beyond it.
 864+	  Clients that have aspect ratio or cell sizing configuration can use
 865+	  a smaller size, however.
 866+	</description>
 867+      </entry>
 868+      <entry name="activated" value="4" summary="the surface is now activated">
 869+	<description summary="the surface is now activated">
 870+	  Client window decorations should be painted as if the window is
 871+	  active. Do not assume this means that the window actually has
 872+	  keyboard or pointer focus.
 873+	</description>
 874+      </entry>
 875+      <entry name="tiled_left" value="5" since="2">
 876+	<description summary="the surface’s left edge is tiled">
 877+	  The window is currently in a tiled layout and the left edge is
 878+	  considered to be adjacent to another part of the tiling grid.
 879+
 880+	  The client should draw without shadow or other decoration outside of
 881+	  the window geometry on the left edge.
 882+	</description>
 883+      </entry>
 884+      <entry name="tiled_right" value="6" since="2">
 885+	<description summary="the surface’s right edge is tiled">
 886+	  The window is currently in a tiled layout and the right edge is
 887+	  considered to be adjacent to another part of the tiling grid.
 888+
 889+	  The client should draw without shadow or other decoration outside of
 890+	  the window geometry on the right edge.
 891+	</description>
 892+      </entry>
 893+      <entry name="tiled_top" value="7" since="2">
 894+	<description summary="the surface’s top edge is tiled">
 895+	  The window is currently in a tiled layout and the top edge is
 896+	  considered to be adjacent to another part of the tiling grid.
 897+
 898+	  The client should draw without shadow or other decoration outside of
 899+	  the window geometry on the top edge.
 900+	</description>
 901+      </entry>
 902+      <entry name="tiled_bottom" value="8" since="2">
 903+	<description summary="the surface’s bottom edge is tiled">
 904+	  The window is currently in a tiled layout and the bottom edge is
 905+	  considered to be adjacent to another part of the tiling grid.
 906+
 907+	  The client should draw without shadow or other decoration outside of
 908+	  the window geometry on the bottom edge.
 909+	</description>
 910+      </entry>
 911+      <entry name="suspended" value="9" since="6">
 912+        <description summary="surface repaint is suspended">
 913+	  The surface is currently not ordinarily being repainted; for
 914+	  example because its content is occluded by another window, or its
 915+	  outputs are switched off due to screen locking.
 916+	</description>
 917+      </entry>
 918+      <entry name="constrained_left" value="10" since="7">
 919+	<description summary="the surface’s left edge is constrained">
 920+          The left edge of the window is currently constrained, meaning it
 921+          shouldn't attempt to resize from that edge. It can for example mean
 922+          it's tiled next to a monitor edge on the constrained side of the
 923+          window.
 924+	</description>
 925+      </entry>
 926+      <entry name="constrained_right" value="11" since="7">
 927+	<description summary="the surface’s right edge is constrained">
 928+          The right edge of the window is currently constrained, meaning it
 929+          shouldn't attempt to resize from that edge. It can for example mean
 930+          it's tiled next to a monitor edge on the constrained side of the
 931+          window.
 932+	</description>
 933+      </entry>
 934+      <entry name="constrained_top" value="12" since="7">
 935+	<description summary="the surface’s top edge is constrained">
 936+          The top edge of the window is currently constrained, meaning it
 937+          shouldn't attempt to resize from that edge. It can for example mean
 938+          it's tiled next to a monitor edge on the constrained side of the
 939+          window.
 940+	</description>
 941+      </entry>
 942+      <entry name="constrained_bottom" value="13" since="7">
 943+	<description summary="the surface’s bottom edge is constrained">
 944+          The bottom edge of the window is currently constrained, meaning it
 945+          shouldn't attempt to resize from that edge. It can for example mean
 946+          it's tiled next to a monitor edge on the constrained side of the
 947+          window.
 948+	</description>
 949+      </entry>
 950+    </enum>
 951+
 952+    <request name="set_max_size">
 953+      <description summary="set the maximum size">
 954+	Set a maximum size for the window.
 955+
 956+	The client can specify a maximum size so that the compositor does
 957+	not try to configure the window beyond this size.
 958+
 959+	The width and height arguments are in window geometry coordinates.
 960+	See xdg_surface.set_window_geometry.
 961+
 962+	Values set in this way are double-buffered, see wl_surface.commit.
 963+
 964+	The compositor can use this information to allow or disallow
 965+	different states like maximize or fullscreen and draw accurate
 966+	animations.
 967+
 968+	Similarly, a tiling window manager may use this information to
 969+	place and resize client windows in a more effective way.
 970+
 971+	The client should not rely on the compositor to obey the maximum
 972+	size. The compositor may decide to ignore the values set by the
 973+	client and request a larger size.
 974+
 975+	If never set, or a value of zero in the request, means that the
 976+	client has no expected maximum size in the given dimension.
 977+	As a result, a client wishing to reset the maximum size
 978+	to an unspecified state can use zero for width and height in the
 979+	request.
 980+
 981+	Requesting a maximum size to be smaller than the minimum size of
 982+	a surface is illegal and will result in an invalid_size error.
 983+
 984+	The width and height must be greater than or equal to zero. Using
 985+	strictly negative values for width or height will result in a
 986+	invalid_size error.
 987+      </description>
 988+      <arg name="width" type="int"/>
 989+      <arg name="height" type="int"/>
 990+    </request>
 991+
 992+    <request name="set_min_size">
 993+      <description summary="set the minimum size">
 994+	Set a minimum size for the window.
 995+
 996+	The client can specify a minimum size so that the compositor does
 997+	not try to configure the window below this size.
 998+
 999+	The width and height arguments are in window geometry coordinates.
1000+	See xdg_surface.set_window_geometry.
1001+
1002+	Values set in this way are double-buffered, see wl_surface.commit.
1003+
1004+	The compositor can use this information to allow or disallow
1005+	different states like maximize or fullscreen and draw accurate
1006+	animations.
1007+
1008+	Similarly, a tiling window manager may use this information to
1009+	place and resize client windows in a more effective way.
1010+
1011+	The client should not rely on the compositor to obey the minimum
1012+	size. The compositor may decide to ignore the values set by the
1013+	client and request a smaller size.
1014+
1015+	If never set, or a value of zero in the request, means that the
1016+	client has no expected minimum size in the given dimension.
1017+	As a result, a client wishing to reset the minimum size
1018+	to an unspecified state can use zero for width and height in the
1019+	request.
1020+
1021+	Requesting a minimum size to be larger than the maximum size of
1022+	a surface is illegal and will result in an invalid_size error.
1023+
1024+	The width and height must be greater than or equal to zero. Using
1025+	strictly negative values for width and height will result in a
1026+	invalid_size error.
1027+      </description>
1028+      <arg name="width" type="int"/>
1029+      <arg name="height" type="int"/>
1030+    </request>
1031+
1032+    <request name="set_maximized">
1033+      <description summary="maximize the window">
1034+	Maximize the surface.
1035+
1036+	After requesting that the surface should be maximized, the compositor
1037+	will respond by emitting a configure event. Whether this configure
1038+	actually sets the window maximized is subject to compositor policies.
1039+	The client must then update its content, drawing in the configured
1040+	state. The client must also acknowledge the configure when committing
1041+	the new content (see ack_configure).
1042+
1043+	It is up to the compositor to decide how and where to maximize the
1044+	surface, for example which output and what region of the screen should
1045+	be used.
1046+
1047+	If the surface was already maximized, the compositor will still emit
1048+	a configure event with the "maximized" state.
1049+
1050+	If the surface is in a fullscreen state, this request has no direct
1051+	effect. It may alter the state the surface is returned to when
1052+	unmaximized unless overridden by the compositor.
1053+      </description>
1054+    </request>
1055+
1056+    <request name="unset_maximized">
1057+      <description summary="unmaximize the window">
1058+	Unmaximize the surface.
1059+
1060+	After requesting that the surface should be unmaximized, the compositor
1061+	will respond by emitting a configure event. Whether this actually
1062+	un-maximizes the window is subject to compositor policies.
1063+	If available and applicable, the compositor will include the window
1064+	geometry dimensions the window had prior to being maximized in the
1065+	configure event. The client must then update its content, drawing it in
1066+	the configured state. The client must also acknowledge the configure
1067+	when committing the new content (see ack_configure).
1068+
1069+	It is up to the compositor to position the surface after it was
1070+	unmaximized; usually the position the surface had before maximizing, if
1071+	applicable.
1072+
1073+	If the surface was already not maximized, the compositor will still
1074+	emit a configure event without the "maximized" state.
1075+
1076+	If the surface is in a fullscreen state, this request has no direct
1077+	effect. It may alter the state the surface is returned to when
1078+	unmaximized unless overridden by the compositor.
1079+      </description>
1080+    </request>
1081+
1082+    <request name="set_fullscreen">
1083+      <description summary="set the window as fullscreen on an output">
1084+	Make the surface fullscreen.
1085+
1086+	After requesting that the surface should be fullscreened, the
1087+	compositor will respond by emitting a configure event. Whether the
1088+	client is actually put into a fullscreen state is subject to compositor
1089+	policies. The client must also acknowledge the configure when
1090+	committing the new content (see ack_configure).
1091+
1092+	The output passed by the request indicates the client's preference as
1093+	to which display it should be set fullscreen on. If this value is NULL,
1094+	it's up to the compositor to choose which display will be used to map
1095+	this surface.
1096+
1097+	If the surface doesn't cover the whole output, the compositor will
1098+	position the surface in the center of the output and compensate with
1099+	with border fill covering the rest of the output. The content of the
1100+	border fill is undefined, but should be assumed to be in some way that
1101+	attempts to blend into the surrounding area (e.g. solid black).
1102+
1103+	If the fullscreened surface is not opaque, the compositor must make
1104+	sure that other screen content not part of the same surface tree (made
1105+	up of subsurfaces, popups or similarly coupled surfaces) are not
1106+	visible below the fullscreened surface.
1107+      </description>
1108+      <arg name="output" type="object" interface="wl_output" allow-null="true"/>
1109+    </request>
1110+
1111+    <request name="unset_fullscreen">
1112+      <description summary="unset the window as fullscreen">
1113+	Make the surface no longer fullscreen.
1114+
1115+	After requesting that the surface should be unfullscreened, the
1116+	compositor will respond by emitting a configure event.
1117+	Whether this actually removes the fullscreen state of the client is
1118+	subject to compositor policies.
1119+
1120+	Making a surface unfullscreen sets states for the surface based on the following:
1121+	* the state(s) it may have had before becoming fullscreen
1122+	* any state(s) decided by the compositor
1123+	* any state(s) requested by the client while the surface was fullscreen
1124+
1125+	The compositor may include the previous window geometry dimensions in
1126+	the configure event, if applicable.
1127+
1128+	The client must also acknowledge the configure when committing the new
1129+	content (see ack_configure).
1130+      </description>
1131+    </request>
1132+
1133+    <request name="set_minimized">
1134+      <description summary="set the window as minimized">
1135+	Request that the compositor minimize your surface. There is no
1136+	way to know if the surface is currently minimized, nor is there
1137+	any way to unset minimization on this surface.
1138+
1139+	If you are looking to throttle redrawing when minimized, please
1140+	instead use the wl_surface.frame event for this, as this will
1141+	also work with live previews on windows in Alt-Tab, Expose or
1142+	similar compositor features.
1143+      </description>
1144+    </request>
1145+
1146+    <event name="configure">
1147+      <description summary="suggest a surface change">
1148+	This configure event asks the client to resize its toplevel surface or
1149+	to change its state. The configured state should not be applied
1150+	immediately. See xdg_surface.configure for details.
1151+
1152+	The width and height arguments specify a hint to the window
1153+	about how its surface should be resized in window geometry
1154+	coordinates. See set_window_geometry.
1155+
1156+	If the width or height arguments are zero, it means the client
1157+	should decide its own window dimension. This may happen when the
1158+	compositor needs to configure the state of the surface but doesn't
1159+	have any information about any previous or expected dimension.
1160+
1161+	The states listed in the event specify how the width/height
1162+	arguments should be interpreted, and possibly how it should be
1163+	drawn.
1164+
1165+	Clients must send an ack_configure in response to this event. See
1166+	xdg_surface.configure and xdg_surface.ack_configure for details.
1167+      </description>
1168+      <arg name="width" type="int"/>
1169+      <arg name="height" type="int"/>
1170+      <arg name="states" type="array"/>
1171+    </event>
1172+
1173+    <event name="close">
1174+      <description summary="surface wants to be closed">
1175+	The close event is sent by the compositor when the user
1176+	wants the surface to be closed. This should be equivalent to
1177+	the user clicking the close button in client-side decorations,
1178+	if your application has any.
1179+
1180+	This is only a request that the user intends to close the
1181+	window. The client may choose to ignore this request, or show
1182+	a dialog to ask the user to save their data, etc.
1183+      </description>
1184+    </event>
1185+
1186+    <!-- Version 4 additions -->
1187+
1188+    <event name="configure_bounds" since="4">
1189+      <description summary="recommended window geometry bounds">
1190+	The configure_bounds event may be sent prior to a xdg_toplevel.configure
1191+	event to communicate the bounds a window geometry size is recommended
1192+	to constrain to.
1193+
1194+	The passed width and height are in surface coordinate space. If width
1195+	and height are 0, it means bounds is unknown and equivalent to as if no
1196+	configure_bounds event was ever sent for this surface.
1197+
1198+	The bounds can for example correspond to the size of a monitor excluding
1199+	any panels or other shell components, so that a surface isn't created in
1200+	a way that it cannot fit.
1201+
1202+	The bounds may change at any point, and in such a case, a new
1203+	xdg_toplevel.configure_bounds will be sent, followed by
1204+	xdg_toplevel.configure and xdg_surface.configure.
1205+      </description>
1206+      <arg name="width" type="int"/>
1207+      <arg name="height" type="int"/>
1208+    </event>
1209+
1210+    <!-- Version 5 additions -->
1211+
1212+    <enum name="wm_capabilities" since="5">
1213+      <entry name="window_menu" value="1" summary="show_window_menu is available"/>
1214+      <entry name="maximize" value="2" summary="set_maximized and unset_maximized are available"/>
1215+      <entry name="fullscreen" value="3" summary="set_fullscreen and unset_fullscreen are available"/>
1216+      <entry name="minimize" value="4" summary="set_minimized is available"/>
1217+    </enum>
1218+
1219+    <event name="wm_capabilities" since="5">
1220+      <description summary="compositor capabilities">
1221+	This event advertises the capabilities supported by the compositor. If
1222+	a capability isn't supported, clients should hide or disable the UI
1223+	elements that expose this functionality. For instance, if the
1224+	compositor doesn't advertise support for minimized toplevels, a button
1225+	triggering the set_minimized request should not be displayed.
1226+
1227+	The compositor will ignore requests it doesn't support. For instance,
1228+	a compositor which doesn't advertise support for minimized will ignore
1229+	set_minimized requests.
1230+
1231+	Compositors must send this event once before the first
1232+	xdg_surface.configure event. When the capabilities change, compositors
1233+	must send this event again and then send an xdg_surface.configure
1234+	event.
1235+
1236+	The configured state should not be applied immediately. See
1237+	xdg_surface.configure for details.
1238+
1239+	The capabilities are sent as an array of 32-bit unsigned integers in
1240+	native endianness.
1241+      </description>
1242+      <arg name="capabilities" type="array" summary="array of 32-bit capabilities"/>
1243+    </event>
1244+  </interface>
1245+
1246+  <interface name="xdg_popup" version="7">
1247+    <description summary="short-lived, popup surfaces for menus">
1248+      A popup surface is a short-lived, temporary surface. It can be used to
1249+      implement for example menus, popovers, tooltips and other similar user
1250+      interface concepts.
1251+
1252+      A popup can be made to take an explicit grab. See xdg_popup.grab for
1253+      details.
1254+
1255+      When the popup is dismissed, a popup_done event will be sent out, and at
1256+      the same time the surface will be unmapped. See the xdg_popup.popup_done
1257+      event for details.
1258+
1259+      Explicitly destroying the xdg_popup object will also dismiss the popup and
1260+      unmap the surface. Clients that want to dismiss the popup when another
1261+      surface of their own is clicked should dismiss the popup using the destroy
1262+      request.
1263+
1264+      A newly created xdg_popup will be stacked on top of all previously created
1265+      xdg_popup surfaces associated with the same xdg_toplevel.
1266+
1267+      The parent of an xdg_popup must be mapped (see the xdg_surface
1268+      description) before the xdg_popup itself.
1269+
1270+      The client must call wl_surface.commit on the corresponding wl_surface
1271+      for the xdg_popup state to take effect.
1272+    </description>
1273+
1274+    <enum name="error">
1275+      <entry name="invalid_grab" value="0"
1276+	     summary="tried to grab after being mapped"/>
1277+    </enum>
1278+
1279+    <request name="destroy" type="destructor">
1280+      <description summary="remove xdg_popup interface">
1281+	This destroys the popup. Explicitly destroying the xdg_popup
1282+	object will also dismiss the popup, and unmap the surface.
1283+
1284+	If this xdg_popup is not the "topmost" popup, the
1285+	xdg_wm_base.not_the_topmost_popup protocol error will be sent.
1286+      </description>
1287+    </request>
1288+
1289+    <request name="grab">
1290+      <description summary="make the popup take an explicit grab">
1291+	This request makes the created popup take an explicit grab. An explicit
1292+	grab will be dismissed when the user dismisses the popup, or when the
1293+	client destroys the xdg_popup. This can be done by the user clicking
1294+	outside the surface, using the keyboard, or even locking the screen
1295+	through closing the lid or a timeout.
1296+
1297+	If the compositor denies the grab, the popup will be immediately
1298+	dismissed.
1299+
1300+	This request must be used in response to some sort of user action like a
1301+	button press, key press, or touch down event. The serial number of the
1302+	event should be passed as 'serial'.
1303+
1304+	The parent of a grabbing popup must either be an xdg_toplevel surface or
1305+	another xdg_popup with an explicit grab. If the parent is another
1306+	xdg_popup it means that the popups are nested, with this popup now being
1307+	the topmost popup.
1308+
1309+	Nested popups must be destroyed in the reverse order they were created
1310+	in, e.g. the only popup you are allowed to destroy at all times is the
1311+	topmost one.
1312+
1313+	When compositors choose to dismiss a popup, they may dismiss every
1314+	nested grabbing popup as well. When a compositor dismisses popups, it
1315+	will follow the same dismissing order as required from the client.
1316+
1317+	If the topmost grabbing popup is destroyed, the grab will be returned to
1318+	the parent of the popup, if that parent previously had an explicit grab.
1319+
1320+	If the parent is a grabbing popup which has already been dismissed, this
1321+	popup will be immediately dismissed. If the parent is a popup that did
1322+	not take an explicit grab, an error will be raised.
1323+
1324+	During a popup grab, the client owning the grab will receive pointer
1325+	and touch events for all their surfaces as normal (similar to an
1326+	"owner-events" grab in X11 parlance), while the top most grabbing popup
1327+	will always have keyboard focus.
1328+      </description>
1329+      <arg name="seat" type="object" interface="wl_seat"
1330+	   summary="the wl_seat of the user event"/>
1331+      <arg name="serial" type="uint" summary="the serial of the user event"/>
1332+    </request>
1333+
1334+    <event name="configure">
1335+      <description summary="configure the popup surface">
1336+	This event asks the popup surface to configure itself given the
1337+	configuration. The configured state should not be applied immediately.
1338+	See xdg_surface.configure for details.
1339+
1340+	The x and y arguments represent the position the popup was placed at
1341+	given the xdg_positioner rule, relative to the upper left corner of the
1342+	window geometry of the parent surface.
1343+
1344+	For version 2 or older, the configure event for an xdg_popup is only
1345+	ever sent once for the initial configuration. Starting with version 3,
1346+	it may be sent again if the popup is setup with an xdg_positioner with
1347+	set_reactive requested, or in response to xdg_popup.reposition requests.
1348+      </description>
1349+      <arg name="x" type="int"
1350+	   summary="x position relative to parent surface window geometry"/>
1351+      <arg name="y" type="int"
1352+	   summary="y position relative to parent surface window geometry"/>
1353+      <arg name="width" type="int" summary="window geometry width"/>
1354+      <arg name="height" type="int" summary="window geometry height"/>
1355+    </event>
1356+
1357+    <event name="popup_done">
1358+      <description summary="popup interaction is done">
1359+	The popup_done event is sent out when a popup is dismissed by the
1360+	compositor. The client should destroy the xdg_popup object at this
1361+	point.
1362+      </description>
1363+    </event>
1364+
1365+    <!-- Version 3 additions -->
1366+
1367+    <request name="reposition" since="3">
1368+      <description summary="recalculate the popup's location">
1369+	Reposition an already-mapped popup. The popup will be placed given the
1370+	details in the passed xdg_positioner object, and a
1371+	xdg_popup.repositioned followed by xdg_popup.configure and
1372+	xdg_surface.configure will be emitted in response. Any parameters set
1373+	by the previous positioner will be discarded.
1374+
1375+	The passed token will be sent in the corresponding
1376+	xdg_popup.repositioned event. The new popup position will not take
1377+	effect until the corresponding configure event is acknowledged by the
1378+	client. See xdg_popup.repositioned for details. The token itself is
1379+	opaque, and has no other special meaning.
1380+
1381+	If multiple reposition requests are sent, the compositor may skip all
1382+	but the last one.
1383+
1384+	If the popup is repositioned in response to a configure event for its
1385+	parent, the client should send an xdg_positioner.set_parent_configure
1386+	and possibly an xdg_positioner.set_parent_size request to allow the
1387+	compositor to properly constrain the popup.
1388+
1389+	If the popup is repositioned together with a parent that is being
1390+	resized, but not in response to a configure event, the client should
1391+	send an xdg_positioner.set_parent_size request.
1392+      </description>
1393+      <arg name="positioner" type="object" interface="xdg_positioner"/>
1394+      <arg name="token" type="uint" summary="reposition request token"/>
1395+    </request>
1396+
1397+    <event name="repositioned" since="3">
1398+      <description summary="signal the completion of a repositioned request">
1399+	The repositioned event is sent as part of a popup configuration
1400+	sequence, together with xdg_popup.configure and lastly
1401+	xdg_surface.configure to notify the completion of a reposition request.
1402+
1403+	The repositioned event is to notify about the completion of a
1404+	xdg_popup.reposition request. The token argument is the token passed
1405+	in the xdg_popup.reposition request.
1406+
1407+	Immediately after this event is emitted, xdg_popup.configure and
1408+	xdg_surface.configure will be sent with the updated size and position,
1409+	as well as a new configure serial.
1410+
1411+	The client should optionally update the content of the popup, but must
1412+	acknowledge the new popup configuration for the new position to take
1413+	effect. See xdg_surface.ack_configure for details.
1414+      </description>
1415+      <arg name="token" type="uint" summary="reposition request token"/>
1416+    </event>
1417+
1418+  </interface>
1419+</protocol>
+568, -0
  1@@ -0,0 +1,568 @@
  2+#include <stdio.h>
  3+#include <stdlib.h>
  4+#include <unistd.h>
  5+#include <string.h>
  6+#include <stdint.h>
  7+#include <stdbool.h>
  8+#include <getopt.h>
  9+#include <signal.h>
 10+#include <errno.h>
 11+#include <fcntl.h>
 12+#include <poll.h>
 13+#include <time.h>
 14+#include <sys/wait.h>
 15+
 16+#include <wayland-client.h>
 17+#include <wld/wld.h>
 18+#include <wld/wayland.h>
 19+
 20+#include <scfg.h>
 21+
 22+#include "xdg-shell-protocol.h"
 23+#include "wlr-layer-shell-unstable-v1.h"
 24+
 25+#define MAXMOD 3
 26+
 27+#define LOG(...) fprintf(stderr, "panko: " __VA_ARGS__)
 28+#define ERRNUM(elem) \
 29+	LOG("at line %d: wrong number of values for option `%s`\n", elem.lineno, elem.name); return false
 30+#define ERRINC(elem) \
 31+	LOG("at line %d: incorrect value for option `%s`\n", elem.lineno, elem.name); return false
 32+
 33+enum { SIDE_LEFT, SIDE_MIDDLE, SIDE_RIGHT };
 34+struct module {
 35+	char *name, *command;
 36+	uint32_t interval;
 37+	uint32_t margins[4], padding[4];
 38+	uint32_t width, height;
 39+	struct {
 40+		uint32_t foreground, background;
 41+		char *font;
 42+		int border_width;
 43+		uint32_t border_color;
 44+	} style;
 45+};
 46+
 47+struct config {
 48+	uint32_t width, height;
 49+	enum zwlr_layer_surface_v1_anchor anchor;
 50+	uint32_t margins[4], padding[4];
 51+	bool exclusive;
 52+	struct {
 53+		uint32_t foreground, background;
 54+		char *font;
 55+	} style;
 56+};
 57+
 58+struct panel {
 59+	struct module *parsed, modules[3][MAXMOD];
 60+	size_t plen, mlen;
 61+};
 62+
 63+struct app {
 64+	struct wl_display *dpy;
 65+	struct wl_registry *reg;
 66+	struct wl_compositor *comp;
 67+	struct zwlr_layer_shell_v1 *layer_shell;
 68+
 69+	/* panel resources */
 70+	struct wl_surface *surface;
 71+	struct zwlr_layer_surface_v1 *layer_surface;
 72+
 73+	/* drawing resources */
 74+	struct wld_context *wld_ctx;
 75+	struct wld_renderer *wld_ren;
 76+	struct wld_font_context *wld_fctx;
 77+	struct wld_font *wld_font;
 78+	struct wld_surface *wld_surface;
 79+
 80+	struct config config;
 81+};
 82+
 83+static volatile sig_atomic_t running = 1;
 84+static char config_path[512];
 85+static bool have_config = true;
 86+
 87+static void
 88+handle_global(void *data, struct wl_registry *reg, uint32_t name,
 89+	const char *iface, uint32_t ver) {
 90+
 91+	struct app *app = data;
 92+
 93+	if (strcmp(iface, "wl_compositor") == 0) {
 94+		app->comp =
 95+			wl_registry_bind(reg, name, &wl_compositor_interface, ver < 4 ? ver : 4);
 96+		return;
 97+	}
 98+
 99+	if (strcmp(iface, "zwlr_layer_shell_v1") == 0) {
100+		app->layer_shell =
101+			wl_registry_bind(reg, name, &zwlr_layer_shell_v1_interface, 5);
102+		return;
103+	}
104+}
105+
106+static void
107+handle_global_remove(void *data, struct wl_registry *reg, uint32_t name) {
108+	/* no-op */
109+}
110+
111+static const struct wl_registry_listener reg_listener = {
112+	.global = handle_global,
113+	.global_remove = handle_global_remove
114+};
115+
116+static void
117+handle_panel_configure(void *data, struct zwlr_layer_surface_v1 *layer_surface,
118+	uint32_t serial, uint32_t width, uint32_t height) {
119+
120+	/* ignored */
121+}
122+
123+static void
124+handle_panel_close(void *data, struct zwlr_layer_surface_v1 *layer_surface) {
125+	zwlr_layer_surface_v1_destroy(layer_surface);
126+}
127+
128+static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
129+	.configure = handle_panel_configure,
130+	.closed = handle_panel_close
131+};
132+
133+static void
134+module_add(struct module *m, int side) {
135+}
136+
137+static bool
138+parse_config(const char *path, struct app *app) {
139+	struct scfg_block block;
140+
141+	int ret = scfg_load_file(&block, path);
142+	if (ret < 0) {
143+		LOG("couldn't load config file: %s\n", strerror(-ret));
144+		return false;
145+	}
146+
147+	for (size_t i = 0; i < block.directives_len; i++) {
148+		struct scfg_directive d = block.directives[i];
149+
150+		if (strcmp(d.name, "width") == 0 || strcmp(d.name, "height") == 0) {
151+			if (d.params_len != 1) {
152+				ERRNUM(d);
153+			}
154+			uint32_t *k = d.name[0] == 'w' ? &app->config.width : &app->config.height;
155+			*k = strtoul(d.params[0], NULL, 0);
156+		}
157+
158+		else if (strcmp(d.name, "anchor") == 0) {
159+			if (d.params_len > 4 || d.params_len <= 0) {
160+				ERRNUM(d);
161+			}
162+			for (size_t j = 0; j < d.params_len; j++) {
163+				if (strcmp(d.params[j], "top") == 0)
164+					app->config.anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;
165+				else if (strcmp(d.params[j], "right") == 0)
166+					app->config.anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
167+				else if (strcmp(d.params[j], "bottom") == 0)
168+					app->config.anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
169+				else if (strcmp(d.params[j], "left") == 0)
170+					app->config.anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT;
171+				else {
172+					ERRINC(d);
173+				}
174+			}
175+		}
176+
177+		else if (strcmp(d.name, "margins") == 0 || strcmp(d.name, "padding") == 0) {
178+			if (d.params_len != 4) {
179+				ERRNUM(d);
180+			}
181+			uint32_t *k = d.name[0] == 'm' ? app->config.margins : app->config.padding;
182+			for (int j = 0; j < 4; j++)
183+				k[j] = strtoul(d.params[j], NULL, 0);
184+		}
185+
186+		else if (strcmp(d.name, "exclusive") == 0) {
187+			if (d.params_len != 1) {
188+				ERRNUM(d);
189+			}
190+			if (strcmp(d.params[0], "true") == 0)
191+				app->config.exclusive = true;
192+			else if (strcmp(d.params[0], "false") == 0)
193+				app->config.exclusive = false;
194+			else {
195+				ERRINC(d);
196+			}
197+		}
198+
199+		else if (strcmp(d.name, "style") == 0) {
200+			struct scfg_block sub = d.children;
201+			for (size_t j = 0; j < sub.directives_len; j++) {
202+				struct scfg_directive s = sub.directives[j];
203+
204+				if (strcmp(s.name, "foreground") == 0) {
205+					if (s.params_len != 1) {
206+						ERRNUM(s);
207+					}
208+					wld_lookup_named_color(s.params[0], &app->config.style.foreground);
209+				}
210+
211+				else if (strcmp(s.name, "background") == 0) {
212+					if (s.params_len != 1) {
213+						ERRNUM(s);
214+					}
215+					wld_lookup_named_color(s.params[0], &app->config.style.background);
216+				}
217+
218+				else if (strcmp(s.name, "font") == 0) {
219+					if (s.params_len != 1) {
220+						ERRNUM(s);
221+					}
222+					*app->config.style.font = '\0';
223+					strncat(app->config.style.font, s.params[0], sizeof(app->config.style.font) - 1);
224+				}
225+			}
226+		}
227+
228+		else if (strcmp(d.name, "module") == 0) {
229+			if (d.params_len != 1) {
230+				ERRNUM(d);
231+			}
232+			struct module m = {0};
233+			memset(&m, 0, sizeof(m));
234+			*m.name = '\0';
235+			strncat(m.name, d.params[0], sizeof(m.name) - 1);
236+
237+			struct scfg_block sub = d.children;
238+			for (size_t j = 0; j < sub.directives_len; j++) {
239+				struct scfg_directive s = sub.directives[j];
240+
241+				if (strcmp(s.name, "command") == 0) {
242+					if (s.params_len != 1) {
243+						ERRNUM(s);
244+					}
245+					*m.command = '\0';
246+					strncat(m.command, s.params[0], sizeof(m.command) - 1);
247+				}
248+
249+				else if (strcmp(s.name, "interval") == 0) {
250+					if (s.params_len != 1) {
251+						ERRNUM(s);
252+					}
253+					m.interval = strtoul(s.params[0], NULL, 0);
254+				}
255+
256+				else if (strcmp(s.name, "margins") == 0 || strcmp(s.name, "padding") == 0) {
257+					if (s.params_len != 4) {
258+						ERRNUM(s);
259+					}
260+					uint32_t *k = s.name[0] == 'm' ? m.margins : m.padding;
261+					for (int y = 0; y < 4; y++)
262+						k[y] = strtoul(s.params[y], NULL, 0);
263+				}
264+
265+				else if (strcmp(s.name, "width") == 0 || strcmp(s.name, "height") == 0) {
266+					if (s.params_len != 1) {
267+						ERRNUM(s);
268+					}
269+					uint32_t *k = s.name[0] == 'w' ? &m.width : &m.height;
270+					*k = strtoul(s.params[0], NULL, 0);
271+				}
272+
273+				else if (strcmp(s.name, "style") == 0) {
274+					struct scfg_block ssub = s.children;
275+					for (size_t n = 0; n < ssub.directives_len; n++) {
276+						struct scfg_directive t = ssub.directives[n];
277+
278+						if (strcmp(t.name, "background") == 0) {
279+							if (t.params_len != 1) {
280+								ERRNUM(t);
281+							}
282+							wld_lookup_named_color(t.params[0], &m.style.background);
283+						}
284+
285+						else if (strcmp(t.name, "foreground") == 0) {
286+							if (t.params_len != 1) {
287+								ERRNUM(t);
288+							}
289+							wld_lookup_named_color(t.params[0], &m.style.foreground);
290+						}
291+
292+						else if (strcmp(t.name, "font") == 0) {
293+							if (t.params_len != 1) {
294+								ERRNUM(t);
295+							}
296+							*m.style.font = '\0';
297+							strncat(m.style.font, t.params[0], sizeof(m.style.font) - 1);
298+						}
299+
300+						else if (strcmp(t.name, "border-width") == 0) {
301+							if (t.params_len != 1) {
302+								ERRNUM(t);
303+							}
304+							m.style.border_width = atoi(t.params[0]);
305+						}
306+
307+						else if (strcmp(t.name, "border-color") == 0) {
308+							if (t.params_len != 1) {
309+								ERRNUM(t);
310+							}
311+							wld_lookup_named_color(t.params[0], &m.style.border_color);
312+						}
313+					}
314+				}
315+			}
316+		}
317+
318+		else if (strcmp(d.name, "modules-left") == 0 || strcmp(d.name, "modules-middle") == 0 || strcmp(d.name, "modules-right") == 0) {
319+			if (d.params_len < 0) {
320+				ERRNUM(d);
321+			}
322+			if (d.params[0][0] == '\0')
323+				continue;
324+
325+#if 0
326+			TODO TODO TODO TODO TODO TODO
327+			for (size_t i = 0; i < app->panel.plen; i++)
328+				for (size_t j = 0; j < d.params_len; j++)
329+					if (strcmp(d.params[j], app->panel.parsed[i]) == 0) {
330+						int side = d.params[0][8] == 'l' ? SIDE_LEFT : d.params[0][8] == 'm' ? SIDE_MIDDLE : SIDE_RIGHT;
331+						module_add(&m, side);
332+					}
333+#endif
334+		}
335+	}
336+
337+	scfg_block_finish(&block);
338+	return true;
339+}
340+
341+static void
342+sig_handler(int s) {
343+	running = 0;
344+}
345+
346+static bool
347+setup(struct app *app) {
348+	memset(app, 0, sizeof(*app));
349+
350+	signal(SIGINT, sig_handler);
351+	signal(SIGTERM, sig_handler);
352+	signal(SIGQUIT, sig_handler);
353+
354+	app->dpy = wl_display_connect(NULL);
355+	if (!app->dpy) {
356+		LOG("couldn't connect to Wayland\n");
357+		return false;
358+	}
359+
360+	app->reg = wl_display_get_registry(app->dpy);
361+	if (!app->reg) {
362+		LOG("couldn't get registry\n");
363+		return false;
364+	}
365+
366+	wl_registry_add_listener(app->reg, &reg_listener, app);
367+	wl_display_roundtrip(app->dpy);
368+
369+	if (!app->comp || !app->layer_shell) {
370+		LOG("required globals wl_compositor or layer_shell not available\n");
371+		return false;
372+	}
373+
374+	app->surface = wl_compositor_create_surface(app->comp);
375+	if (!app->surface) {
376+		LOG("couldn't create surface\n");
377+		return false;
378+	}
379+	app->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
380+		app->layer_shell,
381+		app->surface,
382+		NULL,
383+		ZWLR_LAYER_SHELL_V1_LAYER_TOP,
384+		"panko"
385+	);
386+
387+	if (!app->layer_surface) {
388+		LOG("couldn't get layer surface\n");
389+		return false;
390+	}
391+
392+	zwlr_layer_surface_v1_add_listener(
393+		app->layer_surface,
394+		&layer_surface_listener,
395+		&app
396+	);
397+
398+	if (config_path[0] == '\0') {
399+		char *xdg_home = getenv("XDG_CONFIG_HOME");
400+		if (xdg_home != NULL) {
401+			snprintf(config_path, sizeof(config_path), "%s/panko.scfg", xdg_home);
402+		}
403+		else {
404+			char *home = getenv("HOME");
405+			if (home == NULL) {
406+				LOG("couldn't find config path\n");
407+				return false;
408+			}
409+			snprintf(config_path, sizeof(config_path), "%s/.config/panko/panko.scfg", home);
410+		}
411+	}
412+
413+	if (!parse_config(config_path, app))
414+		return false;
415+
416+	zwlr_layer_surface_v1_set_size(
417+		app->layer_surface,
418+		app->config.width, app->config.height
419+	);
420+	zwlr_layer_surface_v1_set_anchor(
421+		app->layer_surface,
422+		app->config.anchor
423+	);
424+	zwlr_layer_surface_v1_set_exclusive_zone(
425+		app->layer_surface,
426+		app->config.exclusive ? app->config.height : 0
427+	);
428+	zwlr_layer_surface_v1_set_margin(
429+		app->layer_surface,
430+		app->config.margins[0],
431+		app->config.margins[1],
432+		app->config.margins[2],
433+		app->config.margins[3]
434+	);
435+	wl_surface_commit(app->surface);
436+	wl_display_roundtrip(app->dpy);
437+
438+	app->wld_ctx = wld_wayland_create_context(app->dpy, WLD_ANY);
439+	if (!app->wld_ctx) {
440+		LOG("couldn't create WLD context\n");
441+		return false;
442+	}
443+
444+	app->wld_ren = wld_create_renderer(app->wld_ctx);
445+	if (!app->wld_ren) {
446+		LOG("couldn't create WLD renderer\n");
447+		return false;
448+	}
449+
450+	app->wld_fctx = wld_font_create_context();
451+	if (!app->wld_fctx) {
452+		LOG("couldn't create WLD font context\n");
453+		return false;
454+	}
455+
456+	app->wld_font = wld_font_open_name(app->wld_fctx, app->config.style.font);
457+	if (!app->wld_font) {
458+		LOG("couldn't open font: %s\n", app->config.style.font);
459+		return false;
460+	}
461+
462+	app->wld_surface =
463+		wld_wayland_create_surface(app->wld_ctx, app->config.width,
464+		app->config.height, WLD_FORMAT_XRGB8888, 0, app->surface);
465+	if (!app->wld_surface) {
466+		LOG("couldn't create WLD surface\n");
467+		return false;
468+	}
469+
470+	wld_set_target_surface(app->wld_ren, app->wld_surface);
471+	wld_fill_rectangle(app->wld_ren, app->config.style.background, 0, 0,
472+		app->config.width, app->config.height);
473+
474+	struct wld_extents ext;
475+	wld_font_text_extents(app->wld_font, "wowie zowie", &ext);
476+	int y = app->config.height / 2 + app->wld_font->height / 2 - app->wld_font->descent
477+		+ app->config.padding[0] - app->config.padding[2];
478+
479+	wld_draw_text(app->wld_ren, app->wld_font, app->config.style.foreground,
480+		app->config.padding[3], y, "wowie zowie", strlen("wowie zowie"), NULL);
481+
482+	wl_surface_damage(app->surface, 0, 0, app->config.width, app->config.height);
483+	wld_flush(app->wld_ren);
484+	wld_swap(app->wld_surface);
485+
486+	return true;
487+}
488+
489+static void
490+cleanup(struct app *app) {
491+	if (app->wld_surface)
492+		wld_destroy_surface(app->wld_surface);
493+	if (app->wld_font)
494+		wld_font_close(app->wld_font);
495+	if (app->wld_fctx)
496+		wld_font_destroy_context(app->wld_fctx);
497+	if (app->wld_ren)
498+		wld_destroy_renderer(app->wld_ren);
499+	if (app->wld_ctx)
500+		wld_destroy_context(app->wld_ctx);
501+	if (app->layer_surface)
502+		zwlr_layer_surface_v1_destroy(app->layer_surface);
503+	if (app->surface)
504+		wl_surface_destroy(app->surface);
505+	if (app->layer_shell)
506+		zwlr_layer_shell_v1_destroy(app->layer_shell);
507+	if (app->comp)
508+		wl_compositor_destroy(app->comp);
509+	if (app->reg)
510+		wl_registry_destroy(app->reg);
511+	if (app->dpy)
512+		wl_display_disconnect(app->dpy);
513+
514+	memset(app, 0, sizeof(*app));
515+}
516+
517+int
518+main(int argc, char **argv) {
519+	struct app app = {0};
520+	struct pollfd pfd;
521+	config_path[0] = '\0';
522+
523+	int opt;
524+	while ((opt = getopt(argc, argv, ":hvc:")) != -1) {
525+		switch (opt) {
526+			case 'h':
527+				fprintf(stderr, "Usage: %s [-hv] [-c path]\n\n"
528+						"Options:\n"
529+						"  -h\t\tPrint this help message\n"
530+						"  -v\t\tPrint the current version\n"
531+						"  -c path\tLoad the config from this path (default ~/.config/panko/panko.scfg)\n",
532+						argv[0]
533+				);
534+				return 1;
535+				break;
536+			case 'v':
537+				fprintf(stderr, "panko v" VERSION "\n");
538+				return 0;
539+				break;
540+			case 'c':
541+				snprintf(config_path, sizeof(config_path), "%s", optarg);
542+				have_config = true;
543+				break;
544+		}
545+	}
546+
547+	if (!setup(&app))
548+		goto error;
549+
550+	pfd.fd = wl_display_get_fd(app.dpy);
551+	pfd.events = POLLIN;
552+
553+	while (running) {
554+		wl_display_dispatch_pending(app.dpy);
555+		if (wl_display_flush(app.dpy) < 0 && errno != EAGAIN)
556+			break;
557+
558+		poll(&pfd, 1, -1);
559+		if (pfd.revents & POLLIN)
560+			wl_display_dispatch(app.dpy);
561+	}
562+
563+	cleanup(&app);
564+	return 0;
565+
566+error:
567+	cleanup(&app);
568+	return 1;
569+}