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
A
Makefile
+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, ®_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+}