commit d179f183b576213a7d3e2806daca120fac4a25b9
parent 98fdfdab4c6f532ccef8c0ad3a2f33e1a692d879
Author: Jake Koroman <jakekoroman@gmail.com>
Date: Sun, 31 Mar 2024 20:56:56 -0400
add dwlb and dwl, finally going back to a real wm :)
Diffstat:
48 files changed, 18345 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -9,3 +9,7 @@
.config/emacs/history
.config/emacs/eshell
.config/emacs/auto-save-list/
+dwl/*.o
+dwl/dwl
+dwlb/*.o
+dwlb/dwlb
+\ No newline at end of file
diff --git a/.stow-local-ignore b/.stow-local-ignore
@@ -10,3 +10,6 @@ deploy
.bashrc
.bash_profile
.bash_aliases
+
+dwl
+dwlb
diff --git a/deploy b/deploy
@@ -33,6 +33,7 @@ symlink_file() {
symlink_file "$(pwd)/device-specific/$hardware/hardware" "$(pwd)/.config/sway/hardware-specific-config"
symlink_file "$(pwd)/device-specific/$hardware/i3status" "$(pwd)/.config/i3status/config"
symlink_file "$(pwd)/device-specific/$hardware/emacs.el" "$(pwd)/.config/emacs/local/device.el"
+symlink_file "$(pwd)/device-specific/$hardware/dwl-hardware.h" "$(pwd)/dwl/device.h"
sed "s/{FOOT_FONT}/$FOOT_FONT/g" "$(pwd)/shared-configs/foot/template.ini" > "$(pwd)/.config/foot/foot.ini"
diff --git a/device-specific/desktop/dwl-hardware.h b/device-specific/desktop/dwl-hardware.h
@@ -0,0 +1,69 @@
+/*
+ * NOTE(jake): i think its useful to share some settings between dwlb and dwl so putting this here
+ * not sure if i like this approach but it works
+ */
+
+#define DEVICE_FONT "monospace:size=10"
+
+#ifndef NOT_DWL
+/* monitors */
+/* NOTE: ALWAYS add a fallback rule, even if you are completely sure it won't be used */
+static const MonitorRule monrules[] = {
+ /* name mfact nmaster scale layout rotate/reflect x y */
+ { NULL, 0.50f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },
+};
+
+/* keyboard */
+static const struct xkb_rule_names xkb_rules = {
+ /* can specify fields: rules, model, layout, variant, options */
+ /* example:
+ .options = "ctrl:nocaps",
+ */
+ .options = "caps:escape",
+};
+
+static const int repeat_rate = 25;
+static const int repeat_delay = 600;
+
+/* Trackpad */
+static const int tap_to_click = 1;
+static const int tap_and_drag = 1;
+static const int drag_lock = 1;
+static const int natural_scrolling = 0;
+static const int disable_while_typing = 1;
+static const int left_handed = 0;
+static const int middle_button_emulation = 0;
+/* You can choose between:
+LIBINPUT_CONFIG_SCROLL_NO_SCROLL
+LIBINPUT_CONFIG_SCROLL_2FG
+LIBINPUT_CONFIG_SCROLL_EDGE
+LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN
+*/
+static const enum libinput_config_scroll_method scroll_method = LIBINPUT_CONFIG_SCROLL_2FG;
+
+/* You can choose between:
+LIBINPUT_CONFIG_CLICK_METHOD_NONE
+LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS
+LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER
+*/
+static const enum libinput_config_click_method click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
+
+/* You can choose between:
+LIBINPUT_CONFIG_SEND_EVENTS_ENABLED
+LIBINPUT_CONFIG_SEND_EVENTS_DISABLED
+LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE
+*/
+static const uint32_t send_events_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
+
+/* You can choose between:
+LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT
+LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE
+*/
+static const enum libinput_config_accel_profile accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
+static const double accel_speed = -0.15;
+/* You can choose between:
+LIBINPUT_CONFIG_TAP_MAP_LRM -- 1/2/3 finger tap maps to left/right/middle
+LIBINPUT_CONFIG_TAP_MAP_LMR -- 1/2/3 finger tap maps to left/middle/right
+*/
+static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TAP_MAP_LRM;
+#endif
diff --git a/dwl/CHANGELOG.md b/dwl/CHANGELOG.md
@@ -0,0 +1,110 @@
+# Changelog
+
+* [Unreleased](#unreleased)
+* [0.5](#0.5)
+
+
+## Unreleased
+### Added
+### Changed
+### Deprecated
+### Removed
+### Fixed
+### Security
+### Contributors
+
+
+## 0.5
+
+### Added
+
+* Allow configure x and y position of outputs ([#301][301])
+* Implement repeatable keybindings ([#368][368])
+* Print app id in printstatus() output ([#381][381])
+* Display client count in monocle symbol ([#387][387])
+* Export XCURSOR_SIZE to fix apps using an older version of Qt ([#425][425])
+* Support for wp-fractional-scale-v1 (through wlr_scene: [wlroots!3511][wlroots!3511])
+* dwl now sends `wl_surface.preferred_buffer_scale` (through wlr_scene: [wlroots!4269][wlroots!4269])
+* Add support for xdg-shell v6 ([#465][465])
+* Add support for wp-cursor-shape-v1 ([#444][444])
+* Add desktop file ([#484][484])
+* Add macro to easily configure colors ([#466][466])
+* Color of urgent clients are now red ([#494][494])
+* New flag `-d` and option `log_level` to change the wlroots debug level
+* Add CHANGELOG.md ([#501][501])
+
+[301]: https://github.com/djpohly/dwl/pull/301
+[368]: https://github.com/djpohly/dwl/pull/368
+[381]: https://github.com/djpohly/dwl/pull/381
+[387]: https://github.com/djpohly/dwl/issues/387
+[425]: https://github.com/djpohly/dwl/pull/425
+[wlroots!4269]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4269
+[wlroots!3511]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3511
+[465]: https://github.com/djpohly/dwl/pull/465
+[444]: https://github.com/djpohly/dwl/pull/444
+[484]: https://github.com/djpohly/dwl/pull/484
+[466]: https://github.com/djpohly/dwl/issues/466
+[494]: https://github.com/djpohly/dwl/pull/494
+[501]: https://github.com/djpohly/dwl/pull/501
+
+
+### Changed
+
+* Replace `tags` with `TAGCOUNT` in config.def.h ([#403][403])
+* Pop ups are now destroyed when focusing another client ([#408][408])
+* dwl does not longer respect size hints, instead clip windows if they are
+ larger than they should be ([#455][455])
+* The version of wlr-layer-shell-unstable-v1 was lowered to 3 (from 4)
+* Use the same border color as dwm ([#494][494])
+
+[403]: https://github.com/djpohly/dwl/pull/403
+[408]: https://github.com/djpohly/dwl/pull/409
+[455]: https://github.com/djpohly/dwl/pull/455
+[494]: https://github.com/djpohly/dwl/pull/494
+
+
+### Removed
+
+* Remove unused `rootcolor` option ([#401][401])
+* Remove support for wlr-input-inhibitor-unstable-v1 ([#430][430])
+* Remove support for KDE idle protocol ([#431][431])
+
+[401]: https://github.com/djpohly/dwl/pull/401
+[430]: https://github.com/djpohly/dwl/pull/430
+[431]: https://github.com/djpohly/dwl/pull/431
+
+
+### Fixed
+
+* Fix crash when creating a layer surface with all outputs disabled
+ ([#421][421])
+* Fix other clients being shown as focused if the focused client have pop ups
+ open ([#408][408])
+* Resize fullscreen clients when updating monitor mode
+* dwl no longer crash at exit like sometimes did
+* Fullscreen background appearing above clients ([#487][487])
+* Fix a segfault when user provides invalid xkb_rules ([#518][518])
+
+[421]: https://github.com/djpohly/dwl/pull/421
+[408]: https://github.com/djpohly/dwl/issues/408
+[487]: https://github.com/djpohly/dwl/issues/487
+[518]: https://github.com/djpohly/dwl/pull/518
+
+
+### Contributors
+
+* A Frederick Christensen
+* Angelo Antony
+* Ben Collerson
+* Devin J. Pohly
+* Forrest Bushstone
+* gan-of-culture
+* godalming123
+* Job79
+* link2xt
+* Micah Gorrell
+* Nikita Ivanov
+* Palanix
+* pino-desktop
+* Weiseguy
+* Yves Zoundi
diff --git a/dwl/LICENSE b/dwl/LICENSE
@@ -0,0 +1,692 @@
+dwl - dwm for Wayland
+
+Copyright © 2020 dwl team
+
+See also the files LICENSE.tinywl, LICENSE.dwm and LICENSE.sway.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+----
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<https://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<https://www.gnu.org/licenses/why-not-lgpl.html>.
diff --git a/dwl/LICENSE.dwm b/dwl/LICENSE.dwm
@@ -0,0 +1,39 @@
+Portions of dwl based on dwm code are used under the following license:
+
+MIT/X Consortium License
+
+© 2006-2019 Anselm R Garbe <anselm@garbe.ca>
+© 2006-2009 Jukka Salmi <jukka at salmi dot ch>
+© 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
+© 2007-2011 Peter Hartlich <sgkkr at hartlich dot com>
+© 2007-2009 Szabolcs Nagy <nszabolcs at gmail dot com>
+© 2007-2009 Christof Musik <christof at sendfax dot de>
+© 2007-2009 Premysl Hruby <dfenze at gmail dot com>
+© 2007-2008 Enno Gottox Boland <gottox at s01 dot de>
+© 2008 Martin Hurton <martin dot hurton at gmail dot com>
+© 2008 Neale Pickett <neale dot woozle dot org>
+© 2009 Mate Nagy <mnagy at port70 dot net>
+© 2010-2016 Hiltjo Posthuma <hiltjo@codemadness.org>
+© 2010-2012 Connor Lane Smith <cls@lubutu.com>
+© 2011 Christoph Lohmann <20h@r-36.net>
+© 2015-2016 Quentin Rameau <quinq@fifth.space>
+© 2015-2016 Eric Pruitt <eric.pruitt@gmail.com>
+© 2016-2017 Markus Teich <markus.teich@stusta.mhn.de>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/dwl/LICENSE.sway b/dwl/LICENSE.sway
@@ -0,0 +1,19 @@
+Copyright (c) 2016-2017 Drew DeVault
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/dwl/LICENSE.tinywl b/dwl/LICENSE.tinywl
@@ -0,0 +1,127 @@
+dwl is originally based on TinyWL, which is used under the following license:
+
+This work is licensed under CC0, which effectively puts it in the public domain.
+
+---
+
+Creative Commons Legal Code
+
+CC0 1.0 Universal
+
+ CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+ LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
+ ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+ INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+ REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
+ PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
+ THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+ HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator
+and subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for
+the purpose of contributing to a commons of creative, cultural and
+scientific works ("Commons") that the public can reliably and without fear
+of later claims of infringement build upon, modify, incorporate in other
+works, reuse and redistribute as freely as possible in any form whatsoever
+and for any purposes, including without limitation commercial purposes.
+These owners may contribute to the Commons to promote the ideal of a free
+culture and the further production of creative, cultural and scientific
+works, or to gain reputation or greater distribution for their Work in
+part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any
+expectation of additional consideration or compensation, the person
+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
+is an owner of Copyright and Related Rights in the Work, voluntarily
+elects to apply CC0 to the Work and publicly distribute the Work under its
+terms, with knowledge of his or her Copyright and Related Rights in the
+Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not
+limited to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display,
+ communicate, and translate a Work;
+ ii. moral rights retained by the original author(s) and/or performer(s);
+iii. publicity and privacy rights pertaining to a person's image or
+ likeness depicted in a Work;
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+ v. rights protecting the extraction, dissemination, use and reuse of data
+ in a Work;
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation
+ thereof, including any amended or successor version of such
+ directive); and
+vii. other similar, equivalent or corresponding rights throughout the
+ world based on applicable law or treaty, and any national
+ implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention
+of, applicable law, Affirmer hereby overtly, fully, permanently,
+irrevocably and unconditionally waives, abandons, and surrenders all of
+Affirmer's Copyright and Related Rights and associated claims and causes
+of action, whether now known or unknown (including existing as well as
+future claims and causes of action), in the Work (i) in all territories
+worldwide, (ii) for the maximum duration provided by applicable law or
+treaty (including future time extensions), (iii) in any current or future
+medium and for any number of copies, and (iv) for any purpose whatsoever,
+including without limitation commercial, advertising or promotional
+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
+member of the public at large and to the detriment of Affirmer's heirs and
+successors, fully intending that such Waiver shall not be subject to
+revocation, rescission, cancellation, termination, or any other legal or
+equitable action to disrupt the quiet enjoyment of the Work by the public
+as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason
+be judged legally invalid or ineffective under applicable law, then the
+Waiver shall be preserved to the maximum extent permitted taking into
+account Affirmer's express Statement of Purpose. In addition, to the
+extent the Waiver is so judged Affirmer hereby grants to each affected
+person a royalty-free, non transferable, non sublicensable, non exclusive,
+irrevocable and unconditional license to exercise Affirmer's Copyright and
+Related Rights in the Work (i) in all territories worldwide, (ii) for the
+maximum duration provided by applicable law or treaty (including future
+time extensions), (iii) in any current or future medium and for any number
+of copies, and (iv) for any purpose whatsoever, including without
+limitation commercial, advertising or promotional purposes (the
+"License"). The License shall be deemed effective as of the date CC0 was
+applied by Affirmer to the Work. Should any part of the License for any
+reason be judged legally invalid or ineffective under applicable law, such
+partial invalidity or ineffectiveness shall not invalidate the remainder
+of the License, and in such case Affirmer hereby affirms that he or she
+will not (i) exercise any of his or her remaining Copyright and Related
+Rights in the Work or (ii) assert any associated claims and causes of
+action with respect to the Work, in either case contrary to Affirmer's
+express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+ b. Affirmer offers the Work as-is and makes no representations or
+ warranties of any kind concerning the Work, express, implied,
+ statutory or otherwise, including without limitation warranties of
+ title, merchantability, fitness for a particular purpose, non
+ infringement, or the absence of latent or other defects, accuracy, or
+ the present or absence of errors, whether or not discoverable, all to
+ the greatest extent permissible under applicable law.
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without
+ limitation any person's Copyright and Related Rights in the Work.
+ Further, Affirmer disclaims responsibility for obtaining any necessary
+ consents, permissions or other rights required for any use of the
+ Work.
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to
+ this CC0 or use of the Work.
diff --git a/dwl/Makefile b/dwl/Makefile
@@ -0,0 +1,76 @@
+.POSIX:
+.SUFFIXES:
+
+include config.mk
+
+# flags for compiling
+DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XWAYLAND)
+DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement -Wno-unused-parameter -Wshadow -Wunused-macros\
+ -Werror=strict-prototypes -Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types -Wfloat-conversion
+
+# CFLAGS / LDFLAGS
+PKGS = wlroots wayland-server xkbcommon libinput $(XLIBS)
+DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS)
+LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(LIBS)
+
+PREFIX = $(HOME)/.local
+
+all: dwl
+dwl: dwl.o util.o dwl-ipc-unstable-v2-protocol.o
+ $(CC) dwl.o util.o dwl-ipc-unstable-v2-protocol.o $(LDLIBS) $(LDFLAGS) $(DWLCFLAGS) -o $@
+dwl.o: dwl.c config.mk config.h client.h cursor-shape-v1-protocol.h pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h xdg-shell-protocol.h dwl-ipc-unstable-v2-protocol.h
+util.o: util.c util.h
+dwl-ipc-unstable-v2-protocol.o: dwl-ipc-unstable-v2-protocol.c dwl-ipc-unstable-v2-protocol.h
+
+# wayland-scanner is a tool which generates C headers and rigging for Wayland
+# protocols, which are specified in XML. wlroots requires you to rig these up
+# to your build system yourself and provide them in the include path.
+WAYLAND_SCANNER = `$(PKG_CONFIG) --variable=wayland_scanner wayland-scanner`
+WAYLAND_PROTOCOLS = `$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols`
+
+cursor-shape-v1-protocol.h:
+ $(WAYLAND_SCANNER) server-header \
+ $(WAYLAND_PROTOCOLS)/staging/cursor-shape/cursor-shape-v1.xml $@
+pointer-constraints-unstable-v1-protocol.h:
+ $(WAYLAND_SCANNER) server-header \
+ $(WAYLAND_PROTOCOLS)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@
+wlr-layer-shell-unstable-v1-protocol.h:
+ $(WAYLAND_SCANNER) server-header \
+ protocols/wlr-layer-shell-unstable-v1.xml $@
+xdg-shell-protocol.h:
+ $(WAYLAND_SCANNER) server-header \
+ $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
+dwl-ipc-unstable-v2-protocol.h:
+ $(WAYLAND_SCANNER) server-header \
+ protocols/dwl-ipc-unstable-v2.xml $@
+dwl-ipc-unstable-v2-protocol.c:
+ $(WAYLAND_SCANNER) private-code \
+ protocols/dwl-ipc-unstable-v2.xml $@
+
+clean:
+ rm -f dwl *.o *-protocol.h *.patch *.rej *.orig
+
+dist: clean
+ mkdir -p dwl-$(VERSION)
+ cp -R LICENSE* Makefile CHANGELOG.md README.md client.h config.def.h\
+ config.mk protocols dwl.1 dwl.c util.c util.h dwl.desktop\
+ dwl-$(VERSION)
+ tar -caf dwl-$(VERSION).tar.gz dwl-$(VERSION)
+ rm -rf dwl-$(VERSION)
+
+install: dwl
+ mkdir -p $(DESTDIR)$(PREFIX)/bin
+ cp -f dwl $(DESTDIR)$(PREFIX)/bin
+ chmod 755 $(DESTDIR)$(PREFIX)/bin/dwl
+ mkdir -p $(DESTDIR)$(MANDIR)/man1
+ cp -f dwl.1 $(DESTDIR)$(MANDIR)/man1
+ chmod 644 $(DESTDIR)$(MANDIR)/man1/dwl.1
+ mkdir -p $(DESTDIR)$(DATADIR)/wayland-sessions
+ cp -f dwl.desktop $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop
+ chmod 644 $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop
+uninstall:
+ rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop
+
+.SUFFIXES: .c .o
+.c.o:
+ $(CC) $(CPPFLAGS) $(DWLCFLAGS) -c $<
diff --git a/dwl/README.md b/dwl/README.md
@@ -0,0 +1,181 @@
+# dwl - dwm for Wayland
+
+Join us on our IRC channel: [#dwl on Libera Chat]
+Or on our [Discord server].
+
+dwl is a compact, hackable compositor for [Wayland] based on [wlroots]. It is
+intended to fill the same space in the Wayland world that dwm does in X11,
+primarily in terms of functionality, and secondarily in terms of philosophy.
+Like dwm, dwl is:
+
+- Easy to understand, hack on, and extend with patches
+- One C source file (or a very small number) configurable via `config.h`
+- Tied to as few external dependencies as possible
+
+dwl is not meant to provide every feature under the sun. Instead, like dwm, it
+sticks to features which are necessary, simple, and straightforward to implement
+given the base on which it is built. Implemented default features are:
+
+- Any features provided by dwm/Xlib: simple window borders, tags, keybindings,
+ client rules, mouse move/resize. Providing a built-in status bar is an
+ exception to this goal, to avoid dependencies on font rendering and/or
+ drawing libraries when an external bar could work well.
+- Configurable multi-monitor layout support, including position and rotation
+- Configurable HiDPI/multi-DPI support
+- Idle-inhibit protocol which lets applications such as mpv disable idle
+ monitoring
+- Provide information to external status bars via stdout/stdin
+- Urgency hints via xdg-activate protocol
+- Support screen lockers via ext-session-lock-v1 protocol
+- Various Wayland protocols
+- XWayland support as provided by wlroots (can be enabled in `config.mk`)
+- Zero flickering - Wayland users naturally expect that "every frame is perfect"
+- Layer shell popups (used by Waybar)
+- Damage tracking provided by scenegraph API
+
+Given the Wayland architecture, dwl has to implement features from dwm **and**
+the xorg-server. Because of this, it is impossible to maintain the original
+project goal of 2000 SLOC and have a reasonably complete compositor with
+features comparable to dwm. However, this does not mean that the code will grow
+indiscriminately. We will try to keep the code as small as possible.
+
+Features under consideration (possibly as patches) are:
+
+- Protocols made trivial by wlroots
+- Implement the text-input and input-method protocols to support IME once ibus
+ implements input-method v2 (see https://github.com/ibus/ibus/pull/2256 and
+ https://codeberg.org/dwl/dwl/pulls/235)
+
+Feature *non-goals* for the main codebase include:
+
+- Client-side decoration (any more than is necessary to tell the clients not to)
+- Client-initiated window management, such as move, resize, and close, which can
+ be done through the compositor
+- Animations and visual effects
+
+## Building dwl
+
+dwl has the following dependencies:
+```
+libinput
+wayland
+wlroots (compiled with the libinput backend)
+xkbcommon
+wayland-protocols (compile-time only)
+pkg-config (compile-time only)
+```
+If you enable X11 support:
+```
+libxcb
+libxcb-wm
+wlroots (compiled with X11 support)
+Xwayland (runtime only)
+```
+
+Simply install these (and their `-devel` versions if your distro has separate
+development packages) and run `make`. If you wish to build against a Git
+version of wlroots, check out the [wlroots-next branch].
+
+To enable XWayland, you should uncomment its flags in `config.mk`.
+
+## Configuration
+
+All configuration is done by editing `config.h` and recompiling, in the same
+manner as dwm. There is no way to separately restart the window manager in
+Wayland without restarting the entire display server, so any changes will take
+effect the next time dwl is executed.
+
+As in the dwm community, we encourage users to share patches they have created.
+Check out the dwl [patches repository] and [patches wiki]!
+
+## Running dwl
+
+dwl can be run on any of the backends supported by wlroots. This means you can
+run it as a separate window inside either an X11 or Wayland session, as well
+as directly from a VT console. Depending on your distro's setup, you may need
+to add your user to the `video` and `input` groups before you can run dwl on
+a VT. If you are using `elogind` or `systemd-logind` you need to install
+polkit; otherwise you need to add yourself in the `seat` group and
+enable/start the seatd daemon.
+
+When dwl is run with no arguments, it will launch the server and begin handling
+any shortcuts configured in `config.h`. There is no status bar or other
+decoration initially; these are instead clients that can be run within
+the Wayland session.
+Do note that the background color is black.
+
+If you would like to run a script or command automatically at startup, you can
+specify the command using the `-s` option. This command will be executed as a
+shell command using `/bin/sh -c`. It serves a similar function to `.xinitrc`,
+but differs in that the display server will not shut down when this process
+terminates. Instead, dwl will send this process a SIGTERM at shutdown and wait
+for it to terminate (if it hasn't already). This makes it ideal for execing into
+a user service manager like [s6], [anopa], [runit], [dinit], or [`systemd --user`].
+
+Note: The `-s` command is run as a *child process* of dwl, which means that it
+does not have the ability to affect the environment of dwl or of any processes
+that it spawns. If you need to set environment variables that affect the entire
+dwl session, these must be set prior to running dwl. For example, Wayland
+requires a valid `XDG_RUNTIME_DIR`, which is usually set up by a session manager
+such as `elogind` or `systemd-logind`. If your system doesn't do this
+automatically, you will need to configure it prior to launching `dwl`, e.g.:
+
+ export XDG_RUNTIME_DIR=/tmp/xdg-runtime-$(id -u)
+ mkdir -p $XDG_RUNTIME_DIR
+ dwl
+
+### Status information
+
+Information about selected layouts, current window title, app-id, and
+selected/occupied/urgent tags is written to the stdin of the `-s` command (see
+the `printstatus()` function for details). This information can be used to
+populate an external status bar with a script that parses the information.
+Failing to read this information will cause dwl to block, so if you do want to
+run a startup command that does not consume the status information, you can
+close standard input with the `<&-` shell redirection, for example:
+
+ dwl -s 'foot --server <&-'
+
+If your startup command is a shell script, you can achieve the same inside the
+script with the line
+
+ exec <&-
+
+To get a list of status bars that work with dwl consult our [wiki].
+
+## Replacements for X applications
+
+You can find a [list of useful resources on our wiki].
+
+## Acknowledgements
+
+dwl began by extending the TinyWL example provided (CC0) by the sway/wlroots
+developers. This was made possible in many cases by looking at how sway
+accomplished something, then trying to do the same in as suckless a way as
+possible.
+
+Many thanks to suckless.org and the dwm developers and community for the
+inspiration, and to the various contributors to the project, including:
+
+- **Devin J. Pohly for creating and nurturing the fledgling project**
+- Alexander Courtis for the XWayland implementation
+- Guido Cella for the layer-shell protocol implementation, patch maintenance,
+ and for helping to keep the project running
+- Stivvo for output management and fullscreen support, and patch maintenance
+
+
+[Discord server]: https://discord.gg/jJxZnrGPWN
+[#dwl on Libera Chat]: https://web.libera.chat/?channels=#dwl
+[Wayland]: https://wayland.freedesktop.org/
+[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots/
+[wlroots-next branch]: https://codeberg.org/dwl/dwl/src/branch/wlroots-next
+[patches repository]: https://codeberg.org/dwl/dwl-patches
+[patches wiki]: https://codeberg.org/dwl/dwl-patches/wiki
+[s6]: https://skarnet.org/software/s6/
+[anopa]: https://jjacky.com/anopa/
+[runit]: http://smarden.org/runit/faq.html#userservices
+[dinit]: https://davmac.org/projects/dinit/
+[`systemd --user`]: https://wiki.archlinux.org/title/Systemd/User
+[wiki]: https://codeberg.org/dwl/dwl/wiki/Home#compatible-status-bars
+[list of useful resources on our wiki]:
+ https://codeberg.org/dwl/dwl/wiki/Home#migrating-from-x
diff --git a/dwl/client.h b/dwl/client.h
@@ -0,0 +1,422 @@
+/*
+ * Attempt to consolidate unavoidable suck into one file, away from dwl.c. This
+ * file is not meant to be pretty. We use a .h file with static inline
+ * functions instead of a separate .c module, or function pointers like sway, so
+ * that they will simply compile out if the chosen #defines leave them unused.
+ */
+
+/* Leave these functions first; they're used in the others */
+static inline int
+client_is_x11(Client *c)
+{
+#ifdef XWAYLAND
+ return c->type == X11;
+#endif
+ return 0;
+}
+
+static inline struct wlr_surface *
+client_surface(Client *c)
+{
+#ifdef XWAYLAND
+ if (client_is_x11(c))
+ return c->surface.xwayland->surface;
+#endif
+ return c->surface.xdg->surface;
+}
+
+static inline int
+toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl)
+{
+ struct wlr_xdg_surface *xdg_surface, *tmp_xdg_surface;
+ struct wlr_surface *root_surface;
+ struct wlr_layer_surface_v1 *layer_surface;
+ Client *c = NULL;
+ LayerSurface *l = NULL;
+ int type = -1;
+#ifdef XWAYLAND
+ struct wlr_xwayland_surface *xsurface;
+#endif
+
+ if (!s)
+ return -1;
+ root_surface = wlr_surface_get_root_surface(s);
+
+#ifdef XWAYLAND
+ if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(root_surface))) {
+ c = xsurface->data;
+ type = c->type;
+ goto end;
+ }
+#endif
+
+ if ((layer_surface = wlr_layer_surface_v1_try_from_wlr_surface(root_surface))) {
+ l = layer_surface->data;
+ type = LayerShell;
+ goto end;
+ }
+
+ xdg_surface = wlr_xdg_surface_try_from_wlr_surface(root_surface);
+ while (xdg_surface) {
+ tmp_xdg_surface = NULL;
+ switch (xdg_surface->role) {
+ case WLR_XDG_SURFACE_ROLE_POPUP:
+ if (!xdg_surface->popup || !xdg_surface->popup->parent)
+ return -1;
+
+ tmp_xdg_surface = wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent);
+
+ if (!tmp_xdg_surface)
+ return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc, pl);
+
+ xdg_surface = tmp_xdg_surface;
+ break;
+ case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
+ c = xdg_surface->data;
+ type = c->type;
+ goto end;
+ case WLR_XDG_SURFACE_ROLE_NONE:
+ return -1;
+ }
+ }
+
+end:
+ if (pl)
+ *pl = l;
+ if (pc)
+ *pc = c;
+ return type;
+}
+
+/* The others */
+static inline void
+client_activate_surface(struct wlr_surface *s, int activated)
+{
+ struct wlr_xdg_toplevel *toplevel;
+#ifdef XWAYLAND
+ struct wlr_xwayland_surface *xsurface;
+ if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(s))) {
+ wlr_xwayland_surface_activate(xsurface, activated);
+ return;
+ }
+#endif
+ if ((toplevel = wlr_xdg_toplevel_try_from_wlr_surface(s)))
+ wlr_xdg_toplevel_set_activated(toplevel, activated);
+}
+
+static inline uint32_t
+client_set_bounds(Client *c, int32_t width, int32_t height)
+{
+#ifdef XWAYLAND
+ if (client_is_x11(c))
+ return 0;
+#endif
+ if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >=
+ XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION && width >= 0 && height >= 0
+ && (c->bounds.width != width || c->bounds.height != height)) {
+ c->bounds.width = width;
+ c->bounds.height = height;
+ return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height);
+ }
+ return 0;
+}
+
+static inline const char *
+client_get_appid(Client *c)
+{
+#ifdef XWAYLAND
+ if (client_is_x11(c))
+ return c->surface.xwayland->class;
+#endif
+ return c->surface.xdg->toplevel->app_id;
+}
+
+static inline int
+client_get_pid(Client *c)
+{
+ pid_t pid;
+#ifdef XWAYLAND
+ if (client_is_x11(c))
+ return c->surface.xwayland->pid;
+#endif
+ wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL);
+ return pid;
+}
+
+static inline void
+client_get_clip(Client *c, struct wlr_box *clip)
+{
+ struct wlr_box xdg_geom = {0};
+ *clip = (struct wlr_box){
+ .x = 0,
+ .y = 0,
+ .width = c->geom.width - c->bw,
+ .height = c->geom.height - c->bw,
+ };
+
+#ifdef XWAYLAND
+ if (client_is_x11(c))
+ return;
+#endif
+
+ wlr_xdg_surface_get_geometry(c->surface.xdg, &xdg_geom);
+ clip->x = xdg_geom.x;
+ clip->y = xdg_geom.y;
+}
+
+static inline void
+client_get_geometry(Client *c, struct wlr_box *geom)
+{
+#ifdef XWAYLAND
+ if (client_is_x11(c)) {
+ geom->x = c->surface.xwayland->x;
+ geom->y = c->surface.xwayland->y;
+ geom->width = c->surface.xwayland->width;
+ geom->height = c->surface.xwayland->height;
+ return;
+ }
+#endif
+ wlr_xdg_surface_get_geometry(c->surface.xdg, geom);
+}
+
+static inline Client *
+client_get_parent(Client *c)
+{
+ Client *p = NULL;
+#ifdef XWAYLAND
+ if (client_is_x11(c)) {
+ if (c->surface.xwayland->parent)
+ toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL);
+ return p;
+ }
+#endif
+ if (c->surface.xdg->toplevel->parent)
+ toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL);
+ return p;
+}
+
+static inline int
+client_has_children(Client *c)
+{
+#ifdef XWAYLAND
+ if (client_is_x11(c))
+ return !wl_list_empty(&c->surface.xwayland->children);
+#endif
+ /* surface.xdg->link is never empty because it always contains at least the
+ * surface itself. */
+ return wl_list_length(&c->surface.xdg->link) > 1;
+}
+
+static inline const char *
+client_get_title(Client *c)
+{
+#ifdef XWAYLAND
+ if (client_is_x11(c))
+ return c->surface.xwayland->title;
+#endif
+ return c->surface.xdg->toplevel->title;
+}
+
+static inline int
+client_is_float_type(Client *c)
+{
+ struct wlr_xdg_toplevel *toplevel;
+ struct wlr_xdg_toplevel_state state;
+
+#ifdef XWAYLAND
+ if (client_is_x11(c)) {
+ struct wlr_xwayland_surface *surface = c->surface.xwayland;
+ xcb_size_hints_t *size_hints = surface->size_hints;
+ size_t i;
+ if (surface->modal)
+ return 1;
+
+ for (i = 0; i < surface->window_type_len; i++)
+ if (surface->window_type[i] == netatom[NetWMWindowTypeDialog]
+ || surface->window_type[i] == netatom[NetWMWindowTypeSplash]
+ || surface->window_type[i] == netatom[NetWMWindowTypeToolbar]
+ || surface->window_type[i] == netatom[NetWMWindowTypeUtility])
+ return 1;
+
+ return size_hints && size_hints->min_width > 0 && size_hints->min_height > 0
+ && (size_hints->max_width == size_hints->min_width
+ || size_hints->max_height == size_hints->min_height);
+ }
+#endif
+
+ toplevel = c->surface.xdg->toplevel;
+ state = toplevel->current;
+ return toplevel->parent || (state.min_width != 0 && state.min_height != 0
+ && (state.min_width == state.max_width
+ || state.min_height == state.max_height));
+}
+
+static inline int
+client_is_rendered_on_mon(Client *c, Monitor *m)
+{
+ /* This is needed for when you don't want to check formal assignment,
+ * but rather actual displaying of the pixels.
+ * Usually VISIBLEON suffices and is also faster. */
+ struct wlr_surface_output *s;
+ int unused_lx, unused_ly;
+ if (!wlr_scene_node_coords(&c->scene->node, &unused_lx, &unused_ly))
+ return 0;
+ wl_list_for_each(s, &client_surface(c)->current_outputs, link)
+ if (s->output == m->wlr_output)
+ return 1;
+ return 0;
+}
+
+static inline int
+client_is_stopped(Client *c)
+{
+ int pid;
+ siginfo_t in = {0};
+#ifdef XWAYLAND
+ if (client_is_x11(c))
+ return 0;
+#endif
+
+ wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL);
+ if (waitid(P_PID, pid, &in, WNOHANG|WCONTINUED|WSTOPPED|WNOWAIT) < 0) {
+ /* This process is not our child process, while is very unluckely that
+ * it is stopped, in order to do not skip frames assume that it is. */
+ if (errno == ECHILD)
+ return 1;
+ } else if (in.si_pid) {
+ if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED)
+ return 1;
+ if (in.si_code == CLD_CONTINUED)
+ return 0;
+ }
+
+ return 0;
+}
+
+static inline int
+client_is_unmanaged(Client *c)
+{
+#ifdef XWAYLAND
+ if (client_is_x11(c))
+ return c->surface.xwayland->override_redirect;
+#endif
+ return 0;
+}
+
+static inline void
+client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb)
+{
+ if (kb)
+ wlr_seat_keyboard_notify_enter(seat, s, kb->keycodes,
+ kb->num_keycodes, &kb->modifiers);
+ else
+ wlr_seat_keyboard_notify_enter(seat, s, NULL, 0, NULL);
+}
+
+static inline void
+client_restack_surface(Client *c)
+{
+#ifdef XWAYLAND
+ if (client_is_x11(c))
+ wlr_xwayland_surface_restack(c->surface.xwayland, NULL,
+ XCB_STACK_MODE_ABOVE);
+#endif
+ return;
+}
+
+static inline void
+client_send_close(Client *c)
+{
+#ifdef XWAYLAND
+ if (client_is_x11(c)) {
+ wlr_xwayland_surface_close(c->surface.xwayland);
+ return;
+ }
+#endif
+ wlr_xdg_toplevel_send_close(c->surface.xdg->toplevel);
+}
+
+static inline void
+client_set_border_color(Client *c, const float color[static 4])
+{
+ int i;
+ for (i = 0; i < 4; i++)
+ wlr_scene_rect_set_color(c->border[i], color);
+}
+
+static inline void
+client_set_fullscreen(Client *c, int fullscreen)
+{
+#ifdef XWAYLAND
+ if (client_is_x11(c)) {
+ wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, fullscreen);
+ return;
+ }
+#endif
+ wlr_xdg_toplevel_set_fullscreen(c->surface.xdg->toplevel, fullscreen);
+}
+
+static inline uint32_t
+client_set_size(Client *c, uint32_t width, uint32_t height)
+{
+#ifdef XWAYLAND
+ if (client_is_x11(c)) {
+ wlr_xwayland_surface_configure(c->surface.xwayland,
+ c->geom.x, c->geom.y, width, height);
+ return 0;
+ }
+#endif
+ if ((int32_t)width == c->surface.xdg->toplevel->current.width
+ && (int32_t)height == c->surface.xdg->toplevel->current.height)
+ return 0;
+ return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, (int32_t)width, (int32_t)height);
+}
+
+static inline void
+client_set_tiled(Client *c, uint32_t edges)
+{
+#ifdef XWAYLAND
+ if (client_is_x11(c))
+ return;
+#endif
+ if (wl_resource_get_version(c->surface.xdg->toplevel->resource)
+ >= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) {
+ wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges);
+ } else {
+ wlr_xdg_toplevel_set_maximized(c->surface.xdg->toplevel, edges != WLR_EDGE_NONE);
+ }
+}
+
+static inline void
+client_set_suspended(Client *c, int suspended)
+{
+#ifdef XWAYLAND
+ if (client_is_x11(c)) {
+ wlr_xwayland_surface_set_withdrawn(c->surface.xwayland, suspended);
+ return;
+ }
+#endif
+
+ wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended);
+}
+
+static inline int
+client_wants_focus(Client *c)
+{
+#ifdef XWAYLAND
+ return client_is_unmanaged(c)
+ && wlr_xwayland_or_surface_wants_focus(c->surface.xwayland)
+ && wlr_xwayland_icccm_input_model(c->surface.xwayland) != WLR_ICCCM_INPUT_MODEL_NONE;
+#endif
+ return 0;
+}
+
+static inline int
+client_wants_fullscreen(Client *c)
+{
+#ifdef XWAYLAND
+ if (client_is_x11(c))
+ return c->surface.xwayland->fullscreen;
+#endif
+ return c->surface.xdg->toplevel->requested.fullscreen;
+}
diff --git a/dwl/config.h b/dwl/config.h
@@ -0,0 +1,126 @@
+/* Taken from https://github.com/djpohly/dwl/issues/466 */
+#define COLOR(hex) { ((hex >> 24) & 0xFF) / 255.0f, \
+ ((hex >> 16) & 0xFF) / 255.0f, \
+ ((hex >> 8) & 0xFF) / 255.0f, \
+ (hex & 0xFF) / 255.0f }
+/* appearance */
+static const int sloppyfocus = 1; /* focus follows mouse */
+static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */
+static const unsigned int borderpx = 1; /* border pixel of windows */
+static const float rootcolor[] = COLOR(0x222222ff);
+static const float bordercolor[] = COLOR(0x444444ff);
+static const float focuscolor[] = COLOR(0x005577ff);
+static const float urgentcolor[] = COLOR(0xff0000ff);
+/* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */
+static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */
+
+/* tagging - TAGCOUNT must be no greater than 31 */
+#define TAGCOUNT (9)
+
+/* logging */
+static int log_level = WLR_ERROR;
+
+static const Rule rules[] = {
+ /* app_id title tags mask isfloating isterm noswallow monitor */
+ { "foot", NULL, 0, 0, 1, 1, -1 },
+ { "mpv" , NULL, 0, 0, 0, 0, -1 },
+ { "swiv", NULL, 0, 0, 0, 0, -1 },
+};
+
+enum LayoutFunction {
+ ltile = 0,
+ lfloat = 1,
+ lmonocle = 2,
+ lcenteredmaster = 3,
+};
+
+/* layout(s) */
+static const Layout layouts[] = {
+ /* symbol arrange function */
+ { "[]=", tile },
+ { "><>", NULL }, /* no layout function means floating behavior */
+ { "[M]", monocle },
+ { "|M|", centeredmaster },
+};
+
+/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */
+#define MODKEY WLR_MODIFIER_ALT
+
+#define TAGKEYS(KEY,SKEY,TAG) \
+ { MODKEY, KEY, view, {.ui = 1 << TAG} }, \
+ { MODKEY|WLR_MODIFIER_CTRL, KEY, toggleview, {.ui = 1 << TAG} }, \
+ { MODKEY|WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG} }, \
+ { MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,SKEY,toggletag, {.ui = 1 << TAG} }
+
+/* helper for spawning shell commands in the pre dwm-5.0 fashion */
+#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
+
+/* commands */
+static const char *termcmd[] = { "foot", NULL };
+static const char *menucmd[] = { "bemenu-run", NULL };
+static const char *pavucmd[] = { "pavucontrol", NULL };
+static const char *bookmarkscmd[] = { "bookmarks", NULL };
+static const char *passcmd[] = { "passmenu-otp", NULL };
+static const char *sshmenucmd[] = { "sshmenu", NULL };
+
+static const Key keys[] = {
+ /* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */
+ /* modifier key function argument */
+ { MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
+ { MODKEY, XKB_KEY_Return, spawn, {.v = termcmd} },
+ { MODKEY, XKB_KEY_F1, spawn, {.v = pavucmd} },
+ { MODKEY, XKB_KEY_slash, spawn, {.v = bookmarkscmd} },
+ { MODKEY, XKB_KEY_backslash, spawn, {.v = sshmenucmd} },
+ { MODKEY, XKB_KEY_F12, spawn, {.v = passcmd} },
+ { MODKEY, XKB_KEY_F2, togglebar, {0} },
+ { MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
+ { MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_J, movestack, {.i = +1} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_K, movestack, {.i = -1} },
+ { MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
+ { MODKEY, XKB_KEY_d, incnmaster, {.i = -1} },
+ { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} },
+ { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05f} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, zoom, {0} },
+ { MODKEY, XKB_KEY_Tab, view, {0} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, {0} },
+ { MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[ltile]} },
+ { MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[lfloat]} },
+ { MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[lmonocle]} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_M, setlayout, {.v = &layouts[lcenteredmaster]} },
+ { MODKEY, XKB_KEY_space, setlayout, {0} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_f, togglefullscreen, {0} },
+ { MODKEY, XKB_KEY_0, view, {.ui = ~0} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} },
+ { MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
+ { MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },
+
+ TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
+ TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
+ TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
+ TAGKEYS( XKB_KEY_4, XKB_KEY_dollar, 3),
+ TAGKEYS( XKB_KEY_5, XKB_KEY_percent, 4),
+ TAGKEYS( XKB_KEY_6, XKB_KEY_asciicircum, 5),
+ TAGKEYS( XKB_KEY_7, XKB_KEY_ampersand, 6),
+ TAGKEYS( XKB_KEY_8, XKB_KEY_asterisk, 7),
+ TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8),
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Q, quit, {0} },
+
+ /* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */
+ { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_Terminate_Server, quit, {0} },
+ /* Ctrl-Alt-Fx is used to switch to another VT, if you don't know what a VT is
+ * do not remove them.
+ */
+#define CHVT(n) { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_XF86Switch_VT_##n, chvt, {.ui = (n)} }
+ CHVT(1), CHVT(2), CHVT(3), CHVT(4), CHVT(5), CHVT(6),
+ CHVT(7), CHVT(8), CHVT(9), CHVT(10), CHVT(11), CHVT(12),
+};
+
+static const Button buttons[] = {
+ { MODKEY, BTN_LEFT, moveresize, {.ui = CurMove} },
+ { MODKEY, BTN_MIDDLE, togglefloating, {0} },
+ { MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} },
+};
diff --git a/dwl/config.mk b/dwl/config.mk
@@ -0,0 +1,15 @@
+_VERSION = 0.5
+VERSION = `git describe --tags --dirty 2>/dev/null || echo $(_VERSION)`
+
+PKG_CONFIG = pkg-config
+
+# paths
+PREFIX = /usr/local
+MANDIR = $(PREFIX)/share/man
+DATADIR = $(PREFIX)/share
+
+XWAYLAND =
+XLIBS =
+# Uncomment to build XWayland support
+XWAYLAND = -DXWAYLAND
+XLIBS = xcb xcb-icccm
diff --git a/dwl/cursor-shape-v1-protocol.h b/dwl/cursor-shape-v1-protocol.h
@@ -0,0 +1,367 @@
+/* Generated by wayland-scanner 1.22.0 */
+
+#ifndef CURSOR_SHAPE_V1_SERVER_PROTOCOL_H
+#define CURSOR_SHAPE_V1_SERVER_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-server.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct wl_client;
+struct wl_resource;
+
+/**
+ * @page page_cursor_shape_v1 The cursor_shape_v1 protocol
+ * @section page_ifaces_cursor_shape_v1 Interfaces
+ * - @subpage page_iface_wp_cursor_shape_manager_v1 - cursor shape manager
+ * - @subpage page_iface_wp_cursor_shape_device_v1 - cursor shape for a device
+ * @section page_copyright_cursor_shape_v1 Copyright
+ * <pre>
+ *
+ * Copyright 2018 The Chromium Authors
+ * Copyright 2023 Simon Ser
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * </pre>
+ */
+struct wl_pointer;
+struct wp_cursor_shape_device_v1;
+struct wp_cursor_shape_manager_v1;
+struct zwp_tablet_tool_v2;
+
+#ifndef WP_CURSOR_SHAPE_MANAGER_V1_INTERFACE
+#define WP_CURSOR_SHAPE_MANAGER_V1_INTERFACE
+/**
+ * @page page_iface_wp_cursor_shape_manager_v1 wp_cursor_shape_manager_v1
+ * @section page_iface_wp_cursor_shape_manager_v1_desc Description
+ *
+ * This global offers an alternative, optional way to set cursor images. This
+ * new way uses enumerated cursors instead of a wl_surface like
+ * wl_pointer.set_cursor does.
+ *
+ * Warning! The protocol described in this file is currently in the testing
+ * phase. Backward compatible changes may be added together with the
+ * corresponding interface version bump. Backward incompatible changes can
+ * only be done by creating a new major version of the extension.
+ * @section page_iface_wp_cursor_shape_manager_v1_api API
+ * See @ref iface_wp_cursor_shape_manager_v1.
+ */
+/**
+ * @defgroup iface_wp_cursor_shape_manager_v1 The wp_cursor_shape_manager_v1 interface
+ *
+ * This global offers an alternative, optional way to set cursor images. This
+ * new way uses enumerated cursors instead of a wl_surface like
+ * wl_pointer.set_cursor does.
+ *
+ * Warning! The protocol described in this file is currently in the testing
+ * phase. Backward compatible changes may be added together with the
+ * corresponding interface version bump. Backward incompatible changes can
+ * only be done by creating a new major version of the extension.
+ */
+extern const struct wl_interface wp_cursor_shape_manager_v1_interface;
+#endif
+#ifndef WP_CURSOR_SHAPE_DEVICE_V1_INTERFACE
+#define WP_CURSOR_SHAPE_DEVICE_V1_INTERFACE
+/**
+ * @page page_iface_wp_cursor_shape_device_v1 wp_cursor_shape_device_v1
+ * @section page_iface_wp_cursor_shape_device_v1_desc Description
+ *
+ * This interface advertises the list of supported cursor shapes for a
+ * device, and allows clients to set the cursor shape.
+ * @section page_iface_wp_cursor_shape_device_v1_api API
+ * See @ref iface_wp_cursor_shape_device_v1.
+ */
+/**
+ * @defgroup iface_wp_cursor_shape_device_v1 The wp_cursor_shape_device_v1 interface
+ *
+ * This interface advertises the list of supported cursor shapes for a
+ * device, and allows clients to set the cursor shape.
+ */
+extern const struct wl_interface wp_cursor_shape_device_v1_interface;
+#endif
+
+/**
+ * @ingroup iface_wp_cursor_shape_manager_v1
+ * @struct wp_cursor_shape_manager_v1_interface
+ */
+struct wp_cursor_shape_manager_v1_interface {
+ /**
+ * destroy the manager
+ *
+ * Destroy the cursor shape manager.
+ */
+ void (*destroy)(struct wl_client *client,
+ struct wl_resource *resource);
+ /**
+ * manage the cursor shape of a pointer device
+ *
+ * Obtain a wp_cursor_shape_device_v1 for a wl_pointer object.
+ */
+ void (*get_pointer)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t cursor_shape_device,
+ struct wl_resource *pointer);
+ /**
+ * manage the cursor shape of a tablet tool device
+ *
+ * Obtain a wp_cursor_shape_device_v1 for a zwp_tablet_tool_v2
+ * object.
+ */
+ void (*get_tablet_tool_v2)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t cursor_shape_device,
+ struct wl_resource *tablet_tool);
+};
+
+
+/**
+ * @ingroup iface_wp_cursor_shape_manager_v1
+ */
+#define WP_CURSOR_SHAPE_MANAGER_V1_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wp_cursor_shape_manager_v1
+ */
+#define WP_CURSOR_SHAPE_MANAGER_V1_GET_POINTER_SINCE_VERSION 1
+/**
+ * @ingroup iface_wp_cursor_shape_manager_v1
+ */
+#define WP_CURSOR_SHAPE_MANAGER_V1_GET_TABLET_TOOL_V2_SINCE_VERSION 1
+
+#ifndef WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ENUM
+#define WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ENUM
+/**
+ * @ingroup iface_wp_cursor_shape_device_v1
+ * cursor shapes
+ *
+ * This enum describes cursor shapes.
+ *
+ * The names are taken from the CSS W3C specification:
+ * https://w3c.github.io/csswg-drafts/css-ui/#cursor
+ */
+enum wp_cursor_shape_device_v1_shape {
+ /**
+ * default cursor
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT = 1,
+ /**
+ * a context menu is available for the object under the cursor
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CONTEXT_MENU = 2,
+ /**
+ * help is available for the object under the cursor
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_HELP = 3,
+ /**
+ * pointer that indicates a link or another interactive element
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER = 4,
+ /**
+ * progress indicator
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_PROGRESS = 5,
+ /**
+ * program is busy, user should wait
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_WAIT = 6,
+ /**
+ * a cell or set of cells may be selected
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CELL = 7,
+ /**
+ * simple crosshair
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR = 8,
+ /**
+ * text may be selected
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT = 9,
+ /**
+ * vertical text may be selected
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_VERTICAL_TEXT = 10,
+ /**
+ * drag-and-drop: alias of/shortcut to something is to be created
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALIAS = 11,
+ /**
+ * drag-and-drop: something is to be copied
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_COPY = 12,
+ /**
+ * drag-and-drop: something is to be moved
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE = 13,
+ /**
+ * drag-and-drop: the dragged item cannot be dropped at the current cursor location
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NO_DROP = 14,
+ /**
+ * drag-and-drop: the requested action will not be carried out
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NOT_ALLOWED = 15,
+ /**
+ * drag-and-drop: something can be grabbed
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_GRAB = 16,
+ /**
+ * drag-and-drop: something is being grabbed
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_GRABBING = 17,
+ /**
+ * resizing: the east border is to be moved
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_E_RESIZE = 18,
+ /**
+ * resizing: the north border is to be moved
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_N_RESIZE = 19,
+ /**
+ * resizing: the north-east corner is to be moved
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NE_RESIZE = 20,
+ /**
+ * resizing: the north-west corner is to be moved
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NW_RESIZE = 21,
+ /**
+ * resizing: the south border is to be moved
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_S_RESIZE = 22,
+ /**
+ * resizing: the south-east corner is to be moved
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SE_RESIZE = 23,
+ /**
+ * resizing: the south-west corner is to be moved
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SW_RESIZE = 24,
+ /**
+ * resizing: the west border is to be moved
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_W_RESIZE = 25,
+ /**
+ * resizing: the east and west borders are to be moved
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_EW_RESIZE = 26,
+ /**
+ * resizing: the north and south borders are to be moved
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NS_RESIZE = 27,
+ /**
+ * resizing: the north-east and south-west corners are to be moved
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NESW_RESIZE = 28,
+ /**
+ * resizing: the north-west and south-east corners are to be moved
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NWSE_RESIZE = 29,
+ /**
+ * resizing: that the item/column can be resized horizontally
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_COL_RESIZE = 30,
+ /**
+ * resizing: that the item/row can be resized vertically
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ROW_RESIZE = 31,
+ /**
+ * something can be scrolled in any direction
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_SCROLL = 32,
+ /**
+ * something can be zoomed in
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_IN = 33,
+ /**
+ * something can be zoomed out
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_OUT = 34,
+};
+#endif /* WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ENUM */
+
+#ifndef WP_CURSOR_SHAPE_DEVICE_V1_ERROR_ENUM
+#define WP_CURSOR_SHAPE_DEVICE_V1_ERROR_ENUM
+enum wp_cursor_shape_device_v1_error {
+ /**
+ * the specified shape value is invalid
+ */
+ WP_CURSOR_SHAPE_DEVICE_V1_ERROR_INVALID_SHAPE = 1,
+};
+#endif /* WP_CURSOR_SHAPE_DEVICE_V1_ERROR_ENUM */
+
+/**
+ * @ingroup iface_wp_cursor_shape_device_v1
+ * @struct wp_cursor_shape_device_v1_interface
+ */
+struct wp_cursor_shape_device_v1_interface {
+ /**
+ * destroy the cursor shape device
+ *
+ * Destroy the cursor shape device.
+ *
+ * The device cursor shape remains unchanged.
+ */
+ void (*destroy)(struct wl_client *client,
+ struct wl_resource *resource);
+ /**
+ * set device cursor to the shape
+ *
+ * Sets the device cursor to the specified shape. The compositor
+ * will change the cursor image based on the specified shape.
+ *
+ * The cursor actually changes only if the input device focus is
+ * one of the requesting client's surfaces. If any, the previous
+ * cursor image (surface or shape) is replaced.
+ *
+ * The "shape" argument must be a valid enum entry, otherwise the
+ * invalid_shape protocol error is raised.
+ *
+ * This is similar to the wl_pointer.set_cursor and
+ * zwp_tablet_tool_v2.set_cursor requests, but this request accepts
+ * a shape instead of contents in the form of a surface. Clients
+ * can mix set_cursor and set_shape requests.
+ *
+ * The serial parameter must match the latest wl_pointer.enter or
+ * zwp_tablet_tool_v2.proximity_in serial number sent to the
+ * client. Otherwise the request will be ignored.
+ * @param serial serial number of the enter event
+ */
+ void (*set_shape)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t serial,
+ uint32_t shape);
+};
+
+
+/**
+ * @ingroup iface_wp_cursor_shape_device_v1
+ */
+#define WP_CURSOR_SHAPE_DEVICE_V1_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wp_cursor_shape_device_v1
+ */
+#define WP_CURSOR_SHAPE_DEVICE_V1_SET_SHAPE_SINCE_VERSION 1
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/dwl/device.h b/dwl/device.h
@@ -0,0 +1 @@
+/home/jake/dotfiles/device-specific/desktop/dwl-hardware.h
+\ No newline at end of file
diff --git a/dwl/dwl-ipc-unstable-v2-protocol.c b/dwl/dwl-ipc-unstable-v2-protocol.c
@@ -0,0 +1,70 @@
+/* Generated by wayland-scanner 1.22.0 */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+#ifndef __has_attribute
+# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
+#endif
+
+#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
+#define WL_PRIVATE __attribute__ ((visibility("hidden")))
+#else
+#define WL_PRIVATE
+#endif
+
+extern const struct wl_interface wl_output_interface;
+extern const struct wl_interface zdwl_ipc_output_v2_interface;
+
+static const struct wl_interface *dwl_ipc_unstable_v2_types[] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &zdwl_ipc_output_v2_interface,
+ &wl_output_interface,
+};
+
+static const struct wl_message zdwl_ipc_manager_v2_requests[] = {
+ { "release", "", dwl_ipc_unstable_v2_types + 0 },
+ { "get_output", "no", dwl_ipc_unstable_v2_types + 4 },
+};
+
+static const struct wl_message zdwl_ipc_manager_v2_events[] = {
+ { "tags", "u", dwl_ipc_unstable_v2_types + 0 },
+ { "layout", "s", dwl_ipc_unstable_v2_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface zdwl_ipc_manager_v2_interface = {
+ "zdwl_ipc_manager_v2", 2,
+ 2, zdwl_ipc_manager_v2_requests,
+ 2, zdwl_ipc_manager_v2_events,
+};
+
+static const struct wl_message zdwl_ipc_output_v2_requests[] = {
+ { "release", "", dwl_ipc_unstable_v2_types + 0 },
+ { "set_tags", "uu", dwl_ipc_unstable_v2_types + 0 },
+ { "set_client_tags", "uu", dwl_ipc_unstable_v2_types + 0 },
+ { "set_layout", "u", dwl_ipc_unstable_v2_types + 0 },
+};
+
+static const struct wl_message zdwl_ipc_output_v2_events[] = {
+ { "toggle_visibility", "", dwl_ipc_unstable_v2_types + 0 },
+ { "active", "u", dwl_ipc_unstable_v2_types + 0 },
+ { "tag", "uuuu", dwl_ipc_unstable_v2_types + 0 },
+ { "layout", "u", dwl_ipc_unstable_v2_types + 0 },
+ { "title", "s", dwl_ipc_unstable_v2_types + 0 },
+ { "appid", "s", dwl_ipc_unstable_v2_types + 0 },
+ { "layout_symbol", "s", dwl_ipc_unstable_v2_types + 0 },
+ { "frame", "", dwl_ipc_unstable_v2_types + 0 },
+ { "fullscreen", "2u", dwl_ipc_unstable_v2_types + 0 },
+ { "floating", "2u", dwl_ipc_unstable_v2_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface zdwl_ipc_output_v2_interface = {
+ "zdwl_ipc_output_v2", 2,
+ 4, zdwl_ipc_output_v2_requests,
+ 10, zdwl_ipc_output_v2_events,
+};
+
diff --git a/dwl/dwl-ipc-unstable-v2-protocol.h b/dwl/dwl-ipc-unstable-v2-protocol.h
@@ -0,0 +1,422 @@
+/* Generated by wayland-scanner 1.22.0 */
+
+#ifndef DWL_IPC_UNSTABLE_V2_SERVER_PROTOCOL_H
+#define DWL_IPC_UNSTABLE_V2_SERVER_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-server.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct wl_client;
+struct wl_resource;
+
+/**
+ * @page page_dwl_ipc_unstable_v2 The dwl_ipc_unstable_v2 protocol
+ * inter-proccess-communication about dwl's state
+ *
+ * @section page_desc_dwl_ipc_unstable_v2 Description
+ *
+ * This protocol allows clients to update and get updates from dwl.
+ *
+ * Warning! The protocol described in this file is experimental and
+ * backward incompatible changes may be made. Backward compatible
+ * changes may be added together with the corresponding interface
+ * version bump.
+ * Backward incompatible changes are done by bumping the version
+ * number in the protocol and interface names and resetting the
+ * interface version. Once the protocol is to be declared stable,
+ * the 'z' prefix and the version number in the protocol and
+ * interface names are removed and the interface version number is
+ * reset.
+ *
+ * @section page_ifaces_dwl_ipc_unstable_v2 Interfaces
+ * - @subpage page_iface_zdwl_ipc_manager_v2 - manage dwl state
+ * - @subpage page_iface_zdwl_ipc_output_v2 - control dwl output
+ */
+struct wl_output;
+struct zdwl_ipc_manager_v2;
+struct zdwl_ipc_output_v2;
+
+#ifndef ZDWL_IPC_MANAGER_V2_INTERFACE
+#define ZDWL_IPC_MANAGER_V2_INTERFACE
+/**
+ * @page page_iface_zdwl_ipc_manager_v2 zdwl_ipc_manager_v2
+ * @section page_iface_zdwl_ipc_manager_v2_desc Description
+ *
+ * This interface is exposed as a global in wl_registry.
+ *
+ * Clients can use this interface to get a dwl_ipc_output.
+ * After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events.
+ * The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client.
+ * @section page_iface_zdwl_ipc_manager_v2_api API
+ * See @ref iface_zdwl_ipc_manager_v2.
+ */
+/**
+ * @defgroup iface_zdwl_ipc_manager_v2 The zdwl_ipc_manager_v2 interface
+ *
+ * This interface is exposed as a global in wl_registry.
+ *
+ * Clients can use this interface to get a dwl_ipc_output.
+ * After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events.
+ * The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client.
+ */
+extern const struct wl_interface zdwl_ipc_manager_v2_interface;
+#endif
+#ifndef ZDWL_IPC_OUTPUT_V2_INTERFACE
+#define ZDWL_IPC_OUTPUT_V2_INTERFACE
+/**
+ * @page page_iface_zdwl_ipc_output_v2 zdwl_ipc_output_v2
+ * @section page_iface_zdwl_ipc_output_v2_desc Description
+ *
+ * Observe and control a dwl output.
+ *
+ * Events are double-buffered:
+ * Clients should cache events and redraw when a dwl_ipc_output.frame event is sent.
+ *
+ * Request are not double-buffered:
+ * The compositor will update immediately upon request.
+ * @section page_iface_zdwl_ipc_output_v2_api API
+ * See @ref iface_zdwl_ipc_output_v2.
+ */
+/**
+ * @defgroup iface_zdwl_ipc_output_v2 The zdwl_ipc_output_v2 interface
+ *
+ * Observe and control a dwl output.
+ *
+ * Events are double-buffered:
+ * Clients should cache events and redraw when a dwl_ipc_output.frame event is sent.
+ *
+ * Request are not double-buffered:
+ * The compositor will update immediately upon request.
+ */
+extern const struct wl_interface zdwl_ipc_output_v2_interface;
+#endif
+
+/**
+ * @ingroup iface_zdwl_ipc_manager_v2
+ * @struct zdwl_ipc_manager_v2_interface
+ */
+struct zdwl_ipc_manager_v2_interface {
+ /**
+ * release dwl_ipc_manager
+ *
+ * Indicates that the client will not the dwl_ipc_manager object
+ * anymore. Objects created through this instance are not affected.
+ */
+ void (*release)(struct wl_client *client,
+ struct wl_resource *resource);
+ /**
+ * get a dwl_ipc_outout for a wl_output
+ *
+ * Get a dwl_ipc_outout for the specified wl_output.
+ */
+ void (*get_output)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id,
+ struct wl_resource *output);
+};
+
+#define ZDWL_IPC_MANAGER_V2_TAGS 0
+#define ZDWL_IPC_MANAGER_V2_LAYOUT 1
+
+/**
+ * @ingroup iface_zdwl_ipc_manager_v2
+ */
+#define ZDWL_IPC_MANAGER_V2_TAGS_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_manager_v2
+ */
+#define ZDWL_IPC_MANAGER_V2_LAYOUT_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zdwl_ipc_manager_v2
+ */
+#define ZDWL_IPC_MANAGER_V2_RELEASE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_manager_v2
+ */
+#define ZDWL_IPC_MANAGER_V2_GET_OUTPUT_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zdwl_ipc_manager_v2
+ * Sends an tags event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+zdwl_ipc_manager_v2_send_tags(struct wl_resource *resource_, uint32_t amount)
+{
+ wl_resource_post_event(resource_, ZDWL_IPC_MANAGER_V2_TAGS, amount);
+}
+
+/**
+ * @ingroup iface_zdwl_ipc_manager_v2
+ * Sends an layout event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+zdwl_ipc_manager_v2_send_layout(struct wl_resource *resource_, const char *name)
+{
+ wl_resource_post_event(resource_, ZDWL_IPC_MANAGER_V2_LAYOUT, name);
+}
+
+#ifndef ZDWL_IPC_OUTPUT_V2_TAG_STATE_ENUM
+#define ZDWL_IPC_OUTPUT_V2_TAG_STATE_ENUM
+enum zdwl_ipc_output_v2_tag_state {
+ /**
+ * no state
+ */
+ ZDWL_IPC_OUTPUT_V2_TAG_STATE_NONE = 0,
+ /**
+ * tag is active
+ */
+ ZDWL_IPC_OUTPUT_V2_TAG_STATE_ACTIVE = 1,
+ /**
+ * tag has at least one urgent client
+ */
+ ZDWL_IPC_OUTPUT_V2_TAG_STATE_URGENT = 2,
+};
+#endif /* ZDWL_IPC_OUTPUT_V2_TAG_STATE_ENUM */
+
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ * @struct zdwl_ipc_output_v2_interface
+ */
+struct zdwl_ipc_output_v2_interface {
+ /**
+ * release dwl_ipc_outout
+ *
+ * Indicates to that the client no longer needs this
+ * dwl_ipc_output.
+ */
+ void (*release)(struct wl_client *client,
+ struct wl_resource *resource);
+ /**
+ * Set the active tags of this output
+ *
+ *
+ * @param tagmask bitmask of the tags that should be set.
+ * @param toggle_tagset toggle the selected tagset, zero for invalid, nonzero for valid.
+ */
+ void (*set_tags)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t tagmask,
+ uint32_t toggle_tagset);
+ /**
+ * Set the tags of the focused client.
+ *
+ * The tags are updated as follows: new_tags = (current_tags AND
+ * and_tags) XOR xor_tags
+ */
+ void (*set_client_tags)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t and_tags,
+ uint32_t xor_tags);
+ /**
+ * Set the layout of this output
+ *
+ *
+ * @param index index of a layout recieved by dwl_ipc_manager.layout
+ */
+ void (*set_layout)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t index);
+};
+
+#define ZDWL_IPC_OUTPUT_V2_TOGGLE_VISIBILITY 0
+#define ZDWL_IPC_OUTPUT_V2_ACTIVE 1
+#define ZDWL_IPC_OUTPUT_V2_TAG 2
+#define ZDWL_IPC_OUTPUT_V2_LAYOUT 3
+#define ZDWL_IPC_OUTPUT_V2_TITLE 4
+#define ZDWL_IPC_OUTPUT_V2_APPID 5
+#define ZDWL_IPC_OUTPUT_V2_LAYOUT_SYMBOL 6
+#define ZDWL_IPC_OUTPUT_V2_FRAME 7
+#define ZDWL_IPC_OUTPUT_V2_FULLSCREEN 8
+#define ZDWL_IPC_OUTPUT_V2_FLOATING 9
+
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_TOGGLE_VISIBILITY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_ACTIVE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_TAG_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_LAYOUT_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_TITLE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_APPID_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_LAYOUT_SYMBOL_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_FRAME_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_FULLSCREEN_SINCE_VERSION 2
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION 2
+
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_RELEASE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_SET_TAGS_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_SET_CLIENT_TAGS_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_SET_LAYOUT_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ * Sends an toggle_visibility event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+zdwl_ipc_output_v2_send_toggle_visibility(struct wl_resource *resource_)
+{
+ wl_resource_post_event(resource_, ZDWL_IPC_OUTPUT_V2_TOGGLE_VISIBILITY);
+}
+
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ * Sends an active event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+zdwl_ipc_output_v2_send_active(struct wl_resource *resource_, uint32_t active)
+{
+ wl_resource_post_event(resource_, ZDWL_IPC_OUTPUT_V2_ACTIVE, active);
+}
+
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ * Sends an tag event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param tag Index of the tag
+ * @param state The state of the tag.
+ * @param clients The number of clients in the tag.
+ * @param focused If there is a focused client. Nonzero being valid, zero being invalid.
+ */
+static inline void
+zdwl_ipc_output_v2_send_tag(struct wl_resource *resource_, uint32_t tag, uint32_t state, uint32_t clients, uint32_t focused)
+{
+ wl_resource_post_event(resource_, ZDWL_IPC_OUTPUT_V2_TAG, tag, state, clients, focused);
+}
+
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ * Sends an layout event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param layout Index of the layout.
+ */
+static inline void
+zdwl_ipc_output_v2_send_layout(struct wl_resource *resource_, uint32_t layout)
+{
+ wl_resource_post_event(resource_, ZDWL_IPC_OUTPUT_V2_LAYOUT, layout);
+}
+
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ * Sends an title event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param title The new title name.
+ */
+static inline void
+zdwl_ipc_output_v2_send_title(struct wl_resource *resource_, const char *title)
+{
+ wl_resource_post_event(resource_, ZDWL_IPC_OUTPUT_V2_TITLE, title);
+}
+
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ * Sends an appid event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param appid The new appid.
+ */
+static inline void
+zdwl_ipc_output_v2_send_appid(struct wl_resource *resource_, const char *appid)
+{
+ wl_resource_post_event(resource_, ZDWL_IPC_OUTPUT_V2_APPID, appid);
+}
+
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ * Sends an layout_symbol event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param layout The new layout
+ */
+static inline void
+zdwl_ipc_output_v2_send_layout_symbol(struct wl_resource *resource_, const char *layout)
+{
+ wl_resource_post_event(resource_, ZDWL_IPC_OUTPUT_V2_LAYOUT_SYMBOL, layout);
+}
+
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ * Sends an frame event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+zdwl_ipc_output_v2_send_frame(struct wl_resource *resource_)
+{
+ wl_resource_post_event(resource_, ZDWL_IPC_OUTPUT_V2_FRAME);
+}
+
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ * Sends an fullscreen event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param is_fullscreen If the selected client is fullscreen. Nonzero is valid, zero invalid
+ */
+static inline void
+zdwl_ipc_output_v2_send_fullscreen(struct wl_resource *resource_, uint32_t is_fullscreen)
+{
+ wl_resource_post_event(resource_, ZDWL_IPC_OUTPUT_V2_FULLSCREEN, is_fullscreen);
+}
+
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ * Sends an floating event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param is_floating If the selected client is floating. Nonzero is valid, zero invalid
+ */
+static inline void
+zdwl_ipc_output_v2_send_floating(struct wl_resource *resource_, uint32_t is_floating)
+{
+ wl_resource_post_event(resource_, ZDWL_IPC_OUTPUT_V2_FLOATING, is_floating);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/dwl/dwl.1 b/dwl/dwl.1
@@ -0,0 +1,158 @@
+.Dd January 8, 2021
+.Dt DWL 1
+.Os
+.Sh NAME
+.Nm dwl
+.Nd dwm for Wayland
+.Sh SYNOPSIS
+.Nm
+.Op Fl v
+.Op Fl d
+.Op Fl s Ar startup command
+.Sh DESCRIPTION
+.Nm
+is a Wayland compositor based on wlroots.
+It is intended to fill the same space in the Wayland world that
+.Nm dwm
+does for X11.
+.Pp
+When given the
+.Fl v
+option,
+.Nm
+writes its name and version to standard error and exits unsuccessfully.
+.Pp
+When given the
+.Fl d
+option,
+.Nm
+enables full wlroots logging, including debug information.
+.Pp
+When given the
+.Fl s
+option,
+.Nm
+starts a shell process running
+.Ar command
+when starting.
+When stopping, it sends
+.Dv SIGTERM
+to the child process and waits for it to exit.
+.Pp
+Users are encouraged to customize
+.Nm
+by editing the sources, in particular
+.Pa config.h .
+The default key bindings are as follows:
+.Bl -tag -width 20n -offset indent -compact
+.It Mod-[1-9]
+Show only all windows with a tag.
+.It Mod-Ctrl-[1-9]
+Show all windows with a tag.
+.It Mod-Shift-[1-9]
+Move window to a single tag.
+.It Mod-Ctrl-Shift-[1-9]
+Toggle tag for window.
+.It Mod-p
+Spawn
+.Nm bemenu-run .
+.It Mod-Shift-Return
+Spawn
+.Nm foot .
+.It Mod-[jk]
+Move focus down/up the stack.
+.It Mod-[id]
+Increase/decrease number of windows in master area.
+.It Mod-[hl]
+Decrease/increase master area.
+.It Mod-Return
+Move window on top of stack or switch top of stack with second window.
+.It Mod-Tab
+Show only all windows with previous tag.
+.It Mod-Shift-c
+Close window.
+.It Mod-t
+Switch to tabbed layout.
+.It Mod-f
+Switch to floating layout.
+.It Mod-m
+Switch to monocle layout.
+.It Mod-Space
+Switch to previous layout.
+.It Mod-Shift-Space
+Toggle floating state of window.
+.It Mod-e
+Toggle fullscreen state of window.
+.It Mod-0
+Show all windows.
+.It Mod-Shift-0
+Set all tags for window.
+.It Mod-,
+Move focus to previous monitor.
+.It Mod-.
+Move focus to next monitor.
+.It Mod-Shift-,
+Move window to previous monitor.
+.It Mod-Shift-.
+Move window to next monitor.
+.It Mod-Shift-q
+Quit
+.Nm .
+.El
+These might differ depending on your keyboard layout.
+.Sh ENVIRONMENT
+These environment variables are used by
+.Nm :
+.Bl -tag -width XDG_RUNTIME_DIR
+.It Ev XDG_RUNTIME_DIR
+A directory where temporary user files, such as the Wayland socket,
+are stored.
+.It Ev XDG_CONFIG_DIR
+A directory containing configuration of various programs and
+libraries, including libxkbcommon.
+.It Ev DISPLAY , WAYLAND_DISPLAY , WAYLAND_SOCKET
+Tell how to connect to an underlying X11 or Wayland server.
+.It Ev WLR_*
+Various variables specific to wlroots.
+.It Ev XKB_* , XLOCALEDIR , XCOMPOSEFILE
+Various variables specific to libxkbcommon.
+.It Ev XCURSOR_PATH
+List of directories to search for XCursor themes in.
+.It Ev HOME
+A directory where there are always dear files there for you.
+Waiting for you to clean them up.
+.El
+.Pp
+These are set by
+.Nm :
+.Bl -tag -width WAYLAND_DISPLAY
+.It Ev WAYLAND_DISPLAY
+Tell how to connect to
+.Nm .
+.It Ev DISPLAY
+If using
+.Nm Xwayland ,
+tell how to connect to the
+.Nm Xwayland
+server.
+.El
+.Sh EXAMPLES
+Start
+.Nm
+with s6 in the background:
+.Dl dwl -s 's6-svscan <&-'
+.Sh SEE ALSO
+.Xr foot 1 ,
+.Xr bemenu 1 ,
+.Xr dwm 1 ,
+.Xr xkeyboard-config 7
+.Sh CAVEATS
+The child process's standard input is connected with a pipe to
+.Nm .
+If the child process neither reads from the pipe nor closes its
+standard input,
+.Nm
+will freeze after a while due to it blocking when writing to the full
+pipe buffer.
+.Sh BUGS
+All of them.
diff --git a/dwl/dwl.c b/dwl/dwl.c
@@ -0,0 +1,3482 @@
+/*
+ * See LICENSE file for copyright and license details.
+ */
+#include <getopt.h>
+#include <libinput.h>
+#include <linux/input-event-codes.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+#include <wayland-server-core.h>
+#include <wlr/backend.h>
+#include <wlr/backend/libinput.h>
+#include <wlr/render/allocator.h>
+#include <wlr/render/wlr_renderer.h>
+#include <wlr/types/wlr_compositor.h>
+#include <wlr/types/wlr_cursor.h>
+#include <wlr/types/wlr_cursor_shape_v1.h>
+#include <wlr/types/wlr_data_control_v1.h>
+#include <wlr/types/wlr_data_device.h>
+#include <wlr/types/wlr_drm.h>
+#include <wlr/types/wlr_export_dmabuf_v1.h>
+#include <wlr/types/wlr_fractional_scale_v1.h>
+#include <wlr/types/wlr_gamma_control_v1.h>
+#include <wlr/types/wlr_idle_inhibit_v1.h>
+#include <wlr/types/wlr_idle_notify_v1.h>
+#include <wlr/types/wlr_input_device.h>
+#include <wlr/types/wlr_keyboard.h>
+#include <wlr/types/wlr_keyboard_group.h>
+#include <wlr/types/wlr_layer_shell_v1.h>
+#include <wlr/types/wlr_linux_dmabuf_v1.h>
+#include <wlr/types/wlr_output.h>
+#include <wlr/types/wlr_output_layout.h>
+#include <wlr/types/wlr_output_management_v1.h>
+#include <wlr/types/wlr_pointer.h>
+#include <wlr/types/wlr_pointer_constraints_v1.h>
+#include <wlr/types/wlr_presentation_time.h>
+#include <wlr/types/wlr_primary_selection.h>
+#include <wlr/types/wlr_primary_selection_v1.h>
+#include <wlr/types/wlr_relative_pointer_v1.h>
+#include <wlr/types/wlr_scene.h>
+#include <wlr/types/wlr_screencopy_v1.h>
+#include <wlr/types/wlr_seat.h>
+#include <wlr/types/wlr_server_decoration.h>
+#include <wlr/types/wlr_session_lock_v1.h>
+#include <wlr/types/wlr_single_pixel_buffer_v1.h>
+#include <wlr/types/wlr_subcompositor.h>
+#include <wlr/types/wlr_viewporter.h>
+#include <wlr/types/wlr_virtual_keyboard_v1.h>
+#include <wlr/types/wlr_virtual_pointer_v1.h>
+#include <wlr/types/wlr_xcursor_manager.h>
+#include <wlr/types/wlr_xdg_activation_v1.h>
+#include <wlr/types/wlr_xdg_decoration_v1.h>
+#include <wlr/types/wlr_xdg_output_v1.h>
+#include <wlr/types/wlr_xdg_shell.h>
+#include <wlr/util/log.h>
+#include <wlr/util/region.h>
+#include <xkbcommon/xkbcommon.h>
+#ifdef XWAYLAND
+#include <wlr/xwayland.h>
+#include <xcb/xcb.h>
+#include <xcb/xcb_icccm.h>
+#endif
+
+#include "dwl-ipc-unstable-v2-protocol.h"
+#include "util.h"
+
+/* macros */
+#define MAX(A, B) ((A) > (B) ? (A) : (B))
+#define MIN(A, B) ((A) < (B) ? (A) : (B))
+#define ROUND(X) ((int)((X < 0) ? (X - 0.5) : (X + 0.5)))
+#define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS)
+#define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]))
+#define LENGTH(X) (sizeof X / sizeof X[0])
+#define END(A) ((A) + LENGTH(A))
+#define TAGMASK ((1u << TAGCOUNT) - 1)
+#define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L)))
+#define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0)
+
+/* enums */
+enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
+enum { XDGShell, LayerShell, X11 }; /* client types */
+enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrFS, LyrTop, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */
+#ifdef XWAYLAND
+enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar,
+ NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */
+#endif
+
+typedef union {
+ int i;
+ uint32_t ui;
+ float f;
+ const void *v;
+} Arg;
+
+typedef struct {
+ unsigned int mod;
+ unsigned int button;
+ void (*func)(const Arg *);
+ const Arg arg;
+} Button;
+
+typedef struct Monitor Monitor;
+typedef struct Client Client;
+struct Client {
+ /* Must keep these three elements in this order */
+ unsigned int type; /* XDGShell or X11* */
+ struct wlr_box geom; /* layout-relative, includes border */
+ Monitor *mon;
+ struct wlr_scene_tree *scene;
+ struct wlr_scene_rect *border[4]; /* top, bottom, left, right */
+ struct wlr_scene_tree *scene_surface;
+ struct wl_list link;
+ struct wl_list flink;
+ union {
+ struct wlr_xdg_surface *xdg;
+ struct wlr_xwayland_surface *xwayland;
+ } surface;
+ struct wlr_xdg_toplevel_decoration_v1 *decoration;
+ struct wl_listener commit;
+ struct wl_listener map;
+ struct wl_listener maximize;
+ struct wl_listener unmap;
+ struct wl_listener destroy;
+ struct wl_listener set_title;
+ struct wl_listener fullscreen;
+ struct wl_listener set_decoration_mode;
+ struct wl_listener destroy_decoration;
+ struct wlr_box prev; /* layout-relative, includes border */
+ struct wlr_box bounds;
+#ifdef XWAYLAND
+ struct wl_listener activate;
+ struct wl_listener associate;
+ struct wl_listener dissociate;
+ struct wl_listener configure;
+ struct wl_listener set_hints;
+#endif
+ unsigned int bw;
+ uint32_t tags;
+ int isfloating, isurgent, isfullscreen, isterm, noswallow;
+ uint32_t resize; /* configure serial of a pending resize */
+ pid_t pid;
+ Client *swallowing, *swallowedby;
+};
+
+typedef struct {
+ struct wl_list link;
+ struct wl_resource *resource;
+ Monitor *mon;
+} DwlIpcOutput;
+
+typedef struct {
+ uint32_t mod;
+ xkb_keysym_t keysym;
+ void (*func)(const Arg *);
+ const Arg arg;
+} Key;
+
+typedef struct {
+ struct wl_list link;
+ struct wlr_keyboard_group *wlr_group;
+
+ int nsyms;
+ const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */
+ uint32_t mods; /* invalid if nsyms == 0 */
+ struct wl_event_source *key_repeat_source;
+
+ struct wl_listener modifiers;
+ struct wl_listener key;
+} KeyboardGroup;
+
+typedef struct {
+ /* Must keep these three elements in this order */
+ unsigned int type; /* LayerShell */
+ struct wlr_box geom;
+ Monitor *mon;
+ struct wlr_scene_tree *scene;
+ struct wlr_scene_tree *popups;
+ struct wlr_scene_layer_surface_v1 *scene_layer;
+ struct wl_list link;
+ int mapped;
+ struct wlr_layer_surface_v1 *layer_surface;
+
+ struct wl_listener destroy;
+ struct wl_listener map;
+ struct wl_listener unmap;
+ struct wl_listener surface_commit;
+} LayerSurface;
+
+typedef struct {
+ const char *symbol;
+ void (*arrange)(Monitor *);
+} Layout;
+
+struct Monitor {
+ struct wl_list link;
+ struct wl_list dwl_ipc_outputs;
+ struct wlr_output *wlr_output;
+ struct wlr_scene_output *scene_output;
+ struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */
+ struct wl_listener frame;
+ struct wl_listener destroy;
+ struct wl_listener request_state;
+ struct wl_listener destroy_lock_surface;
+ struct wlr_session_lock_surface_v1 *lock_surface;
+ struct wlr_box m; /* monitor area, layout-relative */
+ struct wlr_box w; /* window area, layout-relative */
+ struct wl_list layers[4]; /* LayerSurface.link */
+ const Layout *lt[2];
+ unsigned int seltags;
+ unsigned int sellt;
+ uint32_t tagset[2];
+ float mfact;
+ int gamma_lut_changed;
+ int nmaster;
+ char ltsymbol[16];
+};
+
+typedef struct {
+ const char *name;
+ float mfact;
+ int nmaster;
+ float scale;
+ const Layout *lt;
+ enum wl_output_transform rr;
+ int x, y;
+} MonitorRule;
+
+typedef struct {
+ struct wlr_pointer_constraint_v1 *constraint;
+ struct wl_listener destroy;
+} PointerConstraint;
+
+typedef struct {
+ const char *id;
+ const char *title;
+ uint32_t tags;
+ int isfloating;
+ int isterm;
+ int noswallow;
+ int monitor;
+} Rule;
+
+typedef struct {
+ struct wlr_scene_tree *scene;
+
+ struct wlr_session_lock_v1 *lock;
+ struct wl_listener new_surface;
+ struct wl_listener unlock;
+ struct wl_listener destroy;
+} SessionLock;
+
+/* function declarations */
+static void applybounds(Client *c, struct wlr_box *bbox);
+static void applyrules(Client *c);
+static void arrange(Monitor *m);
+static void arrangelayer(Monitor *m, struct wl_list *list,
+ struct wlr_box *usable_area, int exclusive);
+static void arrangelayers(Monitor *m);
+static void axisnotify(struct wl_listener *listener, void *data);
+static void buttonpress(struct wl_listener *listener, void *data);
+static void centeredmaster(Monitor *m);
+static void chvt(const Arg *arg);
+static void checkidleinhibitor(struct wlr_surface *exclude);
+static void cleanup(void);
+static void cleanupmon(struct wl_listener *listener, void *data);
+static void closemon(Monitor *m);
+static void commitlayersurfacenotify(struct wl_listener *listener, void *data);
+static void commitnotify(struct wl_listener *listener, void *data);
+static void createdecoration(struct wl_listener *listener, void *data);
+static void createidleinhibitor(struct wl_listener *listener, void *data);
+static void createkeyboard(struct wlr_keyboard *keyboard);
+static void createlayersurface(struct wl_listener *listener, void *data);
+static void createlocksurface(struct wl_listener *listener, void *data);
+static void createmon(struct wl_listener *listener, void *data);
+static void createnotify(struct wl_listener *listener, void *data);
+static void createpointer(struct wlr_pointer *pointer);
+static void createpointerconstraint(struct wl_listener *listener, void *data);
+static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint);
+static void cursorframe(struct wl_listener *listener, void *data);
+static void cursorwarptohint(void);
+static void destroydecoration(struct wl_listener *listener, void *data);
+static void destroydragicon(struct wl_listener *listener, void *data);
+static void destroyidleinhibitor(struct wl_listener *listener, void *data);
+static void destroylayersurfacenotify(struct wl_listener *listener, void *data);
+static void destroylock(SessionLock *lock, int unlocked);
+static void destroylocksurface(struct wl_listener *listener, void *data);
+static void destroynotify(struct wl_listener *listener, void *data);
+static void destroypointerconstraint(struct wl_listener *listener, void *data);
+static void destroysessionlock(struct wl_listener *listener, void *data);
+static void destroysessionmgr(struct wl_listener *listener, void *data);
+static Monitor *dirtomon(enum wlr_direction dir);
+static void dwl_ipc_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id);
+static void dwl_ipc_manager_destroy(struct wl_resource *resource);
+static void dwl_ipc_manager_get_output(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *output);
+static void dwl_ipc_manager_release(struct wl_client *client, struct wl_resource *resource);
+static void dwl_ipc_output_destroy(struct wl_resource *resource);
+static void dwl_ipc_output_printstatus(Monitor *monitor);
+static void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output);
+static void dwl_ipc_output_set_client_tags(struct wl_client *client, struct wl_resource *resource, uint32_t and_tags, uint32_t xor_tags);
+static void dwl_ipc_output_set_layout(struct wl_client *client, struct wl_resource *resource, uint32_t index);
+static void dwl_ipc_output_set_tags(struct wl_client *client, struct wl_resource *resource, uint32_t tagmask, uint32_t toggle_tagset);
+static void dwl_ipc_output_release(struct wl_client *client, struct wl_resource *resource);
+static void focusclient(Client *c, int lift);
+static void focusmon(const Arg *arg);
+static void focusstack(const Arg *arg);
+static Client *focustop(Monitor *m);
+static void fullscreennotify(struct wl_listener *listener, void *data);
+static void handlesig(int signo);
+static void incnmaster(const Arg *arg);
+static void inputdevice(struct wl_listener *listener, void *data);
+static int keybinding(uint32_t mods, xkb_keysym_t sym);
+static void keypress(struct wl_listener *listener, void *data);
+static void keypressmod(struct wl_listener *listener, void *data);
+static int keyrepeat(void *data);
+static void killclient(const Arg *arg);
+static void locksession(struct wl_listener *listener, void *data);
+static void maplayersurfacenotify(struct wl_listener *listener, void *data);
+static void mapnotify(struct wl_listener *listener, void *data);
+static void maximizenotify(struct wl_listener *listener, void *data);
+static void monocle(Monitor *m);
+static void movestack(const Arg *arg);
+static void motionabsolute(struct wl_listener *listener, void *data);
+static void motionnotify(uint32_t time, struct wlr_input_device *device, double sx,
+ double sy, double sx_unaccel, double sy_unaccel);
+static void motionrelative(struct wl_listener *listener, void *data);
+static void moveresize(const Arg *arg);
+static void outputmgrapply(struct wl_listener *listener, void *data);
+static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test);
+static void outputmgrtest(struct wl_listener *listener, void *data);
+static void pointerfocus(Client *c, struct wlr_surface *surface,
+ double sx, double sy, uint32_t time);
+static void printstatus(void);
+static void quit(const Arg *arg);
+static void rendermon(struct wl_listener *listener, void *data);
+static void requestdecorationmode(struct wl_listener *listener, void *data);
+static void requeststartdrag(struct wl_listener *listener, void *data);
+static void requestmonstate(struct wl_listener *listener, void *data);
+static void resize(Client *c, struct wlr_box geo, int interact);
+static void run(char *startup_cmd);
+static void setcursor(struct wl_listener *listener, void *data);
+static void setcursorshape(struct wl_listener *listener, void *data);
+static void setfloating(Client *c, int floating);
+static void setfullscreen(Client *c, int fullscreen);
+static void setgamma(struct wl_listener *listener, void *data);
+static void setlayout(const Arg *arg);
+static void setmfact(const Arg *arg);
+static void setmon(Client *c, Monitor *m, uint32_t newtags);
+static void setpsel(struct wl_listener *listener, void *data);
+static void setsel(struct wl_listener *listener, void *data);
+static void setup(void);
+static void spawn(const Arg *arg);
+static void startdrag(struct wl_listener *listener, void *data);
+static void tag(const Arg *arg);
+static void tagmon(const Arg *arg);
+static void tile(Monitor *m);
+static void togglebar(const Arg *arg);
+static void togglefloating(const Arg *arg);
+static void togglefullscreen(const Arg *arg);
+static void toggletag(const Arg *arg);
+static void toggleview(const Arg *arg);
+static void unlocksession(struct wl_listener *listener, void *data);
+static void unmaplayersurfacenotify(struct wl_listener *listener, void *data);
+static void unmapnotify(struct wl_listener *listener, void *data);
+static void updatemons(struct wl_listener *listener, void *data);
+static void updatetitle(struct wl_listener *listener, void *data);
+static void urgent(struct wl_listener *listener, void *data);
+static void view(const Arg *arg);
+static void virtualkeyboard(struct wl_listener *listener, void *data);
+static void virtualpointer(struct wl_listener *listener, void *data);
+static Monitor *xytomon(double x, double y);
+static void xytonode(double x, double y, struct wlr_surface **psurface,
+ Client **pc, LayerSurface **pl, double *nx, double *ny);
+static void zoom(const Arg *arg);
+static pid_t getparentprocess(pid_t p);
+static int isdescprocess(pid_t p, pid_t c);
+static Client *termforwin(Client *w);
+static void swallow(Client *c, Client *w);
+
+/* variables */
+static const char broken[] = "broken";
+static pid_t child_pid = -1;
+static int locked;
+static void *exclusive_focus;
+static struct wl_display *dpy;
+static struct wlr_backend *backend;
+static struct wlr_scene *scene;
+static struct wlr_scene_tree *layers[NUM_LAYERS];
+static struct wlr_scene_tree *drag_icon;
+/* Map from ZWLR_LAYER_SHELL_* constants to Lyr* enum */
+static const int layermap[] = { LyrBg, LyrBottom, LyrTop, LyrOverlay };
+static struct wlr_renderer *drw;
+static struct wlr_allocator *alloc;
+static struct wlr_compositor *compositor;
+static struct wlr_session *session;
+
+static struct wlr_xdg_shell *xdg_shell;
+static struct wlr_xdg_activation_v1 *activation;
+static struct wlr_xdg_decoration_manager_v1 *xdg_decoration_mgr;
+static struct wl_list clients; /* tiling order */
+static struct wl_list fstack; /* focus order */
+static struct wlr_idle_notifier_v1 *idle_notifier;
+static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr;
+static struct wlr_layer_shell_v1 *layer_shell;
+static struct wlr_output_manager_v1 *output_mgr;
+static struct wlr_gamma_control_manager_v1 *gamma_control_mgr;
+static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr;
+static struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr;
+static struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr;
+
+static struct wlr_pointer_constraints_v1 *pointer_constraints;
+static struct wlr_relative_pointer_manager_v1 *relative_pointer_mgr;
+static struct wlr_pointer_constraint_v1 *active_constraint;
+
+static struct wlr_cursor *cursor;
+static struct wlr_xcursor_manager *cursor_mgr;
+
+static struct wlr_scene_rect *root_bg;
+static struct wlr_session_lock_manager_v1 *session_lock_mgr;
+static struct wlr_scene_rect *locked_bg;
+static struct wlr_session_lock_v1 *cur_lock;
+static struct wl_listener lock_listener = {.notify = locksession};
+
+static struct wlr_seat *seat;
+static KeyboardGroup kb_group = {0};
+static KeyboardGroup vkb_group = {0};
+static struct wlr_surface *held_grab;
+static unsigned int cursor_mode;
+static Client *grabc;
+static int grabcx, grabcy; /* client-relative */
+
+static struct wlr_output_layout *output_layout;
+static struct wlr_box sgeom;
+static struct wl_list mons;
+static Monitor *selmon;
+
+static struct zdwl_ipc_manager_v2_interface dwl_manager_implementation = {.release = dwl_ipc_manager_release, .get_output = dwl_ipc_manager_get_output};
+static struct zdwl_ipc_output_v2_interface dwl_output_implementation = {.release = dwl_ipc_output_release, .set_tags = dwl_ipc_output_set_tags, .set_layout = dwl_ipc_output_set_layout, .set_client_tags = dwl_ipc_output_set_client_tags};
+
+#ifdef XWAYLAND
+static void activatex11(struct wl_listener *listener, void *data);
+static void associatex11(struct wl_listener *listener, void *data);
+static void configurex11(struct wl_listener *listener, void *data);
+static void createnotifyx11(struct wl_listener *listener, void *data);
+static void dissociatex11(struct wl_listener *listener, void *data);
+static xcb_atom_t getatom(xcb_connection_t *xc, const char *name);
+static void sethints(struct wl_listener *listener, void *data);
+static void xwaylandready(struct wl_listener *listener, void *data);
+static struct wlr_xwayland *xwayland;
+static xcb_atom_t netatom[NetLast];
+#endif
+
+/* configuration, allows nested code to access above variables */
+#include "config.h"
+#include "device.h"
+
+/* attempt to encapsulate suck into one file */
+#include "client.h"
+
+/* function implementations */
+void
+applybounds(Client *c, struct wlr_box *bbox)
+{
+ /* set minimum possible */
+ c->geom.width = MAX(1 + 2 * (int)c->bw, c->geom.width);
+ c->geom.height = MAX(1 + 2 * (int)c->bw, c->geom.height);
+
+ if (c->geom.x >= bbox->x + bbox->width)
+ c->geom.x = bbox->x + bbox->width - c->geom.width;
+ if (c->geom.y >= bbox->y + bbox->height)
+ c->geom.y = bbox->y + bbox->height - c->geom.height;
+ if (c->geom.x + c->geom.width + 2 * (int)c->bw <= bbox->x)
+ c->geom.x = bbox->x;
+ if (c->geom.y + c->geom.height + 2 * (int)c->bw <= bbox->y)
+ c->geom.y = bbox->y;
+}
+
+void
+applyrules(Client *c)
+{
+ /* rule matching */
+ const char *appid, *title;
+ uint32_t newtags = 0;
+ int i;
+ const Rule *r;
+ Monitor *mon = selmon, *m;
+
+ c->isfloating = client_is_float_type(c);
+ if (!(appid = client_get_appid(c)))
+ appid = broken;
+ if (!(title = client_get_title(c)))
+ title = broken;
+
+ c->pid = client_get_pid(c);
+
+ for (r = rules; r < END(rules); r++) {
+ if ((!r->title || strstr(title, r->title))
+ && (!r->id || strstr(appid, r->id))) {
+ c->isfloating = r->isfloating;
+ c->isterm = r->isterm;
+ c->noswallow = r->noswallow;
+ newtags |= r->tags;
+ i = 0;
+ wl_list_for_each(m, &mons, link) {
+ if (r->monitor == i++)
+ mon = m;
+ }
+ }
+ }
+
+ if (!c->noswallow && !client_is_float_type(c)) {
+ Client *p = termforwin(c);
+ if (p) {
+ c->swallowedby = p;
+ p->swallowing = c;
+ wl_list_remove(&c->link);
+ wl_list_remove(&c->flink);
+ swallow(c,p);
+ wl_list_remove(&p->link);
+ wl_list_remove(&p->flink);
+ mon = p->mon;
+ newtags = p->tags;
+ }
+ }
+ setmon(c, mon, newtags);
+}
+
+void
+arrange(Monitor *m)
+{
+ Client *c;
+
+ if (!m->wlr_output->enabled)
+ return;
+
+ wl_list_for_each(c, &clients, link) {
+ if (c->mon == m) {
+ wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m));
+ client_set_suspended(c, !VISIBLEON(c, m));
+ }
+ }
+
+ wlr_scene_node_set_enabled(&m->fullscreen_bg->node,
+ (c = focustop(m)) && c->isfullscreen);
+
+ strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol));
+
+ if (m->lt[m->sellt]->arrange)
+ m->lt[m->sellt]->arrange(m);
+ motionnotify(0, NULL, 0, 0, 0, 0);
+ checkidleinhibitor(NULL);
+}
+
+void
+arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int exclusive)
+{
+ LayerSurface *l;
+ struct wlr_box full_area = m->m;
+
+ wl_list_for_each(l, list, link) {
+ struct wlr_layer_surface_v1 *layer_surface = l->layer_surface;
+
+ if (exclusive != (layer_surface->current.exclusive_zone > 0))
+ continue;
+
+ wlr_scene_layer_surface_v1_configure(l->scene_layer, &full_area, usable_area);
+ wlr_scene_node_set_position(&l->popups->node, l->scene->node.x, l->scene->node.y);
+ l->geom.x = l->scene->node.x;
+ l->geom.y = l->scene->node.y;
+ }
+}
+
+void
+arrangelayers(Monitor *m)
+{
+ int i;
+ struct wlr_box usable_area = m->m;
+ LayerSurface *l;
+ uint32_t layers_above_shell[] = {
+ ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY,
+ ZWLR_LAYER_SHELL_V1_LAYER_TOP,
+ };
+ if (!m->wlr_output->enabled)
+ return;
+
+ /* Arrange exclusive surfaces from top->bottom */
+ for (i = 3; i >= 0; i--)
+ arrangelayer(m, &m->layers[i], &usable_area, 1);
+
+ if (!wlr_box_equal(&usable_area, &m->w)) {
+ m->w = usable_area;
+ arrange(m);
+ }
+
+ /* Arrange non-exlusive surfaces from top->bottom */
+ for (i = 3; i >= 0; i--)
+ arrangelayer(m, &m->layers[i], &usable_area, 0);
+
+ /* Find topmost keyboard interactive layer, if such a layer exists */
+ for (i = 0; i < (int)LENGTH(layers_above_shell); i++) {
+ wl_list_for_each_reverse(l, &m->layers[layers_above_shell[i]], link) {
+ if (locked || !l->layer_surface->current.keyboard_interactive || !l->mapped)
+ continue;
+ /* Deactivate the focused client. */
+ focusclient(NULL, 0);
+ exclusive_focus = l;
+ client_notify_enter(l->layer_surface->surface, wlr_seat_get_keyboard(seat));
+ return;
+ }
+ }
+}
+
+void
+axisnotify(struct wl_listener *listener, void *data)
+{
+ /* This event is forwarded by the cursor when a pointer emits an axis event,
+ * for example when you move the scroll wheel. */
+ struct wlr_pointer_axis_event *event = data;
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
+ /* TODO: allow usage of scroll whell for mousebindings, it can be implemented
+ * checking the event's orientation and the delta of the event */
+ /* Notify the client with pointer focus of the axis event. */
+ wlr_seat_pointer_notify_axis(seat,
+ event->time_msec, event->orientation, event->delta,
+ event->delta_discrete, event->source);
+}
+
+void
+buttonpress(struct wl_listener *listener, void *data)
+{
+ struct wlr_pointer_button_event *event = data;
+ struct wlr_keyboard *keyboard;
+ uint32_t mods;
+ Client *c;
+ const Button *b;
+
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
+
+ switch (event->state) {
+ case WLR_BUTTON_PRESSED:
+ cursor_mode = CurPressed;
+ held_grab = seat->pointer_state.focused_surface;
+ if (locked)
+ break;
+
+ /* Change focus if the button was _pressed_ over a client */
+ xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL);
+ if (c && (!client_is_unmanaged(c) || client_wants_focus(c)))
+ focusclient(c, 1);
+
+ keyboard = wlr_seat_get_keyboard(seat);
+ mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
+ for (b = buttons; b < END(buttons); b++) {
+ if (CLEANMASK(mods) == CLEANMASK(b->mod) &&
+ event->button == b->button && b->func) {
+ b->func(&b->arg);
+ return;
+ }
+ }
+ break;
+ case WLR_BUTTON_RELEASED:
+ held_grab = NULL;
+ /* If you released any buttons, we exit interactive move/resize mode. */
+ /* TODO should reset to the pointer focus's current setcursor */
+ if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
+ cursor_mode = CurNormal;
+ /* Drop the window off on its new monitor */
+ selmon = xytomon(cursor->x, cursor->y);
+ setmon(grabc, selmon, 0);
+ return;
+ } else {
+ cursor_mode = CurNormal;
+ }
+ break;
+ }
+ /* If the event wasn't handled by the compositor, notify the client with
+ * pointer focus that a button press has occurred */
+ wlr_seat_pointer_notify_button(seat,
+ event->time_msec, event->button, event->state);
+}
+
+void
+centeredmaster(Monitor *m)
+{
+ int i, n, h, mw, mx, my, oty, ety, tw;
+ Client *c;
+
+ n = 0;
+ wl_list_for_each(c, &clients, link)
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
+ n++;
+ if (n == 0)
+ return;
+
+ /* initialize areas */
+ mw = m->w.width;
+ mx = 0;
+ my = 0;
+ tw = mw;
+
+ if (n > m->nmaster) {
+ /* go mfact box in the center if more than nmaster clients */
+ mw = m->nmaster ? (int) (m->w.width * m->mfact) : 0;
+ tw = m->w.width - mw;
+
+ if (n - m->nmaster > 1) {
+ /* only one client */
+ mx = (m->w.width - mw) / 2;
+ tw = (m->w.width - mw) / 2;
+ }
+ }
+
+ i = 0;
+ oty = 0;
+ ety = 0;
+ wl_list_for_each(c, &clients, link) {
+ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
+ continue;
+ if (i < m->nmaster) {
+ /* nmaster clients are stacked vertically, in the center
+ * of the screen */
+ h = (m->w.height - my) / (MIN(n, m->nmaster) - i);
+ resize(c, (struct wlr_box){.x = m->w.x + mx, .y = m->w.y + my, .width = mw,
+ .height = h}, 0);
+ my += c->geom.height;
+ } else {
+ /* stack clients are stacked vertically */
+ if ((i - m->nmaster) % 2) {
+ h = (m->w.height - ety) / ( (1 + n - i) / 2);
+ resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + ety, .width = tw,
+ .height = h}, 0);
+ ety += c->geom.height;
+ } else {
+ h = (m->w.height - oty) / ((1 + n - i) / 2);
+ resize(c, (struct wlr_box){.x = m->w.x + mx + mw, .y = m->w.y + oty, .width = tw,
+ .height = h}, 0);
+ oty += c->geom.height;
+ }
+ }
+ i++;
+ }
+}
+
+void
+chvt(const Arg *arg)
+{
+ wlr_session_change_vt(session, arg->ui);
+}
+
+void
+checkidleinhibitor(struct wlr_surface *exclude)
+{
+ int inhibited = 0, unused_lx, unused_ly;
+ struct wlr_idle_inhibitor_v1 *inhibitor;
+ wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) {
+ struct wlr_surface *surface = wlr_surface_get_root_surface(inhibitor->surface);
+ struct wlr_scene_tree *tree = surface->data;
+ if (exclude != surface && (bypass_surface_visibility || (!tree
+ || wlr_scene_node_coords(&tree->node, &unused_lx, &unused_ly)))) {
+ inhibited = 1;
+ break;
+ }
+ }
+
+ wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited);
+}
+
+void
+cleanup(void)
+{
+#ifdef XWAYLAND
+ wlr_xwayland_destroy(xwayland);
+ xwayland = NULL;
+#endif
+ wl_display_destroy_clients(dpy);
+ if (child_pid > 0) {
+ kill(child_pid, SIGTERM);
+ waitpid(child_pid, NULL, 0);
+ }
+ wlr_xcursor_manager_destroy(cursor_mgr);
+ wlr_output_layout_destroy(output_layout);
+
+ /* Remove event source that use the dpy event loop before destroying dpy */
+ wl_event_source_remove(kb_group.key_repeat_source);
+ wl_event_source_remove(vkb_group.key_repeat_source);
+
+ wl_display_destroy(dpy);
+ /* Destroy after the wayland display (when the monitors are already destroyed)
+ to avoid destroying them with an invalid scene output. */
+ wlr_scene_node_destroy(&scene->tree.node);
+}
+
+void
+cleanupmon(struct wl_listener *listener, void *data)
+{
+ Monitor *m = wl_container_of(listener, m, destroy);
+ LayerSurface *l, *tmp;
+ size_t i;
+
+ DwlIpcOutput *ipc_output, *ipc_output_tmp;
+ wl_list_for_each_safe(ipc_output, ipc_output_tmp, &m->dwl_ipc_outputs, link)
+ wl_resource_destroy(ipc_output->resource);
+
+ /* m->layers[i] are intentionally not unlinked */
+ for (i = 0; i < LENGTH(m->layers); i++) {
+ wl_list_for_each_safe(l, tmp, &m->layers[i], link)
+ wlr_layer_surface_v1_destroy(l->layer_surface);
+ }
+
+ wl_list_remove(&m->destroy.link);
+ wl_list_remove(&m->frame.link);
+ wl_list_remove(&m->link);
+ wl_list_remove(&m->request_state.link);
+ m->wlr_output->data = NULL;
+ wlr_output_layout_remove(output_layout, m->wlr_output);
+ wlr_scene_output_destroy(m->scene_output);
+
+ closemon(m);
+ wlr_scene_node_destroy(&m->fullscreen_bg->node);
+ free(m);
+}
+
+void
+closemon(Monitor *m)
+{
+ /* update selmon if needed and
+ * move closed monitor's clients to the focused one */
+ Client *c;
+ int i = 0, nmons = wl_list_length(&mons);
+ if (!nmons) {
+ selmon = NULL;
+ } else if (m == selmon) {
+ do /* don't switch to disabled mons */
+ selmon = wl_container_of(mons.next, selmon, link);
+ while (!selmon->wlr_output->enabled && i++ < nmons);
+ }
+
+ wl_list_for_each(c, &clients, link) {
+ if (c->isfloating && c->geom.x > m->m.width)
+ resize(c, (struct wlr_box){.x = c->geom.x - m->w.width, .y = c->geom.y,
+ .width = c->geom.width, .height = c->geom.height}, 0);
+ if (c->mon == m)
+ setmon(c, selmon, c->tags);
+ }
+ focusclient(focustop(selmon), 1);
+ printstatus();
+}
+
+void
+commitlayersurfacenotify(struct wl_listener *listener, void *data)
+{
+ LayerSurface *l = wl_container_of(listener, l, surface_commit);
+ struct wlr_layer_surface_v1 *layer_surface = l->layer_surface;
+ struct wlr_scene_tree *scene_layer = layers[layermap[layer_surface->current.layer]];
+
+ if (layer_surface->current.committed == 0 && l->mapped == layer_surface->surface->mapped)
+ return;
+ l->mapped = layer_surface->surface->mapped;
+
+ if (scene_layer != l->scene->node.parent) {
+ wlr_scene_node_reparent(&l->scene->node, scene_layer);
+ wl_list_remove(&l->link);
+ wl_list_insert(&l->mon->layers[layer_surface->current.layer], &l->link);
+ wlr_scene_node_reparent(&l->popups->node, (layer_surface->current.layer
+ < ZWLR_LAYER_SHELL_V1_LAYER_TOP ? layers[LyrTop] : scene_layer));
+ }
+
+ arrangelayers(l->mon);
+}
+
+void
+commitnotify(struct wl_listener *listener, void *data)
+{
+ Client *c = wl_container_of(listener, c, commit);
+
+ if (client_surface(c)->mapped && c->mon)
+ resize(c, c->geom, (c->isfloating && !c->isfullscreen));
+
+ /* mark a pending resize as completed */
+ if (c->resize && c->resize <= c->surface.xdg->current.configure_serial)
+ c->resize = 0;
+}
+
+void
+createdecoration(struct wl_listener *listener, void *data)
+{
+ struct wlr_xdg_toplevel_decoration_v1 *deco = data;
+ Client *c = deco->toplevel->base->data;
+ c->decoration = deco;
+
+ LISTEN(&deco->events.request_mode, &c->set_decoration_mode, requestdecorationmode);
+ LISTEN(&deco->events.destroy, &c->destroy_decoration, destroydecoration);
+
+ requestdecorationmode(&c->set_decoration_mode, deco);
+}
+
+void
+createidleinhibitor(struct wl_listener *listener, void *data)
+{
+ struct wlr_idle_inhibitor_v1 *idle_inhibitor = data;
+ LISTEN_STATIC(&idle_inhibitor->events.destroy, destroyidleinhibitor);
+
+ checkidleinhibitor(NULL);
+}
+
+void
+createkeyboard(struct wlr_keyboard *keyboard)
+{
+ /* Set the keymap to match the group keymap */
+ wlr_keyboard_set_keymap(keyboard, kb_group.wlr_group->keyboard.keymap);
+ wlr_keyboard_set_repeat_info(keyboard, repeat_rate, repeat_delay);
+
+ /* Add the new keyboard to the group */
+ wlr_keyboard_group_add_keyboard(kb_group.wlr_group, keyboard);
+}
+
+void
+createlayersurface(struct wl_listener *listener, void *data)
+{
+ struct wlr_layer_surface_v1 *layer_surface = data;
+ LayerSurface *l;
+ struct wlr_surface *surface = layer_surface->surface;
+ struct wlr_scene_tree *scene_layer = layers[layermap[layer_surface->pending.layer]];
+ struct wlr_layer_surface_v1_state old_state;
+
+ if (!layer_surface->output
+ && !(layer_surface->output = selmon ? selmon->wlr_output : NULL)) {
+ wlr_layer_surface_v1_destroy(layer_surface);
+ return;
+ }
+
+ l = layer_surface->data = ecalloc(1, sizeof(*l));
+ l->type = LayerShell;
+ LISTEN(&surface->events.commit, &l->surface_commit, commitlayersurfacenotify);
+ LISTEN(&surface->events.map, &l->map, maplayersurfacenotify);
+ LISTEN(&surface->events.unmap, &l->unmap, unmaplayersurfacenotify);
+ LISTEN(&layer_surface->events.destroy, &l->destroy, destroylayersurfacenotify);
+
+ l->layer_surface = layer_surface;
+ l->mon = layer_surface->output->data;
+ l->scene_layer = wlr_scene_layer_surface_v1_create(scene_layer, layer_surface);
+ l->scene = l->scene_layer->tree;
+ l->popups = surface->data = wlr_scene_tree_create(layer_surface->current.layer
+ < ZWLR_LAYER_SHELL_V1_LAYER_TOP ? layers[LyrTop] : scene_layer);
+ l->scene->node.data = l->popups->node.data = l;
+
+ wl_list_insert(&l->mon->layers[layer_surface->pending.layer],&l->link);
+ wlr_surface_send_enter(surface, layer_surface->output);
+
+ /* Temporarily set the layer's current state to pending
+ * so that we can easily arrange it
+ */
+ old_state = layer_surface->current;
+ layer_surface->current = layer_surface->pending;
+ l->mapped = 1;
+ arrangelayers(l->mon);
+ layer_surface->current = old_state;
+}
+
+void
+createlocksurface(struct wl_listener *listener, void *data)
+{
+ SessionLock *lock = wl_container_of(listener, lock, new_surface);
+ struct wlr_session_lock_surface_v1 *lock_surface = data;
+ Monitor *m = lock_surface->output->data;
+ struct wlr_scene_tree *scene_tree = lock_surface->surface->data
+ = wlr_scene_subsurface_tree_create(lock->scene, lock_surface->surface);
+ m->lock_surface = lock_surface;
+
+ wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y);
+ wlr_session_lock_surface_v1_configure(lock_surface, m->m.width, m->m.height);
+
+ LISTEN(&lock_surface->events.destroy, &m->destroy_lock_surface, destroylocksurface);
+
+ if (m == selmon)
+ client_notify_enter(lock_surface->surface, wlr_seat_get_keyboard(seat));
+}
+
+void
+createmon(struct wl_listener *listener, void *data)
+{
+ /* This event is raised by the backend when a new output (aka a display or
+ * monitor) becomes available. */
+ struct wlr_output *wlr_output = data;
+ const MonitorRule *r;
+ size_t i;
+ struct wlr_output_state state;
+ Monitor *m;
+
+ if (!wlr_output_init_render(wlr_output, alloc, drw))
+ return;
+
+ m = wlr_output->data = ecalloc(1, sizeof(*m));
+ m->wlr_output = wlr_output;
+
+ wl_list_init(&m->dwl_ipc_outputs);
+
+ for (i = 0; i < LENGTH(m->layers); i++)
+ wl_list_init(&m->layers[i]);
+
+ wlr_output_state_init(&state);
+ /* Initialize monitor state using configured rules */
+ m->tagset[0] = m->tagset[1] = 1;
+ for (r = monrules; r < END(monrules); r++) {
+ if (!r->name || strstr(wlr_output->name, r->name)) {
+ m->m.x = r->x;
+ m->m.y = r->y;
+ m->mfact = r->mfact;
+ m->nmaster = r->nmaster;
+ m->lt[0] = r->lt;
+ m->lt[1] = &layouts[LENGTH(layouts) > 1 && r->lt != &layouts[1]];
+ strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol));
+ wlr_output_state_set_scale(&state, r->scale);
+ wlr_output_state_set_transform(&state, r->rr);
+ break;
+ }
+ }
+
+ /* The mode is a tuple of (width, height, refresh rate), and each
+ * monitor supports only a specific set of modes. We just pick the
+ * monitor's preferred mode; a more sophisticated compositor would let
+ * the user configure it. */
+ wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output));
+
+ /* Set up event listeners */
+ LISTEN(&wlr_output->events.frame, &m->frame, rendermon);
+ LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon);
+ LISTEN(&wlr_output->events.request_state, &m->request_state, requestmonstate);
+
+ wlr_output_state_set_enabled(&state, 1);
+ wlr_output_commit_state(wlr_output, &state);
+ wlr_output_state_finish(&state);
+
+ wl_list_insert(&mons, &m->link);
+ printstatus();
+
+ /* The xdg-protocol specifies:
+ *
+ * If the fullscreened surface is not opaque, the compositor must make
+ * sure that other screen content not part of the same surface tree (made
+ * up of subsurfaces, popups or similarly coupled surfaces) are not
+ * visible below the fullscreened surface.
+ *
+ */
+ /* updatemons() will resize and set correct position */
+ m->fullscreen_bg = wlr_scene_rect_create(layers[LyrFS], 0, 0, fullscreen_bg);
+ wlr_scene_node_set_enabled(&m->fullscreen_bg->node, 0);
+
+ /* Adds this to the output layout in the order it was configured in.
+ *
+ * The output layout utility automatically adds a wl_output global to the
+ * display, which Wayland clients can see to find out information about the
+ * output (such as DPI, scale factor, manufacturer, etc).
+ */
+ m->scene_output = wlr_scene_output_create(scene, wlr_output);
+ if (m->m.x < 0 || m->m.y < 0)
+ wlr_output_layout_add_auto(output_layout, wlr_output);
+ else
+ wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y);
+}
+
+void
+createnotify(struct wl_listener *listener, void *data)
+{
+ /* This event is raised when wlr_xdg_shell receives a new xdg surface from a
+ * client, either a toplevel (application window) or popup,
+ * or when wlr_layer_shell receives a new popup from a layer.
+ * If you want to do something tricky with popups you should check if
+ * its parent is wlr_xdg_shell or wlr_layer_shell */
+ struct wlr_xdg_surface *xdg_surface = data;
+ Client *c = NULL;
+ LayerSurface *l = NULL;
+
+ if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) {
+ struct wlr_xdg_popup *popup = xdg_surface->popup;
+ struct wlr_box box;
+ if (toplevel_from_wlr_surface(popup->base->surface, &c, &l) < 0)
+ return;
+ popup->base->surface->data = wlr_scene_xdg_surface_create(
+ popup->parent->data, popup->base);
+ if ((l && !l->mon) || (c && !c->mon))
+ return;
+ box = l ? l->mon->m : c->mon->w;
+ box.x -= (l ? l->geom.x : c->geom.x);
+ box.y -= (l ? l->geom.y : c->geom.y);
+ wlr_xdg_popup_unconstrain_from_box(popup, &box);
+ return;
+ } else if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_NONE)
+ return;
+
+ /* Allocate a Client for this surface */
+ c = xdg_surface->data = ecalloc(1, sizeof(*c));
+ c->surface.xdg = xdg_surface;
+ c->bw = borderpx;
+
+ wlr_xdg_toplevel_set_wm_capabilities(xdg_surface->toplevel,
+ WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN);
+
+ LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify);
+ LISTEN(&xdg_surface->surface->events.commit, &c->commit, commitnotify);
+ LISTEN(&xdg_surface->surface->events.map, &c->map, mapnotify);
+ LISTEN(&xdg_surface->surface->events.unmap, &c->unmap, unmapnotify);
+ LISTEN(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen,
+ fullscreennotify);
+ LISTEN(&xdg_surface->toplevel->events.request_maximize, &c->maximize,
+ maximizenotify);
+ LISTEN(&xdg_surface->toplevel->events.set_title, &c->set_title, updatetitle);
+}
+
+void
+createpointer(struct wlr_pointer *pointer)
+{
+ struct libinput_device *device;
+ if (wlr_input_device_is_libinput(&pointer->base)
+ && (device = wlr_libinput_get_device_handle(&pointer->base))) {
+
+ if (libinput_device_config_tap_get_finger_count(device)) {
+ libinput_device_config_tap_set_enabled(device, tap_to_click);
+ libinput_device_config_tap_set_drag_enabled(device, tap_and_drag);
+ libinput_device_config_tap_set_drag_lock_enabled(device, drag_lock);
+ libinput_device_config_tap_set_button_map(device, button_map);
+ }
+
+ if (libinput_device_config_scroll_has_natural_scroll(device))
+ libinput_device_config_scroll_set_natural_scroll_enabled(device, natural_scrolling);
+
+ if (libinput_device_config_dwt_is_available(device))
+ libinput_device_config_dwt_set_enabled(device, disable_while_typing);
+
+ if (libinput_device_config_left_handed_is_available(device))
+ libinput_device_config_left_handed_set(device, left_handed);
+
+ if (libinput_device_config_middle_emulation_is_available(device))
+ libinput_device_config_middle_emulation_set_enabled(device, middle_button_emulation);
+
+ if (libinput_device_config_scroll_get_methods(device) != LIBINPUT_CONFIG_SCROLL_NO_SCROLL)
+ libinput_device_config_scroll_set_method (device, scroll_method);
+
+ if (libinput_device_config_click_get_methods(device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE)
+ libinput_device_config_click_set_method (device, click_method);
+
+ if (libinput_device_config_send_events_get_modes(device))
+ libinput_device_config_send_events_set_mode(device, send_events_mode);
+
+ if (libinput_device_config_accel_is_available(device)) {
+ libinput_device_config_accel_set_profile(device, accel_profile);
+ libinput_device_config_accel_set_speed(device, accel_speed);
+ }
+ }
+
+ wlr_cursor_attach_input_device(cursor, &pointer->base);
+}
+
+void
+createpointerconstraint(struct wl_listener *listener, void *data)
+{
+ PointerConstraint *pointer_constraint = ecalloc(1, sizeof(*pointer_constraint));
+ pointer_constraint->constraint = data;
+ LISTEN(&pointer_constraint->constraint->events.destroy,
+ &pointer_constraint->destroy, destroypointerconstraint);
+}
+
+void
+cursorconstrain(struct wlr_pointer_constraint_v1 *constraint)
+{
+ if (active_constraint == constraint)
+ return;
+
+ if (active_constraint)
+ wlr_pointer_constraint_v1_send_deactivated(active_constraint);
+
+ active_constraint = constraint;
+ wlr_pointer_constraint_v1_send_activated(constraint);
+}
+
+void
+cursorframe(struct wl_listener *listener, void *data)
+{
+ /* This event is forwarded by the cursor when a pointer emits an frame
+ * event. Frame events are sent after regular pointer events to group
+ * multiple events together. For instance, two axis events may happen at the
+ * same time, in which case a frame event won't be sent in between. */
+ /* Notify the client with pointer focus of the frame event. */
+ wlr_seat_pointer_notify_frame(seat);
+}
+
+void
+cursorwarptohint(void)
+{
+ Client *c = NULL;
+ double sx = active_constraint->current.cursor_hint.x;
+ double sy = active_constraint->current.cursor_hint.y;
+
+ toplevel_from_wlr_surface(active_constraint->surface, &c, NULL);
+ /* TODO: wlroots 0.18: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4478 */
+ if (c && (active_constraint->current.committed & WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT )) {
+ wlr_cursor_warp(cursor, NULL, sx + c->geom.x + c->bw, sy + c->geom.y + c->bw);
+ wlr_seat_pointer_warp(active_constraint->seat, sx, sy);
+ }
+}
+
+void
+destroydecoration(struct wl_listener *listener, void *data)
+{
+ Client *c = wl_container_of(listener, c, destroy_decoration);
+
+ wl_list_remove(&c->destroy_decoration.link);
+ wl_list_remove(&c->set_decoration_mode.link);
+}
+
+void
+destroydragicon(struct wl_listener *listener, void *data)
+{
+ /* Focus enter isn't sent during drag, so refocus the focused node. */
+ focusclient(focustop(selmon), 1);
+ motionnotify(0, NULL, 0, 0, 0, 0);
+}
+
+void
+destroyidleinhibitor(struct wl_listener *listener, void *data)
+{
+ /* `data` is the wlr_surface of the idle inhibitor being destroyed,
+ * at this point the idle inhibitor is still in the list of the manager */
+ checkidleinhibitor(wlr_surface_get_root_surface(data));
+}
+
+void
+destroylayersurfacenotify(struct wl_listener *listener, void *data)
+{
+ LayerSurface *l = wl_container_of(listener, l, destroy);
+
+ wl_list_remove(&l->link);
+ wl_list_remove(&l->destroy.link);
+ wl_list_remove(&l->map.link);
+ wl_list_remove(&l->unmap.link);
+ wl_list_remove(&l->surface_commit.link);
+ wlr_scene_node_destroy(&l->scene->node);
+ wlr_scene_node_destroy(&l->popups->node);
+ free(l);
+}
+
+void
+destroylock(SessionLock *lock, int unlock)
+{
+ wlr_seat_keyboard_notify_clear_focus(seat);
+ if ((locked = !unlock))
+ goto destroy;
+
+ wlr_scene_node_set_enabled(&locked_bg->node, 0);
+
+ focusclient(focustop(selmon), 0);
+ motionnotify(0, NULL, 0, 0, 0, 0);
+
+destroy:
+ wl_list_remove(&lock->new_surface.link);
+ wl_list_remove(&lock->unlock.link);
+ wl_list_remove(&lock->destroy.link);
+
+ wlr_scene_node_destroy(&lock->scene->node);
+ cur_lock = NULL;
+ free(lock);
+}
+
+void
+destroylocksurface(struct wl_listener *listener, void *data)
+{
+ Monitor *m = wl_container_of(listener, m, destroy_lock_surface);
+ struct wlr_session_lock_surface_v1 *surface, *lock_surface = m->lock_surface;
+
+ m->lock_surface = NULL;
+ wl_list_remove(&m->destroy_lock_surface.link);
+
+ if (lock_surface->surface != seat->keyboard_state.focused_surface)
+ return;
+
+ if (locked && cur_lock && !wl_list_empty(&cur_lock->surfaces)) {
+ surface = wl_container_of(cur_lock->surfaces.next, surface, link);
+ client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat));
+ } else if (!locked) {
+ focusclient(focustop(selmon), 1);
+ } else {
+ wlr_seat_keyboard_clear_focus(seat);
+ }
+}
+
+void
+destroynotify(struct wl_listener *listener, void *data)
+{
+ /* Called when the xdg_toplevel is destroyed. */
+ Client *c = wl_container_of(listener, c, destroy);
+ wl_list_remove(&c->destroy.link);
+ wl_list_remove(&c->set_title.link);
+ wl_list_remove(&c->fullscreen.link);
+#ifdef XWAYLAND
+ if (c->type != XDGShell) {
+ wl_list_remove(&c->activate.link);
+ wl_list_remove(&c->associate.link);
+ wl_list_remove(&c->configure.link);
+ wl_list_remove(&c->dissociate.link);
+ wl_list_remove(&c->set_hints.link);
+ } else
+#endif
+ {
+ wl_list_remove(&c->commit.link);
+ wl_list_remove(&c->map.link);
+ wl_list_remove(&c->unmap.link);
+ }
+ free(c);
+}
+
+void
+destroypointerconstraint(struct wl_listener *listener, void *data)
+{
+ PointerConstraint *pointer_constraint = wl_container_of(listener, pointer_constraint, destroy);
+
+ if (active_constraint == pointer_constraint->constraint) {
+ cursorwarptohint();
+ active_constraint = NULL;
+ }
+
+ wl_list_remove(&pointer_constraint->destroy.link);
+ free(pointer_constraint);
+}
+
+void
+destroysessionlock(struct wl_listener *listener, void *data)
+{
+ SessionLock *lock = wl_container_of(listener, lock, destroy);
+ destroylock(lock, 0);
+}
+
+void
+destroysessionmgr(struct wl_listener *listener, void *data)
+{
+ wl_list_remove(&lock_listener.link);
+ wl_list_remove(&listener->link);
+}
+
+Monitor *
+dirtomon(enum wlr_direction dir)
+{
+ struct wlr_output *next;
+ if (!wlr_output_layout_get(output_layout, selmon->wlr_output))
+ return selmon;
+ if ((next = wlr_output_layout_adjacent_output(output_layout,
+ dir, selmon->wlr_output, selmon->m.x, selmon->m.y)))
+ return next->data;
+ if ((next = wlr_output_layout_farthest_output(output_layout,
+ dir ^ (WLR_DIRECTION_LEFT|WLR_DIRECTION_RIGHT),
+ selmon->wlr_output, selmon->m.x, selmon->m.y)))
+ return next->data;
+ return selmon;
+}
+
+void
+dwl_ipc_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+ struct wl_resource *manager_resource = wl_resource_create(client, &zdwl_ipc_manager_v2_interface, version, id);
+ if (!manager_resource) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+ wl_resource_set_implementation(manager_resource, &dwl_manager_implementation, NULL, dwl_ipc_manager_destroy);
+
+ zdwl_ipc_manager_v2_send_tags(manager_resource, TAGCOUNT);
+
+ for (unsigned int i = 0; i < LENGTH(layouts); i++)
+ zdwl_ipc_manager_v2_send_layout(manager_resource, layouts[i].symbol);
+}
+
+void
+dwl_ipc_manager_destroy(struct wl_resource *resource)
+{
+ /* No state to destroy */
+}
+
+void
+dwl_ipc_manager_get_output(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *output)
+{
+ DwlIpcOutput *ipc_output;
+ Monitor *monitor = wlr_output_from_resource(output)->data;
+ struct wl_resource *output_resource = wl_resource_create(client, &zdwl_ipc_output_v2_interface, wl_resource_get_version(resource), id);
+ if (!output_resource)
+ return;
+
+ ipc_output = ecalloc(1, sizeof(*ipc_output));
+ ipc_output->resource = output_resource;
+ ipc_output->mon = monitor;
+ wl_resource_set_implementation(output_resource, &dwl_output_implementation, ipc_output, dwl_ipc_output_destroy);
+ wl_list_insert(&monitor->dwl_ipc_outputs, &ipc_output->link);
+ dwl_ipc_output_printstatus_to(ipc_output);
+}
+
+void
+dwl_ipc_manager_release(struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+dwl_ipc_output_destroy(struct wl_resource *resource)
+{
+ DwlIpcOutput *ipc_output = wl_resource_get_user_data(resource);
+ wl_list_remove(&ipc_output->link);
+ free(ipc_output);
+}
+
+void
+dwl_ipc_output_printstatus(Monitor *monitor)
+{
+ DwlIpcOutput *ipc_output;
+ wl_list_for_each(ipc_output, &monitor->dwl_ipc_outputs, link)
+ dwl_ipc_output_printstatus_to(ipc_output);
+}
+
+void
+dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output)
+{
+ Monitor *monitor = ipc_output->mon;
+ Client *c, *focused;
+ int tagmask, state, numclients, focused_client, tag;
+ const char *title, *appid;
+ focused = focustop(monitor);
+ zdwl_ipc_output_v2_send_active(ipc_output->resource, monitor == selmon);
+
+ for (tag = 0 ; tag < TAGCOUNT; tag++) {
+ numclients = state = focused_client = 0;
+ tagmask = 1 << tag;
+ if ((tagmask & monitor->tagset[monitor->seltags]) != 0)
+ state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_ACTIVE;
+
+ wl_list_for_each(c, &clients, link) {
+ if (c->mon != monitor)
+ continue;
+ if (!(c->tags & tagmask))
+ continue;
+ if (c == focused)
+ focused_client = 1;
+ if (c->isurgent)
+ state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_URGENT;
+
+ numclients++;
+ }
+ zdwl_ipc_output_v2_send_tag(ipc_output->resource, tag, state, numclients, focused_client);
+ }
+ title = focused ? client_get_title(focused) : "";
+ appid = focused ? client_get_appid(focused) : "";
+
+ zdwl_ipc_output_v2_send_layout(ipc_output->resource, monitor->lt[monitor->sellt] - layouts);
+ zdwl_ipc_output_v2_send_title(ipc_output->resource, title ? title : broken);
+ zdwl_ipc_output_v2_send_appid(ipc_output->resource, appid ? appid : broken);
+ zdwl_ipc_output_v2_send_layout_symbol(ipc_output->resource, monitor->ltsymbol);
+ if (wl_resource_get_version(ipc_output->resource) >= ZDWL_IPC_OUTPUT_V2_FULLSCREEN_SINCE_VERSION) {
+ zdwl_ipc_output_v2_send_fullscreen(ipc_output->resource, focused ? focused->isfullscreen : 0);
+ }
+ if (wl_resource_get_version(ipc_output->resource) >= ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION) {
+ zdwl_ipc_output_v2_send_floating(ipc_output->resource, focused ? focused->isfloating : 0);
+ }
+ zdwl_ipc_output_v2_send_frame(ipc_output->resource);
+}
+
+void
+dwl_ipc_output_set_client_tags(struct wl_client *client, struct wl_resource *resource, uint32_t and_tags, uint32_t xor_tags)
+{
+ DwlIpcOutput *ipc_output;
+ Monitor *monitor;
+ Client *selected_client;
+ unsigned int newtags = 0;
+
+ ipc_output = wl_resource_get_user_data(resource);
+ if (!ipc_output)
+ return;
+
+ monitor = ipc_output->mon;
+ selected_client = focustop(monitor);
+ if (!selected_client)
+ return;
+
+ newtags = (selected_client->tags & and_tags) ^ xor_tags;
+ if (!newtags)
+ return;
+
+ selected_client->tags = newtags;
+ focusclient(focustop(selmon), 1);
+ arrange(selmon);
+ printstatus();
+}
+
+void
+dwl_ipc_output_set_layout(struct wl_client *client, struct wl_resource *resource, uint32_t index)
+{
+ DwlIpcOutput *ipc_output;
+ Monitor *monitor;
+
+ ipc_output = wl_resource_get_user_data(resource);
+ if (!ipc_output)
+ return;
+
+ monitor = ipc_output->mon;
+ if (index >= LENGTH(layouts))
+ return;
+ if (index != monitor->lt[monitor->sellt] - layouts)
+ monitor->sellt ^= 1;
+
+ monitor->lt[monitor->sellt] = &layouts[index];
+ arrange(monitor);
+ printstatus();
+}
+
+void
+dwl_ipc_output_set_tags(struct wl_client *client, struct wl_resource *resource, uint32_t tagmask, uint32_t toggle_tagset)
+{
+ DwlIpcOutput *ipc_output;
+ Monitor *monitor;
+ unsigned int newtags = tagmask & TAGMASK;
+
+ ipc_output = wl_resource_get_user_data(resource);
+ if (!ipc_output)
+ return;
+ monitor = ipc_output->mon;
+
+ if (!newtags || newtags == monitor->tagset[monitor->seltags])
+ return;
+ if (toggle_tagset)
+ monitor->seltags ^= 1;
+
+ monitor->tagset[monitor->seltags] = newtags;
+ focusclient(focustop(monitor), 1);
+ arrange(monitor);
+ printstatus();
+}
+
+void
+dwl_ipc_output_release(struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+void
+focusclient(Client *c, int lift)
+{
+ struct wlr_surface *old = seat->keyboard_state.focused_surface;
+ int unused_lx, unused_ly, old_client_type;
+ Client *old_c = NULL;
+ LayerSurface *old_l = NULL;
+
+ if (locked)
+ return;
+
+ /* Raise client in stacking order if requested */
+ if (c && lift)
+ wlr_scene_node_raise_to_top(&c->scene->node);
+
+ if (c && client_surface(c) == old)
+ return;
+
+ if ((old_client_type = toplevel_from_wlr_surface(old, &old_c, &old_l)) == XDGShell) {
+ struct wlr_xdg_popup *popup, *tmp;
+ wl_list_for_each_safe(popup, tmp, &old_c->surface.xdg->popups, link)
+ wlr_xdg_popup_destroy(popup);
+ }
+
+ /* Put the new client atop the focus stack and select its monitor */
+ if (c && !client_is_unmanaged(c)) {
+ wl_list_remove(&c->flink);
+ wl_list_insert(&fstack, &c->flink);
+ selmon = c->mon;
+ c->isurgent = 0;
+ client_restack_surface(c);
+
+ /* Don't change border color if there is an exclusive focus or we are
+ * handling a drag operation */
+ if (!exclusive_focus && !seat->drag)
+ client_set_border_color(c, focuscolor);
+ }
+
+ /* Deactivate old client if focus is changing */
+ if (old && (!c || client_surface(c) != old)) {
+ /* If an overlay is focused, don't focus or activate the client,
+ * but only update its position in fstack to render its border with focuscolor
+ * and focus it after the overlay is closed. */
+ if (old_client_type == LayerShell && wlr_scene_node_coords(
+ &old_l->scene->node, &unused_lx, &unused_ly)
+ && old_l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) {
+ return;
+ } else if (old_c && old_c == exclusive_focus && client_wants_focus(old_c)) {
+ return;
+ /* Don't deactivate old client if the new one wants focus, as this causes issues with winecfg
+ * and probably other clients */
+ } else if (old_c && !client_is_unmanaged(old_c) && (!c || !client_wants_focus(c))) {
+ client_set_border_color(old_c, bordercolor);
+
+ client_activate_surface(old, 0);
+ }
+ }
+ printstatus();
+
+ if (!c) {
+ /* With no client, all we have left is to clear focus */
+ wlr_seat_keyboard_notify_clear_focus(seat);
+ return;
+ }
+
+ /* Change cursor surface */
+ motionnotify(0, NULL, 0, 0, 0, 0);
+
+ /* Have a client, so focus its top-level wlr_surface */
+ client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat));
+
+ /* Activate the new client */
+ client_activate_surface(client_surface(c), 1);
+}
+
+void
+focusmon(const Arg *arg)
+{
+ int i = 0, nmons = wl_list_length(&mons);
+ if (nmons) {
+ do /* don't switch to disabled mons */
+ selmon = dirtomon(arg->i);
+ while (!selmon->wlr_output->enabled && i++ < nmons);
+ }
+ focusclient(focustop(selmon), 1);
+}
+
+void
+focusstack(const Arg *arg)
+{
+ /* Focus the next or previous client (in tiling order) on selmon */
+ Client *c, *sel = focustop(selmon);
+ if (!sel || (sel->isfullscreen && !client_has_children(sel)))
+ return;
+ if (arg->i > 0) {
+ wl_list_for_each(c, &sel->link, link) {
+ if (&c->link == &clients)
+ continue; /* wrap past the sentinel node */
+ if (VISIBLEON(c, selmon))
+ break; /* found it */
+ }
+ } else {
+ wl_list_for_each_reverse(c, &sel->link, link) {
+ if (&c->link == &clients)
+ continue; /* wrap past the sentinel node */
+ if (VISIBLEON(c, selmon))
+ break; /* found it */
+ }
+ }
+ /* If only one client is visible on selmon, then c == sel */
+ focusclient(c, 1);
+}
+
+/* We probably should change the name of this, it sounds like
+ * will focus the topmost client of this mon, when actually will
+ * only return that client */
+Client *
+focustop(Monitor *m)
+{
+ Client *c;
+ wl_list_for_each(c, &fstack, flink) {
+ if (VISIBLEON(c, m))
+ return c;
+ }
+ return NULL;
+}
+
+void
+fullscreennotify(struct wl_listener *listener, void *data)
+{
+ Client *c = wl_container_of(listener, c, fullscreen);
+ setfullscreen(c, client_wants_fullscreen(c));
+}
+
+void
+handlesig(int signo)
+{
+ if (signo == SIGCHLD) {
+#ifdef XWAYLAND
+ siginfo_t in;
+ /* wlroots expects to reap the XWayland process itself, so we
+ * use WNOWAIT to keep the child waitable until we know it's not
+ * XWayland.
+ */
+ while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid
+ && (!xwayland || in.si_pid != xwayland->server->pid))
+ waitpid(in.si_pid, NULL, 0);
+#else
+ while (waitpid(-1, NULL, WNOHANG) > 0);
+#endif
+ } else if (signo == SIGINT || signo == SIGTERM) {
+ quit(NULL);
+ }
+}
+
+pid_t
+getparentprocess(pid_t p)
+{
+ unsigned int v = 0;
+
+ FILE *f;
+ char buf[256];
+ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
+
+ if (!(f = fopen(buf, "r")))
+ return 0;
+
+ fscanf(f, "%*u %*s %*c %u", &v);
+ fclose(f);
+
+ return (pid_t)v;
+}
+
+int
+isdescprocess(pid_t p, pid_t c)
+{
+ while (p != c && c != 0)
+ c = getparentprocess(c);
+
+ return (int)c;
+}
+
+Client *
+termforwin(Client *w)
+{
+ Client *c;
+
+ if (!w->pid || w->isterm || w->noswallow)
+ return NULL;
+
+ wl_list_for_each(c, &fstack, flink)
+ if (c->isterm && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid))
+ return c;
+
+ return NULL;
+}
+
+void
+swallow(Client *c, Client *w)
+{
+ c->bw = w->bw;
+ c->isfloating = w->isfloating;
+ c->isurgent = w->isurgent;
+ c->isfullscreen = w->isfullscreen;
+ c->tags = w->tags;
+ c->geom = w->geom;
+ wl_list_insert(&w->link, &c->link);
+ wl_list_insert(&w->flink, &c->flink);
+ wlr_scene_node_set_enabled(&w->scene->node, 0);
+ wlr_scene_node_set_enabled(&c->scene->node, 1);
+}
+
+void
+incnmaster(const Arg *arg)
+{
+ if (!arg || !selmon)
+ return;
+ selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
+ arrange(selmon);
+}
+
+void
+inputdevice(struct wl_listener *listener, void *data)
+{
+ /* This event is raised by the backend when a new input device becomes
+ * available. */
+ struct wlr_input_device *device = data;
+ uint32_t caps;
+
+ switch (device->type) {
+ case WLR_INPUT_DEVICE_KEYBOARD:
+ createkeyboard(wlr_keyboard_from_input_device(device));
+ break;
+ case WLR_INPUT_DEVICE_POINTER:
+ createpointer(wlr_pointer_from_input_device(device));
+ break;
+ default:
+ /* TODO handle other input device types */
+ break;
+ }
+
+ /* We need to let the wlr_seat know what our capabilities are, which is
+ * communiciated to the client. In dwl we always have a cursor, even if
+ * there are no pointer devices, so we always include that capability. */
+ /* TODO do we actually require a cursor? */
+ caps = WL_SEAT_CAPABILITY_POINTER;
+ if (!wl_list_empty(&kb_group.wlr_group->devices))
+ caps |= WL_SEAT_CAPABILITY_KEYBOARD;
+ wlr_seat_set_capabilities(seat, caps);
+}
+
+int
+keybinding(uint32_t mods, xkb_keysym_t sym)
+{
+ /*
+ * Here we handle compositor keybindings. This is when the compositor is
+ * processing keys, rather than passing them on to the client for its own
+ * processing.
+ */
+ const Key *k;
+ for (k = keys; k < END(keys); k++) {
+ if (CLEANMASK(mods) == CLEANMASK(k->mod)
+ && sym == k->keysym && k->func) {
+ k->func(&k->arg);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void
+keypress(struct wl_listener *listener, void *data)
+{
+ int i;
+ /* This event is raised when a key is pressed or released. */
+ KeyboardGroup *group = wl_container_of(listener, group, key);
+ struct wlr_keyboard_key_event *event = data;
+
+ /* Translate libinput keycode -> xkbcommon */
+ uint32_t keycode = event->keycode + 8;
+ /* Get a list of keysyms based on the keymap for this keyboard */
+ const xkb_keysym_t *syms;
+ int nsyms = xkb_state_key_get_syms(
+ group->wlr_group->keyboard.xkb_state, keycode, &syms);
+
+ int handled = 0;
+ uint32_t mods = wlr_keyboard_get_modifiers(&group->wlr_group->keyboard);
+
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
+
+ /* On _press_ if there is no active screen locker,
+ * attempt to process a compositor keybinding. */
+ if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+ for (i = 0; i < nsyms; i++)
+ handled = keybinding(mods, syms[i]) || handled;
+ }
+
+ if (handled && group->wlr_group->keyboard.repeat_info.delay > 0) {
+ group->mods = mods;
+ group->keysyms = syms;
+ group->nsyms = nsyms;
+ wl_event_source_timer_update(group->key_repeat_source,
+ group->wlr_group->keyboard.repeat_info.delay);
+ } else {
+ group->nsyms = 0;
+ wl_event_source_timer_update(group->key_repeat_source, 0);
+ }
+
+ if (handled)
+ return;
+
+ wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard);
+ /* Pass unhandled keycodes along to the client. */
+ wlr_seat_keyboard_notify_key(seat, event->time_msec,
+ event->keycode, event->state);
+}
+
+void
+keypressmod(struct wl_listener *listener, void *data)
+{
+ /* This event is raised when a modifier key, such as shift or alt, is
+ * pressed. We simply communicate this to the client. */
+ KeyboardGroup *group = wl_container_of(listener, group, modifiers);
+
+ wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard);
+ /* Send modifiers to the client. */
+ wlr_seat_keyboard_notify_modifiers(seat,
+ &group->wlr_group->keyboard.modifiers);
+}
+
+int
+keyrepeat(void *data)
+{
+ KeyboardGroup *group = data;
+ int i;
+ if (!group->nsyms || group->wlr_group->keyboard.repeat_info.rate <= 0)
+ return 0;
+
+ wl_event_source_timer_update(group->key_repeat_source,
+ 1000 / group->wlr_group->keyboard.repeat_info.rate);
+
+ for (i = 0; i < group->nsyms; i++)
+ keybinding(group->mods, group->keysyms[i]);
+
+ return 0;
+}
+
+void
+killclient(const Arg *arg)
+{
+ Client *sel = focustop(selmon);
+ if (sel)
+ client_send_close(sel);
+}
+
+void
+locksession(struct wl_listener *listener, void *data)
+{
+ struct wlr_session_lock_v1 *session_lock = data;
+ SessionLock *lock;
+ wlr_scene_node_set_enabled(&locked_bg->node, 1);
+ if (cur_lock) {
+ wlr_session_lock_v1_destroy(session_lock);
+ return;
+ }
+ lock = session_lock->data = ecalloc(1, sizeof(*lock));
+ focusclient(NULL, 0);
+
+ lock->scene = wlr_scene_tree_create(layers[LyrBlock]);
+ cur_lock = lock->lock = session_lock;
+ locked = 1;
+
+ LISTEN(&session_lock->events.new_surface, &lock->new_surface, createlocksurface);
+ LISTEN(&session_lock->events.destroy, &lock->destroy, destroysessionlock);
+ LISTEN(&session_lock->events.unlock, &lock->unlock, unlocksession);
+
+ wlr_session_lock_v1_send_locked(session_lock);
+}
+
+void
+maplayersurfacenotify(struct wl_listener *listener, void *data)
+{
+ motionnotify(0, NULL, 0, 0, 0, 0);
+}
+
+void
+mapnotify(struct wl_listener *listener, void *data)
+{
+ /* Called when the surface is mapped, or ready to display on-screen. */
+ Client *p = NULL;
+ Client *w, *c = wl_container_of(listener, c, map);
+ Monitor *m;
+ int i;
+
+ /* Create scene tree for this client and its border */
+ c->scene = client_surface(c)->data = wlr_scene_tree_create(layers[LyrTile]);
+ wlr_scene_node_set_enabled(&c->scene->node, c->type != XDGShell);
+ c->scene_surface = c->type == XDGShell
+ ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg)
+ : wlr_scene_subsurface_tree_create(c->scene, client_surface(c));
+ c->scene->node.data = c->scene_surface->node.data = c;
+
+ client_get_geometry(c, &c->geom);
+
+ /* Handle unmanaged clients first so we can return prior create borders */
+ if (client_is_unmanaged(c)) {
+ /* Unmanaged clients always are floating */
+ wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]);
+ wlr_scene_node_set_position(&c->scene->node, c->geom.x + borderpx,
+ c->geom.y + borderpx);
+ if (client_wants_focus(c)) {
+ focusclient(c, 1);
+ exclusive_focus = c;
+ }
+ goto unset_fullscreen;
+ }
+
+ for (i = 0; i < 4; i++) {
+ c->border[i] = wlr_scene_rect_create(c->scene, 0, 0,
+ c->isurgent ? urgentcolor : bordercolor);
+ c->border[i]->node.data = c;
+ }
+
+ /* Initialize client geometry with room for border */
+ client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT);
+ c->geom.width += 2 * c->bw;
+ c->geom.height += 2 * c->bw;
+
+ /* Insert this client into client lists. */
+ wl_list_insert(&clients, &c->link);
+ wl_list_insert(&fstack, &c->flink);
+
+ /* Set initial monitor, tags, floating status, and focus:
+ * we always consider floating, clients that have parent and thus
+ * we set the same tags and monitor than its parent, if not
+ * try to apply rules for them */
+ if ((p = client_get_parent(c))) {
+ c->isfloating = 1;
+ setmon(c, p->mon, p->tags);
+ } else {
+ applyrules(c);
+ }
+ printstatus();
+
+unset_fullscreen:
+ m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y);
+ wl_list_for_each(w, &clients, link) {
+ if (w != c && w != p && w->isfullscreen && m == w->mon && (w->tags & c->tags))
+ setfullscreen(w, 0);
+ }
+}
+
+void
+maximizenotify(struct wl_listener *listener, void *data)
+{
+ /* This event is raised when a client would like to maximize itself,
+ * typically because the user clicked on the maximize button on
+ * client-side decorations. dwl doesn't support maximization, but
+ * to conform to xdg-shell protocol we still must send a configure.
+ * Since xdg-shell protocol v5 we should ignore request of unsupported
+ * capabilities, just schedule a empty configure when the client uses <5
+ * protocol version
+ * wlr_xdg_surface_schedule_configure() is used to send an empty reply. */
+ Client *c = wl_container_of(listener, c, maximize);
+ if (wl_resource_get_version(c->surface.xdg->toplevel->resource)
+ < XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION)
+ wlr_xdg_surface_schedule_configure(c->surface.xdg);
+}
+
+void
+monocle(Monitor *m)
+{
+ Client *c;
+ int n = 0;
+
+ wl_list_for_each(c, &clients, link) {
+ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
+ continue;
+ resize(c, m->w, 0);
+ n++;
+ }
+ if (n)
+ snprintf(m->ltsymbol, LENGTH(m->ltsymbol), "[%d]", n);
+ if ((c = focustop(m)))
+ wlr_scene_node_raise_to_top(&c->scene->node);
+}
+
+void
+movestack(const Arg *arg)
+{
+ Client *c, *sel = focustop(selmon);
+
+ if (!sel) {
+ return;
+ }
+
+ if (wl_list_length(&clients) <= 1) {
+ return;
+ }
+
+ if (arg->i > 0) {
+ wl_list_for_each(c, &sel->link, link) {
+ if (VISIBLEON(c, selmon) || &c->link == &clients) {
+ break; /* found it */
+ }
+ }
+ } else {
+ wl_list_for_each_reverse(c, &sel->link, link) {
+ if (VISIBLEON(c, selmon) || &c->link == &clients) {
+ break; /* found it */
+ }
+ }
+ /* backup one client */
+ c = wl_container_of(c->link.prev, c, link);
+ }
+
+ wl_list_remove(&sel->link);
+ wl_list_insert(&c->link, &sel->link);
+ arrange(selmon);
+}
+
+void
+motionabsolute(struct wl_listener *listener, void *data)
+{
+ /* This event is forwarded by the cursor when a pointer emits an _absolute_
+ * motion event, from 0..1 on each axis. This happens, for example, when
+ * wlroots is running under a Wayland window rather than KMS+DRM, and you
+ * move the mouse over the window. You could enter the window from any edge,
+ * so we have to warp the mouse there. There is also some hardware which
+ * emits these events. */
+ struct wlr_pointer_motion_absolute_event *event = data;
+ double lx, ly, dx, dy;
+
+ if (!event->time_msec) /* this is 0 with virtual pointers */
+ wlr_cursor_warp_absolute(cursor, &event->pointer->base, event->x, event->y);
+
+ wlr_cursor_absolute_to_layout_coords(cursor, &event->pointer->base, event->x, event->y, &lx, &ly);
+ dx = lx - cursor->x;
+ dy = ly - cursor->y;
+ motionnotify(event->time_msec, &event->pointer->base, dx, dy, dx, dy);
+}
+
+void
+motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy,
+ double dx_unaccel, double dy_unaccel)
+{
+ double sx = 0, sy = 0, sx_confined, sy_confined;
+ Client *c = NULL, *w = NULL;
+ LayerSurface *l = NULL;
+ struct wlr_surface *surface = NULL;
+ struct wlr_pointer_constraint_v1 *constraint;
+
+ /* time is 0 in internal calls meant to restore pointer focus. */
+ if (time) {
+ wlr_relative_pointer_manager_v1_send_relative_motion(
+ relative_pointer_mgr, seat, (uint64_t)time * 1000,
+ dx, dy, dx_unaccel, dy_unaccel);
+
+ wl_list_for_each(constraint, &pointer_constraints->constraints, link)
+ cursorconstrain(constraint);
+
+ if (active_constraint && cursor_mode != CurResize && cursor_mode != CurMove) {
+ toplevel_from_wlr_surface(active_constraint->surface, &c, NULL);
+ if (c && active_constraint->surface == seat->pointer_state.focused_surface) {
+ sx = cursor->x - c->geom.x - c->bw;
+ sy = cursor->y - c->geom.y - c->bw;
+ if (wlr_region_confine(&active_constraint->region, sx, sy,
+ sx + dx, sy + dy, &sx_confined, &sy_confined)) {
+ dx = sx_confined - sx;
+ dy = sy_confined - sy;
+ }
+
+ if (active_constraint->type == WLR_POINTER_CONSTRAINT_V1_LOCKED)
+ return;
+ }
+ }
+
+ wlr_cursor_move(cursor, device, dx, dy);
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
+
+ /* Update selmon (even while dragging a window) */
+ if (sloppyfocus)
+ selmon = xytomon(cursor->x, cursor->y);
+ }
+
+ /* Update drag icon's position */
+ wlr_scene_node_set_position(&drag_icon->node, ROUND(cursor->x), ROUND(cursor->y));
+
+ /* If we are currently grabbing the mouse, handle and return */
+ if (cursor_mode == CurMove) {
+ /* Move the grabbed client to the new position. */
+ resize(grabc, (struct wlr_box){.x = ROUND(cursor->x) - grabcx, .y = ROUND(cursor->y) - grabcy,
+ .width = grabc->geom.width, .height = grabc->geom.height}, 1);
+ return;
+ } else if (cursor_mode == CurResize) {
+ resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
+ .width = ROUND(cursor->x) - grabc->geom.x, .height = ROUND(cursor->y) - grabc->geom.y}, 1);
+ return;
+ }
+
+ /* Find the client under the pointer and send the event along. */
+ xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy);
+
+ if (cursor_mode == CurPressed && !seat->drag && surface != held_grab
+ && toplevel_from_wlr_surface(held_grab, &w, &l) >= 0) {
+ c = w;
+ surface = held_grab;
+ sx = cursor->x - (l ? l->geom.x : w->geom.x);
+ sy = cursor->y - (l ? l->geom.y : w->geom.y);
+ }
+
+ /* If there's no client surface under the cursor, set the cursor image to a
+ * default. This is what makes the cursor image appear when you move it
+ * off of a client or over its border. */
+ if (!surface && !seat->drag)
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
+
+ pointerfocus(c, surface, sx, sy, time);
+}
+
+void
+motionrelative(struct wl_listener *listener, void *data)
+{
+ /* This event is forwarded by the cursor when a pointer emits a _relative_
+ * pointer motion event (i.e. a delta) */
+ struct wlr_pointer_motion_event *event = data;
+ /* The cursor doesn't move unless we tell it to. The cursor automatically
+ * handles constraining the motion to the output layout, as well as any
+ * special configuration applied for the specific input device which
+ * generated the event. You can pass NULL for the device if you want to move
+ * the cursor around without any input. */
+ motionnotify(event->time_msec, &event->pointer->base, event->delta_x, event->delta_y,
+ event->unaccel_dx, event->unaccel_dy);
+}
+
+void
+moveresize(const Arg *arg)
+{
+ if (cursor_mode != CurNormal && cursor_mode != CurPressed)
+ return;
+ xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL);
+ if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
+ return;
+
+ /* Float the window and tell motionnotify to grab it */
+ setfloating(grabc, 1);
+ switch (cursor_mode = arg->ui) {
+ case CurMove:
+ grabcx = ROUND(cursor->x) - grabc->geom.x;
+ grabcy = ROUND(cursor->y) - grabc->geom.y;
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
+ break;
+ case CurResize:
+ /* Doesn't work for X11 output - the next absolute motion event
+ * returns the cursor to where it started */
+ wlr_cursor_warp_closest(cursor, NULL,
+ grabc->geom.x + grabc->geom.width,
+ grabc->geom.y + grabc->geom.height);
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "se-resize");
+ break;
+ }
+}
+
+void
+outputmgrapply(struct wl_listener *listener, void *data)
+{
+ struct wlr_output_configuration_v1 *config = data;
+ outputmgrapplyortest(config, 0);
+}
+
+void
+outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test)
+{
+ /*
+ * Called when a client such as wlr-randr requests a change in output
+ * configuration. This is only one way that the layout can be changed,
+ * so any Monitor information should be updated by updatemons() after an
+ * output_layout.change event, not here.
+ */
+ struct wlr_output_configuration_head_v1 *config_head;
+ int ok = 1;
+
+ wl_list_for_each(config_head, &config->heads, link) {
+ struct wlr_output *wlr_output = config_head->state.output;
+ Monitor *m = wlr_output->data;
+ struct wlr_output_state state;
+
+ wlr_output_state_init(&state);
+ wlr_output_state_set_enabled(&state, config_head->state.enabled);
+ if (!config_head->state.enabled)
+ goto apply_or_test;
+
+ if (config_head->state.mode)
+ wlr_output_state_set_mode(&state, config_head->state.mode);
+ else
+ wlr_output_state_set_custom_mode(&state,
+ config_head->state.custom_mode.width,
+ config_head->state.custom_mode.height,
+ config_head->state.custom_mode.refresh);
+
+ /* Don't move monitors if position wouldn't change, this to avoid
+ * wlroots marking the output as manually configured */
+ if (m->m.x != config_head->state.x || m->m.y != config_head->state.y)
+ wlr_output_layout_add(output_layout, wlr_output,
+ config_head->state.x, config_head->state.y);
+ wlr_output_state_set_transform(&state, config_head->state.transform);
+ wlr_output_state_set_scale(&state, config_head->state.scale);
+ wlr_output_state_set_adaptive_sync_enabled(&state,
+ config_head->state.adaptive_sync_enabled);
+
+apply_or_test:
+ ok &= test ? wlr_output_test_state(wlr_output, &state)
+ : wlr_output_commit_state(wlr_output, &state);
+
+ wlr_output_state_finish(&state);
+ }
+
+ if (ok)
+ wlr_output_configuration_v1_send_succeeded(config);
+ else
+ wlr_output_configuration_v1_send_failed(config);
+ wlr_output_configuration_v1_destroy(config);
+
+ /* TODO: use a wrapper function? */
+ updatemons(NULL, NULL);
+}
+
+void
+outputmgrtest(struct wl_listener *listener, void *data)
+{
+ struct wlr_output_configuration_v1 *config = data;
+ outputmgrapplyortest(config, 1);
+}
+
+void
+pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,
+ uint32_t time)
+{
+ struct timespec now;
+
+ if ((!active_constraint || active_constraint->surface != surface) &&
+ sloppyfocus && time && c && !client_is_unmanaged(c))
+ focusclient(c, 0);
+
+ /* If surface is NULL, clear pointer focus */
+ if (!surface) {
+ wlr_seat_pointer_notify_clear_focus(seat);
+ return;
+ }
+
+ if (!time) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ time = now.tv_sec * 1000 + now.tv_nsec / 1000000;
+ }
+
+ /* Let the client know that the mouse cursor has entered one
+ * of its surfaces, and make keyboard focus follow if desired.
+ * wlroots makes this a no-op if surface is already focused */
+ wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
+ wlr_seat_pointer_notify_motion(seat, time, sx, sy);
+}
+
+void
+printstatus(void)
+{
+ Monitor *m = NULL;
+
+ wl_list_for_each(m, &mons, link)
+ dwl_ipc_output_printstatus(m);
+}
+
+void
+quit(const Arg *arg)
+{
+ wl_display_terminate(dpy);
+}
+
+void
+rendermon(struct wl_listener *listener, void *data)
+{
+ /* This function is called every time an output is ready to display a frame,
+ * generally at the output's refresh rate (e.g. 60Hz). */
+ Monitor *m = wl_container_of(listener, m, frame);
+ Client *c;
+ struct wlr_output_state pending = {0};
+ struct wlr_gamma_control_v1 *gamma_control;
+ struct timespec now;
+
+ /* Render if no XDG clients have an outstanding resize and are visible on
+ * this monitor. */
+ wl_list_for_each(c, &clients, link) {
+ if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && !client_is_stopped(c))
+ goto skip;
+ }
+
+ /*
+ * HACK: The "correct" way to set the gamma is to commit it together with
+ * the rest of the state in one go, but to do that we would need to rewrite
+ * wlr_scene_output_commit() in order to add the gamma to the pending
+ * state before committing, instead try to commit the gamma in one frame,
+ * and commit the rest of the state in the next one (or in the same frame if
+ * the gamma can not be committed).
+ */
+ if (m->gamma_lut_changed) {
+ gamma_control
+ = wlr_gamma_control_manager_v1_get_control(gamma_control_mgr, m->wlr_output);
+ m->gamma_lut_changed = 0;
+
+ if (!wlr_gamma_control_v1_apply(gamma_control, &pending))
+ goto commit;
+
+ if (!wlr_output_test_state(m->wlr_output, &pending)) {
+ wlr_gamma_control_v1_send_failed_and_destroy(gamma_control);
+ goto commit;
+ }
+ wlr_output_commit_state(m->wlr_output, &pending);
+ wlr_output_schedule_frame(m->wlr_output);
+ } else {
+commit:
+ wlr_scene_output_commit(m->scene_output, NULL);
+ }
+
+skip:
+ /* Let clients know a frame has been rendered */
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ wlr_scene_output_send_frame_done(m->scene_output, &now);
+ wlr_output_state_finish(&pending);
+}
+
+void
+requestdecorationmode(struct wl_listener *listener, void *data)
+{
+ Client *c = wl_container_of(listener, c, set_decoration_mode);
+ wlr_xdg_toplevel_decoration_v1_set_mode(c->decoration,
+ WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
+}
+
+void
+requeststartdrag(struct wl_listener *listener, void *data)
+{
+ struct wlr_seat_request_start_drag_event *event = data;
+
+ if (wlr_seat_validate_pointer_grab_serial(seat, event->origin,
+ event->serial))
+ wlr_seat_start_pointer_drag(seat, event->drag, event->serial);
+ else
+ wlr_data_source_destroy(event->drag->source);
+}
+
+void
+requestmonstate(struct wl_listener *listener, void *data)
+{
+ struct wlr_output_event_request_state *event = data;
+ wlr_output_commit_state(event->output, event->state);
+ updatemons(NULL, NULL);
+}
+
+void
+resize(Client *c, struct wlr_box geo, int interact)
+{
+ struct wlr_box *bbox = interact ? &sgeom : &c->mon->w;
+ struct wlr_box clip;
+ client_set_bounds(c, geo.width, geo.height);
+ c->geom = geo;
+ applybounds(c, bbox);
+
+ /* Update scene-graph, including borders */
+ wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
+ wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);
+ wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw);
+ wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw);
+ wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw);
+ wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw);
+ wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw);
+ wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw);
+ wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw);
+
+ /* this is a no-op if size hasn't changed */
+ c->resize = client_set_size(c, c->geom.width - 2 * c->bw,
+ c->geom.height - 2 * c->bw);
+ client_get_clip(c, &clip);
+ wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip);
+}
+
+void
+run(char *startup_cmd)
+{
+ /* Add a Unix socket to the Wayland display. */
+ const char *socket = wl_display_add_socket_auto(dpy);
+ if (!socket)
+ die("startup: display_add_socket_auto");
+ setenv("WAYLAND_DISPLAY", socket, 1);
+
+ /* Start the backend. This will enumerate outputs and inputs, become the DRM
+ * master, etc */
+ if (!wlr_backend_start(backend))
+ die("startup: backend_start");
+
+ /* Now that the socket exists and the backend is started, run the startup command */
+ if (startup_cmd) {
+ int piperw[2];
+ if (pipe(piperw) < 0)
+ die("startup: pipe:");
+ if ((child_pid = fork()) < 0)
+ die("startup: fork:");
+ if (child_pid == 0) {
+ dup2(piperw[0], STDIN_FILENO);
+ close(piperw[0]);
+ close(piperw[1]);
+ execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL);
+ die("startup: execl:");
+ }
+ dup2(piperw[1], STDOUT_FILENO);
+ close(piperw[1]);
+ close(piperw[0]);
+ }
+ printstatus();
+
+ /* At this point the outputs are initialized, choose initial selmon based on
+ * cursor position, and set default cursor image */
+ selmon = xytomon(cursor->x, cursor->y);
+
+ /* TODO hack to get cursor to display in its initial location (100, 100)
+ * instead of (0, 0) and then jumping. still may not be fully
+ * initialized, as the image/coordinates are not transformed for the
+ * monitor when displayed here */
+ wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y);
+ wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
+
+ /* Run the Wayland event loop. This does not return until you exit the
+ * compositor. Starting the backend rigged up all of the necessary event
+ * loop configuration to listen to libinput events, DRM events, generate
+ * frame events at the refresh rate, and so on. */
+ wl_display_run(dpy);
+}
+
+void
+setcursor(struct wl_listener *listener, void *data)
+{
+ /* This event is raised by the seat when a client provides a cursor image */
+ struct wlr_seat_pointer_request_set_cursor_event *event = data;
+ /* If we're "grabbing" the cursor, don't use the client's image, we will
+ * restore it after "grabbing" sending a leave event, followed by a enter
+ * event, which will result in the client requesting set the cursor surface */
+ if (cursor_mode != CurNormal && cursor_mode != CurPressed)
+ return;
+ /* This can be sent by any client, so we check to make sure this one is
+ * actually has pointer focus first. If so, we can tell the cursor to
+ * use the provided surface as the cursor image. It will set the
+ * hardware cursor on the output that it's currently on and continue to
+ * do so as the cursor moves between outputs. */
+ if (event->seat_client == seat->pointer_state.focused_client)
+ wlr_cursor_set_surface(cursor, event->surface,
+ event->hotspot_x, event->hotspot_y);
+}
+
+void
+setcursorshape(struct wl_listener *listener, void *data)
+{
+ struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data;
+ if (cursor_mode != CurNormal && cursor_mode != CurPressed)
+ return;
+ /* This can be sent by any client, so we check to make sure this one is
+ * actually has pointer focus first. If so, we can tell the cursor to
+ * use the provided cursor shape. */
+ if (event->seat_client == seat->pointer_state.focused_client)
+ wlr_cursor_set_xcursor(cursor, cursor_mgr,
+ wlr_cursor_shape_v1_name(event->shape));
+}
+
+void
+setfloating(Client *c, int floating)
+{
+ Client *p = client_get_parent(c);
+ c->isfloating = floating;
+ if (!c->mon)
+ return;
+ wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ||
+ (p && p->isfullscreen) ? LyrFS
+ : c->isfloating ? LyrFloat : LyrTile]);
+ arrange(c->mon);
+ printstatus();
+}
+
+void
+setfullscreen(Client *c, int fullscreen)
+{
+ c->isfullscreen = fullscreen;
+ if (!c->mon)
+ return;
+ c->bw = fullscreen ? 0 : borderpx;
+ client_set_fullscreen(c, fullscreen);
+ wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen
+ ? LyrFS : c->isfloating ? LyrFloat : LyrTile]);
+
+ if (fullscreen) {
+ c->prev = c->geom;
+ resize(c, c->mon->m, 0);
+ } else {
+ /* restore previous size instead of arrange for floating windows since
+ * client positions are set by the user and cannot be recalculated */
+ resize(c, c->prev, 0);
+ }
+ arrange(c->mon);
+ printstatus();
+}
+
+void
+setgamma(struct wl_listener *listener, void *data)
+{
+ struct wlr_gamma_control_manager_v1_set_gamma_event *event = data;
+ Monitor *m = event->output->data;
+ if (!m)
+ return;
+ m->gamma_lut_changed = 1;
+ wlr_output_schedule_frame(m->wlr_output);
+}
+
+void
+setlayout(const Arg *arg)
+{
+ if (!selmon)
+ return;
+ if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
+ selmon->sellt ^= 1;
+ if (arg && arg->v) {
+ selmon->lt[selmon->sellt] = (Layout *)arg->v;
+ }
+ strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, LENGTH(selmon->ltsymbol));
+ arrange(selmon);
+ printstatus();
+}
+
+/* arg > 1.0 will set mfact absolutely */
+void
+setmfact(const Arg *arg)
+{
+ float f;
+
+ if (!arg || !selmon || !selmon->lt[selmon->sellt]->arrange)
+ return;
+ f = arg->f < 1.0f ? arg->f + selmon->mfact : arg->f - 1.0f;
+ if (f < 0.1 || f > 0.9)
+ return;
+ selmon->mfact = f;
+ arrange(selmon);
+}
+
+void
+setmon(Client *c, Monitor *m, uint32_t newtags)
+{
+ Monitor *oldmon = c->mon;
+
+ if (oldmon == m)
+ return;
+ c->mon = m;
+ c->prev = c->geom;
+
+ /* Scene graph sends surface leave/enter events on move and resize */
+ if (oldmon)
+ arrange(oldmon);
+ if (m) {
+ /* Make sure window actually overlaps with the monitor */
+ resize(c, c->geom, 0);
+ c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */
+ setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */
+ setfloating(c, c->isfloating);
+ }
+ focusclient(focustop(selmon), 1);
+}
+
+void
+setpsel(struct wl_listener *listener, void *data)
+{
+ /* This event is raised by the seat when a client wants to set the selection,
+ * usually when the user copies something. wlroots allows compositors to
+ * ignore such requests if they so choose, but in dwl we always honor
+ */
+ struct wlr_seat_request_set_primary_selection_event *event = data;
+ wlr_seat_set_primary_selection(seat, event->source, event->serial);
+}
+
+void
+setsel(struct wl_listener *listener, void *data)
+{
+ /* This event is raised by the seat when a client wants to set the selection,
+ * usually when the user copies something. wlroots allows compositors to
+ * ignore such requests if they so choose, but in dwl we always honor
+ */
+ struct wlr_seat_request_set_selection_event *event = data;
+ wlr_seat_set_selection(seat, event->source, event->serial);
+}
+
+void
+setup(void)
+{
+ struct xkb_context *context;
+ struct xkb_keymap *keymap;
+
+ int i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE};
+ struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig};
+ sigemptyset(&sa.sa_mask);
+
+ for (i = 0; i < (int)LENGTH(sig); i++)
+ sigaction(sig[i], &sa, NULL);
+
+ wlr_log_init(log_level, NULL);
+
+ /* The Wayland display is managed by libwayland. It handles accepting
+ * clients from the Unix socket, manging Wayland globals, and so on. */
+ dpy = wl_display_create();
+
+ /* The backend is a wlroots feature which abstracts the underlying input and
+ * output hardware. The autocreate option will choose the most suitable
+ * backend based on the current environment, such as opening an X11 window
+ * if an X11 server is running. */
+ if (!(backend = wlr_backend_autocreate(dpy, &session)))
+ die("couldn't create backend");
+
+ /* Initialize the scene graph used to lay out windows */
+ scene = wlr_scene_create();
+ root_bg = wlr_scene_rect_create(&scene->tree, 0, 0, rootcolor);
+ for (i = 0; i < NUM_LAYERS; i++)
+ layers[i] = wlr_scene_tree_create(&scene->tree);
+ drag_icon = wlr_scene_tree_create(&scene->tree);
+ wlr_scene_node_place_below(&drag_icon->node, &layers[LyrBlock]->node);
+
+ /* Autocreates a renderer, either Pixman, GLES2 or Vulkan for us. The user
+ * can also specify a renderer using the WLR_RENDERER env var.
+ * The renderer is responsible for defining the various pixel formats it
+ * supports for shared memory, this configures that for clients. */
+ if (!(drw = wlr_renderer_autocreate(backend)))
+ die("couldn't create renderer");
+
+ /* Create shm, drm and linux_dmabuf interfaces by ourselves.
+ * The simplest way is call:
+ * wlr_renderer_init_wl_display(drw);
+ * but we need to create manually the linux_dmabuf interface to integrate it
+ * with wlr_scene. */
+ wlr_renderer_init_wl_shm(drw, dpy);
+
+ if (wlr_renderer_get_dmabuf_texture_formats(drw)) {
+ wlr_drm_create(dpy, drw);
+ wlr_scene_set_linux_dmabuf_v1(scene,
+ wlr_linux_dmabuf_v1_create_with_renderer(dpy, 4, drw));
+ }
+
+ /* Autocreates an allocator for us.
+ * The allocator is the bridge between the renderer and the backend. It
+ * handles the buffer creation, allowing wlroots to render onto the
+ * screen */
+ if (!(alloc = wlr_allocator_autocreate(backend, drw)))
+ die("couldn't create allocator");
+
+ /* This creates some hands-off wlroots interfaces. The compositor is
+ * necessary for clients to allocate surfaces and the data device manager
+ * handles the clipboard. Each of these wlroots interfaces has room for you
+ * to dig your fingers in and play with their behavior if you want. Note that
+ * the clients cannot set the selection directly without compositor approval,
+ * see the setsel() function. */
+ compositor = wlr_compositor_create(dpy, 6, drw);
+ wlr_subcompositor_create(dpy);
+ wlr_data_device_manager_create(dpy);
+ wlr_export_dmabuf_manager_v1_create(dpy);
+ wlr_screencopy_manager_v1_create(dpy);
+ wlr_data_control_manager_v1_create(dpy);
+ wlr_primary_selection_v1_device_manager_create(dpy);
+ wlr_viewporter_create(dpy);
+ wlr_single_pixel_buffer_manager_v1_create(dpy);
+ wlr_fractional_scale_manager_v1_create(dpy, 1);
+
+ /* Initializes the interface used to implement urgency hints */
+ activation = wlr_xdg_activation_v1_create(dpy);
+ LISTEN_STATIC(&activation->events.request_activate, urgent);
+
+ gamma_control_mgr = wlr_gamma_control_manager_v1_create(dpy);
+ LISTEN_STATIC(&gamma_control_mgr->events.set_gamma, setgamma);
+
+ /* Creates an output layout, which a wlroots utility for working with an
+ * arrangement of screens in a physical layout. */
+ output_layout = wlr_output_layout_create();
+ LISTEN_STATIC(&output_layout->events.change, updatemons);
+ wlr_xdg_output_manager_v1_create(dpy, output_layout);
+
+ /* Configure a listener to be notified when new outputs are available on the
+ * backend. */
+ wl_list_init(&mons);
+ LISTEN_STATIC(&backend->events.new_output, createmon);
+
+ /* Set up our client lists, the xdg-shell and the layer-shell. The xdg-shell is a
+ * Wayland protocol which is used for application windows. For more
+ * detail on shells, refer to the article:
+ *
+ * https://drewdevault.com/2018/07/29/Wayland-shells.html
+ */
+ wl_list_init(&clients);
+ wl_list_init(&fstack);
+
+ xdg_shell = wlr_xdg_shell_create(dpy, 6);
+ LISTEN_STATIC(&xdg_shell->events.new_surface, createnotify);
+
+ layer_shell = wlr_layer_shell_v1_create(dpy, 3);
+ LISTEN_STATIC(&layer_shell->events.new_surface, createlayersurface);
+
+ idle_notifier = wlr_idle_notifier_v1_create(dpy);
+
+ idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy);
+ LISTEN_STATIC(&idle_inhibit_mgr->events.new_inhibitor, createidleinhibitor);
+
+ session_lock_mgr = wlr_session_lock_manager_v1_create(dpy);
+ wl_signal_add(&session_lock_mgr->events.new_lock, &lock_listener);
+ LISTEN_STATIC(&session_lock_mgr->events.destroy, destroysessionmgr);
+ locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height,
+ (float [4]){0.1f, 0.1f, 0.1f, 1.0f});
+ wlr_scene_node_set_enabled(&locked_bg->node, 0);
+
+ /* Use decoration protocols to negotiate server-side decorations */
+ wlr_server_decoration_manager_set_default_mode(
+ wlr_server_decoration_manager_create(dpy),
+ WLR_SERVER_DECORATION_MANAGER_MODE_SERVER);
+ xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy);
+ LISTEN_STATIC(&xdg_decoration_mgr->events.new_toplevel_decoration, createdecoration);
+
+ pointer_constraints = wlr_pointer_constraints_v1_create(dpy);
+ LISTEN_STATIC(&pointer_constraints->events.new_constraint, createpointerconstraint);
+
+ relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy);
+
+ /*
+ * Creates a cursor, which is a wlroots utility for tracking the cursor
+ * image shown on screen.
+ */
+ cursor = wlr_cursor_create();
+ wlr_cursor_attach_output_layout(cursor, output_layout);
+
+ /* Creates an xcursor manager, another wlroots utility which loads up
+ * Xcursor themes to source cursor images from and makes sure that cursor
+ * images are available at all scale factors on the screen (necessary for
+ * HiDPI support). Scaled cursors will be loaded with each output. */
+ cursor_mgr = wlr_xcursor_manager_create(NULL, 24);
+ setenv("XCURSOR_SIZE", "24", 1);
+
+ /*
+ * wlr_cursor *only* displays an image on screen. It does not move around
+ * when the pointer moves. However, we can attach input devices to it, and
+ * it will generate aggregate events for all of them. In these events, we
+ * can choose how we want to process them, forwarding them to clients and
+ * moving the cursor around. More detail on this process is described in
+ * https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html
+ *
+ * And more comments are sprinkled throughout the notify functions above.
+ */
+ LISTEN_STATIC(&cursor->events.motion, motionrelative);
+ LISTEN_STATIC(&cursor->events.motion_absolute, motionabsolute);
+ LISTEN_STATIC(&cursor->events.button, buttonpress);
+ LISTEN_STATIC(&cursor->events.axis, axisnotify);
+ LISTEN_STATIC(&cursor->events.frame, cursorframe);
+
+ cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1);
+ LISTEN_STATIC(&cursor_shape_mgr->events.request_set_shape, setcursorshape);
+
+ /*
+ * Configures a seat, which is a single "seat" at which a user sits and
+ * operates the computer. This conceptually includes up to one keyboard,
+ * pointer, touch, and drawing tablet device. We also rig up a listener to
+ * let us know when new input devices are available on the backend.
+ */
+ LISTEN_STATIC(&backend->events.new_input, inputdevice);
+ virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy);
+ LISTEN_STATIC(&virtual_keyboard_mgr->events.new_virtual_keyboard, virtualkeyboard);
+ virtual_pointer_mgr = wlr_virtual_pointer_manager_v1_create(dpy);
+ LISTEN_STATIC(&virtual_pointer_mgr->events.new_virtual_pointer, virtualpointer);
+
+ seat = wlr_seat_create(dpy, "seat0");
+ LISTEN_STATIC(&seat->events.request_set_cursor, setcursor);
+ LISTEN_STATIC(&seat->events.request_set_selection, setsel);
+ LISTEN_STATIC(&seat->events.request_set_primary_selection, setpsel);
+ LISTEN_STATIC(&seat->events.request_start_drag, requeststartdrag);
+ LISTEN_STATIC(&seat->events.start_drag, startdrag);
+
+ /*
+ * Configures a keyboard group, which will keep track of all connected
+ * keyboards, keep their modifier and LED states in sync, and handle
+ * keypresses
+ */
+ kb_group.wlr_group = wlr_keyboard_group_create();
+ kb_group.wlr_group->data = &kb_group;
+
+ /*
+ * Virtual keyboards need to be in a different group
+ * https://codeberg.org/dwl/dwl/issues/554
+ */
+ vkb_group.wlr_group = wlr_keyboard_group_create();
+ vkb_group.wlr_group->data = &vkb_group;
+
+ /* Prepare an XKB keymap and assign it to the keyboard group. */
+ context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+ if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules,
+ XKB_KEYMAP_COMPILE_NO_FLAGS)))
+ die("failed to compile keymap");
+
+ wlr_keyboard_set_keymap(&kb_group.wlr_group->keyboard, keymap);
+ wlr_keyboard_set_keymap(&vkb_group.wlr_group->keyboard, keymap);
+ xkb_keymap_unref(keymap);
+ xkb_context_unref(context);
+
+ wlr_keyboard_set_repeat_info(&kb_group.wlr_group->keyboard, repeat_rate, repeat_delay);
+ wlr_keyboard_set_repeat_info(&vkb_group.wlr_group->keyboard, repeat_rate, repeat_delay);
+
+ /* Set up listeners for keyboard events */
+ LISTEN(&kb_group.wlr_group->keyboard.events.key, &kb_group.key, keypress);
+ LISTEN(&kb_group.wlr_group->keyboard.events.modifiers, &kb_group.modifiers, keypressmod);
+ LISTEN(&vkb_group.wlr_group->keyboard.events.key, &vkb_group.key, keypress);
+ LISTEN(&vkb_group.wlr_group->keyboard.events.modifiers, &vkb_group.modifiers, keypressmod);
+
+ kb_group.key_repeat_source = wl_event_loop_add_timer(
+ wl_display_get_event_loop(dpy), keyrepeat, &kb_group);
+ vkb_group.key_repeat_source = wl_event_loop_add_timer(
+ wl_display_get_event_loop(dpy), keyrepeat, &vkb_group);
+
+ /* A seat can only have one keyboard, but this is a limitation of the
+ * Wayland protocol - not wlroots. We assign all connected keyboards to the
+ * same wlr_keyboard_group, which provides a single wlr_keyboard interface for
+ * all of them. Set this combined wlr_keyboard as the seat keyboard.
+ */
+ wlr_seat_set_keyboard(seat, &kb_group.wlr_group->keyboard);
+
+ output_mgr = wlr_output_manager_v1_create(dpy);
+ LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply);
+ LISTEN_STATIC(&output_mgr->events.test, outputmgrtest);
+
+ wlr_scene_set_presentation(scene, wlr_presentation_create(dpy, backend));
+ wl_global_create(dpy, &zdwl_ipc_manager_v2_interface, 2, NULL, dwl_ipc_manager_bind);
+
+ /* Make sure XWayland clients don't connect to the parent X server,
+ * e.g when running in the x11 backend or the wayland backend and the
+ * compositor has Xwayland support */
+ unsetenv("DISPLAY");
+#ifdef XWAYLAND
+ /*
+ * Initialise the XWayland X server.
+ * It will be started when the first X client is started.
+ */
+ if ((xwayland = wlr_xwayland_create(dpy, compositor, 1))) {
+ LISTEN_STATIC(&xwayland->events.ready, xwaylandready);
+ LISTEN_STATIC(&xwayland->events.new_surface, createnotifyx11);
+
+ setenv("DISPLAY", xwayland->display_name, 1);
+ } else {
+ fprintf(stderr, "failed to setup XWayland X server, continuing without it\n");
+ }
+#endif
+}
+
+void
+spawn(const Arg *arg)
+{
+ if (fork() == 0) {
+ dup2(STDERR_FILENO, STDOUT_FILENO);
+ setsid();
+ execvp(((char **)arg->v)[0], (char **)arg->v);
+ die("dwl: execvp %s failed:", ((char **)arg->v)[0]);
+ }
+}
+
+void
+startdrag(struct wl_listener *listener, void *data)
+{
+ struct wlr_drag *drag = data;
+ if (!drag->icon)
+ return;
+
+ drag->icon->data = &wlr_scene_drag_icon_create(drag_icon, drag->icon)->node;
+ LISTEN_STATIC(&drag->icon->events.destroy, destroydragicon);
+}
+
+void
+tag(const Arg *arg)
+{
+ Client *sel = focustop(selmon);
+ if (!sel || (arg->ui & TAGMASK) == 0)
+ return;
+
+ sel->tags = arg->ui & TAGMASK;
+ focusclient(focustop(selmon), 1);
+ arrange(selmon);
+ printstatus();
+}
+
+void
+tagmon(const Arg *arg)
+{
+ Client *sel = focustop(selmon);
+ if (sel)
+ setmon(sel, dirtomon(arg->i), 0);
+}
+
+void
+tile(Monitor *m)
+{
+ unsigned int mw, my, ty;
+ int i, n = 0;
+ Client *c;
+
+ wl_list_for_each(c, &clients, link)
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
+ n++;
+ if (n == 0)
+ return;
+
+ if (n > m->nmaster)
+ mw = m->nmaster ? ROUND(m->w.width * m->mfact) : 0;
+ else
+ mw = m->w.width;
+ i = my = ty = 0;
+ wl_list_for_each(c, &clients, link) {
+ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
+ continue;
+ if (i < m->nmaster) {
+ resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw,
+ .height = (m->w.height - my) / (MIN(n, m->nmaster) - i)}, 0);
+ my += c->geom.height;
+ } else {
+ resize(c, (struct wlr_box){.x = m->w.x + mw, .y = m->w.y + ty,
+ .width = m->w.width - mw, .height = (m->w.height - ty) / (n - i)}, 0);
+ ty += c->geom.height;
+ }
+ i++;
+ }
+}
+
+void
+togglebar(const Arg *arg) {
+ DwlIpcOutput *ipc_output;
+ wl_list_for_each(ipc_output, &selmon->dwl_ipc_outputs, link)
+ zdwl_ipc_output_v2_send_toggle_visibility(ipc_output->resource);
+}
+
+void
+togglefloating(const Arg *arg)
+{
+ Client *sel = focustop(selmon);
+ /* return if fullscreen */
+ if (sel && !sel->isfullscreen)
+ setfloating(sel, !sel->isfloating);
+}
+
+void
+togglefullscreen(const Arg *arg)
+{
+ Client *sel = focustop(selmon);
+ if (sel)
+ setfullscreen(sel, !sel->isfullscreen);
+}
+
+void
+toggletag(const Arg *arg)
+{
+ uint32_t newtags;
+ Client *sel = focustop(selmon);
+ if (!sel || !(newtags = sel->tags ^ (arg->ui & TAGMASK)))
+ return;
+
+ sel->tags = newtags;
+ focusclient(focustop(selmon), 1);
+ arrange(selmon);
+ printstatus();
+}
+
+void
+toggleview(const Arg *arg)
+{
+ uint32_t newtagset;
+ if (!(newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0))
+ return;
+
+ selmon->tagset[selmon->seltags] = newtagset;
+ focusclient(focustop(selmon), 1);
+ arrange(selmon);
+ printstatus();
+}
+
+void
+unlocksession(struct wl_listener *listener, void *data)
+{
+ SessionLock *lock = wl_container_of(listener, lock, unlock);
+ destroylock(lock, 1);
+}
+
+void
+unmaplayersurfacenotify(struct wl_listener *listener, void *data)
+{
+ LayerSurface *l = wl_container_of(listener, l, unmap);
+
+ l->mapped = 0;
+ wlr_scene_node_set_enabled(&l->scene->node, 0);
+ if (l == exclusive_focus)
+ exclusive_focus = NULL;
+ if (l->layer_surface->output && (l->mon = l->layer_surface->output->data))
+ arrangelayers(l->mon);
+ if (l->layer_surface->surface == seat->keyboard_state.focused_surface)
+ focusclient(focustop(selmon), 1);
+ motionnotify(0, NULL, 0, 0, 0, 0);
+}
+
+void
+unmapnotify(struct wl_listener *listener, void *data)
+{
+ /* Called when the surface is unmapped, and should no longer be shown. */
+ Client *c = wl_container_of(listener, c, unmap);
+ if (c == grabc) {
+ cursor_mode = CurNormal;
+ grabc = NULL;
+ }
+
+ if (c->swallowedby) {
+ swallow(c->swallowedby, c);
+ }
+
+ if (client_is_unmanaged(c)) {
+ if (c == exclusive_focus) {
+ exclusive_focus = NULL;
+ focusclient(focustop(selmon), 1);
+ }
+ } else {
+ if (!c->swallowing)
+ wl_list_remove(&c->link);
+ setmon(c, NULL, 0);
+ if (!c->swallowing)
+ wl_list_remove(&c->flink);
+ }
+
+ if (c->swallowedby) {
+ c->swallowedby->prev = c->geom;
+ setfullscreen(c->swallowedby, c->isfullscreen);
+ c->swallowedby->swallowing = NULL;
+ c->swallowedby = NULL;
+ }
+
+ if (c->swallowing) {
+ c->swallowing->swallowedby = NULL;
+ c->swallowing = NULL;
+ }
+
+ wlr_scene_node_destroy(&c->scene->node);
+ printstatus();
+ motionnotify(0, NULL, 0, 0, 0, 0);
+}
+
+void
+updatemons(struct wl_listener *listener, void *data)
+{
+ /*
+ * Called whenever the output layout changes: adding or removing a
+ * monitor, changing an output's mode or position, etc. This is where
+ * the change officially happens and we update geometry, window
+ * positions, focus, and the stored configuration in wlroots'
+ * output-manager implementation.
+ */
+ struct wlr_output_configuration_v1 *config
+ = wlr_output_configuration_v1_create();
+ Client *c;
+ struct wlr_output_configuration_head_v1 *config_head;
+ Monitor *m;
+
+ /* First remove from the layout the disabled monitors */
+ wl_list_for_each(m, &mons, link) {
+ if (m->wlr_output->enabled)
+ continue;
+ config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output);
+ config_head->state.enabled = 0;
+ /* Remove this output from the layout to avoid cursor enter inside it */
+ wlr_output_layout_remove(output_layout, m->wlr_output);
+ closemon(m);
+ m->m = m->w = (struct wlr_box){0};
+ }
+ /* Insert outputs that need to */
+ wl_list_for_each(m, &mons, link) {
+ if (m->wlr_output->enabled
+ && !wlr_output_layout_get(output_layout, m->wlr_output))
+ wlr_output_layout_add_auto(output_layout, m->wlr_output);
+ }
+
+ /* Now that we update the output layout we can get its box */
+ wlr_output_layout_get_box(output_layout, NULL, &sgeom);
+
+ wlr_scene_node_set_position(&root_bg->node, sgeom.x, sgeom.y);
+ wlr_scene_rect_set_size(root_bg, sgeom.width, sgeom.height);
+
+ /* Make sure the clients are hidden when dwl is locked */
+ wlr_scene_node_set_position(&locked_bg->node, sgeom.x, sgeom.y);
+ wlr_scene_rect_set_size(locked_bg, sgeom.width, sgeom.height);
+
+ wl_list_for_each(m, &mons, link) {
+ if (!m->wlr_output->enabled)
+ continue;
+ config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output);
+
+ /* Get the effective monitor geometry to use for surfaces */
+ wlr_output_layout_get_box(output_layout, m->wlr_output, &m->m);
+ m->w = m->m;
+ wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y);
+
+ wlr_scene_node_set_position(&m->fullscreen_bg->node, m->m.x, m->m.y);
+ wlr_scene_rect_set_size(m->fullscreen_bg, m->m.width, m->m.height);
+
+ if (m->lock_surface) {
+ struct wlr_scene_tree *scene_tree = m->lock_surface->surface->data;
+ wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y);
+ wlr_session_lock_surface_v1_configure(m->lock_surface, m->m.width, m->m.height);
+ }
+
+ /* Calculate the effective monitor geometry to use for clients */
+ arrangelayers(m);
+ /* Don't move clients to the left output when plugging monitors */
+ arrange(m);
+ /* make sure fullscreen clients have the right size */
+ if ((c = focustop(m)) && c->isfullscreen)
+ resize(c, m->m, 0);
+
+ /* Try to re-set the gamma LUT when updating monitors,
+ * it's only really needed when enabling a disabled output, but meh. */
+ m->gamma_lut_changed = 1;
+
+ config_head->state.x = m->m.x;
+ config_head->state.y = m->m.y;
+ }
+
+ if (selmon && selmon->wlr_output->enabled) {
+ wl_list_for_each(c, &clients, link) {
+ if (!c->mon && client_surface(c)->mapped)
+ setmon(c, selmon, c->tags);
+ }
+ focusclient(focustop(selmon), 1);
+ if (selmon->lock_surface) {
+ client_notify_enter(selmon->lock_surface->surface,
+ wlr_seat_get_keyboard(seat));
+ client_activate_surface(selmon->lock_surface->surface, 1);
+ }
+ }
+
+ /* FIXME: figure out why the cursor image is at 0,0 after turning all
+ * the monitors on.
+ * Move the cursor image where it used to be. It does not generate a
+ * wl_pointer.motion event for the clients, it's only the image what it's
+ * at the wrong position after all. */
+ wlr_cursor_move(cursor, NULL, 0, 0);
+
+ wlr_output_manager_v1_set_configuration(output_mgr, config);
+}
+
+void
+updatetitle(struct wl_listener *listener, void *data)
+{
+ Client *c = wl_container_of(listener, c, set_title);
+ if (c == focustop(c->mon))
+ printstatus();
+}
+
+void
+urgent(struct wl_listener *listener, void *data)
+{
+ struct wlr_xdg_activation_v1_request_activate_event *event = data;
+ Client *c = NULL;
+ toplevel_from_wlr_surface(event->surface, &c, NULL);
+ if (!c || c == focustop(selmon))
+ return;
+
+ c->isurgent = 1;
+ printstatus();
+
+ if (client_surface(c)->mapped)
+ client_set_border_color(c, urgentcolor);
+}
+
+void
+view(const Arg *arg)
+{
+ if (!selmon || (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
+ return;
+ selmon->seltags ^= 1; /* toggle sel tagset */
+ if (arg->ui & TAGMASK)
+ selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
+ focusclient(focustop(selmon), 1);
+ arrange(selmon);
+ printstatus();
+}
+
+void
+virtualkeyboard(struct wl_listener *listener, void *data)
+{
+ struct wlr_virtual_keyboard_v1 *keyboard = data;
+ /* Set the keymap to match the group keymap */
+ wlr_keyboard_set_keymap(&keyboard->keyboard, vkb_group.wlr_group->keyboard.keymap);
+ wlr_keyboard_set_repeat_info(&keyboard->keyboard, repeat_rate, repeat_delay);
+
+ /* Add the new keyboard to the group */
+ wlr_keyboard_group_add_keyboard(vkb_group.wlr_group, &keyboard->keyboard);
+}
+
+void
+virtualpointer(struct wl_listener *listener, void *data)
+{
+ struct wlr_virtual_pointer_v1_new_pointer_event *event = data;
+ struct wlr_pointer pointer = event->new_pointer->pointer;
+
+ wlr_cursor_attach_input_device(cursor, &pointer.base);
+ if (event->suggested_output)
+ wlr_cursor_map_input_to_output(cursor, &pointer.base, event->suggested_output);
+}
+
+Monitor *
+xytomon(double x, double y)
+{
+ struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y);
+ return o ? o->data : NULL;
+}
+
+void
+xytonode(double x, double y, struct wlr_surface **psurface,
+ Client **pc, LayerSurface **pl, double *nx, double *ny)
+{
+ struct wlr_scene_node *node, *pnode;
+ struct wlr_surface *surface = NULL;
+ Client *c = NULL;
+ LayerSurface *l = NULL;
+ int layer;
+
+ for (layer = NUM_LAYERS - 1; !surface && layer >= 0; layer--) {
+ if (!(node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny)))
+ continue;
+
+ if (node->type == WLR_SCENE_NODE_BUFFER)
+ surface = wlr_scene_surface_try_from_buffer(
+ wlr_scene_buffer_from_node(node))->surface;
+ /* Walk the tree to find a node that knows the client */
+ for (pnode = node; pnode && !c; pnode = &pnode->parent->node)
+ c = pnode->data;
+ if (c && c->type == LayerShell) {
+ c = NULL;
+ l = pnode->data;
+ }
+ }
+
+ if (psurface) *psurface = surface;
+ if (pc) *pc = c;
+ if (pl) *pl = l;
+}
+
+void
+zoom(const Arg *arg)
+{
+ Client *c, *sel = focustop(selmon);
+
+ if (!sel || !selmon || !selmon->lt[selmon->sellt]->arrange || sel->isfloating)
+ return;
+
+ /* Search for the first tiled window that is not sel, marking sel as
+ * NULL if we pass it along the way */
+ wl_list_for_each(c, &clients, link) {
+ if (VISIBLEON(c, selmon) && !c->isfloating) {
+ if (c != sel)
+ break;
+ sel = NULL;
+ }
+ }
+
+ /* Return if no other tiled window was found */
+ if (&c->link == &clients)
+ return;
+
+ /* If we passed sel, move c to the front; otherwise, move sel to the
+ * front */
+ if (!sel)
+ sel = c;
+ wl_list_remove(&sel->link);
+ wl_list_insert(&clients, &sel->link);
+
+ focusclient(sel, 1);
+ arrange(selmon);
+}
+
+#ifdef XWAYLAND
+void
+activatex11(struct wl_listener *listener, void *data)
+{
+ Client *c = wl_container_of(listener, c, activate);
+
+ /* Only "managed" windows can be activated */
+ if (!client_is_unmanaged(c))
+ wlr_xwayland_surface_activate(c->surface.xwayland, 1);
+}
+
+void
+associatex11(struct wl_listener *listener, void *data)
+{
+ Client *c = wl_container_of(listener, c, associate);
+
+ LISTEN(&client_surface(c)->events.map, &c->map, mapnotify);
+ LISTEN(&client_surface(c)->events.unmap, &c->unmap, unmapnotify);
+}
+
+void
+configurex11(struct wl_listener *listener, void *data)
+{
+ Client *c = wl_container_of(listener, c, configure);
+ struct wlr_xwayland_surface_configure_event *event = data;
+ /* TODO: figure out if there is another way to do this */
+ if (!c->mon) {
+ wlr_xwayland_surface_configure(c->surface.xwayland,
+ event->x, event->y, event->width, event->height);
+ return;
+ }
+ if (c->isfloating || client_is_unmanaged(c))
+ resize(c, (struct wlr_box){.x = event->x, .y = event->y,
+ .width = event->width, .height = event->height}, 0);
+ else
+ arrange(c->mon);
+}
+
+void
+createnotifyx11(struct wl_listener *listener, void *data)
+{
+ struct wlr_xwayland_surface *xsurface = data;
+ Client *c;
+
+ /* Allocate a Client for this surface */
+ c = xsurface->data = ecalloc(1, sizeof(*c));
+ c->surface.xwayland = xsurface;
+ c->type = X11;
+ c->bw = borderpx;
+
+ /* Listen to the various events it can emit */
+ LISTEN(&xsurface->events.associate, &c->associate, associatex11);
+ LISTEN(&xsurface->events.destroy, &c->destroy, destroynotify);
+ LISTEN(&xsurface->events.dissociate, &c->dissociate, dissociatex11);
+ LISTEN(&xsurface->events.request_activate, &c->activate, activatex11);
+ LISTEN(&xsurface->events.request_configure, &c->configure, configurex11);
+ LISTEN(&xsurface->events.request_fullscreen, &c->fullscreen, fullscreennotify);
+ LISTEN(&xsurface->events.set_hints, &c->set_hints, sethints);
+ LISTEN(&xsurface->events.set_title, &c->set_title, updatetitle);
+}
+
+void
+dissociatex11(struct wl_listener *listener, void *data)
+{
+ Client *c = wl_container_of(listener, c, dissociate);
+ wl_list_remove(&c->map.link);
+ wl_list_remove(&c->unmap.link);
+}
+
+xcb_atom_t
+getatom(xcb_connection_t *xc, const char *name)
+{
+ xcb_atom_t atom = 0;
+ xcb_intern_atom_reply_t *reply;
+ xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xc, 0, strlen(name), name);
+ if ((reply = xcb_intern_atom_reply(xc, cookie, NULL)))
+ atom = reply->atom;
+ free(reply);
+
+ return atom;
+}
+
+void
+sethints(struct wl_listener *listener, void *data)
+{
+ Client *c = wl_container_of(listener, c, set_hints);
+ struct wlr_surface *surface = client_surface(c);
+ if (c == focustop(selmon))
+ return;
+
+ c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints);
+ printstatus();
+
+ if (c->isurgent && surface && surface->mapped)
+ client_set_border_color(c, urgentcolor);
+}
+
+void
+xwaylandready(struct wl_listener *listener, void *data)
+{
+ struct wlr_xcursor *xcursor;
+ xcb_connection_t *xc = xcb_connect(xwayland->display_name, NULL);
+ int err = xcb_connection_has_error(xc);
+ if (err) {
+ fprintf(stderr, "xcb_connect to X server failed with code %d\n. Continuing with degraded functionality.\n", err);
+ return;
+ }
+
+ /* Collect atoms we are interested in. If getatom returns 0, we will
+ * not detect that window type. */
+ netatom[NetWMWindowTypeDialog] = getatom(xc, "_NET_WM_WINDOW_TYPE_DIALOG");
+ netatom[NetWMWindowTypeSplash] = getatom(xc, "_NET_WM_WINDOW_TYPE_SPLASH");
+ netatom[NetWMWindowTypeToolbar] = getatom(xc, "_NET_WM_WINDOW_TYPE_TOOLBAR");
+ netatom[NetWMWindowTypeUtility] = getatom(xc, "_NET_WM_WINDOW_TYPE_UTILITY");
+
+ /* assign the one and only seat */
+ wlr_xwayland_set_seat(xwayland, seat);
+
+ /* Set the default XWayland cursor to match the rest of dwl. */
+ if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "default", 1)))
+ wlr_xwayland_set_cursor(xwayland,
+ xcursor->images[0]->buffer, xcursor->images[0]->width * 4,
+ xcursor->images[0]->width, xcursor->images[0]->height,
+ xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y);
+
+ xcb_disconnect(xc);
+}
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ char *startup_cmd = NULL;
+ int c;
+
+ while ((c = getopt(argc, argv, "s:hdv")) != -1) {
+ if (c == 's')
+ startup_cmd = optarg;
+ else if (c == 'd')
+ log_level = WLR_DEBUG;
+ else if (c == 'v')
+ die("dwl " VERSION);
+ else
+ goto usage;
+ }
+ if (optind < argc)
+ goto usage;
+
+ /* Wayland requires XDG_RUNTIME_DIR for creating its communications socket */
+ if (!getenv("XDG_RUNTIME_DIR"))
+ die("XDG_RUNTIME_DIR must be set");
+ setup();
+ run(startup_cmd);
+ cleanup();
+ return EXIT_SUCCESS;
+
+usage:
+ die("Usage: %s [-v] [-d] [-s startup command]", argv[0]);
+}
diff --git a/dwl/dwl.desktop b/dwl/dwl.desktop
@@ -0,0 +1,5 @@
+[Desktop Entry]
+Name=dwl
+Comment=dwm for Wayland
+Exec=dwl
+Type=Application
diff --git a/dwl/pointer-constraints-unstable-v1-protocol.h b/dwl/pointer-constraints-unstable-v1-protocol.h
@@ -0,0 +1,577 @@
+/* Generated by wayland-scanner 1.22.0 */
+
+#ifndef POINTER_CONSTRAINTS_UNSTABLE_V1_SERVER_PROTOCOL_H
+#define POINTER_CONSTRAINTS_UNSTABLE_V1_SERVER_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-server.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct wl_client;
+struct wl_resource;
+
+/**
+ * @page page_pointer_constraints_unstable_v1 The pointer_constraints_unstable_v1 protocol
+ * protocol for constraining pointer motions
+ *
+ * @section page_desc_pointer_constraints_unstable_v1 Description
+ *
+ * This protocol specifies a set of interfaces used for adding constraints to
+ * the motion of a pointer. Possible constraints include confining pointer
+ * motions to a given region, or locking it to its current position.
+ *
+ * In order to constrain the pointer, a client must first bind the global
+ * interface "wp_pointer_constraints" which, if a compositor supports pointer
+ * constraints, is exposed by the registry. Using the bound global object, the
+ * client uses the request that corresponds to the type of constraint it wants
+ * to make. See wp_pointer_constraints for more details.
+ *
+ * Warning! The protocol described in this file is experimental and backward
+ * incompatible changes may be made. Backward compatible changes may be added
+ * together with the corresponding interface version bump. Backward
+ * incompatible changes are done by bumping the version number in the protocol
+ * and interface names and resetting the interface version. Once the protocol
+ * is to be declared stable, the 'z' prefix and the version number in the
+ * protocol and interface names are removed and the interface version number is
+ * reset.
+ *
+ * @section page_ifaces_pointer_constraints_unstable_v1 Interfaces
+ * - @subpage page_iface_zwp_pointer_constraints_v1 - constrain the movement of a pointer
+ * - @subpage page_iface_zwp_locked_pointer_v1 - receive relative pointer motion events
+ * - @subpage page_iface_zwp_confined_pointer_v1 - confined pointer object
+ * @section page_copyright_pointer_constraints_unstable_v1 Copyright
+ * <pre>
+ *
+ * Copyright © 2014 Jonas Ådahl
+ * Copyright © 2015 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * </pre>
+ */
+struct wl_pointer;
+struct wl_region;
+struct wl_surface;
+struct zwp_confined_pointer_v1;
+struct zwp_locked_pointer_v1;
+struct zwp_pointer_constraints_v1;
+
+#ifndef ZWP_POINTER_CONSTRAINTS_V1_INTERFACE
+#define ZWP_POINTER_CONSTRAINTS_V1_INTERFACE
+/**
+ * @page page_iface_zwp_pointer_constraints_v1 zwp_pointer_constraints_v1
+ * @section page_iface_zwp_pointer_constraints_v1_desc Description
+ *
+ * The global interface exposing pointer constraining functionality. It
+ * exposes two requests: lock_pointer for locking the pointer to its
+ * position, and confine_pointer for locking the pointer to a region.
+ *
+ * The lock_pointer and confine_pointer requests create the objects
+ * wp_locked_pointer and wp_confined_pointer respectively, and the client can
+ * use these objects to interact with the lock.
+ *
+ * For any surface, only one lock or confinement may be active across all
+ * wl_pointer objects of the same seat. If a lock or confinement is requested
+ * when another lock or confinement is active or requested on the same surface
+ * and with any of the wl_pointer objects of the same seat, an
+ * 'already_constrained' error will be raised.
+ * @section page_iface_zwp_pointer_constraints_v1_api API
+ * See @ref iface_zwp_pointer_constraints_v1.
+ */
+/**
+ * @defgroup iface_zwp_pointer_constraints_v1 The zwp_pointer_constraints_v1 interface
+ *
+ * The global interface exposing pointer constraining functionality. It
+ * exposes two requests: lock_pointer for locking the pointer to its
+ * position, and confine_pointer for locking the pointer to a region.
+ *
+ * The lock_pointer and confine_pointer requests create the objects
+ * wp_locked_pointer and wp_confined_pointer respectively, and the client can
+ * use these objects to interact with the lock.
+ *
+ * For any surface, only one lock or confinement may be active across all
+ * wl_pointer objects of the same seat. If a lock or confinement is requested
+ * when another lock or confinement is active or requested on the same surface
+ * and with any of the wl_pointer objects of the same seat, an
+ * 'already_constrained' error will be raised.
+ */
+extern const struct wl_interface zwp_pointer_constraints_v1_interface;
+#endif
+#ifndef ZWP_LOCKED_POINTER_V1_INTERFACE
+#define ZWP_LOCKED_POINTER_V1_INTERFACE
+/**
+ * @page page_iface_zwp_locked_pointer_v1 zwp_locked_pointer_v1
+ * @section page_iface_zwp_locked_pointer_v1_desc Description
+ *
+ * The wp_locked_pointer interface represents a locked pointer state.
+ *
+ * While the lock of this object is active, the wl_pointer objects of the
+ * associated seat will not emit any wl_pointer.motion events.
+ *
+ * This object will send the event 'locked' when the lock is activated.
+ * Whenever the lock is activated, it is guaranteed that the locked surface
+ * will already have received pointer focus and that the pointer will be
+ * within the region passed to the request creating this object.
+ *
+ * To unlock the pointer, send the destroy request. This will also destroy
+ * the wp_locked_pointer object.
+ *
+ * If the compositor decides to unlock the pointer the unlocked event is
+ * sent. See wp_locked_pointer.unlock for details.
+ *
+ * When unlocking, the compositor may warp the cursor position to the set
+ * cursor position hint. If it does, it will not result in any relative
+ * motion events emitted via wp_relative_pointer.
+ *
+ * If the surface the lock was requested on is destroyed and the lock is not
+ * yet activated, the wp_locked_pointer object is now defunct and must be
+ * destroyed.
+ * @section page_iface_zwp_locked_pointer_v1_api API
+ * See @ref iface_zwp_locked_pointer_v1.
+ */
+/**
+ * @defgroup iface_zwp_locked_pointer_v1 The zwp_locked_pointer_v1 interface
+ *
+ * The wp_locked_pointer interface represents a locked pointer state.
+ *
+ * While the lock of this object is active, the wl_pointer objects of the
+ * associated seat will not emit any wl_pointer.motion events.
+ *
+ * This object will send the event 'locked' when the lock is activated.
+ * Whenever the lock is activated, it is guaranteed that the locked surface
+ * will already have received pointer focus and that the pointer will be
+ * within the region passed to the request creating this object.
+ *
+ * To unlock the pointer, send the destroy request. This will also destroy
+ * the wp_locked_pointer object.
+ *
+ * If the compositor decides to unlock the pointer the unlocked event is
+ * sent. See wp_locked_pointer.unlock for details.
+ *
+ * When unlocking, the compositor may warp the cursor position to the set
+ * cursor position hint. If it does, it will not result in any relative
+ * motion events emitted via wp_relative_pointer.
+ *
+ * If the surface the lock was requested on is destroyed and the lock is not
+ * yet activated, the wp_locked_pointer object is now defunct and must be
+ * destroyed.
+ */
+extern const struct wl_interface zwp_locked_pointer_v1_interface;
+#endif
+#ifndef ZWP_CONFINED_POINTER_V1_INTERFACE
+#define ZWP_CONFINED_POINTER_V1_INTERFACE
+/**
+ * @page page_iface_zwp_confined_pointer_v1 zwp_confined_pointer_v1
+ * @section page_iface_zwp_confined_pointer_v1_desc Description
+ *
+ * The wp_confined_pointer interface represents a confined pointer state.
+ *
+ * This object will send the event 'confined' when the confinement is
+ * activated. Whenever the confinement is activated, it is guaranteed that
+ * the surface the pointer is confined to will already have received pointer
+ * focus and that the pointer will be within the region passed to the request
+ * creating this object. It is up to the compositor to decide whether this
+ * requires some user interaction and if the pointer will warp to within the
+ * passed region if outside.
+ *
+ * To unconfine the pointer, send the destroy request. This will also destroy
+ * the wp_confined_pointer object.
+ *
+ * If the compositor decides to unconfine the pointer the unconfined event is
+ * sent. The wp_confined_pointer object is at this point defunct and should
+ * be destroyed.
+ * @section page_iface_zwp_confined_pointer_v1_api API
+ * See @ref iface_zwp_confined_pointer_v1.
+ */
+/**
+ * @defgroup iface_zwp_confined_pointer_v1 The zwp_confined_pointer_v1 interface
+ *
+ * The wp_confined_pointer interface represents a confined pointer state.
+ *
+ * This object will send the event 'confined' when the confinement is
+ * activated. Whenever the confinement is activated, it is guaranteed that
+ * the surface the pointer is confined to will already have received pointer
+ * focus and that the pointer will be within the region passed to the request
+ * creating this object. It is up to the compositor to decide whether this
+ * requires some user interaction and if the pointer will warp to within the
+ * passed region if outside.
+ *
+ * To unconfine the pointer, send the destroy request. This will also destroy
+ * the wp_confined_pointer object.
+ *
+ * If the compositor decides to unconfine the pointer the unconfined event is
+ * sent. The wp_confined_pointer object is at this point defunct and should
+ * be destroyed.
+ */
+extern const struct wl_interface zwp_confined_pointer_v1_interface;
+#endif
+
+#ifndef ZWP_POINTER_CONSTRAINTS_V1_ERROR_ENUM
+#define ZWP_POINTER_CONSTRAINTS_V1_ERROR_ENUM
+/**
+ * @ingroup iface_zwp_pointer_constraints_v1
+ * wp_pointer_constraints error values
+ *
+ * These errors can be emitted in response to wp_pointer_constraints
+ * requests.
+ */
+enum zwp_pointer_constraints_v1_error {
+ /**
+ * pointer constraint already requested on that surface
+ */
+ ZWP_POINTER_CONSTRAINTS_V1_ERROR_ALREADY_CONSTRAINED = 1,
+};
+#endif /* ZWP_POINTER_CONSTRAINTS_V1_ERROR_ENUM */
+
+#ifndef ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ENUM
+#define ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ENUM
+/**
+ * @ingroup iface_zwp_pointer_constraints_v1
+ * constraint lifetime
+ *
+ * These values represent different lifetime semantics. They are passed
+ * as arguments to the factory requests to specify how the constraint
+ * lifetimes should be managed.
+ */
+enum zwp_pointer_constraints_v1_lifetime {
+ /**
+ * the pointer constraint is defunct once deactivated
+ *
+ * A oneshot pointer constraint will never reactivate once it has
+ * been deactivated. See the corresponding deactivation event
+ * (wp_locked_pointer.unlocked and wp_confined_pointer.unconfined)
+ * for details.
+ */
+ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT = 1,
+ /**
+ * the pointer constraint may reactivate
+ *
+ * A persistent pointer constraint may again reactivate once it
+ * has been deactivated. See the corresponding deactivation event
+ * (wp_locked_pointer.unlocked and wp_confined_pointer.unconfined)
+ * for details.
+ */
+ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT = 2,
+};
+#endif /* ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ENUM */
+
+/**
+ * @ingroup iface_zwp_pointer_constraints_v1
+ * @struct zwp_pointer_constraints_v1_interface
+ */
+struct zwp_pointer_constraints_v1_interface {
+ /**
+ * destroy the pointer constraints manager object
+ *
+ * Used by the client to notify the server that it will no longer
+ * use this pointer constraints object.
+ */
+ void (*destroy)(struct wl_client *client,
+ struct wl_resource *resource);
+ /**
+ * lock pointer to a position
+ *
+ * The lock_pointer request lets the client request to disable
+ * movements of the virtual pointer (i.e. the cursor), effectively
+ * locking the pointer to a position. This request may not take
+ * effect immediately; in the future, when the compositor deems
+ * implementation-specific constraints are satisfied, the pointer
+ * lock will be activated and the compositor sends a locked event.
+ *
+ * The protocol provides no guarantee that the constraints are ever
+ * satisfied, and does not require the compositor to send an error
+ * if the constraints cannot ever be satisfied. It is thus possible
+ * to request a lock that will never activate.
+ *
+ * There may not be another pointer constraint of any kind
+ * requested or active on the surface for any of the wl_pointer
+ * objects of the seat of the passed pointer when requesting a
+ * lock. If there is, an error will be raised. See general pointer
+ * lock documentation for more details.
+ *
+ * The intersection of the region passed with this request and the
+ * input region of the surface is used to determine where the
+ * pointer must be in order for the lock to activate. It is up to
+ * the compositor whether to warp the pointer or require some kind
+ * of user interaction for the lock to activate. If the region is
+ * null the surface input region is used.
+ *
+ * A surface may receive pointer focus without the lock being
+ * activated.
+ *
+ * The request creates a new object wp_locked_pointer which is used
+ * to interact with the lock as well as receive updates about its
+ * state. See the the description of wp_locked_pointer for further
+ * information.
+ *
+ * Note that while a pointer is locked, the wl_pointer objects of
+ * the corresponding seat will not emit any wl_pointer.motion
+ * events, but relative motion events will still be emitted via
+ * wp_relative_pointer objects of the same seat. wl_pointer.axis
+ * and wl_pointer.button events are unaffected.
+ * @param surface surface to lock pointer to
+ * @param pointer the pointer that should be locked
+ * @param region region of surface
+ * @param lifetime lock lifetime
+ */
+ void (*lock_pointer)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id,
+ struct wl_resource *surface,
+ struct wl_resource *pointer,
+ struct wl_resource *region,
+ uint32_t lifetime);
+ /**
+ * confine pointer to a region
+ *
+ * The confine_pointer request lets the client request to confine
+ * the pointer cursor to a given region. This request may not take
+ * effect immediately; in the future, when the compositor deems
+ * implementation- specific constraints are satisfied, the pointer
+ * confinement will be activated and the compositor sends a
+ * confined event.
+ *
+ * The intersection of the region passed with this request and the
+ * input region of the surface is used to determine where the
+ * pointer must be in order for the confinement to activate. It is
+ * up to the compositor whether to warp the pointer or require some
+ * kind of user interaction for the confinement to activate. If the
+ * region is null the surface input region is used.
+ *
+ * The request will create a new object wp_confined_pointer which
+ * is used to interact with the confinement as well as receive
+ * updates about its state. See the the description of
+ * wp_confined_pointer for further information.
+ * @param surface surface to lock pointer to
+ * @param pointer the pointer that should be confined
+ * @param region region of surface
+ * @param lifetime confinement lifetime
+ */
+ void (*confine_pointer)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id,
+ struct wl_resource *surface,
+ struct wl_resource *pointer,
+ struct wl_resource *region,
+ uint32_t lifetime);
+};
+
+
+/**
+ * @ingroup iface_zwp_pointer_constraints_v1
+ */
+#define ZWP_POINTER_CONSTRAINTS_V1_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_pointer_constraints_v1
+ */
+#define ZWP_POINTER_CONSTRAINTS_V1_LOCK_POINTER_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_pointer_constraints_v1
+ */
+#define ZWP_POINTER_CONSTRAINTS_V1_CONFINE_POINTER_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_locked_pointer_v1
+ * @struct zwp_locked_pointer_v1_interface
+ */
+struct zwp_locked_pointer_v1_interface {
+ /**
+ * destroy the locked pointer object
+ *
+ * Destroy the locked pointer object. If applicable, the
+ * compositor will unlock the pointer.
+ */
+ void (*destroy)(struct wl_client *client,
+ struct wl_resource *resource);
+ /**
+ * set the pointer cursor position hint
+ *
+ * Set the cursor position hint relative to the top left corner
+ * of the surface.
+ *
+ * If the client is drawing its own cursor, it should update the
+ * position hint to the position of its own cursor. A compositor
+ * may use this information to warp the pointer upon unlock in
+ * order to avoid pointer jumps.
+ *
+ * The cursor position hint is double buffered. The new hint will
+ * only take effect when the associated surface gets it pending
+ * state applied. See wl_surface.commit for details.
+ * @param surface_x surface-local x coordinate
+ * @param surface_y surface-local y coordinate
+ */
+ void (*set_cursor_position_hint)(struct wl_client *client,
+ struct wl_resource *resource,
+ wl_fixed_t surface_x,
+ wl_fixed_t surface_y);
+ /**
+ * set a new lock region
+ *
+ * Set a new region used to lock the pointer.
+ *
+ * The new lock region is double-buffered. The new lock region will
+ * only take effect when the associated surface gets its pending
+ * state applied. See wl_surface.commit for details.
+ *
+ * For details about the lock region, see wp_locked_pointer.
+ * @param region region of surface
+ */
+ void (*set_region)(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *region);
+};
+
+#define ZWP_LOCKED_POINTER_V1_LOCKED 0
+#define ZWP_LOCKED_POINTER_V1_UNLOCKED 1
+
+/**
+ * @ingroup iface_zwp_locked_pointer_v1
+ */
+#define ZWP_LOCKED_POINTER_V1_LOCKED_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_locked_pointer_v1
+ */
+#define ZWP_LOCKED_POINTER_V1_UNLOCKED_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_locked_pointer_v1
+ */
+#define ZWP_LOCKED_POINTER_V1_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_locked_pointer_v1
+ */
+#define ZWP_LOCKED_POINTER_V1_SET_CURSOR_POSITION_HINT_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_locked_pointer_v1
+ */
+#define ZWP_LOCKED_POINTER_V1_SET_REGION_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_locked_pointer_v1
+ * Sends an locked event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+zwp_locked_pointer_v1_send_locked(struct wl_resource *resource_)
+{
+ wl_resource_post_event(resource_, ZWP_LOCKED_POINTER_V1_LOCKED);
+}
+
+/**
+ * @ingroup iface_zwp_locked_pointer_v1
+ * Sends an unlocked event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+zwp_locked_pointer_v1_send_unlocked(struct wl_resource *resource_)
+{
+ wl_resource_post_event(resource_, ZWP_LOCKED_POINTER_V1_UNLOCKED);
+}
+
+/**
+ * @ingroup iface_zwp_confined_pointer_v1
+ * @struct zwp_confined_pointer_v1_interface
+ */
+struct zwp_confined_pointer_v1_interface {
+ /**
+ * destroy the confined pointer object
+ *
+ * Destroy the confined pointer object. If applicable, the
+ * compositor will unconfine the pointer.
+ */
+ void (*destroy)(struct wl_client *client,
+ struct wl_resource *resource);
+ /**
+ * set a new confine region
+ *
+ * Set a new region used to confine the pointer.
+ *
+ * The new confine region is double-buffered. The new confine
+ * region will only take effect when the associated surface gets
+ * its pending state applied. See wl_surface.commit for details.
+ *
+ * If the confinement is active when the new confinement region is
+ * applied and the pointer ends up outside of newly applied region,
+ * the pointer may warped to a position within the new confinement
+ * region. If warped, a wl_pointer.motion event will be emitted,
+ * but no wp_relative_pointer.relative_motion event.
+ *
+ * The compositor may also, instead of using the new region,
+ * unconfine the pointer.
+ *
+ * For details about the confine region, see wp_confined_pointer.
+ * @param region region of surface
+ */
+ void (*set_region)(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *region);
+};
+
+#define ZWP_CONFINED_POINTER_V1_CONFINED 0
+#define ZWP_CONFINED_POINTER_V1_UNCONFINED 1
+
+/**
+ * @ingroup iface_zwp_confined_pointer_v1
+ */
+#define ZWP_CONFINED_POINTER_V1_CONFINED_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_confined_pointer_v1
+ */
+#define ZWP_CONFINED_POINTER_V1_UNCONFINED_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_confined_pointer_v1
+ */
+#define ZWP_CONFINED_POINTER_V1_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_confined_pointer_v1
+ */
+#define ZWP_CONFINED_POINTER_V1_SET_REGION_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwp_confined_pointer_v1
+ * Sends an confined event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+zwp_confined_pointer_v1_send_confined(struct wl_resource *resource_)
+{
+ wl_resource_post_event(resource_, ZWP_CONFINED_POINTER_V1_CONFINED);
+}
+
+/**
+ * @ingroup iface_zwp_confined_pointer_v1
+ * Sends an unconfined event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+zwp_confined_pointer_v1_send_unconfined(struct wl_resource *resource_)
+{
+ wl_resource_post_event(resource_, ZWP_CONFINED_POINTER_V1_UNCONFINED);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/dwl/protocols/dwl-ipc-unstable-v2.xml b/dwl/protocols/dwl-ipc-unstable-v2.xml
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+This is largely ripped from somebar's ipc patchset; just with some personal modifications.
+I would probably just submit raphi's patchset but I don't think that would be polite.
+-->
+<protocol name="dwl_ipc_unstable_v2">
+ <description summary="inter-proccess-communication about dwl's state">
+ This protocol allows clients to update and get updates from dwl.
+
+ Warning! The protocol described in this file is experimental and
+ backward incompatible changes may be made. Backward compatible
+ changes may be added together with the corresponding interface
+ version bump.
+ Backward incompatible changes are done by bumping the version
+ number in the protocol and interface names and resetting the
+ interface version. Once the protocol is to be declared stable,
+ the 'z' prefix and the version number in the protocol and
+ interface names are removed and the interface version number is
+ reset.
+ </description>
+
+ <interface name="zdwl_ipc_manager_v2" version="2">
+ <description summary="manage dwl state">
+ This interface is exposed as a global in wl_registry.
+
+ Clients can use this interface to get a dwl_ipc_output.
+ After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events.
+ The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client.
+ </description>
+
+ <request name="release" type="destructor">
+ <description summary="release dwl_ipc_manager">
+ Indicates that the client will not the dwl_ipc_manager object anymore.
+ Objects created through this instance are not affected.
+ </description>
+ </request>
+
+ <request name="get_output">
+ <description summary="get a dwl_ipc_outout for a wl_output">
+ Get a dwl_ipc_outout for the specified wl_output.
+ </description>
+ <arg name="id" type="new_id" interface="zdwl_ipc_output_v2"/>
+ <arg name="output" type="object" interface="wl_output"/>
+ </request>
+
+ <event name="tags">
+ <description summary="Announces tag amount">
+ This event is sent after binding.
+ A roundtrip after binding guarantees the client recieved all tags.
+ </description>
+ <arg name="amount" type="uint"/>
+ </event>
+
+ <event name="layout">
+ <description summary="Announces a layout">
+ This event is sent after binding.
+ A roundtrip after binding guarantees the client recieved all layouts.
+ </description>
+ <arg name="name" type="string"/>
+ </event>
+ </interface>
+
+ <interface name="zdwl_ipc_output_v2" version="2">
+ <description summary="control dwl output">
+ Observe and control a dwl output.
+
+ Events are double-buffered:
+ Clients should cache events and redraw when a dwl_ipc_output.frame event is sent.
+
+ Request are not double-buffered:
+ The compositor will update immediately upon request.
+ </description>
+
+ <enum name="tag_state">
+ <entry name="none" value="0" summary="no state"/>
+ <entry name="active" value="1" summary="tag is active"/>
+ <entry name="urgent" value="2" summary="tag has at least one urgent client"/>
+ </enum>
+
+ <request name="release" type="destructor">
+ <description summary="release dwl_ipc_outout">
+ Indicates to that the client no longer needs this dwl_ipc_output.
+ </description>
+ </request>
+
+ <event name="toggle_visibility">
+ <description summary="Toggle client visibilty">
+ Indicates the client should hide or show themselves.
+ If the client is visible then hide, if hidden then show.
+ </description>
+ </event>
+
+ <event name="active">
+ <description summary="Update the selected output.">
+ Indicates if the output is active. Zero is invalid, nonzero is valid.
+ </description>
+ <arg name="active" type="uint"/>
+ </event>
+
+ <event name="tag">
+ <description summary="Update the state of a tag.">
+ Indicates that a tag has been updated.
+ </description>
+ <arg name="tag" type="uint" summary="Index of the tag"/>
+ <arg name="state" type="uint" enum="tag_state" summary="The state of the tag."/>
+ <arg name="clients" type="uint" summary="The number of clients in the tag."/>
+ <arg name="focused" type="uint" summary="If there is a focused client. Nonzero being valid, zero being invalid."/>
+ </event>
+
+ <event name="layout">
+ <description summary="Update the layout.">
+ Indicates a new layout is selected.
+ </description>
+ <arg name="layout" type="uint" summary="Index of the layout."/>
+ </event>
+
+ <event name="title">
+ <description summary="Update the title.">
+ Indicates the title has changed.
+ </description>
+ <arg name="title" type="string" summary="The new title name."/>
+ </event>
+
+ <event name="appid" since="1">
+ <description summary="Update the appid.">
+ Indicates the appid has changed.
+ </description>
+ <arg name="appid" type="string" summary="The new appid."/>
+ </event>
+
+ <event name="layout_symbol" since="1">
+ <description summary="Update the current layout symbol">
+ Indicates the layout has changed. Since layout symbols are dynamic.
+ As opposed to the zdwl_ipc_manager.layout event, this should take precendence when displaying.
+ You can ignore the zdwl_ipc_output.layout event.
+ </description>
+ <arg name="layout" type="string" summary="The new layout"/>
+ </event>
+
+ <event name="frame">
+ <description summary="The update sequence is done.">
+ Indicates that a sequence of status updates have finished and the client should redraw.
+ </description>
+ </event>
+
+ <request name="set_tags">
+ <description summary="Set the active tags of this output"/>
+ <arg name="tagmask" type="uint" summary="bitmask of the tags that should be set."/>
+ <arg name="toggle_tagset" type="uint" summary="toggle the selected tagset, zero for invalid, nonzero for valid."/>
+ </request>
+
+ <request name="set_client_tags">
+ <description summary="Set the tags of the focused client.">
+ The tags are updated as follows:
+ new_tags = (current_tags AND and_tags) XOR xor_tags
+ </description>
+ <arg name="and_tags" type="uint"/>
+ <arg name="xor_tags" type="uint"/>
+ </request>
+
+ <request name="set_layout">
+ <description summary="Set the layout of this output"/>
+ <arg name="index" type="uint" summary="index of a layout recieved by dwl_ipc_manager.layout"/>
+ </request>
+
+ <!-- Version 2 -->
+ <event name="fullscreen" since="2">
+ <description summary="Update fullscreen status">
+ Indicates if the selected client on this output is fullscreen.
+ </description>
+ <arg name="is_fullscreen" type="uint" summary="If the selected client is fullscreen. Nonzero is valid, zero invalid"/>
+ </event>
+
+ <event name="floating" since="2">
+ <description summary="Update the floating status">
+ Indicates if the selected client on this output is floating.
+ </description>
+ <arg name="is_floating" type="uint" summary="If the selected client is floating. Nonzero is valid, zero invalid"/>
+ </event>
+ </interface>
+</protocol>
diff --git a/dwl/protocols/wlr-layer-shell-unstable-v1.xml b/dwl/protocols/wlr-layer-shell-unstable-v1.xml
@@ -0,0 +1,390 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="wlr_layer_shell_unstable_v1">
+ <copyright>
+ Copyright © 2017 Drew DeVault
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, provided that the above copyright notice appear in
+ all copies and that both that copyright notice and this permission
+ notice appear in supporting documentation, and that the name of
+ the copyright holders not be used in advertising or publicity
+ pertaining to distribution of the software without specific,
+ written prior permission. The copyright holders make no
+ representations about the suitability of this software for any
+ purpose. It is provided "as is" without express or implied
+ warranty.
+
+ THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ THIS SOFTWARE.
+ </copyright>
+
+ <interface name="zwlr_layer_shell_v1" version="4">
+ <description summary="create surfaces that are layers of the desktop">
+ Clients can use this interface to assign the surface_layer role to
+ wl_surfaces. Such surfaces are assigned to a "layer" of the output and
+ rendered with a defined z-depth respective to each other. They may also be
+ anchored to the edges and corners of a screen and specify input handling
+ semantics. This interface should be suitable for the implementation of
+ many desktop shell components, and a broad number of other applications
+ that interact with the desktop.
+ </description>
+
+ <request name="get_layer_surface">
+ <description summary="create a layer_surface from a surface">
+ Create a layer surface for an existing surface. This assigns the role of
+ layer_surface, or raises a protocol error if another role is already
+ assigned.
+
+ Creating a layer surface from a wl_surface which has a buffer attached
+ or committed is a client error, and any attempts by a client to attach
+ or manipulate a buffer prior to the first layer_surface.configure call
+ must also be treated as errors.
+
+ After creating a layer_surface object and setting it up, the client
+ must perform an initial commit without any buffer attached.
+ The compositor will reply with a layer_surface.configure event.
+ The client must acknowledge it and is then allowed to attach a buffer
+ to map the surface.
+
+ You may pass NULL for output to allow the compositor to decide which
+ output to use. Generally this will be the one that the user most
+ recently interacted with.
+
+ Clients can specify a namespace that defines the purpose of the layer
+ surface.
+ </description>
+ <arg name="id" type="new_id" interface="zwlr_layer_surface_v1"/>
+ <arg name="surface" type="object" interface="wl_surface"/>
+ <arg name="output" type="object" interface="wl_output" allow-null="true"/>
+ <arg name="layer" type="uint" enum="layer" summary="layer to add this surface to"/>
+ <arg name="namespace" type="string" summary="namespace for the layer surface"/>
+ </request>
+
+ <enum name="error">
+ <entry name="role" value="0" summary="wl_surface has another role"/>
+ <entry name="invalid_layer" value="1" summary="layer value is invalid"/>
+ <entry name="already_constructed" value="2" summary="wl_surface has a buffer attached or committed"/>
+ </enum>
+
+ <enum name="layer">
+ <description summary="available layers for surfaces">
+ These values indicate which layers a surface can be rendered in. They
+ are ordered by z depth, bottom-most first. Traditional shell surfaces
+ will typically be rendered between the bottom and top layers.
+ Fullscreen shell surfaces are typically rendered at the top layer.
+ Multiple surfaces can share a single layer, and ordering within a
+ single layer is undefined.
+ </description>
+
+ <entry name="background" value="0"/>
+ <entry name="bottom" value="1"/>
+ <entry name="top" value="2"/>
+ <entry name="overlay" value="3"/>
+ </enum>
+
+ <!-- Version 3 additions -->
+
+ <request name="destroy" type="destructor" since="3">
+ <description summary="destroy the layer_shell object">
+ This request indicates that the client will not use the layer_shell
+ object any more. Objects that have been created through this instance
+ are not affected.
+ </description>
+ </request>
+ </interface>
+
+ <interface name="zwlr_layer_surface_v1" version="4">
+ <description summary="layer metadata interface">
+ An interface that may be implemented by a wl_surface, for surfaces that
+ are designed to be rendered as a layer of a stacked desktop-like
+ environment.
+
+ Layer surface state (layer, size, anchor, exclusive zone,
+ margin, interactivity) is double-buffered, and will be applied at the
+ time wl_surface.commit of the corresponding wl_surface is called.
+
+ Attaching a null buffer to a layer surface unmaps it.
+
+ Unmapping a layer_surface means that the surface cannot be shown by the
+ compositor until it is explicitly mapped again. The layer_surface
+ returns to the state it had right after layer_shell.get_layer_surface.
+ The client can re-map the surface by performing a commit without any
+ buffer attached, waiting for a configure event and handling it as usual.
+ </description>
+
+ <request name="set_size">
+ <description summary="sets the size of the surface">
+ Sets the size of the surface in surface-local coordinates. The
+ compositor will display the surface centered with respect to its
+ anchors.
+
+ If you pass 0 for either value, the compositor will assign it and
+ inform you of the assignment in the configure event. You must set your
+ anchor to opposite edges in the dimensions you omit; not doing so is a
+ protocol error. Both values are 0 by default.
+
+ Size is double-buffered, see wl_surface.commit.
+ </description>
+ <arg name="width" type="uint"/>
+ <arg name="height" type="uint"/>
+ </request>
+
+ <request name="set_anchor">
+ <description summary="configures the anchor point of the surface">
+ Requests that the compositor anchor the surface to the specified edges
+ and corners. If two orthogonal edges are specified (e.g. 'top' and
+ 'left'), then the anchor point will be the intersection of the edges
+ (e.g. the top left corner of the output); otherwise the anchor point
+ will be centered on that edge, or in the center if none is specified.
+
+ Anchor is double-buffered, see wl_surface.commit.
+ </description>
+ <arg name="anchor" type="uint" enum="anchor"/>
+ </request>
+
+ <request name="set_exclusive_zone">
+ <description summary="configures the exclusive geometry of this surface">
+ Requests that the compositor avoids occluding an area with other
+ surfaces. The compositor's use of this information is
+ implementation-dependent - do not assume that this region will not
+ actually be occluded.
+
+ A positive value is only meaningful if the surface is anchored to one
+ edge or an edge and both perpendicular edges. If the surface is not
+ anchored, anchored to only two perpendicular edges (a corner), anchored
+ to only two parallel edges or anchored to all edges, a positive value
+ will be treated the same as zero.
+
+ A positive zone is the distance from the edge in surface-local
+ coordinates to consider exclusive.
+
+ Surfaces that do not wish to have an exclusive zone may instead specify
+ how they should interact with surfaces that do. If set to zero, the
+ surface indicates that it would like to be moved to avoid occluding
+ surfaces with a positive exclusive zone. If set to -1, the surface
+ indicates that it would not like to be moved to accommodate for other
+ surfaces, and the compositor should extend it all the way to the edges
+ it is anchored to.
+
+ For example, a panel might set its exclusive zone to 10, so that
+ maximized shell surfaces are not shown on top of it. A notification
+ might set its exclusive zone to 0, so that it is moved to avoid
+ occluding the panel, but shell surfaces are shown underneath it. A
+ wallpaper or lock screen might set their exclusive zone to -1, so that
+ they stretch below or over the panel.
+
+ The default value is 0.
+
+ Exclusive zone is double-buffered, see wl_surface.commit.
+ </description>
+ <arg name="zone" type="int"/>
+ </request>
+
+ <request name="set_margin">
+ <description summary="sets a margin from the anchor point">
+ Requests that the surface be placed some distance away from the anchor
+ point on the output, in surface-local coordinates. Setting this value
+ for edges you are not anchored to has no effect.
+
+ The exclusive zone includes the margin.
+
+ Margin is double-buffered, see wl_surface.commit.
+ </description>
+ <arg name="top" type="int"/>
+ <arg name="right" type="int"/>
+ <arg name="bottom" type="int"/>
+ <arg name="left" type="int"/>
+ </request>
+
+ <enum name="keyboard_interactivity">
+ <description summary="types of keyboard interaction possible for a layer shell surface">
+ Types of keyboard interaction possible for layer shell surfaces. The
+ rationale for this is twofold: (1) some applications are not interested
+ in keyboard events and not allowing them to be focused can improve the
+ desktop experience; (2) some applications will want to take exclusive
+ keyboard focus.
+ </description>
+
+ <entry name="none" value="0">
+ <description summary="no keyboard focus is possible">
+ This value indicates that this surface is not interested in keyboard
+ events and the compositor should never assign it the keyboard focus.
+
+ This is the default value, set for newly created layer shell surfaces.
+
+ This is useful for e.g. desktop widgets that display information or
+ only have interaction with non-keyboard input devices.
+ </description>
+ </entry>
+ <entry name="exclusive" value="1">
+ <description summary="request exclusive keyboard focus">
+ Request exclusive keyboard focus if this surface is above the shell surface layer.
+
+ For the top and overlay layers, the seat will always give
+ exclusive keyboard focus to the top-most layer which has keyboard
+ interactivity set to exclusive. If this layer contains multiple
+ surfaces with keyboard interactivity set to exclusive, the compositor
+ determines the one receiving keyboard events in an implementation-
+ defined manner. In this case, no guarantee is made when this surface
+ will receive keyboard focus (if ever).
+
+ For the bottom and background layers, the compositor is allowed to use
+ normal focus semantics.
+
+ This setting is mainly intended for applications that need to ensure
+ they receive all keyboard events, such as a lock screen or a password
+ prompt.
+ </description>
+ </entry>
+ <entry name="on_demand" value="2" since="4">
+ <description summary="request regular keyboard focus semantics">
+ This requests the compositor to allow this surface to be focused and
+ unfocused by the user in an implementation-defined manner. The user
+ should be able to unfocus this surface even regardless of the layer
+ it is on.
+
+ Typically, the compositor will want to use its normal mechanism to
+ manage keyboard focus between layer shell surfaces with this setting
+ and regular toplevels on the desktop layer (e.g. click to focus).
+ Nevertheless, it is possible for a compositor to require a special
+ interaction to focus or unfocus layer shell surfaces (e.g. requiring
+ a click even if focus follows the mouse normally, or providing a
+ keybinding to switch focus between layers).
+
+ This setting is mainly intended for desktop shell components (e.g.
+ panels) that allow keyboard interaction. Using this option can allow
+ implementing a desktop shell that can be fully usable without the
+ mouse.
+ </description>
+ </entry>
+ </enum>
+
+ <request name="set_keyboard_interactivity">
+ <description summary="requests keyboard events">
+ Set how keyboard events are delivered to this surface. By default,
+ layer shell surfaces do not receive keyboard events; this request can
+ be used to change this.
+
+ This setting is inherited by child surfaces set by the get_popup
+ request.
+
+ Layer surfaces receive pointer, touch, and tablet events normally. If
+ you do not want to receive them, set the input region on your surface
+ to an empty region.
+
+ Keyboard interactivity is double-buffered, see wl_surface.commit.
+ </description>
+ <arg name="keyboard_interactivity" type="uint" enum="keyboard_interactivity"/>
+ </request>
+
+ <request name="get_popup">
+ <description summary="assign this layer_surface as an xdg_popup parent">
+ This assigns an xdg_popup's parent to this layer_surface. This popup
+ should have been created via xdg_surface::get_popup with the parent set
+ to NULL, and this request must be invoked before committing the popup's
+ initial state.
+
+ See the documentation of xdg_popup for more details about what an
+ xdg_popup is and how it is used.
+ </description>
+ <arg name="popup" type="object" interface="xdg_popup"/>
+ </request>
+
+ <request name="ack_configure">
+ <description summary="ack a configure event">
+ When a configure event is received, if a client commits the
+ surface in response to the configure event, then the client
+ must make an ack_configure request sometime before the commit
+ request, passing along the serial of the configure event.
+
+ If the client receives multiple configure events before it
+ can respond to one, it only has to ack the last configure event.
+
+ A client is not required to commit immediately after sending
+ an ack_configure request - it may even ack_configure several times
+ before its next surface commit.
+
+ A client may send multiple ack_configure requests before committing, but
+ only the last request sent before a commit indicates which configure
+ event the client really is responding to.
+ </description>
+ <arg name="serial" type="uint" summary="the serial from the configure event"/>
+ </request>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the layer_surface">
+ This request destroys the layer surface.
+ </description>
+ </request>
+
+ <event name="configure">
+ <description summary="suggest a surface change">
+ The configure event asks the client to resize its surface.
+
+ Clients should arrange their surface for the new states, and then send
+ an ack_configure request with the serial sent in this configure event at
+ some point before committing the new surface.
+
+ The client is free to dismiss all but the last configure event it
+ received.
+
+ The width and height arguments specify the size of the window in
+ surface-local coordinates.
+
+ The size is a hint, in the sense that the client is free to ignore it if
+ it doesn't resize, pick a smaller size (to satisfy aspect ratio or
+ resize in steps of NxM pixels). If the client picks a smaller size and
+ is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the
+ surface will be centered on this axis.
+
+ If the width or height arguments are zero, it means the client should
+ decide its own window dimension.
+ </description>
+ <arg name="serial" type="uint"/>
+ <arg name="width" type="uint"/>
+ <arg name="height" type="uint"/>
+ </event>
+
+ <event name="closed">
+ <description summary="surface should be closed">
+ The closed event is sent by the compositor when the surface will no
+ longer be shown. The output may have been destroyed or the user may
+ have asked for it to be removed. Further changes to the surface will be
+ ignored. The client should destroy the resource after receiving this
+ event, and create a new surface if they so choose.
+ </description>
+ </event>
+
+ <enum name="error">
+ <entry name="invalid_surface_state" value="0" summary="provided surface state is invalid"/>
+ <entry name="invalid_size" value="1" summary="size is invalid"/>
+ <entry name="invalid_anchor" value="2" summary="anchor bitfield is invalid"/>
+ <entry name="invalid_keyboard_interactivity" value="3" summary="keyboard interactivity is invalid"/>
+ </enum>
+
+ <enum name="anchor" bitfield="true">
+ <entry name="top" value="1" summary="the top edge of the anchor rectangle"/>
+ <entry name="bottom" value="2" summary="the bottom edge of the anchor rectangle"/>
+ <entry name="left" value="4" summary="the left edge of the anchor rectangle"/>
+ <entry name="right" value="8" summary="the right edge of the anchor rectangle"/>
+ </enum>
+
+ <!-- Version 2 additions -->
+
+ <request name="set_layer" since="2">
+ <description summary="change the layer of the surface">
+ Change the layer that the surface is rendered on.
+
+ Layer is double-buffered, see wl_surface.commit.
+ </description>
+ <arg name="layer" type="uint" enum="zwlr_layer_shell_v1.layer" summary="layer to move this surface to"/>
+ </request>
+ </interface>
+</protocol>
diff --git a/dwl/util.c b/dwl/util.c
@@ -0,0 +1,35 @@
+/* See LICENSE.dwm file for copyright and license details. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+
+void
+die(const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
+ fputc(' ', stderr);
+ perror(NULL);
+ } else {
+ fputc('\n', stderr);
+ }
+
+ exit(1);
+}
+
+void *
+ecalloc(size_t nmemb, size_t size)
+{
+ void *p;
+
+ if (!(p = calloc(nmemb, size)))
+ die("calloc:");
+ return p;
+}
diff --git a/dwl/util.h b/dwl/util.h
@@ -0,0 +1,4 @@
+/* See LICENSE.dwm file for copyright and license details. */
+
+void die(const char *fmt, ...);
+void *ecalloc(size_t nmemb, size_t size);
diff --git a/dwl/wlr-layer-shell-unstable-v1-protocol.h b/dwl/wlr-layer-shell-unstable-v1-protocol.h
@@ -0,0 +1,606 @@
+/* Generated by wayland-scanner 1.22.0 */
+
+#ifndef WLR_LAYER_SHELL_UNSTABLE_V1_SERVER_PROTOCOL_H
+#define WLR_LAYER_SHELL_UNSTABLE_V1_SERVER_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-server.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct wl_client;
+struct wl_resource;
+
+/**
+ * @page page_wlr_layer_shell_unstable_v1 The wlr_layer_shell_unstable_v1 protocol
+ * @section page_ifaces_wlr_layer_shell_unstable_v1 Interfaces
+ * - @subpage page_iface_zwlr_layer_shell_v1 - create surfaces that are layers of the desktop
+ * - @subpage page_iface_zwlr_layer_surface_v1 - layer metadata interface
+ * @section page_copyright_wlr_layer_shell_unstable_v1 Copyright
+ * <pre>
+ *
+ * Copyright © 2017 Drew DeVault
+ *
+ * Permission to use, copy, modify, distribute, and sell this
+ * software and its documentation for any purpose is hereby granted
+ * without fee, provided that the above copyright notice appear in
+ * all copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * the copyright holders not be used in advertising or publicity
+ * pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ * </pre>
+ */
+struct wl_output;
+struct wl_surface;
+struct xdg_popup;
+struct zwlr_layer_shell_v1;
+struct zwlr_layer_surface_v1;
+
+#ifndef ZWLR_LAYER_SHELL_V1_INTERFACE
+#define ZWLR_LAYER_SHELL_V1_INTERFACE
+/**
+ * @page page_iface_zwlr_layer_shell_v1 zwlr_layer_shell_v1
+ * @section page_iface_zwlr_layer_shell_v1_desc Description
+ *
+ * Clients can use this interface to assign the surface_layer role to
+ * wl_surfaces. Such surfaces are assigned to a "layer" of the output and
+ * rendered with a defined z-depth respective to each other. They may also be
+ * anchored to the edges and corners of a screen and specify input handling
+ * semantics. This interface should be suitable for the implementation of
+ * many desktop shell components, and a broad number of other applications
+ * that interact with the desktop.
+ * @section page_iface_zwlr_layer_shell_v1_api API
+ * See @ref iface_zwlr_layer_shell_v1.
+ */
+/**
+ * @defgroup iface_zwlr_layer_shell_v1 The zwlr_layer_shell_v1 interface
+ *
+ * Clients can use this interface to assign the surface_layer role to
+ * wl_surfaces. Such surfaces are assigned to a "layer" of the output and
+ * rendered with a defined z-depth respective to each other. They may also be
+ * anchored to the edges and corners of a screen and specify input handling
+ * semantics. This interface should be suitable for the implementation of
+ * many desktop shell components, and a broad number of other applications
+ * that interact with the desktop.
+ */
+extern const struct wl_interface zwlr_layer_shell_v1_interface;
+#endif
+#ifndef ZWLR_LAYER_SURFACE_V1_INTERFACE
+#define ZWLR_LAYER_SURFACE_V1_INTERFACE
+/**
+ * @page page_iface_zwlr_layer_surface_v1 zwlr_layer_surface_v1
+ * @section page_iface_zwlr_layer_surface_v1_desc Description
+ *
+ * An interface that may be implemented by a wl_surface, for surfaces that
+ * are designed to be rendered as a layer of a stacked desktop-like
+ * environment.
+ *
+ * Layer surface state (layer, size, anchor, exclusive zone,
+ * margin, interactivity) is double-buffered, and will be applied at the
+ * time wl_surface.commit of the corresponding wl_surface is called.
+ *
+ * Attaching a null buffer to a layer surface unmaps it.
+ *
+ * Unmapping a layer_surface means that the surface cannot be shown by the
+ * compositor until it is explicitly mapped again. The layer_surface
+ * returns to the state it had right after layer_shell.get_layer_surface.
+ * The client can re-map the surface by performing a commit without any
+ * buffer attached, waiting for a configure event and handling it as usual.
+ * @section page_iface_zwlr_layer_surface_v1_api API
+ * See @ref iface_zwlr_layer_surface_v1.
+ */
+/**
+ * @defgroup iface_zwlr_layer_surface_v1 The zwlr_layer_surface_v1 interface
+ *
+ * An interface that may be implemented by a wl_surface, for surfaces that
+ * are designed to be rendered as a layer of a stacked desktop-like
+ * environment.
+ *
+ * Layer surface state (layer, size, anchor, exclusive zone,
+ * margin, interactivity) is double-buffered, and will be applied at the
+ * time wl_surface.commit of the corresponding wl_surface is called.
+ *
+ * Attaching a null buffer to a layer surface unmaps it.
+ *
+ * Unmapping a layer_surface means that the surface cannot be shown by the
+ * compositor until it is explicitly mapped again. The layer_surface
+ * returns to the state it had right after layer_shell.get_layer_surface.
+ * The client can re-map the surface by performing a commit without any
+ * buffer attached, waiting for a configure event and handling it as usual.
+ */
+extern const struct wl_interface zwlr_layer_surface_v1_interface;
+#endif
+
+#ifndef ZWLR_LAYER_SHELL_V1_ERROR_ENUM
+#define ZWLR_LAYER_SHELL_V1_ERROR_ENUM
+enum zwlr_layer_shell_v1_error {
+ /**
+ * wl_surface has another role
+ */
+ ZWLR_LAYER_SHELL_V1_ERROR_ROLE = 0,
+ /**
+ * layer value is invalid
+ */
+ ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER = 1,
+ /**
+ * wl_surface has a buffer attached or committed
+ */
+ ZWLR_LAYER_SHELL_V1_ERROR_ALREADY_CONSTRUCTED = 2,
+};
+#endif /* ZWLR_LAYER_SHELL_V1_ERROR_ENUM */
+
+#ifndef ZWLR_LAYER_SHELL_V1_LAYER_ENUM
+#define ZWLR_LAYER_SHELL_V1_LAYER_ENUM
+/**
+ * @ingroup iface_zwlr_layer_shell_v1
+ * available layers for surfaces
+ *
+ * These values indicate which layers a surface can be rendered in. They
+ * are ordered by z depth, bottom-most first. Traditional shell surfaces
+ * will typically be rendered between the bottom and top layers.
+ * Fullscreen shell surfaces are typically rendered at the top layer.
+ * Multiple surfaces can share a single layer, and ordering within a
+ * single layer is undefined.
+ */
+enum zwlr_layer_shell_v1_layer {
+ ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND = 0,
+ ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM = 1,
+ ZWLR_LAYER_SHELL_V1_LAYER_TOP = 2,
+ ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY = 3,
+};
+#endif /* ZWLR_LAYER_SHELL_V1_LAYER_ENUM */
+
+/**
+ * @ingroup iface_zwlr_layer_shell_v1
+ * @struct zwlr_layer_shell_v1_interface
+ */
+struct zwlr_layer_shell_v1_interface {
+ /**
+ * create a layer_surface from a surface
+ *
+ * Create a layer surface for an existing surface. This assigns
+ * the role of layer_surface, or raises a protocol error if another
+ * role is already assigned.
+ *
+ * Creating a layer surface from a wl_surface which has a buffer
+ * attached or committed is a client error, and any attempts by a
+ * client to attach or manipulate a buffer prior to the first
+ * layer_surface.configure call must also be treated as errors.
+ *
+ * After creating a layer_surface object and setting it up, the
+ * client must perform an initial commit without any buffer
+ * attached. The compositor will reply with a
+ * layer_surface.configure event. The client must acknowledge it
+ * and is then allowed to attach a buffer to map the surface.
+ *
+ * You may pass NULL for output to allow the compositor to decide
+ * which output to use. Generally this will be the one that the
+ * user most recently interacted with.
+ *
+ * Clients can specify a namespace that defines the purpose of the
+ * layer surface.
+ * @param layer layer to add this surface to
+ * @param namespace namespace for the layer surface
+ */
+ void (*get_layer_surface)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id,
+ struct wl_resource *surface,
+ struct wl_resource *output,
+ uint32_t layer,
+ const char *namespace);
+ /**
+ * destroy the layer_shell object
+ *
+ * This request indicates that the client will not use the
+ * layer_shell object any more. Objects that have been created
+ * through this instance are not affected.
+ * @since 3
+ */
+ void (*destroy)(struct wl_client *client,
+ struct wl_resource *resource);
+};
+
+
+/**
+ * @ingroup iface_zwlr_layer_shell_v1
+ */
+#define ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwlr_layer_shell_v1
+ */
+#define ZWLR_LAYER_SHELL_V1_DESTROY_SINCE_VERSION 3
+
+#ifndef ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ENUM
+#define ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ENUM
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ * types of keyboard interaction possible for a layer shell surface
+ *
+ * Types of keyboard interaction possible for layer shell surfaces. The
+ * rationale for this is twofold: (1) some applications are not interested
+ * in keyboard events and not allowing them to be focused can improve the
+ * desktop experience; (2) some applications will want to take exclusive
+ * keyboard focus.
+ */
+enum zwlr_layer_surface_v1_keyboard_interactivity {
+ /**
+ * no keyboard focus is possible
+ *
+ * This value indicates that this surface is not interested in
+ * keyboard events and the compositor should never assign it the
+ * keyboard focus.
+ *
+ * This is the default value, set for newly created layer shell
+ * surfaces.
+ *
+ * This is useful for e.g. desktop widgets that display information
+ * or only have interaction with non-keyboard input devices.
+ */
+ ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE = 0,
+ /**
+ * request exclusive keyboard focus
+ *
+ * Request exclusive keyboard focus if this surface is above the
+ * shell surface layer.
+ *
+ * For the top and overlay layers, the seat will always give
+ * exclusive keyboard focus to the top-most layer which has
+ * keyboard interactivity set to exclusive. If this layer contains
+ * multiple surfaces with keyboard interactivity set to exclusive,
+ * the compositor determines the one receiving keyboard events in
+ * an implementation- defined manner. In this case, no guarantee is
+ * made when this surface will receive keyboard focus (if ever).
+ *
+ * For the bottom and background layers, the compositor is allowed
+ * to use normal focus semantics.
+ *
+ * This setting is mainly intended for applications that need to
+ * ensure they receive all keyboard events, such as a lock screen
+ * or a password prompt.
+ */
+ ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE = 1,
+ /**
+ * request regular keyboard focus semantics
+ *
+ * This requests the compositor to allow this surface to be
+ * focused and unfocused by the user in an implementation-defined
+ * manner. The user should be able to unfocus this surface even
+ * regardless of the layer it is on.
+ *
+ * Typically, the compositor will want to use its normal mechanism
+ * to manage keyboard focus between layer shell surfaces with this
+ * setting and regular toplevels on the desktop layer (e.g. click
+ * to focus). Nevertheless, it is possible for a compositor to
+ * require a special interaction to focus or unfocus layer shell
+ * surfaces (e.g. requiring a click even if focus follows the mouse
+ * normally, or providing a keybinding to switch focus between
+ * layers).
+ *
+ * This setting is mainly intended for desktop shell components
+ * (e.g. panels) that allow keyboard interaction. Using this option
+ * can allow implementing a desktop shell that can be fully usable
+ * without the mouse.
+ * @since 4
+ */
+ ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND = 2,
+};
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND_SINCE_VERSION 4
+#endif /* ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ENUM */
+
+#ifndef ZWLR_LAYER_SURFACE_V1_ERROR_ENUM
+#define ZWLR_LAYER_SURFACE_V1_ERROR_ENUM
+enum zwlr_layer_surface_v1_error {
+ /**
+ * provided surface state is invalid
+ */
+ ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SURFACE_STATE = 0,
+ /**
+ * size is invalid
+ */
+ ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SIZE = 1,
+ /**
+ * anchor bitfield is invalid
+ */
+ ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_ANCHOR = 2,
+ /**
+ * keyboard interactivity is invalid
+ */
+ ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_KEYBOARD_INTERACTIVITY = 3,
+};
+#endif /* ZWLR_LAYER_SURFACE_V1_ERROR_ENUM */
+
+#ifndef ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM
+#define ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM
+enum zwlr_layer_surface_v1_anchor {
+ /**
+ * the top edge of the anchor rectangle
+ */
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP = 1,
+ /**
+ * the bottom edge of the anchor rectangle
+ */
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM = 2,
+ /**
+ * the left edge of the anchor rectangle
+ */
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT = 4,
+ /**
+ * the right edge of the anchor rectangle
+ */
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT = 8,
+};
+#endif /* ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM */
+
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ * @struct zwlr_layer_surface_v1_interface
+ */
+struct zwlr_layer_surface_v1_interface {
+ /**
+ * sets the size of the surface
+ *
+ * Sets the size of the surface in surface-local coordinates. The
+ * compositor will display the surface centered with respect to its
+ * anchors.
+ *
+ * If you pass 0 for either value, the compositor will assign it
+ * and inform you of the assignment in the configure event. You
+ * must set your anchor to opposite edges in the dimensions you
+ * omit; not doing so is a protocol error. Both values are 0 by
+ * default.
+ *
+ * Size is double-buffered, see wl_surface.commit.
+ */
+ void (*set_size)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t width,
+ uint32_t height);
+ /**
+ * configures the anchor point of the surface
+ *
+ * Requests that the compositor anchor the surface to the
+ * specified edges and corners. If two orthogonal edges are
+ * specified (e.g. 'top' and 'left'), then the anchor point will be
+ * the intersection of the edges (e.g. the top left corner of the
+ * output); otherwise the anchor point will be centered on that
+ * edge, or in the center if none is specified.
+ *
+ * Anchor is double-buffered, see wl_surface.commit.
+ */
+ void (*set_anchor)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t anchor);
+ /**
+ * configures the exclusive geometry of this surface
+ *
+ * Requests that the compositor avoids occluding an area with
+ * other surfaces. The compositor's use of this information is
+ * implementation-dependent - do not assume that this region will
+ * not actually be occluded.
+ *
+ * A positive value is only meaningful if the surface is anchored
+ * to one edge or an edge and both perpendicular edges. If the
+ * surface is not anchored, anchored to only two perpendicular
+ * edges (a corner), anchored to only two parallel edges or
+ * anchored to all edges, a positive value will be treated the same
+ * as zero.
+ *
+ * A positive zone is the distance from the edge in surface-local
+ * coordinates to consider exclusive.
+ *
+ * Surfaces that do not wish to have an exclusive zone may instead
+ * specify how they should interact with surfaces that do. If set
+ * to zero, the surface indicates that it would like to be moved to
+ * avoid occluding surfaces with a positive exclusive zone. If set
+ * to -1, the surface indicates that it would not like to be moved
+ * to accommodate for other surfaces, and the compositor should
+ * extend it all the way to the edges it is anchored to.
+ *
+ * For example, a panel might set its exclusive zone to 10, so that
+ * maximized shell surfaces are not shown on top of it. A
+ * notification might set its exclusive zone to 0, so that it is
+ * moved to avoid occluding the panel, but shell surfaces are shown
+ * underneath it. A wallpaper or lock screen might set their
+ * exclusive zone to -1, so that they stretch below or over the
+ * panel.
+ *
+ * The default value is 0.
+ *
+ * Exclusive zone is double-buffered, see wl_surface.commit.
+ */
+ void (*set_exclusive_zone)(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t zone);
+ /**
+ * sets a margin from the anchor point
+ *
+ * Requests that the surface be placed some distance away from
+ * the anchor point on the output, in surface-local coordinates.
+ * Setting this value for edges you are not anchored to has no
+ * effect.
+ *
+ * The exclusive zone includes the margin.
+ *
+ * Margin is double-buffered, see wl_surface.commit.
+ */
+ void (*set_margin)(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t top,
+ int32_t right,
+ int32_t bottom,
+ int32_t left);
+ /**
+ * requests keyboard events
+ *
+ * Set how keyboard events are delivered to this surface. By
+ * default, layer shell surfaces do not receive keyboard events;
+ * this request can be used to change this.
+ *
+ * This setting is inherited by child surfaces set by the get_popup
+ * request.
+ *
+ * Layer surfaces receive pointer, touch, and tablet events
+ * normally. If you do not want to receive them, set the input
+ * region on your surface to an empty region.
+ *
+ * Keyboard interactivity is double-buffered, see
+ * wl_surface.commit.
+ */
+ void (*set_keyboard_interactivity)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t keyboard_interactivity);
+ /**
+ * assign this layer_surface as an xdg_popup parent
+ *
+ * This assigns an xdg_popup's parent to this layer_surface. This
+ * popup should have been created via xdg_surface::get_popup with
+ * the parent set to NULL, and this request must be invoked before
+ * committing the popup's initial state.
+ *
+ * See the documentation of xdg_popup for more details about what
+ * an xdg_popup is and how it is used.
+ */
+ void (*get_popup)(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *popup);
+ /**
+ * ack a configure event
+ *
+ * When a configure event is received, if a client commits the
+ * surface in response to the configure event, then the client must
+ * make an ack_configure request sometime before the commit
+ * request, passing along the serial of the configure event.
+ *
+ * If the client receives multiple configure events before it can
+ * respond to one, it only has to ack the last configure event.
+ *
+ * A client is not required to commit immediately after sending an
+ * ack_configure request - it may even ack_configure several times
+ * before its next surface commit.
+ *
+ * A client may send multiple ack_configure requests before
+ * committing, but only the last request sent before a commit
+ * indicates which configure event the client really is responding
+ * to.
+ * @param serial the serial from the configure event
+ */
+ void (*ack_configure)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t serial);
+ /**
+ * destroy the layer_surface
+ *
+ * This request destroys the layer surface.
+ */
+ void (*destroy)(struct wl_client *client,
+ struct wl_resource *resource);
+ /**
+ * change the layer of the surface
+ *
+ * Change the layer that the surface is rendered on.
+ *
+ * Layer is double-buffered, see wl_surface.commit.
+ * @param layer layer to move this surface to
+ * @since 2
+ */
+ void (*set_layer)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t layer);
+};
+
+#define ZWLR_LAYER_SURFACE_V1_CONFIGURE 0
+#define ZWLR_LAYER_SURFACE_V1_CLOSED 1
+
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_CONFIGURE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_CLOSED_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_SET_SIZE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_SET_ANCHOR_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_SET_MARGIN_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_GET_POPUP_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_SET_LAYER_SINCE_VERSION 2
+
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ * Sends an configure event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+zwlr_layer_surface_v1_send_configure(struct wl_resource *resource_, uint32_t serial, uint32_t width, uint32_t height)
+{
+ wl_resource_post_event(resource_, ZWLR_LAYER_SURFACE_V1_CONFIGURE, serial, width, height);
+}
+
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ * Sends an closed event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+zwlr_layer_surface_v1_send_closed(struct wl_resource *resource_)
+{
+ wl_resource_post_event(resource_, ZWLR_LAYER_SURFACE_V1_CLOSED);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/dwl/xdg-shell-protocol.h b/dwl/xdg-shell-protocol.h
@@ -0,0 +1,1969 @@
+/* Generated by wayland-scanner 1.22.0 */
+
+#ifndef XDG_SHELL_SERVER_PROTOCOL_H
+#define XDG_SHELL_SERVER_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-server.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct wl_client;
+struct wl_resource;
+
+/**
+ * @page page_xdg_shell The xdg_shell protocol
+ * @section page_ifaces_xdg_shell Interfaces
+ * - @subpage page_iface_xdg_wm_base - create desktop-style surfaces
+ * - @subpage page_iface_xdg_positioner - child surface positioner
+ * - @subpage page_iface_xdg_surface - desktop user interface surface base interface
+ * - @subpage page_iface_xdg_toplevel - toplevel surface
+ * - @subpage page_iface_xdg_popup - short-lived, popup surfaces for menus
+ * @section page_copyright_xdg_shell Copyright
+ * <pre>
+ *
+ * Copyright © 2008-2013 Kristian Høgsberg
+ * Copyright © 2013 Rafael Antognolli
+ * Copyright © 2013 Jasper St. Pierre
+ * Copyright © 2010-2013 Intel Corporation
+ * Copyright © 2015-2017 Samsung Electronics Co., Ltd
+ * Copyright © 2015-2017 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * </pre>
+ */
+struct wl_output;
+struct wl_seat;
+struct wl_surface;
+struct xdg_popup;
+struct xdg_positioner;
+struct xdg_surface;
+struct xdg_toplevel;
+struct xdg_wm_base;
+
+#ifndef XDG_WM_BASE_INTERFACE
+#define XDG_WM_BASE_INTERFACE
+/**
+ * @page page_iface_xdg_wm_base xdg_wm_base
+ * @section page_iface_xdg_wm_base_desc Description
+ *
+ * The xdg_wm_base interface is exposed as a global object enabling clients
+ * to turn their wl_surfaces into windows in a desktop environment. It
+ * defines the basic functionality needed for clients and the compositor to
+ * create windows that can be dragged, resized, maximized, etc, as well as
+ * creating transient windows such as popup menus.
+ * @section page_iface_xdg_wm_base_api API
+ * See @ref iface_xdg_wm_base.
+ */
+/**
+ * @defgroup iface_xdg_wm_base The xdg_wm_base interface
+ *
+ * The xdg_wm_base interface is exposed as a global object enabling clients
+ * to turn their wl_surfaces into windows in a desktop environment. It
+ * defines the basic functionality needed for clients and the compositor to
+ * create windows that can be dragged, resized, maximized, etc, as well as
+ * creating transient windows such as popup menus.
+ */
+extern const struct wl_interface xdg_wm_base_interface;
+#endif
+#ifndef XDG_POSITIONER_INTERFACE
+#define XDG_POSITIONER_INTERFACE
+/**
+ * @page page_iface_xdg_positioner xdg_positioner
+ * @section page_iface_xdg_positioner_desc Description
+ *
+ * The xdg_positioner provides a collection of rules for the placement of a
+ * child surface relative to a parent surface. Rules can be defined to ensure
+ * the child surface remains within the visible area's borders, and to
+ * specify how the child surface changes its position, such as sliding along
+ * an axis, or flipping around a rectangle. These positioner-created rules are
+ * constrained by the requirement that a child surface must intersect with or
+ * be at least partially adjacent to its parent surface.
+ *
+ * See the various requests for details about possible rules.
+ *
+ * At the time of the request, the compositor makes a copy of the rules
+ * specified by the xdg_positioner. Thus, after the request is complete the
+ * xdg_positioner object can be destroyed or reused; further changes to the
+ * object will have no effect on previous usages.
+ *
+ * For an xdg_positioner object to be considered complete, it must have a
+ * non-zero size set by set_size, and a non-zero anchor rectangle set by
+ * set_anchor_rect. Passing an incomplete xdg_positioner object when
+ * positioning a surface raises an invalid_positioner error.
+ * @section page_iface_xdg_positioner_api API
+ * See @ref iface_xdg_positioner.
+ */
+/**
+ * @defgroup iface_xdg_positioner The xdg_positioner interface
+ *
+ * The xdg_positioner provides a collection of rules for the placement of a
+ * child surface relative to a parent surface. Rules can be defined to ensure
+ * the child surface remains within the visible area's borders, and to
+ * specify how the child surface changes its position, such as sliding along
+ * an axis, or flipping around a rectangle. These positioner-created rules are
+ * constrained by the requirement that a child surface must intersect with or
+ * be at least partially adjacent to its parent surface.
+ *
+ * See the various requests for details about possible rules.
+ *
+ * At the time of the request, the compositor makes a copy of the rules
+ * specified by the xdg_positioner. Thus, after the request is complete the
+ * xdg_positioner object can be destroyed or reused; further changes to the
+ * object will have no effect on previous usages.
+ *
+ * For an xdg_positioner object to be considered complete, it must have a
+ * non-zero size set by set_size, and a non-zero anchor rectangle set by
+ * set_anchor_rect. Passing an incomplete xdg_positioner object when
+ * positioning a surface raises an invalid_positioner error.
+ */
+extern const struct wl_interface xdg_positioner_interface;
+#endif
+#ifndef XDG_SURFACE_INTERFACE
+#define XDG_SURFACE_INTERFACE
+/**
+ * @page page_iface_xdg_surface xdg_surface
+ * @section page_iface_xdg_surface_desc Description
+ *
+ * An interface that may be implemented by a wl_surface, for
+ * implementations that provide a desktop-style user interface.
+ *
+ * It provides a base set of functionality required to construct user
+ * interface elements requiring management by the compositor, such as
+ * toplevel windows, menus, etc. The types of functionality are split into
+ * xdg_surface roles.
+ *
+ * Creating an xdg_surface does not set the role for a wl_surface. In order
+ * to map an xdg_surface, the client must create a role-specific object
+ * using, e.g., get_toplevel, get_popup. The wl_surface for any given
+ * xdg_surface can have at most one role, and may not be assigned any role
+ * not based on xdg_surface.
+ *
+ * A role must be assigned before any other requests are made to the
+ * xdg_surface object.
+ *
+ * The client must call wl_surface.commit on the corresponding wl_surface
+ * for the xdg_surface state to take effect.
+ *
+ * Creating an xdg_surface from a wl_surface which has a buffer attached or
+ * committed is a client error, and any attempts by a client to attach or
+ * manipulate a buffer prior to the first xdg_surface.configure call must
+ * also be treated as errors.
+ *
+ * After creating a role-specific object and setting it up, the client must
+ * perform an initial commit without any buffer attached. The compositor
+ * will reply with initial wl_surface state such as
+ * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure
+ * event. The client must acknowledge it and is then allowed to attach a
+ * buffer to map the surface.
+ *
+ * Mapping an xdg_surface-based role surface is defined as making it
+ * possible for the surface to be shown by the compositor. Note that
+ * a mapped surface is not guaranteed to be visible once it is mapped.
+ *
+ * For an xdg_surface to be mapped by the compositor, the following
+ * conditions must be met:
+ * (1) the client has assigned an xdg_surface-based role to the surface
+ * (2) the client has set and committed the xdg_surface state and the
+ * role-dependent state to the surface
+ * (3) the client has committed a buffer to the surface
+ *
+ * A newly-unmapped surface is considered to have met condition (1) out
+ * of the 3 required conditions for mapping a surface if its role surface
+ * has not been destroyed, i.e. the client must perform the initial commit
+ * again before attaching a buffer.
+ * @section page_iface_xdg_surface_api API
+ * See @ref iface_xdg_surface.
+ */
+/**
+ * @defgroup iface_xdg_surface The xdg_surface interface
+ *
+ * An interface that may be implemented by a wl_surface, for
+ * implementations that provide a desktop-style user interface.
+ *
+ * It provides a base set of functionality required to construct user
+ * interface elements requiring management by the compositor, such as
+ * toplevel windows, menus, etc. The types of functionality are split into
+ * xdg_surface roles.
+ *
+ * Creating an xdg_surface does not set the role for a wl_surface. In order
+ * to map an xdg_surface, the client must create a role-specific object
+ * using, e.g., get_toplevel, get_popup. The wl_surface for any given
+ * xdg_surface can have at most one role, and may not be assigned any role
+ * not based on xdg_surface.
+ *
+ * A role must be assigned before any other requests are made to the
+ * xdg_surface object.
+ *
+ * The client must call wl_surface.commit on the corresponding wl_surface
+ * for the xdg_surface state to take effect.
+ *
+ * Creating an xdg_surface from a wl_surface which has a buffer attached or
+ * committed is a client error, and any attempts by a client to attach or
+ * manipulate a buffer prior to the first xdg_surface.configure call must
+ * also be treated as errors.
+ *
+ * After creating a role-specific object and setting it up, the client must
+ * perform an initial commit without any buffer attached. The compositor
+ * will reply with initial wl_surface state such as
+ * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure
+ * event. The client must acknowledge it and is then allowed to attach a
+ * buffer to map the surface.
+ *
+ * Mapping an xdg_surface-based role surface is defined as making it
+ * possible for the surface to be shown by the compositor. Note that
+ * a mapped surface is not guaranteed to be visible once it is mapped.
+ *
+ * For an xdg_surface to be mapped by the compositor, the following
+ * conditions must be met:
+ * (1) the client has assigned an xdg_surface-based role to the surface
+ * (2) the client has set and committed the xdg_surface state and the
+ * role-dependent state to the surface
+ * (3) the client has committed a buffer to the surface
+ *
+ * A newly-unmapped surface is considered to have met condition (1) out
+ * of the 3 required conditions for mapping a surface if its role surface
+ * has not been destroyed, i.e. the client must perform the initial commit
+ * again before attaching a buffer.
+ */
+extern const struct wl_interface xdg_surface_interface;
+#endif
+#ifndef XDG_TOPLEVEL_INTERFACE
+#define XDG_TOPLEVEL_INTERFACE
+/**
+ * @page page_iface_xdg_toplevel xdg_toplevel
+ * @section page_iface_xdg_toplevel_desc Description
+ *
+ * This interface defines an xdg_surface role which allows a surface to,
+ * among other things, set window-like properties such as maximize,
+ * fullscreen, and minimize, set application-specific metadata like title and
+ * id, and well as trigger user interactive operations such as interactive
+ * resize and move.
+ *
+ * A xdg_toplevel by default is responsible for providing the full intended
+ * visual representation of the toplevel, which depending on the window
+ * state, may mean things like a title bar, window controls and drop shadow.
+ *
+ * Unmapping an xdg_toplevel means that the surface cannot be shown
+ * by the compositor until it is explicitly mapped again.
+ * All active operations (e.g., move, resize) are canceled and all
+ * attributes (e.g. title, state, stacking, ...) are discarded for
+ * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to
+ * the state it had right after xdg_surface.get_toplevel. The client
+ * can re-map the toplevel by perfoming a commit without any buffer
+ * attached, waiting for a configure event and handling it as usual (see
+ * xdg_surface description).
+ *
+ * Attaching a null buffer to a toplevel unmaps the surface.
+ * @section page_iface_xdg_toplevel_api API
+ * See @ref iface_xdg_toplevel.
+ */
+/**
+ * @defgroup iface_xdg_toplevel The xdg_toplevel interface
+ *
+ * This interface defines an xdg_surface role which allows a surface to,
+ * among other things, set window-like properties such as maximize,
+ * fullscreen, and minimize, set application-specific metadata like title and
+ * id, and well as trigger user interactive operations such as interactive
+ * resize and move.
+ *
+ * A xdg_toplevel by default is responsible for providing the full intended
+ * visual representation of the toplevel, which depending on the window
+ * state, may mean things like a title bar, window controls and drop shadow.
+ *
+ * Unmapping an xdg_toplevel means that the surface cannot be shown
+ * by the compositor until it is explicitly mapped again.
+ * All active operations (e.g., move, resize) are canceled and all
+ * attributes (e.g. title, state, stacking, ...) are discarded for
+ * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to
+ * the state it had right after xdg_surface.get_toplevel. The client
+ * can re-map the toplevel by perfoming a commit without any buffer
+ * attached, waiting for a configure event and handling it as usual (see
+ * xdg_surface description).
+ *
+ * Attaching a null buffer to a toplevel unmaps the surface.
+ */
+extern const struct wl_interface xdg_toplevel_interface;
+#endif
+#ifndef XDG_POPUP_INTERFACE
+#define XDG_POPUP_INTERFACE
+/**
+ * @page page_iface_xdg_popup xdg_popup
+ * @section page_iface_xdg_popup_desc Description
+ *
+ * A popup surface is a short-lived, temporary surface. It can be used to
+ * implement for example menus, popovers, tooltips and other similar user
+ * interface concepts.
+ *
+ * A popup can be made to take an explicit grab. See xdg_popup.grab for
+ * details.
+ *
+ * When the popup is dismissed, a popup_done event will be sent out, and at
+ * the same time the surface will be unmapped. See the xdg_popup.popup_done
+ * event for details.
+ *
+ * Explicitly destroying the xdg_popup object will also dismiss the popup and
+ * unmap the surface. Clients that want to dismiss the popup when another
+ * surface of their own is clicked should dismiss the popup using the destroy
+ * request.
+ *
+ * A newly created xdg_popup will be stacked on top of all previously created
+ * xdg_popup surfaces associated with the same xdg_toplevel.
+ *
+ * The parent of an xdg_popup must be mapped (see the xdg_surface
+ * description) before the xdg_popup itself.
+ *
+ * The client must call wl_surface.commit on the corresponding wl_surface
+ * for the xdg_popup state to take effect.
+ * @section page_iface_xdg_popup_api API
+ * See @ref iface_xdg_popup.
+ */
+/**
+ * @defgroup iface_xdg_popup The xdg_popup interface
+ *
+ * A popup surface is a short-lived, temporary surface. It can be used to
+ * implement for example menus, popovers, tooltips and other similar user
+ * interface concepts.
+ *
+ * A popup can be made to take an explicit grab. See xdg_popup.grab for
+ * details.
+ *
+ * When the popup is dismissed, a popup_done event will be sent out, and at
+ * the same time the surface will be unmapped. See the xdg_popup.popup_done
+ * event for details.
+ *
+ * Explicitly destroying the xdg_popup object will also dismiss the popup and
+ * unmap the surface. Clients that want to dismiss the popup when another
+ * surface of their own is clicked should dismiss the popup using the destroy
+ * request.
+ *
+ * A newly created xdg_popup will be stacked on top of all previously created
+ * xdg_popup surfaces associated with the same xdg_toplevel.
+ *
+ * The parent of an xdg_popup must be mapped (see the xdg_surface
+ * description) before the xdg_popup itself.
+ *
+ * The client must call wl_surface.commit on the corresponding wl_surface
+ * for the xdg_popup state to take effect.
+ */
+extern const struct wl_interface xdg_popup_interface;
+#endif
+
+#ifndef XDG_WM_BASE_ERROR_ENUM
+#define XDG_WM_BASE_ERROR_ENUM
+enum xdg_wm_base_error {
+ /**
+ * given wl_surface has another role
+ */
+ XDG_WM_BASE_ERROR_ROLE = 0,
+ /**
+ * xdg_wm_base was destroyed before children
+ */
+ XDG_WM_BASE_ERROR_DEFUNCT_SURFACES = 1,
+ /**
+ * the client tried to map or destroy a non-topmost popup
+ */
+ XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP = 2,
+ /**
+ * the client specified an invalid popup parent surface
+ */
+ XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT = 3,
+ /**
+ * the client provided an invalid surface state
+ */
+ XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE = 4,
+ /**
+ * the client provided an invalid positioner
+ */
+ XDG_WM_BASE_ERROR_INVALID_POSITIONER = 5,
+ /**
+ * the client didn’t respond to a ping event in time
+ */
+ XDG_WM_BASE_ERROR_UNRESPONSIVE = 6,
+};
+#endif /* XDG_WM_BASE_ERROR_ENUM */
+
+/**
+ * @ingroup iface_xdg_wm_base
+ * @struct xdg_wm_base_interface
+ */
+struct xdg_wm_base_interface {
+ /**
+ * destroy xdg_wm_base
+ *
+ * Destroy this xdg_wm_base object.
+ *
+ * Destroying a bound xdg_wm_base object while there are surfaces
+ * still alive created by this xdg_wm_base object instance is
+ * illegal and will result in a defunct_surfaces error.
+ */
+ void (*destroy)(struct wl_client *client,
+ struct wl_resource *resource);
+ /**
+ * create a positioner object
+ *
+ * Create a positioner object. A positioner object is used to
+ * position surfaces relative to some parent surface. See the
+ * interface description and xdg_surface.get_popup for details.
+ */
+ void (*create_positioner)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id);
+ /**
+ * create a shell surface from a surface
+ *
+ * This creates an xdg_surface for the given surface. While
+ * xdg_surface itself is not a role, the corresponding surface may
+ * only be assigned a role extending xdg_surface, such as
+ * xdg_toplevel or xdg_popup. It is illegal to create an
+ * xdg_surface for a wl_surface which already has an assigned role
+ * and this will result in a role error.
+ *
+ * This creates an xdg_surface for the given surface. An
+ * xdg_surface is used as basis to define a role to a given
+ * surface, such as xdg_toplevel or xdg_popup. It also manages
+ * functionality shared between xdg_surface based surface roles.
+ *
+ * See the documentation of xdg_surface for more details about what
+ * an xdg_surface is and how it is used.
+ */
+ void (*get_xdg_surface)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id,
+ struct wl_resource *surface);
+ /**
+ * respond to a ping event
+ *
+ * A client must respond to a ping event with a pong request or
+ * the client may be deemed unresponsive. See xdg_wm_base.ping and
+ * xdg_wm_base.error.unresponsive.
+ * @param serial serial of the ping event
+ */
+ void (*pong)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t serial);
+};
+
+#define XDG_WM_BASE_PING 0
+
+/**
+ * @ingroup iface_xdg_wm_base
+ */
+#define XDG_WM_BASE_PING_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_xdg_wm_base
+ */
+#define XDG_WM_BASE_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_wm_base
+ */
+#define XDG_WM_BASE_CREATE_POSITIONER_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_wm_base
+ */
+#define XDG_WM_BASE_GET_XDG_SURFACE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_wm_base
+ */
+#define XDG_WM_BASE_PONG_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_xdg_wm_base
+ * Sends an ping event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param serial pass this to the pong request
+ */
+static inline void
+xdg_wm_base_send_ping(struct wl_resource *resource_, uint32_t serial)
+{
+ wl_resource_post_event(resource_, XDG_WM_BASE_PING, serial);
+}
+
+#ifndef XDG_POSITIONER_ERROR_ENUM
+#define XDG_POSITIONER_ERROR_ENUM
+enum xdg_positioner_error {
+ /**
+ * invalid input provided
+ */
+ XDG_POSITIONER_ERROR_INVALID_INPUT = 0,
+};
+#endif /* XDG_POSITIONER_ERROR_ENUM */
+
+#ifndef XDG_POSITIONER_ANCHOR_ENUM
+#define XDG_POSITIONER_ANCHOR_ENUM
+enum xdg_positioner_anchor {
+ XDG_POSITIONER_ANCHOR_NONE = 0,
+ XDG_POSITIONER_ANCHOR_TOP = 1,
+ XDG_POSITIONER_ANCHOR_BOTTOM = 2,
+ XDG_POSITIONER_ANCHOR_LEFT = 3,
+ XDG_POSITIONER_ANCHOR_RIGHT = 4,
+ XDG_POSITIONER_ANCHOR_TOP_LEFT = 5,
+ XDG_POSITIONER_ANCHOR_BOTTOM_LEFT = 6,
+ XDG_POSITIONER_ANCHOR_TOP_RIGHT = 7,
+ XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT = 8,
+};
+#endif /* XDG_POSITIONER_ANCHOR_ENUM */
+
+#ifndef XDG_POSITIONER_GRAVITY_ENUM
+#define XDG_POSITIONER_GRAVITY_ENUM
+enum xdg_positioner_gravity {
+ XDG_POSITIONER_GRAVITY_NONE = 0,
+ XDG_POSITIONER_GRAVITY_TOP = 1,
+ XDG_POSITIONER_GRAVITY_BOTTOM = 2,
+ XDG_POSITIONER_GRAVITY_LEFT = 3,
+ XDG_POSITIONER_GRAVITY_RIGHT = 4,
+ XDG_POSITIONER_GRAVITY_TOP_LEFT = 5,
+ XDG_POSITIONER_GRAVITY_BOTTOM_LEFT = 6,
+ XDG_POSITIONER_GRAVITY_TOP_RIGHT = 7,
+ XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT = 8,
+};
+#endif /* XDG_POSITIONER_GRAVITY_ENUM */
+
+#ifndef XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM
+#define XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM
+/**
+ * @ingroup iface_xdg_positioner
+ * constraint adjustments
+ *
+ * The constraint adjustment value define ways the compositor will adjust
+ * the position of the surface, if the unadjusted position would result
+ * in the surface being partly constrained.
+ *
+ * Whether a surface is considered 'constrained' is left to the compositor
+ * to determine. For example, the surface may be partly outside the
+ * compositor's defined 'work area', thus necessitating the child surface's
+ * position be adjusted until it is entirely inside the work area.
+ *
+ * The adjustments can be combined, according to a defined precedence: 1)
+ * Flip, 2) Slide, 3) Resize.
+ */
+enum xdg_positioner_constraint_adjustment {
+ /**
+ * don't move the child surface when constrained
+ *
+ * Don't alter the surface position even if it is constrained on
+ * some axis, for example partially outside the edge of an output.
+ */
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE = 0,
+ /**
+ * move along the x axis until unconstrained
+ *
+ * Slide the surface along the x axis until it is no longer
+ * constrained.
+ *
+ * First try to slide towards the direction of the gravity on the x
+ * axis until either the edge in the opposite direction of the
+ * gravity is unconstrained or the edge in the direction of the
+ * gravity is constrained.
+ *
+ * Then try to slide towards the opposite direction of the gravity
+ * on the x axis until either the edge in the direction of the
+ * gravity is unconstrained or the edge in the opposite direction
+ * of the gravity is constrained.
+ */
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1,
+ /**
+ * move along the y axis until unconstrained
+ *
+ * Slide the surface along the y axis until it is no longer
+ * constrained.
+ *
+ * First try to slide towards the direction of the gravity on the y
+ * axis until either the edge in the opposite direction of the
+ * gravity is unconstrained or the edge in the direction of the
+ * gravity is constrained.
+ *
+ * Then try to slide towards the opposite direction of the gravity
+ * on the y axis until either the edge in the direction of the
+ * gravity is unconstrained or the edge in the opposite direction
+ * of the gravity is constrained.
+ */
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2,
+ /**
+ * invert the anchor and gravity on the x axis
+ *
+ * Invert the anchor and gravity on the x axis if the surface is
+ * constrained on the x axis. For example, if the left edge of the
+ * surface is constrained, the gravity is 'left' and the anchor is
+ * 'left', change the gravity to 'right' and the anchor to 'right'.
+ *
+ * If the adjusted position also ends up being constrained, the
+ * resulting position of the flip_x adjustment will be the one
+ * before the adjustment.
+ */
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X = 4,
+ /**
+ * invert the anchor and gravity on the y axis
+ *
+ * Invert the anchor and gravity on the y axis if the surface is
+ * constrained on the y axis. For example, if the bottom edge of
+ * the surface is constrained, the gravity is 'bottom' and the
+ * anchor is 'bottom', change the gravity to 'top' and the anchor
+ * to 'top'.
+ *
+ * The adjusted position is calculated given the original anchor
+ * rectangle and offset, but with the new flipped anchor and
+ * gravity values.
+ *
+ * If the adjusted position also ends up being constrained, the
+ * resulting position of the flip_y adjustment will be the one
+ * before the adjustment.
+ */
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8,
+ /**
+ * horizontally resize the surface
+ *
+ * Resize the surface horizontally so that it is completely
+ * unconstrained.
+ */
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16,
+ /**
+ * vertically resize the surface
+ *
+ * Resize the surface vertically so that it is completely
+ * unconstrained.
+ */
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32,
+};
+#endif /* XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM */
+
+/**
+ * @ingroup iface_xdg_positioner
+ * @struct xdg_positioner_interface
+ */
+struct xdg_positioner_interface {
+ /**
+ * destroy the xdg_positioner object
+ *
+ * Notify the compositor that the xdg_positioner will no longer
+ * be used.
+ */
+ void (*destroy)(struct wl_client *client,
+ struct wl_resource *resource);
+ /**
+ * set the size of the to-be positioned rectangle
+ *
+ * Set the size of the surface that is to be positioned with the
+ * positioner object. The size is in surface-local coordinates and
+ * corresponds to the window geometry. See
+ * xdg_surface.set_window_geometry.
+ *
+ * If a zero or negative size is set the invalid_input error is
+ * raised.
+ * @param width width of positioned rectangle
+ * @param height height of positioned rectangle
+ */
+ void (*set_size)(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t width,
+ int32_t height);
+ /**
+ * set the anchor rectangle within the parent surface
+ *
+ * Specify the anchor rectangle within the parent surface that
+ * the child surface will be placed relative to. The rectangle is
+ * relative to the window geometry as defined by
+ * xdg_surface.set_window_geometry of the parent surface.
+ *
+ * When the xdg_positioner object is used to position a child
+ * surface, the anchor rectangle may not extend outside the window
+ * geometry of the positioned child's parent surface.
+ *
+ * If a negative size is set the invalid_input error is raised.
+ * @param x x position of anchor rectangle
+ * @param y y position of anchor rectangle
+ * @param width width of anchor rectangle
+ * @param height height of anchor rectangle
+ */
+ void (*set_anchor_rect)(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t x,
+ int32_t y,
+ int32_t width,
+ int32_t height);
+ /**
+ * set anchor rectangle anchor
+ *
+ * Defines the anchor point for the anchor rectangle. The
+ * specified anchor is used derive an anchor point that the child
+ * surface will be positioned relative to. If a corner anchor is
+ * set (e.g. 'top_left' or 'bottom_right'), the anchor point will
+ * be at the specified corner; otherwise, the derived anchor point
+ * will be centered on the specified edge, or in the center of the
+ * anchor rectangle if no edge is specified.
+ * @param anchor anchor
+ */
+ void (*set_anchor)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t anchor);
+ /**
+ * set child surface gravity
+ *
+ * Defines in what direction a surface should be positioned,
+ * relative to the anchor point of the parent surface. If a corner
+ * gravity is specified (e.g. 'bottom_right' or 'top_left'), then
+ * the child surface will be placed towards the specified gravity;
+ * otherwise, the child surface will be centered over the anchor
+ * point on any axis that had no gravity specified. If the gravity
+ * is not in the ‘gravity’ enum, an invalid_input error is
+ * raised.
+ * @param gravity gravity direction
+ */
+ void (*set_gravity)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t gravity);
+ /**
+ * set the adjustment to be done when constrained
+ *
+ * Specify how the window should be positioned if the originally
+ * intended position caused the surface to be constrained, meaning
+ * at least partially outside positioning boundaries set by the
+ * compositor. The adjustment is set by constructing a bitmask
+ * describing the adjustment to be made when the surface is
+ * constrained on that axis.
+ *
+ * If no bit for one axis is set, the compositor will assume that
+ * the child surface should not change its position on that axis
+ * when constrained.
+ *
+ * If more than one bit for one axis is set, the order of how
+ * adjustments are applied is specified in the corresponding
+ * adjustment descriptions.
+ *
+ * The default adjustment is none.
+ * @param constraint_adjustment bit mask of constraint adjustments
+ */
+ void (*set_constraint_adjustment)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t constraint_adjustment);
+ /**
+ * set surface position offset
+ *
+ * Specify the surface position offset relative to the position
+ * of the anchor on the anchor rectangle and the anchor on the
+ * surface. For example if the anchor of the anchor rectangle is at
+ * (x, y), the surface has the gravity bottom|right, and the offset
+ * is (ox, oy), the calculated surface position will be (x + ox, y
+ * + oy). The offset position of the surface is the one used for
+ * constraint testing. See set_constraint_adjustment.
+ *
+ * An example use case is placing a popup menu on top of a user
+ * interface element, while aligning the user interface element of
+ * the parent surface with some user interface element placed
+ * somewhere in the popup surface.
+ * @param x surface position x offset
+ * @param y surface position y offset
+ */
+ void (*set_offset)(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t x,
+ int32_t y);
+ /**
+ * continuously reconstrain the surface
+ *
+ * When set reactive, the surface is reconstrained if the
+ * conditions used for constraining changed, e.g. the parent window
+ * moved.
+ *
+ * If the conditions changed and the popup was reconstrained, an
+ * xdg_popup.configure event is sent with updated geometry,
+ * followed by an xdg_surface.configure event.
+ * @since 3
+ */
+ void (*set_reactive)(struct wl_client *client,
+ struct wl_resource *resource);
+ /**
+ *
+ *
+ * Set the parent window geometry the compositor should use when
+ * positioning the popup. The compositor may use this information
+ * to determine the future state the popup should be constrained
+ * using. If this doesn't match the dimension of the parent the
+ * popup is eventually positioned against, the behavior is
+ * undefined.
+ *
+ * The arguments are given in the surface-local coordinate space.
+ * @param parent_width future window geometry width of parent
+ * @param parent_height future window geometry height of parent
+ * @since 3
+ */
+ void (*set_parent_size)(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t parent_width,
+ int32_t parent_height);
+ /**
+ * set parent configure this is a response to
+ *
+ * Set the serial of an xdg_surface.configure event this
+ * positioner will be used in response to. The compositor may use
+ * this information together with set_parent_size to determine what
+ * future state the popup should be constrained using.
+ * @param serial serial of parent configure event
+ * @since 3
+ */
+ void (*set_parent_configure)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t serial);
+};
+
+
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_SIZE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_ANCHOR_RECT_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_ANCHOR_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_GRAVITY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_OFFSET_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_REACTIVE_SINCE_VERSION 3
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_PARENT_SIZE_SINCE_VERSION 3
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_PARENT_CONFIGURE_SINCE_VERSION 3
+
+#ifndef XDG_SURFACE_ERROR_ENUM
+#define XDG_SURFACE_ERROR_ENUM
+enum xdg_surface_error {
+ /**
+ * Surface was not fully constructed
+ */
+ XDG_SURFACE_ERROR_NOT_CONSTRUCTED = 1,
+ /**
+ * Surface was already constructed
+ */
+ XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED = 2,
+ /**
+ * Attaching a buffer to an unconfigured surface
+ */
+ XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER = 3,
+ /**
+ * Invalid serial number when acking a configure event
+ */
+ XDG_SURFACE_ERROR_INVALID_SERIAL = 4,
+ /**
+ * Width or height was zero or negative
+ */
+ XDG_SURFACE_ERROR_INVALID_SIZE = 5,
+ /**
+ * Surface was destroyed before its role object
+ */
+ XDG_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT = 6,
+};
+#endif /* XDG_SURFACE_ERROR_ENUM */
+
+/**
+ * @ingroup iface_xdg_surface
+ * @struct xdg_surface_interface
+ */
+struct xdg_surface_interface {
+ /**
+ * destroy the xdg_surface
+ *
+ * Destroy the xdg_surface object. An xdg_surface must only be
+ * destroyed after its role object has been destroyed, otherwise a
+ * defunct_role_object error is raised.
+ */
+ void (*destroy)(struct wl_client *client,
+ struct wl_resource *resource);
+ /**
+ * assign the xdg_toplevel surface role
+ *
+ * This creates an xdg_toplevel object for the given xdg_surface
+ * and gives the associated wl_surface the xdg_toplevel role.
+ *
+ * See the documentation of xdg_toplevel for more details about
+ * what an xdg_toplevel is and how it is used.
+ */
+ void (*get_toplevel)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id);
+ /**
+ * assign the xdg_popup surface role
+ *
+ * This creates an xdg_popup object for the given xdg_surface and
+ * gives the associated wl_surface the xdg_popup role.
+ *
+ * If null is passed as a parent, a parent surface must be
+ * specified using some other protocol, before committing the
+ * initial state.
+ *
+ * See the documentation of xdg_popup for more details about what
+ * an xdg_popup is and how it is used.
+ */
+ void (*get_popup)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id,
+ struct wl_resource *parent,
+ struct wl_resource *positioner);
+ /**
+ * set the new window geometry
+ *
+ * The window geometry of a surface is its "visible bounds" from
+ * the user's perspective. Client-side decorations often have
+ * invisible portions like drop-shadows which should be ignored for
+ * the purposes of aligning, placing and constraining windows.
+ *
+ * The window geometry is double buffered, and will be applied at
+ * the time wl_surface.commit of the corresponding wl_surface is
+ * called.
+ *
+ * When maintaining a position, the compositor should treat the (x,
+ * y) coordinate of the window geometry as the top left corner of
+ * the window. A client changing the (x, y) window geometry
+ * coordinate should in general not alter the position of the
+ * window.
+ *
+ * Once the window geometry of the surface is set, it is not
+ * possible to unset it, and it will remain the same until
+ * set_window_geometry is called again, even if a new subsurface or
+ * buffer is attached.
+ *
+ * If never set, the value is the full bounds of the surface,
+ * including any subsurfaces. This updates dynamically on every
+ * commit. This unset is meant for extremely simple clients.
+ *
+ * The arguments are given in the surface-local coordinate space of
+ * the wl_surface associated with this xdg_surface, and may extend
+ * outside of the wl_surface itself to mark parts of the subsurface
+ * tree as part of the window geometry.
+ *
+ * When applied, the effective window geometry will be the set
+ * window geometry clamped to the bounding rectangle of the
+ * combined geometry of the surface of the xdg_surface and the
+ * associated subsurfaces.
+ *
+ * The effective geometry will not be recalculated unless a new
+ * call to set_window_geometry is done and the new pending surface
+ * state is subsequently applied.
+ *
+ * The width and height of the effective window geometry must be
+ * greater than zero. Setting an invalid size will raise an
+ * invalid_size error.
+ */
+ void (*set_window_geometry)(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t x,
+ int32_t y,
+ int32_t width,
+ int32_t height);
+ /**
+ * ack a configure event
+ *
+ * When a configure event is received, if a client commits the
+ * surface in response to the configure event, then the client must
+ * make an ack_configure request sometime before the commit
+ * request, passing along the serial of the configure event.
+ *
+ * For instance, for toplevel surfaces the compositor might use
+ * this information to move a surface to the top left only when the
+ * client has drawn itself for the maximized or fullscreen state.
+ *
+ * If the client receives multiple configure events before it can
+ * respond to one, it only has to ack the last configure event.
+ * Acking a configure event that was never sent raises an
+ * invalid_serial error.
+ *
+ * A client is not required to commit immediately after sending an
+ * ack_configure request - it may even ack_configure several times
+ * before its next surface commit.
+ *
+ * A client may send multiple ack_configure requests before
+ * committing, but only the last request sent before a commit
+ * indicates which configure event the client really is responding
+ * to.
+ *
+ * Sending an ack_configure request consumes the serial number sent
+ * with the request, as well as serial numbers sent by all
+ * configure events sent on this xdg_surface prior to the configure
+ * event referenced by the committed serial.
+ *
+ * It is an error to issue multiple ack_configure requests
+ * referencing a serial from the same configure event, or to issue
+ * an ack_configure request referencing a serial from a configure
+ * event issued before the event identified by the last
+ * ack_configure request for the same xdg_surface. Doing so will
+ * raise an invalid_serial error.
+ * @param serial the serial from the configure event
+ */
+ void (*ack_configure)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t serial);
+};
+
+#define XDG_SURFACE_CONFIGURE 0
+
+/**
+ * @ingroup iface_xdg_surface
+ */
+#define XDG_SURFACE_CONFIGURE_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_xdg_surface
+ */
+#define XDG_SURFACE_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_surface
+ */
+#define XDG_SURFACE_GET_TOPLEVEL_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_surface
+ */
+#define XDG_SURFACE_GET_POPUP_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_surface
+ */
+#define XDG_SURFACE_SET_WINDOW_GEOMETRY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_surface
+ */
+#define XDG_SURFACE_ACK_CONFIGURE_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_xdg_surface
+ * Sends an configure event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param serial serial of the configure event
+ */
+static inline void
+xdg_surface_send_configure(struct wl_resource *resource_, uint32_t serial)
+{
+ wl_resource_post_event(resource_, XDG_SURFACE_CONFIGURE, serial);
+}
+
+#ifndef XDG_TOPLEVEL_ERROR_ENUM
+#define XDG_TOPLEVEL_ERROR_ENUM
+enum xdg_toplevel_error {
+ /**
+ * provided value is not a valid variant of the resize_edge enum
+ */
+ XDG_TOPLEVEL_ERROR_INVALID_RESIZE_EDGE = 0,
+ /**
+ * invalid parent toplevel
+ */
+ XDG_TOPLEVEL_ERROR_INVALID_PARENT = 1,
+ /**
+ * client provided an invalid min or max size
+ */
+ XDG_TOPLEVEL_ERROR_INVALID_SIZE = 2,
+};
+#endif /* XDG_TOPLEVEL_ERROR_ENUM */
+
+#ifndef XDG_TOPLEVEL_RESIZE_EDGE_ENUM
+#define XDG_TOPLEVEL_RESIZE_EDGE_ENUM
+/**
+ * @ingroup iface_xdg_toplevel
+ * edge values for resizing
+ *
+ * These values are used to indicate which edge of a surface
+ * is being dragged in a resize operation.
+ */
+enum xdg_toplevel_resize_edge {
+ XDG_TOPLEVEL_RESIZE_EDGE_NONE = 0,
+ XDG_TOPLEVEL_RESIZE_EDGE_TOP = 1,
+ XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM = 2,
+ XDG_TOPLEVEL_RESIZE_EDGE_LEFT = 4,
+ XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT = 5,
+ XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT = 6,
+ XDG_TOPLEVEL_RESIZE_EDGE_RIGHT = 8,
+ XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT = 9,
+ XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT = 10,
+};
+#endif /* XDG_TOPLEVEL_RESIZE_EDGE_ENUM */
+
+#ifndef XDG_TOPLEVEL_STATE_ENUM
+#define XDG_TOPLEVEL_STATE_ENUM
+/**
+ * @ingroup iface_xdg_toplevel
+ * types of state on the surface
+ *
+ * The different state values used on the surface. This is designed for
+ * state values like maximized, fullscreen. It is paired with the
+ * configure event to ensure that both the client and the compositor
+ * setting the state can be synchronized.
+ *
+ * States set in this way are double-buffered. They will get applied on
+ * the next commit.
+ */
+enum xdg_toplevel_state {
+ /**
+ * the surface is maximized
+ * the surface is maximized
+ *
+ * The surface is maximized. The window geometry specified in the
+ * configure event must be obeyed by the client, or the
+ * xdg_wm_base.invalid_surface_state error is raised.
+ *
+ * The client should draw without shadow or other decoration
+ * outside of the window geometry.
+ */
+ XDG_TOPLEVEL_STATE_MAXIMIZED = 1,
+ /**
+ * the surface is fullscreen
+ * the surface is fullscreen
+ *
+ * The surface is fullscreen. The window geometry specified in
+ * the configure event is a maximum; the client cannot resize
+ * beyond it. For a surface to cover the whole fullscreened area,
+ * the geometry dimensions must be obeyed by the client. For more
+ * details, see xdg_toplevel.set_fullscreen.
+ */
+ XDG_TOPLEVEL_STATE_FULLSCREEN = 2,
+ /**
+ * the surface is being resized
+ * the surface is being resized
+ *
+ * The surface is being resized. The window geometry specified in
+ * the configure event is a maximum; the client cannot resize
+ * beyond it. Clients that have aspect ratio or cell sizing
+ * configuration can use a smaller size, however.
+ */
+ XDG_TOPLEVEL_STATE_RESIZING = 3,
+ /**
+ * the surface is now activated
+ * the surface is now activated
+ *
+ * Client window decorations should be painted as if the window
+ * is active. Do not assume this means that the window actually has
+ * keyboard or pointer focus.
+ */
+ XDG_TOPLEVEL_STATE_ACTIVATED = 4,
+ /**
+ * the surface’s left edge is tiled
+ *
+ * The window is currently in a tiled layout and the left edge is
+ * considered to be adjacent to another part of the tiling grid.
+ * @since 2
+ */
+ XDG_TOPLEVEL_STATE_TILED_LEFT = 5,
+ /**
+ * the surface’s right edge is tiled
+ *
+ * The window is currently in a tiled layout and the right edge
+ * is considered to be adjacent to another part of the tiling grid.
+ * @since 2
+ */
+ XDG_TOPLEVEL_STATE_TILED_RIGHT = 6,
+ /**
+ * the surface’s top edge is tiled
+ *
+ * The window is currently in a tiled layout and the top edge is
+ * considered to be adjacent to another part of the tiling grid.
+ * @since 2
+ */
+ XDG_TOPLEVEL_STATE_TILED_TOP = 7,
+ /**
+ * the surface’s bottom edge is tiled
+ *
+ * The window is currently in a tiled layout and the bottom edge
+ * is considered to be adjacent to another part of the tiling grid.
+ * @since 2
+ */
+ XDG_TOPLEVEL_STATE_TILED_BOTTOM = 8,
+ /**
+ * surface repaint is suspended
+ *
+ * The surface is currently not ordinarily being repainted; for
+ * example because its content is occluded by another window, or
+ * its outputs are switched off due to screen locking.
+ * @since 6
+ */
+ XDG_TOPLEVEL_STATE_SUSPENDED = 9,
+};
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION 2
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION 2
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_STATE_TILED_TOP_SINCE_VERSION 2
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_STATE_TILED_BOTTOM_SINCE_VERSION 2
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION 6
+#endif /* XDG_TOPLEVEL_STATE_ENUM */
+
+#ifndef XDG_TOPLEVEL_WM_CAPABILITIES_ENUM
+#define XDG_TOPLEVEL_WM_CAPABILITIES_ENUM
+enum xdg_toplevel_wm_capabilities {
+ /**
+ * show_window_menu is available
+ */
+ XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU = 1,
+ /**
+ * set_maximized and unset_maximized are available
+ */
+ XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE = 2,
+ /**
+ * set_fullscreen and unset_fullscreen are available
+ */
+ XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN = 3,
+ /**
+ * set_minimized is available
+ */
+ XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE = 4,
+};
+#endif /* XDG_TOPLEVEL_WM_CAPABILITIES_ENUM */
+
+/**
+ * @ingroup iface_xdg_toplevel
+ * @struct xdg_toplevel_interface
+ */
+struct xdg_toplevel_interface {
+ /**
+ * destroy the xdg_toplevel
+ *
+ * This request destroys the role surface and unmaps the surface;
+ * see "Unmapping" behavior in interface section for details.
+ */
+ void (*destroy)(struct wl_client *client,
+ struct wl_resource *resource);
+ /**
+ * set the parent of this surface
+ *
+ * Set the "parent" of this surface. This surface should be
+ * stacked above the parent surface and all other ancestor
+ * surfaces.
+ *
+ * Parent surfaces should be set on dialogs, toolboxes, or other
+ * "auxiliary" surfaces, so that the parent is raised when the
+ * dialog is raised.
+ *
+ * Setting a null parent for a child surface unsets its parent.
+ * Setting a null parent for a surface which currently has no
+ * parent is a no-op.
+ *
+ * Only mapped surfaces can have child surfaces. Setting a parent
+ * which is not mapped is equivalent to setting a null parent. If a
+ * surface becomes unmapped, its children's parent is set to the
+ * parent of the now-unmapped surface. If the now-unmapped surface
+ * has no parent, its children's parent is unset. If the
+ * now-unmapped surface becomes mapped again, its parent-child
+ * relationship is not restored.
+ *
+ * The parent toplevel must not be one of the child toplevel's
+ * descendants, and the parent must be different from the child
+ * toplevel, otherwise the invalid_parent protocol error is raised.
+ */
+ void (*set_parent)(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *parent);
+ /**
+ * set surface title
+ *
+ * Set a short title for the surface.
+ *
+ * This string may be used to identify the surface in a task bar,
+ * window list, or other user interface elements provided by the
+ * compositor.
+ *
+ * The string must be encoded in UTF-8.
+ */
+ void (*set_title)(struct wl_client *client,
+ struct wl_resource *resource,
+ const char *title);
+ /**
+ * set application ID
+ *
+ * Set an application identifier for the surface.
+ *
+ * The app ID identifies the general class of applications to which
+ * the surface belongs. The compositor can use this to group
+ * multiple surfaces together, or to determine how to launch a new
+ * application.
+ *
+ * For D-Bus activatable applications, the app ID is used as the
+ * D-Bus service name.
+ *
+ * The compositor shell will try to group application surfaces
+ * together by their app ID. As a best practice, it is suggested to
+ * select app ID's that match the basename of the application's
+ * .desktop file. For example, "org.freedesktop.FooViewer" where
+ * the .desktop file is "org.freedesktop.FooViewer.desktop".
+ *
+ * Like other properties, a set_app_id request can be sent after
+ * the xdg_toplevel has been mapped to update the property.
+ *
+ * See the desktop-entry specification [0] for more details on
+ * application identifiers and how they relate to well-known D-Bus
+ * names and .desktop files.
+ *
+ * [0] https://standards.freedesktop.org/desktop-entry-spec/
+ */
+ void (*set_app_id)(struct wl_client *client,
+ struct wl_resource *resource,
+ const char *app_id);
+ /**
+ * show the window menu
+ *
+ * Clients implementing client-side decorations might want to
+ * show a context menu when right-clicking on the decorations,
+ * giving the user a menu that they can use to maximize or minimize
+ * the window.
+ *
+ * This request asks the compositor to pop up such a window menu at
+ * the given position, relative to the local surface coordinates of
+ * the parent surface. There are no guarantees as to what menu
+ * items the window menu contains, or even if a window menu will be
+ * drawn at all.
+ *
+ * This request must be used in response to some sort of user
+ * action like a button press, key press, or touch down event.
+ * @param seat the wl_seat of the user event
+ * @param serial the serial of the user event
+ * @param x the x position to pop up the window menu at
+ * @param y the y position to pop up the window menu at
+ */
+ void (*show_window_menu)(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *seat,
+ uint32_t serial,
+ int32_t x,
+ int32_t y);
+ /**
+ * start an interactive move
+ *
+ * Start an interactive, user-driven move of the surface.
+ *
+ * This request must be used in response to some sort of user
+ * action like a button press, key press, or touch down event. The
+ * passed serial is used to determine the type of interactive move
+ * (touch, pointer, etc).
+ *
+ * The server may ignore move requests depending on the state of
+ * the surface (e.g. fullscreen or maximized), or if the passed
+ * serial is no longer valid.
+ *
+ * If triggered, the surface will lose the focus of the device
+ * (wl_pointer, wl_touch, etc) used for the move. It is up to the
+ * compositor to visually indicate that the move is taking place,
+ * such as updating a pointer cursor, during the move. There is no
+ * guarantee that the device focus will return when the move is
+ * completed.
+ * @param seat the wl_seat of the user event
+ * @param serial the serial of the user event
+ */
+ void (*move)(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *seat,
+ uint32_t serial);
+ /**
+ * start an interactive resize
+ *
+ * Start a user-driven, interactive resize of the surface.
+ *
+ * This request must be used in response to some sort of user
+ * action like a button press, key press, or touch down event. The
+ * passed serial is used to determine the type of interactive
+ * resize (touch, pointer, etc).
+ *
+ * The server may ignore resize requests depending on the state of
+ * the surface (e.g. fullscreen or maximized).
+ *
+ * If triggered, the client will receive configure events with the
+ * "resize" state enum value and the expected sizes. See the
+ * "resize" enum value for more details about what is required. The
+ * client must also acknowledge configure events using
+ * "ack_configure". After the resize is completed, the client will
+ * receive another "configure" event without the resize state.
+ *
+ * If triggered, the surface also will lose the focus of the device
+ * (wl_pointer, wl_touch, etc) used for the resize. It is up to the
+ * compositor to visually indicate that the resize is taking place,
+ * such as updating a pointer cursor, during the resize. There is
+ * no guarantee that the device focus will return when the resize
+ * is completed.
+ *
+ * The edges parameter specifies how the surface should be resized,
+ * and is one of the values of the resize_edge enum. Values not
+ * matching a variant of the enum will cause the
+ * invalid_resize_edge protocol error. The compositor may use this
+ * information to update the surface position for example when
+ * dragging the top left corner. The compositor may also use this
+ * information to adapt its behavior, e.g. choose an appropriate
+ * cursor image.
+ * @param seat the wl_seat of the user event
+ * @param serial the serial of the user event
+ * @param edges which edge or corner is being dragged
+ */
+ void (*resize)(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *seat,
+ uint32_t serial,
+ uint32_t edges);
+ /**
+ * set the maximum size
+ *
+ * Set a maximum size for the window.
+ *
+ * The client can specify a maximum size so that the compositor
+ * does not try to configure the window beyond this size.
+ *
+ * The width and height arguments are in window geometry
+ * coordinates. See xdg_surface.set_window_geometry.
+ *
+ * Values set in this way are double-buffered. They will get
+ * applied on the next commit.
+ *
+ * The compositor can use this information to allow or disallow
+ * different states like maximize or fullscreen and draw accurate
+ * animations.
+ *
+ * Similarly, a tiling window manager may use this information to
+ * place and resize client windows in a more effective way.
+ *
+ * The client should not rely on the compositor to obey the maximum
+ * size. The compositor may decide to ignore the values set by the
+ * client and request a larger size.
+ *
+ * If never set, or a value of zero in the request, means that the
+ * client has no expected maximum size in the given dimension. As a
+ * result, a client wishing to reset the maximum size to an
+ * unspecified state can use zero for width and height in the
+ * request.
+ *
+ * Requesting a maximum size to be smaller than the minimum size of
+ * a surface is illegal and will result in an invalid_size error.
+ *
+ * The width and height must be greater than or equal to zero.
+ * Using strictly negative values for width or height will result
+ * in a invalid_size error.
+ */
+ void (*set_max_size)(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t width,
+ int32_t height);
+ /**
+ * set the minimum size
+ *
+ * Set a minimum size for the window.
+ *
+ * The client can specify a minimum size so that the compositor
+ * does not try to configure the window below this size.
+ *
+ * The width and height arguments are in window geometry
+ * coordinates. See xdg_surface.set_window_geometry.
+ *
+ * Values set in this way are double-buffered. They will get
+ * applied on the next commit.
+ *
+ * The compositor can use this information to allow or disallow
+ * different states like maximize or fullscreen and draw accurate
+ * animations.
+ *
+ * Similarly, a tiling window manager may use this information to
+ * place and resize client windows in a more effective way.
+ *
+ * The client should not rely on the compositor to obey the minimum
+ * size. The compositor may decide to ignore the values set by the
+ * client and request a smaller size.
+ *
+ * If never set, or a value of zero in the request, means that the
+ * client has no expected minimum size in the given dimension. As a
+ * result, a client wishing to reset the minimum size to an
+ * unspecified state can use zero for width and height in the
+ * request.
+ *
+ * Requesting a minimum size to be larger than the maximum size of
+ * a surface is illegal and will result in an invalid_size error.
+ *
+ * The width and height must be greater than or equal to zero.
+ * Using strictly negative values for width and height will result
+ * in a invalid_size error.
+ */
+ void (*set_min_size)(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t width,
+ int32_t height);
+ /**
+ * maximize the window
+ *
+ * Maximize the surface.
+ *
+ * After requesting that the surface should be maximized, the
+ * compositor will respond by emitting a configure event. Whether
+ * this configure actually sets the window maximized is subject to
+ * compositor policies. The client must then update its content,
+ * drawing in the configured state. The client must also
+ * acknowledge the configure when committing the new content (see
+ * ack_configure).
+ *
+ * It is up to the compositor to decide how and where to maximize
+ * the surface, for example which output and what region of the
+ * screen should be used.
+ *
+ * If the surface was already maximized, the compositor will still
+ * emit a configure event with the "maximized" state.
+ *
+ * If the surface is in a fullscreen state, this request has no
+ * direct effect. It may alter the state the surface is returned to
+ * when unmaximized unless overridden by the compositor.
+ */
+ void (*set_maximized)(struct wl_client *client,
+ struct wl_resource *resource);
+ /**
+ * unmaximize the window
+ *
+ * Unmaximize the surface.
+ *
+ * After requesting that the surface should be unmaximized, the
+ * compositor will respond by emitting a configure event. Whether
+ * this actually un-maximizes the window is subject to compositor
+ * policies. If available and applicable, the compositor will
+ * include the window geometry dimensions the window had prior to
+ * being maximized in the configure event. The client must then
+ * update its content, drawing it in the configured state. The
+ * client must also acknowledge the configure when committing the
+ * new content (see ack_configure).
+ *
+ * It is up to the compositor to position the surface after it was
+ * unmaximized; usually the position the surface had before
+ * maximizing, if applicable.
+ *
+ * If the surface was already not maximized, the compositor will
+ * still emit a configure event without the "maximized" state.
+ *
+ * If the surface is in a fullscreen state, this request has no
+ * direct effect. It may alter the state the surface is returned to
+ * when unmaximized unless overridden by the compositor.
+ */
+ void (*unset_maximized)(struct wl_client *client,
+ struct wl_resource *resource);
+ /**
+ * set the window as fullscreen on an output
+ *
+ * Make the surface fullscreen.
+ *
+ * After requesting that the surface should be fullscreened, the
+ * compositor will respond by emitting a configure event. Whether
+ * the client is actually put into a fullscreen state is subject to
+ * compositor policies. The client must also acknowledge the
+ * configure when committing the new content (see ack_configure).
+ *
+ * The output passed by the request indicates the client's
+ * preference as to which display it should be set fullscreen on.
+ * If this value is NULL, it's up to the compositor to choose which
+ * display will be used to map this surface.
+ *
+ * If the surface doesn't cover the whole output, the compositor
+ * will position the surface in the center of the output and
+ * compensate with with border fill covering the rest of the
+ * output. The content of the border fill is undefined, but should
+ * be assumed to be in some way that attempts to blend into the
+ * surrounding area (e.g. solid black).
+ *
+ * If the fullscreened surface is not opaque, the compositor must
+ * make sure that other screen content not part of the same surface
+ * tree (made up of subsurfaces, popups or similarly coupled
+ * surfaces) are not visible below the fullscreened surface.
+ */
+ void (*set_fullscreen)(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *output);
+ /**
+ * unset the window as fullscreen
+ *
+ * Make the surface no longer fullscreen.
+ *
+ * After requesting that the surface should be unfullscreened, the
+ * compositor will respond by emitting a configure event. Whether
+ * this actually removes the fullscreen state of the client is
+ * subject to compositor policies.
+ *
+ * Making a surface unfullscreen sets states for the surface based
+ * on the following: * the state(s) it may have had before becoming
+ * fullscreen * any state(s) decided by the compositor * any
+ * state(s) requested by the client while the surface was
+ * fullscreen
+ *
+ * The compositor may include the previous window geometry
+ * dimensions in the configure event, if applicable.
+ *
+ * The client must also acknowledge the configure when committing
+ * the new content (see ack_configure).
+ */
+ void (*unset_fullscreen)(struct wl_client *client,
+ struct wl_resource *resource);
+ /**
+ * set the window as minimized
+ *
+ * Request that the compositor minimize your surface. There is no
+ * way to know if the surface is currently minimized, nor is there
+ * any way to unset minimization on this surface.
+ *
+ * If you are looking to throttle redrawing when minimized, please
+ * instead use the wl_surface.frame event for this, as this will
+ * also work with live previews on windows in Alt-Tab, Expose or
+ * similar compositor features.
+ */
+ void (*set_minimized)(struct wl_client *client,
+ struct wl_resource *resource);
+};
+
+#define XDG_TOPLEVEL_CONFIGURE 0
+#define XDG_TOPLEVEL_CLOSE 1
+#define XDG_TOPLEVEL_CONFIGURE_BOUNDS 2
+#define XDG_TOPLEVEL_WM_CAPABILITIES 3
+
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_CONFIGURE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_CLOSE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION 4
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION 5
+
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_PARENT_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_TITLE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_APP_ID_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SHOW_WINDOW_MENU_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_MOVE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_RESIZE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_MAX_SIZE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_MIN_SIZE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_MAXIMIZED_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_UNSET_MAXIMIZED_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_FULLSCREEN_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_UNSET_FULLSCREEN_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_MINIMIZED_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_xdg_toplevel
+ * Sends an configure event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+xdg_toplevel_send_configure(struct wl_resource *resource_, int32_t width, int32_t height, struct wl_array *states)
+{
+ wl_resource_post_event(resource_, XDG_TOPLEVEL_CONFIGURE, width, height, states);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ * Sends an close event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+xdg_toplevel_send_close(struct wl_resource *resource_)
+{
+ wl_resource_post_event(resource_, XDG_TOPLEVEL_CLOSE);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ * Sends an configure_bounds event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+xdg_toplevel_send_configure_bounds(struct wl_resource *resource_, int32_t width, int32_t height)
+{
+ wl_resource_post_event(resource_, XDG_TOPLEVEL_CONFIGURE_BOUNDS, width, height);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ * Sends an wm_capabilities event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param capabilities array of 32-bit capabilities
+ */
+static inline void
+xdg_toplevel_send_wm_capabilities(struct wl_resource *resource_, struct wl_array *capabilities)
+{
+ wl_resource_post_event(resource_, XDG_TOPLEVEL_WM_CAPABILITIES, capabilities);
+}
+
+#ifndef XDG_POPUP_ERROR_ENUM
+#define XDG_POPUP_ERROR_ENUM
+enum xdg_popup_error {
+ /**
+ * tried to grab after being mapped
+ */
+ XDG_POPUP_ERROR_INVALID_GRAB = 0,
+};
+#endif /* XDG_POPUP_ERROR_ENUM */
+
+/**
+ * @ingroup iface_xdg_popup
+ * @struct xdg_popup_interface
+ */
+struct xdg_popup_interface {
+ /**
+ * remove xdg_popup interface
+ *
+ * This destroys the popup. Explicitly destroying the xdg_popup
+ * object will also dismiss the popup, and unmap the surface.
+ *
+ * If this xdg_popup is not the "topmost" popup, the
+ * xdg_wm_base.not_the_topmost_popup protocol error will be sent.
+ */
+ void (*destroy)(struct wl_client *client,
+ struct wl_resource *resource);
+ /**
+ * make the popup take an explicit grab
+ *
+ * This request makes the created popup take an explicit grab. An
+ * explicit grab will be dismissed when the user dismisses the
+ * popup, or when the client destroys the xdg_popup. This can be
+ * done by the user clicking outside the surface, using the
+ * keyboard, or even locking the screen through closing the lid or
+ * a timeout.
+ *
+ * If the compositor denies the grab, the popup will be immediately
+ * dismissed.
+ *
+ * This request must be used in response to some sort of user
+ * action like a button press, key press, or touch down event. The
+ * serial number of the event should be passed as 'serial'.
+ *
+ * The parent of a grabbing popup must either be an xdg_toplevel
+ * surface or another xdg_popup with an explicit grab. If the
+ * parent is another xdg_popup it means that the popups are nested,
+ * with this popup now being the topmost popup.
+ *
+ * Nested popups must be destroyed in the reverse order they were
+ * created in, e.g. the only popup you are allowed to destroy at
+ * all times is the topmost one.
+ *
+ * When compositors choose to dismiss a popup, they may dismiss
+ * every nested grabbing popup as well. When a compositor dismisses
+ * popups, it will follow the same dismissing order as required
+ * from the client.
+ *
+ * If the topmost grabbing popup is destroyed, the grab will be
+ * returned to the parent of the popup, if that parent previously
+ * had an explicit grab.
+ *
+ * If the parent is a grabbing popup which has already been
+ * dismissed, this popup will be immediately dismissed. If the
+ * parent is a popup that did not take an explicit grab, an error
+ * will be raised.
+ *
+ * During a popup grab, the client owning the grab will receive
+ * pointer and touch events for all their surfaces as normal
+ * (similar to an "owner-events" grab in X11 parlance), while the
+ * top most grabbing popup will always have keyboard focus.
+ * @param seat the wl_seat of the user event
+ * @param serial the serial of the user event
+ */
+ void (*grab)(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *seat,
+ uint32_t serial);
+ /**
+ * recalculate the popup's location
+ *
+ * Reposition an already-mapped popup. The popup will be placed
+ * given the details in the passed xdg_positioner object, and a
+ * xdg_popup.repositioned followed by xdg_popup.configure and
+ * xdg_surface.configure will be emitted in response. Any
+ * parameters set by the previous positioner will be discarded.
+ *
+ * The passed token will be sent in the corresponding
+ * xdg_popup.repositioned event. The new popup position will not
+ * take effect until the corresponding configure event is
+ * acknowledged by the client. See xdg_popup.repositioned for
+ * details. The token itself is opaque, and has no other special
+ * meaning.
+ *
+ * If multiple reposition requests are sent, the compositor may
+ * skip all but the last one.
+ *
+ * If the popup is repositioned in response to a configure event
+ * for its parent, the client should send an
+ * xdg_positioner.set_parent_configure and possibly an
+ * xdg_positioner.set_parent_size request to allow the compositor
+ * to properly constrain the popup.
+ *
+ * If the popup is repositioned together with a parent that is
+ * being resized, but not in response to a configure event, the
+ * client should send an xdg_positioner.set_parent_size request.
+ * @param token reposition request token
+ * @since 3
+ */
+ void (*reposition)(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *positioner,
+ uint32_t token);
+};
+
+#define XDG_POPUP_CONFIGURE 0
+#define XDG_POPUP_POPUP_DONE 1
+#define XDG_POPUP_REPOSITIONED 2
+
+/**
+ * @ingroup iface_xdg_popup
+ */
+#define XDG_POPUP_CONFIGURE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_popup
+ */
+#define XDG_POPUP_POPUP_DONE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_popup
+ */
+#define XDG_POPUP_REPOSITIONED_SINCE_VERSION 3
+
+/**
+ * @ingroup iface_xdg_popup
+ */
+#define XDG_POPUP_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_popup
+ */
+#define XDG_POPUP_GRAB_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_popup
+ */
+#define XDG_POPUP_REPOSITION_SINCE_VERSION 3
+
+/**
+ * @ingroup iface_xdg_popup
+ * Sends an configure event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param x x position relative to parent surface window geometry
+ * @param y y position relative to parent surface window geometry
+ * @param width window geometry width
+ * @param height window geometry height
+ */
+static inline void
+xdg_popup_send_configure(struct wl_resource *resource_, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+ wl_resource_post_event(resource_, XDG_POPUP_CONFIGURE, x, y, width, height);
+}
+
+/**
+ * @ingroup iface_xdg_popup
+ * Sends an popup_done event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+xdg_popup_send_popup_done(struct wl_resource *resource_)
+{
+ wl_resource_post_event(resource_, XDG_POPUP_POPUP_DONE);
+}
+
+/**
+ * @ingroup iface_xdg_popup
+ * Sends an repositioned event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param token reposition request token
+ */
+static inline void
+xdg_popup_send_repositioned(struct wl_resource *resource_, uint32_t token)
+{
+ wl_resource_post_event(resource_, XDG_POPUP_REPOSITIONED, token);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/dwlb/LICENSE b/dwlb/LICENSE
@@ -0,0 +1,793 @@
+dwlb - bar for dwl
+
+Copyright © 2023 kolunmi
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+---
+
+dtao - dzen for Wayland
+
+Copyright © 2021 Devin J. Pohly and dtao team
+
+See also the license information in dtao.c.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+----
+
+Portions of the code labeled [dzen] are derived from the original dzen2 and
+used under the following license:
+
+MIT/X Consortium License
+
+(C)opyright MMVII Robert Manea <rob dot manea at gmail dot com>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+----
+
+Portions of the code labeled [wlroots] are derived from wlroots and used under
+the following license:
+
+Copyright (c) 2017, 2018 Drew DeVault
+Copyright (c) 2014 Jari Vetoniemi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+----
+
+Portions of the code labeled [swaywm] are derived from sway and are used under
+the following license:
+
+Copyright (c) 2016-2017 Drew DeVault
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+----
+
+Portions of the code labeled [wayland-book] are derived from example code found
+in The Wayland Protocol by Drew DeVault (https://wayland-book.com/). The book
+is available under CC-BY-SA 4.0, and the author indicates that code examples may
+be used under CC0.
+
+----
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<https://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<https://www.gnu.org/licenses/why-not-lgpl.html>.
diff --git a/dwlb/Makefile b/dwlb/Makefile
@@ -0,0 +1,52 @@
+BINS = dwlb
+MANS = dwlb.1
+
+PREFIX = $(HOME)/.local
+CFLAGS += -Wall -Wextra -Wno-unused-parameter -Wno-format-truncation -g
+
+all: $(BINS)
+
+clean:
+ $(RM) $(BINS) $(addsuffix .o,$(BINS))
+
+install: all
+ install -D -t $(PREFIX)/bin $(BINS)
+ install -D -m0644 -t $(PREFIX)/share/man/man1 $(MANS)
+
+WAYLAND_PROTOCOLS=$(shell pkg-config --variable=pkgdatadir wayland-protocols)
+WAYLAND_SCANNER=$(shell pkg-config --variable=wayland_scanner wayland-scanner)
+
+xdg-shell-protocol.h:
+ $(WAYLAND_SCANNER) client-header $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
+xdg-shell-protocol.c:
+ $(WAYLAND_SCANNER) private-code $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
+xdg-shell-protocol.o: xdg-shell-protocol.h
+
+xdg-output-unstable-v1-protocol.h:
+ $(WAYLAND_SCANNER) client-header $(WAYLAND_PROTOCOLS)/unstable/xdg-output/xdg-output-unstable-v1.xml $@
+xdg-output-unstable-v1-protocol.c:
+ $(WAYLAND_SCANNER) private-code $(WAYLAND_PROTOCOLS)/unstable/xdg-output/xdg-output-unstable-v1.xml $@
+xdg-output-unstable-v1-protocol.o: xdg-output-unstable-v1-protocol.h
+
+wlr-layer-shell-unstable-v1-protocol.h:
+ $(WAYLAND_SCANNER) client-header protocols/wlr-layer-shell-unstable-v1.xml $@
+wlr-layer-shell-unstable-v1-protocol.c:
+ $(WAYLAND_SCANNER) private-code protocols/wlr-layer-shell-unstable-v1.xml $@
+wlr-layer-shell-unstable-v1-protocol.o: wlr-layer-shell-unstable-v1-protocol.h
+
+dwl-ipc-unstable-v2-protocol.h:
+ $(WAYLAND_SCANNER) client-header protocols/dwl-ipc-unstable-v2.xml $@
+dwl-ipc-unstable-v2-protocol.c:
+ $(WAYLAND_SCANNER) private-code protocols/dwl-ipc-unstable-v2.xml $@
+dwl-ipc-unstable-v2-protocol.o: dwl-ipc-unstable-v2-protocol.h
+
+dwlb.o: utf8.h config.h xdg-shell-protocol.h xdg-output-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h dwl-ipc-unstable-v2-protocol.h
+
+# Protocol dependencies
+dwlb: xdg-shell-protocol.o xdg-output-unstable-v1-protocol.o wlr-layer-shell-unstable-v1-protocol.o dwl-ipc-unstable-v2-protocol.o
+
+# Library dependencies
+dwlb: CFLAGS+=$(shell pkg-config --cflags wayland-client wayland-cursor fcft pixman-1)
+dwlb: LDLIBS+=$(shell pkg-config --libs wayland-client wayland-cursor fcft pixman-1) -lrt
+
+.PHONY: all clean install
diff --git a/dwlb/README.md b/dwlb/README.md
@@ -0,0 +1,72 @@
+<div align="center">
+<h1>dwlb</h1>
+
+A fast, feature-complete bar for [dwl](https://github.com/djpohly/dwl).
+
+![screenshot 1](/screenshot1.png "screenshot 1")
+![screenshot 2](/screenshot2.png "screenshot 2")
+</div>
+
+## Dependencies
+* libwayland-client
+* libwayland-cursor
+* pixman
+* fcft
+
+## Installation
+```bash
+git clone https://github.com/kolunmi/dwlb
+cd dwlb
+make
+make install
+```
+
+## Usage
+Pass `dwlb` as an argument to dwl's `-s` flag. This will populate each connected output with a bar. For example:
+```bash
+dwl -s 'dwlb -font "monospace:size=16"'
+```
+
+## Ipc
+If dwl is [patched](https://github.com/djpohly/dwl/wiki/ipc) appropriately, dwlb is capable of communicating directly with dwl. When ipc is enabled with `-ipc`, dwlb does not read from stdin, and clicking tags functions as you would expect. Ipc can be disabled with `-no-ipc`.
+
+## Commands
+Command options send instructions to existing instances of dwlb. All commands take at least one argument to specify a bar on which to operate. This may be zxdg_output_v1 name, "all" to affect all outputs, or "selected" for the current output.
+
+### Status Text
+The `-status` and `-title` commands are used to write status text. The text may contain in-line commands in the following format: `^cmd(argument)`.
+
+| In-Line Command | Description |
+|---------------------|-----------------------------------------------------------------------------|
+| `^fg(HEXCOLOR)` | Sets foreground color to `HEXCOLOR`. |
+| `^bg(HEXCOLOR)` | Sets background color to `HEXCOLOR`. |
+| `^lm(SHELLCOMMAND)` | Begins or terminates left mouse button region with action `SHELLCOMMAND`. |
+| `^mm(SHELLCOMMAND)` | Begins or terminates middle mouse button region with action `SHELLCOMMAND`. |
+| `^rm(SHELLCOMMAND)` | Begins or terminates right mouse button region with action `SHELLCOMMAND`. |
+
+In this example, clicking the text highlighted in red will spawn the [foot](https://codeberg.org/dnkl/foot) terminal.
+```bash
+dwlb -status all 'text ^bg(ff0000)^lm(foot)text^bg()^lm() text'
+```
+
+A color command with no argument reverts to the default value. `^^` represents a single `^` character. Status commands can be disabled with `-no-status-commands`.
+
+## Scaling
+If you use scaling in Wayland, you can specify `buffer_scale` through config file or by passing it as an option (only integer values):
+```bash
+dwlb -scale 2
+```
+This will render both surface and a cursor with 2x detail. If your monitor is set to 1.25 or 1.5 scaling, setting scale to 2 will also work as compositor will downscale the buffer properly.
+
+## Other Options
+Run `dwlb -h` for a full list of options.
+
+## Someblocks
+To use someblocks, or any program that outputs to stdout, with dwlb, use this one-liner:
+```bash
+someblocks -p | dwlb -status-stdin all
+```
+
+## Acknowledgements
+* [dtao](https://github.com/djpohly/dtao)
+* [somebar](https://sr.ht/~raphi/somebar/)
diff --git a/dwlb/config.h b/dwlb/config.h
@@ -0,0 +1,48 @@
+#define NOT_DWL
+#include "../dwl/device.h"
+
+// use ipc functionality
+static bool ipc = true;
+// initially hide all bars
+static bool hidden = false;
+// initially draw all bars at the bottom
+static bool bottom = false;
+// hide vacant tags
+static bool hide_vacant = true;
+// vertical pixel padding above and below text
+static uint32_t vertical_padding = 1;
+// allow in-line color commands in status text
+static bool status_commands = true;
+// center title text
+static bool center_title = false;
+// use title space as status text element
+static bool custom_title = false;
+// scale
+static uint32_t buffer_scale = 1;
+// font
+static char *fontstr = DEVICE_FONT;
+// tag names
+static char *tags_names[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+
+#define COLOR(r, g, b) { .red = 0x##r##r, .green = 0x##g##g, .blue = 0x##b##b, .alpha = 0xffff }
+
+#define FG COLOR(e4, e4, e4)
+#define BG COLOR(18, 18, 18)
+
+#define BLUE COLOR(34, 65, A4)
+#define RED COLOR(a4, 00, 00)
+
+static pixman_color_t active_fg_color = FG;
+static pixman_color_t active_bg_color = BLUE;
+
+static pixman_color_t occupied_fg_color = FG;
+static pixman_color_t occupied_bg_color = BG;
+
+static pixman_color_t inactive_fg_color = FG;
+static pixman_color_t inactive_bg_color = BG;
+
+static pixman_color_t urgent_fg_color = RED;
+static pixman_color_t urgent_bg_color = BG;
+
+static pixman_color_t middle_bg_color = BG;
+static pixman_color_t middle_bg_color_selected = BLUE;
diff --git a/dwlb/dwl-ipc-unstable-v2-protocol.c b/dwlb/dwl-ipc-unstable-v2-protocol.c
@@ -0,0 +1,70 @@
+/* Generated by wayland-scanner 1.22.0 */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+#ifndef __has_attribute
+# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
+#endif
+
+#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
+#define WL_PRIVATE __attribute__ ((visibility("hidden")))
+#else
+#define WL_PRIVATE
+#endif
+
+extern const struct wl_interface wl_output_interface;
+extern const struct wl_interface zdwl_ipc_output_v2_interface;
+
+static const struct wl_interface *dwl_ipc_unstable_v2_types[] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &zdwl_ipc_output_v2_interface,
+ &wl_output_interface,
+};
+
+static const struct wl_message zdwl_ipc_manager_v2_requests[] = {
+ { "release", "", dwl_ipc_unstable_v2_types + 0 },
+ { "get_output", "no", dwl_ipc_unstable_v2_types + 4 },
+};
+
+static const struct wl_message zdwl_ipc_manager_v2_events[] = {
+ { "tags", "u", dwl_ipc_unstable_v2_types + 0 },
+ { "layout", "s", dwl_ipc_unstable_v2_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface zdwl_ipc_manager_v2_interface = {
+ "zdwl_ipc_manager_v2", 2,
+ 2, zdwl_ipc_manager_v2_requests,
+ 2, zdwl_ipc_manager_v2_events,
+};
+
+static const struct wl_message zdwl_ipc_output_v2_requests[] = {
+ { "release", "", dwl_ipc_unstable_v2_types + 0 },
+ { "set_tags", "uu", dwl_ipc_unstable_v2_types + 0 },
+ { "set_client_tags", "uu", dwl_ipc_unstable_v2_types + 0 },
+ { "set_layout", "u", dwl_ipc_unstable_v2_types + 0 },
+};
+
+static const struct wl_message zdwl_ipc_output_v2_events[] = {
+ { "toggle_visibility", "", dwl_ipc_unstable_v2_types + 0 },
+ { "active", "u", dwl_ipc_unstable_v2_types + 0 },
+ { "tag", "uuuu", dwl_ipc_unstable_v2_types + 0 },
+ { "layout", "u", dwl_ipc_unstable_v2_types + 0 },
+ { "title", "s", dwl_ipc_unstable_v2_types + 0 },
+ { "appid", "s", dwl_ipc_unstable_v2_types + 0 },
+ { "layout_symbol", "s", dwl_ipc_unstable_v2_types + 0 },
+ { "frame", "", dwl_ipc_unstable_v2_types + 0 },
+ { "fullscreen", "2u", dwl_ipc_unstable_v2_types + 0 },
+ { "floating", "2u", dwl_ipc_unstable_v2_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface zdwl_ipc_output_v2_interface = {
+ "zdwl_ipc_output_v2", 2,
+ 4, zdwl_ipc_output_v2_requests,
+ 10, zdwl_ipc_output_v2_events,
+};
+
diff --git a/dwlb/dwl-ipc-unstable-v2-protocol.h b/dwlb/dwl-ipc-unstable-v2-protocol.h
@@ -0,0 +1,483 @@
+/* Generated by wayland-scanner 1.22.0 */
+
+#ifndef DWL_IPC_UNSTABLE_V2_CLIENT_PROTOCOL_H
+#define DWL_IPC_UNSTABLE_V2_CLIENT_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @page page_dwl_ipc_unstable_v2 The dwl_ipc_unstable_v2 protocol
+ * inter-proccess-communication about dwl's state
+ *
+ * @section page_desc_dwl_ipc_unstable_v2 Description
+ *
+ * This protocol allows clients to update and get updates from dwl.
+ *
+ * Warning! The protocol described in this file is experimental and
+ * backward incompatible changes may be made. Backward compatible
+ * changes may be added together with the corresponding interface
+ * version bump.
+ * Backward incompatible changes are done by bumping the version
+ * number in the protocol and interface names and resetting the
+ * interface version. Once the protocol is to be declared stable,
+ * the 'z' prefix and the version number in the protocol and
+ * interface names are removed and the interface version number is
+ * reset.
+ *
+ * @section page_ifaces_dwl_ipc_unstable_v2 Interfaces
+ * - @subpage page_iface_zdwl_ipc_manager_v2 - manage dwl state
+ * - @subpage page_iface_zdwl_ipc_output_v2 - control dwl output
+ */
+struct wl_output;
+struct zdwl_ipc_manager_v2;
+struct zdwl_ipc_output_v2;
+
+#ifndef ZDWL_IPC_MANAGER_V2_INTERFACE
+#define ZDWL_IPC_MANAGER_V2_INTERFACE
+/**
+ * @page page_iface_zdwl_ipc_manager_v2 zdwl_ipc_manager_v2
+ * @section page_iface_zdwl_ipc_manager_v2_desc Description
+ *
+ * This interface is exposed as a global in wl_registry.
+ *
+ * Clients can use this interface to get a dwl_ipc_output.
+ * After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events.
+ * The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client.
+ * @section page_iface_zdwl_ipc_manager_v2_api API
+ * See @ref iface_zdwl_ipc_manager_v2.
+ */
+/**
+ * @defgroup iface_zdwl_ipc_manager_v2 The zdwl_ipc_manager_v2 interface
+ *
+ * This interface is exposed as a global in wl_registry.
+ *
+ * Clients can use this interface to get a dwl_ipc_output.
+ * After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events.
+ * The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client.
+ */
+extern const struct wl_interface zdwl_ipc_manager_v2_interface;
+#endif
+#ifndef ZDWL_IPC_OUTPUT_V2_INTERFACE
+#define ZDWL_IPC_OUTPUT_V2_INTERFACE
+/**
+ * @page page_iface_zdwl_ipc_output_v2 zdwl_ipc_output_v2
+ * @section page_iface_zdwl_ipc_output_v2_desc Description
+ *
+ * Observe and control a dwl output.
+ *
+ * Events are double-buffered:
+ * Clients should cache events and redraw when a dwl_ipc_output.frame event is sent.
+ *
+ * Request are not double-buffered:
+ * The compositor will update immediately upon request.
+ * @section page_iface_zdwl_ipc_output_v2_api API
+ * See @ref iface_zdwl_ipc_output_v2.
+ */
+/**
+ * @defgroup iface_zdwl_ipc_output_v2 The zdwl_ipc_output_v2 interface
+ *
+ * Observe and control a dwl output.
+ *
+ * Events are double-buffered:
+ * Clients should cache events and redraw when a dwl_ipc_output.frame event is sent.
+ *
+ * Request are not double-buffered:
+ * The compositor will update immediately upon request.
+ */
+extern const struct wl_interface zdwl_ipc_output_v2_interface;
+#endif
+
+/**
+ * @ingroup iface_zdwl_ipc_manager_v2
+ * @struct zdwl_ipc_manager_v2_listener
+ */
+struct zdwl_ipc_manager_v2_listener {
+ /**
+ * Announces tag amount
+ *
+ * This event is sent after binding. A roundtrip after binding
+ * guarantees the client recieved all tags.
+ */
+ void (*tags)(void *data,
+ struct zdwl_ipc_manager_v2 *zdwl_ipc_manager_v2,
+ uint32_t amount);
+ /**
+ * Announces a layout
+ *
+ * This event is sent after binding. A roundtrip after binding
+ * guarantees the client recieved all layouts.
+ */
+ void (*layout)(void *data,
+ struct zdwl_ipc_manager_v2 *zdwl_ipc_manager_v2,
+ const char *name);
+};
+
+/**
+ * @ingroup iface_zdwl_ipc_manager_v2
+ */
+static inline int
+zdwl_ipc_manager_v2_add_listener(struct zdwl_ipc_manager_v2 *zdwl_ipc_manager_v2,
+ const struct zdwl_ipc_manager_v2_listener *listener, void *data)
+{
+ return wl_proxy_add_listener((struct wl_proxy *) zdwl_ipc_manager_v2,
+ (void (**)(void)) listener, data);
+}
+
+#define ZDWL_IPC_MANAGER_V2_RELEASE 0
+#define ZDWL_IPC_MANAGER_V2_GET_OUTPUT 1
+
+/**
+ * @ingroup iface_zdwl_ipc_manager_v2
+ */
+#define ZDWL_IPC_MANAGER_V2_TAGS_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_manager_v2
+ */
+#define ZDWL_IPC_MANAGER_V2_LAYOUT_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zdwl_ipc_manager_v2
+ */
+#define ZDWL_IPC_MANAGER_V2_RELEASE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_manager_v2
+ */
+#define ZDWL_IPC_MANAGER_V2_GET_OUTPUT_SINCE_VERSION 1
+
+/** @ingroup iface_zdwl_ipc_manager_v2 */
+static inline void
+zdwl_ipc_manager_v2_set_user_data(struct zdwl_ipc_manager_v2 *zdwl_ipc_manager_v2, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) zdwl_ipc_manager_v2, user_data);
+}
+
+/** @ingroup iface_zdwl_ipc_manager_v2 */
+static inline void *
+zdwl_ipc_manager_v2_get_user_data(struct zdwl_ipc_manager_v2 *zdwl_ipc_manager_v2)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) zdwl_ipc_manager_v2);
+}
+
+static inline uint32_t
+zdwl_ipc_manager_v2_get_version(struct zdwl_ipc_manager_v2 *zdwl_ipc_manager_v2)
+{
+ return wl_proxy_get_version((struct wl_proxy *) zdwl_ipc_manager_v2);
+}
+
+/** @ingroup iface_zdwl_ipc_manager_v2 */
+static inline void
+zdwl_ipc_manager_v2_destroy(struct zdwl_ipc_manager_v2 *zdwl_ipc_manager_v2)
+{
+ wl_proxy_destroy((struct wl_proxy *) zdwl_ipc_manager_v2);
+}
+
+/**
+ * @ingroup iface_zdwl_ipc_manager_v2
+ *
+ * Indicates that the client will not the dwl_ipc_manager object anymore.
+ * Objects created through this instance are not affected.
+ */
+static inline void
+zdwl_ipc_manager_v2_release(struct zdwl_ipc_manager_v2 *zdwl_ipc_manager_v2)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zdwl_ipc_manager_v2,
+ ZDWL_IPC_MANAGER_V2_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) zdwl_ipc_manager_v2), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_zdwl_ipc_manager_v2
+ *
+ * Get a dwl_ipc_outout for the specified wl_output.
+ */
+static inline struct zdwl_ipc_output_v2 *
+zdwl_ipc_manager_v2_get_output(struct zdwl_ipc_manager_v2 *zdwl_ipc_manager_v2, struct wl_output *output)
+{
+ struct wl_proxy *id;
+
+ id = wl_proxy_marshal_flags((struct wl_proxy *) zdwl_ipc_manager_v2,
+ ZDWL_IPC_MANAGER_V2_GET_OUTPUT, &zdwl_ipc_output_v2_interface, wl_proxy_get_version((struct wl_proxy *) zdwl_ipc_manager_v2), 0, NULL, output);
+
+ return (struct zdwl_ipc_output_v2 *) id;
+}
+
+#ifndef ZDWL_IPC_OUTPUT_V2_TAG_STATE_ENUM
+#define ZDWL_IPC_OUTPUT_V2_TAG_STATE_ENUM
+enum zdwl_ipc_output_v2_tag_state {
+ /**
+ * no state
+ */
+ ZDWL_IPC_OUTPUT_V2_TAG_STATE_NONE = 0,
+ /**
+ * tag is active
+ */
+ ZDWL_IPC_OUTPUT_V2_TAG_STATE_ACTIVE = 1,
+ /**
+ * tag has at least one urgent client
+ */
+ ZDWL_IPC_OUTPUT_V2_TAG_STATE_URGENT = 2,
+};
+#endif /* ZDWL_IPC_OUTPUT_V2_TAG_STATE_ENUM */
+
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ * @struct zdwl_ipc_output_v2_listener
+ */
+struct zdwl_ipc_output_v2_listener {
+ /**
+ * Toggle client visibilty
+ *
+ * Indicates the client should hide or show themselves. If the
+ * client is visible then hide, if hidden then show.
+ */
+ void (*toggle_visibility)(void *data,
+ struct zdwl_ipc_output_v2 *zdwl_ipc_output_v2);
+ /**
+ * Update the selected output.
+ *
+ * Indicates if the output is active. Zero is invalid, nonzero is
+ * valid.
+ */
+ void (*active)(void *data,
+ struct zdwl_ipc_output_v2 *zdwl_ipc_output_v2,
+ uint32_t active);
+ /**
+ * Update the state of a tag.
+ *
+ * Indicates that a tag has been updated.
+ * @param tag Index of the tag
+ * @param state The state of the tag.
+ * @param clients The number of clients in the tag.
+ * @param focused If there is a focused client. Nonzero being valid, zero being invalid.
+ */
+ void (*tag)(void *data,
+ struct zdwl_ipc_output_v2 *zdwl_ipc_output_v2,
+ uint32_t tag,
+ uint32_t state,
+ uint32_t clients,
+ uint32_t focused);
+ /**
+ * Update the layout.
+ *
+ * Indicates a new layout is selected.
+ * @param layout Index of the layout.
+ */
+ void (*layout)(void *data,
+ struct zdwl_ipc_output_v2 *zdwl_ipc_output_v2,
+ uint32_t layout);
+ /**
+ * Update the title.
+ *
+ * Indicates the title has changed.
+ * @param title The new title name.
+ */
+ void (*title)(void *data,
+ struct zdwl_ipc_output_v2 *zdwl_ipc_output_v2,
+ const char *title);
+ /**
+ * Update the appid.
+ *
+ * Indicates the appid has changed.
+ * @param appid The new appid.
+ */
+ void (*appid)(void *data,
+ struct zdwl_ipc_output_v2 *zdwl_ipc_output_v2,
+ const char *appid);
+ /**
+ * Update the current layout symbol
+ *
+ * Indicates the layout has changed. Since layout symbols are
+ * dynamic. As opposed to the zdwl_ipc_manager.layout event, this
+ * should take precendence when displaying. You can ignore the
+ * zdwl_ipc_output.layout event.
+ * @param layout The new layout
+ */
+ void (*layout_symbol)(void *data,
+ struct zdwl_ipc_output_v2 *zdwl_ipc_output_v2,
+ const char *layout);
+ /**
+ * The update sequence is done.
+ *
+ * Indicates that a sequence of status updates have finished and
+ * the client should redraw.
+ */
+ void (*frame)(void *data,
+ struct zdwl_ipc_output_v2 *zdwl_ipc_output_v2);
+ /**
+ * Update fullscreen status
+ *
+ * Indicates if the selected client on this output is fullscreen.
+ * @param is_fullscreen If the selected client is fullscreen. Nonzero is valid, zero invalid
+ * @since 2
+ */
+ void (*fullscreen)(void *data,
+ struct zdwl_ipc_output_v2 *zdwl_ipc_output_v2,
+ uint32_t is_fullscreen);
+ /**
+ * Update the floating status
+ *
+ * Indicates if the selected client on this output is floating.
+ * @param is_floating If the selected client is floating. Nonzero is valid, zero invalid
+ * @since 2
+ */
+ void (*floating)(void *data,
+ struct zdwl_ipc_output_v2 *zdwl_ipc_output_v2,
+ uint32_t is_floating);
+};
+
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+static inline int
+zdwl_ipc_output_v2_add_listener(struct zdwl_ipc_output_v2 *zdwl_ipc_output_v2,
+ const struct zdwl_ipc_output_v2_listener *listener, void *data)
+{
+ return wl_proxy_add_listener((struct wl_proxy *) zdwl_ipc_output_v2,
+ (void (**)(void)) listener, data);
+}
+
+#define ZDWL_IPC_OUTPUT_V2_RELEASE 0
+#define ZDWL_IPC_OUTPUT_V2_SET_TAGS 1
+#define ZDWL_IPC_OUTPUT_V2_SET_CLIENT_TAGS 2
+#define ZDWL_IPC_OUTPUT_V2_SET_LAYOUT 3
+
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_TOGGLE_VISIBILITY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_ACTIVE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_TAG_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_LAYOUT_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_TITLE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_APPID_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_LAYOUT_SYMBOL_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_FRAME_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_FULLSCREEN_SINCE_VERSION 2
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION 2
+
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_RELEASE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_SET_TAGS_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_SET_CLIENT_TAGS_SINCE_VERSION 1
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+#define ZDWL_IPC_OUTPUT_V2_SET_LAYOUT_SINCE_VERSION 1
+
+/** @ingroup iface_zdwl_ipc_output_v2 */
+static inline void
+zdwl_ipc_output_v2_set_user_data(struct zdwl_ipc_output_v2 *zdwl_ipc_output_v2, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) zdwl_ipc_output_v2, user_data);
+}
+
+/** @ingroup iface_zdwl_ipc_output_v2 */
+static inline void *
+zdwl_ipc_output_v2_get_user_data(struct zdwl_ipc_output_v2 *zdwl_ipc_output_v2)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) zdwl_ipc_output_v2);
+}
+
+static inline uint32_t
+zdwl_ipc_output_v2_get_version(struct zdwl_ipc_output_v2 *zdwl_ipc_output_v2)
+{
+ return wl_proxy_get_version((struct wl_proxy *) zdwl_ipc_output_v2);
+}
+
+/** @ingroup iface_zdwl_ipc_output_v2 */
+static inline void
+zdwl_ipc_output_v2_destroy(struct zdwl_ipc_output_v2 *zdwl_ipc_output_v2)
+{
+ wl_proxy_destroy((struct wl_proxy *) zdwl_ipc_output_v2);
+}
+
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ *
+ * Indicates to that the client no longer needs this dwl_ipc_output.
+ */
+static inline void
+zdwl_ipc_output_v2_release(struct zdwl_ipc_output_v2 *zdwl_ipc_output_v2)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zdwl_ipc_output_v2,
+ ZDWL_IPC_OUTPUT_V2_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) zdwl_ipc_output_v2), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+static inline void
+zdwl_ipc_output_v2_set_tags(struct zdwl_ipc_output_v2 *zdwl_ipc_output_v2, uint32_t tagmask, uint32_t toggle_tagset)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zdwl_ipc_output_v2,
+ ZDWL_IPC_OUTPUT_V2_SET_TAGS, NULL, wl_proxy_get_version((struct wl_proxy *) zdwl_ipc_output_v2), 0, tagmask, toggle_tagset);
+}
+
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ *
+ * The tags are updated as follows:
+ * new_tags = (current_tags AND and_tags) XOR xor_tags
+ */
+static inline void
+zdwl_ipc_output_v2_set_client_tags(struct zdwl_ipc_output_v2 *zdwl_ipc_output_v2, uint32_t and_tags, uint32_t xor_tags)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zdwl_ipc_output_v2,
+ ZDWL_IPC_OUTPUT_V2_SET_CLIENT_TAGS, NULL, wl_proxy_get_version((struct wl_proxy *) zdwl_ipc_output_v2), 0, and_tags, xor_tags);
+}
+
+/**
+ * @ingroup iface_zdwl_ipc_output_v2
+ */
+static inline void
+zdwl_ipc_output_v2_set_layout(struct zdwl_ipc_output_v2 *zdwl_ipc_output_v2, uint32_t index)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zdwl_ipc_output_v2,
+ ZDWL_IPC_OUTPUT_V2_SET_LAYOUT, NULL, wl_proxy_get_version((struct wl_proxy *) zdwl_ipc_output_v2), 0, index);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/dwlb/dwlb.1 b/dwlb/dwlb.1
@@ -0,0 +1,324 @@
+.TH DWLB 1 2023 Linux "User's Reference Manuals"
+.
+.SH NAME
+dwlb \- feature-complete bar for dwl
+.
+.SH SYNOPSIS
+.
+.SY dwlb
+.RI [ OPTIONS\~ \&.\|.\|.\&]
+.YS
+.
+.SH DESCRIPTION
+.
+.B dwlb
+is a feature-complete status bar for
+.IR dwl .
+.
+.SH USAGE
+.
+Pass
+.B dwlb
+as an argument to
+.IR dwl 's
+.B -s
+flag.
+This will populate
+each connected output with a bar.
+.
+.PP
+For example:
+.IP
+.EX
+dwl \-s \(aqdwlb \-font "monospace:size=16"\(aq
+.EE
+.
+.SS IPC
+.
+.PP
+If
+.I dwl
+is patched appropriately,
+.B dwlb
+is capable of communicating directly with
+.IR dwl .
+When IPC is enabled with
+.BR \-ipc ,
+.B dwlb
+does not read from
+.IR stdin ,
+and clicking tags functions as you would expect.
+IPC can be disabled with
+.BR \-no\-ipc .
+.
+.SS Commands
+.
+Command options send instructions
+to existing instances of
+.BR dwlb .
+All commands take at least one argument
+to specify a bar on which to operate.
+This may be
+.I zxdg_output_v1
+name,
+"all" to affect all outputs,
+or "selected" for the current output.
+.
+.PP
+The
+.B \-status
+and
+.B \-title
+commands are used to write status text.
+The text may contain in-line commands
+in the following format:
+.IR \(hacmd(argument) .
+.
+.TP
+.BR \(hafg \c
+.BI ( HEXCOLOR )
+Sets foreground color to
+.IR HEXCOLOR .
+.TP
+.BR \(habg \c
+.BI ( HEXCOLOR )
+Sets background color to
+.IR HEXCOLOR .
+.TP
+.BR \(halm \c
+.BI ( SHELLCOMMAND )
+Begins or terminates left mouse button region with action
+.IR SHELLCOMMAND .
+.TP
+.BR \(hamm \c
+.BI ( SHELLCOMMAND )
+Begins or terminates middle mouse button region with action
+.IR SHELLCOMMAND .
+.TP
+.BR \(harm \c
+.BI ( SHELLCOMMAND )
+Begins or terminates right mouse button region with action
+.IR SHELLCOMMAND .
+.
+.PP
+In this example,
+clicking the text highlighted in red
+will spawn the foot terminal.
+.
+.IP
+.EX
+dwlb \-status all \(aqtext \(habg(ff0000)\(halm(foot)text\(habg()\(halm() text\(aq
+.EE
+.
+.PP
+A color command with no argument reverts to the default value.
+.B \(ha\(ha
+represents a single
+.B \(ha
+character.
+Status commands can be disabled with
+.BR \-no\-status\-commands .
+.
+.SS Scaling
+.
+.PP
+If you use scaling in Wayland,
+you can specify
+.B buffer_scale
+through config file or by passing it as an option
+(only integer values):
+.
+.IP
+.EX
+dwlb \-scale 2
+.EE
+.
+.PP
+This will render both surface and a cursor with 2\(mu detail.
+If your monitor is set to 1.25 or 1.5 scaling,
+setting scale to 2 will also work as compositor
+will downscale the buffer properly.
+.
+.SS Someblocks
+.
+.PP
+To use
+.IR someblocks ,
+or any program that outputs to
+.IR stdout ,
+with
+.BR dwlb ,
+use this one-liner:
+.
+.IP
+.EX
+someblocks \-p | dwlb \-status\-stdin all
+.EE
+.
+.SH OPTIONS
+.
+.SS IPC
+.
+.TP
+.B \-ipc
+Allow commands to be sent to
+.I dwl
+.RI ( dwl
+Must be patched)
+.TP
+.B \-no\-ipc
+Disable ipc
+.
+.SS Configuration
+.
+.TP
+.B \-hidden
+Bars will initially be hidden
+.TP
+.B \-no\-hidden
+Bars will not initially be hidden
+.TP
+.B \-bottom
+Bars will initially be drawn at the bottom
+.TP
+.B \-no\-bottom
+Bars will initially be drawn at the top
+.TP
+.B \-hide\-vacant\-tags
+Do not display empty and inactive tags
+.TP
+.B \-no\-hide\-vacant\-tags
+Display empty and inactive tags
+.TP
+.B \-status\-commands
+Enable in-line commands in status text
+.TP
+.B \-no\-status\-commands
+Disable in-line commands in status text
+.TP
+.B \-center\-title
+Center title text on bar
+.TP
+.B \-no\-center\-title
+Do not center title text on bar
+.TP
+.B \-custom\-title
+Do not display window title and
+Treat the area as another status text element;
+see
+.B \-title
+command
+.TP
+.B \-no\-custom\-title
+Display current window title as normal
+.TP
+.BR \-font \~\c
+.I FONT
+Specify a font
+.TP
+.BR \-tags \~\c
+.IR NUMBER \~\c
+.IR FIRST \&.\|.\|.\& LAST
+If ipc is disabled, specify custom tag names
+.TP
+.BR \-vertical\-padding \~\c
+.I PIXELS
+Specify vertical pixel padding above and below text
+.TP
+.BR \-active\-fg\-color \~\c
+.I COLOR
+Specify text color of active tags or monitors
+.TP
+.BR \-active\-bg\-color \~\c
+.I COLOR
+Specify background color of active tags or monitors
+.TP
+.BR \-occupied\-fg\-color \~\c
+.I COLOR
+Specify text color of occupied tags
+.TP
+.BR \-occupied\-bg\-color \~\c
+.I COLOR
+Specify background color of occupied tags
+.TP
+.BR \-inactive\-fg\-color \~\c
+.I COLOR
+Specify text color of inactive tags or monitors
+.TP
+.BR \-inactive\-bg\-color \~\c
+.I COLOR
+Specify background color of inactive tags or monitors
+.TP
+.BR \-urgent\-fg\-color \~\c
+.I COLOR
+Specify text color of urgent tags
+.TP
+.BR \-urgent\-bg\-color \~\c
+.I COLOR
+Specify background color of urgent tags
+.TP
+.BR \-scale \~\c
+.I BUFFER_SCALE
+Specify buffer scale value for integer scaling
+.
+.SS Commands
+.
+.TP
+.BR \-status \~\c
+.I OUTPUT\~TEXT
+Set status text
+.TP
+.BR \-status\-stdin \~\c
+.I OUTPUT
+Set status text from stdin
+.TP
+.BR \-title \~\c
+.I OUTPUT\~TEXT
+Set title text,
+if
+.B \-custom\-title
+Is enabled
+.TP
+.BR \-show \~\c
+.I OUTPUT
+Show bar
+.TP
+.BR \-hide \~\c
+.I OUTPUT
+Hide bar
+.TP
+.BR \-toggle\-visibility \~\c
+.I OUTPUT
+Toggle bar visibility
+.TP
+.BR \-set\-top \~\c
+.I OUTPUT
+Draw bar at the top
+.TP
+.BR \-set\-bottom \~\c
+.I OUTPUT
+Draw bar at the bottom
+.TP
+.BR \-toggle\-location \~\c
+.I OUTPUT
+Toggle bar location
+.
+.SS Others
+.
+.TP
+.B \-v
+Get version information
+.TP
+.B \-h
+View this help text
+.
+.SH SEE ALSO
+.
+.BR dwl (1),
+.BR someblocks (1)
+.
+.SH AUTHOR
+.
+.UR https://\:github\:.com/\:kolunmi
+kolumni
+.UE
diff --git a/dwlb/dwlb.c b/dwlb/dwlb.c
@@ -0,0 +1,1935 @@
+#define _GNU_SOURCE
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcft/fcft.h>
+#include <fcntl.h>
+#include <linux/input-event-codes.h>
+#include <pixman-1/pixman.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <wayland-client.h>
+#include <wayland-cursor.h>
+#include <wayland-util.h>
+
+#include "utf8.h"
+#include "xdg-shell-protocol.h"
+#include "xdg-output-unstable-v1-protocol.h"
+#include "wlr-layer-shell-unstable-v1-protocol.h"
+#include "dwl-ipc-unstable-v2-protocol.h"
+
+#define DIE(fmt, ...) \
+ do { \
+ cleanup(); \
+ fprintf(stderr, fmt "\n", ##__VA_ARGS__); \
+ exit(1); \
+ } while (0)
+#define EDIE(fmt, ...) \
+ DIE(fmt ": %s", ##__VA_ARGS__, strerror(errno));
+
+#define MIN(a, b) \
+ ((a) < (b) ? (a) : (b))
+#define MAX(a, b) \
+ ((a) > (b) ? (a) : (b))
+#define LENGTH(x) \
+ (sizeof x / sizeof x[0])
+
+#define ARRAY_INIT_CAP 16
+#define ARRAY_EXPAND(arr, len, cap, inc) \
+ do { \
+ uint32_t new_len, new_cap; \
+ new_len = (len) + (inc); \
+ if (new_len > (cap)) { \
+ new_cap = new_len * 2; \
+ if (new_cap < ARRAY_INIT_CAP) \
+ new_cap = ARRAY_INIT_CAP; \
+ if (!((arr) = realloc((arr), sizeof(*(arr)) * new_cap))) \
+ EDIE("realloc"); \
+ (cap) = new_cap; \
+ } \
+ (len) = new_len; \
+ } while (0)
+#define ARRAY_APPEND(arr, len, cap, ptr) \
+ do { \
+ ARRAY_EXPAND((arr), (len), (cap), 1); \
+ (ptr) = &(arr)[(len) - 1]; \
+ } while (0)
+
+#define PROGRAM "dwlb"
+#define VERSION "0.2"
+#define USAGE \
+ "usage: dwlb [OPTIONS]\n" \
+ "Ipc\n" \
+ " -ipc allow commands to be sent to dwl (dwl must be patched)\n" \
+ " -no-ipc disable ipc\n" \
+ "Bar Config\n" \
+ " -hidden bars will initially be hidden\n" \
+ " -no-hidden bars will not initially be hidden\n" \
+ " -bottom bars will initially be drawn at the bottom\n" \
+ " -no-bottom bars will initially be drawn at the top\n" \
+ " -hide-vacant-tags do not display empty and inactive tags\n" \
+ " -no-hide-vacant-tags display empty and inactive tags\n" \
+ " -status-commands enable in-line commands in status text\n" \
+ " -no-status-commands disable in-line commands in status text\n" \
+ " -center-title center title text on bar\n" \
+ " -no-center-title do not center title text on bar\n" \
+ " -custom-title do not display window title and treat the area as another status text element; see -title command\n" \
+ " -no-custom-title display current window title as normal\n" \
+ " -font [FONT] specify a font\n" \
+ " -tags [NUMBER] [FIRST]...[LAST] if ipc is disabled, specify custom tag names. If NUMBER is 0, then no tag names should be given \n" \
+ " -vertical-padding [PIXELS] specify vertical pixel padding above and below text\n" \
+ " -active-fg-color [COLOR] specify text color of active tags or monitors\n" \
+ " -active-bg-color [COLOR] specify background color of active tags or monitors\n" \
+ " -occupied-fg-color [COLOR] specify text color of occupied tags\n" \
+ " -occupied-bg-color [COLOR] specify background color of occupied tags\n" \
+ " -inactive-fg-color [COLOR] specify text color of inactive tags or monitors\n" \
+ " -inactive-bg-color [COLOR] specify background color of inactive tags or monitors\n" \
+ " -urgent-fg-color [COLOR] specify text color of urgent tags\n" \
+ " -urgent-bg-color [COLOR] specify background color of urgent tags\n" \
+ " -middle-bg-color [COLOR] specify background color of the color in the middle of the bar\n" \
+ " -middle-bg-color-selected [COLOR] specify background color of the color in the middle of the bar, when selected\n" \
+ " -scale [BUFFER_SCALE] specify buffer scale value for integer scaling\n" \
+ "Commands\n" \
+ " -target-socket [SOCKET-NAME] set the socket to send command to. Sockets can be found in `$XDG_RUNTIME_DIR/dwlb/`\n"\
+ " -status [OUTPUT] [TEXT] set status text\n" \
+ " -status-stdin [OUTPUT] set status text from stdin\n" \
+ " -title [OUTPUT] [TEXT] set title text, if -custom-title is enabled\n" \
+ " -show [OUTPUT] show bar\n" \
+ " -hide [OUTPUT] hide bar\n" \
+ " -toggle-visibility [OUTPUT] toggle bar visibility\n" \
+ " -set-top [OUTPUT] draw bar at the top\n" \
+ " -set-bottom [OUTPUT] draw bar at the bottom\n" \
+ " -toggle-location [OUTPUT] toggle bar location\n" \
+ "Other\n" \
+ " -v get version information\n" \
+ " -h view this help text\n"
+
+#define TEXT_MAX 2048
+
+typedef struct {
+ pixman_color_t color;
+ bool bg;
+ char *start;
+} Color;
+
+typedef struct {
+ uint32_t btn;
+ uint32_t x1;
+ uint32_t x2;
+ char command[128];
+} Button;
+
+typedef struct {
+ char text[TEXT_MAX];
+ Color *colors;
+ uint32_t colors_l, colors_c;
+ Button *buttons;
+ uint32_t buttons_l, buttons_c;
+} CustomText;
+
+typedef struct {
+ struct wl_output *wl_output;
+ struct wl_surface *wl_surface;
+ struct zwlr_layer_surface_v1 *layer_surface;
+ struct zxdg_output_v1 *xdg_output;
+ struct zdwl_ipc_output_v2 *dwl_wm_output;
+
+ uint32_t registry_name;
+ char *xdg_output_name;
+
+ bool configured;
+ uint32_t width, height;
+ uint32_t textpadding;
+ uint32_t stride, bufsize;
+
+ uint32_t mtags, ctags, urg, sel;
+ char *layout, *window_title;
+ uint32_t layout_idx, last_layout_idx;
+ CustomText title, status;
+
+ bool hidden, bottom;
+ bool redraw;
+
+ struct wl_list link;
+} Bar;
+
+typedef struct {
+ struct wl_seat *wl_seat;
+ struct wl_pointer *wl_pointer;
+ uint32_t registry_name;
+
+ Bar *bar;
+ uint32_t pointer_x, pointer_y;
+ uint32_t pointer_button;
+
+ struct wl_list link;
+} Seat;
+
+static int sock_fd;
+static char socketdir[256];
+static char *socketpath;
+static char sockbuf[4096];
+
+static char *stdinbuf;
+static size_t stdinbuf_cap;
+
+static struct wl_display *display;
+static struct wl_compositor *compositor;
+static struct wl_shm *shm;
+static struct zwlr_layer_shell_v1 *layer_shell;
+static struct zxdg_output_manager_v1 *output_manager;
+
+static struct zdwl_ipc_manager_v2 *dwl_wm;
+static struct wl_cursor_image *cursor_image;
+static struct wl_surface *cursor_surface;
+
+static struct wl_list bar_list, seat_list;
+
+static char **tags;
+static uint32_t tags_l, tags_c;
+static char **layouts;
+static uint32_t layouts_l, layouts_c;
+
+static struct fcft_font *font;
+static uint32_t height, textpadding, buffer_scale;
+
+static bool run_display;
+
+#include "config.h"
+
+static void
+wl_buffer_release(void *data, struct wl_buffer *wl_buffer)
+{
+ /* Sent by the compositor when it's no longer using this buffer */
+ wl_buffer_destroy(wl_buffer);
+}
+
+static const struct wl_buffer_listener wl_buffer_listener = {
+ .release = wl_buffer_release,
+};
+
+/* Shared memory support function adapted from [wayland-book] */
+static int
+allocate_shm_file(size_t size)
+{
+ int fd = memfd_create("surface", MFD_CLOEXEC);
+ if (fd == -1)
+ return -1;
+ int ret;
+ do {
+ ret = ftruncate(fd, size);
+ } while (ret == -1 && errno == EINTR);
+ if (ret == -1) {
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+
+static uint32_t
+draw_text(char *text,
+ uint32_t x,
+ uint32_t y,
+ pixman_image_t *foreground,
+ pixman_image_t *background,
+ pixman_color_t *fg_color,
+ pixman_color_t *bg_color,
+ uint32_t max_x,
+ uint32_t buf_height,
+ uint32_t padding,
+ Color *colors,
+ uint32_t colors_l)
+{
+ if (!text || !*text || !max_x)
+ return x;
+
+ uint32_t ix = x, nx;
+
+ if ((nx = x + padding) + padding >= max_x)
+ return x;
+ x = nx;
+
+ bool draw_fg = foreground && fg_color;
+ bool draw_bg = background && bg_color;
+
+ pixman_image_t *fg_fill;
+ pixman_color_t *cur_bg_color;
+ if (draw_fg)
+ fg_fill = pixman_image_create_solid_fill(fg_color);
+ if (draw_bg)
+ cur_bg_color = bg_color;
+
+ uint32_t color_ind = 0, codepoint, state = UTF8_ACCEPT, last_cp = 0;
+ for (char *p = text; *p; p++) {
+ /* Check for new colors */
+ if (state == UTF8_ACCEPT && colors && (draw_fg || draw_bg)) {
+ while (color_ind < colors_l && p == colors[color_ind].start) {
+ if (colors[color_ind].bg) {
+ if (draw_bg)
+ cur_bg_color = &colors[color_ind].color;
+ } else if (draw_fg) {
+ pixman_image_unref(fg_fill);
+ fg_fill = pixman_image_create_solid_fill(&colors[color_ind].color);
+ }
+ color_ind++;
+ }
+ }
+
+ /* Returns nonzero if more bytes are needed */
+ if (utf8decode(&state, &codepoint, *p))
+ continue;
+
+ /* Turn off subpixel rendering, which complicates things when
+ * mixed with alpha channels */
+ const struct fcft_glyph *glyph = fcft_rasterize_char_utf32(font, codepoint, FCFT_SUBPIXEL_NONE);
+ if (!glyph)
+ continue;
+
+ /* Adjust x position based on kerning with previous glyph */
+ long kern = 0;
+ if (last_cp)
+ fcft_kerning(font, last_cp, codepoint, &kern, NULL);
+ if ((nx = x + kern + glyph->advance.x) + padding > max_x)
+ break;
+ last_cp = codepoint;
+ x += kern;
+
+ if (draw_fg) {
+ /* Detect and handle pre-rendered glyphs (e.g. emoji) */
+ if (pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8) {
+ /* Only the alpha channel of the mask is used, so we can
+ * use fgfill here to blend prerendered glyphs with the
+ * same opacity */
+ pixman_image_composite32(
+ PIXMAN_OP_OVER, glyph->pix, fg_fill, foreground, 0, 0, 0, 0,
+ x + glyph->x, y - glyph->y, glyph->width, glyph->height);
+ } else {
+ /* Applying the foreground color here would mess up
+ * component alphas for subpixel-rendered text, so we
+ * apply it when blending. */
+ pixman_image_composite32(
+ PIXMAN_OP_OVER, fg_fill, glyph->pix, foreground, 0, 0, 0, 0,
+ x + glyph->x, y - glyph->y, glyph->width, glyph->height);
+ }
+ }
+
+ if (draw_bg) {
+ pixman_image_fill_boxes(PIXMAN_OP_OVER, background,
+ cur_bg_color, 1, &(pixman_box32_t){
+ .x1 = x, .x2 = nx,
+ .y1 = 0, .y2 = buf_height
+ });
+ }
+
+ /* increment pen position */
+ x = nx;
+ }
+
+ if (draw_fg)
+ pixman_image_unref(fg_fill);
+ if (!last_cp)
+ return ix;
+
+ nx = x + padding;
+ if (draw_bg) {
+ /* Fill padding background */
+ pixman_image_fill_boxes(PIXMAN_OP_OVER, background,
+ bg_color, 1, &(pixman_box32_t){
+ .x1 = ix, .x2 = ix + padding,
+ .y1 = 0, .y2 = buf_height
+ });
+ pixman_image_fill_boxes(PIXMAN_OP_OVER, background,
+ bg_color, 1, &(pixman_box32_t){
+ .x1 = x, .x2 = nx,
+ .y1 = 0, .y2 = buf_height
+ });
+ }
+
+ return nx;
+}
+
+#define TEXT_WIDTH(text, maxwidth, padding) \
+ draw_text(text, 0, 0, NULL, NULL, NULL, NULL, maxwidth, 0, padding, NULL, 0)
+
+static int
+draw_frame(Bar *bar)
+{
+ /* Allocate buffer to be attached to the surface */
+ int fd = allocate_shm_file(bar->bufsize);
+ if (fd == -1)
+ return -1;
+
+ uint32_t *data = mmap(NULL, bar->bufsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (data == MAP_FAILED) {
+ close(fd);
+ return -1;
+ }
+
+ struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, bar->bufsize);
+ struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool, 0, bar->width, bar->height, bar->stride, WL_SHM_FORMAT_ARGB8888);
+ wl_buffer_add_listener(buffer, &wl_buffer_listener, NULL);
+ wl_shm_pool_destroy(pool);
+ close(fd);
+
+ /* Pixman image corresponding to main buffer */
+ pixman_image_t *final = pixman_image_create_bits(PIXMAN_a8r8g8b8, bar->width, bar->height, data, bar->width * 4);
+
+ /* Text background and foreground layers */
+ pixman_image_t *foreground = pixman_image_create_bits(PIXMAN_a8r8g8b8, bar->width, bar->height, NULL, bar->width * 4);
+ pixman_image_t *background = pixman_image_create_bits(PIXMAN_a8r8g8b8, bar->width, bar->height, NULL, bar->width * 4);
+
+ /* Draw on images */
+ uint32_t x = 0;
+ uint32_t y = (bar->height + font->ascent - font->descent) / 2;
+ uint32_t boxs = font->height / 9;
+ uint32_t boxw = font->height / 6 + 2;
+
+ for (uint32_t i = 0; i < tags_l; i++) {
+ const bool active = bar->mtags & 1 << i;
+ const bool occupied = bar->ctags & 1 << i;
+ const bool urgent = bar->urg & 1 << i;
+
+ if (hide_vacant && !active && !occupied && !urgent)
+ continue;
+
+ pixman_color_t *fg_color = urgent ? &urgent_fg_color : (active ? &active_fg_color : (occupied ? &occupied_fg_color : &inactive_fg_color));
+ pixman_color_t *bg_color = urgent ? &urgent_bg_color : (active ? &active_bg_color : (occupied ? &occupied_bg_color : &inactive_bg_color));
+
+ if (!hide_vacant && occupied) {
+ pixman_image_fill_boxes(PIXMAN_OP_SRC, foreground,
+ fg_color, 1, &(pixman_box32_t){
+ .x1 = x + boxs, .x2 = x + boxs + boxw,
+ .y1 = boxs, .y2 = boxs + boxw
+ });
+ if ((!bar->sel || !active) && boxw >= 3) {
+ /* Make box hollow */
+ pixman_image_fill_boxes(PIXMAN_OP_SRC, foreground,
+ &(pixman_color_t){ 0 },
+ 1, &(pixman_box32_t){
+ .x1 = x + boxs + 1, .x2 = x + boxs + boxw - 1,
+ .y1 = boxs + 1, .y2 = boxs + boxw - 1
+ });
+ }
+ }
+
+ x = draw_text(tags[i], x, y, foreground, background, fg_color, bg_color,
+ bar->width, bar->height, bar->textpadding, NULL, 0);
+ }
+
+ x = draw_text(bar->layout, x, y, foreground, background,
+ &inactive_fg_color, &inactive_bg_color, bar->width,
+ bar->height, bar->textpadding, NULL, 0);
+
+ uint32_t status_width = TEXT_WIDTH(bar->status.text, bar->width - x, bar->textpadding);
+ draw_text(bar->status.text, bar->width - status_width, y, foreground,
+ background, &inactive_fg_color, &inactive_bg_color,
+ bar->width, bar->height, bar->textpadding,
+ bar->status.colors, bar->status.colors_l);
+
+ uint32_t nx;
+ if (center_title) {
+ uint32_t title_width = TEXT_WIDTH(custom_title ? bar->title.text : bar->window_title, bar->width - status_width - x, 0);
+ nx = MAX(x, MIN((bar->width - title_width) / 2, bar->width - status_width - title_width));
+ } else {
+ nx = MIN(x + bar->textpadding, bar->width - status_width);
+ }
+ pixman_image_fill_boxes(PIXMAN_OP_SRC, background,
+ bar->sel ? &middle_bg_color_selected : &middle_bg_color, 1,
+ &(pixman_box32_t){
+ .x1 = x, .x2 = nx,
+ .y1 = 0, .y2 = bar->height
+ });
+ x = nx;
+
+ x = draw_text(custom_title ? bar->title.text : bar->window_title,
+ x, y, foreground, background,
+ bar->sel ? &active_fg_color : &inactive_fg_color,
+ bar->sel ? &active_bg_color : &inactive_bg_color,
+ bar->width - status_width, bar->height, 0,
+ custom_title ? bar->title.colors : NULL,
+ custom_title ? bar->title.colors_l : 0);
+
+ pixman_image_fill_boxes(PIXMAN_OP_SRC, background,
+ bar->sel ? &middle_bg_color_selected : &middle_bg_color, 1,
+ &(pixman_box32_t){
+ .x1 = x, .x2 = bar->width - status_width,
+ .y1 = 0, .y2 = bar->height
+ });
+
+ /* Draw background and foreground on bar */
+ pixman_image_composite32(PIXMAN_OP_OVER, background, NULL, final, 0, 0, 0, 0, 0, 0, bar->width, bar->height);
+ pixman_image_composite32(PIXMAN_OP_OVER, foreground, NULL, final, 0, 0, 0, 0, 0, 0, bar->width, bar->height);
+
+ pixman_image_unref(foreground);
+ pixman_image_unref(background);
+ pixman_image_unref(final);
+
+ munmap(data, bar->bufsize);
+
+ wl_surface_set_buffer_scale(bar->wl_surface, buffer_scale);
+ wl_surface_attach(bar->wl_surface, buffer, 0, 0);
+ wl_surface_damage_buffer(bar->wl_surface, 0, 0, bar->width, bar->height);
+ wl_surface_commit(bar->wl_surface);
+
+ return 0;
+}
+
+/* Layer-surface setup adapted from layer-shell example in [wlroots] */
+static void
+layer_surface_configure(void *data, struct zwlr_layer_surface_v1 *surface,
+ uint32_t serial, uint32_t w, uint32_t h)
+{
+ w = w * buffer_scale;
+ h = h * buffer_scale;
+
+ zwlr_layer_surface_v1_ack_configure(surface, serial);
+
+ Bar *bar = (Bar *)data;
+
+ if (bar->configured && w == bar->width && h == bar->height)
+ return;
+
+ bar->width = w;
+ bar->height = h;
+ bar->stride = bar->width * 4;
+ bar->bufsize = bar->stride * bar->height;
+ bar->configured = true;
+
+ draw_frame(bar);
+}
+
+static void
+layer_surface_closed(void *data, struct zwlr_layer_surface_v1 *surface)
+{
+ run_display = false;
+}
+
+static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
+ .configure = layer_surface_configure,
+ .closed = layer_surface_closed,
+};
+
+static void
+cleanup(void)
+{
+ if (socketpath)
+ unlink(socketpath);
+}
+
+static void
+output_name(void *data, struct zxdg_output_v1 *xdg_output, const char *name)
+{
+ Bar *bar = (Bar *)data;
+
+ if (bar->xdg_output_name)
+ free(bar->xdg_output_name);
+ if (!(bar->xdg_output_name = strdup(name)))
+ EDIE("strdup");
+}
+
+static void
+output_logical_position(void *data, struct zxdg_output_v1 *xdg_output,
+ int32_t x, int32_t y)
+{
+}
+
+static void
+output_logical_size(void *data, struct zxdg_output_v1 *xdg_output,
+ int32_t width, int32_t height)
+{
+}
+
+static void
+output_done(void *data, struct zxdg_output_v1 *xdg_output)
+{
+}
+
+static void
+output_description(void *data, struct zxdg_output_v1 *xdg_output,
+ const char *description)
+{
+}
+
+static const struct zxdg_output_v1_listener output_listener = {
+ .name = output_name,
+ .logical_position = output_logical_position,
+ .logical_size = output_logical_size,
+ .done = output_done,
+ .description = output_description
+};
+
+static void
+shell_command(char *command)
+{
+ if (fork() == 0) {
+ setsid();
+ execl("/bin/sh", "sh", "-c", command, NULL);
+ exit(EXIT_SUCCESS);
+ }
+}
+
+static void
+pointer_enter(void *data, struct wl_pointer *pointer,
+ uint32_t serial, struct wl_surface *surface,
+ wl_fixed_t surface_x, wl_fixed_t surface_y)
+{
+ Seat *seat = (Seat *)data;
+
+ seat->bar = NULL;
+ Bar *bar;
+ wl_list_for_each(bar, &bar_list, link) {
+ if (bar->wl_surface == surface) {
+ seat->bar = bar;
+ break;
+ }
+ }
+
+ if (!cursor_image) {
+ const char *size_str = getenv("XCURSOR_SIZE");
+ int size = size_str ? atoi(size_str) : 0;
+ if (size == 0)
+ size = 24;
+ struct wl_cursor_theme *cursor_theme = wl_cursor_theme_load(getenv("XCURSOR_THEME"), size * buffer_scale, shm);
+ cursor_image = wl_cursor_theme_get_cursor(cursor_theme, "left_ptr")->images[0];
+ cursor_surface = wl_compositor_create_surface(compositor);
+ wl_surface_set_buffer_scale(cursor_surface, buffer_scale);
+ wl_surface_attach(cursor_surface, wl_cursor_image_get_buffer(cursor_image), 0, 0);
+ wl_surface_commit(cursor_surface);
+ }
+ wl_pointer_set_cursor(pointer, serial, cursor_surface,
+ cursor_image->hotspot_x,
+ cursor_image->hotspot_y);
+}
+
+static void
+pointer_leave(void *data, struct wl_pointer *pointer,
+ uint32_t serial, struct wl_surface *surface)
+{
+ Seat *seat = (Seat *)data;
+
+ seat->bar = NULL;
+}
+
+static void
+pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial,
+ uint32_t time, uint32_t button, uint32_t state)
+{
+ Seat *seat = (Seat *)data;
+
+ seat->pointer_button = state == WL_POINTER_BUTTON_STATE_PRESSED ? button : 0;
+}
+
+static void
+pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time,
+ wl_fixed_t surface_x, wl_fixed_t surface_y)
+{
+ Seat *seat = (Seat *)data;
+
+ seat->pointer_x = wl_fixed_to_int(surface_x);
+ seat->pointer_y = wl_fixed_to_int(surface_y);
+}
+
+static void
+pointer_frame(void *data, struct wl_pointer *pointer)
+{
+ Seat *seat = (Seat *)data;
+
+ if (!seat->pointer_button || !seat->bar)
+ return;
+
+ uint32_t x = 0, i = 0;
+ do {
+ if (hide_vacant) {
+ const bool active = seat->bar->mtags & 1 << i;
+ const bool occupied = seat->bar->ctags & 1 << i;
+ const bool urgent = seat->bar->urg & 1 << i;
+ if (!active && !occupied && !urgent)
+ continue;
+ }
+ x += TEXT_WIDTH(tags[i], seat->bar->width - x, seat->bar->textpadding) / buffer_scale;
+ } while (seat->pointer_x >= x && ++i < tags_l);
+
+ if (i < tags_l) {
+ /* Clicked on tags */
+ if (ipc) {
+ if (seat->pointer_button == BTN_LEFT)
+ zdwl_ipc_output_v2_set_tags(seat->bar->dwl_wm_output, 1 << i, 1);
+ else if (seat->pointer_button == BTN_MIDDLE)
+ zdwl_ipc_output_v2_set_tags(seat->bar->dwl_wm_output, ~0, 1);
+ else if (seat->pointer_button == BTN_RIGHT)
+ zdwl_ipc_output_v2_set_tags(seat->bar->dwl_wm_output, seat->bar->mtags ^ (1 << i), 0);
+ }
+ } else if (seat->pointer_x < (x += TEXT_WIDTH(seat->bar->layout, seat->bar->width - x, seat->bar->textpadding))) {
+ /* Clicked on layout */
+ if (ipc) {
+ if (seat->pointer_button == BTN_LEFT)
+ zdwl_ipc_output_v2_set_layout(seat->bar->dwl_wm_output, seat->bar->last_layout_idx);
+ else if (seat->pointer_button == BTN_RIGHT)
+ zdwl_ipc_output_v2_set_layout(seat->bar->dwl_wm_output, 2);
+ }
+ } else {
+ uint32_t status_x = seat->bar->width / buffer_scale - TEXT_WIDTH(seat->bar->status.text, seat->bar->width - x, seat->bar->textpadding) / buffer_scale;
+ if (seat->pointer_x < status_x) {
+ /* Clicked on title */
+ if (custom_title) {
+ if (center_title) {
+ uint32_t title_width = TEXT_WIDTH(seat->bar->title.text, status_x - x, 0);
+ x = MAX(x, MIN((seat->bar->width - title_width) / 2, status_x - title_width));
+ } else {
+ x = MIN(x + seat->bar->textpadding, status_x);
+ }
+ for (i = 0; i < seat->bar->title.buttons_l; i++) {
+ if (seat->pointer_button == seat->bar->title.buttons[i].btn
+ && seat->pointer_x >= x + seat->bar->title.buttons[i].x1
+ && seat->pointer_x < x + seat->bar->title.buttons[i].x2) {
+ shell_command(seat->bar->title.buttons[i].command);
+ break;
+ }
+ }
+ }
+ } else {
+ /* Clicked on status */
+ for (i = 0; i < seat->bar->status.buttons_l; i++) {
+ if (seat->pointer_button == seat->bar->status.buttons[i].btn
+ && seat->pointer_x >= status_x + seat->bar->textpadding + seat->bar->status.buttons[i].x1 / buffer_scale
+ && seat->pointer_x < status_x + seat->bar->textpadding + seat->bar->status.buttons[i].x2 / buffer_scale) {
+ shell_command(seat->bar->status.buttons[i].command);
+ break;
+ }
+ }
+ }
+ }
+
+ seat->pointer_button = 0;
+}
+
+static void
+pointer_axis(void *data, struct wl_pointer *pointer,
+ uint32_t time, uint32_t axis, wl_fixed_t value)
+{
+}
+
+static void
+pointer_axis_discrete(void *data, struct wl_pointer *pointer,
+ uint32_t axis, int32_t discrete)
+{
+}
+
+static void
+pointer_axis_source(void *data, struct wl_pointer *pointer,
+ uint32_t axis_source)
+{
+}
+
+static void
+pointer_axis_stop(void *data, struct wl_pointer *pointer,
+ uint32_t time, uint32_t axis)
+{
+}
+
+static void
+pointer_axis_value120(void *data, struct wl_pointer *pointer,
+ uint32_t axis, int32_t discrete)
+{
+}
+
+static const struct wl_pointer_listener pointer_listener = {
+ .axis = pointer_axis,
+ .axis_discrete = pointer_axis_discrete,
+ .axis_source = pointer_axis_source,
+ .axis_stop = pointer_axis_stop,
+ .axis_value120 = pointer_axis_value120,
+ .button = pointer_button,
+ .enter = pointer_enter,
+ .frame = pointer_frame,
+ .leave = pointer_leave,
+ .motion = pointer_motion,
+};
+
+static void
+seat_capabilities(void *data, struct wl_seat *wl_seat,
+ uint32_t capabilities)
+{
+ Seat *seat = (Seat *)data;
+
+ uint32_t has_pointer = capabilities & WL_SEAT_CAPABILITY_POINTER;
+ if (has_pointer && !seat->wl_pointer) {
+ seat->wl_pointer = wl_seat_get_pointer(seat->wl_seat);
+ wl_pointer_add_listener(seat->wl_pointer, &pointer_listener, seat);
+ } else if (!has_pointer && seat->wl_pointer) {
+ wl_pointer_destroy(seat->wl_pointer);
+ seat->wl_pointer = NULL;
+ }
+}
+
+static void
+seat_name(void *data, struct wl_seat *wl_seat, const char *name)
+{
+}
+
+static const struct wl_seat_listener seat_listener = {
+ .capabilities = seat_capabilities,
+ .name = seat_name,
+};
+
+static void
+show_bar(Bar *bar)
+{
+ bar->wl_surface = wl_compositor_create_surface(compositor);
+ if (!bar->wl_surface)
+ DIE("Could not create wl_surface");
+
+ bar->layer_surface = zwlr_layer_shell_v1_get_layer_surface(layer_shell, bar->wl_surface, bar->wl_output,
+ ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, PROGRAM);
+ if (!bar->layer_surface)
+ DIE("Could not create layer_surface");
+ zwlr_layer_surface_v1_add_listener(bar->layer_surface, &layer_surface_listener, bar);
+
+ zwlr_layer_surface_v1_set_size(bar->layer_surface, 0, bar->height / buffer_scale);
+ zwlr_layer_surface_v1_set_anchor(bar->layer_surface,
+ (bar->bottom ? ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM : ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)
+ | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
+ | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT);
+ zwlr_layer_surface_v1_set_exclusive_zone(bar->layer_surface, bar->height / buffer_scale);
+ wl_surface_commit(bar->wl_surface);
+
+ bar->hidden = false;
+}
+
+static void
+hide_bar(Bar *bar)
+{
+ zwlr_layer_surface_v1_destroy(bar->layer_surface);
+ wl_surface_destroy(bar->wl_surface);
+
+ bar->configured = false;
+ bar->hidden = true;
+}
+
+static void
+dwl_wm_tags(void *data, struct zdwl_ipc_manager_v2 *dwl_wm,
+ uint32_t amount)
+{
+ if (!tags && !(tags = malloc(amount * sizeof(char *))))
+ EDIE("malloc");
+ uint32_t i = tags_l;
+ ARRAY_EXPAND(tags, tags_l, tags_c, MAX(0, (int)amount - (int)tags_l));
+ for (; i < amount; i++)
+ if (!(tags[i] = strdup(tags_names[MIN(i, LENGTH(tags_names)-1)])))
+ EDIE("strdup");
+}
+
+static void
+dwl_wm_layout(void *data, struct zdwl_ipc_manager_v2 *dwl_wm,
+ const char *name)
+{
+ char **ptr;
+ ARRAY_APPEND(layouts, layouts_l, layouts_c, ptr);
+ if (!(*ptr = strdup(name)))
+ EDIE("strdup");
+}
+
+static const struct zdwl_ipc_manager_v2_listener dwl_wm_listener = {
+ .tags = dwl_wm_tags,
+ .layout = dwl_wm_layout
+};
+
+static void
+dwl_wm_output_toggle_visibility(void *data, struct zdwl_ipc_output_v2 *dwl_wm_output)
+{
+ Bar *bar = (Bar *)data;
+
+ if (bar->hidden)
+ show_bar(bar);
+ else
+ hide_bar(bar);
+}
+
+static void
+dwl_wm_output_active(void *data, struct zdwl_ipc_output_v2 *dwl_wm_output,
+ uint32_t active)
+{
+ Bar *bar = (Bar *)data;
+
+ if (active != bar->sel)
+ bar->sel = active;
+}
+
+static void
+dwl_wm_output_tag(void *data, struct zdwl_ipc_output_v2 *dwl_wm_output,
+ uint32_t tag, uint32_t state, uint32_t clients, uint32_t focused)
+{
+ Bar *bar = (Bar *)data;
+
+ if (state & ZDWL_IPC_OUTPUT_V2_TAG_STATE_ACTIVE)
+ bar->mtags |= 1 << tag;
+ else
+ bar->mtags &= ~(1 << tag);
+ if (clients > 0)
+ bar->ctags |= 1 << tag;
+ else
+ bar->ctags &= ~(1 << tag);
+ if (state & ZDWL_IPC_OUTPUT_V2_TAG_STATE_URGENT)
+ bar->urg |= 1 << tag;
+ else
+ bar->urg &= ~(1 << tag);
+}
+
+static void
+dwl_wm_output_layout(void *data, struct zdwl_ipc_output_v2 *dwl_wm_output,
+ uint32_t layout)
+{
+ Bar *bar = (Bar *)data;
+
+ bar->last_layout_idx = bar->layout_idx;
+ bar->layout_idx = layout;
+}
+
+static void
+dwl_wm_output_title(void *data, struct zdwl_ipc_output_v2 *dwl_wm_output,
+ const char *title)
+{
+ if (custom_title)
+ return;
+
+ Bar *bar = (Bar *)data;
+
+ if (bar->window_title)
+ free(bar->window_title);
+ if (!(bar->window_title = strdup(title)))
+ EDIE("strdup");
+}
+
+static void
+dwl_wm_output_appid(void *data, struct zdwl_ipc_output_v2 *dwl_wm_output,
+ const char *appid)
+{
+}
+
+static void
+dwl_wm_output_layout_symbol(void *data, struct zdwl_ipc_output_v2 *dwl_wm_output,
+ const char *layout)
+{
+ Bar *bar = (Bar *)data;
+
+ if (layouts[bar->layout_idx])
+ free(layouts[bar->layout_idx]);
+ if (!(layouts[bar->layout_idx] = strdup(layout)))
+ EDIE("strdup");
+ bar->layout = layouts[bar->layout_idx];
+}
+
+static void
+dwl_wm_output_frame(void *data, struct zdwl_ipc_output_v2 *dwl_wm_output)
+{
+ Bar *bar = (Bar *)data;
+ bar->redraw = true;
+}
+
+static void
+dwl_wm_output_fullscreen(void *data, struct zdwl_ipc_output_v2 *dwl_wm_output,
+ uint32_t is_fullscreen)
+{
+}
+
+static void
+dwl_wm_output_floating(void *data, struct zdwl_ipc_output_v2 *dwl_wm_output,
+ uint32_t is_floating)
+{
+}
+
+static const struct zdwl_ipc_output_v2_listener dwl_wm_output_listener = {
+ .toggle_visibility = dwl_wm_output_toggle_visibility,
+ .active = dwl_wm_output_active,
+ .tag = dwl_wm_output_tag,
+ .layout = dwl_wm_output_layout,
+ .title = dwl_wm_output_title,
+ .appid = dwl_wm_output_appid,
+ .layout_symbol = dwl_wm_output_layout_symbol,
+ .frame = dwl_wm_output_frame,
+ .fullscreen = dwl_wm_output_fullscreen,
+ .floating = dwl_wm_output_floating
+};
+
+static void
+setup_bar(Bar *bar)
+{
+ bar->height = height * buffer_scale;
+ bar->textpadding = textpadding;
+ bar->bottom = bottom;
+ bar->hidden = hidden;
+
+ bar->xdg_output = zxdg_output_manager_v1_get_xdg_output(output_manager, bar->wl_output);
+ if (!bar->xdg_output)
+ DIE("Could not create xdg_output");
+ zxdg_output_v1_add_listener(bar->xdg_output, &output_listener, bar);
+
+ if (ipc) {
+ bar->dwl_wm_output = zdwl_ipc_manager_v2_get_output(dwl_wm, bar->wl_output);
+ if (!bar->dwl_wm_output)
+ DIE("Could not create dwl_wm_output");
+ zdwl_ipc_output_v2_add_listener(bar->dwl_wm_output, &dwl_wm_output_listener, bar);
+ }
+
+ if (!bar->hidden)
+ show_bar(bar);
+}
+
+static void
+handle_global(void *data, struct wl_registry *registry,
+ uint32_t name, const char *interface, uint32_t version)
+{
+ if (!strcmp(interface, wl_compositor_interface.name)) {
+ compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 4);
+ } else if (!strcmp(interface, wl_shm_interface.name)) {
+ shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
+ } else if (!strcmp(interface, zwlr_layer_shell_v1_interface.name)) {
+ layer_shell = wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, 1);
+ } else if (!strcmp(interface, zxdg_output_manager_v1_interface.name)) {
+ output_manager = wl_registry_bind(registry, name, &zxdg_output_manager_v1_interface, 2);
+ } else if (!strcmp(interface, zdwl_ipc_manager_v2_interface.name)) {
+ if (ipc) {
+ dwl_wm = wl_registry_bind(registry, name, &zdwl_ipc_manager_v2_interface, 2);
+ zdwl_ipc_manager_v2_add_listener(dwl_wm, &dwl_wm_listener, NULL);
+ }
+ } else if (!strcmp(interface, wl_output_interface.name)) {
+ Bar *bar = calloc(1, sizeof(Bar));
+ if (!bar)
+ EDIE("calloc");
+ bar->registry_name = name;
+ bar->wl_output = wl_registry_bind(registry, name, &wl_output_interface, 1);
+ if (run_display)
+ setup_bar(bar);
+ wl_list_insert(&bar_list, &bar->link);
+ } else if (!strcmp(interface, wl_seat_interface.name)) {
+ Seat *seat = calloc(1, sizeof(Seat));
+ if (!seat)
+ EDIE("calloc");
+ seat->registry_name = name;
+ seat->wl_seat = wl_registry_bind(registry, name, &wl_seat_interface, 7);
+ wl_seat_add_listener(seat->wl_seat, &seat_listener, seat);
+ wl_list_insert(&seat_list, &seat->link);
+ }
+}
+
+static void
+teardown_bar(Bar *bar)
+{
+ if (bar->status.colors)
+ free(bar->status.colors);
+ if (bar->status.buttons)
+ free(bar->status.buttons);
+ if (bar->title.colors)
+ free(bar->title.colors);
+ if (bar->title.buttons)
+ free(bar->title.buttons);
+ if (bar->window_title)
+ free(bar->window_title);
+ if (!ipc && bar->layout)
+ free(bar->layout);
+ if (ipc)
+ zdwl_ipc_output_v2_destroy(bar->dwl_wm_output);
+ if (bar->xdg_output_name)
+ free(bar->xdg_output_name);
+ if (!bar->hidden) {
+ zwlr_layer_surface_v1_destroy(bar->layer_surface);
+ wl_surface_destroy(bar->wl_surface);
+ }
+ zxdg_output_v1_destroy(bar->xdg_output);
+ wl_output_destroy(bar->wl_output);
+ free(bar);
+}
+
+static void
+teardown_seat(Seat *seat)
+{
+ if (seat->wl_pointer)
+ wl_pointer_destroy(seat->wl_pointer);
+ wl_seat_destroy(seat->wl_seat);
+ free(seat);
+}
+
+static void
+handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
+{
+ Bar *bar;
+ Seat *seat;
+
+ wl_list_for_each(bar, &bar_list, link) {
+ if (bar->registry_name == name) {
+ wl_list_remove(&bar->link);
+ teardown_bar(bar);
+ return;
+ }
+ }
+ wl_list_for_each(seat, &seat_list, link) {
+ if (seat->registry_name == name) {
+ wl_list_remove(&seat->link);
+ teardown_seat(seat);
+ return;
+ }
+ }
+}
+
+static const struct wl_registry_listener registry_listener = {
+ .global = handle_global,
+ .global_remove = handle_global_remove
+};
+
+static int
+advance_word(char **beg, char **end)
+{
+ for (*beg = *end; **beg == ' '; (*beg)++);
+ for (*end = *beg; **end && **end != ' '; (*end)++);
+ if (!**end)
+ /* last word */
+ return -1;
+ **end = '\0';
+ (*end)++;
+ return 0;
+}
+
+#define ADVANCE() advance_word(&wordbeg, &wordend)
+#define ADVANCE_IF_LAST_CONT() if (ADVANCE() == -1) continue
+#define ADVANCE_IF_LAST_RET() if (ADVANCE() == -1) return
+
+static void
+read_stdin(void)
+{
+ size_t len = 0;
+ for (;;) {
+ ssize_t rv = read(STDIN_FILENO, stdinbuf + len, stdinbuf_cap - len);
+ if (rv == -1) {
+ if (errno == EWOULDBLOCK)
+ break;
+ EDIE("read");
+ }
+ if (rv == 0) {
+ run_display = false;
+ return;
+ }
+
+ if ((len += rv) > stdinbuf_cap / 2)
+ if (!(stdinbuf = realloc(stdinbuf, (stdinbuf_cap *= 2))))
+ EDIE("realloc");
+ }
+
+ char *linebeg, *lineend;
+ char *wordbeg, *wordend;
+
+ for (linebeg = stdinbuf;
+ (lineend = memchr(linebeg, '\n', stdinbuf + len - linebeg));
+ linebeg = lineend) {
+ *lineend++ = '\0';
+ wordend = linebeg;
+
+ ADVANCE_IF_LAST_CONT();
+
+ Bar *it, *bar = NULL;
+ wl_list_for_each(it, &bar_list, link) {
+ if (it->xdg_output_name && !strcmp(wordbeg, it->xdg_output_name)) {
+ bar = it;
+ break;
+ }
+ }
+ if (!bar)
+ continue;
+
+ ADVANCE_IF_LAST_CONT();
+
+ uint32_t val;
+ if (!strcmp(wordbeg, "tags")) {
+ ADVANCE_IF_LAST_CONT();
+ if ((val = atoi(wordbeg)) != bar->ctags) {
+ bar->ctags = val;
+ bar->redraw = true;
+ }
+ ADVANCE_IF_LAST_CONT();
+ if ((val = atoi(wordbeg)) != bar->mtags) {
+ bar->mtags = val;
+ bar->redraw = true;
+ }
+ ADVANCE_IF_LAST_CONT();
+ /* skip sel */
+ ADVANCE();
+ if ((val = atoi(wordbeg)) != bar->urg) {
+ bar->urg = val;
+ bar->redraw = true;
+ }
+ } else if (!strcmp(wordbeg, "layout")) {
+ if (bar->layout)
+ free(bar->layout);
+ if (!(bar->layout = strdup(wordend)))
+ EDIE("strdup");
+ bar->redraw = true;
+ } else if (!strcmp(wordbeg, "title")) {
+ if (custom_title)
+ continue;
+ if (bar->window_title)
+ free(bar->window_title);
+ if (!(bar->window_title = strdup(wordend)))
+ EDIE("strdup");
+ bar->redraw = true;
+ } else if (!strcmp(wordbeg, "selmon")) {
+ ADVANCE();
+ if ((val = atoi(wordbeg)) != bar->sel) {
+ bar->sel = val;
+ bar->redraw = true;
+ }
+ }
+ }
+}
+
+static void
+set_top(Bar *bar)
+{
+ if (!bar->hidden) {
+ zwlr_layer_surface_v1_set_anchor(bar->layer_surface,
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP
+ | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
+ | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT);
+ bar->redraw = true;
+ }
+ bar->bottom = false;
+}
+
+static void
+set_bottom(Bar *bar)
+{
+ if (!bar->hidden) {
+ zwlr_layer_surface_v1_set_anchor(bar->layer_surface,
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM
+ | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
+ | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT);
+ bar->redraw = true;
+ }
+ bar->bottom = true;
+}
+
+/* Color parsing logic adapted from [sway] */
+static int
+parse_color(const char *str, pixman_color_t *clr)
+{
+ if (*str == '#')
+ str++;
+ int len = strlen(str);
+
+ // Disallows "0x" prefix that strtoul would ignore
+ if ((len != 6 && len != 8) || !isxdigit(str[0]) || !isxdigit(str[1]))
+ return -1;
+
+ char *ptr;
+ uint32_t parsed = strtoul(str, &ptr, 16);
+ if (*ptr)
+ return -1;
+
+ if (len == 8) {
+ clr->alpha = (parsed & 0xff) * 0x101;
+ parsed >>= 8;
+ } else {
+ clr->alpha = 0xffff;
+ }
+ clr->red = ((parsed >> 16) & 0xff) * 0x101;
+ clr->green = ((parsed >> 8) & 0xff) * 0x101;
+ clr->blue = ((parsed >> 0) & 0xff) * 0x101;
+ return 0;
+}
+
+static void
+parse_into_customtext(CustomText *ct, char *text)
+{
+ ct->colors_l = ct->buttons_l = 0;
+
+ if (status_commands) {
+ uint32_t codepoint;
+ uint32_t state = UTF8_ACCEPT;
+ uint32_t last_cp = 0;
+ uint32_t x = 0;
+ size_t str_pos = 0;
+
+ Button *left_button = NULL;
+ Button *middle_button = NULL;
+ Button *right_button = NULL;
+
+ for (char *p = text; *p && str_pos < sizeof(ct->text) - 1; p++) {
+ if (state == UTF8_ACCEPT && *p == '^') {
+ p++;
+ if (*p != '^') {
+ char *arg, *end;
+ if (!(arg = strchr(p, '(')) || !(end = strchr(arg + 1, ')')))
+ continue;
+ *arg++ = '\0';
+ *end = '\0';
+
+ if (!strcmp(p, "bg")) {
+ Color *color;
+ ARRAY_APPEND(ct->colors, ct->colors_l, ct->colors_c, color);
+ if (!*arg)
+ color->color = inactive_bg_color;
+ else
+ parse_color(arg, &color->color);
+ color->bg = true;
+ color->start = ct->text + str_pos;
+ } else if (!strcmp(p, "fg")) {
+ Color *color;
+ ARRAY_APPEND(ct->colors, ct->colors_l, ct->colors_c, color);
+ if (!*arg)
+ color->color = inactive_fg_color;
+ else
+ parse_color(arg, &color->color);
+ color->bg = false;
+ color->start = ct->text + str_pos;
+ } else if (!strcmp(p, "lm")) {
+ if (left_button) {
+ left_button->x2 = x;
+ left_button = NULL;
+ } else if (*arg) {
+ ARRAY_APPEND(ct->buttons, ct->buttons_l, ct->buttons_c, left_button);
+ left_button->btn = BTN_LEFT;
+ snprintf(left_button->command, sizeof left_button->command, "%s", arg);
+ left_button->x1 = x;
+ }
+ } else if (!strcmp(p, "mm")) {
+ if (middle_button) {
+ middle_button->x2 = x;
+ middle_button = NULL;
+ } else if (*arg) {
+ ARRAY_APPEND(ct->buttons, ct->buttons_l, ct->buttons_c, middle_button);
+ middle_button->btn = BTN_MIDDLE;
+ snprintf(middle_button->command, sizeof middle_button->command, "%s", arg);
+ middle_button->x1 = x;
+ }
+ } else if (!strcmp(p, "rm")) {
+ if (right_button) {
+ right_button->x2 = x;
+ right_button = NULL;
+ } else if (*arg) {
+ ARRAY_APPEND(ct->buttons, ct->buttons_l, ct->buttons_c, right_button);
+ right_button->btn = BTN_RIGHT;
+ snprintf(right_button->command, sizeof right_button->command, "%s", arg);
+ right_button->x1 = x;
+ }
+ }
+
+ *--arg = '(';
+ *end = ')';
+
+ p = end;
+ continue;
+ }
+ }
+
+ ct->text[str_pos++] = *p;
+
+ if (utf8decode(&state, &codepoint, *p))
+ continue;
+
+ const struct fcft_glyph *glyph = fcft_rasterize_char_utf32(font, codepoint, FCFT_SUBPIXEL_NONE);
+ if (!glyph)
+ continue;
+
+ long kern = 0;
+ if (last_cp)
+ fcft_kerning(font, last_cp, codepoint, &kern, NULL);
+ last_cp = codepoint;
+
+ x += kern + glyph->advance.x;
+ }
+
+ if (left_button)
+ left_button->x2 = x;
+ if (middle_button)
+ middle_button->x2 = x;
+ if (right_button)
+ right_button->x2 = x;
+
+ ct->text[str_pos] = '\0';
+ } else {
+ snprintf(ct->text, sizeof ct->text, "%s", text);
+ }
+}
+
+static void
+copy_customtext(CustomText *from, CustomText *to)
+{
+ snprintf(to->text, sizeof to->text, "%s", from->text);
+ to->colors_l = to->buttons_l = 0;
+ for (uint32_t i = 0; i < from->colors_l; i++) {
+ Color *color;
+ ARRAY_APPEND(to->colors, to->colors_l, to->colors_c, color);
+ color->color = from->colors[i].color;
+ color->bg = from->colors[i].bg;
+ color->start = from->colors[i].start - (char *)&from->text + (char *)&to->text;
+ }
+ for (uint32_t i = 0; i < from->buttons_l; i++) {
+ Button *button;
+ ARRAY_APPEND(to->buttons, to->buttons_l, to->buttons_c, button);
+ *button = from->buttons[i];
+ }
+}
+
+static void
+read_socket(void)
+{
+ int cli_fd;
+ if ((cli_fd = accept(sock_fd, NULL, 0)) == -1)
+ EDIE("accept");
+ ssize_t len = recv(cli_fd, sockbuf, sizeof sockbuf - 1, 0);
+ if (len == -1)
+ EDIE("recv");
+ close(cli_fd);
+ if (len == 0)
+ return;
+ sockbuf[len] = '\0';
+
+ char *wordbeg, *wordend;
+ wordend = (char *)&sockbuf;
+
+ ADVANCE_IF_LAST_RET();
+
+ Bar *bar = NULL, *it;
+ bool all = false;
+
+ if (!strcmp(wordbeg, "all")) {
+ all = true;
+ } else if (!strcmp(wordbeg, "selected")) {
+ wl_list_for_each(it, &bar_list, link) {
+ if (it->sel) {
+ bar = it;
+ break;
+ }
+ }
+ } else {
+ wl_list_for_each(it, &bar_list, link) {
+ if (it->xdg_output_name && !strcmp(wordbeg, it->xdg_output_name)) {
+ bar = it;
+ break;
+ }
+ }
+ }
+
+ if (!all && !bar)
+ return;
+
+ ADVANCE();
+
+ if (!strcmp(wordbeg, "status")) {
+ if (!*wordend)
+ return;
+ if (all) {
+ Bar *first = NULL;
+ wl_list_for_each(bar, &bar_list, link) {
+ if (first) {
+ copy_customtext(&first->status, &bar->status);
+ } else {
+ parse_into_customtext(&bar->status, wordend);
+ first = bar;
+ }
+ bar->redraw = true;
+ }
+ } else {
+ parse_into_customtext(&bar->status, wordend);
+ bar->redraw = true;
+ }
+ } else if (!strcmp(wordbeg, "title")) {
+ if (!custom_title || !*wordend)
+ return;
+ if (all) {
+ Bar *first = NULL;
+ wl_list_for_each(bar, &bar_list, link) {
+ if (first) {
+ copy_customtext(&first->title, &bar->title);
+ } else {
+ parse_into_customtext(&bar->title, wordend);
+ first = bar;
+ }
+ bar->redraw = true;
+ }
+ } else {
+ parse_into_customtext(&bar->title, wordend);
+ bar->redraw = true;
+ }
+ } else if (!strcmp(wordbeg, "show")) {
+ if (all) {
+ wl_list_for_each(bar, &bar_list, link)
+ if (bar->hidden)
+ show_bar(bar);
+ } else {
+ if (bar->hidden)
+ show_bar(bar);
+ }
+ } else if (!strcmp(wordbeg, "hide")) {
+ if (all) {
+ wl_list_for_each(bar, &bar_list, link)
+ if (!bar->hidden)
+ hide_bar(bar);
+ } else {
+ if (!bar->hidden)
+ hide_bar(bar);
+ }
+ } else if (!strcmp(wordbeg, "toggle-visibility")) {
+ if (all) {
+ wl_list_for_each(bar, &bar_list, link)
+ if (bar->hidden)
+ show_bar(bar);
+ else
+ hide_bar(bar);
+ } else {
+ if (bar->hidden)
+ show_bar(bar);
+ else
+ hide_bar(bar);
+ }
+ } else if (!strcmp(wordbeg, "set-top")) {
+ if (all) {
+ wl_list_for_each(bar, &bar_list, link)
+ if (bar->bottom)
+ set_top(bar);
+
+ } else {
+ if (bar->bottom)
+ set_top(bar);
+ }
+ } else if (!strcmp(wordbeg, "set-bottom")) {
+ if (all) {
+ wl_list_for_each(bar, &bar_list, link)
+ if (!bar->bottom)
+ set_bottom(bar);
+
+ } else {
+ if (!bar->bottom)
+ set_bottom(bar);
+ }
+ } else if (!strcmp(wordbeg, "toggle-location")) {
+ if (all) {
+ wl_list_for_each(bar, &bar_list, link)
+ if (bar->bottom)
+ set_top(bar);
+ else
+ set_bottom(bar);
+ } else {
+ if (bar->bottom)
+ set_top(bar);
+ else
+ set_bottom(bar);
+ }
+ }
+}
+
+static void
+event_loop(void)
+{
+ int wl_fd = wl_display_get_fd(display);
+
+ while (run_display) {
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ FD_SET(wl_fd, &rfds);
+ FD_SET(sock_fd, &rfds);
+ if (!ipc)
+ FD_SET(STDIN_FILENO, &rfds);
+
+ wl_display_flush(display);
+
+ if (select(MAX(sock_fd, wl_fd) + 1, &rfds, NULL, NULL, NULL) == -1) {
+ if (errno == EINTR)
+ continue;
+ else
+ EDIE("select");
+ }
+
+ if (FD_ISSET(wl_fd, &rfds))
+ if (wl_display_dispatch(display) == -1)
+ break;
+ if (FD_ISSET(sock_fd, &rfds))
+ read_socket();
+ if (!ipc && FD_ISSET(STDIN_FILENO, &rfds))
+ read_stdin();
+
+ Bar *bar;
+ wl_list_for_each(bar, &bar_list, link) {
+ if (bar->redraw) {
+ if (!bar->hidden)
+ draw_frame(bar);
+ bar->redraw = false;
+ }
+ }
+ }
+}
+
+static void
+client_send_command(struct sockaddr_un *sock_address, const char *output,
+ const char *cmd, const char *data, const char *target_socket)
+{
+ DIR *dir;
+ if (!(dir = opendir(socketdir)))
+ EDIE("Could not open directory '%s'", socketdir);
+
+ if (data)
+ snprintf(sockbuf, sizeof sockbuf, "%s %s %s", output, cmd, data);
+ else
+ snprintf(sockbuf, sizeof sockbuf, "%s %s", output, cmd);
+
+ size_t len = strlen(sockbuf);
+
+ struct dirent *de;
+ bool newfd = true;
+
+ /* Send data to all dwlb instances */
+ while ((de = readdir(dir))) {
+ if (!strncmp(de->d_name, "dwlb-", 5)) {
+ if (!target_socket || !strncmp(de -> d_name, target_socket, 6)){
+ if (newfd && (sock_fd = socket(AF_UNIX, SOCK_STREAM, 1)) == -1)
+ EDIE("socket");
+ snprintf(sock_address->sun_path, sizeof sock_address->sun_path, "%s/%s", socketdir, de->d_name);
+ if (connect(sock_fd, (struct sockaddr *) sock_address, sizeof(*sock_address)) == -1) {
+ newfd = false;
+ continue;
+ }
+ if (send(sock_fd, sockbuf, len, 0) == -1)
+ fprintf(stderr, "Could not send status data to '%s'\n", sock_address->sun_path);
+ close(sock_fd);
+ newfd = true;
+ }
+ }
+ }
+
+ closedir(dir);
+}
+
+void
+sig_handler(int sig)
+{
+ if (sig == SIGINT || sig == SIGHUP || sig == SIGTERM)
+ run_display = false;
+}
+
+int
+main(int argc, char **argv)
+{
+ char *xdgruntimedir;
+ struct sockaddr_un sock_address;
+ Bar *bar, *bar2;
+ Seat *seat, *seat2;
+
+ /* Establish socket directory */
+ if (!(xdgruntimedir = getenv("XDG_RUNTIME_DIR")))
+ DIE("Could not retrieve XDG_RUNTIME_DIR");
+ snprintf(socketdir, sizeof socketdir, "%s/dwlb", xdgruntimedir);
+ if (mkdir(socketdir, S_IRWXU) == -1)
+ if (errno != EEXIST)
+ EDIE("Could not create directory '%s'", socketdir);
+ sock_address.sun_family = AF_UNIX;
+
+ /* Parse options */
+ char *target_socket = NULL;
+ int i = 1;
+ if (argc > 1 && !strcmp(argv[1], "-target-socket")) {
+ if (2 >= argc) {
+ DIE("Option -socket requires an argument");
+ }
+ target_socket = argv[2];
+ i += 2;
+ }
+ for (; i < argc; i++) {
+ if (!strcmp(argv[i], "-status")) {
+ if (++i + 1 >= argc)
+ DIE("Option -status requires two arguments");
+ client_send_command(&sock_address, argv[i], "status", argv[i + 1], target_socket);
+ return 0;
+ } else if (!strcmp(argv[i], "-status-stdin")) {
+ if (++i >= argc)
+ DIE("Option -status-stdin requires an argument");
+ char *status = malloc(TEXT_MAX * sizeof(char));
+ while (fgets(status, TEXT_MAX-1, stdin)) {
+ status[strlen(status)-1] = '\0';
+ client_send_command(&sock_address, argv[i], "status", status, target_socket);
+ }
+ free(status);
+ return 0;
+ } else if (!strcmp(argv[i], "-title")) {
+ if (++i + 1 >= argc)
+ DIE("Option -title requires two arguments");
+ client_send_command(&sock_address, argv[i], "title", argv[i + 1], target_socket);
+ return 0;
+ } else if (!strcmp(argv[i], "-show")) {
+ if (++i >= argc)
+ DIE("Option -show requires an argument");
+ client_send_command(&sock_address, argv[i], "show", NULL, target_socket);
+ return 0;
+ } else if (!strcmp(argv[i], "-hide")) {
+ if (++i >= argc)
+ DIE("Option -hide requires an argument");
+ client_send_command(&sock_address, argv[i], "hide", NULL, target_socket);
+ return 0;
+ } else if (!strcmp(argv[i], "-toggle-visibility")) {
+ if (++i >= argc)
+ DIE("Option -toggle requires an argument");
+ client_send_command(&sock_address, argv[i], "toggle-visibility", NULL, target_socket);
+ return 0;
+ } else if (!strcmp(argv[i], "-set-top")) {
+ if (++i >= argc)
+ DIE("Option -set-top requires an argument");
+ client_send_command(&sock_address, argv[i], "set-top", NULL, target_socket);
+ return 0;
+ } else if (!strcmp(argv[i], "-set-bottom")) {
+ if (++i >= argc)
+ DIE("Option -set-bottom requires an argument");
+ client_send_command(&sock_address, argv[i], "set-bottom", NULL, target_socket);
+ return 0;
+ } else if (!strcmp(argv[i], "-toggle-location")) {
+ if (++i >= argc)
+ DIE("Option -toggle-location requires an argument");
+ client_send_command(&sock_address, argv[i], "toggle-location", NULL, target_socket);
+ return 0;
+ } else if (!strcmp(argv[i], "-ipc")) {
+ ipc = true;
+ } else if (!strcmp(argv[i], "-no-ipc")) {
+ ipc = false;
+ } else if (!strcmp(argv[i], "-hide-vacant-tags")) {
+ hide_vacant = true;
+ } else if (!strcmp(argv[i], "-no-hide-vacant-tags")) {
+ hide_vacant = false;
+ } else if (!strcmp(argv[i], "-bottom")) {
+ bottom = true;
+ } else if (!strcmp(argv[i], "-no-bottom")) {
+ bottom = false;
+ } else if (!strcmp(argv[i], "-hidden")) {
+ hidden = true;
+ } else if (!strcmp(argv[i], "-no-hidden")) {
+ hidden = false;
+ } else if (!strcmp(argv[i], "-status-commands")) {
+ status_commands = true;
+ } else if (!strcmp(argv[i], "-no-status-commands")) {
+ status_commands = false;
+ } else if (!strcmp(argv[i], "-center-title")) {
+ center_title = true;
+ } else if (!strcmp(argv[i], "-no-center-title")) {
+ center_title = false;
+ } else if (!strcmp(argv[i], "-custom-title")) {
+ custom_title = true;
+ } else if (!strcmp(argv[i], "-no-custom-title")) {
+ custom_title = false;
+ } else if (!strcmp(argv[i], "-font")) {
+ if (++i >= argc)
+ DIE("Option -font requires an argument");
+ fontstr = argv[i];
+ } else if (!strcmp(argv[i], "-vertical-padding")) {
+ if (++i >= argc)
+ DIE("Option -vertical-padding requires an argument");
+ vertical_padding = MAX(MIN(atoi(argv[i]), 100), 0);
+ } else if (!strcmp(argv[i], "-active-fg-color")) {
+ if (++i >= argc)
+ DIE("Option -active-fg-color requires an argument");
+ if (parse_color(argv[i], &active_fg_color) == -1)
+ DIE("malformed color string");
+ } else if (!strcmp(argv[i], "-active-bg-color")) {
+ if (++i >= argc)
+ DIE("Option -active-bg-color requires an argument");
+ if (parse_color(argv[i], &active_bg_color) == -1)
+ DIE("malformed color string");
+ } else if (!strcmp(argv[i], "-occupied-fg-color")) {
+ if (++i >= argc)
+ DIE("Option -occupied-fg-color requires an argument");
+ if (parse_color(argv[i], &occupied_fg_color) == -1)
+ DIE("malformed color string");
+ } else if (!strcmp(argv[i], "-occupied-bg-color")) {
+ if (++i >= argc)
+ DIE("Option -occupied-bg-color requires an argument");
+ if (parse_color(argv[i], &occupied_bg_color) == -1)
+ DIE("malformed color string");
+ } else if (!strcmp(argv[i], "-inactive-fg-color")) {
+ if (++i >= argc)
+ DIE("Option -inactive-fg-color requires an argument");
+ if (parse_color(argv[i], &inactive_fg_color) == -1)
+ DIE("malformed color string");
+ } else if (!strcmp(argv[i], "-inactive-bg-color")) {
+ if (++i >= argc)
+ DIE("Option -inactive-bg-color requires an argument");
+ if (parse_color(argv[i], &inactive_bg_color) == -1)
+ DIE("malformed color string");
+ } else if (!strcmp(argv[i], "-urgent-fg-color")) {
+ if (++i >= argc)
+ DIE("Option -urgent-fg-color requires an argument");
+ if (parse_color(argv[i], &urgent_fg_color) == -1)
+ DIE("malformed color string");
+ } else if (!strcmp(argv[i], "-urgent-bg-color")) {
+ if (++i >= argc)
+ DIE("Option -urgent-bg-color requires an argument");
+ if (parse_color(argv[i], &urgent_bg_color) == -1)
+ DIE("malformed color string");
+ } else if (!strcmp(argv[i], "-middle-bg-color-selected")) {
+ if (++i >= argc)
+ DIE("Option -middle-bg-color-selected requires an argument");
+ if (parse_color(argv[i], &middle_bg_color_selected) == -1)
+ DIE("malformed color string");
+ } else if (!strcmp(argv[i], "-middle-bg-color")) {
+ if (++i >= argc)
+ DIE("Option -middle-bg-color requires an argument");
+ if (parse_color(argv[i], &middle_bg_color) == -1)
+ DIE("malformed color string");
+ } else if (!strcmp(argv[i], "-tags")) {
+ if (++i >= argc)
+ DIE("Option -tags requires at least one argument");
+ int v;
+ if ((v = atoi(argv[i])) < 0 || i + v >= argc)
+ DIE("-tags: invalid arguments");
+ if (tags) {
+ for (uint32_t j = 0; j < tags_l; j++)
+ free(tags[j]);
+ free(tags);
+ }
+ if (!(tags = malloc(v * sizeof(char *))))
+ EDIE("malloc");
+ for (int j = 0; j < v; j++)
+ if (!(tags[j] = strdup(argv[i + 1 + j])))
+ EDIE("strdup");
+ tags_l = tags_c = v;
+ i += v;
+ } else if (!strcmp(argv[i], "-scale")) {
+ if (++i >= argc)
+ DIE("Option -scale requires an argument");
+ buffer_scale = strtoul(argv[i], &argv[i] + strlen(argv[i]), 10);
+ } else if (!strcmp(argv[i], "-v")) {
+ fprintf(stderr, PROGRAM " " VERSION "\n");
+ return 0;
+ } else if (!strcmp(argv[i], "-h")) {
+ fprintf(stderr, USAGE);
+ return 0;
+ } else {
+ DIE("Option '%s' not recognized\n" USAGE, argv[i]);
+ }
+ }
+
+ /* Set up display and protocols */
+ display = wl_display_connect(NULL);
+ if (!display)
+ DIE("Failed to create display");
+
+ wl_list_init(&bar_list);
+ wl_list_init(&seat_list);
+
+ struct wl_registry *registry = wl_display_get_registry(display);
+ wl_registry_add_listener(registry, ®istry_listener, NULL);
+ wl_display_roundtrip(display);
+ if (!compositor || !shm || !layer_shell || !output_manager || (ipc && !dwl_wm))
+ DIE("Compositor does not support all needed protocols");
+
+ /* Load selected font */
+ fcft_init(FCFT_LOG_COLORIZE_AUTO, 0, FCFT_LOG_CLASS_ERROR);
+ fcft_set_scaling_filter(FCFT_SCALING_FILTER_LANCZOS3);
+
+ unsigned int dpi = 96 * buffer_scale;
+ char buf[10];
+ snprintf(buf, sizeof buf, "dpi=%u", dpi);
+ if (!(font = fcft_from_name(1, (const char *[]) {fontstr}, buf)))
+ DIE("Could not load font");
+ textpadding = font->height / 2;
+ height = font->height / buffer_scale + vertical_padding * 2;
+
+ /* Configure tag names */
+ if (!ipc && !tags) {
+ if (!(tags = malloc(LENGTH(tags_names) * sizeof(char *))))
+ EDIE("malloc");
+ tags_l = tags_c = LENGTH(tags_names);
+ for (uint32_t i = 0; i < tags_l; i++)
+ if (!(tags[i] = strdup(tags_names[i])))
+ EDIE("strdup");
+ }
+
+ /* Setup bars */
+ wl_list_for_each(bar, &bar_list, link)
+ setup_bar(bar);
+ wl_display_roundtrip(display);
+
+ if (!ipc) {
+ /* Configure stdin */
+ if (fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
+ EDIE("fcntl");
+
+ /* Allocate stdin buffer */
+ if (!(stdinbuf = malloc(1024)))
+ EDIE("malloc");
+ stdinbuf_cap = 1024;
+ }
+
+ /* Set up socket */
+ bool found = false;
+ for (uint32_t i = 0; i < 50; i++) {
+ if ((sock_fd = socket(AF_UNIX, SOCK_STREAM, 1)) == -1)
+ DIE("socket");
+ snprintf(sock_address.sun_path, sizeof sock_address.sun_path, "%s/dwlb-%i", socketdir, i);
+ if (connect(sock_fd, (struct sockaddr *)&sock_address, sizeof sock_address) == -1) {
+ found = true;
+ break;
+ }
+ close(sock_fd);
+ }
+ if (!found)
+ DIE("Could not secure a socket path");
+
+ socketpath = (char *)&sock_address.sun_path;
+ unlink(socketpath);
+ if (bind(sock_fd, (struct sockaddr *)&sock_address, sizeof sock_address) == -1)
+ EDIE("bind");
+ if (listen(sock_fd, SOMAXCONN) == -1)
+ EDIE("listen");
+ fcntl(sock_fd, F_SETFD, FD_CLOEXEC | fcntl(sock_fd, F_GETFD));
+
+ /* Set up signals */
+ signal(SIGINT, sig_handler);
+ signal(SIGHUP, sig_handler);
+ signal(SIGTERM, sig_handler);
+ signal(SIGCHLD, SIG_IGN);
+
+ /* Run */
+ run_display = true;
+ event_loop();
+
+ /* Clean everything up */
+ close(sock_fd);
+ unlink(socketpath);
+
+ if (!ipc)
+ free(stdinbuf);
+
+ if (tags) {
+ for (uint32_t i = 0; i < tags_l; i++)
+ free(tags[i]);
+ free(tags);
+ }
+ if (layouts) {
+ for (uint32_t i = 0; i < layouts_l; i++)
+ free(layouts[i]);
+ free(layouts);
+ }
+
+ wl_list_for_each_safe(bar, bar2, &bar_list, link)
+ teardown_bar(bar);
+ wl_list_for_each_safe(seat, seat2, &seat_list, link)
+ teardown_seat(seat);
+
+ zwlr_layer_shell_v1_destroy(layer_shell);
+ zxdg_output_manager_v1_destroy(output_manager);
+ if (ipc)
+ zdwl_ipc_manager_v2_destroy(dwl_wm);
+
+ fcft_destroy(font);
+ fcft_fini();
+
+ wl_shm_destroy(shm);
+ wl_compositor_destroy(compositor);
+ wl_registry_destroy(registry);
+ wl_display_disconnect(display);
+
+ return 0;
+}
diff --git a/dwlb/protocols/dwl-ipc-unstable-v2.xml b/dwlb/protocols/dwl-ipc-unstable-v2.xml
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+This is largely ripped from somebar's ipc patchset; just with some personal modifications.
+I would probably just submit raphi's patchset but I don't think that would be polite.
+-->
+<protocol name="dwl_ipc_unstable_v2">
+ <description summary="inter-proccess-communication about dwl's state">
+ This protocol allows clients to update and get updates from dwl.
+
+ Warning! The protocol described in this file is experimental and
+ backward incompatible changes may be made. Backward compatible
+ changes may be added together with the corresponding interface
+ version bump.
+ Backward incompatible changes are done by bumping the version
+ number in the protocol and interface names and resetting the
+ interface version. Once the protocol is to be declared stable,
+ the 'z' prefix and the version number in the protocol and
+ interface names are removed and the interface version number is
+ reset.
+ </description>
+
+ <interface name="zdwl_ipc_manager_v2" version="2">
+ <description summary="manage dwl state">
+ This interface is exposed as a global in wl_registry.
+
+ Clients can use this interface to get a dwl_ipc_output.
+ After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events.
+ The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client.
+ </description>
+
+ <request name="release" type="destructor">
+ <description summary="release dwl_ipc_manager">
+ Indicates that the client will not the dwl_ipc_manager object anymore.
+ Objects created through this instance are not affected.
+ </description>
+ </request>
+
+ <request name="get_output">
+ <description summary="get a dwl_ipc_outout for a wl_output">
+ Get a dwl_ipc_outout for the specified wl_output.
+ </description>
+ <arg name="id" type="new_id" interface="zdwl_ipc_output_v2"/>
+ <arg name="output" type="object" interface="wl_output"/>
+ </request>
+
+ <event name="tags">
+ <description summary="Announces tag amount">
+ This event is sent after binding.
+ A roundtrip after binding guarantees the client recieved all tags.
+ </description>
+ <arg name="amount" type="uint"/>
+ </event>
+
+ <event name="layout">
+ <description summary="Announces a layout">
+ This event is sent after binding.
+ A roundtrip after binding guarantees the client recieved all layouts.
+ </description>
+ <arg name="name" type="string"/>
+ </event>
+ </interface>
+
+ <interface name="zdwl_ipc_output_v2" version="2">
+ <description summary="control dwl output">
+ Observe and control a dwl output.
+
+ Events are double-buffered:
+ Clients should cache events and redraw when a dwl_ipc_output.frame event is sent.
+
+ Request are not double-buffered:
+ The compositor will update immediately upon request.
+ </description>
+
+ <enum name="tag_state">
+ <entry name="none" value="0" summary="no state"/>
+ <entry name="active" value="1" summary="tag is active"/>
+ <entry name="urgent" value="2" summary="tag has at least one urgent client"/>
+ </enum>
+
+ <request name="release" type="destructor">
+ <description summary="release dwl_ipc_outout">
+ Indicates to that the client no longer needs this dwl_ipc_output.
+ </description>
+ </request>
+
+ <event name="toggle_visibility">
+ <description summary="Toggle client visibilty">
+ Indicates the client should hide or show themselves.
+ If the client is visible then hide, if hidden then show.
+ </description>
+ </event>
+
+ <event name="active">
+ <description summary="Update the selected output.">
+ Indicates if the output is active. Zero is invalid, nonzero is valid.
+ </description>
+ <arg name="active" type="uint"/>
+ </event>
+
+ <event name="tag">
+ <description summary="Update the state of a tag.">
+ Indicates that a tag has been updated.
+ </description>
+ <arg name="tag" type="uint" summary="Index of the tag"/>
+ <arg name="state" type="uint" enum="tag_state" summary="The state of the tag."/>
+ <arg name="clients" type="uint" summary="The number of clients in the tag."/>
+ <arg name="focused" type="uint" summary="If there is a focused client. Nonzero being valid, zero being invalid."/>
+ </event>
+
+ <event name="layout">
+ <description summary="Update the layout.">
+ Indicates a new layout is selected.
+ </description>
+ <arg name="layout" type="uint" summary="Index of the layout."/>
+ </event>
+
+ <event name="title">
+ <description summary="Update the title.">
+ Indicates the title has changed.
+ </description>
+ <arg name="title" type="string" summary="The new title name."/>
+ </event>
+
+ <event name="appid" since="1">
+ <description summary="Update the appid.">
+ Indicates the appid has changed.
+ </description>
+ <arg name="appid" type="string" summary="The new appid."/>
+ </event>
+
+ <event name="layout_symbol" since="1">
+ <description summary="Update the current layout symbol">
+ Indicates the layout has changed. Since layout symbols are dynamic.
+ As opposed to the zdwl_ipc_manager.layout event, this should take precendence when displaying.
+ You can ignore the zdwl_ipc_output.layout event.
+ </description>
+ <arg name="layout" type="string" summary="The new layout"/>
+ </event>
+
+ <event name="frame">
+ <description summary="The update sequence is done.">
+ Indicates that a sequence of status updates have finished and the client should redraw.
+ </description>
+ </event>
+
+ <request name="set_tags">
+ <description summary="Set the active tags of this output"/>
+ <arg name="tagmask" type="uint" summary="bitmask of the tags that should be set."/>
+ <arg name="toggle_tagset" type="uint" summary="toggle the selected tagset, zero for invalid, nonzero for valid."/>
+ </request>
+
+ <request name="set_client_tags">
+ <description summary="Set the tags of the focused client.">
+ The tags are updated as follows:
+ new_tags = (current_tags AND and_tags) XOR xor_tags
+ </description>
+ <arg name="and_tags" type="uint"/>
+ <arg name="xor_tags" type="uint"/>
+ </request>
+
+ <request name="set_layout">
+ <description summary="Set the layout of this output"/>
+ <arg name="index" type="uint" summary="index of a layout recieved by dwl_ipc_manager.layout"/>
+ </request>
+
+ <!-- Version 2 -->
+ <event name="fullscreen" since="2">
+ <description summary="Update fullscreen status">
+ Indicates if the selected client on this output is fullscreen.
+ </description>
+ <arg name="is_fullscreen" type="uint" summary="If the selected client is fullscreen. Nonzero is valid, zero invalid"/>
+ </event>
+
+ <event name="floating" since="2">
+ <description summary="Update the floating status">
+ Indicates if the selected client on this output is floating.
+ </description>
+ <arg name="is_floating" type="uint" summary="If the selected client is floating. Nonzero is valid, zero invalid"/>
+ </event>
+ </interface>
+</protocol>
diff --git a/dwlb/protocols/wlr-layer-shell-unstable-v1.xml b/dwlb/protocols/wlr-layer-shell-unstable-v1.xml
@@ -0,0 +1,390 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="wlr_layer_shell_unstable_v1">
+ <copyright>
+ Copyright © 2017 Drew DeVault
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, provided that the above copyright notice appear in
+ all copies and that both that copyright notice and this permission
+ notice appear in supporting documentation, and that the name of
+ the copyright holders not be used in advertising or publicity
+ pertaining to distribution of the software without specific,
+ written prior permission. The copyright holders make no
+ representations about the suitability of this software for any
+ purpose. It is provided "as is" without express or implied
+ warranty.
+
+ THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ THIS SOFTWARE.
+ </copyright>
+
+ <interface name="zwlr_layer_shell_v1" version="4">
+ <description summary="create surfaces that are layers of the desktop">
+ Clients can use this interface to assign the surface_layer role to
+ wl_surfaces. Such surfaces are assigned to a "layer" of the output and
+ rendered with a defined z-depth respective to each other. They may also be
+ anchored to the edges and corners of a screen and specify input handling
+ semantics. This interface should be suitable for the implementation of
+ many desktop shell components, and a broad number of other applications
+ that interact with the desktop.
+ </description>
+
+ <request name="get_layer_surface">
+ <description summary="create a layer_surface from a surface">
+ Create a layer surface for an existing surface. This assigns the role of
+ layer_surface, or raises a protocol error if another role is already
+ assigned.
+
+ Creating a layer surface from a wl_surface which has a buffer attached
+ or committed is a client error, and any attempts by a client to attach
+ or manipulate a buffer prior to the first layer_surface.configure call
+ must also be treated as errors.
+
+ After creating a layer_surface object and setting it up, the client
+ must perform an initial commit without any buffer attached.
+ The compositor will reply with a layer_surface.configure event.
+ The client must acknowledge it and is then allowed to attach a buffer
+ to map the surface.
+
+ You may pass NULL for output to allow the compositor to decide which
+ output to use. Generally this will be the one that the user most
+ recently interacted with.
+
+ Clients can specify a namespace that defines the purpose of the layer
+ surface.
+ </description>
+ <arg name="id" type="new_id" interface="zwlr_layer_surface_v1"/>
+ <arg name="surface" type="object" interface="wl_surface"/>
+ <arg name="output" type="object" interface="wl_output" allow-null="true"/>
+ <arg name="layer" type="uint" enum="layer" summary="layer to add this surface to"/>
+ <arg name="namespace" type="string" summary="namespace for the layer surface"/>
+ </request>
+
+ <enum name="error">
+ <entry name="role" value="0" summary="wl_surface has another role"/>
+ <entry name="invalid_layer" value="1" summary="layer value is invalid"/>
+ <entry name="already_constructed" value="2" summary="wl_surface has a buffer attached or committed"/>
+ </enum>
+
+ <enum name="layer">
+ <description summary="available layers for surfaces">
+ These values indicate which layers a surface can be rendered in. They
+ are ordered by z depth, bottom-most first. Traditional shell surfaces
+ will typically be rendered between the bottom and top layers.
+ Fullscreen shell surfaces are typically rendered at the top layer.
+ Multiple surfaces can share a single layer, and ordering within a
+ single layer is undefined.
+ </description>
+
+ <entry name="background" value="0"/>
+ <entry name="bottom" value="1"/>
+ <entry name="top" value="2"/>
+ <entry name="overlay" value="3"/>
+ </enum>
+
+ <!-- Version 3 additions -->
+
+ <request name="destroy" type="destructor" since="3">
+ <description summary="destroy the layer_shell object">
+ This request indicates that the client will not use the layer_shell
+ object any more. Objects that have been created through this instance
+ are not affected.
+ </description>
+ </request>
+ </interface>
+
+ <interface name="zwlr_layer_surface_v1" version="4">
+ <description summary="layer metadata interface">
+ An interface that may be implemented by a wl_surface, for surfaces that
+ are designed to be rendered as a layer of a stacked desktop-like
+ environment.
+
+ Layer surface state (layer, size, anchor, exclusive zone,
+ margin, interactivity) is double-buffered, and will be applied at the
+ time wl_surface.commit of the corresponding wl_surface is called.
+
+ Attaching a null buffer to a layer surface unmaps it.
+
+ Unmapping a layer_surface means that the surface cannot be shown by the
+ compositor until it is explicitly mapped again. The layer_surface
+ returns to the state it had right after layer_shell.get_layer_surface.
+ The client can re-map the surface by performing a commit without any
+ buffer attached, waiting for a configure event and handling it as usual.
+ </description>
+
+ <request name="set_size">
+ <description summary="sets the size of the surface">
+ Sets the size of the surface in surface-local coordinates. The
+ compositor will display the surface centered with respect to its
+ anchors.
+
+ If you pass 0 for either value, the compositor will assign it and
+ inform you of the assignment in the configure event. You must set your
+ anchor to opposite edges in the dimensions you omit; not doing so is a
+ protocol error. Both values are 0 by default.
+
+ Size is double-buffered, see wl_surface.commit.
+ </description>
+ <arg name="width" type="uint"/>
+ <arg name="height" type="uint"/>
+ </request>
+
+ <request name="set_anchor">
+ <description summary="configures the anchor point of the surface">
+ Requests that the compositor anchor the surface to the specified edges
+ and corners. If two orthogonal edges are specified (e.g. 'top' and
+ 'left'), then the anchor point will be the intersection of the edges
+ (e.g. the top left corner of the output); otherwise the anchor point
+ will be centered on that edge, or in the center if none is specified.
+
+ Anchor is double-buffered, see wl_surface.commit.
+ </description>
+ <arg name="anchor" type="uint" enum="anchor"/>
+ </request>
+
+ <request name="set_exclusive_zone">
+ <description summary="configures the exclusive geometry of this surface">
+ Requests that the compositor avoids occluding an area with other
+ surfaces. The compositor's use of this information is
+ implementation-dependent - do not assume that this region will not
+ actually be occluded.
+
+ A positive value is only meaningful if the surface is anchored to one
+ edge or an edge and both perpendicular edges. If the surface is not
+ anchored, anchored to only two perpendicular edges (a corner), anchored
+ to only two parallel edges or anchored to all edges, a positive value
+ will be treated the same as zero.
+
+ A positive zone is the distance from the edge in surface-local
+ coordinates to consider exclusive.
+
+ Surfaces that do not wish to have an exclusive zone may instead specify
+ how they should interact with surfaces that do. If set to zero, the
+ surface indicates that it would like to be moved to avoid occluding
+ surfaces with a positive exclusive zone. If set to -1, the surface
+ indicates that it would not like to be moved to accommodate for other
+ surfaces, and the compositor should extend it all the way to the edges
+ it is anchored to.
+
+ For example, a panel might set its exclusive zone to 10, so that
+ maximized shell surfaces are not shown on top of it. A notification
+ might set its exclusive zone to 0, so that it is moved to avoid
+ occluding the panel, but shell surfaces are shown underneath it. A
+ wallpaper or lock screen might set their exclusive zone to -1, so that
+ they stretch below or over the panel.
+
+ The default value is 0.
+
+ Exclusive zone is double-buffered, see wl_surface.commit.
+ </description>
+ <arg name="zone" type="int"/>
+ </request>
+
+ <request name="set_margin">
+ <description summary="sets a margin from the anchor point">
+ Requests that the surface be placed some distance away from the anchor
+ point on the output, in surface-local coordinates. Setting this value
+ for edges you are not anchored to has no effect.
+
+ The exclusive zone includes the margin.
+
+ Margin is double-buffered, see wl_surface.commit.
+ </description>
+ <arg name="top" type="int"/>
+ <arg name="right" type="int"/>
+ <arg name="bottom" type="int"/>
+ <arg name="left" type="int"/>
+ </request>
+
+ <enum name="keyboard_interactivity">
+ <description summary="types of keyboard interaction possible for a layer shell surface">
+ Types of keyboard interaction possible for layer shell surfaces. The
+ rationale for this is twofold: (1) some applications are not interested
+ in keyboard events and not allowing them to be focused can improve the
+ desktop experience; (2) some applications will want to take exclusive
+ keyboard focus.
+ </description>
+
+ <entry name="none" value="0">
+ <description summary="no keyboard focus is possible">
+ This value indicates that this surface is not interested in keyboard
+ events and the compositor should never assign it the keyboard focus.
+
+ This is the default value, set for newly created layer shell surfaces.
+
+ This is useful for e.g. desktop widgets that display information or
+ only have interaction with non-keyboard input devices.
+ </description>
+ </entry>
+ <entry name="exclusive" value="1">
+ <description summary="request exclusive keyboard focus">
+ Request exclusive keyboard focus if this surface is above the shell surface layer.
+
+ For the top and overlay layers, the seat will always give
+ exclusive keyboard focus to the top-most layer which has keyboard
+ interactivity set to exclusive. If this layer contains multiple
+ surfaces with keyboard interactivity set to exclusive, the compositor
+ determines the one receiving keyboard events in an implementation-
+ defined manner. In this case, no guarantee is made when this surface
+ will receive keyboard focus (if ever).
+
+ For the bottom and background layers, the compositor is allowed to use
+ normal focus semantics.
+
+ This setting is mainly intended for applications that need to ensure
+ they receive all keyboard events, such as a lock screen or a password
+ prompt.
+ </description>
+ </entry>
+ <entry name="on_demand" value="2" since="4">
+ <description summary="request regular keyboard focus semantics">
+ This requests the compositor to allow this surface to be focused and
+ unfocused by the user in an implementation-defined manner. The user
+ should be able to unfocus this surface even regardless of the layer
+ it is on.
+
+ Typically, the compositor will want to use its normal mechanism to
+ manage keyboard focus between layer shell surfaces with this setting
+ and regular toplevels on the desktop layer (e.g. click to focus).
+ Nevertheless, it is possible for a compositor to require a special
+ interaction to focus or unfocus layer shell surfaces (e.g. requiring
+ a click even if focus follows the mouse normally, or providing a
+ keybinding to switch focus between layers).
+
+ This setting is mainly intended for desktop shell components (e.g.
+ panels) that allow keyboard interaction. Using this option can allow
+ implementing a desktop shell that can be fully usable without the
+ mouse.
+ </description>
+ </entry>
+ </enum>
+
+ <request name="set_keyboard_interactivity">
+ <description summary="requests keyboard events">
+ Set how keyboard events are delivered to this surface. By default,
+ layer shell surfaces do not receive keyboard events; this request can
+ be used to change this.
+
+ This setting is inherited by child surfaces set by the get_popup
+ request.
+
+ Layer surfaces receive pointer, touch, and tablet events normally. If
+ you do not want to receive them, set the input region on your surface
+ to an empty region.
+
+ Keyboard interactivity is double-buffered, see wl_surface.commit.
+ </description>
+ <arg name="keyboard_interactivity" type="uint" enum="keyboard_interactivity"/>
+ </request>
+
+ <request name="get_popup">
+ <description summary="assign this layer_surface as an xdg_popup parent">
+ This assigns an xdg_popup's parent to this layer_surface. This popup
+ should have been created via xdg_surface::get_popup with the parent set
+ to NULL, and this request must be invoked before committing the popup's
+ initial state.
+
+ See the documentation of xdg_popup for more details about what an
+ xdg_popup is and how it is used.
+ </description>
+ <arg name="popup" type="object" interface="xdg_popup"/>
+ </request>
+
+ <request name="ack_configure">
+ <description summary="ack a configure event">
+ When a configure event is received, if a client commits the
+ surface in response to the configure event, then the client
+ must make an ack_configure request sometime before the commit
+ request, passing along the serial of the configure event.
+
+ If the client receives multiple configure events before it
+ can respond to one, it only has to ack the last configure event.
+
+ A client is not required to commit immediately after sending
+ an ack_configure request - it may even ack_configure several times
+ before its next surface commit.
+
+ A client may send multiple ack_configure requests before committing, but
+ only the last request sent before a commit indicates which configure
+ event the client really is responding to.
+ </description>
+ <arg name="serial" type="uint" summary="the serial from the configure event"/>
+ </request>
+
+ <request name="destroy" type="destructor">
+ <description summary="destroy the layer_surface">
+ This request destroys the layer surface.
+ </description>
+ </request>
+
+ <event name="configure">
+ <description summary="suggest a surface change">
+ The configure event asks the client to resize its surface.
+
+ Clients should arrange their surface for the new states, and then send
+ an ack_configure request with the serial sent in this configure event at
+ some point before committing the new surface.
+
+ The client is free to dismiss all but the last configure event it
+ received.
+
+ The width and height arguments specify the size of the window in
+ surface-local coordinates.
+
+ The size is a hint, in the sense that the client is free to ignore it if
+ it doesn't resize, pick a smaller size (to satisfy aspect ratio or
+ resize in steps of NxM pixels). If the client picks a smaller size and
+ is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the
+ surface will be centered on this axis.
+
+ If the width or height arguments are zero, it means the client should
+ decide its own window dimension.
+ </description>
+ <arg name="serial" type="uint"/>
+ <arg name="width" type="uint"/>
+ <arg name="height" type="uint"/>
+ </event>
+
+ <event name="closed">
+ <description summary="surface should be closed">
+ The closed event is sent by the compositor when the surface will no
+ longer be shown. The output may have been destroyed or the user may
+ have asked for it to be removed. Further changes to the surface will be
+ ignored. The client should destroy the resource after receiving this
+ event, and create a new surface if they so choose.
+ </description>
+ </event>
+
+ <enum name="error">
+ <entry name="invalid_surface_state" value="0" summary="provided surface state is invalid"/>
+ <entry name="invalid_size" value="1" summary="size is invalid"/>
+ <entry name="invalid_anchor" value="2" summary="anchor bitfield is invalid"/>
+ <entry name="invalid_keyboard_interactivity" value="3" summary="keyboard interactivity is invalid"/>
+ </enum>
+
+ <enum name="anchor" bitfield="true">
+ <entry name="top" value="1" summary="the top edge of the anchor rectangle"/>
+ <entry name="bottom" value="2" summary="the bottom edge of the anchor rectangle"/>
+ <entry name="left" value="4" summary="the left edge of the anchor rectangle"/>
+ <entry name="right" value="8" summary="the right edge of the anchor rectangle"/>
+ </enum>
+
+ <!-- Version 2 additions -->
+
+ <request name="set_layer" since="2">
+ <description summary="change the layer of the surface">
+ Change the layer that the surface is rendered on.
+
+ Layer is double-buffered, see wl_surface.commit.
+ </description>
+ <arg name="layer" type="uint" enum="zwlr_layer_shell_v1.layer" summary="layer to move this surface to"/>
+ </request>
+ </interface>
+</protocol>
diff --git a/dwlb/screenshot1.png b/dwlb/screenshot1.png
Binary files differ.
diff --git a/dwlb/screenshot2.png b/dwlb/screenshot2.png
Binary files differ.
diff --git a/dwlb/utf8.h b/dwlb/utf8.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
+// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+#include <stdint.h>
+
+#define UTF8_ACCEPT 0
+#define UTF8_REJECT 1
+
+static const uint8_t utf8d[] = {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
+ 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
+ 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
+ 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
+ 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
+ 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
+ 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
+ 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
+};
+
+static inline uint32_t
+utf8decode(uint32_t *state, uint32_t *codep, uint8_t byte)
+{
+ uint32_t type = utf8d[byte];
+
+ *codep = (*state != UTF8_ACCEPT) ?
+ (byte & 0x3fu) | (*codep << 6) :
+ (0xff >> type) & (byte);
+
+ *state = utf8d[256 + *state*16 + type];
+ return *state;
+}
diff --git a/dwlb/wlr-layer-shell-unstable-v1-protocol.c b/dwlb/wlr-layer-shell-unstable-v1-protocol.c
@@ -0,0 +1,93 @@
+/* Generated by wayland-scanner 1.22.0 */
+
+/*
+ * Copyright © 2017 Drew DeVault
+ *
+ * Permission to use, copy, modify, distribute, and sell this
+ * software and its documentation for any purpose is hereby granted
+ * without fee, provided that the above copyright notice appear in
+ * all copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * the copyright holders not be used in advertising or publicity
+ * pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+#ifndef __has_attribute
+# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
+#endif
+
+#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
+#define WL_PRIVATE __attribute__ ((visibility("hidden")))
+#else
+#define WL_PRIVATE
+#endif
+
+extern const struct wl_interface wl_output_interface;
+extern const struct wl_interface wl_surface_interface;
+extern const struct wl_interface xdg_popup_interface;
+extern const struct wl_interface zwlr_layer_surface_v1_interface;
+
+static const struct wl_interface *wlr_layer_shell_unstable_v1_types[] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &zwlr_layer_surface_v1_interface,
+ &wl_surface_interface,
+ &wl_output_interface,
+ NULL,
+ NULL,
+ &xdg_popup_interface,
+};
+
+static const struct wl_message zwlr_layer_shell_v1_requests[] = {
+ { "get_layer_surface", "no?ous", wlr_layer_shell_unstable_v1_types + 4 },
+ { "destroy", "3", wlr_layer_shell_unstable_v1_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface zwlr_layer_shell_v1_interface = {
+ "zwlr_layer_shell_v1", 4,
+ 2, zwlr_layer_shell_v1_requests,
+ 0, NULL,
+};
+
+static const struct wl_message zwlr_layer_surface_v1_requests[] = {
+ { "set_size", "uu", wlr_layer_shell_unstable_v1_types + 0 },
+ { "set_anchor", "u", wlr_layer_shell_unstable_v1_types + 0 },
+ { "set_exclusive_zone", "i", wlr_layer_shell_unstable_v1_types + 0 },
+ { "set_margin", "iiii", wlr_layer_shell_unstable_v1_types + 0 },
+ { "set_keyboard_interactivity", "u", wlr_layer_shell_unstable_v1_types + 0 },
+ { "get_popup", "o", wlr_layer_shell_unstable_v1_types + 9 },
+ { "ack_configure", "u", wlr_layer_shell_unstable_v1_types + 0 },
+ { "destroy", "", wlr_layer_shell_unstable_v1_types + 0 },
+ { "set_layer", "2u", wlr_layer_shell_unstable_v1_types + 0 },
+};
+
+static const struct wl_message zwlr_layer_surface_v1_events[] = {
+ { "configure", "uuu", wlr_layer_shell_unstable_v1_types + 0 },
+ { "closed", "", wlr_layer_shell_unstable_v1_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface zwlr_layer_surface_v1_interface = {
+ "zwlr_layer_surface_v1", 4,
+ 9, zwlr_layer_surface_v1_requests,
+ 2, zwlr_layer_surface_v1_events,
+};
+
diff --git a/dwlb/wlr-layer-shell-unstable-v1-protocol.h b/dwlb/wlr-layer-shell-unstable-v1-protocol.h
@@ -0,0 +1,706 @@
+/* Generated by wayland-scanner 1.22.0 */
+
+#ifndef WLR_LAYER_SHELL_UNSTABLE_V1_CLIENT_PROTOCOL_H
+#define WLR_LAYER_SHELL_UNSTABLE_V1_CLIENT_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @page page_wlr_layer_shell_unstable_v1 The wlr_layer_shell_unstable_v1 protocol
+ * @section page_ifaces_wlr_layer_shell_unstable_v1 Interfaces
+ * - @subpage page_iface_zwlr_layer_shell_v1 - create surfaces that are layers of the desktop
+ * - @subpage page_iface_zwlr_layer_surface_v1 - layer metadata interface
+ * @section page_copyright_wlr_layer_shell_unstable_v1 Copyright
+ * <pre>
+ *
+ * Copyright © 2017 Drew DeVault
+ *
+ * Permission to use, copy, modify, distribute, and sell this
+ * software and its documentation for any purpose is hereby granted
+ * without fee, provided that the above copyright notice appear in
+ * all copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * the copyright holders not be used in advertising or publicity
+ * pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ * </pre>
+ */
+struct wl_output;
+struct wl_surface;
+struct xdg_popup;
+struct zwlr_layer_shell_v1;
+struct zwlr_layer_surface_v1;
+
+#ifndef ZWLR_LAYER_SHELL_V1_INTERFACE
+#define ZWLR_LAYER_SHELL_V1_INTERFACE
+/**
+ * @page page_iface_zwlr_layer_shell_v1 zwlr_layer_shell_v1
+ * @section page_iface_zwlr_layer_shell_v1_desc Description
+ *
+ * Clients can use this interface to assign the surface_layer role to
+ * wl_surfaces. Such surfaces are assigned to a "layer" of the output and
+ * rendered with a defined z-depth respective to each other. They may also be
+ * anchored to the edges and corners of a screen and specify input handling
+ * semantics. This interface should be suitable for the implementation of
+ * many desktop shell components, and a broad number of other applications
+ * that interact with the desktop.
+ * @section page_iface_zwlr_layer_shell_v1_api API
+ * See @ref iface_zwlr_layer_shell_v1.
+ */
+/**
+ * @defgroup iface_zwlr_layer_shell_v1 The zwlr_layer_shell_v1 interface
+ *
+ * Clients can use this interface to assign the surface_layer role to
+ * wl_surfaces. Such surfaces are assigned to a "layer" of the output and
+ * rendered with a defined z-depth respective to each other. They may also be
+ * anchored to the edges and corners of a screen and specify input handling
+ * semantics. This interface should be suitable for the implementation of
+ * many desktop shell components, and a broad number of other applications
+ * that interact with the desktop.
+ */
+extern const struct wl_interface zwlr_layer_shell_v1_interface;
+#endif
+#ifndef ZWLR_LAYER_SURFACE_V1_INTERFACE
+#define ZWLR_LAYER_SURFACE_V1_INTERFACE
+/**
+ * @page page_iface_zwlr_layer_surface_v1 zwlr_layer_surface_v1
+ * @section page_iface_zwlr_layer_surface_v1_desc Description
+ *
+ * An interface that may be implemented by a wl_surface, for surfaces that
+ * are designed to be rendered as a layer of a stacked desktop-like
+ * environment.
+ *
+ * Layer surface state (layer, size, anchor, exclusive zone,
+ * margin, interactivity) is double-buffered, and will be applied at the
+ * time wl_surface.commit of the corresponding wl_surface is called.
+ *
+ * Attaching a null buffer to a layer surface unmaps it.
+ *
+ * Unmapping a layer_surface means that the surface cannot be shown by the
+ * compositor until it is explicitly mapped again. The layer_surface
+ * returns to the state it had right after layer_shell.get_layer_surface.
+ * The client can re-map the surface by performing a commit without any
+ * buffer attached, waiting for a configure event and handling it as usual.
+ * @section page_iface_zwlr_layer_surface_v1_api API
+ * See @ref iface_zwlr_layer_surface_v1.
+ */
+/**
+ * @defgroup iface_zwlr_layer_surface_v1 The zwlr_layer_surface_v1 interface
+ *
+ * An interface that may be implemented by a wl_surface, for surfaces that
+ * are designed to be rendered as a layer of a stacked desktop-like
+ * environment.
+ *
+ * Layer surface state (layer, size, anchor, exclusive zone,
+ * margin, interactivity) is double-buffered, and will be applied at the
+ * time wl_surface.commit of the corresponding wl_surface is called.
+ *
+ * Attaching a null buffer to a layer surface unmaps it.
+ *
+ * Unmapping a layer_surface means that the surface cannot be shown by the
+ * compositor until it is explicitly mapped again. The layer_surface
+ * returns to the state it had right after layer_shell.get_layer_surface.
+ * The client can re-map the surface by performing a commit without any
+ * buffer attached, waiting for a configure event and handling it as usual.
+ */
+extern const struct wl_interface zwlr_layer_surface_v1_interface;
+#endif
+
+#ifndef ZWLR_LAYER_SHELL_V1_ERROR_ENUM
+#define ZWLR_LAYER_SHELL_V1_ERROR_ENUM
+enum zwlr_layer_shell_v1_error {
+ /**
+ * wl_surface has another role
+ */
+ ZWLR_LAYER_SHELL_V1_ERROR_ROLE = 0,
+ /**
+ * layer value is invalid
+ */
+ ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER = 1,
+ /**
+ * wl_surface has a buffer attached or committed
+ */
+ ZWLR_LAYER_SHELL_V1_ERROR_ALREADY_CONSTRUCTED = 2,
+};
+#endif /* ZWLR_LAYER_SHELL_V1_ERROR_ENUM */
+
+#ifndef ZWLR_LAYER_SHELL_V1_LAYER_ENUM
+#define ZWLR_LAYER_SHELL_V1_LAYER_ENUM
+/**
+ * @ingroup iface_zwlr_layer_shell_v1
+ * available layers for surfaces
+ *
+ * These values indicate which layers a surface can be rendered in. They
+ * are ordered by z depth, bottom-most first. Traditional shell surfaces
+ * will typically be rendered between the bottom and top layers.
+ * Fullscreen shell surfaces are typically rendered at the top layer.
+ * Multiple surfaces can share a single layer, and ordering within a
+ * single layer is undefined.
+ */
+enum zwlr_layer_shell_v1_layer {
+ ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND = 0,
+ ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM = 1,
+ ZWLR_LAYER_SHELL_V1_LAYER_TOP = 2,
+ ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY = 3,
+};
+#endif /* ZWLR_LAYER_SHELL_V1_LAYER_ENUM */
+
+#define ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE 0
+#define ZWLR_LAYER_SHELL_V1_DESTROY 1
+
+
+/**
+ * @ingroup iface_zwlr_layer_shell_v1
+ */
+#define ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwlr_layer_shell_v1
+ */
+#define ZWLR_LAYER_SHELL_V1_DESTROY_SINCE_VERSION 3
+
+/** @ingroup iface_zwlr_layer_shell_v1 */
+static inline void
+zwlr_layer_shell_v1_set_user_data(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) zwlr_layer_shell_v1, user_data);
+}
+
+/** @ingroup iface_zwlr_layer_shell_v1 */
+static inline void *
+zwlr_layer_shell_v1_get_user_data(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) zwlr_layer_shell_v1);
+}
+
+static inline uint32_t
+zwlr_layer_shell_v1_get_version(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1)
+{
+ return wl_proxy_get_version((struct wl_proxy *) zwlr_layer_shell_v1);
+}
+
+/**
+ * @ingroup iface_zwlr_layer_shell_v1
+ *
+ * Create a layer surface for an existing surface. This assigns the role of
+ * layer_surface, or raises a protocol error if another role is already
+ * assigned.
+ *
+ * Creating a layer surface from a wl_surface which has a buffer attached
+ * or committed is a client error, and any attempts by a client to attach
+ * or manipulate a buffer prior to the first layer_surface.configure call
+ * must also be treated as errors.
+ *
+ * After creating a layer_surface object and setting it up, the client
+ * must perform an initial commit without any buffer attached.
+ * The compositor will reply with a layer_surface.configure event.
+ * The client must acknowledge it and is then allowed to attach a buffer
+ * to map the surface.
+ *
+ * You may pass NULL for output to allow the compositor to decide which
+ * output to use. Generally this will be the one that the user most
+ * recently interacted with.
+ *
+ * Clients can specify a namespace that defines the purpose of the layer
+ * surface.
+ */
+static inline struct zwlr_layer_surface_v1 *
+zwlr_layer_shell_v1_get_layer_surface(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1, struct wl_surface *surface, struct wl_output *output, uint32_t layer, const char *namespace)
+{
+ struct wl_proxy *id;
+
+ id = wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_shell_v1,
+ ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE, &zwlr_layer_surface_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_shell_v1), 0, NULL, surface, output, layer, namespace);
+
+ return (struct zwlr_layer_surface_v1 *) id;
+}
+
+/**
+ * @ingroup iface_zwlr_layer_shell_v1
+ *
+ * This request indicates that the client will not use the layer_shell
+ * object any more. Objects that have been created through this instance
+ * are not affected.
+ */
+static inline void
+zwlr_layer_shell_v1_destroy(struct zwlr_layer_shell_v1 *zwlr_layer_shell_v1)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_shell_v1,
+ ZWLR_LAYER_SHELL_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_shell_v1), WL_MARSHAL_FLAG_DESTROY);
+}
+
+#ifndef ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ENUM
+#define ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ENUM
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ * types of keyboard interaction possible for a layer shell surface
+ *
+ * Types of keyboard interaction possible for layer shell surfaces. The
+ * rationale for this is twofold: (1) some applications are not interested
+ * in keyboard events and not allowing them to be focused can improve the
+ * desktop experience; (2) some applications will want to take exclusive
+ * keyboard focus.
+ */
+enum zwlr_layer_surface_v1_keyboard_interactivity {
+ /**
+ * no keyboard focus is possible
+ *
+ * This value indicates that this surface is not interested in
+ * keyboard events and the compositor should never assign it the
+ * keyboard focus.
+ *
+ * This is the default value, set for newly created layer shell
+ * surfaces.
+ *
+ * This is useful for e.g. desktop widgets that display information
+ * or only have interaction with non-keyboard input devices.
+ */
+ ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE = 0,
+ /**
+ * request exclusive keyboard focus
+ *
+ * Request exclusive keyboard focus if this surface is above the
+ * shell surface layer.
+ *
+ * For the top and overlay layers, the seat will always give
+ * exclusive keyboard focus to the top-most layer which has
+ * keyboard interactivity set to exclusive. If this layer contains
+ * multiple surfaces with keyboard interactivity set to exclusive,
+ * the compositor determines the one receiving keyboard events in
+ * an implementation- defined manner. In this case, no guarantee is
+ * made when this surface will receive keyboard focus (if ever).
+ *
+ * For the bottom and background layers, the compositor is allowed
+ * to use normal focus semantics.
+ *
+ * This setting is mainly intended for applications that need to
+ * ensure they receive all keyboard events, such as a lock screen
+ * or a password prompt.
+ */
+ ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE = 1,
+ /**
+ * request regular keyboard focus semantics
+ *
+ * This requests the compositor to allow this surface to be
+ * focused and unfocused by the user in an implementation-defined
+ * manner. The user should be able to unfocus this surface even
+ * regardless of the layer it is on.
+ *
+ * Typically, the compositor will want to use its normal mechanism
+ * to manage keyboard focus between layer shell surfaces with this
+ * setting and regular toplevels on the desktop layer (e.g. click
+ * to focus). Nevertheless, it is possible for a compositor to
+ * require a special interaction to focus or unfocus layer shell
+ * surfaces (e.g. requiring a click even if focus follows the mouse
+ * normally, or providing a keybinding to switch focus between
+ * layers).
+ *
+ * This setting is mainly intended for desktop shell components
+ * (e.g. panels) that allow keyboard interaction. Using this option
+ * can allow implementing a desktop shell that can be fully usable
+ * without the mouse.
+ * @since 4
+ */
+ ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND = 2,
+};
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND_SINCE_VERSION 4
+#endif /* ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ENUM */
+
+#ifndef ZWLR_LAYER_SURFACE_V1_ERROR_ENUM
+#define ZWLR_LAYER_SURFACE_V1_ERROR_ENUM
+enum zwlr_layer_surface_v1_error {
+ /**
+ * provided surface state is invalid
+ */
+ ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SURFACE_STATE = 0,
+ /**
+ * size is invalid
+ */
+ ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SIZE = 1,
+ /**
+ * anchor bitfield is invalid
+ */
+ ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_ANCHOR = 2,
+ /**
+ * keyboard interactivity is invalid
+ */
+ ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_KEYBOARD_INTERACTIVITY = 3,
+};
+#endif /* ZWLR_LAYER_SURFACE_V1_ERROR_ENUM */
+
+#ifndef ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM
+#define ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM
+enum zwlr_layer_surface_v1_anchor {
+ /**
+ * the top edge of the anchor rectangle
+ */
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP = 1,
+ /**
+ * the bottom edge of the anchor rectangle
+ */
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM = 2,
+ /**
+ * the left edge of the anchor rectangle
+ */
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT = 4,
+ /**
+ * the right edge of the anchor rectangle
+ */
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT = 8,
+};
+#endif /* ZWLR_LAYER_SURFACE_V1_ANCHOR_ENUM */
+
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ * @struct zwlr_layer_surface_v1_listener
+ */
+struct zwlr_layer_surface_v1_listener {
+ /**
+ * suggest a surface change
+ *
+ * The configure event asks the client to resize its surface.
+ *
+ * Clients should arrange their surface for the new states, and
+ * then send an ack_configure request with the serial sent in this
+ * configure event at some point before committing the new surface.
+ *
+ * The client is free to dismiss all but the last configure event
+ * it received.
+ *
+ * The width and height arguments specify the size of the window in
+ * surface-local coordinates.
+ *
+ * The size is a hint, in the sense that the client is free to
+ * ignore it if it doesn't resize, pick a smaller size (to satisfy
+ * aspect ratio or resize in steps of NxM pixels). If the client
+ * picks a smaller size and is anchored to two opposite anchors
+ * (e.g. 'top' and 'bottom'), the surface will be centered on this
+ * axis.
+ *
+ * If the width or height arguments are zero, it means the client
+ * should decide its own window dimension.
+ */
+ void (*configure)(void *data,
+ struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1,
+ uint32_t serial,
+ uint32_t width,
+ uint32_t height);
+ /**
+ * surface should be closed
+ *
+ * The closed event is sent by the compositor when the surface
+ * will no longer be shown. The output may have been destroyed or
+ * the user may have asked for it to be removed. Further changes to
+ * the surface will be ignored. The client should destroy the
+ * resource after receiving this event, and create a new surface if
+ * they so choose.
+ */
+ void (*closed)(void *data,
+ struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1);
+};
+
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+static inline int
+zwlr_layer_surface_v1_add_listener(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1,
+ const struct zwlr_layer_surface_v1_listener *listener, void *data)
+{
+ return wl_proxy_add_listener((struct wl_proxy *) zwlr_layer_surface_v1,
+ (void (**)(void)) listener, data);
+}
+
+#define ZWLR_LAYER_SURFACE_V1_SET_SIZE 0
+#define ZWLR_LAYER_SURFACE_V1_SET_ANCHOR 1
+#define ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE 2
+#define ZWLR_LAYER_SURFACE_V1_SET_MARGIN 3
+#define ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY 4
+#define ZWLR_LAYER_SURFACE_V1_GET_POPUP 5
+#define ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE 6
+#define ZWLR_LAYER_SURFACE_V1_DESTROY 7
+#define ZWLR_LAYER_SURFACE_V1_SET_LAYER 8
+
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_CONFIGURE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_CLOSED_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_SET_SIZE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_SET_ANCHOR_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_SET_MARGIN_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_GET_POPUP_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ */
+#define ZWLR_LAYER_SURFACE_V1_SET_LAYER_SINCE_VERSION 2
+
+/** @ingroup iface_zwlr_layer_surface_v1 */
+static inline void
+zwlr_layer_surface_v1_set_user_data(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) zwlr_layer_surface_v1, user_data);
+}
+
+/** @ingroup iface_zwlr_layer_surface_v1 */
+static inline void *
+zwlr_layer_surface_v1_get_user_data(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) zwlr_layer_surface_v1);
+}
+
+static inline uint32_t
+zwlr_layer_surface_v1_get_version(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1)
+{
+ return wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1);
+}
+
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ *
+ * Sets the size of the surface in surface-local coordinates. The
+ * compositor will display the surface centered with respect to its
+ * anchors.
+ *
+ * If you pass 0 for either value, the compositor will assign it and
+ * inform you of the assignment in the configure event. You must set your
+ * anchor to opposite edges in the dimensions you omit; not doing so is a
+ * protocol error. Both values are 0 by default.
+ *
+ * Size is double-buffered, see wl_surface.commit.
+ */
+static inline void
+zwlr_layer_surface_v1_set_size(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t width, uint32_t height)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1,
+ ZWLR_LAYER_SURFACE_V1_SET_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, width, height);
+}
+
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ *
+ * Requests that the compositor anchor the surface to the specified edges
+ * and corners. If two orthogonal edges are specified (e.g. 'top' and
+ * 'left'), then the anchor point will be the intersection of the edges
+ * (e.g. the top left corner of the output); otherwise the anchor point
+ * will be centered on that edge, or in the center if none is specified.
+ *
+ * Anchor is double-buffered, see wl_surface.commit.
+ */
+static inline void
+zwlr_layer_surface_v1_set_anchor(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t anchor)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1,
+ ZWLR_LAYER_SURFACE_V1_SET_ANCHOR, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, anchor);
+}
+
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ *
+ * Requests that the compositor avoids occluding an area with other
+ * surfaces. The compositor's use of this information is
+ * implementation-dependent - do not assume that this region will not
+ * actually be occluded.
+ *
+ * A positive value is only meaningful if the surface is anchored to one
+ * edge or an edge and both perpendicular edges. If the surface is not
+ * anchored, anchored to only two perpendicular edges (a corner), anchored
+ * to only two parallel edges or anchored to all edges, a positive value
+ * will be treated the same as zero.
+ *
+ * A positive zone is the distance from the edge in surface-local
+ * coordinates to consider exclusive.
+ *
+ * Surfaces that do not wish to have an exclusive zone may instead specify
+ * how they should interact with surfaces that do. If set to zero, the
+ * surface indicates that it would like to be moved to avoid occluding
+ * surfaces with a positive exclusive zone. If set to -1, the surface
+ * indicates that it would not like to be moved to accommodate for other
+ * surfaces, and the compositor should extend it all the way to the edges
+ * it is anchored to.
+ *
+ * For example, a panel might set its exclusive zone to 10, so that
+ * maximized shell surfaces are not shown on top of it. A notification
+ * might set its exclusive zone to 0, so that it is moved to avoid
+ * occluding the panel, but shell surfaces are shown underneath it. A
+ * wallpaper or lock screen might set their exclusive zone to -1, so that
+ * they stretch below or over the panel.
+ *
+ * The default value is 0.
+ *
+ * Exclusive zone is double-buffered, see wl_surface.commit.
+ */
+static inline void
+zwlr_layer_surface_v1_set_exclusive_zone(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, int32_t zone)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1,
+ ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, zone);
+}
+
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ *
+ * Requests that the surface be placed some distance away from the anchor
+ * point on the output, in surface-local coordinates. Setting this value
+ * for edges you are not anchored to has no effect.
+ *
+ * The exclusive zone includes the margin.
+ *
+ * Margin is double-buffered, see wl_surface.commit.
+ */
+static inline void
+zwlr_layer_surface_v1_set_margin(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, int32_t top, int32_t right, int32_t bottom, int32_t left)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1,
+ ZWLR_LAYER_SURFACE_V1_SET_MARGIN, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, top, right, bottom, left);
+}
+
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ *
+ * Set how keyboard events are delivered to this surface. By default,
+ * layer shell surfaces do not receive keyboard events; this request can
+ * be used to change this.
+ *
+ * This setting is inherited by child surfaces set by the get_popup
+ * request.
+ *
+ * Layer surfaces receive pointer, touch, and tablet events normally. If
+ * you do not want to receive them, set the input region on your surface
+ * to an empty region.
+ *
+ * Keyboard interactivity is double-buffered, see wl_surface.commit.
+ */
+static inline void
+zwlr_layer_surface_v1_set_keyboard_interactivity(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t keyboard_interactivity)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1,
+ ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, keyboard_interactivity);
+}
+
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ *
+ * This assigns an xdg_popup's parent to this layer_surface. This popup
+ * should have been created via xdg_surface::get_popup with the parent set
+ * to NULL, and this request must be invoked before committing the popup's
+ * initial state.
+ *
+ * See the documentation of xdg_popup for more details about what an
+ * xdg_popup is and how it is used.
+ */
+static inline void
+zwlr_layer_surface_v1_get_popup(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, struct xdg_popup *popup)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1,
+ ZWLR_LAYER_SURFACE_V1_GET_POPUP, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, popup);
+}
+
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ *
+ * When a configure event is received, if a client commits the
+ * surface in response to the configure event, then the client
+ * must make an ack_configure request sometime before the commit
+ * request, passing along the serial of the configure event.
+ *
+ * If the client receives multiple configure events before it
+ * can respond to one, it only has to ack the last configure event.
+ *
+ * A client is not required to commit immediately after sending
+ * an ack_configure request - it may even ack_configure several times
+ * before its next surface commit.
+ *
+ * A client may send multiple ack_configure requests before committing, but
+ * only the last request sent before a commit indicates which configure
+ * event the client really is responding to.
+ */
+static inline void
+zwlr_layer_surface_v1_ack_configure(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t serial)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1,
+ ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, serial);
+}
+
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ *
+ * This request destroys the layer surface.
+ */
+static inline void
+zwlr_layer_surface_v1_destroy(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1,
+ ZWLR_LAYER_SURFACE_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_zwlr_layer_surface_v1
+ *
+ * Change the layer that the surface is rendered on.
+ *
+ * Layer is double-buffered, see wl_surface.commit.
+ */
+static inline void
+zwlr_layer_surface_v1_set_layer(struct zwlr_layer_surface_v1 *zwlr_layer_surface_v1, uint32_t layer)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwlr_layer_surface_v1,
+ ZWLR_LAYER_SURFACE_V1_SET_LAYER, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_layer_surface_v1), 0, layer);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/dwlb/xdg-output-unstable-v1-protocol.c b/dwlb/xdg-output-unstable-v1-protocol.c
@@ -0,0 +1,78 @@
+/* Generated by wayland-scanner 1.22.0 */
+
+/*
+ * Copyright © 2017 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+#ifndef __has_attribute
+# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
+#endif
+
+#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
+#define WL_PRIVATE __attribute__ ((visibility("hidden")))
+#else
+#define WL_PRIVATE
+#endif
+
+extern const struct wl_interface wl_output_interface;
+extern const struct wl_interface zxdg_output_v1_interface;
+
+static const struct wl_interface *xdg_output_unstable_v1_types[] = {
+ NULL,
+ NULL,
+ &zxdg_output_v1_interface,
+ &wl_output_interface,
+};
+
+static const struct wl_message zxdg_output_manager_v1_requests[] = {
+ { "destroy", "", xdg_output_unstable_v1_types + 0 },
+ { "get_xdg_output", "no", xdg_output_unstable_v1_types + 2 },
+};
+
+WL_PRIVATE const struct wl_interface zxdg_output_manager_v1_interface = {
+ "zxdg_output_manager_v1", 3,
+ 2, zxdg_output_manager_v1_requests,
+ 0, NULL,
+};
+
+static const struct wl_message zxdg_output_v1_requests[] = {
+ { "destroy", "", xdg_output_unstable_v1_types + 0 },
+};
+
+static const struct wl_message zxdg_output_v1_events[] = {
+ { "logical_position", "ii", xdg_output_unstable_v1_types + 0 },
+ { "logical_size", "ii", xdg_output_unstable_v1_types + 0 },
+ { "done", "", xdg_output_unstable_v1_types + 0 },
+ { "name", "2s", xdg_output_unstable_v1_types + 0 },
+ { "description", "2s", xdg_output_unstable_v1_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface zxdg_output_v1_interface = {
+ "zxdg_output_v1", 3,
+ 1, zxdg_output_v1_requests,
+ 5, zxdg_output_v1_events,
+};
+
diff --git a/dwlb/xdg-output-unstable-v1-protocol.h b/dwlb/xdg-output-unstable-v1-protocol.h
@@ -0,0 +1,414 @@
+/* Generated by wayland-scanner 1.22.0 */
+
+#ifndef XDG_OUTPUT_UNSTABLE_V1_CLIENT_PROTOCOL_H
+#define XDG_OUTPUT_UNSTABLE_V1_CLIENT_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @page page_xdg_output_unstable_v1 The xdg_output_unstable_v1 protocol
+ * Protocol to describe output regions
+ *
+ * @section page_desc_xdg_output_unstable_v1 Description
+ *
+ * This protocol aims at describing outputs in a way which is more in line
+ * with the concept of an output on desktop oriented systems.
+ *
+ * Some information are more specific to the concept of an output for
+ * a desktop oriented system and may not make sense in other applications,
+ * such as IVI systems for example.
+ *
+ * Typically, the global compositor space on a desktop system is made of
+ * a contiguous or overlapping set of rectangular regions.
+ *
+ * The logical_position and logical_size events defined in this protocol
+ * might provide information identical to their counterparts already
+ * available from wl_output, in which case the information provided by this
+ * protocol should be preferred to their equivalent in wl_output. The goal is
+ * to move the desktop specific concepts (such as output location within the
+ * global compositor space, etc.) out of the core wl_output protocol.
+ *
+ * Warning! The protocol described in this file is experimental and
+ * backward incompatible changes may be made. Backward compatible
+ * changes may be added together with the corresponding interface
+ * version bump.
+ * Backward incompatible changes are done by bumping the version
+ * number in the protocol and interface names and resetting the
+ * interface version. Once the protocol is to be declared stable,
+ * the 'z' prefix and the version number in the protocol and
+ * interface names are removed and the interface version number is
+ * reset.
+ *
+ * @section page_ifaces_xdg_output_unstable_v1 Interfaces
+ * - @subpage page_iface_zxdg_output_manager_v1 - manage xdg_output objects
+ * - @subpage page_iface_zxdg_output_v1 - compositor logical output region
+ * @section page_copyright_xdg_output_unstable_v1 Copyright
+ * <pre>
+ *
+ * Copyright © 2017 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * </pre>
+ */
+struct wl_output;
+struct zxdg_output_manager_v1;
+struct zxdg_output_v1;
+
+#ifndef ZXDG_OUTPUT_MANAGER_V1_INTERFACE
+#define ZXDG_OUTPUT_MANAGER_V1_INTERFACE
+/**
+ * @page page_iface_zxdg_output_manager_v1 zxdg_output_manager_v1
+ * @section page_iface_zxdg_output_manager_v1_desc Description
+ *
+ * A global factory interface for xdg_output objects.
+ * @section page_iface_zxdg_output_manager_v1_api API
+ * See @ref iface_zxdg_output_manager_v1.
+ */
+/**
+ * @defgroup iface_zxdg_output_manager_v1 The zxdg_output_manager_v1 interface
+ *
+ * A global factory interface for xdg_output objects.
+ */
+extern const struct wl_interface zxdg_output_manager_v1_interface;
+#endif
+#ifndef ZXDG_OUTPUT_V1_INTERFACE
+#define ZXDG_OUTPUT_V1_INTERFACE
+/**
+ * @page page_iface_zxdg_output_v1 zxdg_output_v1
+ * @section page_iface_zxdg_output_v1_desc Description
+ *
+ * An xdg_output describes part of the compositor geometry.
+ *
+ * This typically corresponds to a monitor that displays part of the
+ * compositor space.
+ *
+ * For objects version 3 onwards, after all xdg_output properties have been
+ * sent (when the object is created and when properties are updated), a
+ * wl_output.done event is sent. This allows changes to the output
+ * properties to be seen as atomic, even if they happen via multiple events.
+ * @section page_iface_zxdg_output_v1_api API
+ * See @ref iface_zxdg_output_v1.
+ */
+/**
+ * @defgroup iface_zxdg_output_v1 The zxdg_output_v1 interface
+ *
+ * An xdg_output describes part of the compositor geometry.
+ *
+ * This typically corresponds to a monitor that displays part of the
+ * compositor space.
+ *
+ * For objects version 3 onwards, after all xdg_output properties have been
+ * sent (when the object is created and when properties are updated), a
+ * wl_output.done event is sent. This allows changes to the output
+ * properties to be seen as atomic, even if they happen via multiple events.
+ */
+extern const struct wl_interface zxdg_output_v1_interface;
+#endif
+
+#define ZXDG_OUTPUT_MANAGER_V1_DESTROY 0
+#define ZXDG_OUTPUT_MANAGER_V1_GET_XDG_OUTPUT 1
+
+
+/**
+ * @ingroup iface_zxdg_output_manager_v1
+ */
+#define ZXDG_OUTPUT_MANAGER_V1_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zxdg_output_manager_v1
+ */
+#define ZXDG_OUTPUT_MANAGER_V1_GET_XDG_OUTPUT_SINCE_VERSION 1
+
+/** @ingroup iface_zxdg_output_manager_v1 */
+static inline void
+zxdg_output_manager_v1_set_user_data(struct zxdg_output_manager_v1 *zxdg_output_manager_v1, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) zxdg_output_manager_v1, user_data);
+}
+
+/** @ingroup iface_zxdg_output_manager_v1 */
+static inline void *
+zxdg_output_manager_v1_get_user_data(struct zxdg_output_manager_v1 *zxdg_output_manager_v1)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) zxdg_output_manager_v1);
+}
+
+static inline uint32_t
+zxdg_output_manager_v1_get_version(struct zxdg_output_manager_v1 *zxdg_output_manager_v1)
+{
+ return wl_proxy_get_version((struct wl_proxy *) zxdg_output_manager_v1);
+}
+
+/**
+ * @ingroup iface_zxdg_output_manager_v1
+ *
+ * Using this request a client can tell the server that it is not
+ * going to use the xdg_output_manager object anymore.
+ *
+ * Any objects already created through this instance are not affected.
+ */
+static inline void
+zxdg_output_manager_v1_destroy(struct zxdg_output_manager_v1 *zxdg_output_manager_v1)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zxdg_output_manager_v1,
+ ZXDG_OUTPUT_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_output_manager_v1), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_zxdg_output_manager_v1
+ *
+ * This creates a new xdg_output object for the given wl_output.
+ */
+static inline struct zxdg_output_v1 *
+zxdg_output_manager_v1_get_xdg_output(struct zxdg_output_manager_v1 *zxdg_output_manager_v1, struct wl_output *output)
+{
+ struct wl_proxy *id;
+
+ id = wl_proxy_marshal_flags((struct wl_proxy *) zxdg_output_manager_v1,
+ ZXDG_OUTPUT_MANAGER_V1_GET_XDG_OUTPUT, &zxdg_output_v1_interface, wl_proxy_get_version((struct wl_proxy *) zxdg_output_manager_v1), 0, NULL, output);
+
+ return (struct zxdg_output_v1 *) id;
+}
+
+/**
+ * @ingroup iface_zxdg_output_v1
+ * @struct zxdg_output_v1_listener
+ */
+struct zxdg_output_v1_listener {
+ /**
+ * position of the output within the global compositor space
+ *
+ * The position event describes the location of the wl_output
+ * within the global compositor space.
+ *
+ * The logical_position event is sent after creating an xdg_output
+ * (see xdg_output_manager.get_xdg_output) and whenever the
+ * location of the output changes within the global compositor
+ * space.
+ * @param x x position within the global compositor space
+ * @param y y position within the global compositor space
+ */
+ void (*logical_position)(void *data,
+ struct zxdg_output_v1 *zxdg_output_v1,
+ int32_t x,
+ int32_t y);
+ /**
+ * size of the output in the global compositor space
+ *
+ * The logical_size event describes the size of the output in the
+ * global compositor space.
+ *
+ * Most regular Wayland clients should not pay attention to the
+ * logical size and would rather rely on xdg_shell interfaces.
+ *
+ * Some clients such as Xwayland, however, need this to configure
+ * their surfaces in the global compositor space as the compositor
+ * may apply a different scale from what is advertised by the
+ * output scaling property (to achieve fractional scaling, for
+ * example).
+ *
+ * For example, for a wl_output mode 3840×2160 and a scale factor
+ * 2:
+ *
+ * - A compositor not scaling the monitor viewport in its
+ * compositing space will advertise a logical size of 3840×2160,
+ *
+ * - A compositor scaling the monitor viewport with scale factor 2
+ * will advertise a logical size of 1920×1080,
+ *
+ * - A compositor scaling the monitor viewport using a fractional
+ * scale of 1.5 will advertise a logical size of 2560×1440.
+ *
+ * For example, for a wl_output mode 1920×1080 and a 90 degree
+ * rotation, the compositor will advertise a logical size of
+ * 1080x1920.
+ *
+ * The logical_size event is sent after creating an xdg_output (see
+ * xdg_output_manager.get_xdg_output) and whenever the logical size
+ * of the output changes, either as a result of a change in the
+ * applied scale or because of a change in the corresponding output
+ * mode(see wl_output.mode) or transform (see wl_output.transform).
+ * @param width width in global compositor space
+ * @param height height in global compositor space
+ */
+ void (*logical_size)(void *data,
+ struct zxdg_output_v1 *zxdg_output_v1,
+ int32_t width,
+ int32_t height);
+ /**
+ * all information about the output have been sent
+ *
+ * This event is sent after all other properties of an xdg_output
+ * have been sent.
+ *
+ * This allows changes to the xdg_output properties to be seen as
+ * atomic, even if they happen via multiple events.
+ *
+ * For objects version 3 onwards, this event is deprecated.
+ * Compositors are not required to send it anymore and must send
+ * wl_output.done instead.
+ */
+ void (*done)(void *data,
+ struct zxdg_output_v1 *zxdg_output_v1);
+ /**
+ * name of this output
+ *
+ * Many compositors will assign names to their outputs, show them
+ * to the user, allow them to be configured by name, etc. The
+ * client may wish to know this name as well to offer the user
+ * similar behaviors.
+ *
+ * The naming convention is compositor defined, but limited to
+ * alphanumeric characters and dashes (-). Each name is unique
+ * among all wl_output globals, but if a wl_output global is
+ * destroyed the same name may be reused later. The names will also
+ * remain consistent across sessions with the same hardware and
+ * software configuration.
+ *
+ * Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc.
+ * However, do not assume that the name is a reflection of an
+ * underlying DRM connector, X11 connection, etc.
+ *
+ * The name event is sent after creating an xdg_output (see
+ * xdg_output_manager.get_xdg_output). This event is only sent once
+ * per xdg_output, and the name does not change over the lifetime
+ * of the wl_output global.
+ *
+ * This event is deprecated, instead clients should use
+ * wl_output.name. Compositors must still support this event.
+ * @param name output name
+ * @since 2
+ */
+ void (*name)(void *data,
+ struct zxdg_output_v1 *zxdg_output_v1,
+ const char *name);
+ /**
+ * human-readable description of this output
+ *
+ * Many compositors can produce human-readable descriptions of
+ * their outputs. The client may wish to know this description as
+ * well, to communicate the user for various purposes.
+ *
+ * The description is a UTF-8 string with no convention defined for
+ * its contents. Examples might include 'Foocorp 11" Display' or
+ * 'Virtual X11 output via :1'.
+ *
+ * The description event is sent after creating an xdg_output (see
+ * xdg_output_manager.get_xdg_output) and whenever the description
+ * changes. The description is optional, and may not be sent at
+ * all.
+ *
+ * For objects of version 2 and lower, this event is only sent once
+ * per xdg_output, and the description does not change over the
+ * lifetime of the wl_output global.
+ *
+ * This event is deprecated, instead clients should use
+ * wl_output.description. Compositors must still support this
+ * event.
+ * @param description output description
+ * @since 2
+ */
+ void (*description)(void *data,
+ struct zxdg_output_v1 *zxdg_output_v1,
+ const char *description);
+};
+
+/**
+ * @ingroup iface_zxdg_output_v1
+ */
+static inline int
+zxdg_output_v1_add_listener(struct zxdg_output_v1 *zxdg_output_v1,
+ const struct zxdg_output_v1_listener *listener, void *data)
+{
+ return wl_proxy_add_listener((struct wl_proxy *) zxdg_output_v1,
+ (void (**)(void)) listener, data);
+}
+
+#define ZXDG_OUTPUT_V1_DESTROY 0
+
+/**
+ * @ingroup iface_zxdg_output_v1
+ */
+#define ZXDG_OUTPUT_V1_LOGICAL_POSITION_SINCE_VERSION 1
+/**
+ * @ingroup iface_zxdg_output_v1
+ */
+#define ZXDG_OUTPUT_V1_LOGICAL_SIZE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zxdg_output_v1
+ */
+#define ZXDG_OUTPUT_V1_DONE_SINCE_VERSION 1
+/**
+ * @ingroup iface_zxdg_output_v1
+ */
+#define ZXDG_OUTPUT_V1_NAME_SINCE_VERSION 2
+/**
+ * @ingroup iface_zxdg_output_v1
+ */
+#define ZXDG_OUTPUT_V1_DESCRIPTION_SINCE_VERSION 2
+
+/**
+ * @ingroup iface_zxdg_output_v1
+ */
+#define ZXDG_OUTPUT_V1_DESTROY_SINCE_VERSION 1
+
+/** @ingroup iface_zxdg_output_v1 */
+static inline void
+zxdg_output_v1_set_user_data(struct zxdg_output_v1 *zxdg_output_v1, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) zxdg_output_v1, user_data);
+}
+
+/** @ingroup iface_zxdg_output_v1 */
+static inline void *
+zxdg_output_v1_get_user_data(struct zxdg_output_v1 *zxdg_output_v1)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) zxdg_output_v1);
+}
+
+static inline uint32_t
+zxdg_output_v1_get_version(struct zxdg_output_v1 *zxdg_output_v1)
+{
+ return wl_proxy_get_version((struct wl_proxy *) zxdg_output_v1);
+}
+
+/**
+ * @ingroup iface_zxdg_output_v1
+ *
+ * Using this request a client can tell the server that it is not
+ * going to use the xdg_output object anymore.
+ */
+static inline void
+zxdg_output_v1_destroy(struct zxdg_output_v1 *zxdg_output_v1)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zxdg_output_v1,
+ ZXDG_OUTPUT_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_output_v1), WL_MARSHAL_FLAG_DESTROY);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/dwlb/xdg-shell-protocol.c b/dwlb/xdg-shell-protocol.c
@@ -0,0 +1,183 @@
+/* Generated by wayland-scanner 1.22.0 */
+
+/*
+ * Copyright © 2008-2013 Kristian Høgsberg
+ * Copyright © 2013 Rafael Antognolli
+ * Copyright © 2013 Jasper St. Pierre
+ * Copyright © 2010-2013 Intel Corporation
+ * Copyright © 2015-2017 Samsung Electronics Co., Ltd
+ * Copyright © 2015-2017 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+#ifndef __has_attribute
+# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
+#endif
+
+#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
+#define WL_PRIVATE __attribute__ ((visibility("hidden")))
+#else
+#define WL_PRIVATE
+#endif
+
+extern const struct wl_interface wl_output_interface;
+extern const struct wl_interface wl_seat_interface;
+extern const struct wl_interface wl_surface_interface;
+extern const struct wl_interface xdg_popup_interface;
+extern const struct wl_interface xdg_positioner_interface;
+extern const struct wl_interface xdg_surface_interface;
+extern const struct wl_interface xdg_toplevel_interface;
+
+static const struct wl_interface *xdg_shell_types[] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &xdg_positioner_interface,
+ &xdg_surface_interface,
+ &wl_surface_interface,
+ &xdg_toplevel_interface,
+ &xdg_popup_interface,
+ &xdg_surface_interface,
+ &xdg_positioner_interface,
+ &xdg_toplevel_interface,
+ &wl_seat_interface,
+ NULL,
+ NULL,
+ NULL,
+ &wl_seat_interface,
+ NULL,
+ &wl_seat_interface,
+ NULL,
+ NULL,
+ &wl_output_interface,
+ &wl_seat_interface,
+ NULL,
+ &xdg_positioner_interface,
+ NULL,
+};
+
+static const struct wl_message xdg_wm_base_requests[] = {
+ { "destroy", "", xdg_shell_types + 0 },
+ { "create_positioner", "n", xdg_shell_types + 4 },
+ { "get_xdg_surface", "no", xdg_shell_types + 5 },
+ { "pong", "u", xdg_shell_types + 0 },
+};
+
+static const struct wl_message xdg_wm_base_events[] = {
+ { "ping", "u", xdg_shell_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface xdg_wm_base_interface = {
+ "xdg_wm_base", 6,
+ 4, xdg_wm_base_requests,
+ 1, xdg_wm_base_events,
+};
+
+static const struct wl_message xdg_positioner_requests[] = {
+ { "destroy", "", xdg_shell_types + 0 },
+ { "set_size", "ii", xdg_shell_types + 0 },
+ { "set_anchor_rect", "iiii", xdg_shell_types + 0 },
+ { "set_anchor", "u", xdg_shell_types + 0 },
+ { "set_gravity", "u", xdg_shell_types + 0 },
+ { "set_constraint_adjustment", "u", xdg_shell_types + 0 },
+ { "set_offset", "ii", xdg_shell_types + 0 },
+ { "set_reactive", "3", xdg_shell_types + 0 },
+ { "set_parent_size", "3ii", xdg_shell_types + 0 },
+ { "set_parent_configure", "3u", xdg_shell_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface xdg_positioner_interface = {
+ "xdg_positioner", 6,
+ 10, xdg_positioner_requests,
+ 0, NULL,
+};
+
+static const struct wl_message xdg_surface_requests[] = {
+ { "destroy", "", xdg_shell_types + 0 },
+ { "get_toplevel", "n", xdg_shell_types + 7 },
+ { "get_popup", "n?oo", xdg_shell_types + 8 },
+ { "set_window_geometry", "iiii", xdg_shell_types + 0 },
+ { "ack_configure", "u", xdg_shell_types + 0 },
+};
+
+static const struct wl_message xdg_surface_events[] = {
+ { "configure", "u", xdg_shell_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface xdg_surface_interface = {
+ "xdg_surface", 6,
+ 5, xdg_surface_requests,
+ 1, xdg_surface_events,
+};
+
+static const struct wl_message xdg_toplevel_requests[] = {
+ { "destroy", "", xdg_shell_types + 0 },
+ { "set_parent", "?o", xdg_shell_types + 11 },
+ { "set_title", "s", xdg_shell_types + 0 },
+ { "set_app_id", "s", xdg_shell_types + 0 },
+ { "show_window_menu", "ouii", xdg_shell_types + 12 },
+ { "move", "ou", xdg_shell_types + 16 },
+ { "resize", "ouu", xdg_shell_types + 18 },
+ { "set_max_size", "ii", xdg_shell_types + 0 },
+ { "set_min_size", "ii", xdg_shell_types + 0 },
+ { "set_maximized", "", xdg_shell_types + 0 },
+ { "unset_maximized", "", xdg_shell_types + 0 },
+ { "set_fullscreen", "?o", xdg_shell_types + 21 },
+ { "unset_fullscreen", "", xdg_shell_types + 0 },
+ { "set_minimized", "", xdg_shell_types + 0 },
+};
+
+static const struct wl_message xdg_toplevel_events[] = {
+ { "configure", "iia", xdg_shell_types + 0 },
+ { "close", "", xdg_shell_types + 0 },
+ { "configure_bounds", "4ii", xdg_shell_types + 0 },
+ { "wm_capabilities", "5a", xdg_shell_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface xdg_toplevel_interface = {
+ "xdg_toplevel", 6,
+ 14, xdg_toplevel_requests,
+ 4, xdg_toplevel_events,
+};
+
+static const struct wl_message xdg_popup_requests[] = {
+ { "destroy", "", xdg_shell_types + 0 },
+ { "grab", "ou", xdg_shell_types + 22 },
+ { "reposition", "3ou", xdg_shell_types + 24 },
+};
+
+static const struct wl_message xdg_popup_events[] = {
+ { "configure", "iiii", xdg_shell_types + 0 },
+ { "popup_done", "", xdg_shell_types + 0 },
+ { "repositioned", "3u", xdg_shell_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface xdg_popup_interface = {
+ "xdg_popup", 6,
+ 3, xdg_popup_requests,
+ 3, xdg_popup_events,
+};
+
diff --git a/dwlb/xdg-shell-protocol.h b/dwlb/xdg-shell-protocol.h
@@ -0,0 +1,2315 @@
+/* Generated by wayland-scanner 1.22.0 */
+
+#ifndef XDG_SHELL_CLIENT_PROTOCOL_H
+#define XDG_SHELL_CLIENT_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @page page_xdg_shell The xdg_shell protocol
+ * @section page_ifaces_xdg_shell Interfaces
+ * - @subpage page_iface_xdg_wm_base - create desktop-style surfaces
+ * - @subpage page_iface_xdg_positioner - child surface positioner
+ * - @subpage page_iface_xdg_surface - desktop user interface surface base interface
+ * - @subpage page_iface_xdg_toplevel - toplevel surface
+ * - @subpage page_iface_xdg_popup - short-lived, popup surfaces for menus
+ * @section page_copyright_xdg_shell Copyright
+ * <pre>
+ *
+ * Copyright © 2008-2013 Kristian Høgsberg
+ * Copyright © 2013 Rafael Antognolli
+ * Copyright © 2013 Jasper St. Pierre
+ * Copyright © 2010-2013 Intel Corporation
+ * Copyright © 2015-2017 Samsung Electronics Co., Ltd
+ * Copyright © 2015-2017 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * </pre>
+ */
+struct wl_output;
+struct wl_seat;
+struct wl_surface;
+struct xdg_popup;
+struct xdg_positioner;
+struct xdg_surface;
+struct xdg_toplevel;
+struct xdg_wm_base;
+
+#ifndef XDG_WM_BASE_INTERFACE
+#define XDG_WM_BASE_INTERFACE
+/**
+ * @page page_iface_xdg_wm_base xdg_wm_base
+ * @section page_iface_xdg_wm_base_desc Description
+ *
+ * The xdg_wm_base interface is exposed as a global object enabling clients
+ * to turn their wl_surfaces into windows in a desktop environment. It
+ * defines the basic functionality needed for clients and the compositor to
+ * create windows that can be dragged, resized, maximized, etc, as well as
+ * creating transient windows such as popup menus.
+ * @section page_iface_xdg_wm_base_api API
+ * See @ref iface_xdg_wm_base.
+ */
+/**
+ * @defgroup iface_xdg_wm_base The xdg_wm_base interface
+ *
+ * The xdg_wm_base interface is exposed as a global object enabling clients
+ * to turn their wl_surfaces into windows in a desktop environment. It
+ * defines the basic functionality needed for clients and the compositor to
+ * create windows that can be dragged, resized, maximized, etc, as well as
+ * creating transient windows such as popup menus.
+ */
+extern const struct wl_interface xdg_wm_base_interface;
+#endif
+#ifndef XDG_POSITIONER_INTERFACE
+#define XDG_POSITIONER_INTERFACE
+/**
+ * @page page_iface_xdg_positioner xdg_positioner
+ * @section page_iface_xdg_positioner_desc Description
+ *
+ * The xdg_positioner provides a collection of rules for the placement of a
+ * child surface relative to a parent surface. Rules can be defined to ensure
+ * the child surface remains within the visible area's borders, and to
+ * specify how the child surface changes its position, such as sliding along
+ * an axis, or flipping around a rectangle. These positioner-created rules are
+ * constrained by the requirement that a child surface must intersect with or
+ * be at least partially adjacent to its parent surface.
+ *
+ * See the various requests for details about possible rules.
+ *
+ * At the time of the request, the compositor makes a copy of the rules
+ * specified by the xdg_positioner. Thus, after the request is complete the
+ * xdg_positioner object can be destroyed or reused; further changes to the
+ * object will have no effect on previous usages.
+ *
+ * For an xdg_positioner object to be considered complete, it must have a
+ * non-zero size set by set_size, and a non-zero anchor rectangle set by
+ * set_anchor_rect. Passing an incomplete xdg_positioner object when
+ * positioning a surface raises an invalid_positioner error.
+ * @section page_iface_xdg_positioner_api API
+ * See @ref iface_xdg_positioner.
+ */
+/**
+ * @defgroup iface_xdg_positioner The xdg_positioner interface
+ *
+ * The xdg_positioner provides a collection of rules for the placement of a
+ * child surface relative to a parent surface. Rules can be defined to ensure
+ * the child surface remains within the visible area's borders, and to
+ * specify how the child surface changes its position, such as sliding along
+ * an axis, or flipping around a rectangle. These positioner-created rules are
+ * constrained by the requirement that a child surface must intersect with or
+ * be at least partially adjacent to its parent surface.
+ *
+ * See the various requests for details about possible rules.
+ *
+ * At the time of the request, the compositor makes a copy of the rules
+ * specified by the xdg_positioner. Thus, after the request is complete the
+ * xdg_positioner object can be destroyed or reused; further changes to the
+ * object will have no effect on previous usages.
+ *
+ * For an xdg_positioner object to be considered complete, it must have a
+ * non-zero size set by set_size, and a non-zero anchor rectangle set by
+ * set_anchor_rect. Passing an incomplete xdg_positioner object when
+ * positioning a surface raises an invalid_positioner error.
+ */
+extern const struct wl_interface xdg_positioner_interface;
+#endif
+#ifndef XDG_SURFACE_INTERFACE
+#define XDG_SURFACE_INTERFACE
+/**
+ * @page page_iface_xdg_surface xdg_surface
+ * @section page_iface_xdg_surface_desc Description
+ *
+ * An interface that may be implemented by a wl_surface, for
+ * implementations that provide a desktop-style user interface.
+ *
+ * It provides a base set of functionality required to construct user
+ * interface elements requiring management by the compositor, such as
+ * toplevel windows, menus, etc. The types of functionality are split into
+ * xdg_surface roles.
+ *
+ * Creating an xdg_surface does not set the role for a wl_surface. In order
+ * to map an xdg_surface, the client must create a role-specific object
+ * using, e.g., get_toplevel, get_popup. The wl_surface for any given
+ * xdg_surface can have at most one role, and may not be assigned any role
+ * not based on xdg_surface.
+ *
+ * A role must be assigned before any other requests are made to the
+ * xdg_surface object.
+ *
+ * The client must call wl_surface.commit on the corresponding wl_surface
+ * for the xdg_surface state to take effect.
+ *
+ * Creating an xdg_surface from a wl_surface which has a buffer attached or
+ * committed is a client error, and any attempts by a client to attach or
+ * manipulate a buffer prior to the first xdg_surface.configure call must
+ * also be treated as errors.
+ *
+ * After creating a role-specific object and setting it up, the client must
+ * perform an initial commit without any buffer attached. The compositor
+ * will reply with initial wl_surface state such as
+ * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure
+ * event. The client must acknowledge it and is then allowed to attach a
+ * buffer to map the surface.
+ *
+ * Mapping an xdg_surface-based role surface is defined as making it
+ * possible for the surface to be shown by the compositor. Note that
+ * a mapped surface is not guaranteed to be visible once it is mapped.
+ *
+ * For an xdg_surface to be mapped by the compositor, the following
+ * conditions must be met:
+ * (1) the client has assigned an xdg_surface-based role to the surface
+ * (2) the client has set and committed the xdg_surface state and the
+ * role-dependent state to the surface
+ * (3) the client has committed a buffer to the surface
+ *
+ * A newly-unmapped surface is considered to have met condition (1) out
+ * of the 3 required conditions for mapping a surface if its role surface
+ * has not been destroyed, i.e. the client must perform the initial commit
+ * again before attaching a buffer.
+ * @section page_iface_xdg_surface_api API
+ * See @ref iface_xdg_surface.
+ */
+/**
+ * @defgroup iface_xdg_surface The xdg_surface interface
+ *
+ * An interface that may be implemented by a wl_surface, for
+ * implementations that provide a desktop-style user interface.
+ *
+ * It provides a base set of functionality required to construct user
+ * interface elements requiring management by the compositor, such as
+ * toplevel windows, menus, etc. The types of functionality are split into
+ * xdg_surface roles.
+ *
+ * Creating an xdg_surface does not set the role for a wl_surface. In order
+ * to map an xdg_surface, the client must create a role-specific object
+ * using, e.g., get_toplevel, get_popup. The wl_surface for any given
+ * xdg_surface can have at most one role, and may not be assigned any role
+ * not based on xdg_surface.
+ *
+ * A role must be assigned before any other requests are made to the
+ * xdg_surface object.
+ *
+ * The client must call wl_surface.commit on the corresponding wl_surface
+ * for the xdg_surface state to take effect.
+ *
+ * Creating an xdg_surface from a wl_surface which has a buffer attached or
+ * committed is a client error, and any attempts by a client to attach or
+ * manipulate a buffer prior to the first xdg_surface.configure call must
+ * also be treated as errors.
+ *
+ * After creating a role-specific object and setting it up, the client must
+ * perform an initial commit without any buffer attached. The compositor
+ * will reply with initial wl_surface state such as
+ * wl_surface.preferred_buffer_scale followed by an xdg_surface.configure
+ * event. The client must acknowledge it and is then allowed to attach a
+ * buffer to map the surface.
+ *
+ * Mapping an xdg_surface-based role surface is defined as making it
+ * possible for the surface to be shown by the compositor. Note that
+ * a mapped surface is not guaranteed to be visible once it is mapped.
+ *
+ * For an xdg_surface to be mapped by the compositor, the following
+ * conditions must be met:
+ * (1) the client has assigned an xdg_surface-based role to the surface
+ * (2) the client has set and committed the xdg_surface state and the
+ * role-dependent state to the surface
+ * (3) the client has committed a buffer to the surface
+ *
+ * A newly-unmapped surface is considered to have met condition (1) out
+ * of the 3 required conditions for mapping a surface if its role surface
+ * has not been destroyed, i.e. the client must perform the initial commit
+ * again before attaching a buffer.
+ */
+extern const struct wl_interface xdg_surface_interface;
+#endif
+#ifndef XDG_TOPLEVEL_INTERFACE
+#define XDG_TOPLEVEL_INTERFACE
+/**
+ * @page page_iface_xdg_toplevel xdg_toplevel
+ * @section page_iface_xdg_toplevel_desc Description
+ *
+ * This interface defines an xdg_surface role which allows a surface to,
+ * among other things, set window-like properties such as maximize,
+ * fullscreen, and minimize, set application-specific metadata like title and
+ * id, and well as trigger user interactive operations such as interactive
+ * resize and move.
+ *
+ * A xdg_toplevel by default is responsible for providing the full intended
+ * visual representation of the toplevel, which depending on the window
+ * state, may mean things like a title bar, window controls and drop shadow.
+ *
+ * Unmapping an xdg_toplevel means that the surface cannot be shown
+ * by the compositor until it is explicitly mapped again.
+ * All active operations (e.g., move, resize) are canceled and all
+ * attributes (e.g. title, state, stacking, ...) are discarded for
+ * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to
+ * the state it had right after xdg_surface.get_toplevel. The client
+ * can re-map the toplevel by perfoming a commit without any buffer
+ * attached, waiting for a configure event and handling it as usual (see
+ * xdg_surface description).
+ *
+ * Attaching a null buffer to a toplevel unmaps the surface.
+ * @section page_iface_xdg_toplevel_api API
+ * See @ref iface_xdg_toplevel.
+ */
+/**
+ * @defgroup iface_xdg_toplevel The xdg_toplevel interface
+ *
+ * This interface defines an xdg_surface role which allows a surface to,
+ * among other things, set window-like properties such as maximize,
+ * fullscreen, and minimize, set application-specific metadata like title and
+ * id, and well as trigger user interactive operations such as interactive
+ * resize and move.
+ *
+ * A xdg_toplevel by default is responsible for providing the full intended
+ * visual representation of the toplevel, which depending on the window
+ * state, may mean things like a title bar, window controls and drop shadow.
+ *
+ * Unmapping an xdg_toplevel means that the surface cannot be shown
+ * by the compositor until it is explicitly mapped again.
+ * All active operations (e.g., move, resize) are canceled and all
+ * attributes (e.g. title, state, stacking, ...) are discarded for
+ * an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to
+ * the state it had right after xdg_surface.get_toplevel. The client
+ * can re-map the toplevel by perfoming a commit without any buffer
+ * attached, waiting for a configure event and handling it as usual (see
+ * xdg_surface description).
+ *
+ * Attaching a null buffer to a toplevel unmaps the surface.
+ */
+extern const struct wl_interface xdg_toplevel_interface;
+#endif
+#ifndef XDG_POPUP_INTERFACE
+#define XDG_POPUP_INTERFACE
+/**
+ * @page page_iface_xdg_popup xdg_popup
+ * @section page_iface_xdg_popup_desc Description
+ *
+ * A popup surface is a short-lived, temporary surface. It can be used to
+ * implement for example menus, popovers, tooltips and other similar user
+ * interface concepts.
+ *
+ * A popup can be made to take an explicit grab. See xdg_popup.grab for
+ * details.
+ *
+ * When the popup is dismissed, a popup_done event will be sent out, and at
+ * the same time the surface will be unmapped. See the xdg_popup.popup_done
+ * event for details.
+ *
+ * Explicitly destroying the xdg_popup object will also dismiss the popup and
+ * unmap the surface. Clients that want to dismiss the popup when another
+ * surface of their own is clicked should dismiss the popup using the destroy
+ * request.
+ *
+ * A newly created xdg_popup will be stacked on top of all previously created
+ * xdg_popup surfaces associated with the same xdg_toplevel.
+ *
+ * The parent of an xdg_popup must be mapped (see the xdg_surface
+ * description) before the xdg_popup itself.
+ *
+ * The client must call wl_surface.commit on the corresponding wl_surface
+ * for the xdg_popup state to take effect.
+ * @section page_iface_xdg_popup_api API
+ * See @ref iface_xdg_popup.
+ */
+/**
+ * @defgroup iface_xdg_popup The xdg_popup interface
+ *
+ * A popup surface is a short-lived, temporary surface. It can be used to
+ * implement for example menus, popovers, tooltips and other similar user
+ * interface concepts.
+ *
+ * A popup can be made to take an explicit grab. See xdg_popup.grab for
+ * details.
+ *
+ * When the popup is dismissed, a popup_done event will be sent out, and at
+ * the same time the surface will be unmapped. See the xdg_popup.popup_done
+ * event for details.
+ *
+ * Explicitly destroying the xdg_popup object will also dismiss the popup and
+ * unmap the surface. Clients that want to dismiss the popup when another
+ * surface of their own is clicked should dismiss the popup using the destroy
+ * request.
+ *
+ * A newly created xdg_popup will be stacked on top of all previously created
+ * xdg_popup surfaces associated with the same xdg_toplevel.
+ *
+ * The parent of an xdg_popup must be mapped (see the xdg_surface
+ * description) before the xdg_popup itself.
+ *
+ * The client must call wl_surface.commit on the corresponding wl_surface
+ * for the xdg_popup state to take effect.
+ */
+extern const struct wl_interface xdg_popup_interface;
+#endif
+
+#ifndef XDG_WM_BASE_ERROR_ENUM
+#define XDG_WM_BASE_ERROR_ENUM
+enum xdg_wm_base_error {
+ /**
+ * given wl_surface has another role
+ */
+ XDG_WM_BASE_ERROR_ROLE = 0,
+ /**
+ * xdg_wm_base was destroyed before children
+ */
+ XDG_WM_BASE_ERROR_DEFUNCT_SURFACES = 1,
+ /**
+ * the client tried to map or destroy a non-topmost popup
+ */
+ XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP = 2,
+ /**
+ * the client specified an invalid popup parent surface
+ */
+ XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT = 3,
+ /**
+ * the client provided an invalid surface state
+ */
+ XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE = 4,
+ /**
+ * the client provided an invalid positioner
+ */
+ XDG_WM_BASE_ERROR_INVALID_POSITIONER = 5,
+ /**
+ * the client didn’t respond to a ping event in time
+ */
+ XDG_WM_BASE_ERROR_UNRESPONSIVE = 6,
+};
+#endif /* XDG_WM_BASE_ERROR_ENUM */
+
+/**
+ * @ingroup iface_xdg_wm_base
+ * @struct xdg_wm_base_listener
+ */
+struct xdg_wm_base_listener {
+ /**
+ * check if the client is alive
+ *
+ * The ping event asks the client if it's still alive. Pass the
+ * serial specified in the event back to the compositor by sending
+ * a "pong" request back with the specified serial. See
+ * xdg_wm_base.pong.
+ *
+ * Compositors can use this to determine if the client is still
+ * alive. It's unspecified what will happen if the client doesn't
+ * respond to the ping request, or in what timeframe. Clients
+ * should try to respond in a reasonable amount of time. The
+ * “unresponsive” error is provided for compositors that wish
+ * to disconnect unresponsive clients.
+ *
+ * A compositor is free to ping in any way it wants, but a client
+ * must always respond to any xdg_wm_base object it created.
+ * @param serial pass this to the pong request
+ */
+ void (*ping)(void *data,
+ struct xdg_wm_base *xdg_wm_base,
+ uint32_t serial);
+};
+
+/**
+ * @ingroup iface_xdg_wm_base
+ */
+static inline int
+xdg_wm_base_add_listener(struct xdg_wm_base *xdg_wm_base,
+ const struct xdg_wm_base_listener *listener, void *data)
+{
+ return wl_proxy_add_listener((struct wl_proxy *) xdg_wm_base,
+ (void (**)(void)) listener, data);
+}
+
+#define XDG_WM_BASE_DESTROY 0
+#define XDG_WM_BASE_CREATE_POSITIONER 1
+#define XDG_WM_BASE_GET_XDG_SURFACE 2
+#define XDG_WM_BASE_PONG 3
+
+/**
+ * @ingroup iface_xdg_wm_base
+ */
+#define XDG_WM_BASE_PING_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_xdg_wm_base
+ */
+#define XDG_WM_BASE_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_wm_base
+ */
+#define XDG_WM_BASE_CREATE_POSITIONER_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_wm_base
+ */
+#define XDG_WM_BASE_GET_XDG_SURFACE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_wm_base
+ */
+#define XDG_WM_BASE_PONG_SINCE_VERSION 1
+
+/** @ingroup iface_xdg_wm_base */
+static inline void
+xdg_wm_base_set_user_data(struct xdg_wm_base *xdg_wm_base, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) xdg_wm_base, user_data);
+}
+
+/** @ingroup iface_xdg_wm_base */
+static inline void *
+xdg_wm_base_get_user_data(struct xdg_wm_base *xdg_wm_base)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) xdg_wm_base);
+}
+
+static inline uint32_t
+xdg_wm_base_get_version(struct xdg_wm_base *xdg_wm_base)
+{
+ return wl_proxy_get_version((struct wl_proxy *) xdg_wm_base);
+}
+
+/**
+ * @ingroup iface_xdg_wm_base
+ *
+ * Destroy this xdg_wm_base object.
+ *
+ * Destroying a bound xdg_wm_base object while there are surfaces
+ * still alive created by this xdg_wm_base object instance is illegal
+ * and will result in a defunct_surfaces error.
+ */
+static inline void
+xdg_wm_base_destroy(struct xdg_wm_base *xdg_wm_base)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base,
+ XDG_WM_BASE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_xdg_wm_base
+ *
+ * Create a positioner object. A positioner object is used to position
+ * surfaces relative to some parent surface. See the interface description
+ * and xdg_surface.get_popup for details.
+ */
+static inline struct xdg_positioner *
+xdg_wm_base_create_positioner(struct xdg_wm_base *xdg_wm_base)
+{
+ struct wl_proxy *id;
+
+ id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base,
+ XDG_WM_BASE_CREATE_POSITIONER, &xdg_positioner_interface, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, NULL);
+
+ return (struct xdg_positioner *) id;
+}
+
+/**
+ * @ingroup iface_xdg_wm_base
+ *
+ * This creates an xdg_surface for the given surface. While xdg_surface
+ * itself is not a role, the corresponding surface may only be assigned
+ * a role extending xdg_surface, such as xdg_toplevel or xdg_popup. It is
+ * illegal to create an xdg_surface for a wl_surface which already has an
+ * assigned role and this will result in a role error.
+ *
+ * This creates an xdg_surface for the given surface. An xdg_surface is
+ * used as basis to define a role to a given surface, such as xdg_toplevel
+ * or xdg_popup. It also manages functionality shared between xdg_surface
+ * based surface roles.
+ *
+ * See the documentation of xdg_surface for more details about what an
+ * xdg_surface is and how it is used.
+ */
+static inline struct xdg_surface *
+xdg_wm_base_get_xdg_surface(struct xdg_wm_base *xdg_wm_base, struct wl_surface *surface)
+{
+ struct wl_proxy *id;
+
+ id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base,
+ XDG_WM_BASE_GET_XDG_SURFACE, &xdg_surface_interface, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, NULL, surface);
+
+ return (struct xdg_surface *) id;
+}
+
+/**
+ * @ingroup iface_xdg_wm_base
+ *
+ * A client must respond to a ping event with a pong request or
+ * the client may be deemed unresponsive. See xdg_wm_base.ping
+ * and xdg_wm_base.error.unresponsive.
+ */
+static inline void
+xdg_wm_base_pong(struct xdg_wm_base *xdg_wm_base, uint32_t serial)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_wm_base,
+ XDG_WM_BASE_PONG, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_wm_base), 0, serial);
+}
+
+#ifndef XDG_POSITIONER_ERROR_ENUM
+#define XDG_POSITIONER_ERROR_ENUM
+enum xdg_positioner_error {
+ /**
+ * invalid input provided
+ */
+ XDG_POSITIONER_ERROR_INVALID_INPUT = 0,
+};
+#endif /* XDG_POSITIONER_ERROR_ENUM */
+
+#ifndef XDG_POSITIONER_ANCHOR_ENUM
+#define XDG_POSITIONER_ANCHOR_ENUM
+enum xdg_positioner_anchor {
+ XDG_POSITIONER_ANCHOR_NONE = 0,
+ XDG_POSITIONER_ANCHOR_TOP = 1,
+ XDG_POSITIONER_ANCHOR_BOTTOM = 2,
+ XDG_POSITIONER_ANCHOR_LEFT = 3,
+ XDG_POSITIONER_ANCHOR_RIGHT = 4,
+ XDG_POSITIONER_ANCHOR_TOP_LEFT = 5,
+ XDG_POSITIONER_ANCHOR_BOTTOM_LEFT = 6,
+ XDG_POSITIONER_ANCHOR_TOP_RIGHT = 7,
+ XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT = 8,
+};
+#endif /* XDG_POSITIONER_ANCHOR_ENUM */
+
+#ifndef XDG_POSITIONER_GRAVITY_ENUM
+#define XDG_POSITIONER_GRAVITY_ENUM
+enum xdg_positioner_gravity {
+ XDG_POSITIONER_GRAVITY_NONE = 0,
+ XDG_POSITIONER_GRAVITY_TOP = 1,
+ XDG_POSITIONER_GRAVITY_BOTTOM = 2,
+ XDG_POSITIONER_GRAVITY_LEFT = 3,
+ XDG_POSITIONER_GRAVITY_RIGHT = 4,
+ XDG_POSITIONER_GRAVITY_TOP_LEFT = 5,
+ XDG_POSITIONER_GRAVITY_BOTTOM_LEFT = 6,
+ XDG_POSITIONER_GRAVITY_TOP_RIGHT = 7,
+ XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT = 8,
+};
+#endif /* XDG_POSITIONER_GRAVITY_ENUM */
+
+#ifndef XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM
+#define XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM
+/**
+ * @ingroup iface_xdg_positioner
+ * constraint adjustments
+ *
+ * The constraint adjustment value define ways the compositor will adjust
+ * the position of the surface, if the unadjusted position would result
+ * in the surface being partly constrained.
+ *
+ * Whether a surface is considered 'constrained' is left to the compositor
+ * to determine. For example, the surface may be partly outside the
+ * compositor's defined 'work area', thus necessitating the child surface's
+ * position be adjusted until it is entirely inside the work area.
+ *
+ * The adjustments can be combined, according to a defined precedence: 1)
+ * Flip, 2) Slide, 3) Resize.
+ */
+enum xdg_positioner_constraint_adjustment {
+ /**
+ * don't move the child surface when constrained
+ *
+ * Don't alter the surface position even if it is constrained on
+ * some axis, for example partially outside the edge of an output.
+ */
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE = 0,
+ /**
+ * move along the x axis until unconstrained
+ *
+ * Slide the surface along the x axis until it is no longer
+ * constrained.
+ *
+ * First try to slide towards the direction of the gravity on the x
+ * axis until either the edge in the opposite direction of the
+ * gravity is unconstrained or the edge in the direction of the
+ * gravity is constrained.
+ *
+ * Then try to slide towards the opposite direction of the gravity
+ * on the x axis until either the edge in the direction of the
+ * gravity is unconstrained or the edge in the opposite direction
+ * of the gravity is constrained.
+ */
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1,
+ /**
+ * move along the y axis until unconstrained
+ *
+ * Slide the surface along the y axis until it is no longer
+ * constrained.
+ *
+ * First try to slide towards the direction of the gravity on the y
+ * axis until either the edge in the opposite direction of the
+ * gravity is unconstrained or the edge in the direction of the
+ * gravity is constrained.
+ *
+ * Then try to slide towards the opposite direction of the gravity
+ * on the y axis until either the edge in the direction of the
+ * gravity is unconstrained or the edge in the opposite direction
+ * of the gravity is constrained.
+ */
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2,
+ /**
+ * invert the anchor and gravity on the x axis
+ *
+ * Invert the anchor and gravity on the x axis if the surface is
+ * constrained on the x axis. For example, if the left edge of the
+ * surface is constrained, the gravity is 'left' and the anchor is
+ * 'left', change the gravity to 'right' and the anchor to 'right'.
+ *
+ * If the adjusted position also ends up being constrained, the
+ * resulting position of the flip_x adjustment will be the one
+ * before the adjustment.
+ */
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X = 4,
+ /**
+ * invert the anchor and gravity on the y axis
+ *
+ * Invert the anchor and gravity on the y axis if the surface is
+ * constrained on the y axis. For example, if the bottom edge of
+ * the surface is constrained, the gravity is 'bottom' and the
+ * anchor is 'bottom', change the gravity to 'top' and the anchor
+ * to 'top'.
+ *
+ * The adjusted position is calculated given the original anchor
+ * rectangle and offset, but with the new flipped anchor and
+ * gravity values.
+ *
+ * If the adjusted position also ends up being constrained, the
+ * resulting position of the flip_y adjustment will be the one
+ * before the adjustment.
+ */
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y = 8,
+ /**
+ * horizontally resize the surface
+ *
+ * Resize the surface horizontally so that it is completely
+ * unconstrained.
+ */
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X = 16,
+ /**
+ * vertically resize the surface
+ *
+ * Resize the surface vertically so that it is completely
+ * unconstrained.
+ */
+ XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32,
+};
+#endif /* XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_ENUM */
+
+#define XDG_POSITIONER_DESTROY 0
+#define XDG_POSITIONER_SET_SIZE 1
+#define XDG_POSITIONER_SET_ANCHOR_RECT 2
+#define XDG_POSITIONER_SET_ANCHOR 3
+#define XDG_POSITIONER_SET_GRAVITY 4
+#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT 5
+#define XDG_POSITIONER_SET_OFFSET 6
+#define XDG_POSITIONER_SET_REACTIVE 7
+#define XDG_POSITIONER_SET_PARENT_SIZE 8
+#define XDG_POSITIONER_SET_PARENT_CONFIGURE 9
+
+
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_SIZE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_ANCHOR_RECT_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_ANCHOR_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_GRAVITY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_OFFSET_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_REACTIVE_SINCE_VERSION 3
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_PARENT_SIZE_SINCE_VERSION 3
+/**
+ * @ingroup iface_xdg_positioner
+ */
+#define XDG_POSITIONER_SET_PARENT_CONFIGURE_SINCE_VERSION 3
+
+/** @ingroup iface_xdg_positioner */
+static inline void
+xdg_positioner_set_user_data(struct xdg_positioner *xdg_positioner, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) xdg_positioner, user_data);
+}
+
+/** @ingroup iface_xdg_positioner */
+static inline void *
+xdg_positioner_get_user_data(struct xdg_positioner *xdg_positioner)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) xdg_positioner);
+}
+
+static inline uint32_t
+xdg_positioner_get_version(struct xdg_positioner *xdg_positioner)
+{
+ return wl_proxy_get_version((struct wl_proxy *) xdg_positioner);
+}
+
+/**
+ * @ingroup iface_xdg_positioner
+ *
+ * Notify the compositor that the xdg_positioner will no longer be used.
+ */
+static inline void
+xdg_positioner_destroy(struct xdg_positioner *xdg_positioner)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
+ XDG_POSITIONER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_xdg_positioner
+ *
+ * Set the size of the surface that is to be positioned with the positioner
+ * object. The size is in surface-local coordinates and corresponds to the
+ * window geometry. See xdg_surface.set_window_geometry.
+ *
+ * If a zero or negative size is set the invalid_input error is raised.
+ */
+static inline void
+xdg_positioner_set_size(struct xdg_positioner *xdg_positioner, int32_t width, int32_t height)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
+ XDG_POSITIONER_SET_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, width, height);
+}
+
+/**
+ * @ingroup iface_xdg_positioner
+ *
+ * Specify the anchor rectangle within the parent surface that the child
+ * surface will be placed relative to. The rectangle is relative to the
+ * window geometry as defined by xdg_surface.set_window_geometry of the
+ * parent surface.
+ *
+ * When the xdg_positioner object is used to position a child surface, the
+ * anchor rectangle may not extend outside the window geometry of the
+ * positioned child's parent surface.
+ *
+ * If a negative size is set the invalid_input error is raised.
+ */
+static inline void
+xdg_positioner_set_anchor_rect(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
+ XDG_POSITIONER_SET_ANCHOR_RECT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, x, y, width, height);
+}
+
+/**
+ * @ingroup iface_xdg_positioner
+ *
+ * Defines the anchor point for the anchor rectangle. The specified anchor
+ * is used derive an anchor point that the child surface will be
+ * positioned relative to. If a corner anchor is set (e.g. 'top_left' or
+ * 'bottom_right'), the anchor point will be at the specified corner;
+ * otherwise, the derived anchor point will be centered on the specified
+ * edge, or in the center of the anchor rectangle if no edge is specified.
+ */
+static inline void
+xdg_positioner_set_anchor(struct xdg_positioner *xdg_positioner, uint32_t anchor)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
+ XDG_POSITIONER_SET_ANCHOR, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, anchor);
+}
+
+/**
+ * @ingroup iface_xdg_positioner
+ *
+ * Defines in what direction a surface should be positioned, relative to
+ * the anchor point of the parent surface. If a corner gravity is
+ * specified (e.g. 'bottom_right' or 'top_left'), then the child surface
+ * will be placed towards the specified gravity; otherwise, the child
+ * surface will be centered over the anchor point on any axis that had no
+ * gravity specified. If the gravity is not in the ‘gravity’ enum, an
+ * invalid_input error is raised.
+ */
+static inline void
+xdg_positioner_set_gravity(struct xdg_positioner *xdg_positioner, uint32_t gravity)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
+ XDG_POSITIONER_SET_GRAVITY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, gravity);
+}
+
+/**
+ * @ingroup iface_xdg_positioner
+ *
+ * Specify how the window should be positioned if the originally intended
+ * position caused the surface to be constrained, meaning at least
+ * partially outside positioning boundaries set by the compositor. The
+ * adjustment is set by constructing a bitmask describing the adjustment to
+ * be made when the surface is constrained on that axis.
+ *
+ * If no bit for one axis is set, the compositor will assume that the child
+ * surface should not change its position on that axis when constrained.
+ *
+ * If more than one bit for one axis is set, the order of how adjustments
+ * are applied is specified in the corresponding adjustment descriptions.
+ *
+ * The default adjustment is none.
+ */
+static inline void
+xdg_positioner_set_constraint_adjustment(struct xdg_positioner *xdg_positioner, uint32_t constraint_adjustment)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
+ XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, constraint_adjustment);
+}
+
+/**
+ * @ingroup iface_xdg_positioner
+ *
+ * Specify the surface position offset relative to the position of the
+ * anchor on the anchor rectangle and the anchor on the surface. For
+ * example if the anchor of the anchor rectangle is at (x, y), the surface
+ * has the gravity bottom|right, and the offset is (ox, oy), the calculated
+ * surface position will be (x + ox, y + oy). The offset position of the
+ * surface is the one used for constraint testing. See
+ * set_constraint_adjustment.
+ *
+ * An example use case is placing a popup menu on top of a user interface
+ * element, while aligning the user interface element of the parent surface
+ * with some user interface element placed somewhere in the popup surface.
+ */
+static inline void
+xdg_positioner_set_offset(struct xdg_positioner *xdg_positioner, int32_t x, int32_t y)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
+ XDG_POSITIONER_SET_OFFSET, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, x, y);
+}
+
+/**
+ * @ingroup iface_xdg_positioner
+ *
+ * When set reactive, the surface is reconstrained if the conditions used
+ * for constraining changed, e.g. the parent window moved.
+ *
+ * If the conditions changed and the popup was reconstrained, an
+ * xdg_popup.configure event is sent with updated geometry, followed by an
+ * xdg_surface.configure event.
+ */
+static inline void
+xdg_positioner_set_reactive(struct xdg_positioner *xdg_positioner)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
+ XDG_POSITIONER_SET_REACTIVE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0);
+}
+
+/**
+ * @ingroup iface_xdg_positioner
+ *
+ * Set the parent window geometry the compositor should use when
+ * positioning the popup. The compositor may use this information to
+ * determine the future state the popup should be constrained using. If
+ * this doesn't match the dimension of the parent the popup is eventually
+ * positioned against, the behavior is undefined.
+ *
+ * The arguments are given in the surface-local coordinate space.
+ */
+static inline void
+xdg_positioner_set_parent_size(struct xdg_positioner *xdg_positioner, int32_t parent_width, int32_t parent_height)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
+ XDG_POSITIONER_SET_PARENT_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, parent_width, parent_height);
+}
+
+/**
+ * @ingroup iface_xdg_positioner
+ *
+ * Set the serial of an xdg_surface.configure event this positioner will be
+ * used in response to. The compositor may use this information together
+ * with set_parent_size to determine what future state the popup should be
+ * constrained using.
+ */
+static inline void
+xdg_positioner_set_parent_configure(struct xdg_positioner *xdg_positioner, uint32_t serial)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_positioner,
+ XDG_POSITIONER_SET_PARENT_CONFIGURE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_positioner), 0, serial);
+}
+
+#ifndef XDG_SURFACE_ERROR_ENUM
+#define XDG_SURFACE_ERROR_ENUM
+enum xdg_surface_error {
+ /**
+ * Surface was not fully constructed
+ */
+ XDG_SURFACE_ERROR_NOT_CONSTRUCTED = 1,
+ /**
+ * Surface was already constructed
+ */
+ XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED = 2,
+ /**
+ * Attaching a buffer to an unconfigured surface
+ */
+ XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER = 3,
+ /**
+ * Invalid serial number when acking a configure event
+ */
+ XDG_SURFACE_ERROR_INVALID_SERIAL = 4,
+ /**
+ * Width or height was zero or negative
+ */
+ XDG_SURFACE_ERROR_INVALID_SIZE = 5,
+ /**
+ * Surface was destroyed before its role object
+ */
+ XDG_SURFACE_ERROR_DEFUNCT_ROLE_OBJECT = 6,
+};
+#endif /* XDG_SURFACE_ERROR_ENUM */
+
+/**
+ * @ingroup iface_xdg_surface
+ * @struct xdg_surface_listener
+ */
+struct xdg_surface_listener {
+ /**
+ * suggest a surface change
+ *
+ * The configure event marks the end of a configure sequence. A
+ * configure sequence is a set of one or more events configuring
+ * the state of the xdg_surface, including the final
+ * xdg_surface.configure event.
+ *
+ * Where applicable, xdg_surface surface roles will during a
+ * configure sequence extend this event as a latched state sent as
+ * events before the xdg_surface.configure event. Such events
+ * should be considered to make up a set of atomically applied
+ * configuration states, where the xdg_surface.configure commits
+ * the accumulated state.
+ *
+ * Clients should arrange their surface for the new states, and
+ * then send an ack_configure request with the serial sent in this
+ * configure event at some point before committing the new surface.
+ *
+ * If the client receives multiple configure events before it can
+ * respond to one, it is free to discard all but the last event it
+ * received.
+ * @param serial serial of the configure event
+ */
+ void (*configure)(void *data,
+ struct xdg_surface *xdg_surface,
+ uint32_t serial);
+};
+
+/**
+ * @ingroup iface_xdg_surface
+ */
+static inline int
+xdg_surface_add_listener(struct xdg_surface *xdg_surface,
+ const struct xdg_surface_listener *listener, void *data)
+{
+ return wl_proxy_add_listener((struct wl_proxy *) xdg_surface,
+ (void (**)(void)) listener, data);
+}
+
+#define XDG_SURFACE_DESTROY 0
+#define XDG_SURFACE_GET_TOPLEVEL 1
+#define XDG_SURFACE_GET_POPUP 2
+#define XDG_SURFACE_SET_WINDOW_GEOMETRY 3
+#define XDG_SURFACE_ACK_CONFIGURE 4
+
+/**
+ * @ingroup iface_xdg_surface
+ */
+#define XDG_SURFACE_CONFIGURE_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_xdg_surface
+ */
+#define XDG_SURFACE_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_surface
+ */
+#define XDG_SURFACE_GET_TOPLEVEL_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_surface
+ */
+#define XDG_SURFACE_GET_POPUP_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_surface
+ */
+#define XDG_SURFACE_SET_WINDOW_GEOMETRY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_surface
+ */
+#define XDG_SURFACE_ACK_CONFIGURE_SINCE_VERSION 1
+
+/** @ingroup iface_xdg_surface */
+static inline void
+xdg_surface_set_user_data(struct xdg_surface *xdg_surface, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) xdg_surface, user_data);
+}
+
+/** @ingroup iface_xdg_surface */
+static inline void *
+xdg_surface_get_user_data(struct xdg_surface *xdg_surface)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) xdg_surface);
+}
+
+static inline uint32_t
+xdg_surface_get_version(struct xdg_surface *xdg_surface)
+{
+ return wl_proxy_get_version((struct wl_proxy *) xdg_surface);
+}
+
+/**
+ * @ingroup iface_xdg_surface
+ *
+ * Destroy the xdg_surface object. An xdg_surface must only be destroyed
+ * after its role object has been destroyed, otherwise
+ * a defunct_role_object error is raised.
+ */
+static inline void
+xdg_surface_destroy(struct xdg_surface *xdg_surface)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface,
+ XDG_SURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_xdg_surface
+ *
+ * This creates an xdg_toplevel object for the given xdg_surface and gives
+ * the associated wl_surface the xdg_toplevel role.
+ *
+ * See the documentation of xdg_toplevel for more details about what an
+ * xdg_toplevel is and how it is used.
+ */
+static inline struct xdg_toplevel *
+xdg_surface_get_toplevel(struct xdg_surface *xdg_surface)
+{
+ struct wl_proxy *id;
+
+ id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface,
+ XDG_SURFACE_GET_TOPLEVEL, &xdg_toplevel_interface, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, NULL);
+
+ return (struct xdg_toplevel *) id;
+}
+
+/**
+ * @ingroup iface_xdg_surface
+ *
+ * This creates an xdg_popup object for the given xdg_surface and gives
+ * the associated wl_surface the xdg_popup role.
+ *
+ * If null is passed as a parent, a parent surface must be specified using
+ * some other protocol, before committing the initial state.
+ *
+ * See the documentation of xdg_popup for more details about what an
+ * xdg_popup is and how it is used.
+ */
+static inline struct xdg_popup *
+xdg_surface_get_popup(struct xdg_surface *xdg_surface, struct xdg_surface *parent, struct xdg_positioner *positioner)
+{
+ struct wl_proxy *id;
+
+ id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface,
+ XDG_SURFACE_GET_POPUP, &xdg_popup_interface, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, NULL, parent, positioner);
+
+ return (struct xdg_popup *) id;
+}
+
+/**
+ * @ingroup iface_xdg_surface
+ *
+ * The window geometry of a surface is its "visible bounds" from the
+ * user's perspective. Client-side decorations often have invisible
+ * portions like drop-shadows which should be ignored for the
+ * purposes of aligning, placing and constraining windows.
+ *
+ * The window geometry is double buffered, and will be applied at the
+ * time wl_surface.commit of the corresponding wl_surface is called.
+ *
+ * When maintaining a position, the compositor should treat the (x, y)
+ * coordinate of the window geometry as the top left corner of the window.
+ * A client changing the (x, y) window geometry coordinate should in
+ * general not alter the position of the window.
+ *
+ * Once the window geometry of the surface is set, it is not possible to
+ * unset it, and it will remain the same until set_window_geometry is
+ * called again, even if a new subsurface or buffer is attached.
+ *
+ * If never set, the value is the full bounds of the surface,
+ * including any subsurfaces. This updates dynamically on every
+ * commit. This unset is meant for extremely simple clients.
+ *
+ * The arguments are given in the surface-local coordinate space of
+ * the wl_surface associated with this xdg_surface, and may extend outside
+ * of the wl_surface itself to mark parts of the subsurface tree as part of
+ * the window geometry.
+ *
+ * When applied, the effective window geometry will be the set window
+ * geometry clamped to the bounding rectangle of the combined
+ * geometry of the surface of the xdg_surface and the associated
+ * subsurfaces.
+ *
+ * The effective geometry will not be recalculated unless a new call to
+ * set_window_geometry is done and the new pending surface state is
+ * subsequently applied.
+ *
+ * The width and height of the effective window geometry must be
+ * greater than zero. Setting an invalid size will raise an
+ * invalid_size error.
+ */
+static inline void
+xdg_surface_set_window_geometry(struct xdg_surface *xdg_surface, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface,
+ XDG_SURFACE_SET_WINDOW_GEOMETRY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, x, y, width, height);
+}
+
+/**
+ * @ingroup iface_xdg_surface
+ *
+ * When a configure event is received, if a client commits the
+ * surface in response to the configure event, then the client
+ * must make an ack_configure request sometime before the commit
+ * request, passing along the serial of the configure event.
+ *
+ * For instance, for toplevel surfaces the compositor might use this
+ * information to move a surface to the top left only when the client has
+ * drawn itself for the maximized or fullscreen state.
+ *
+ * If the client receives multiple configure events before it
+ * can respond to one, it only has to ack the last configure event.
+ * Acking a configure event that was never sent raises an invalid_serial
+ * error.
+ *
+ * A client is not required to commit immediately after sending
+ * an ack_configure request - it may even ack_configure several times
+ * before its next surface commit.
+ *
+ * A client may send multiple ack_configure requests before committing, but
+ * only the last request sent before a commit indicates which configure
+ * event the client really is responding to.
+ *
+ * Sending an ack_configure request consumes the serial number sent with
+ * the request, as well as serial numbers sent by all configure events
+ * sent on this xdg_surface prior to the configure event referenced by
+ * the committed serial.
+ *
+ * It is an error to issue multiple ack_configure requests referencing a
+ * serial from the same configure event, or to issue an ack_configure
+ * request referencing a serial from a configure event issued before the
+ * event identified by the last ack_configure request for the same
+ * xdg_surface. Doing so will raise an invalid_serial error.
+ */
+static inline void
+xdg_surface_ack_configure(struct xdg_surface *xdg_surface, uint32_t serial)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_surface,
+ XDG_SURFACE_ACK_CONFIGURE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_surface), 0, serial);
+}
+
+#ifndef XDG_TOPLEVEL_ERROR_ENUM
+#define XDG_TOPLEVEL_ERROR_ENUM
+enum xdg_toplevel_error {
+ /**
+ * provided value is not a valid variant of the resize_edge enum
+ */
+ XDG_TOPLEVEL_ERROR_INVALID_RESIZE_EDGE = 0,
+ /**
+ * invalid parent toplevel
+ */
+ XDG_TOPLEVEL_ERROR_INVALID_PARENT = 1,
+ /**
+ * client provided an invalid min or max size
+ */
+ XDG_TOPLEVEL_ERROR_INVALID_SIZE = 2,
+};
+#endif /* XDG_TOPLEVEL_ERROR_ENUM */
+
+#ifndef XDG_TOPLEVEL_RESIZE_EDGE_ENUM
+#define XDG_TOPLEVEL_RESIZE_EDGE_ENUM
+/**
+ * @ingroup iface_xdg_toplevel
+ * edge values for resizing
+ *
+ * These values are used to indicate which edge of a surface
+ * is being dragged in a resize operation.
+ */
+enum xdg_toplevel_resize_edge {
+ XDG_TOPLEVEL_RESIZE_EDGE_NONE = 0,
+ XDG_TOPLEVEL_RESIZE_EDGE_TOP = 1,
+ XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM = 2,
+ XDG_TOPLEVEL_RESIZE_EDGE_LEFT = 4,
+ XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT = 5,
+ XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT = 6,
+ XDG_TOPLEVEL_RESIZE_EDGE_RIGHT = 8,
+ XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT = 9,
+ XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT = 10,
+};
+#endif /* XDG_TOPLEVEL_RESIZE_EDGE_ENUM */
+
+#ifndef XDG_TOPLEVEL_STATE_ENUM
+#define XDG_TOPLEVEL_STATE_ENUM
+/**
+ * @ingroup iface_xdg_toplevel
+ * types of state on the surface
+ *
+ * The different state values used on the surface. This is designed for
+ * state values like maximized, fullscreen. It is paired with the
+ * configure event to ensure that both the client and the compositor
+ * setting the state can be synchronized.
+ *
+ * States set in this way are double-buffered. They will get applied on
+ * the next commit.
+ */
+enum xdg_toplevel_state {
+ /**
+ * the surface is maximized
+ * the surface is maximized
+ *
+ * The surface is maximized. The window geometry specified in the
+ * configure event must be obeyed by the client, or the
+ * xdg_wm_base.invalid_surface_state error is raised.
+ *
+ * The client should draw without shadow or other decoration
+ * outside of the window geometry.
+ */
+ XDG_TOPLEVEL_STATE_MAXIMIZED = 1,
+ /**
+ * the surface is fullscreen
+ * the surface is fullscreen
+ *
+ * The surface is fullscreen. The window geometry specified in
+ * the configure event is a maximum; the client cannot resize
+ * beyond it. For a surface to cover the whole fullscreened area,
+ * the geometry dimensions must be obeyed by the client. For more
+ * details, see xdg_toplevel.set_fullscreen.
+ */
+ XDG_TOPLEVEL_STATE_FULLSCREEN = 2,
+ /**
+ * the surface is being resized
+ * the surface is being resized
+ *
+ * The surface is being resized. The window geometry specified in
+ * the configure event is a maximum; the client cannot resize
+ * beyond it. Clients that have aspect ratio or cell sizing
+ * configuration can use a smaller size, however.
+ */
+ XDG_TOPLEVEL_STATE_RESIZING = 3,
+ /**
+ * the surface is now activated
+ * the surface is now activated
+ *
+ * Client window decorations should be painted as if the window
+ * is active. Do not assume this means that the window actually has
+ * keyboard or pointer focus.
+ */
+ XDG_TOPLEVEL_STATE_ACTIVATED = 4,
+ /**
+ * the surface’s left edge is tiled
+ *
+ * The window is currently in a tiled layout and the left edge is
+ * considered to be adjacent to another part of the tiling grid.
+ * @since 2
+ */
+ XDG_TOPLEVEL_STATE_TILED_LEFT = 5,
+ /**
+ * the surface’s right edge is tiled
+ *
+ * The window is currently in a tiled layout and the right edge
+ * is considered to be adjacent to another part of the tiling grid.
+ * @since 2
+ */
+ XDG_TOPLEVEL_STATE_TILED_RIGHT = 6,
+ /**
+ * the surface’s top edge is tiled
+ *
+ * The window is currently in a tiled layout and the top edge is
+ * considered to be adjacent to another part of the tiling grid.
+ * @since 2
+ */
+ XDG_TOPLEVEL_STATE_TILED_TOP = 7,
+ /**
+ * the surface’s bottom edge is tiled
+ *
+ * The window is currently in a tiled layout and the bottom edge
+ * is considered to be adjacent to another part of the tiling grid.
+ * @since 2
+ */
+ XDG_TOPLEVEL_STATE_TILED_BOTTOM = 8,
+ /**
+ * surface repaint is suspended
+ *
+ * The surface is currently not ordinarily being repainted; for
+ * example because its content is occluded by another window, or
+ * its outputs are switched off due to screen locking.
+ * @since 6
+ */
+ XDG_TOPLEVEL_STATE_SUSPENDED = 9,
+};
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION 2
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION 2
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_STATE_TILED_TOP_SINCE_VERSION 2
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_STATE_TILED_BOTTOM_SINCE_VERSION 2
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION 6
+#endif /* XDG_TOPLEVEL_STATE_ENUM */
+
+#ifndef XDG_TOPLEVEL_WM_CAPABILITIES_ENUM
+#define XDG_TOPLEVEL_WM_CAPABILITIES_ENUM
+enum xdg_toplevel_wm_capabilities {
+ /**
+ * show_window_menu is available
+ */
+ XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU = 1,
+ /**
+ * set_maximized and unset_maximized are available
+ */
+ XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE = 2,
+ /**
+ * set_fullscreen and unset_fullscreen are available
+ */
+ XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN = 3,
+ /**
+ * set_minimized is available
+ */
+ XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE = 4,
+};
+#endif /* XDG_TOPLEVEL_WM_CAPABILITIES_ENUM */
+
+/**
+ * @ingroup iface_xdg_toplevel
+ * @struct xdg_toplevel_listener
+ */
+struct xdg_toplevel_listener {
+ /**
+ * suggest a surface change
+ *
+ * This configure event asks the client to resize its toplevel
+ * surface or to change its state. The configured state should not
+ * be applied immediately. See xdg_surface.configure for details.
+ *
+ * The width and height arguments specify a hint to the window
+ * about how its surface should be resized in window geometry
+ * coordinates. See set_window_geometry.
+ *
+ * If the width or height arguments are zero, it means the client
+ * should decide its own window dimension. This may happen when the
+ * compositor needs to configure the state of the surface but
+ * doesn't have any information about any previous or expected
+ * dimension.
+ *
+ * The states listed in the event specify how the width/height
+ * arguments should be interpreted, and possibly how it should be
+ * drawn.
+ *
+ * Clients must send an ack_configure in response to this event.
+ * See xdg_surface.configure and xdg_surface.ack_configure for
+ * details.
+ */
+ void (*configure)(void *data,
+ struct xdg_toplevel *xdg_toplevel,
+ int32_t width,
+ int32_t height,
+ struct wl_array *states);
+ /**
+ * surface wants to be closed
+ *
+ * The close event is sent by the compositor when the user wants
+ * the surface to be closed. This should be equivalent to the user
+ * clicking the close button in client-side decorations, if your
+ * application has any.
+ *
+ * This is only a request that the user intends to close the
+ * window. The client may choose to ignore this request, or show a
+ * dialog to ask the user to save their data, etc.
+ */
+ void (*close)(void *data,
+ struct xdg_toplevel *xdg_toplevel);
+ /**
+ * recommended window geometry bounds
+ *
+ * The configure_bounds event may be sent prior to a
+ * xdg_toplevel.configure event to communicate the bounds a window
+ * geometry size is recommended to constrain to.
+ *
+ * The passed width and height are in surface coordinate space. If
+ * width and height are 0, it means bounds is unknown and
+ * equivalent to as if no configure_bounds event was ever sent for
+ * this surface.
+ *
+ * The bounds can for example correspond to the size of a monitor
+ * excluding any panels or other shell components, so that a
+ * surface isn't created in a way that it cannot fit.
+ *
+ * The bounds may change at any point, and in such a case, a new
+ * xdg_toplevel.configure_bounds will be sent, followed by
+ * xdg_toplevel.configure and xdg_surface.configure.
+ * @since 4
+ */
+ void (*configure_bounds)(void *data,
+ struct xdg_toplevel *xdg_toplevel,
+ int32_t width,
+ int32_t height);
+ /**
+ * compositor capabilities
+ *
+ * This event advertises the capabilities supported by the
+ * compositor. If a capability isn't supported, clients should hide
+ * or disable the UI elements that expose this functionality. For
+ * instance, if the compositor doesn't advertise support for
+ * minimized toplevels, a button triggering the set_minimized
+ * request should not be displayed.
+ *
+ * The compositor will ignore requests it doesn't support. For
+ * instance, a compositor which doesn't advertise support for
+ * minimized will ignore set_minimized requests.
+ *
+ * Compositors must send this event once before the first
+ * xdg_surface.configure event. When the capabilities change,
+ * compositors must send this event again and then send an
+ * xdg_surface.configure event.
+ *
+ * The configured state should not be applied immediately. See
+ * xdg_surface.configure for details.
+ *
+ * The capabilities are sent as an array of 32-bit unsigned
+ * integers in native endianness.
+ * @param capabilities array of 32-bit capabilities
+ * @since 5
+ */
+ void (*wm_capabilities)(void *data,
+ struct xdg_toplevel *xdg_toplevel,
+ struct wl_array *capabilities);
+};
+
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+static inline int
+xdg_toplevel_add_listener(struct xdg_toplevel *xdg_toplevel,
+ const struct xdg_toplevel_listener *listener, void *data)
+{
+ return wl_proxy_add_listener((struct wl_proxy *) xdg_toplevel,
+ (void (**)(void)) listener, data);
+}
+
+#define XDG_TOPLEVEL_DESTROY 0
+#define XDG_TOPLEVEL_SET_PARENT 1
+#define XDG_TOPLEVEL_SET_TITLE 2
+#define XDG_TOPLEVEL_SET_APP_ID 3
+#define XDG_TOPLEVEL_SHOW_WINDOW_MENU 4
+#define XDG_TOPLEVEL_MOVE 5
+#define XDG_TOPLEVEL_RESIZE 6
+#define XDG_TOPLEVEL_SET_MAX_SIZE 7
+#define XDG_TOPLEVEL_SET_MIN_SIZE 8
+#define XDG_TOPLEVEL_SET_MAXIMIZED 9
+#define XDG_TOPLEVEL_UNSET_MAXIMIZED 10
+#define XDG_TOPLEVEL_SET_FULLSCREEN 11
+#define XDG_TOPLEVEL_UNSET_FULLSCREEN 12
+#define XDG_TOPLEVEL_SET_MINIMIZED 13
+
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_CONFIGURE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_CLOSE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION 4
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION 5
+
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_PARENT_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_TITLE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_APP_ID_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SHOW_WINDOW_MENU_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_MOVE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_RESIZE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_MAX_SIZE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_MIN_SIZE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_MAXIMIZED_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_UNSET_MAXIMIZED_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_FULLSCREEN_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_UNSET_FULLSCREEN_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_toplevel
+ */
+#define XDG_TOPLEVEL_SET_MINIMIZED_SINCE_VERSION 1
+
+/** @ingroup iface_xdg_toplevel */
+static inline void
+xdg_toplevel_set_user_data(struct xdg_toplevel *xdg_toplevel, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) xdg_toplevel, user_data);
+}
+
+/** @ingroup iface_xdg_toplevel */
+static inline void *
+xdg_toplevel_get_user_data(struct xdg_toplevel *xdg_toplevel)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) xdg_toplevel);
+}
+
+static inline uint32_t
+xdg_toplevel_get_version(struct xdg_toplevel *xdg_toplevel)
+{
+ return wl_proxy_get_version((struct wl_proxy *) xdg_toplevel);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * This request destroys the role surface and unmaps the surface;
+ * see "Unmapping" behavior in interface section for details.
+ */
+static inline void
+xdg_toplevel_destroy(struct xdg_toplevel *xdg_toplevel)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Set the "parent" of this surface. This surface should be stacked
+ * above the parent surface and all other ancestor surfaces.
+ *
+ * Parent surfaces should be set on dialogs, toolboxes, or other
+ * "auxiliary" surfaces, so that the parent is raised when the dialog
+ * is raised.
+ *
+ * Setting a null parent for a child surface unsets its parent. Setting
+ * a null parent for a surface which currently has no parent is a no-op.
+ *
+ * Only mapped surfaces can have child surfaces. Setting a parent which
+ * is not mapped is equivalent to setting a null parent. If a surface
+ * becomes unmapped, its children's parent is set to the parent of
+ * the now-unmapped surface. If the now-unmapped surface has no parent,
+ * its children's parent is unset. If the now-unmapped surface becomes
+ * mapped again, its parent-child relationship is not restored.
+ *
+ * The parent toplevel must not be one of the child toplevel's
+ * descendants, and the parent must be different from the child toplevel,
+ * otherwise the invalid_parent protocol error is raised.
+ */
+static inline void
+xdg_toplevel_set_parent(struct xdg_toplevel *xdg_toplevel, struct xdg_toplevel *parent)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_SET_PARENT, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, parent);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Set a short title for the surface.
+ *
+ * This string may be used to identify the surface in a task bar,
+ * window list, or other user interface elements provided by the
+ * compositor.
+ *
+ * The string must be encoded in UTF-8.
+ */
+static inline void
+xdg_toplevel_set_title(struct xdg_toplevel *xdg_toplevel, const char *title)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_SET_TITLE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, title);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Set an application identifier for the surface.
+ *
+ * The app ID identifies the general class of applications to which
+ * the surface belongs. The compositor can use this to group multiple
+ * surfaces together, or to determine how to launch a new application.
+ *
+ * For D-Bus activatable applications, the app ID is used as the D-Bus
+ * service name.
+ *
+ * The compositor shell will try to group application surfaces together
+ * by their app ID. As a best practice, it is suggested to select app
+ * ID's that match the basename of the application's .desktop file.
+ * For example, "org.freedesktop.FooViewer" where the .desktop file is
+ * "org.freedesktop.FooViewer.desktop".
+ *
+ * Like other properties, a set_app_id request can be sent after the
+ * xdg_toplevel has been mapped to update the property.
+ *
+ * See the desktop-entry specification [0] for more details on
+ * application identifiers and how they relate to well-known D-Bus
+ * names and .desktop files.
+ *
+ * [0] https://standards.freedesktop.org/desktop-entry-spec/
+ */
+static inline void
+xdg_toplevel_set_app_id(struct xdg_toplevel *xdg_toplevel, const char *app_id)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_SET_APP_ID, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, app_id);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Clients implementing client-side decorations might want to show
+ * a context menu when right-clicking on the decorations, giving the
+ * user a menu that they can use to maximize or minimize the window.
+ *
+ * This request asks the compositor to pop up such a window menu at
+ * the given position, relative to the local surface coordinates of
+ * the parent surface. There are no guarantees as to what menu items
+ * the window menu contains, or even if a window menu will be drawn
+ * at all.
+ *
+ * This request must be used in response to some sort of user action
+ * like a button press, key press, or touch down event.
+ */
+static inline void
+xdg_toplevel_show_window_menu(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, int32_t x, int32_t y)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_SHOW_WINDOW_MENU, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial, x, y);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Start an interactive, user-driven move of the surface.
+ *
+ * This request must be used in response to some sort of user action
+ * like a button press, key press, or touch down event. The passed
+ * serial is used to determine the type of interactive move (touch,
+ * pointer, etc).
+ *
+ * The server may ignore move requests depending on the state of
+ * the surface (e.g. fullscreen or maximized), or if the passed serial
+ * is no longer valid.
+ *
+ * If triggered, the surface will lose the focus of the device
+ * (wl_pointer, wl_touch, etc) used for the move. It is up to the
+ * compositor to visually indicate that the move is taking place, such as
+ * updating a pointer cursor, during the move. There is no guarantee
+ * that the device focus will return when the move is completed.
+ */
+static inline void
+xdg_toplevel_move(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_MOVE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Start a user-driven, interactive resize of the surface.
+ *
+ * This request must be used in response to some sort of user action
+ * like a button press, key press, or touch down event. The passed
+ * serial is used to determine the type of interactive resize (touch,
+ * pointer, etc).
+ *
+ * The server may ignore resize requests depending on the state of
+ * the surface (e.g. fullscreen or maximized).
+ *
+ * If triggered, the client will receive configure events with the
+ * "resize" state enum value and the expected sizes. See the "resize"
+ * enum value for more details about what is required. The client
+ * must also acknowledge configure events using "ack_configure". After
+ * the resize is completed, the client will receive another "configure"
+ * event without the resize state.
+ *
+ * If triggered, the surface also will lose the focus of the device
+ * (wl_pointer, wl_touch, etc) used for the resize. It is up to the
+ * compositor to visually indicate that the resize is taking place,
+ * such as updating a pointer cursor, during the resize. There is no
+ * guarantee that the device focus will return when the resize is
+ * completed.
+ *
+ * The edges parameter specifies how the surface should be resized, and
+ * is one of the values of the resize_edge enum. Values not matching
+ * a variant of the enum will cause the invalid_resize_edge protocol error.
+ * The compositor may use this information to update the surface position
+ * for example when dragging the top left corner. The compositor may also
+ * use this information to adapt its behavior, e.g. choose an appropriate
+ * cursor image.
+ */
+static inline void
+xdg_toplevel_resize(struct xdg_toplevel *xdg_toplevel, struct wl_seat *seat, uint32_t serial, uint32_t edges)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, seat, serial, edges);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Set a maximum size for the window.
+ *
+ * The client can specify a maximum size so that the compositor does
+ * not try to configure the window beyond this size.
+ *
+ * The width and height arguments are in window geometry coordinates.
+ * See xdg_surface.set_window_geometry.
+ *
+ * Values set in this way are double-buffered. They will get applied
+ * on the next commit.
+ *
+ * The compositor can use this information to allow or disallow
+ * different states like maximize or fullscreen and draw accurate
+ * animations.
+ *
+ * Similarly, a tiling window manager may use this information to
+ * place and resize client windows in a more effective way.
+ *
+ * The client should not rely on the compositor to obey the maximum
+ * size. The compositor may decide to ignore the values set by the
+ * client and request a larger size.
+ *
+ * If never set, or a value of zero in the request, means that the
+ * client has no expected maximum size in the given dimension.
+ * As a result, a client wishing to reset the maximum size
+ * to an unspecified state can use zero for width and height in the
+ * request.
+ *
+ * Requesting a maximum size to be smaller than the minimum size of
+ * a surface is illegal and will result in an invalid_size error.
+ *
+ * The width and height must be greater than or equal to zero. Using
+ * strictly negative values for width or height will result in a
+ * invalid_size error.
+ */
+static inline void
+xdg_toplevel_set_max_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_SET_MAX_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, width, height);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Set a minimum size for the window.
+ *
+ * The client can specify a minimum size so that the compositor does
+ * not try to configure the window below this size.
+ *
+ * The width and height arguments are in window geometry coordinates.
+ * See xdg_surface.set_window_geometry.
+ *
+ * Values set in this way are double-buffered. They will get applied
+ * on the next commit.
+ *
+ * The compositor can use this information to allow or disallow
+ * different states like maximize or fullscreen and draw accurate
+ * animations.
+ *
+ * Similarly, a tiling window manager may use this information to
+ * place and resize client windows in a more effective way.
+ *
+ * The client should not rely on the compositor to obey the minimum
+ * size. The compositor may decide to ignore the values set by the
+ * client and request a smaller size.
+ *
+ * If never set, or a value of zero in the request, means that the
+ * client has no expected minimum size in the given dimension.
+ * As a result, a client wishing to reset the minimum size
+ * to an unspecified state can use zero for width and height in the
+ * request.
+ *
+ * Requesting a minimum size to be larger than the maximum size of
+ * a surface is illegal and will result in an invalid_size error.
+ *
+ * The width and height must be greater than or equal to zero. Using
+ * strictly negative values for width and height will result in a
+ * invalid_size error.
+ */
+static inline void
+xdg_toplevel_set_min_size(struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_SET_MIN_SIZE, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, width, height);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Maximize the surface.
+ *
+ * After requesting that the surface should be maximized, the compositor
+ * will respond by emitting a configure event. Whether this configure
+ * actually sets the window maximized is subject to compositor policies.
+ * The client must then update its content, drawing in the configured
+ * state. The client must also acknowledge the configure when committing
+ * the new content (see ack_configure).
+ *
+ * It is up to the compositor to decide how and where to maximize the
+ * surface, for example which output and what region of the screen should
+ * be used.
+ *
+ * If the surface was already maximized, the compositor will still emit
+ * a configure event with the "maximized" state.
+ *
+ * If the surface is in a fullscreen state, this request has no direct
+ * effect. It may alter the state the surface is returned to when
+ * unmaximized unless overridden by the compositor.
+ */
+static inline void
+xdg_toplevel_set_maximized(struct xdg_toplevel *xdg_toplevel)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_SET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Unmaximize the surface.
+ *
+ * After requesting that the surface should be unmaximized, the compositor
+ * will respond by emitting a configure event. Whether this actually
+ * un-maximizes the window is subject to compositor policies.
+ * If available and applicable, the compositor will include the window
+ * geometry dimensions the window had prior to being maximized in the
+ * configure event. The client must then update its content, drawing it in
+ * the configured state. The client must also acknowledge the configure
+ * when committing the new content (see ack_configure).
+ *
+ * It is up to the compositor to position the surface after it was
+ * unmaximized; usually the position the surface had before maximizing, if
+ * applicable.
+ *
+ * If the surface was already not maximized, the compositor will still
+ * emit a configure event without the "maximized" state.
+ *
+ * If the surface is in a fullscreen state, this request has no direct
+ * effect. It may alter the state the surface is returned to when
+ * unmaximized unless overridden by the compositor.
+ */
+static inline void
+xdg_toplevel_unset_maximized(struct xdg_toplevel *xdg_toplevel)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_UNSET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Make the surface fullscreen.
+ *
+ * After requesting that the surface should be fullscreened, the
+ * compositor will respond by emitting a configure event. Whether the
+ * client is actually put into a fullscreen state is subject to compositor
+ * policies. The client must also acknowledge the configure when
+ * committing the new content (see ack_configure).
+ *
+ * The output passed by the request indicates the client's preference as
+ * to which display it should be set fullscreen on. If this value is NULL,
+ * it's up to the compositor to choose which display will be used to map
+ * this surface.
+ *
+ * If the surface doesn't cover the whole output, the compositor will
+ * position the surface in the center of the output and compensate with
+ * with border fill covering the rest of the output. The content of the
+ * border fill is undefined, but should be assumed to be in some way that
+ * attempts to blend into the surrounding area (e.g. solid black).
+ *
+ * If the fullscreened surface is not opaque, the compositor must make
+ * sure that other screen content not part of the same surface tree (made
+ * up of subsurfaces, popups or similarly coupled surfaces) are not
+ * visible below the fullscreened surface.
+ */
+static inline void
+xdg_toplevel_set_fullscreen(struct xdg_toplevel *xdg_toplevel, struct wl_output *output)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_SET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0, output);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Make the surface no longer fullscreen.
+ *
+ * After requesting that the surface should be unfullscreened, the
+ * compositor will respond by emitting a configure event.
+ * Whether this actually removes the fullscreen state of the client is
+ * subject to compositor policies.
+ *
+ * Making a surface unfullscreen sets states for the surface based on the following:
+ * * the state(s) it may have had before becoming fullscreen
+ * * any state(s) decided by the compositor
+ * * any state(s) requested by the client while the surface was fullscreen
+ *
+ * The compositor may include the previous window geometry dimensions in
+ * the configure event, if applicable.
+ *
+ * The client must also acknowledge the configure when committing the new
+ * content (see ack_configure).
+ */
+static inline void
+xdg_toplevel_unset_fullscreen(struct xdg_toplevel *xdg_toplevel)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_UNSET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0);
+}
+
+/**
+ * @ingroup iface_xdg_toplevel
+ *
+ * Request that the compositor minimize your surface. There is no
+ * way to know if the surface is currently minimized, nor is there
+ * any way to unset minimization on this surface.
+ *
+ * If you are looking to throttle redrawing when minimized, please
+ * instead use the wl_surface.frame event for this, as this will
+ * also work with live previews on windows in Alt-Tab, Expose or
+ * similar compositor features.
+ */
+static inline void
+xdg_toplevel_set_minimized(struct xdg_toplevel *xdg_toplevel)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel,
+ XDG_TOPLEVEL_SET_MINIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel), 0);
+}
+
+#ifndef XDG_POPUP_ERROR_ENUM
+#define XDG_POPUP_ERROR_ENUM
+enum xdg_popup_error {
+ /**
+ * tried to grab after being mapped
+ */
+ XDG_POPUP_ERROR_INVALID_GRAB = 0,
+};
+#endif /* XDG_POPUP_ERROR_ENUM */
+
+/**
+ * @ingroup iface_xdg_popup
+ * @struct xdg_popup_listener
+ */
+struct xdg_popup_listener {
+ /**
+ * configure the popup surface
+ *
+ * This event asks the popup surface to configure itself given
+ * the configuration. The configured state should not be applied
+ * immediately. See xdg_surface.configure for details.
+ *
+ * The x and y arguments represent the position the popup was
+ * placed at given the xdg_positioner rule, relative to the upper
+ * left corner of the window geometry of the parent surface.
+ *
+ * For version 2 or older, the configure event for an xdg_popup is
+ * only ever sent once for the initial configuration. Starting with
+ * version 3, it may be sent again if the popup is setup with an
+ * xdg_positioner with set_reactive requested, or in response to
+ * xdg_popup.reposition requests.
+ * @param x x position relative to parent surface window geometry
+ * @param y y position relative to parent surface window geometry
+ * @param width window geometry width
+ * @param height window geometry height
+ */
+ void (*configure)(void *data,
+ struct xdg_popup *xdg_popup,
+ int32_t x,
+ int32_t y,
+ int32_t width,
+ int32_t height);
+ /**
+ * popup interaction is done
+ *
+ * The popup_done event is sent out when a popup is dismissed by
+ * the compositor. The client should destroy the xdg_popup object
+ * at this point.
+ */
+ void (*popup_done)(void *data,
+ struct xdg_popup *xdg_popup);
+ /**
+ * signal the completion of a repositioned request
+ *
+ * The repositioned event is sent as part of a popup
+ * configuration sequence, together with xdg_popup.configure and
+ * lastly xdg_surface.configure to notify the completion of a
+ * reposition request.
+ *
+ * The repositioned event is to notify about the completion of a
+ * xdg_popup.reposition request. The token argument is the token
+ * passed in the xdg_popup.reposition request.
+ *
+ * Immediately after this event is emitted, xdg_popup.configure and
+ * xdg_surface.configure will be sent with the updated size and
+ * position, as well as a new configure serial.
+ *
+ * The client should optionally update the content of the popup,
+ * but must acknowledge the new popup configuration for the new
+ * position to take effect. See xdg_surface.ack_configure for
+ * details.
+ * @param token reposition request token
+ * @since 3
+ */
+ void (*repositioned)(void *data,
+ struct xdg_popup *xdg_popup,
+ uint32_t token);
+};
+
+/**
+ * @ingroup iface_xdg_popup
+ */
+static inline int
+xdg_popup_add_listener(struct xdg_popup *xdg_popup,
+ const struct xdg_popup_listener *listener, void *data)
+{
+ return wl_proxy_add_listener((struct wl_proxy *) xdg_popup,
+ (void (**)(void)) listener, data);
+}
+
+#define XDG_POPUP_DESTROY 0
+#define XDG_POPUP_GRAB 1
+#define XDG_POPUP_REPOSITION 2
+
+/**
+ * @ingroup iface_xdg_popup
+ */
+#define XDG_POPUP_CONFIGURE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_popup
+ */
+#define XDG_POPUP_POPUP_DONE_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_popup
+ */
+#define XDG_POPUP_REPOSITIONED_SINCE_VERSION 3
+
+/**
+ * @ingroup iface_xdg_popup
+ */
+#define XDG_POPUP_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_popup
+ */
+#define XDG_POPUP_GRAB_SINCE_VERSION 1
+/**
+ * @ingroup iface_xdg_popup
+ */
+#define XDG_POPUP_REPOSITION_SINCE_VERSION 3
+
+/** @ingroup iface_xdg_popup */
+static inline void
+xdg_popup_set_user_data(struct xdg_popup *xdg_popup, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) xdg_popup, user_data);
+}
+
+/** @ingroup iface_xdg_popup */
+static inline void *
+xdg_popup_get_user_data(struct xdg_popup *xdg_popup)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) xdg_popup);
+}
+
+static inline uint32_t
+xdg_popup_get_version(struct xdg_popup *xdg_popup)
+{
+ return wl_proxy_get_version((struct wl_proxy *) xdg_popup);
+}
+
+/**
+ * @ingroup iface_xdg_popup
+ *
+ * This destroys the popup. Explicitly destroying the xdg_popup
+ * object will also dismiss the popup, and unmap the surface.
+ *
+ * If this xdg_popup is not the "topmost" popup, the
+ * xdg_wm_base.not_the_topmost_popup protocol error will be sent.
+ */
+static inline void
+xdg_popup_destroy(struct xdg_popup *xdg_popup)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup,
+ XDG_POPUP_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_xdg_popup
+ *
+ * This request makes the created popup take an explicit grab. An explicit
+ * grab will be dismissed when the user dismisses the popup, or when the
+ * client destroys the xdg_popup. This can be done by the user clicking
+ * outside the surface, using the keyboard, or even locking the screen
+ * through closing the lid or a timeout.
+ *
+ * If the compositor denies the grab, the popup will be immediately
+ * dismissed.
+ *
+ * This request must be used in response to some sort of user action like a
+ * button press, key press, or touch down event. The serial number of the
+ * event should be passed as 'serial'.
+ *
+ * The parent of a grabbing popup must either be an xdg_toplevel surface or
+ * another xdg_popup with an explicit grab. If the parent is another
+ * xdg_popup it means that the popups are nested, with this popup now being
+ * the topmost popup.
+ *
+ * Nested popups must be destroyed in the reverse order they were created
+ * in, e.g. the only popup you are allowed to destroy at all times is the
+ * topmost one.
+ *
+ * When compositors choose to dismiss a popup, they may dismiss every
+ * nested grabbing popup as well. When a compositor dismisses popups, it
+ * will follow the same dismissing order as required from the client.
+ *
+ * If the topmost grabbing popup is destroyed, the grab will be returned to
+ * the parent of the popup, if that parent previously had an explicit grab.
+ *
+ * If the parent is a grabbing popup which has already been dismissed, this
+ * popup will be immediately dismissed. If the parent is a popup that did
+ * not take an explicit grab, an error will be raised.
+ *
+ * During a popup grab, the client owning the grab will receive pointer
+ * and touch events for all their surfaces as normal (similar to an
+ * "owner-events" grab in X11 parlance), while the top most grabbing popup
+ * will always have keyboard focus.
+ */
+static inline void
+xdg_popup_grab(struct xdg_popup *xdg_popup, struct wl_seat *seat, uint32_t serial)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup,
+ XDG_POPUP_GRAB, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), 0, seat, serial);
+}
+
+/**
+ * @ingroup iface_xdg_popup
+ *
+ * Reposition an already-mapped popup. The popup will be placed given the
+ * details in the passed xdg_positioner object, and a
+ * xdg_popup.repositioned followed by xdg_popup.configure and
+ * xdg_surface.configure will be emitted in response. Any parameters set
+ * by the previous positioner will be discarded.
+ *
+ * The passed token will be sent in the corresponding
+ * xdg_popup.repositioned event. The new popup position will not take
+ * effect until the corresponding configure event is acknowledged by the
+ * client. See xdg_popup.repositioned for details. The token itself is
+ * opaque, and has no other special meaning.
+ *
+ * If multiple reposition requests are sent, the compositor may skip all
+ * but the last one.
+ *
+ * If the popup is repositioned in response to a configure event for its
+ * parent, the client should send an xdg_positioner.set_parent_configure
+ * and possibly an xdg_positioner.set_parent_size request to allow the
+ * compositor to properly constrain the popup.
+ *
+ * If the popup is repositioned together with a parent that is being
+ * resized, but not in response to a configure event, the client should
+ * send an xdg_positioner.set_parent_size request.
+ */
+static inline void
+xdg_popup_reposition(struct xdg_popup *xdg_popup, struct xdg_positioner *positioner, uint32_t token)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) xdg_popup,
+ XDG_POPUP_REPOSITION, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_popup), 0, positioner, token);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/dwlb/zsh b/dwlb/zsh