From 0d2d3d4cb61319b847c9c2a554716d1658377ec9 Mon Sep 17 00:00:00 2001 From: q3aql Date: Sat, 26 Nov 2022 23:40:39 +0100 Subject: [PATCH] Dotfiles config update (2022-11-26) --- .config/dwl/LICENSE | 692 ++++ .config/dwl/LICENSE.dwm | 39 + .config/dwl/LICENSE.sway | 19 + .config/dwl/LICENSE.tinywl | 127 + .config/dwl/Makefile | 60 + .config/dwl/autostart.sh | 35 + .config/dwl/client.h | 337 ++ .config/dwl/config.def.h | 181 + .config/dwl/config.h | 181 + .config/dwl/config.mk | 14 + .config/dwl/dwl | Bin 0 -> 88432 bytes .config/dwl/dwl.1 | 151 + .config/dwl/dwl.c | 2913 +++++++++++++++++ .config/dwl/dwl.o | Bin 0 -> 76088 bytes .config/dwl/dwl_start.sh | 3 + .config/dwl/patch.sh | 6 + .config/dwl/patch/autostart.patch | 132 + .config/dwl/patch/cyclelayouts.patch | 68 + .config/dwl/patch/toggleKbLayout.patch | 199 ++ .config/dwl/patch/vanitygaps.patch | 343 ++ .../protocols/wlr-layer-shell-unstable-v1.xml | 390 +++ .config/dwl/scripts/checkUpdates.sh | 22 + .config/dwl/scripts/cpu_info.sh | 20 + .config/dwl/scripts/cpu_load.sh | 83 + .config/dwl/scripts/current_date.sh | 4 + .config/dwl/scripts/disk_info.sh | 3 + .config/dwl/scripts/get_volume.sh | 4 + .config/dwl/scripts/kernel_version.sh | 34 + .config/dwl/scripts/kernel_version_num.sh | 34 + .config/dwl/scripts/launch-spectrwm.sh | 23 + .config/dwl/scripts/launch.sh | 23 + .config/dwl/scripts/mem_info.sh | 47 + .config/dwl/scripts/mem_info_new.sh | 42 + .config/dwl/scripts/mem_info_old.sh | 6 + .config/dwl/scripts/status_bar.sh | 14 + .config/dwl/somebar/.builds/archlinux.yml | 19 + .config/dwl/somebar/.builds/freebsd.yml | 20 + .config/dwl/somebar/.editorconfig | 5 + .config/dwl/somebar/LICENSE | 20 + .config/dwl/somebar/README.md | 113 + .../somebar/contrib/colorless-status.patch | 15 + .../somebar/contrib/hide-vacant-tags.patch | 34 + .../contrib/indicator-size-props.patch | 54 + .config/dwl/somebar/contrib/ipc.patch | 504 +++ .config/dwl/somebar/install.sh | 7 + .config/dwl/somebar/meson.build | 31 + .config/dwl/somebar/protocols/meson.build | 22 + .../protocols/wlr-layer-shell-unstable-v1.xml | 390 +++ .config/dwl/somebar/screenshot.png | Bin 0 -> 6715 bytes .config/dwl/somebar/somebar.1 | 55 + .config/dwl/somebar/src/bar.cpp | 315 ++ .config/dwl/somebar/src/bar.hpp | 74 + .config/dwl/somebar/src/common.hpp | 70 + .config/dwl/somebar/src/config.def.hpp | 27 + .config/dwl/somebar/src/config.hpp | 28 + .config/dwl/somebar/src/line_buffer.hpp | 71 + .config/dwl/somebar/src/main.cpp | 613 ++++ .config/dwl/somebar/src/shm_buffer.cpp | 85 + .config/dwl/somebar/src/shm_buffer.hpp | 45 + .config/dwl/startscreensaver.sh | 82 + .config/dwl/startwlrrandr.sh | 12 + .config/dwl/util.c | 35 + .config/dwl/util.h | 4 + .config/dwl/util.o | Bin 0 -> 2240 bytes .../wlr-layer-shell-unstable-v1-protocol.h | 606 ++++ .config/dwl/xdg-shell-protocol.h | 1928 +++++++++++ .config/nwg-wrapper/conky_dwl.sh | 64 + 67 files changed, 11597 insertions(+) create mode 100644 .config/dwl/LICENSE create mode 100644 .config/dwl/LICENSE.dwm create mode 100644 .config/dwl/LICENSE.sway create mode 100644 .config/dwl/LICENSE.tinywl create mode 100644 .config/dwl/Makefile create mode 100755 .config/dwl/autostart.sh create mode 100644 .config/dwl/client.h create mode 100644 .config/dwl/config.def.h create mode 100644 .config/dwl/config.h create mode 100644 .config/dwl/config.mk create mode 100755 .config/dwl/dwl create mode 100644 .config/dwl/dwl.1 create mode 100644 .config/dwl/dwl.c create mode 100644 .config/dwl/dwl.o create mode 100755 .config/dwl/dwl_start.sh create mode 100755 .config/dwl/patch.sh create mode 100644 .config/dwl/patch/autostart.patch create mode 100644 .config/dwl/patch/cyclelayouts.patch create mode 100644 .config/dwl/patch/toggleKbLayout.patch create mode 100644 .config/dwl/patch/vanitygaps.patch create mode 100644 .config/dwl/protocols/wlr-layer-shell-unstable-v1.xml create mode 100755 .config/dwl/scripts/checkUpdates.sh create mode 100755 .config/dwl/scripts/cpu_info.sh create mode 100755 .config/dwl/scripts/cpu_load.sh create mode 100755 .config/dwl/scripts/current_date.sh create mode 100755 .config/dwl/scripts/disk_info.sh create mode 100755 .config/dwl/scripts/get_volume.sh create mode 100755 .config/dwl/scripts/kernel_version.sh create mode 100755 .config/dwl/scripts/kernel_version_num.sh create mode 100755 .config/dwl/scripts/launch-spectrwm.sh create mode 100755 .config/dwl/scripts/launch.sh create mode 100755 .config/dwl/scripts/mem_info.sh create mode 100755 .config/dwl/scripts/mem_info_new.sh create mode 100755 .config/dwl/scripts/mem_info_old.sh create mode 100755 .config/dwl/scripts/status_bar.sh create mode 100644 .config/dwl/somebar/.builds/archlinux.yml create mode 100644 .config/dwl/somebar/.builds/freebsd.yml create mode 100644 .config/dwl/somebar/.editorconfig create mode 100644 .config/dwl/somebar/LICENSE create mode 100644 .config/dwl/somebar/README.md create mode 100644 .config/dwl/somebar/contrib/colorless-status.patch create mode 100644 .config/dwl/somebar/contrib/hide-vacant-tags.patch create mode 100644 .config/dwl/somebar/contrib/indicator-size-props.patch create mode 100644 .config/dwl/somebar/contrib/ipc.patch create mode 100755 .config/dwl/somebar/install.sh create mode 100644 .config/dwl/somebar/meson.build create mode 100644 .config/dwl/somebar/protocols/meson.build create mode 100644 .config/dwl/somebar/protocols/wlr-layer-shell-unstable-v1.xml create mode 100644 .config/dwl/somebar/screenshot.png create mode 100644 .config/dwl/somebar/somebar.1 create mode 100644 .config/dwl/somebar/src/bar.cpp create mode 100644 .config/dwl/somebar/src/bar.hpp create mode 100644 .config/dwl/somebar/src/common.hpp create mode 100644 .config/dwl/somebar/src/config.def.hpp create mode 100644 .config/dwl/somebar/src/config.hpp create mode 100644 .config/dwl/somebar/src/line_buffer.hpp create mode 100644 .config/dwl/somebar/src/main.cpp create mode 100644 .config/dwl/somebar/src/shm_buffer.cpp create mode 100644 .config/dwl/somebar/src/shm_buffer.hpp create mode 100755 .config/dwl/startscreensaver.sh create mode 100755 .config/dwl/startwlrrandr.sh create mode 100644 .config/dwl/util.c create mode 100644 .config/dwl/util.h create mode 100644 .config/dwl/util.o create mode 100644 .config/dwl/wlr-layer-shell-unstable-v1-protocol.h create mode 100644 .config/dwl/xdg-shell-protocol.h create mode 100755 .config/nwg-wrapper/conky_dwl.sh diff --git a/.config/dwl/LICENSE b/.config/dwl/LICENSE new file mode 100644 index 0000000..658085a --- /dev/null +++ b/.config/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. + 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. + + + Copyright (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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +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: + + Copyright (C) + 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 +. + + 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 +. diff --git a/.config/dwl/LICENSE.dwm b/.config/dwl/LICENSE.dwm new file mode 100644 index 0000000..507e4dc --- /dev/null +++ b/.config/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 +© 2006-2009 Jukka Salmi +© 2006-2007 Sander van Dijk +© 2007-2011 Peter Hartlich +© 2007-2009 Szabolcs Nagy +© 2007-2009 Christof Musik +© 2007-2009 Premysl Hruby +© 2007-2008 Enno Gottox Boland +© 2008 Martin Hurton +© 2008 Neale Pickett +© 2009 Mate Nagy +© 2010-2016 Hiltjo Posthuma +© 2010-2012 Connor Lane Smith +© 2011 Christoph Lohmann <20h@r-36.net> +© 2015-2016 Quentin Rameau +© 2015-2016 Eric Pruitt +© 2016-2017 Markus Teich + +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/.config/dwl/LICENSE.sway b/.config/dwl/LICENSE.sway new file mode 100644 index 0000000..3e0cacc --- /dev/null +++ b/.config/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/.config/dwl/LICENSE.tinywl b/.config/dwl/LICENSE.tinywl new file mode 100644 index 0000000..7023690 --- /dev/null +++ b/.config/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/.config/dwl/Makefile b/.config/dwl/Makefile new file mode 100644 index 0000000..67b9780 --- /dev/null +++ b/.config/dwl/Makefile @@ -0,0 +1,60 @@ +.POSIX: +.SUFFIXES: + +include config.mk + +# flags for compiling +DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L -DWAYLAND -DVERSION=\"$(VERSION)\" $(XWAYLAND) +DWLDEVCFLAGS = -pedantic -Wall -Wextra -Wdeclaration-after-statement -Wno-unused-parameter -Wno-sign-compare -Wshadow -Wunused-macros\ + -Werror=strict-prototypes -Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types + +# CFLAGS / LDFLAGS +PKGS = wlroots wayland-server xkbcommon libinput $(XLIBS) +DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS) +LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(LIBS) + +all: dwl +dwl: dwl.o util.o + $(CC) dwl.o util.o $(LDLIBS) $(LDFLAGS) $(DWLCFLAGS) -o $@ +dwl.o: dwl.c config.mk config.h client.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h +util.o: util.c util.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` + +xdg-shell-protocol.h: + $(WAYLAND_SCANNER) server-header \ + $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ +wlr-layer-shell-unstable-v1-protocol.h: + $(WAYLAND_SCANNER) server-header \ + protocols/wlr-layer-shell-unstable-v1.xml $@ + +config.h: + cp config.def.h $@ +clean: + rm -f dwl *.o *-protocol.h + +dist: clean + mkdir -p dwl-$(VERSION) + cp -R LICENSE* Makefile README.md client.h config.def.h\ + config.mk protocols dwl.1 dwl.c util.c util.h\ + 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 +uninstall: + rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 + +.SUFFIXES: .c .o +.c.o: + $(CC) $(CPPFLAGS) $(DWLCFLAGS) -c $< diff --git a/.config/dwl/autostart.sh b/.config/dwl/autostart.sh new file mode 100755 index 0000000..9d91bf9 --- /dev/null +++ b/.config/dwl/autostart.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# Network applet +#connman-gtk --tray & +nm-applet & + +# Applet for Audio +pnmixer -t & + +# Configure screens and resolution +~/.config/dwl/startwlrrandr.sh & + +# Configure wallpaper +swaybg -i ~/wallpapers/sarosi/39.png -m fill & + +# Run terminal +kitty & + +# Configure screensaver +~/.config/dwl/startscreensaver.sh & + +# Clipboard (Diodon) +diodon & + +# Status bar +/usr/bin/somebar & + +# Load Conky +sleep 10 && nwg-wrapper -s conky_dwl.sh -r 2000 -p right -mr 15 -mt 10 -mb 80 & + +# Load Keepass +sleep 5 && keepassxc & + +# Load electronmail +sleep 3 && electron-mail & diff --git a/.config/dwl/client.h b/.config/dwl/client.h new file mode 100644 index 0000000..38330d5 --- /dev/null +++ b/.config/dwl/client.h @@ -0,0 +1,337 @@ +/* + * 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 == X11Managed || c->type == X11Unmanaged; +#else + return 0; +#endif +} + +static inline Client * +client_from_wlr_surface(struct wlr_surface *s) +{ + struct wlr_xdg_surface *surface; + +#ifdef XWAYLAND + struct wlr_xwayland_surface *xsurface; + if (s && wlr_surface_is_xwayland_surface(s) + && (xsurface = wlr_xwayland_surface_from_wlr_surface(s))) + return xsurface->data; +#endif + if (s && wlr_surface_is_xdg_surface(s) + && (surface = wlr_xdg_surface_from_wlr_surface(s)) + && surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) + return surface->data; + + if (s && wlr_surface_is_subsurface(s)) + return client_from_wlr_surface(wlr_surface_get_root_surface(s)); + return NULL; +} + +static inline Client * +client_get_parent(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c) && c->surface.xwayland->parent) + return client_from_wlr_surface(c->surface.xwayland->parent->surface); +#endif + if (c->surface.xdg->toplevel->parent) + return client_from_wlr_surface(c->surface.xdg->toplevel->parent->surface); + + return NULL; +} + +static inline void +client_get_size_hints(Client *c, struct wlr_box *max, struct wlr_box *min) +{ + struct wlr_xdg_toplevel *toplevel; + struct wlr_xdg_toplevel_state *state; +#ifdef XWAYLAND + if (client_is_x11(c)) { + struct wlr_xwayland_surface_size_hints *size_hints; + size_hints = c->surface.xwayland->size_hints; + if (size_hints) { + max->width = size_hints->max_width; + max->height = size_hints->max_height; + min->width = size_hints->min_width; + min->height = size_hints->min_height; + } + return; + } +#endif + toplevel = c->surface.xdg->toplevel; + state = &toplevel->current; + max->width = state->max_width; + max->height = state->max_height; + min->width = state->min_width; + min->height = state->min_height; +} + +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; +} + +/* The others */ +static inline void +client_activate_surface(struct wlr_surface *s, int activated) +{ + struct wlr_xdg_surface *surface; +#ifdef XWAYLAND + struct wlr_xwayland_surface *xsurface; + if (wlr_surface_is_xwayland_surface(s) + && (xsurface = wlr_xwayland_surface_from_wlr_surface(s))) { + wlr_xwayland_surface_activate(xsurface, activated); + return; + } +#endif + if (wlr_surface_is_xdg_surface(s) + && (surface = wlr_xdg_surface_from_wlr_surface(s)) + && surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) + wlr_xdg_toplevel_set_activated(surface, activated); +} + +static inline void +client_for_each_surface(Client *c, wlr_surface_iterator_func_t fn, void *data) +{ + wlr_surface_for_each_surface(client_surface(c), fn, data); +#ifdef XWAYLAND + if (client_is_x11(c)) + return; +#endif + wlr_xdg_surface_for_each_popup_surface(c->surface.xdg, fn, data); +} + +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 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 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_box min = {0}, max = {0}; + client_get_size_hints(c, &max, &min); + +#ifdef XWAYLAND + if (client_is_x11(c)) { + struct wlr_xwayland_surface *surface = c->surface.xwayland; + if (surface->modal) + return 1; + + for (size_t 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; + } +#endif + return ((min.width > 0 || min.height > 0 || max.width > 0 || max.height > 0) + && (min.width == max.width || min.height == max.height)) + || client_get_parent(c); +} + +static inline int +client_is_mapped(Client *c) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return c->surface.xwayland->mapped; +#endif + return c->surface.xdg->mapped; +} + +static inline int +client_is_unmanaged(Client *c) +{ +#ifdef XWAYLAND + return c->type == X11Unmanaged; +#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); +} + +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, 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 + return wlr_xdg_toplevel_set_size(c->surface.xdg, width, height); +} + +static inline void +client_set_tiled(Client *c, uint32_t edges) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return; +#endif + wlr_xdg_toplevel_set_tiled(c->surface.xdg, edges); +} + +static inline struct wlr_surface * +client_surface_at(Client *c, double cx, double cy, double *sx, double *sy) +{ +#ifdef XWAYLAND + if (client_is_x11(c)) + return wlr_surface_surface_at(c->surface.xwayland->surface, + cx, cy, sx, sy); +#endif + return wlr_xdg_surface_surface_at(c->surface.xdg, cx, cy, sx, sy); +} + +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; +} + +static inline void * +toplevel_from_popup(struct wlr_xdg_popup *popup) +{ + struct wlr_xdg_surface *surface = popup->base; + + while (1) { + switch (surface->role) { + case WLR_XDG_SURFACE_ROLE_POPUP: + if (!surface->popup->parent) + return NULL; + else if (wlr_surface_is_layer_surface(surface->popup->parent)) + return wlr_layer_surface_v1_from_wlr_surface(surface->popup->parent)->data; + else if (!wlr_surface_is_xdg_surface(surface->popup->parent)) + return NULL; + + surface = wlr_xdg_surface_from_wlr_surface(surface->popup->parent); + break; + case WLR_XDG_SURFACE_ROLE_TOPLEVEL: + return surface->data; + case WLR_XDG_SURFACE_ROLE_NONE: + return NULL; + } + } +} + +static inline void * +toplevel_from_wlr_layer_surface(struct wlr_surface *s) +{ + Client *c; + struct wlr_layer_surface_v1 *wlr_layer_surface; + + if ((c = client_from_wlr_surface(s))) + return c; + else if (s && wlr_surface_is_layer_surface(s) + && (wlr_layer_surface = wlr_layer_surface_v1_from_wlr_surface(s))) + return wlr_layer_surface->data; + + return NULL; +} diff --git a/.config/dwl/config.def.h b/.config/dwl/config.def.h new file mode 100644 index 0000000..f25dcf7 --- /dev/null +++ b/.config/dwl/config.def.h @@ -0,0 +1,181 @@ +/* appearance */ +static const int sloppyfocus = 1; /* focus follows mouse */ +static const unsigned int borderpx = 1; /* border pixel of windows */ +static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ +static const unsigned int gappih = 10; /* horiz inner gap between windows */ +static const unsigned int gappiv = 10; /* vert inner gap between windows */ +static const unsigned int gappoh = 10; /* horiz outer gap between windows and screen edge */ +static const unsigned int gappov = 10; /* vert outer gap between windows and screen edge */ +static const int smartgaps = 0; /* 1 means no outer gap when there is only one window */ +static const int monoclegaps = 0; /* 1 means outer gaps in monocle layout */ +static const float rootcolor[] = {0.3, 0.3, 0.3, 1.0}; +static const float bordercolor[] = {0.5, 0.5, 0.5, 1.0}; +static const float focuscolor[] = {1.0, 0.0, 0.0, 1.0}; +/* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */ +static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; + +/* tagging */ +static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + +static const Rule rules[] = { + /* app_id title tags mask isfloating monitor */ + /* examples: + { "Gimp", NULL, 0, 1, -1 }, + */ + { "firefox", NULL, 1 << 8, 0, -1 }, +}; + +/* layout(s) */ +static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, +}; + +/* monitors */ +static const MonitorRule monrules[] = { + /* name mfact nmaster scale layout rotate/reflect */ + /* example of a HiDPI laptop monitor: + { "eDP-1", 0.5, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL }, + */ + /* defaults */ + { NULL, 0.55, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL }, +}; + +/* keyboard */ +static const struct xkb_rule_names xkb_rules = { + /* can specify fields: rules, model, layout, variant, options */ + /* example: + .options = "ctrl:nocaps", + */ + .options = NULL, +}; + +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.0; + +/* Autostart */ +static const char *const autostart[] = { + "sh", "-c", "swaybg --image /xap/local/background", NULL, + NULL /* terminate */ +}; + +/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */ +#define MODKEY WLR_MODIFIER_LOGO + +#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[] = { "kitty", NULL }; +static const char *menucmd[] = { "dmenu_run", 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|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} }, + { MODKEY, XKB_KEY_j, focusstack, {.i = +1} }, + { MODKEY, XKB_KEY_k, focusstack, {.i = -1} }, + { MODKEY, XKB_KEY_i, incnmaster, {.i = +1} }, + { MODKEY, XKB_KEY_d, incnmaster, {.i = -1} }, + { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05} }, + { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05} }, + { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_h, incgaps, {.i = +1 } }, + { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_l, incgaps, {.i = -1 } }, + { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_H, incogaps, {.i = +1 } }, + { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_L, incogaps, {.i = -1 } }, + { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_CTRL, XKB_KEY_h, incigaps, {.i = +1 } }, + { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_CTRL, XKB_KEY_l, incigaps, {.i = -1 } }, + { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_0, togglegaps, {0} }, + { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_parenright,defaultgaps, {0} }, + { MODKEY, XKB_KEY_y, incihgaps, {.i = +1 } }, + { MODKEY, XKB_KEY_o, incihgaps, {.i = -1 } }, + { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_y, incivgaps, {.i = +1 } }, + { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_o, incivgaps, {.i = -1 } }, + { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_y, incohgaps, {.i = +1 } }, + { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_o, incohgaps, {.i = -1 } }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Y, incovgaps, {.i = +1 } }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_O, incovgaps, {.i = -1 } }, + { MODKEY, 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[0]} }, + { MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} }, + { MODKEY, XKB_KEY_space, setlayout, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, + { MODKEY, XKB_KEY_e, 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} }, +#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/.config/dwl/config.h b/.config/dwl/config.h new file mode 100644 index 0000000..2f6ec70 --- /dev/null +++ b/.config/dwl/config.h @@ -0,0 +1,181 @@ +/* appearance */ +static const int sloppyfocus = 1; /* focus follows mouse */ +static const unsigned int borderpx = 1; /* border pixel of windows */ +static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ +static const unsigned int gappih = 10; /* horiz inner gap between windows */ +static const unsigned int gappiv = 10; /* vert inner gap between windows */ +static const unsigned int gappoh = 10; /* horiz outer gap between windows and screen edge */ +static const unsigned int gappov = 10; /* vert outer gap between windows and screen edge */ +static const int smartgaps = 0; /* 1 means no outer gap when there is only one window */ +static const int monoclegaps = 0; /* 1 means outer gaps in monocle layout */ +static const float rootcolor[] = {0.3, 0.3, 0.3, 1.0}; +static const float bordercolor[] = {0.5, 0.5, 0.5, 1.0}; +static const float focuscolor[] = {1.0, 0.0, 0.0, 1.0}; +/* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */ +static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; + +/* tagging */ +static const char *tags[] = { "term", "www", "chat", "files", "media", "game", "mail", "dev", "vm" }; + +static const Rule rules[] = { + /* app_id title tags mask isfloating monitor */ + /* examples: + { "Gimp", NULL, 0, 1, -1 }, + */ + { "firefox", NULL, 1 << 8, 0, -1 }, +}; + +/* layout(s) */ +static const Layout layouts[] = { + /* symbol arrange function */ + { "[]=", tile }, + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, +}; + +/* monitors */ +static const MonitorRule monrules[] = { + /* name mfact nmaster scale layout rotate/reflect */ + /* example of a HiDPI laptop monitor: + { "eDP-1", 0.5, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL }, + */ + /* defaults */ + { NULL, 0.55, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL }, +}; + +/* keyboard */ +static const struct xkb_rule_names xkb_rules = { + /* can specify fields: rules, model, layout, variant, options */ + /* example: + .options = "ctrl:nocaps", + */ + .options = NULL, +}; + +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.0; + +/* Autostart */ +static const char *const autostart[] = { + "sh", "-c", "bash ~/.config/dwl/autostart.sh", NULL, + NULL /* terminate */ +}; + +/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */ +#define MODKEY WLR_MODIFIER_LOGO + +#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[] = { "kitty", NULL }; +static const char *menucmd[] = { "wofi --show run", 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|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} }, + { MODKEY, XKB_KEY_j, focusstack, {.i = +1} }, + { MODKEY, XKB_KEY_k, focusstack, {.i = -1} }, + { MODKEY, XKB_KEY_i, incnmaster, {.i = +1} }, + { MODKEY, XKB_KEY_d, incnmaster, {.i = -1} }, + { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05} }, + { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05} }, + { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_h, incgaps, {.i = +1 } }, + { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_l, incgaps, {.i = -1 } }, + { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_H, incogaps, {.i = +1 } }, + { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_L, incogaps, {.i = -1 } }, + { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_CTRL, XKB_KEY_h, incigaps, {.i = +1 } }, + { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_CTRL, XKB_KEY_l, incigaps, {.i = -1 } }, + { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_0, togglegaps, {0} }, + { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_parenright,defaultgaps, {0} }, + { MODKEY, XKB_KEY_y, incihgaps, {.i = +1 } }, + { MODKEY, XKB_KEY_o, incihgaps, {.i = -1 } }, + { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_y, incivgaps, {.i = +1 } }, + { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_o, incivgaps, {.i = -1 } }, + { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_y, incohgaps, {.i = +1 } }, + { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_o, incohgaps, {.i = -1 } }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Y, incovgaps, {.i = +1 } }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_O, incovgaps, {.i = -1 } }, + { MODKEY, XKB_KEY_Return, zoom, {0} }, + { MODKEY, XKB_KEY_Tab, view, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Q, killclient, {0} }, + { MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} }, + { MODKEY, XKB_KEY_space, setlayout, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, + { MODKEY, XKB_KEY_e, 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_E, 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} }, +#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/.config/dwl/config.mk b/.config/dwl/config.mk new file mode 100644 index 0000000..c715468 --- /dev/null +++ b/.config/dwl/config.mk @@ -0,0 +1,14 @@ +_VERSION = 0.3.1-dev +VERSION = `git describe --long --tags --dirty 2>/dev/null || echo $(_VERSION)` + +PKG_CONFIG = pkg-config + +# paths +PREFIX = /usr/ +MANDIR = $(PREFIX)/share/man + +XWAYLAND = +XLIBS = +# Uncomment to build XWayland support +#XWAYLAND = -DXWAYLAND +#XLIBS = xcb diff --git a/.config/dwl/dwl b/.config/dwl/dwl new file mode 100755 index 0000000000000000000000000000000000000000..103eb3ad34187bbde33f0793a5b731b680d2a51e GIT binary patch literal 88432 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
    Mw%qzc43vf>+M#p^p6w~yn^I}E2 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 literal 0 HcmV?d00001 diff --git a/.config/dwl/dwl.1 b/.config/dwl/dwl.1 new file mode 100644 index 0000000..d958210 --- /dev/null +++ b/.config/dwl/dwl.1 @@ -0,0 +1,151 @@ +.Dd January 8, 2021 +.Dt DWL 1 +.Os +.Sh NAME +.Nm dwl +.Nd dwm for Wayland +.Sh SYNOPSIS +.Nm +.Op Fl v +.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 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 alacritty . +.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 containung 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 alacritty 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/.config/dwl/dwl.c b/.config/dwl/dwl.c new file mode 100644 index 0000000..0ae28aa --- /dev/null +++ b/.config/dwl/dwl.c @@ -0,0 +1,2913 @@ +/* + * See LICENSE file for copyright and license details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef XWAYLAND +#include +#include +#endif + +#include "util.h" + +/* macros */ +#define MAX(A, B) ((A) > (B) ? (A) : (B)) +#define MIN(A, B) ((A) < (B) ? (A) : (B)) +#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 ((1 << LENGTH(tags)) - 1) +#define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) + +/* enums */ +enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ +enum { XDGShell, LayerShell, X11Managed, X11Unmanaged }; /* client types */ +enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrDragIcon, NUM_LAYERS }; /* scene layers */ +#ifdef XWAYLAND +enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, + NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ +#endif + +typedef union { + int i; + unsigned int 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 { + /* 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_node *scene; + struct wlr_scene_rect *border[4]; /* top, bottom, left, right */ + struct wlr_scene_node *scene_surface; + struct wlr_scene_rect *fullscreen_bg; /* See setfullscreen() for info */ + struct wl_list link; + struct wl_list flink; + union { + struct wlr_xdg_surface *xdg; + struct wlr_xwayland_surface *xwayland; + } surface; + struct wl_listener commit; + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener destroy; + struct wl_listener set_title; + struct wl_listener fullscreen; + struct wlr_box prev; /* layout-relative, includes border */ +#ifdef XWAYLAND + struct wl_listener activate; + struct wl_listener configure; + struct wl_listener set_hints; +#endif + unsigned int bw; + unsigned int tags; + int isfloating, isurgent, isfullscreen; + uint32_t resize; /* configure serial of a pending resize */ +} Client; + +typedef struct { + uint32_t singular_anchor; + uint32_t anchor_triplet; + int *positive_axis; + int *negative_axis; + int margin; +} Edge; + +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_input_device *device; + + struct wl_listener modifiers; + struct wl_listener key; + struct wl_listener destroy; +} Keyboard; + +typedef struct { + /* Must keep these three elements in this order */ + unsigned int type; /* LayerShell */ + struct wlr_box geom; + Monitor *mon; + struct wlr_scene_node *scene; + struct wlr_scene_node *popups; + 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 wlr_output *wlr_output; + struct wlr_scene_output *scene_output; + struct wl_listener frame; + struct wl_listener destroy; + 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]; + int gappih; /* horizontal gap between windows */ + int gappiv; /* vertical gap between windows */ + int gappoh; /* horizontal outer gaps */ + int gappov; /* vertical outer gaps */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; + double mfact; + int nmaster; + int un_map; /* If a map/unmap happened on this monitor, then this should be true */ +}; + +typedef struct { + const char *name; + float mfact; + int nmaster; + float scale; + const Layout *lt; + enum wl_output_transform rr; +} MonitorRule; + +typedef struct { + const char *id; + const char *title; + unsigned int tags; + int isfloating; + int monitor; +} Rule; + +/* function declarations */ +static void applybounds(Client *c, struct wlr_box *bbox); +static void applyexclusive(struct wlr_box *usable_area, uint32_t anchor, + int32_t exclusive, int32_t margin_top, int32_t margin_right, + int32_t margin_bottom, int32_t margin_left); +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 autostartexec(void); +static void axisnotify(struct wl_listener *listener, void *data); +static void buttonpress(struct wl_listener *listener, void *data); +static void chvt(const Arg *arg); +static void checkidleinhibitor(struct wlr_surface *exclude); +static void cleanup(void); +static void cleanupkeyboard(struct wl_listener *listener, void *data); +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 createidleinhibitor(struct wl_listener *listener, void *data); +static void createkeyboard(struct wlr_input_device *device); +static void createlayersurface(struct wl_listener *listener, void *data); +static void createmon(struct wl_listener *listener, void *data); +static void createnotify(struct wl_listener *listener, void *data); +static void createpointer(struct wlr_input_device *device); +static void cursorframe(struct wl_listener *listener, void *data); +static void defaultgaps(const Arg *arg); +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 destroynotify(struct wl_listener *listener, void *data); +static Monitor *dirtomon(enum wlr_direction dir); +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 incnmaster(const Arg *arg); +static void incgaps(const Arg *arg); +static void incigaps(const Arg *arg); +static void incihgaps(const Arg *arg); +static void incivgaps(const Arg *arg); +static void incogaps(const Arg *arg); +static void incohgaps(const Arg *arg); +static void incovgaps(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 void killclient(const Arg *arg); +static void maplayersurfacenotify(struct wl_listener *listener, void *data); +static void mapnotify(struct wl_listener *listener, void *data); +static void monocle(Monitor *m); +static void motionabsolute(struct wl_listener *listener, void *data); +static void motionnotify(uint32_t time); +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 quitsignal(int signo); +static void rendermon(struct wl_listener *listener, void *data); +static void requeststartdrag(struct wl_listener *listener, void *data); +static void resize(Client *c, struct wlr_box geo, int interact); +static void run(char *startup_cmd); +static Client *selclient(void); +static void setcursor(struct wl_listener *listener, void *data); +static void setfloating(Client *c, int floating); +static void setfullscreen(Client *c, int fullscreen); +static void setgaps(int oh, int ov, int ih, int iv); +static void setlayout(const Arg *arg); +static void setmfact(const Arg *arg); +static void setmon(Client *c, Monitor *m, unsigned int 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 sigchld(int unused); +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 togglefloating(const Arg *arg); +static void togglefullscreen(const Arg *arg); +static void togglegaps(const Arg *arg); +static void toggletag(const Arg *arg); +static void toggleview(const Arg *arg); +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 Monitor *xytomon(double x, double y); +static struct wlr_scene_node *xytonode(double x, double y, struct wlr_surface **psurface, + Client **pc, LayerSurface **pl, double *nx, double *ny); +static void zoom(const Arg *arg); + +/* variables */ +static const char broken[] = "broken"; +static const char *cursor_image = "left_ptr"; +static pid_t child_pid = -1; +static void *exclusive_focus; +static struct wl_display *dpy; +static struct wlr_backend *backend; +static struct wlr_scene *scene; +static struct wlr_scene_node *layers[NUM_LAYERS]; +static struct wlr_renderer *drw; +static struct wlr_allocator *alloc; +static struct wlr_compositor *compositor; + +static struct wlr_xdg_shell *xdg_shell; +static struct wlr_xdg_activation_v1 *activation; +static struct wl_list clients; /* tiling order */ +static struct wl_list fstack; /* focus order */ +static struct wlr_idle *idle; +static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr; +static struct wlr_input_inhibit_manager *input_inhibit_mgr; +static struct wlr_layer_shell_v1 *layer_shell; +static struct wlr_output_manager_v1 *output_mgr; +static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; + +static struct wlr_cursor *cursor; +static struct wlr_xcursor_manager *cursor_mgr; + +static struct wlr_seat *seat; +static struct wl_list keyboards; +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 int enablegaps = 1; /* enables gaps, used by togglegaps */ + +/* global event handlers */ +static struct wl_listener cursor_axis = {.notify = axisnotify}; +static struct wl_listener cursor_button = {.notify = buttonpress}; +static struct wl_listener cursor_frame = {.notify = cursorframe}; +static struct wl_listener cursor_motion = {.notify = motionrelative}; +static struct wl_listener cursor_motion_absolute = {.notify = motionabsolute}; +static struct wl_listener drag_icon_destroy = {.notify = destroydragicon}; +static struct wl_listener idle_inhibitor_create = {.notify = createidleinhibitor}; +static struct wl_listener idle_inhibitor_destroy = {.notify = destroyidleinhibitor}; +static struct wl_listener layout_change = {.notify = updatemons}; +static struct wl_listener new_input = {.notify = inputdevice}; +static struct wl_listener new_virtual_keyboard = {.notify = virtualkeyboard}; +static struct wl_listener new_output = {.notify = createmon}; +static struct wl_listener new_xdg_surface = {.notify = createnotify}; +static struct wl_listener new_layer_shell_surface = {.notify = createlayersurface}; +static struct wl_listener output_mgr_apply = {.notify = outputmgrapply}; +static struct wl_listener output_mgr_test = {.notify = outputmgrtest}; +static struct wl_listener request_activate = {.notify = urgent}; +static struct wl_listener request_cursor = {.notify = setcursor}; +static struct wl_listener request_set_psel = {.notify = setpsel}; +static struct wl_listener request_set_sel = {.notify = setsel}; +static struct wl_listener request_start_drag = {.notify = requeststartdrag}; +static struct wl_listener start_drag = {.notify = startdrag}; + +#ifdef XWAYLAND +static void activatex11(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 Atom 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 wl_listener new_xwayland_surface = {.notify = createnotifyx11}; +static struct wl_listener xwayland_ready = {.notify = xwaylandready}; +static struct wlr_xwayland *xwayland; +static Atom netatom[NetLast]; +#endif + +/* configuration, allows nested code to access above variables */ +#include "config.h" + +/* attempt to encapsulate suck into one file */ +#include "client.h" + +/* compile-time check if all tags fit into an unsigned int bit array. */ +struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +static pid_t *autostart_pids; +static size_t autostart_len; + +/* function implementations */ +void +applybounds(Client *c, struct wlr_box *bbox) +{ + if (!c->isfullscreen) { + struct wlr_box min = {0}, max = {0}; + client_get_size_hints(c, &max, &min); + /* try to set size hints */ + c->geom.width = MAX(min.width + (2 * (int)c->bw), c->geom.width); + c->geom.height = MAX(min.height + (2 * (int)c->bw), c->geom.height); + /* Some clients set them max size to INT_MAX, which does not violates + * the protocol but its innecesary, they can set them max size to zero. */ + if (max.width > 0 && !(2 * c->bw > INT_MAX - max.width)) /* Checks for overflow */ + c->geom.width = MIN(max.width + (2 * c->bw), c->geom.width); + if (max.height > 0 && !(2 * c->bw > INT_MAX - max.height)) /* Checks for overflow */ + c->geom.height = MIN(max.height + (2 * 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 * c->bw <= bbox->x) + c->geom.x = bbox->x; + if (c->geom.y + c->geom.height + 2 * c->bw <= bbox->y) + c->geom.y = bbox->y; +} + +void +autostartexec(void) { + const char *const *p; + size_t i = 0; + + /* count entries */ + for (p = autostart; *p; autostart_len++, p++) + while (*++p); + + autostart_pids = calloc(autostart_len, sizeof(pid_t)); + for (p = autostart; *p; i++, p++) { + if ((autostart_pids[i] = fork()) == 0) { + setsid(); + execvp(*p, (char *const *)p); + fprintf(stderr, "dwl: execvp %s\n", *p); + perror(" failed"); + _exit(EXIT_FAILURE); + } + /* skip arguments */ + while (*++p); + } +} + +void +applyexclusive(struct wlr_box *usable_area, + uint32_t anchor, int32_t exclusive, + int32_t margin_top, int32_t margin_right, + int32_t margin_bottom, int32_t margin_left) { + size_t i; + Edge edges[] = { + { /* Top */ + .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, + .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, + .positive_axis = &usable_area->y, + .negative_axis = &usable_area->height, + .margin = margin_top, + }, + { /* Bottom */ + .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, + .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, + .positive_axis = NULL, + .negative_axis = &usable_area->height, + .margin = margin_bottom, + }, + { /* Left */ + .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT, + .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, + .positive_axis = &usable_area->x, + .negative_axis = &usable_area->width, + .margin = margin_left, + }, + { /* Right */ + .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, + .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, + .positive_axis = NULL, + .negative_axis = &usable_area->width, + .margin = margin_right, + } + }; + for (i = 0; i < LENGTH(edges); i++) { + if ((anchor == edges[i].singular_anchor || anchor == edges[i].anchor_triplet) + && exclusive + edges[i].margin > 0) { + if (edges[i].positive_axis) + *edges[i].positive_axis += exclusive + edges[i].margin; + if (edges[i].negative_axis) + *edges[i].negative_axis -= exclusive + edges[i].margin; + break; + } + } +} + +void +applyrules(Client *c) +{ + /* rule matching */ + const char *appid, *title; + unsigned int i, newtags = 0; + 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; + + for (r = rules; r < END(rules); r++) { + if ((!r->title || strstr(title, r->title)) + && (!r->id || strstr(appid, r->id))) { + c->isfloating = r->isfloating; + newtags |= r->tags; + i = 0; + wl_list_for_each(m, &mons, link) + if (r->monitor == i++) + mon = m; + } + } + wlr_scene_node_reparent(c->scene, layers[c->isfloating ? LyrFloat : LyrTile]); + setmon(c, mon, newtags); +} + +void +arrange(Monitor *m) +{ + Client *c; + wl_list_for_each(c, &clients, link) + if (c->mon == m) + wlr_scene_node_set_enabled(c->scene, VISIBLEON(c, m)); + + if (m && m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); + motionnotify(0); +} + +void +arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int exclusive) +{ + LayerSurface *layersurface; + struct wlr_box full_area = m->m; + + wl_list_for_each(layersurface, list, link) { + struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; + struct wlr_layer_surface_v1_state *state = &wlr_layer_surface->current; + struct wlr_box bounds; + struct wlr_box box = { + .width = state->desired_width, + .height = state->desired_height + }; + const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT + | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; + const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP + | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; + + /* Unmapped surfaces shouldn't have exclusive zone */ + if (!((LayerSurface *)wlr_layer_surface->data)->mapped + || exclusive != (state->exclusive_zone > 0)) + continue; + + bounds = state->exclusive_zone == -1 ? full_area : *usable_area; + + /* Horizontal axis */ + if ((state->anchor & both_horiz) && box.width == 0) { + box.x = bounds.x; + box.width = bounds.width; + } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { + box.x = bounds.x; + } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { + box.x = bounds.x + (bounds.width - box.width); + } else { + box.x = bounds.x + ((bounds.width / 2) - (box.width / 2)); + } + /* Vertical axis */ + if ((state->anchor & both_vert) && box.height == 0) { + box.y = bounds.y; + box.height = bounds.height; + } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { + box.y = bounds.y; + } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { + box.y = bounds.y + (bounds.height - box.height); + } else { + box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); + } + /* Margin */ + if ((state->anchor & both_horiz) == both_horiz) { + box.x += state->margin.left; + box.width -= state->margin.left + state->margin.right; + } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { + box.x += state->margin.left; + } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { + box.x -= state->margin.right; + } + if ((state->anchor & both_vert) == both_vert) { + box.y += state->margin.top; + box.height -= state->margin.top + state->margin.bottom; + } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { + box.y += state->margin.top; + } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { + box.y -= state->margin.bottom; + } + if (box.width < 0 || box.height < 0) { + wlr_layer_surface_v1_destroy(wlr_layer_surface); + continue; + } + layersurface->geom = box; + + if (state->exclusive_zone > 0) + applyexclusive(usable_area, state->anchor, state->exclusive_zone, + state->margin.top, state->margin.right, + state->margin.bottom, state->margin.left); + wlr_scene_node_set_position(layersurface->scene, box.x, box.y); + wlr_scene_node_set_position(layersurface->popups, box.x, box.y); + wlr_layer_surface_v1_configure(wlr_layer_surface, box.width, box.height); + } +} + +void +arrangelayers(Monitor *m) +{ + int i; + struct wlr_box usable_area = m->m; + uint32_t layers_above_shell[] = { + ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, + ZWLR_LAYER_SHELL_V1_LAYER_TOP, + }; + LayerSurface *layersurface; + 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 (memcmp(&usable_area, &m->w, sizeof(struct wlr_box))) { + 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 < LENGTH(layers_above_shell); i++) { + wl_list_for_each_reverse(layersurface, + &m->layers[layers_above_shell[i]], link) { + if (layersurface->layer_surface->current.keyboard_interactive && + layersurface->mapped) { + /* Deactivate the focused client. */ + focusclient(NULL, 0); + exclusive_focus = layersurface; + client_notify_enter(layersurface->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_event_pointer_axis *event = data; + wlr_idle_notify_activity(idle, 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_event_pointer_button *event = data; + struct wlr_keyboard *keyboard; + uint32_t mods; + Client *c; + const Button *b; + + wlr_idle_notify_activity(idle, seat); + + switch (event->state) { + case WLR_BUTTON_PRESSED: + /* 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; + } + } + cursor_mode = CurPressed; + break; + case WLR_BUTTON_RELEASED: + /* If you released any buttons, we exit interactive move/resize mode. */ + if (cursor_mode != CurNormal && cursor_mode != CurPressed) { + cursor_mode = CurNormal; + /* Clear the pointer focus, this way if the cursor is over a surface + * we will send an enter event after which the client will provide us + * a cursor surface */ + wlr_seat_pointer_clear_focus(seat); + motionnotify(0); + /* 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 +chvt(const Arg *arg) +{ + wlr_session_change_vt(wlr_backend_get_session(backend), arg->ui); +} + +void +checkidleinhibitor(struct wlr_surface *exclude) +{ + int inhibited = 0; + struct wlr_idle_inhibitor_v1 *inhibitor; + wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { + Client *c; + if (exclude == inhibitor->surface) + continue; + /* In case we can't get a client from the surface assume that it is + * visible, for example a layer surface */ + if (!(c = client_from_wlr_surface(inhibitor->surface)) + || VISIBLEON(c, c->mon)) { + inhibited = 1; + break; + } + } + + wlr_idle_set_enabled(idle, NULL, !inhibited); +} + +void +cleanup(void) +{ +#ifdef XWAYLAND + wlr_xwayland_destroy(xwayland); +#endif + wl_display_destroy_clients(dpy); + if (child_pid > 0) { + kill(child_pid, SIGTERM); + waitpid(child_pid, NULL, 0); + } + wlr_backend_destroy(backend); + wlr_renderer_destroy(drw); + wlr_allocator_destroy(alloc); + wlr_xcursor_manager_destroy(cursor_mgr); + wlr_cursor_destroy(cursor); + wlr_output_layout_destroy(output_layout); + wlr_seat_destroy(seat); + wl_display_destroy(dpy); +} + +void +cleanupkeyboard(struct wl_listener *listener, void *data) +{ + Keyboard *kb = wl_container_of(listener, kb, destroy); + + wl_list_remove(&kb->link); + wl_list_remove(&kb->modifiers.link); + wl_list_remove(&kb->key.link); + wl_list_remove(&kb->destroy.link); + free(kb); +} + +void +cleanupmon(struct wl_listener *listener, void *data) +{ + Monitor *m = wl_container_of(listener, m, destroy); + LayerSurface *l, *tmp; + int i; + + for (i = 0; i <= ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; i++) { + wl_list_for_each_safe(l, tmp, &m->layers[i], link) { + wlr_scene_node_set_enabled(l->scene, 0); + 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); + m->wlr_output->data = NULL; + wlr_output_layout_remove(output_layout, m->wlr_output); + wlr_scene_output_destroy(m->scene_output); + + closemon(m); + free(m); +} + +void +closemon(Monitor *m) +{ + /* update selmon if needed and + * move closed monitor's clients to the focused one */ + Client *c; + if (wl_list_empty(&mons)) { + selmon = NULL; + } else if (m == selmon) { + int nmons = wl_list_length(&mons), i = 0; + 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 *layersurface = wl_container_of(listener, layersurface, surface_commit); + struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; + struct wlr_output *wlr_output = wlr_layer_surface->output; + + /* For some reason this layersurface have no monitor, this can be because + * its monitor has just been destroyed */ + if (!wlr_output || !(layersurface->mon = wlr_output->data)) + return; + + if (layers[wlr_layer_surface->current.layer] != layersurface->scene->parent) { + wlr_scene_node_reparent(layersurface->scene, + layers[wlr_layer_surface->current.layer]); + wlr_scene_node_reparent(layersurface->popups, + layers[wlr_layer_surface->current.layer]); + wl_list_remove(&layersurface->link); + wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->current.layer], + &layersurface->link); + } + if (wlr_layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) + wlr_scene_node_reparent(layersurface->popups, layers[LyrTop]); + + if (wlr_layer_surface->current.committed == 0 + && layersurface->mapped == wlr_layer_surface->mapped) + return; + layersurface->mapped = wlr_layer_surface->mapped; + + arrangelayers(layersurface->mon); +} + +void +commitnotify(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, commit); + struct wlr_box box = {0}; + client_get_geometry(c, &box); + + if (c->mon && !wlr_box_empty(&box) && (box.width != c->geom.width - 2 * c->bw + || box.height != c->geom.height - 2 * c->bw)) + arrange(c->mon); + + /* mark a pending resize as completed */ + if (c->resize && (c->resize <= c->surface.xdg->current.configure_serial + || (c->surface.xdg->current.geometry.width == c->surface.xdg->pending.geometry.width + && c->surface.xdg->current.geometry.height == c->surface.xdg->pending.geometry.height))) + c->resize = 0; +} + +void +createidleinhibitor(struct wl_listener *listener, void *data) +{ + struct wlr_idle_inhibitor_v1 *idle_inhibitor = data; + wl_signal_add(&idle_inhibitor->events.destroy, &idle_inhibitor_destroy); + + checkidleinhibitor(NULL); +} + +void +createkeyboard(struct wlr_input_device *device) +{ + struct xkb_context *context; + struct xkb_keymap *keymap; + Keyboard *kb = device->data = ecalloc(1, sizeof(*kb)); + kb->device = device; + + /* Prepare an XKB keymap and assign it to the keyboard. */ + context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + keymap = xkb_keymap_new_from_names(context, &xkb_rules, + XKB_KEYMAP_COMPILE_NO_FLAGS); + + wlr_keyboard_set_keymap(device->keyboard, keymap); + xkb_keymap_unref(keymap); + xkb_context_unref(context); + wlr_keyboard_set_repeat_info(device->keyboard, repeat_rate, repeat_delay); + + /* Here we set up listeners for keyboard events. */ + LISTEN(&device->keyboard->events.modifiers, &kb->modifiers, keypressmod); + LISTEN(&device->keyboard->events.key, &kb->key, keypress); + LISTEN(&device->events.destroy, &kb->destroy, cleanupkeyboard); + + wlr_seat_set_keyboard(seat, device); + + /* And add the keyboard to our list of keyboards */ + wl_list_insert(&keyboards, &kb->link); +} + +void +createlayersurface(struct wl_listener *listener, void *data) +{ + struct wlr_layer_surface_v1 *wlr_layer_surface = data; + LayerSurface *layersurface; + struct wlr_layer_surface_v1_state old_state; + + if (!wlr_layer_surface->output) + wlr_layer_surface->output = selmon ? selmon->wlr_output : NULL; + + if (!wlr_layer_surface->output) + wlr_layer_surface_v1_destroy(wlr_layer_surface); + + layersurface = ecalloc(1, sizeof(LayerSurface)); + layersurface->type = LayerShell; + LISTEN(&wlr_layer_surface->surface->events.commit, + &layersurface->surface_commit, commitlayersurfacenotify); + LISTEN(&wlr_layer_surface->events.destroy, &layersurface->destroy, + destroylayersurfacenotify); + LISTEN(&wlr_layer_surface->events.map, &layersurface->map, + maplayersurfacenotify); + LISTEN(&wlr_layer_surface->events.unmap, &layersurface->unmap, + unmaplayersurfacenotify); + + layersurface->layer_surface = wlr_layer_surface; + layersurface->mon = wlr_layer_surface->output->data; + wlr_layer_surface->data = layersurface; + + layersurface->scene = wlr_scene_subsurface_tree_create( + layers[wlr_layer_surface->pending.layer], wlr_layer_surface->surface); + layersurface->scene->data = layersurface; + layersurface->popups = wlr_layer_surface->surface->data = + &wlr_scene_tree_create(layers[wlr_layer_surface->pending.layer])->node; + + wl_list_insert(&layersurface->mon->layers[wlr_layer_surface->pending.layer], + &layersurface->link); + + /* Temporarily set the layer's current state to pending + * so that we can easily arrange it + */ + old_state = wlr_layer_surface->current; + wlr_layer_surface->current = wlr_layer_surface->pending; + layersurface->mapped = 1; + arrangelayers(layersurface->mon); + wlr_layer_surface->current = old_state; +} + +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; + Monitor *m = wlr_output->data = ecalloc(1, sizeof(*m)); + m->wlr_output = wlr_output; + + wlr_output_init_render(wlr_output, alloc, drw); + + /* Initialize monitor state using configured rules */ + for (i = 0; i < LENGTH(m->layers); i++) + wl_list_init(&m->layers[i]); + + m->gappih = gappih; + m->gappiv = gappiv; + m->gappoh = gappoh; + m->gappov = gappov; + m->tagset[0] = m->tagset[1] = 1; + for (r = monrules; r < END(monrules); r++) { + if (!r->name || strstr(wlr_output->name, r->name)) { + m->mfact = r->mfact; + m->nmaster = r->nmaster; + wlr_output_set_scale(wlr_output, r->scale); + wlr_xcursor_manager_load(cursor_mgr, r->scale); + m->lt[0] = m->lt[1] = r->lt; + wlr_output_set_transform(wlr_output, 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_set_mode(wlr_output, wlr_output_preferred_mode(wlr_output)); + wlr_output_enable_adaptive_sync(wlr_output, 1); + + /* Set up event listeners */ + LISTEN(&wlr_output->events.frame, &m->frame, rendermon); + LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon); + + wlr_output_enable(wlr_output, 1); + if (!wlr_output_commit(wlr_output)) + return; + + wl_list_insert(&mons, &m->link); + printstatus(); + + /* 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); + wlr_output_layout_add_auto(output_layout, wlr_output); +} + +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; + + if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { + struct wlr_box box; + LayerSurface *l = toplevel_from_popup(xdg_surface->popup); + if (!xdg_surface->popup->parent) + return; + xdg_surface->surface->data = wlr_scene_xdg_surface_create( + xdg_surface->popup->parent->data, xdg_surface); + /* Probably the check of `l` is useless, the only thing that can be NULL + * is its monitor */ + if (!l || !l->mon) + return; + box = l->type == LayerShell ? l->mon->m : l->mon->w; + box.x -= l->geom.x; + box.y -= l->geom.y; + wlr_xdg_popup_unconstrain_from_box(xdg_surface->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; + + LISTEN(&xdg_surface->events.map, &c->map, mapnotify); + LISTEN(&xdg_surface->events.unmap, &c->unmap, unmapnotify); + LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify); + LISTEN(&xdg_surface->toplevel->events.set_title, &c->set_title, updatetitle); + LISTEN(&xdg_surface->toplevel->events.request_fullscreen, &c->fullscreen, + fullscreennotify); +} + +void +createpointer(struct wlr_input_device *device) +{ + if (wlr_input_device_is_libinput(device)) { + struct libinput_device *libinput_device = (struct libinput_device*) + wlr_libinput_get_device_handle(device); + + if (libinput_device_config_tap_get_finger_count(libinput_device)) { + libinput_device_config_tap_set_enabled(libinput_device, tap_to_click); + libinput_device_config_tap_set_drag_enabled(libinput_device, tap_and_drag); + libinput_device_config_tap_set_drag_lock_enabled(libinput_device, drag_lock); + } + + if (libinput_device_config_scroll_has_natural_scroll(libinput_device)) + libinput_device_config_scroll_set_natural_scroll_enabled(libinput_device, natural_scrolling); + + if (libinput_device_config_dwt_is_available(libinput_device)) + libinput_device_config_dwt_set_enabled(libinput_device, disable_while_typing); + + if (libinput_device_config_left_handed_is_available(libinput_device)) + libinput_device_config_left_handed_set(libinput_device, left_handed); + + if (libinput_device_config_middle_emulation_is_available(libinput_device)) + libinput_device_config_middle_emulation_set_enabled(libinput_device, middle_button_emulation); + + if (libinput_device_config_scroll_get_methods(libinput_device) != LIBINPUT_CONFIG_SCROLL_NO_SCROLL) + libinput_device_config_scroll_set_method (libinput_device, scroll_method); + + if (libinput_device_config_click_get_methods(libinput_device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE) + libinput_device_config_click_set_method (libinput_device, click_method); + + if (libinput_device_config_send_events_get_modes(libinput_device)) + libinput_device_config_send_events_set_mode(libinput_device, send_events_mode); + + if (libinput_device_config_accel_is_available(libinput_device)) { + libinput_device_config_accel_set_profile(libinput_device, accel_profile); + libinput_device_config_accel_set_speed(libinput_device, accel_speed); + } + } + + wlr_cursor_attach_input_device(cursor, device); +} + +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 +defaultgaps(const Arg *arg) +{ + setgaps(gappoh, gappov, gappih, gappiv); +} + +void +destroydragicon(struct wl_listener *listener, void *data) +{ + struct wlr_drag_icon *icon = data; + wlr_scene_node_destroy(icon->data); + /* Focus enter isn't sent during drag, so refocus the focused node. */ + focusclient(selclient(), 1); + motionnotify(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(data); +} + +void +destroylayersurfacenotify(struct wl_listener *listener, void *data) +{ + LayerSurface *layersurface = wl_container_of(listener, layersurface, destroy); + + wl_list_remove(&layersurface->link); + wl_list_remove(&layersurface->destroy.link); + wl_list_remove(&layersurface->map.link); + wl_list_remove(&layersurface->unmap.link); + wl_list_remove(&layersurface->surface_commit.link); + wlr_scene_node_destroy(layersurface->scene); + free(layersurface); +} + +void +destroynotify(struct wl_listener *listener, void *data) +{ + /* Called when the surface is destroyed and should never be shown again. */ + Client *c = wl_container_of(listener, c, destroy); + wl_list_remove(&c->map.link); + wl_list_remove(&c->unmap.link); + 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->configure.link); + wl_list_remove(&c->set_hints.link); + wl_list_remove(&c->activate.link); + } +#endif + free(c); +} + +Monitor * +dirtomon(enum wlr_direction dir) +{ + struct wlr_output *next; + if (wlr_output_layout_get(output_layout, selmon->wlr_output) + && (next = wlr_output_layout_adjacent_output(output_layout, + dir, selmon->wlr_output, selmon->m.x, selmon->m.y))) + return next->data; + if (wlr_output_layout_get(output_layout, selmon->wlr_output) + && (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 +focusclient(Client *c, int lift) +{ + struct wlr_surface *old = seat->keyboard_state.focused_surface; + int i; + + /* Raise client in stacking order if requested */ + if (c && lift) + wlr_scene_node_raise_to_top(c->scene); + + if (c && client_surface(c) == old) + return; + + /* 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) + for (i = 0; i < 4; i++) + wlr_scene_rect_set_color(c->border[i], 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. */ + Client *w = client_from_wlr_surface(old); + if (wlr_surface_is_layer_surface(old)) { + struct wlr_layer_surface_v1 *wlr_layer_surface = + wlr_layer_surface_v1_from_wlr_surface(old); + + if (wlr_layer_surface && ((LayerSurface *)wlr_layer_surface->data)->mapped + && (wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP + || wlr_layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY)) + return; + } else if (w && w == exclusive_focus && client_wants_focus(w)) { + return; + /* Don't deactivate old client if the new one wants focus, as this causes issues with winecfg + * and probably other clients */ + } else if (w && !client_is_unmanaged(w) && (!c || !client_wants_focus(c))) { + for (i = 0; i < 4; i++) + wlr_scene_rect_set_color(w->border[i], bordercolor); + + client_activate_surface(old, 0); + } + } + + printstatus(); + checkidleinhibitor(NULL); + + 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); + + /* 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 = selclient(); + if (!sel || (sel->isfullscreen && lockfullscreen)) + 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 +incnmaster(const Arg *arg) +{ + if (!arg || !selmon) + return; + selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); +} + +void +incgaps(const Arg *arg) +{ + setgaps( + selmon->gappoh + arg->i, + selmon->gappov + arg->i, + selmon->gappih + arg->i, + selmon->gappiv + arg->i + ); +} + +void +incigaps(const Arg *arg) +{ + setgaps( + selmon->gappoh, + selmon->gappov, + selmon->gappih + arg->i, + selmon->gappiv + arg->i + ); +} + +void +incihgaps(const Arg *arg) +{ + setgaps( + selmon->gappoh, + selmon->gappov, + selmon->gappih + arg->i, + selmon->gappiv + ); +} + +void +incivgaps(const Arg *arg) +{ + setgaps( + selmon->gappoh, + selmon->gappov, + selmon->gappih, + selmon->gappiv + arg->i + ); +} + +void +incogaps(const Arg *arg) +{ + setgaps( + selmon->gappoh + arg->i, + selmon->gappov + arg->i, + selmon->gappih, + selmon->gappiv + ); +} + +void +incohgaps(const Arg *arg) +{ + setgaps( + selmon->gappoh + arg->i, + selmon->gappov, + selmon->gappih, + selmon->gappiv + ); +} + +void +incovgaps(const Arg *arg) +{ + setgaps( + selmon->gappoh, + selmon->gappov + arg->i, + selmon->gappih, + selmon->gappiv + ); +} + +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(device); + break; + case WLR_INPUT_DEVICE_POINTER: + createpointer(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(&keyboards)) + 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. + */ + int handled = 0; + 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); + handled = 1; + } + } + return handled; +} + +void +keypress(struct wl_listener *listener, void *data) +{ + int i; + /* This event is raised when a key is pressed or released. */ + Keyboard *kb = wl_container_of(listener, kb, key); + struct wlr_event_keyboard_key *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( + kb->device->keyboard->xkb_state, keycode, &syms); + + int handled = 0; + uint32_t mods = wlr_keyboard_get_modifiers(kb->device->keyboard); + + wlr_idle_notify_activity(idle, seat); + + /* On _press_ if there is no active screen locker, + * attempt to process a compositor keybinding. */ + if (!input_inhibit_mgr->active_inhibitor + && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) + for (i = 0; i < nsyms; i++) + handled = keybinding(mods, syms[i]) || handled; + + if (!handled) { + /* Pass unhandled keycodes along to the client. */ + wlr_seat_set_keyboard(seat, kb->device); + 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. */ + Keyboard *kb = wl_container_of(listener, kb, modifiers); + /* + * 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 seat. You can swap out the underlying wlr_keyboard like this and + * wlr_seat handles this transparently. + */ + wlr_seat_set_keyboard(seat, kb->device); + /* Send modifiers to the client. */ + wlr_seat_keyboard_notify_modifiers(seat, + &kb->device->keyboard->modifiers); +} + +void +killclient(const Arg *arg) +{ + Client *sel = selclient(); + if (sel) + client_send_close(sel); +} + +void +maplayersurfacenotify(struct wl_listener *listener, void *data) +{ + LayerSurface *l = wl_container_of(listener, l, map); + wlr_surface_send_enter(l->layer_surface->surface, l->mon->wlr_output); + motionnotify(0); +} + +void +mapnotify(struct wl_listener *listener, void *data) +{ + /* Called when the surface is mapped, or ready to display on-screen. */ + Client *p, *c = wl_container_of(listener, c, map); + int i; + + /* Create scene tree for this client and its border */ + c->scene = &wlr_scene_tree_create(layers[LyrTile])->node; + 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)); + if (client_surface(c)) { + client_surface(c)->data = c->scene; + /* Ideally we should do this in createnotify{,x11} but at that moment + * wlr_xwayland_surface doesn't have wlr_surface yet + */ + LISTEN(&client_surface(c)->events.commit, &c->commit, commitnotify); + + } + c->scene->data = c->scene_surface->data = c; + +#ifdef XWAYLAND + /* Handle unmanaged clients first so we can return prior create borders */ + if (client_is_unmanaged(c)) { + client_get_geometry(c, &c->geom); + /* Unmanaged clients always are floating */ + wlr_scene_node_reparent(c->scene, layers[LyrFloat]); + wlr_scene_node_set_position(c->scene, c->geom.x + borderpx, + c->geom.y + borderpx); + if (client_wants_focus(c)) { + focusclient(c, 1); + exclusive_focus = c; + } + return; + } +#endif + + for (i = 0; i < 4; i++) { + c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, bordercolor); + c->border[i]->node.data = c; + wlr_scene_rect_set_color(c->border[i], bordercolor); + } + + /* Initialize client geometry with room for border */ + client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); + client_get_geometry(c, &c->geom); + 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)) && client_is_mapped(p)) { + c->isfloating = 1; + wlr_scene_node_reparent(c->scene, layers[LyrFloat]); + setmon(c, p->mon, p->tags); + } else { + applyrules(c); + } + printstatus(); + + c->mon->un_map = 1; +} + +void +monocle(Monitor *m) +{ + Client *c; + + wl_list_for_each(c, &clients, link) { + if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) + continue; + if (!monoclegaps) + resize(c, m->w, 0); + else + resize(c, (struct wlr_box){.x = m->w.x + gappoh, .y = m->w.y + gappov, + .width = m->w.width - 2 * gappoh, .height = m->w.height - 2 * gappov}, 0); + } + if ((c = focustop(m))) + wlr_scene_node_raise_to_top(c->scene); +} + +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_event_pointer_motion_absolute *event = data; + wlr_cursor_warp_absolute(cursor, event->device, event->x, event->y); + motionnotify(event->time_msec); +} + +void +motionnotify(uint32_t time) +{ + double sx = 0, sy = 0; + Client *c = NULL; + LayerSurface *l; + struct wlr_surface *surface = NULL; + struct wlr_drag_icon *icon; + + /* time is 0 in internal calls meant to restore pointer focus. */ + if (time) { + wlr_idle_notify_activity(idle, seat); + + /* Update selmon (even while dragging a window) */ + if (sloppyfocus) + selmon = xytomon(cursor->x, cursor->y); + } + + /* Update drag icon's position if any */ + if (seat->drag && (icon = seat->drag->icon)) + wlr_scene_node_set_position(icon->data, cursor->x + icon->surface->sx, + cursor->y + icon->surface->sy); + /* 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 = cursor->x - grabcx, .y = 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 = cursor->x - grabc->geom.x, .height = 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) { + if ((l = toplevel_from_wlr_layer_surface( + seat->pointer_state.focused_surface))) { + surface = seat->pointer_state.focused_surface; + sx = cursor->x - l->geom.x; + sy = cursor->y - l->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 && (!cursor_image || strcmp(cursor_image, "left_ptr"))) + wlr_xcursor_manager_set_cursor_image(cursor_mgr, (cursor_image = "left_ptr"), cursor); + + 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_event_pointer_motion *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. */ + wlr_cursor_move(cursor, event->device, event->delta_x, event->delta_y); + motionnotify(event->time_msec); +} + +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)) + return; + + /* Float the window and tell motionnotify to grab it */ + setfloating(grabc, 1); + switch (cursor_mode = arg->ui) { + case CurMove: + grabcx = cursor->x - grabc->geom.x; + grabcy = cursor->y - grabc->geom.y; + wlr_xcursor_manager_set_cursor_image(cursor_mgr, (cursor_image = "fleur"), cursor); + 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_xcursor_manager_set_cursor_image(cursor_mgr, + (cursor_image = "bottom_right_corner"), cursor); + 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; + + wlr_output_enable(wlr_output, config_head->state.enabled); + if (!config_head->state.enabled) + goto apply_or_test; + if (config_head->state.mode) + wlr_output_set_mode(wlr_output, config_head->state.mode); + else + wlr_output_set_custom_mode(wlr_output, + 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_move(output_layout, wlr_output, + config_head->state.x, config_head->state.y); + wlr_output_set_transform(wlr_output, config_head->state.transform); + wlr_output_set_scale(wlr_output, config_head->state.scale); + +apply_or_test: + if (test) { + ok &= wlr_output_test(wlr_output); + wlr_output_rollback(wlr_output); + } else { + int output_ok = 1; + /* If it's a custom mode to avoid an assertion failed in wlr_output_commit() + * we test if that mode does not fail rather than just call wlr_output_commit(). + * We do not test normal modes because (at least in my hardware (@sevz17)) + * wlr_output_test() fails even if that mode can actually be set */ + if (!config_head->state.mode && config_head->state.enabled) + ok &= (output_ok = wlr_output_test(wlr_output) + && wlr_output_commit(wlr_output)); + else + ok &= wlr_output_commit(wlr_output); + + /* In custom modes we call wlr_output_test(), it it fails + * we need to rollback, and normal modes seems to does not cause + * assertions failed in wlr_output_commit() which rollback + * the output on failure */ + if (!output_ok) + wlr_output_rollback(wlr_output); + } + } + + 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; + int internal_call = !time; + + if (sloppyfocus && !internal_call && 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 (internal_call) { + 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; + Client *c; + unsigned int occ, urg, sel; + + wl_list_for_each(m, &mons, link) { + occ = urg = 0; + wl_list_for_each(c, &clients, link) { + if (c->mon != m) + continue; + occ |= c->tags; + if (c->isurgent) + urg |= c->tags; + } + if ((c = focustop(m))) { + printf("%s title %s\n", m->wlr_output->name, client_get_title(c)); + printf("%s fullscreen %u\n", m->wlr_output->name, c->isfullscreen); + printf("%s floating %u\n", m->wlr_output->name, c->isfloating); + sel = c->tags; + } else { + printf("%s title \n", m->wlr_output->name); + printf("%s fullscreen \n", m->wlr_output->name); + printf("%s floating \n", m->wlr_output->name); + sel = 0; + } + + printf("%s selmon %u\n", m->wlr_output->name, m == selmon); + printf("%s tags %u %u %u %u\n", m->wlr_output->name, occ, m->tagset[m->seltags], + sel, urg); + printf("%s layout %s\n", m->wlr_output->name, m->lt[m->sellt]->symbol); + } +} + +void +quit(const Arg *arg) +{ + size_t i; + + /* kill child processes */ + for (i = 0; i < autostart_len; i++) { + if (0 < autostart_pids[i]) { + kill(autostart_pids[i], SIGTERM); + waitpid(autostart_pids[i], NULL, 0); + } + } + + wl_display_terminate(dpy); +} + +void +quitsignal(int signo) +{ + quit(NULL); +} + +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; + int skip = 0; + struct timespec now; + + clock_gettime(CLOCK_MONOTONIC, &now); + + /* Render if no XDG clients have an outstanding resize and are visible on + * this monitor. */ + /* Checking m->un_map for every client is not optimal but works */ + wl_list_for_each(c, &clients, link) { + if ((c->resize && m->un_map) || (c->type == XDGShell + && (c->surface.xdg->pending.geometry.width != + c->surface.xdg->current.geometry.width + || c->surface.xdg->pending.geometry.height != + c->surface.xdg->current.geometry.height))) { + /* Lie */ + wlr_surface_send_frame_done(client_surface(c), &now); + skip = 1; + } + } + if (!skip && !wlr_scene_output_commit(m->scene_output)) + return; + /* Let clients know a frame has been rendered */ + wlr_scene_output_send_frame_done(m->scene_output, &now); + m->un_map = 0; +} + +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 +resize(Client *c, struct wlr_box geo, int interact) +{ + struct wlr_box *bbox = interact ? &sgeom : &c->mon->w; + c->geom = geo; + applybounds(c, bbox); + + /* Update scene-graph, including borders */ + wlr_scene_node_set_position(c->scene, c->geom.x, c->geom.y); + wlr_scene_node_set_position(c->scene_surface, 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); + if (c->fullscreen_bg) + wlr_scene_rect_set_size(c->fullscreen_bg, c->geom.width, c->geom.height); + + /* wlroots makes this 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); +} + +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 */ + autostartexec(); + 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]); + } + /* If nobody is reading the status output, don't terminate */ + signal(SIGPIPE, SIG_IGN); + 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_xcursor_manager_set_cursor_image(cursor_mgr, cursor_image, cursor); + + /* 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); +} + +Client * +selclient(void) +{ + Client *c = wl_container_of(fstack.next, c, flink); + if (wl_list_empty(&fstack) || !VISIBLEON(c, selmon)) + return NULL; + return c; +} + +void +setcursor(struct wl_listener *listener, void *data) +{ + /* 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; + cursor_image = NULL; + /* 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 +setfloating(Client *c, int floating) +{ + c->isfloating = floating; + wlr_scene_node_reparent(c->scene, layers[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); + + if (fullscreen) { + c->prev = c->geom; + resize(c, c->mon->m, 0); + /* 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. + * + * For brevity we set a black background for all clients + */ + if (!c->fullscreen_bg) { + c->fullscreen_bg = wlr_scene_rect_create(c->scene, + c->geom.width, c->geom.height, fullscreen_bg); + wlr_scene_node_lower_to_bottom(&c->fullscreen_bg->node); + } + } 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); + if (c->fullscreen_bg) { + wlr_scene_node_destroy(&c->fullscreen_bg->node); + c->fullscreen_bg = NULL; + } + } + arrange(c->mon); + printstatus(); +} + +void +setgaps(int oh, int ov, int ih, int iv) +{ + selmon->gappoh = MAX(oh, 0); + selmon->gappov = MAX(ov, 0); + selmon->gappih = MAX(ih, 0); + selmon->gappiv = MAX(iv, 0); + arrange(selmon); +} + +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; + /* TODO change layout symbol? */ + 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.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if (f < 0.1 || f > 0.9) + return; + selmon->mfact = f; + arrange(selmon); +} + +void +setmon(Client *c, Monitor *m, unsigned int newtags) +{ + Monitor *oldmon = c->mon; + + if (oldmon == m) + return; + c->mon = m; + c->prev = c->geom; + + /* TODO leave/enter is not optimal but works */ + if (oldmon) { + wlr_surface_send_leave(client_surface(c), oldmon->wlr_output); + arrange(oldmon); + } + if (m) { + /* Make sure window actually overlaps with the monitor */ + resize(c, c->geom, 0); + wlr_surface_send_enter(client_surface(c), m->wlr_output); + c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */ + setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ + } + 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) +{ + /* Force line-buffered stdout */ + setvbuf(stdout, NULL, _IOLBF, 0); + + /* 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(); + + /* Set up signal handlers */ + sigchld(0); + signal(SIGINT, quitsignal); + signal(SIGTERM, quitsignal); + + /* 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. The NULL argument here optionally allows you + * to pass in a custom renderer if wlr_renderer doesn't meet your needs. The + * backend uses the renderer, for example, to fall back to software cursors + * if the backend does not support hardware cursors (some older GPUs + * don't). */ + if (!(backend = wlr_backend_autocreate(dpy))) + die("couldn't create backend"); + + /* Initialize the scene graph used to lay out windows */ + scene = wlr_scene_create(); + layers[LyrBg] = &wlr_scene_tree_create(&scene->node)->node; + layers[LyrBottom] = &wlr_scene_tree_create(&scene->node)->node; + layers[LyrTile] = &wlr_scene_tree_create(&scene->node)->node; + layers[LyrFloat] = &wlr_scene_tree_create(&scene->node)->node; + layers[LyrTop] = &wlr_scene_tree_create(&scene->node)->node; + layers[LyrOverlay] = &wlr_scene_tree_create(&scene->node)->node; + layers[LyrDragIcon] = &wlr_scene_tree_create(&scene->node)->node; + + /* Create a renderer with the default implementation */ + if (!(drw = wlr_renderer_autocreate(backend))) + die("couldn't create renderer"); + wlr_renderer_init_wl_display(drw, dpy); + + /* Create a default allocator */ + 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, drw); + wlr_export_dmabuf_manager_v1_create(dpy); + wlr_screencopy_manager_v1_create(dpy); + wlr_data_control_manager_v1_create(dpy); + wlr_data_device_manager_create(dpy); + wlr_gamma_control_manager_v1_create(dpy); + wlr_primary_selection_v1_device_manager_create(dpy); + wlr_viewporter_create(dpy); + + /* Initializes the interface used to implement urgency hints */ + activation = wlr_xdg_activation_v1_create(dpy); + wl_signal_add(&activation->events.request_activate, &request_activate); + + /* 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(); + wl_signal_add(&output_layout->events.change, &layout_change); + 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); + wl_signal_add(&backend->events.new_output, &new_output); + + /* Set up our client lists and the xdg-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); + + idle = wlr_idle_create(dpy); + + idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); + wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &idle_inhibitor_create); + + layer_shell = wlr_layer_shell_v1_create(dpy); + wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface); + + xdg_shell = wlr_xdg_shell_create(dpy); + wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface); + + input_inhibit_mgr = wlr_input_inhibit_manager_create(dpy); + + /* 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); + wlr_xdg_decoration_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); + + /* + * 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 my + * input handling blog post: + * + * https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html + * + * And more comments are sprinkled throughout the notify functions above. + */ + wl_signal_add(&cursor->events.motion, &cursor_motion); + wl_signal_add(&cursor->events.motion_absolute, &cursor_motion_absolute); + wl_signal_add(&cursor->events.button, &cursor_button); + wl_signal_add(&cursor->events.axis, &cursor_axis); + wl_signal_add(&cursor->events.frame, &cursor_frame); + + /* + * 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. + */ + wl_list_init(&keyboards); + wl_signal_add(&backend->events.new_input, &new_input); + virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy); + wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard, + &new_virtual_keyboard); + seat = wlr_seat_create(dpy, "seat0"); + wl_signal_add(&seat->events.request_set_cursor, &request_cursor); + wl_signal_add(&seat->events.request_set_selection, &request_set_sel); + wl_signal_add(&seat->events.request_set_primary_selection, &request_set_psel); + wl_signal_add(&seat->events.request_start_drag, &request_start_drag); + wl_signal_add(&seat->events.start_drag, &start_drag); + + output_mgr = wlr_output_manager_v1_create(dpy); + wl_signal_add(&output_mgr->events.apply, &output_mgr_apply); + wl_signal_add(&output_mgr->events.test, &output_mgr_test); + + wlr_scene_set_presentation(scene, wlr_presentation_create(dpy, backend)); + +#ifdef XWAYLAND + /* + * Initialise the XWayland X server. + * It will be started when the first X client is started. + */ + xwayland = wlr_xwayland_create(dpy, compositor, 1); + if (xwayland) { + wl_signal_add(&xwayland->events.ready, &xwayland_ready); + wl_signal_add(&xwayland->events.new_surface, &new_xwayland_surface); + + setenv("DISPLAY", xwayland->display_name, 1); + } else { + fprintf(stderr, "failed to setup XWayland X server, continuing without it\n"); + } +#endif +} + +void +sigchld(int unused) +{ + /* We should be able to remove this function in favor of a simple + * signal(SIGCHLD, SIG_IGN); + * but the Xwayland implementation in wlroots currently prevents us from + * setting our own disposition for SIGCHLD. + */ + pid_t pid; + + if (signal(SIGCHLD, sigchld) == SIG_ERR) + die("can't install SIGCHLD handler:"); + while (0 < (pid = waitpid(-1, NULL, WNOHANG))) { + pid_t *p, *lim; + if (pid == child_pid) + child_pid = -1; + if (!(p = autostart_pids)) + continue; + lim = &p[autostart_len]; + + for (; p < lim; p++) { + if (*p == pid) { + *p = -1; + break; + } + } + } +} + +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_subsurface_tree_create(layers[LyrDragIcon], drag->icon->surface); + motionnotify(0); + wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); +} + +void +tag(const Arg *arg) +{ + Client *sel = selclient(); + if (sel && arg->ui & TAGMASK) { + sel->tags = arg->ui & TAGMASK; + focusclient(focustop(selmon), 1); + arrange(selmon); + } + printstatus(); +} + +void +tagmon(const Arg *arg) +{ + Client *sel = selclient(); + if (sel) + setmon(sel, dirtomon(arg->i), 0); +} + +void +tile(Monitor *m) +{ + unsigned int i, n = 0, h, r, oe = enablegaps, ie = enablegaps, mw, my, ty; + Client *c; + + wl_list_for_each(c, &clients, link) + if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) + n++; + if (n == 0) + return; + + if (smartgaps == n) { + oe = 0; // outer gaps disabled + } + + if (n > m->nmaster) + mw = m->nmaster ? (m->w.width + m->gappiv*ie) * m->mfact : 0; + else + mw = m->w.width - 2*m->gappov*oe + m->gappiv*ie; + i = 0; + my = ty = m->gappoh*oe; + wl_list_for_each(c, &clients, link) { + if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) + continue; + if (i < m->nmaster) { + r = MIN(n, m->nmaster) - i; + h = (m->w.height - my - m->gappoh*oe - m->gappih*ie * (r - 1)) / r; + resize(c, (struct wlr_box){.x = m->w.x + m->gappov*oe, .y = m->w.y + my, + .width = mw - m->gappiv*ie, .height = h}, 0); + my += c->geom.height + m->gappih*ie; + } else { + r = n - i; + h = (m->w.height - ty - m->gappoh*oe - m->gappih*ie * (r - 1)) / r; + resize(c, (struct wlr_box){.x = m->w.x + mw + m->gappov*oe, .y = m->w.y + ty, + .width = m->w.width - mw - 2*m->gappov*oe, .height = h}, 0); + ty += c->geom.height + m->gappih*ie; + } + i++; + } +} + +void +togglefloating(const Arg *arg) +{ + Client *sel = selclient(); + /* return if fullscreen */ + if (sel && !sel->isfullscreen) + setfloating(sel, !sel->isfloating); +} + +void +togglefullscreen(const Arg *arg) +{ + Client *sel = selclient(); + if (sel) + setfullscreen(sel, !sel->isfullscreen); +} + +void +togglegaps(const Arg *arg) +{ + enablegaps = !enablegaps; + arrange(selmon); +} + +void +toggletag(const Arg *arg) +{ + unsigned int newtags; + Client *sel = selclient(); + if (!sel) + return; + newtags = sel->tags ^ (arg->ui & TAGMASK); + if (newtags) { + sel->tags = newtags; + focusclient(focustop(selmon), 1); + arrange(selmon); + } + printstatus(); +} + +void +toggleview(const Arg *arg) +{ + unsigned int newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0; + + if (newtagset) { + selmon->tagset[selmon->seltags] = newtagset; + focusclient(focustop(selmon), 1); + arrange(selmon); + } + printstatus(); +} + +void +unmaplayersurfacenotify(struct wl_listener *listener, void *data) +{ + LayerSurface *layersurface = wl_container_of(listener, layersurface, unmap); + + layersurface->mapped = 0; + wlr_scene_node_set_enabled(layersurface->scene, 0); + if (layersurface == exclusive_focus) + exclusive_focus = NULL; + if (layersurface->layer_surface->output + && (layersurface->mon = layersurface->layer_surface->output->data)) + arrangelayers(layersurface->mon); + if (layersurface->layer_surface->surface == + seat->keyboard_state.focused_surface) + focusclient(selclient(), 1); + motionnotify(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->mon) + c->mon->un_map = 1; + + if (client_is_unmanaged(c)) { + if (c == exclusive_focus) + exclusive_focus = NULL; + if (client_surface(c) == seat->keyboard_state.focused_surface) + focusclient(selclient(), 1); + } else { + wl_list_remove(&c->link); + setmon(c, NULL, 0); + wl_list_remove(&c->flink); + } + + wl_list_remove(&c->commit.link); + wlr_scene_node_destroy(c->scene); + printstatus(); + motionnotify(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); + memset(&m->m, 0, sizeof(m->m)); + memset(&m->w, 0, sizeof(m->w)); + } + /* 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 */ + sgeom = *wlr_output_layout_get_box(output_layout, NULL); + 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 */ + m->m = m->w = *wlr_output_layout_get_box(output_layout, m->wlr_output); + wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y); + /* Calculate the effective monitor geometry to use for clients */ + arrangelayers(m); + /* Don't move clients to the left output when plugging monitors */ + arrange(m); + + config_head->state.enabled = 1; + config_head->state.mode = m->wlr_output->current_mode; + 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_is_mapped(c)) + setmon(c, selmon, c->tags); + + 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 = client_from_wlr_surface(event->surface); + if (c && c != selclient()) { + c->isurgent = 1; + printstatus(); + } +} + +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; + createkeyboard(&keyboard->input_device); +} + +Monitor * +xytomon(double x, double y) +{ + struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y); + return o ? o->data : NULL; +} + +struct wlr_scene_node * +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; + const int *layer; + int focus_order[] = { LyrOverlay, LyrTop, LyrFloat, LyrTile, LyrBottom, LyrBg }; + + for (layer = focus_order; layer < END(focus_order); layer++) { + if ((node = wlr_scene_node_at(layers[*layer], x, y, nx, ny))) { + if (node->type == WLR_SCENE_NODE_SURFACE) + surface = wlr_scene_surface_from_node(node)->surface; + /* Walk the tree to find a node that knows the client */ + for (pnode = node; pnode && !c; pnode = pnode->parent) + c = pnode->data; + if (c && c->type == LayerShell) { + c = NULL; + l = pnode->data; + } + } + if (surface) + break; + } + + if (psurface) *psurface = surface; + if (pc) *pc = c; + if (pl) *pl = l; + return node; +} + +void +zoom(const Arg *arg) +{ + Client *c, *sel = selclient(); + + 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 (c->type == X11Managed) + wlr_xwayland_surface_activate(c->surface.xwayland, 1); +} + +void +configurex11(struct wl_listener *listener, void *data) +{ + Client *c = wl_container_of(listener, c, configure); + struct wlr_xwayland_surface_configure_event *event = data; + wlr_xwayland_surface_configure(c->surface.xwayland, + event->x, event->y, event->width, event->height); +} + +void +createnotifyx11(struct wl_listener *listener, void *data) +{ + struct wlr_xwayland_surface *xwayland_surface = data; + Client *c; + /* TODO: why we unset fullscreen when a xwayland client is created? */ + wl_list_for_each(c, &clients, link) + if (c->isfullscreen && VISIBLEON(c, c->mon)) + setfullscreen(c, 0); + + /* Allocate a Client for this surface */ + c = xwayland_surface->data = ecalloc(1, sizeof(*c)); + c->surface.xwayland = xwayland_surface; + c->type = xwayland_surface->override_redirect ? X11Unmanaged : X11Managed; + c->bw = borderpx; + + /* Listen to the various events it can emit */ + LISTEN(&xwayland_surface->events.map, &c->map, mapnotify); + LISTEN(&xwayland_surface->events.unmap, &c->unmap, unmapnotify); + LISTEN(&xwayland_surface->events.request_activate, &c->activate, activatex11); + LISTEN(&xwayland_surface->events.request_configure, &c->configure, + configurex11); + LISTEN(&xwayland_surface->events.set_hints, &c->set_hints, sethints); + LISTEN(&xwayland_surface->events.set_title, &c->set_title, updatetitle); + LISTEN(&xwayland_surface->events.destroy, &c->destroy, destroynotify); + LISTEN(&xwayland_surface->events.request_fullscreen, &c->fullscreen, + fullscreennotify); +} + +Atom +getatom(xcb_connection_t *xc, const char *name) +{ + Atom 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); + if (c != selclient()) { + c->isurgent = c->surface.xwayland->hints_urgency; + printstatus(); + } +} + +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, "left_ptr", 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:hv")) != -1) { + if (c == 's') + startup_cmd = optarg; + 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] [-s startup command]", argv[0]); +} diff --git a/.config/dwl/dwl.o b/.config/dwl/dwl.o new file mode 100644 index 0000000000000000000000000000000000000000..5c4dd035ffaca89c83d93a5c13995e23f77a063c GIT binary patch literal 76088 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 z zru_GYVJ6|@l#ln+9ygiTSDtzI XbJV{)sPl(0P2+DLamz0xhE)DPpYb<1 literal 0 HcmV?d00001 diff --git a/.config/dwl/dwl_start.sh b/.config/dwl/dwl_start.sh new file mode 100755 index 0000000..209ae42 --- /dev/null +++ b/.config/dwl/dwl_start.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +dwl -s somebar diff --git a/.config/dwl/patch.sh b/.config/dwl/patch.sh new file mode 100755 index 0000000..a2ca828 --- /dev/null +++ b/.config/dwl/patch.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +#patch < patch/cyclelayouts.patch +#patch < patch/toggleKbLayout.patch +patch < patch/vanitygaps.patch +patch < patch/autostart.patch diff --git a/.config/dwl/patch/autostart.patch b/.config/dwl/patch/autostart.patch new file mode 100644 index 0000000..8f625a1 --- /dev/null +++ b/.config/dwl/patch/autostart.patch @@ -0,0 +1,132 @@ +From a5baf707d5aef5ecfe0e331a92d3c384a892c72c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= + +Date: Wed, 9 Feb 2022 07:02:47 -0600 +Subject: [PATCH] apply autostart patch from dwm + +https://dwm.suckless.org/patches/cool_autostart/ +--- + config.def.h | 6 ++++++ + dwl.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 58 insertions(+), 1 deletion(-) + +diff --git a/config.def.h b/config.def.h +index ec1f0528..001000a4 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -86,6 +86,12 @@ 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.0; + ++/* Autostart */ ++static const char *const autostart[] = { ++ "sh", "-c", "swaybg --image /xap/local/background", NULL, ++ NULL /* terminate */ ++}; ++ + /* If you want to use the windows key change this to WLR_MODIFIER_LOGO */ + #define MODKEY WLR_MODIFIER_ALT + #define TAGKEYS(KEY,SKEY,TAG) \ +diff --git a/dwl.c b/dwl.c +index a80de054..6dee1e8e 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -212,6 +212,7 @@ 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 autostartexec(void); + static void axisnotify(struct wl_listener *listener, void *data); + static void buttonpress(struct wl_listener *listener, void *data); + static void chvt(const Arg *arg); +@@ -380,6 +381,9 @@ static Atom netatom[NetLast]; + /* compile-time check if all tags fit into an unsigned int bit array. */ + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + ++static pid_t *autostart_pids; ++static size_t autostart_len; ++ + /* function implementations */ + void + applybounds(Client *c, struct wlr_box *bbox) +@@ -408,6 +412,29 @@ applybounds(Client *c, struct wlr_box *bbox) + c->geom.y = bbox->y; + } + ++void ++autostartexec(void) { ++ const char *const *p; ++ size_t i = 0; ++ ++ /* count entries */ ++ for (p = autostart; *p; autostart_len++, p++) ++ while (*++p); ++ ++ autostart_pids = calloc(autostart_len, sizeof(pid_t)); ++ for (p = autostart; *p; i++, p++) { ++ if ((autostart_pids[i] = fork()) == 0) { ++ setsid(); ++ execvp(*p, (char *const *)p); ++ fprintf(stderr, "dwl: execvp %s\n", *p); ++ perror(" failed"); ++ _exit(EXIT_FAILURE); ++ } ++ /* skip arguments */ ++ while (*++p); ++ } ++} ++ + void + applyexclusive(struct wlr_box *usable_area, + uint32_t anchor, int32_t exclusive, +@@ -1772,6 +1799,16 @@ printstatus(void) + void + quit(const Arg *arg) + { ++ size_t i; ++ ++ /* kill child processes */ ++ for (i = 0; i < autostart_len; i++) { ++ if (0 < autostart_pids[i]) { ++ kill(autostart_pids[i], SIGTERM); ++ waitpid(autostart_pids[i], NULL, 0); ++ } ++ } ++ + wl_display_terminate(dpy); + } + +@@ -1866,6 +1903,7 @@ run(char *startup_cmd) + die("startup: backend_start"); + + /* Now that the socket exists and the backend is started, run the startup command */ ++ autostartexec(); + if (startup_cmd) { + int piperw[2]; + if (pipe(piperw) < 0) +@@ -2243,11 +2281,24 @@ sigchld(int unused) + * setting our own disposition for SIGCHLD. + */ + pid_t pid; ++ + if (signal(SIGCHLD, sigchld) == SIG_ERR) + die("can't install SIGCHLD handler:"); +- while (0 < (pid = waitpid(-1, NULL, WNOHANG))) ++ while (0 < (pid = waitpid(-1, NULL, WNOHANG))) { ++ pid_t *p, *lim; + if (pid == child_pid) + child_pid = -1; ++ if (!(p = autostart_pids)) ++ continue; ++ lim = &p[autostart_len]; ++ ++ for (; p < lim; p++) { ++ if (*p == pid) { ++ *p = -1; ++ break; ++ } ++ } ++ } + } + + void diff --git a/.config/dwl/patch/cyclelayouts.patch b/.config/dwl/patch/cyclelayouts.patch new file mode 100644 index 0000000..e2970bc --- /dev/null +++ b/.config/dwl/patch/cyclelayouts.patch @@ -0,0 +1,68 @@ +From 8510cd247ad288e63ac346539ed75320c407897d Mon Sep 17 00:00:00 2001 +From: Vladislav Nepogodin +Date: Tue, 27 Jul 2021 23:01:45 +0400 +Subject: [PATCH] Function to cycle through available layouts. + +--- + config.def.h | 3 +++ + dwl.c | 19 +++++++++++++++++++ + 2 files changed, 22 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 089aa379..1c6a1331 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -22,6 +22,7 @@ static const Layout layouts[] = { + { "[]=", tile }, + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, ++ { NULL, NULL }, + }; + + /* monitors +@@ -82,6 +83,8 @@ static const Key keys[] = { + { MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} }, + { MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} }, + { MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} }, ++ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_comma, cyclelayout, {.i = -1 } }, ++ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_period, cyclelayout, {.i = +1 } }, + { MODKEY, XKB_KEY_space, setlayout, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, + { MODKEY, XKB_KEY_e, togglefullscreen, {0} }, +diff --git a/dwl.c b/dwl.c +index a2a0b692..bc6e76b5 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -232,6 +232,7 @@ static void createnotify(struct wl_listener *listener, void *data); + static void createlayersurface(struct wl_listener *listener, void *data); + static void createpointer(struct wlr_input_device *device); + static void cursorframe(struct wl_listener *listener, void *data); ++static void cyclelayout(const Arg *arg); + static void destroylayersurfacenotify(struct wl_listener *listener, void *data); + static void destroynotify(struct wl_listener *listener, void *data); + static Monitor *dirtomon(enum wlr_direction dir); +@@ -971,6 +972,24 @@ cursorframe(struct wl_listener *listener, void *data) + wlr_seat_pointer_notify_frame(seat); + } + ++void ++cyclelayout(const Arg *arg) ++{ ++ Layout *l; ++ for (l = (Layout *)layouts; l != selmon->lt[selmon->sellt]; l++); ++ if (arg->i > 0) { ++ if (l->symbol && (l + 1)->symbol) ++ setlayout(&((Arg) { .v = (l + 1) })); ++ else ++ setlayout(&((Arg) { .v = layouts })); ++ } else { ++ if (l != layouts && (l - 1)->symbol) ++ setlayout(&((Arg) { .v = (l - 1) })); ++ else ++ setlayout(&((Arg) { .v = &layouts[LENGTH(layouts) - 2] })); ++ } ++} ++ + void + destroylayersurfacenotify(struct wl_listener *listener, void *data) + { diff --git a/.config/dwl/patch/toggleKbLayout.patch b/.config/dwl/patch/toggleKbLayout.patch new file mode 100644 index 0000000..40b3abd --- /dev/null +++ b/.config/dwl/patch/toggleKbLayout.patch @@ -0,0 +1,199 @@ +From d04df999acc1b0c0a0bdf5fe8a737e9e0fae0a2f Mon Sep 17 00:00:00 2001 +From: Stivvo +Date: Fri, 18 Sep 2020 12:56:23 +0200 +Subject: [PATCH 1/2] Switch between keyboard layouts ar runtime + +setkblayout() avoids to rewrite the code necessary to set the keyboard +layout in createkeyboard() and togglekblayout() +--- + config.def.h | 6 ++++++ + dwl.c | 38 +++++++++++++++++++++++++++++--------- + 2 files changed, 35 insertions(+), 9 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 53021cf7..b0fb9321 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -44,6 +44,11 @@ static const struct xkb_rule_names xkb_rules = { + static const int repeat_rate = 25; + static const int repeat_delay = 600; + ++/* gb will be set the first time togglekblayout is called, then us.. it is ++ * recommended to set the same layout in position 0 of kblayouts and in ++ * xkb_rules */ ++static const char *kblayouts[] = {"us", "gb"}; ++ + #define MODKEY WLR_MODIFIER_ALT + #define TAGKEYS(KEY,SKEY,TAG) \ + { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ +@@ -81,6 +86,7 @@ static const Key keys[] = { + { MODKEY, XKB_KEY_period, focusmon, {.i = +1} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = -1} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = +1} }, ++ { MODKEY, XKB_KEY_w, togglekblayout, {0} }, + TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0), + TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1), + TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2), +diff --git a/dwl.c b/dwl.c +index 730e46a1..5256eec0 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -221,6 +221,7 @@ static void run(char *startup_cmd); + static void scalebox(struct wlr_box *box, float scale); + static Client *selclient(void); + static void setcursor(struct wl_listener *listener, void *data); ++static void setkblayout(Keyboard *kb, const struct xkb_rule_names *newrule); + static void setpsel(struct wl_listener *listener, void *data); + static void setsel(struct wl_listener *listener, void *data); + static void setfloating(Client *c, int floating); +@@ -234,6 +235,7 @@ static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *m); + static void togglefloating(const Arg *arg); ++static void togglekblayout(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); + static void unmapnotify(struct wl_listener *listener, void *data); +@@ -261,6 +263,7 @@ static struct wlr_xcursor_manager *cursor_mgr; + + static struct wlr_seat *seat; + static struct wl_list keyboards; ++static unsigned int kblayout = 0; /* index of kblayouts */ + static unsigned int cursor_mode; + static Client *grabc; + static int grabcx, grabcy; /* client-relative */ +@@ -480,24 +483,28 @@ commitnotify(struct wl_listener *listener, void *data) + c->resize = 0; + } + ++void ++setkblayout(Keyboard *kb, const struct xkb_rule_names *newrule) ++{ ++ /* Prepare an XKB keymap and assign it to the keyboard. */ ++ struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); ++ struct xkb_keymap *keymap = xkb_map_new_from_names(context, newrule, ++ XKB_KEYMAP_COMPILE_NO_FLAGS); ++ wlr_keyboard_set_keymap(kb->device->keyboard, keymap); ++ xkb_keymap_unref(keymap); ++ xkb_context_unref(context); ++} ++ + void + createkeyboard(struct wlr_input_device *device) + { +- struct xkb_context *context; +- struct xkb_keymap *keymap; + Keyboard *kb; + + kb = device->data = calloc(1, sizeof(*kb)); + kb->device = device; + +- /* Prepare an XKB keymap and assign it to the keyboard. */ +- context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); +- keymap = xkb_map_new_from_names(context, &xkb_rules, +- XKB_KEYMAP_COMPILE_NO_FLAGS); ++ setkblayout(kb, &xkb_rules); + +- wlr_keyboard_set_keymap(device->keyboard, keymap); +- xkb_keymap_unref(keymap); +- xkb_context_unref(context); + wlr_keyboard_set_repeat_info(device->keyboard, repeat_rate, repeat_delay); + + /* Here we set up listeners for keyboard events. */ +@@ -1675,6 +1682,19 @@ togglefloating(const Arg *arg) + setfloating(sel, !sel->isfloating /* || sel->isfixed */); + } + ++void ++togglekblayout(const Arg *arg) ++{ ++ Keyboard *kb; ++ struct xkb_rule_names newrule = xkb_rules; ++ ++ kblayout = (kblayout + 1) % LENGTH(kblayouts); ++ newrule.layout = kblayouts[kblayout]; ++ wl_list_for_each(kb, &keyboards, link) { ++ setkblayout(kb, &newrule); ++ } ++} ++ + void + toggletag(const Arg *arg) + { + +From 382ec6b9cddbde9e66a08bc11d4836327b8f084a Mon Sep 17 00:00:00 2001 +From: Stivvo +Date: Mon, 8 Mar 2021 17:19:18 +0100 +Subject: [PATCH 2/2] Don't interfere with the dwl codebase + +Removing setkblayout duplicates a few lines of code to avoid touch the +codebase +--- + dwl.c | 34 ++++++++++++++++++---------------- + 1 file changed, 18 insertions(+), 16 deletions(-) + +diff --git a/dwl.c b/dwl.c +index 83dc16d0..4749936f 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -270,7 +270,6 @@ static void run(char *startup_cmd); + static void scalebox(struct wlr_box *box, float scale); + static Client *selclient(void); + static void setcursor(struct wl_listener *listener, void *data); +-static void setkblayout(Keyboard *kb, const struct xkb_rule_names *newrule); + static void setpsel(struct wl_listener *listener, void *data); + static void setsel(struct wl_listener *listener, void *data); + static void setfloating(Client *c, int floating); +@@ -784,25 +783,22 @@ commitnotify(struct wl_listener *listener, void *data) + c->resize = 0; + } + +-void +-setkblayout(Keyboard *kb, const struct xkb_rule_names *newrule) +-{ +- /* Prepare an XKB keymap and assign it to the keyboard. */ +- struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); +- struct xkb_keymap *keymap = xkb_map_new_from_names(context, newrule, +- XKB_KEYMAP_COMPILE_NO_FLAGS); +- wlr_keyboard_set_keymap(kb->device->keyboard, keymap); +- xkb_keymap_unref(keymap); +- xkb_context_unref(context); +-} +- + void + createkeyboard(struct wlr_input_device *device) + { ++ struct xkb_context *context; ++ struct xkb_keymap *keymap; + Keyboard *kb = device->data = calloc(1, sizeof(*kb)); + kb->device = device; + +- setkblayout(kb, &xkb_rules); ++ /* Prepare an XKB keymap and assign it to the keyboard. */ ++ context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); ++ keymap = xkb_map_new_from_names(context, &xkb_rules, ++ XKB_KEYMAP_COMPILE_NO_FLAGS); ++ ++ wlr_keyboard_set_keymap(device->keyboard, keymap); ++ xkb_keymap_unref(keymap); ++ xkb_context_unref(context); + wlr_keyboard_set_repeat_info(device->keyboard, repeat_rate, repeat_delay); + + /* Here we set up listeners for keyboard events. */ +@@ -2234,8 +2230,14 @@ togglekblayout(const Arg *arg) + + kblayout = (kblayout + 1) % LENGTH(kblayouts); + newrule.layout = kblayouts[kblayout]; +- wl_list_for_each(kb, &keyboards, link) +- setkblayout(kb, &newrule); ++ wl_list_for_each(kb, &keyboards, link) { ++ struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); ++ struct xkb_keymap *keymap = xkb_map_new_from_names(context, &newrule, ++ XKB_KEYMAP_COMPILE_NO_FLAGS); ++ wlr_keyboard_set_keymap(kb->device->keyboard, keymap); ++ xkb_keymap_unref(keymap); ++ xkb_context_unref(context); ++ } + } + + void diff --git a/.config/dwl/patch/vanitygaps.patch b/.config/dwl/patch/vanitygaps.patch new file mode 100644 index 0000000..478eca2 --- /dev/null +++ b/.config/dwl/patch/vanitygaps.patch @@ -0,0 +1,343 @@ +From 958da336feda010ce94c7dcbae3888c159ba1e9d Mon Sep 17 00:00:00 2001 +From: Bonicgamer <44382222+Bonicgamer@users.noreply.github.com> +Date: Mon, 17 Aug 2020 14:48:24 -0400 +Subject: [PATCH 1/2] Implement vanitygaps + +--- + config.def.h | 21 ++++++++ + dwl.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++---- + 2 files changed, 161 insertions(+), 10 deletions(-) + +diff --git a/config.def.h b/config.def.h +index ec1f0528..50dc8a26 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -2,6 +2,11 @@ + static const int sloppyfocus = 1; /* focus follows mouse */ + static const unsigned int borderpx = 1; /* border pixel of windows */ + static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */ ++static const unsigned int gappih = 10; /* horiz inner gap between windows */ ++static const unsigned int gappiv = 10; /* vert inner gap between windows */ ++static const unsigned int gappoh = 10; /* horiz outer gap between windows and screen edge */ ++static const unsigned int gappov = 10; /* vert outer gap between windows and screen edge */ ++static const int smartgaps = 0; /* 1 means no outer gap when there is only one window */ + static const float rootcolor[] = {0.3, 0.3, 0.3, 1.0}; + static const float bordercolor[] = {0.5, 0.5, 0.5, 1.0}; + static const float focuscolor[] = {1.0, 0.0, 0.0, 1.0}; +@@ -112,6 +117,22 @@ static const Key keys[] = { + { MODKEY, XKB_KEY_d, incnmaster, {.i = -1} }, + { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05} }, + { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05} }, ++ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_h, incgaps, {.i = +1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_l, incgaps, {.i = -1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_H, incogaps, {.i = +1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_L, incogaps, {.i = -1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_CTRL, XKB_KEY_h, incigaps, {.i = +1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_CTRL, XKB_KEY_l, incigaps, {.i = -1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_0, togglegaps, {0} }, ++ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_parenright,defaultgaps, {0} }, ++ { MODKEY, XKB_KEY_y, incihgaps, {.i = +1 } }, ++ { MODKEY, XKB_KEY_o, incihgaps, {.i = -1 } }, ++ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_y, incivgaps, {.i = +1 } }, ++ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_o, incivgaps, {.i = -1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_y, incohgaps, {.i = +1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_o, incohgaps, {.i = -1 } }, ++ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Y, incovgaps, {.i = +1 } }, ++ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_O, incovgaps, {.i = -1 } }, + { MODKEY, XKB_KEY_Return, zoom, {0} }, + { MODKEY, XKB_KEY_Tab, view, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, {0} }, +diff --git a/dwl.c b/dwl.c +index a80de054..1757dd5b 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -177,6 +177,10 @@ struct Monitor { + struct wlr_box w; /* window area, layout-relative */ + struct wl_list layers[4]; /* LayerSurface::link */ + const Layout *lt[2]; ++ int gappih; /* horizontal gap between windows */ ++ int gappiv; /* vertical gap between windows */ ++ int gappoh; /* horizontal outer gaps */ ++ int gappov; /* vertical outer gaps */ + unsigned int seltags; + unsigned int sellt; + unsigned int tagset[2]; +@@ -229,6 +233,7 @@ static void createmon(struct wl_listener *listener, void *data); + static void createnotify(struct wl_listener *listener, void *data); + static void createpointer(struct wlr_input_device *device); + static void cursorframe(struct wl_listener *listener, void *data); ++static void defaultgaps(const Arg *arg); + 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); +@@ -240,6 +245,13 @@ static void focusstack(const Arg *arg); + static Client *focustop(Monitor *m); + static void fullscreennotify(struct wl_listener *listener, void *data); + static void incnmaster(const Arg *arg); ++static void incgaps(const Arg *arg); ++static void incigaps(const Arg *arg); ++static void incihgaps(const Arg *arg); ++static void incivgaps(const Arg *arg); ++static void incogaps(const Arg *arg); ++static void incohgaps(const Arg *arg); ++static void incovgaps(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); +@@ -268,6 +280,7 @@ static Client *selclient(void); + static void setcursor(struct wl_listener *listener, void *data); + static void setfloating(Client *c, int floating); + static void setfullscreen(Client *c, int fullscreen); ++static void setgaps(int oh, int ov, int ih, int iv); + static void setlayout(const Arg *arg); + static void setmfact(const Arg *arg); + static void setmon(Client *c, Monitor *m, unsigned int newtags); +@@ -282,6 +295,7 @@ static void tagmon(const Arg *arg); + static void tile(Monitor *m); + static void togglefloating(const Arg *arg); + static void togglefullscreen(const Arg *arg); ++static void togglegaps(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); + static void unmaplayersurfacenotify(struct wl_listener *listener, void *data); +@@ -334,6 +348,8 @@ static struct wlr_box sgeom; + static struct wl_list mons; + static Monitor *selmon; + ++static int enablegaps = 1; /* enables gaps, used by togglegaps */ ++ + /* global event handlers */ + static struct wl_listener cursor_axis = {.notify = axisnotify}; + static struct wl_listener cursor_button = {.notify = buttonpress}; +@@ -950,6 +966,11 @@ createmon(struct wl_listener *listener, void *data) + /* Initialize monitor state using configured rules */ + for (i = 0; i < LENGTH(m->layers); i++) + wl_list_init(&m->layers[i]); ++ ++ m->gappih = gappih; ++ m->gappiv = gappiv; ++ m->gappoh = gappoh; ++ m->gappov = gappov; + m->tagset[0] = m->tagset[1] = 1; + for (r = monrules; r < END(monrules); r++) { + if (!r->name || strstr(wlr_output->name, r->name)) { +@@ -1092,6 +1113,12 @@ cursorframe(struct wl_listener *listener, void *data) + wlr_seat_pointer_notify_frame(seat); + } + ++void ++defaultgaps(const Arg *arg) ++{ ++ setgaps(gappoh, gappov, gappih, gappiv); ++} ++ + void + destroydragicon(struct wl_listener *listener, void *data) + { +@@ -1296,6 +1323,83 @@ incnmaster(const Arg *arg) + arrange(selmon); + } + ++void ++incgaps(const Arg *arg) ++{ ++ setgaps( ++ selmon->gappoh + arg->i, ++ selmon->gappov + arg->i, ++ selmon->gappih + arg->i, ++ selmon->gappiv + arg->i ++ ); ++} ++ ++void ++incigaps(const Arg *arg) ++{ ++ setgaps( ++ selmon->gappoh, ++ selmon->gappov, ++ selmon->gappih + arg->i, ++ selmon->gappiv + arg->i ++ ); ++} ++ ++void ++incihgaps(const Arg *arg) ++{ ++ setgaps( ++ selmon->gappoh, ++ selmon->gappov, ++ selmon->gappih + arg->i, ++ selmon->gappiv ++ ); ++} ++ ++void ++incivgaps(const Arg *arg) ++{ ++ setgaps( ++ selmon->gappoh, ++ selmon->gappov, ++ selmon->gappih, ++ selmon->gappiv + arg->i ++ ); ++} ++ ++void ++incogaps(const Arg *arg) ++{ ++ setgaps( ++ selmon->gappoh + arg->i, ++ selmon->gappov + arg->i, ++ selmon->gappih, ++ selmon->gappiv ++ ); ++} ++ ++void ++incohgaps(const Arg *arg) ++{ ++ setgaps( ++ selmon->gappoh + arg->i, ++ selmon->gappov, ++ selmon->gappih, ++ selmon->gappiv ++ ); ++} ++ ++void ++incovgaps(const Arg *arg) ++{ ++ setgaps( ++ selmon->gappoh, ++ selmon->gappov + arg->i, ++ selmon->gappih, ++ selmon->gappiv ++ ); ++} ++ + void + inputdevice(struct wl_listener *listener, void *data) + { +@@ -1983,6 +2087,16 @@ setfullscreen(Client *c, int fullscreen) + printstatus(); + } + ++void ++setgaps(int oh, int ov, int ih, int iv) ++{ ++ selmon->gappoh = MAX(oh, 0); ++ selmon->gappov = MAX(ov, 0); ++ selmon->gappih = MAX(ih, 0); ++ selmon->gappiv = MAX(iv, 0); ++ arrange(selmon); ++} ++ + void + setlayout(const Arg *arg) + { +@@ -2297,7 +2411,7 @@ tagmon(const Arg *arg) + void + tile(Monitor *m) + { +- unsigned int i, n = 0, mw, my, ty; ++ unsigned int i, n = 0, h, r, oe = enablegaps, ie = enablegaps, mw, my, ty; + Client *c; + + wl_list_for_each(c, &clients, link) +@@ -2305,23 +2419,32 @@ tile(Monitor *m) + n++; + if (n == 0) + return; ++ ++ if (smartgaps == n) { ++ oe = 0; // outer gaps disabled ++ } + + if (n > m->nmaster) +- mw = m->nmaster ? m->w.width * m->mfact : 0; ++ mw = m->nmaster ? (m->w.width + m->gappiv*ie) * m->mfact : 0; + else +- mw = m->w.width; +- i = my = ty = 0; ++ mw = m->w.width - 2*m->gappov*oe + m->gappiv*ie; ++ i = 0; ++ my = ty = m->gappoh*oe; + 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; ++ r = MIN(n, m->nmaster) - i; ++ h = (m->w.height - my - m->gappoh*oe - m->gappih*ie * (r - 1)) / r; ++ resize(c, (struct wlr_box){.x = m->w.x + m->gappov*oe, .y = m->w.y + my, ++ .width = mw - m->gappiv*ie, .height = h}, 0); ++ my += c->geom.height + m->gappih*ie; + } 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; ++ r = n - i; ++ h = (m->w.height - ty - m->gappoh*oe - m->gappih*ie * (r - 1)) / r; ++ resize(c, (struct wlr_box){.x = m->w.x + mw + m->gappov*oe, .y = m->w.y + ty, ++ .width = m->w.width - mw - 2*m->gappov*oe, .height = h}, 0); ++ ty += c->geom.height + m->gappih*ie; + } + i++; + } +@@ -2344,6 +2467,13 @@ togglefullscreen(const Arg *arg) + setfullscreen(sel, !sel->isfullscreen); + } + ++void ++togglegaps(const Arg *arg) ++{ ++ enablegaps = !enablegaps; ++ arrange(selmon); ++} ++ + void + toggletag(const Arg *arg) + { + +From a43fe2052be3692be4cf5f1300c31bba37f0b45e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= + +Date: Wed, 20 Jul 2022 00:15:32 -0500 +Subject: [PATCH 2/2] allow gaps in monocle layout if requested + +--- + config.def.h | 1 + + dwl.c | 6 +++++- + 2 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/config.def.h b/config.def.h +index 50dc8a26..8079702a 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -7,6 +7,7 @@ static const unsigned int gappiv = 10; /* vert inner gap between window + static const unsigned int gappoh = 10; /* horiz outer gap between windows and screen edge */ + static const unsigned int gappov = 10; /* vert outer gap between windows and screen edge */ + static const int smartgaps = 0; /* 1 means no outer gap when there is only one window */ ++static const int monoclegaps = 0; /* 1 means outer gaps in monocle layout */ + static const float rootcolor[] = {0.3, 0.3, 0.3, 1.0}; + static const float bordercolor[] = {0.5, 0.5, 0.5, 1.0}; + static const float focuscolor[] = {1.0, 0.0, 0.0, 1.0}; +diff --git a/dwl.c b/dwl.c +index 1757dd5b..e0f68fd2 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -1597,7 +1597,11 @@ monocle(Monitor *m) + wl_list_for_each(c, &clients, link) { + if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) + continue; +- resize(c, m->w, 0); ++ if (!monoclegaps) ++ resize(c, m->w, 0); ++ else ++ resize(c, (struct wlr_box){.x = m->w.x + gappoh, .y = m->w.y + gappov, ++ .width = m->w.width - 2 * gappoh, .height = m->w.height - 2 * gappov}, 0); + } + focusclient(focustop(m), 1); + } diff --git a/.config/dwl/protocols/wlr-layer-shell-unstable-v1.xml b/.config/dwl/protocols/wlr-layer-shell-unstable-v1.xml new file mode 100644 index 0000000..d62fd51 --- /dev/null +++ b/.config/dwl/protocols/wlr-layer-shell-unstable-v1.xml @@ -0,0 +1,390 @@ + + + + Copyright © 2017 Drew DeVault + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + Clients can use this interface to assign the surface_layer role to + wl_surfaces. Such surfaces are assigned to a "layer" of the output and + rendered with a defined z-depth respective to each other. They may also be + anchored to the edges and corners of a screen and specify input handling + semantics. This interface should be suitable for the implementation of + many desktop shell components, and a broad number of other applications + that interact with the desktop. + + + + + Create a layer surface for an existing surface. This assigns the role of + layer_surface, or raises a protocol error if another role is already + assigned. + + Creating a layer surface from a wl_surface which has a buffer attached + or committed is a client error, and any attempts by a client to attach + or manipulate a buffer prior to the first layer_surface.configure call + must also be treated as errors. + + 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. + + + + + + + + + + + + + + + + + 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. + + + + + + + + + + + + + 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. + + + + + + + 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. + + + + + Sets the size of the surface in surface-local coordinates. The + compositor will display the surface centered with respect to its + anchors. + + If you pass 0 for either value, the compositor will assign it and + inform you of the assignment in the configure event. You must set your + anchor to opposite edges in the dimensions you omit; not doing so is a + protocol error. Both values are 0 by default. + + Size is double-buffered, see wl_surface.commit. + + + + + + + + Requests that the compositor anchor the surface to the specified edges + and corners. If two orthogonal edges are specified (e.g. 'top' and + 'left'), then the anchor point will be the intersection of the edges + (e.g. the top left corner of the output); otherwise the anchor point + will be centered on that edge, or in the center if none is specified. + + Anchor is double-buffered, see wl_surface.commit. + + + + + + + Requests that the compositor avoids occluding an area with other + surfaces. The compositor's use of this information is + implementation-dependent - do not assume that this region will not + actually be occluded. + + A positive value is only meaningful if the surface is anchored to one + edge or an edge and both perpendicular edges. If the surface is not + anchored, anchored to only two perpendicular edges (a corner), anchored + to only two parallel edges or anchored to all edges, a positive value + will be treated the same as zero. + + A positive zone is the distance from the edge in surface-local + coordinates to consider exclusive. + + Surfaces that do not wish to have an exclusive zone may instead specify + how they should interact with surfaces that do. If set to zero, the + surface indicates that it would like to be moved to avoid occluding + surfaces with a positive exclusive zone. If set to -1, the surface + indicates that it would not like to be moved to accommodate for other + surfaces, and the compositor should extend it all the way to the edges + it is anchored to. + + For example, a panel might set its exclusive zone to 10, so that + maximized shell surfaces are not shown on top of it. A notification + might set its exclusive zone to 0, so that it is moved to avoid + occluding the panel, but shell surfaces are shown underneath it. A + wallpaper or lock screen might set their exclusive zone to -1, so that + they stretch below or over the panel. + + The default value is 0. + + Exclusive zone is double-buffered, see wl_surface.commit. + + + + + + + Requests that the surface be placed some distance away from the anchor + point on the output, in surface-local coordinates. Setting this value + for edges you are not anchored to has no effect. + + The exclusive zone includes the margin. + + Margin is double-buffered, see wl_surface.commit. + + + + + + + + + + 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. + + + + + 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. + + + + + 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. + + + + + 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. + + + + + + + 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. + + + + + + + This assigns an xdg_popup's parent to this layer_surface. This popup + should have been created via xdg_surface::get_popup with the parent set + to NULL, and this request must be invoked before committing the popup's + initial state. + + See the documentation of xdg_popup for more details about what an + xdg_popup is and how it is used. + + + + + + + When a configure event is received, if a client commits the + surface in response to the configure event, then the client + must make an ack_configure request sometime before the commit + request, passing along the serial of the configure event. + + If the client receives multiple configure events before it + can respond to one, it only has to ack the last configure event. + + A client is not required to commit immediately after sending + an ack_configure request - it may even ack_configure several times + before its next surface commit. + + A client may send multiple ack_configure requests before committing, but + only the last request sent before a commit indicates which configure + event the client really is responding to. + + + + + + + This request destroys the layer surface. + + + + + + The configure event asks the client to resize its surface. + + Clients should arrange their surface for the new states, and then send + an ack_configure request with the serial sent in this configure event at + some point before committing the new surface. + + The client is free to dismiss all but the last configure event it + received. + + The width and height arguments specify the size of the window in + surface-local coordinates. + + The size is a hint, in the sense that the client is free to ignore it if + it doesn't resize, pick a smaller size (to satisfy aspect ratio or + resize in steps of NxM pixels). If the client picks a smaller size and + is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the + surface will be centered on this axis. + + If the width or height arguments are zero, it means the client should + decide its own window dimension. + + + + + + + + + The closed event is sent by the compositor when the surface will no + longer be shown. The output may have been destroyed or the user may + have asked for it to be removed. Further changes to the surface will be + ignored. The client should destroy the resource after receiving this + event, and create a new surface if they so choose. + + + + + + + + + + + + + + + + + + + + + + Change the layer that the surface is rendered on. + + Layer is double-buffered, see wl_surface.commit. + + + + + diff --git a/.config/dwl/scripts/checkUpdates.sh b/.config/dwl/scripts/checkUpdates.sh new file mode 100755 index 0000000..59ae3f2 --- /dev/null +++ b/.config/dwl/scripts/checkUpdates.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# Check updates on Arch Linux +# Note: Create cron on /etc/cron.d/checkupdates with the following lines: +# 0 * * * * root /usr/bin/pacman -Sy +# 30 * * * * root /usr/bin/pacman -Sy +if [ -f /usr/bin/pacman ] ; then + num_packages=$(pacman -Qu | wc -l) + echo " ${num_packages} " + +# Check updates on Ubuntu/Debian/Devuan +# Note: Create cron on /etc/cron.d/checkupdates with the following lines: +# 0 * * * * root /usr/bin/aptitude update +# 30 * * * * root /usr/bin/aptitude update +elif [ -f /usr/bin/aptitude ] ; then + num_packages=$(aptitude search "~U" | wc -l) + echo " ${num_packages} " + +# Disable for other distros +else + echo " 0 " +fi diff --git a/.config/dwl/scripts/cpu_info.sh b/.config/dwl/scripts/cpu_info.sh new file mode 100755 index 0000000..b09d830 --- /dev/null +++ b/.config/dwl/scripts/cpu_info.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +check_sensor=$(sensors | grep "Tdie:" 2> /dev/null) +if [ -z "${check_sensor}" ] ; then + check_sensor=$(sensors | grep "Tctl:" 2> /dev/null) + if [ -z "${check_sensor}" ] ; then + CPU_USAGE=$(~/.config/dwl/scripts/cpu_load.sh -p) + echo "$CPU_USAGE" | awk '{ printf("%6s \n"), $1, $2 }' + else + TEMP=$(sensors | grep 'Package id 0:\|Tctl' | grep ':[ ]*+[0-9]*.[0-9]*°C' -o | grep '+[0-9]*.[0-9]*°C' -o) + #CPU_USAGE=$(mpstat 1 1 | awk '/Average:/ {printf("%s\n", $(NF-9))}') + CPU_USAGE=$(~/.config/dwl/scripts/cpu_load.sh -p) + echo "$CPU_USAGE $TEMP" | awk '{ printf("%6s @ %s \n"), $1, $2 }' + fi +else + TEMP=$(sensors | grep 'Package id 0:\|Tdie' | grep ':[ ]*+[0-9]*.[0-9]*°C' -o | grep '+[0-9]*.[0-9]*°C' -o) + #CPU_USAGE=$(mpstat 1 1 | awk '/Average:/ {printf("%s\n", $(NF-9))}') + CPU_USAGE=$(~/.config/dwl/scripts/cpu_load.sh -p) + echo "$CPU_USAGE $TEMP" | awk '{ printf("%6s @ %s \n"), $1, $2 }' +fi diff --git a/.config/dwl/scripts/cpu_load.sh b/.config/dwl/scripts/cpu_load.sh new file mode 100755 index 0000000..57fc7e5 --- /dev/null +++ b/.config/dwl/scripts/cpu_load.sh @@ -0,0 +1,83 @@ +#!/bin/bash + +# Script to show cpu +# Created by q3aql (q3aql@protonmail.ch) +# Licensed by GPL v.2 +# Date: 10-01-2020 +# -------------------------------------- +VERSION="1.0" + + +# Variables +cpuPercentage=$(top -b -n1 | grep \%Cpu | awk '{print 100-$8}') +showCpuPercentage=$(echo ${cpuPercentage}) +showCpuPercentageInteger=$(echo ${showCpuPercentage} | cut -d "." -f 1) + +# Show percentage bar +if [ ${showCpuPercentageInteger} -ge 0 ] ; then + showCpuPercentageBar="=" +fi +if [ ${showCpuPercentageInteger} -ge 3 ] ; then + showCpuPercentageBar="==" +fi +if [ ${showCpuPercentageInteger} -ge 12 ] ; then + showCpuPercentageBar="===" +fi +if [ ${showCpuPercentageInteger} -ge 18 ] ; then + showCpuPercentageBar="====" +fi +if [ ${showCpuPercentageInteger} -ge 25 ] ; then + showCpuPercentageBar="=====" +fi +if [ ${showCpuPercentageInteger} -ge 35 ] ; then + showCpuPercentageBar="======" +fi +if [ ${showCpuPercentageInteger} -ge 40 ] ; then + showCpuPercentageBar="=======" +fi +if [ ${showCpuPercentageInteger} -ge 45 ] ; then + showCpuPercentageBar="========" +fi +if [ ${showCpuPercentageInteger} -ge 50 ] ; then + showCpuPercentageBar="==========" +fi +if [ ${showCpuPercentageInteger} -ge 62 ] ; then + showCpuPercentageBar="=============" +fi +if [ ${showCpuPercentageInteger} -ge 75 ] ; then + showCpuPercentageBar="===============" +fi +if [ ${showCpuPercentageInteger} -ge 85 ] ; then + showCpuPercentageBar="=================" +fi +if [ ${showCpuPercentageInteger} -ge 90 ] ; then + showCpuPercentageBar="==================" +fi +if [ ${showCpuPercentageInteger} -ge 95 ] ; then + showCpuPercentageBar="===================" +fi +if [ ${showCpuPercentageInteger} -ge 100 ] ; then + showCpuPercentageBar="====================" +fi + +# Show results +if [ "$1" == "-p" ]; then + echo ${showCpuPercentage}% +elif [ "$1" == "-b" ]; then + echo ${showCpuPercentageBar} +else + echo "" + echo " cpuinfo v$VERSION" + echo " ------------" + echo "" + echo " CpuPercentage Use:" + echo " ${showCpuPercentageBar} ${showCpuPercentage}%" + echo "" + echo " Available commands:" + echo "" + echo " cpuinfo.sh -p | Show CpuPercentage" + echo " cpuinfo.sh -b | Show CpuPercentage Bar" + echo "" + echo " Note: Conky require 'maximum_width = 240'" + echo "" +fi diff --git a/.config/dwl/scripts/current_date.sh b/.config/dwl/scripts/current_date.sh new file mode 100755 index 0000000..224de78 --- /dev/null +++ b/.config/dwl/scripts/current_date.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +current_date=$(date "+%d/%m/%Y %H:%M") +echo " ${current_date} " diff --git a/.config/dwl/scripts/disk_info.sh b/.config/dwl/scripts/disk_info.sh new file mode 100755 index 0000000..da3f2b2 --- /dev/null +++ b/.config/dwl/scripts/disk_info.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +df -h / | awk '/\//{ printf(" %4s / %s \n", $4, $2) }' diff --git a/.config/dwl/scripts/get_volume.sh b/.config/dwl/scripts/get_volume.sh new file mode 100755 index 0000000..a501178 --- /dev/null +++ b/.config/dwl/scripts/get_volume.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +get_volume=$(amixer | grep "%" | head -1 | cut -d "%" -f 1 | cut -d "[" -f 2) +echo " ${get_volume}% " diff --git a/.config/dwl/scripts/kernel_version.sh b/.config/dwl/scripts/kernel_version.sh new file mode 100755 index 0000000..8483f29 --- /dev/null +++ b/.config/dwl/scripts/kernel_version.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# Parameters +longNumber=2 +kernelCommand="uname -r" +archCommand=$(uname -m) + +# Kernel version +kernelVersion="" +count=1 + +# Extract numbers of kernel version +kernelVersionTemp=$(uname -r | cut -d "." -f ${count}) + kernelVersionTempDot="${kernelVersionTemp}" + kernelVersion="${kernelVersion}${kernelVersionTempDot}" + count=$(expr ${count} + 1) + +while [ ${count} -le ${longNumber} ] ; do + kernelVersionTemp=$(uname -r | cut -d "." -f ${count}) + kernelVersionTempDot=".${kernelVersionTemp}" + kernelVersion="${kernelVersion}${kernelVersionTempDot}" + count=$(expr ${count} + 1) +done + +kernelVersionTemp=$(uname -r | cut -d "." -f ${count} | cut -d "-" -f 1) +kernelVersionTempDot=".${kernelVersionTemp}" +kernelVersion=${kernelVersion}${kernelVersionTempDot} + +# Apply arch +#kernelVersion=${kernelVersion}-${archCommand} +kernelVersion=${kernelVersion} +#echo "Kernel: Linux ${kernelVersion} " +echo " ${kernelVersion} " + diff --git a/.config/dwl/scripts/kernel_version_num.sh b/.config/dwl/scripts/kernel_version_num.sh new file mode 100755 index 0000000..8483f29 --- /dev/null +++ b/.config/dwl/scripts/kernel_version_num.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# Parameters +longNumber=2 +kernelCommand="uname -r" +archCommand=$(uname -m) + +# Kernel version +kernelVersion="" +count=1 + +# Extract numbers of kernel version +kernelVersionTemp=$(uname -r | cut -d "." -f ${count}) + kernelVersionTempDot="${kernelVersionTemp}" + kernelVersion="${kernelVersion}${kernelVersionTempDot}" + count=$(expr ${count} + 1) + +while [ ${count} -le ${longNumber} ] ; do + kernelVersionTemp=$(uname -r | cut -d "." -f ${count}) + kernelVersionTempDot=".${kernelVersionTemp}" + kernelVersion="${kernelVersion}${kernelVersionTempDot}" + count=$(expr ${count} + 1) +done + +kernelVersionTemp=$(uname -r | cut -d "." -f ${count} | cut -d "-" -f 1) +kernelVersionTempDot=".${kernelVersionTemp}" +kernelVersion=${kernelVersion}${kernelVersionTempDot} + +# Apply arch +#kernelVersion=${kernelVersion}-${archCommand} +kernelVersion=${kernelVersion} +#echo "Kernel: Linux ${kernelVersion} " +echo " ${kernelVersion} " + diff --git a/.config/dwl/scripts/launch-spectrwm.sh b/.config/dwl/scripts/launch-spectrwm.sh new file mode 100755 index 0000000..8406e40 --- /dev/null +++ b/.config/dwl/scripts/launch-spectrwm.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +# Terminate already running bar instances +killall -q polybar + +# Restore config for i3 +#cp -rfv ~/.config/polybar/config.i3 ~/.config/polybar/config + +# Wait until the processes have been shut down +while pgrep -u $UID -x polybar >/dev/null; do sleep 1; done + +if type "xrandr"; then + for m in $(xrandr --query | grep " connected" | cut -d" " -f1); do + MONITOR=$m polybar --reload mainbar-spectrwm -c ~/.config/polybar/config & + done +else + polybar --reload mainbar-spectrwm -c ~/.config/polybar/config & +fi + +# Launch bar1 and bar2 +#polybar example & + +#echo "Bars launched..." diff --git a/.config/dwl/scripts/launch.sh b/.config/dwl/scripts/launch.sh new file mode 100755 index 0000000..93692e1 --- /dev/null +++ b/.config/dwl/scripts/launch.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +# Terminate already running bar instances +killall -q polybar + +# Restore config for i3 +#cp -rfv ~/.config/polybar/config.i3 ~/.config/polybar/config + +# Wait until the processes have been shut down +while pgrep -u $UID -x polybar >/dev/null; do sleep 1; done + +if type "xrandr"; then + for m in $(xrandr --query | grep " connected" | cut -d" " -f1); do + MONITOR=$m polybar --reload mainbar-i3 -c ~/.config/polybar/config & + done +else + polybar --reload mainbar-i3 -c ~/.config/polybar/config & +fi + +# Launch bar1 and bar2 +#polybar example & + +#echo "Bars launched..." diff --git a/.config/dwl/scripts/mem_info.sh b/.config/dwl/scripts/mem_info.sh new file mode 100755 index 0000000..ac8c2ad --- /dev/null +++ b/.config/dwl/scripts/mem_info.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +# Configuration variable +python_bin="/usr/bin/python3" +memfile="/proc/meminfo" +size="G" # Change to M for MiB + +# Variables +memTotal=$(cat ${memfile} | grep -i "memtotal:" | head -1 | tr -s " " | cut -d " " -f 2) +memActive=$(cat ${memfile} | grep -i "memavailable:" | head -1 | tr -s " " | cut -d " " -f 2) +memActive=$(expr ${memTotal} - ${memActive}) + +# Variables to calculate +memTotalM=$(expr ${memTotal} / 1024 ) +memActiveM=$(expr ${memActive} / 1024) +if [ -f ${python_bin} ] ; then + memPercentage=$(echo "n=${memActive}/${memTotal}*100 ; print(n)" | ${python_bin}) + memTotalG=$(echo "n=${memTotalM}/1024 ; print(n)" | ${python_bin} | tr -s " " | cut -c1-4) + memActiveG=$(echo "n=${memActiveM}/1024 ; print(n)" | ${python_bin} | tr -s " " | cut -c1-4) +elif [ -f /usr/bin/calc ] ; then + memPercentage=$(calc ${memActive} / ${memTotal} \* 100) + memTotalG=$(calc ${memTotalM} / 1024 | tr -s " " | cut -c1-5) + memActiveG=$(calc ${memActiveM} / 1024 | tr -s " " | cut -c1-5) +else + memPercentage=$(expr ${memActive} / ${memTotal} \* 100) + memTotalG=$(expr ${memTotalM} / 1024 | tr -s " " | cut -c1-5) + memActiveG=$(expr ${memActiveM} / 1024 | tr -s " " | cut -c1-5) +fi + +# Variables to show +showMemPercentage=$(echo ${memPercentage} | cut -d "~" -f 2 | cut -d "." -f 1) +if [ "${size}" == "G" ] ; then + showMemTotal="${memTotalG}Gi" + showMemActive="${memActiveG}Gi" +elif [ "${size}" == "M" ] ; then + showMemTotal="${memTotalM}Mi" + showMemActive="${memActiveM}Mi" +else + showMemTotal="${memTotalG}Gi" + showMemActive="${memActiveG}Gi" +fi + +echo -n " " +memshowactive=$(echo ${showMemActive}) +memshowtotal=$(echo ${showMemTotal}) +echo -n ${memshowactive}/${memshowtotal} +echo " " diff --git a/.config/dwl/scripts/mem_info_new.sh b/.config/dwl/scripts/mem_info_new.sh new file mode 100755 index 0000000..8ed29c1 --- /dev/null +++ b/.config/dwl/scripts/mem_info_new.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# Configuration variables +memfile="/proc/meminfo" +size="G" # Change to M for MiB + +# Variables +memTotal=$(cat ${memfile} | grep -i "memtotal:" | head -1 | tr -s " " | cut -d " " -f 2) +memActive=$(cat ${memfile} | grep -i "memavailable:" | head -1 | tr -s " " | cut -d " " -f 2) +memActive=$(expr ${memTotal} - ${memActive}) + +# Variables to calculate +memTotalM=$(expr ${memTotal} / 1024 ) +memActiveM=$(expr ${memActive} / 1024) +if [ -f /usr/bin/calc ] ; then + memPercentage=$(calc ${memActive} / ${memTotal} \* 100) + memTotalG=$(calc ${memTotalM} / 1024 | tr -s " " | cut -c1-5) + memActiveG=$(calc ${memActiveM} / 1024 | tr -s " " | cut -c1-5) +else + memPercentage=$(expr ${memActive} / ${memTotal} \* 100) + memTotalG=$(expr ${memTotalM} / 1024 | tr -s " " | cut -c1-5) + memActiveG=$(expr ${memActiveM} / 1024 | tr -s " " | cut -c1-5) +fi + +# Variables to show +showMemPercentage=$(echo ${memPercentage} | cut -d "~" -f 2 | cut -d "." -f 1) +if [ "${size}" == "G" ] ; then + showMemTotal="${memTotalG}Gi" + showMemActive="${memActiveG}Gi" +elif [ "${size}" == "M" ] ; then + showMemTotal="${memTotalM}Mi" + showMemActive="${memActiveM}Mi" +else + showMemTotal="${memTotalG}Gi" + showMemActive="${memActiveG}Gi" +fi + +echo -n " " +memshowactive=$(echo ${showMemActive}) +memshowtotal=$(echo ${showMemTotal}) +echo -n ${memshowactive}/${memshowtotal} +echo " " diff --git a/.config/dwl/scripts/mem_info_old.sh b/.config/dwl/scripts/mem_info_old.sh new file mode 100755 index 0000000..6c8eeec --- /dev/null +++ b/.config/dwl/scripts/mem_info_old.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +mem_info=$(free -h | awk '/Mem:/ { printf(" %5s/%s \n", $3, $2) }') +echo -n " " +echo -n ${mem_info} +echo " " diff --git a/.config/dwl/scripts/status_bar.sh b/.config/dwl/scripts/status_bar.sh new file mode 100755 index 0000000..276aa83 --- /dev/null +++ b/.config/dwl/scripts/status_bar.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +status_bar=0 + +while [ ${status_bar} -eq 0 ] ; do + updates=$(~/.config/dwl/scripts/checkUpdates.sh) + kernel=$(~/.config/dwl/scripts/kernel_version.sh) + cpuinfo=$(~/.config/dwl/scripts/cpu_info.sh) + meminfo=$(~/.config/dwl/scripts/mem_info.sh) + volume=$(~/.config/dwl/scripts/get_volume.sh) + date=$(~/.config/dwl/scripts/current_date.sh) + echo "${updates} ${kernel} ${cpuinfo} ${meminfo} ${volume} ${date}" + sleep 2 +done diff --git a/.config/dwl/somebar/.builds/archlinux.yml b/.config/dwl/somebar/.builds/archlinux.yml new file mode 100644 index 0000000..7c4f209 --- /dev/null +++ b/.config/dwl/somebar/.builds/archlinux.yml @@ -0,0 +1,19 @@ +image: archlinux +packages: + - base-devel + - meson + - wayland + - wayland-protocols + - cairo + - pango +sources: + - https://git.sr.ht/~raphi/somebar +tasks: + - setup: | + cd somebar + meson build --fatal-meson-warnings + cp src/config.def.hpp src/config.hpp + - build: | + cd somebar/build + ninja + sudo ninja install diff --git a/.config/dwl/somebar/.builds/freebsd.yml b/.config/dwl/somebar/.builds/freebsd.yml new file mode 100644 index 0000000..90e6f1a --- /dev/null +++ b/.config/dwl/somebar/.builds/freebsd.yml @@ -0,0 +1,20 @@ +image: freebsd/latest +packages: + - devel/evdev-proto + - devel/meson + - devel/pkgconf + - graphics/cairo + - graphics/wayland + - graphics/wayland-protocols + - x11-toolkits/pango +sources: + - https://git.sr.ht/~raphi/somebar +tasks: + - setup: | + cd somebar + meson build --fatal-meson-warnings + cp src/config.def.hpp src/config.hpp + - build: | + cd somebar/build + ninja + sudo ninja install \ No newline at end of file diff --git a/.config/dwl/somebar/.editorconfig b/.config/dwl/somebar/.editorconfig new file mode 100644 index 0000000..5c4a037 --- /dev/null +++ b/.config/dwl/somebar/.editorconfig @@ -0,0 +1,5 @@ +root = true + +[*] +indent_style = tab +indent_brace_style = K&R diff --git a/.config/dwl/somebar/LICENSE b/.config/dwl/somebar/LICENSE new file mode 100644 index 0000000..7bebc11 --- /dev/null +++ b/.config/dwl/somebar/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2021 Raphael Robatsch + +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. diff --git a/.config/dwl/somebar/README.md b/.config/dwl/somebar/README.md new file mode 100644 index 0000000..b61c935 --- /dev/null +++ b/.config/dwl/somebar/README.md @@ -0,0 +1,113 @@ +# somebar - dwm-like bar for dwl + +![Screenshot](screenshot.png) + +The mailing list for this project is +[~raphi/public-inbox@lists.sr.ht](mailto:~raphi/public-inbox@lists.sr.ht). + +## Dependencies + +* c++ compiler, meson, and ninja +* wayland-scanner +* libwayland-client +* libwayland-cursor +* libcairo +* libpango +* libpangocairo + +``` +sudo apt install build-essential meson ninja-build \ + libwayland-bin libwayland-client0 libwayland-cursor0 libwayland-dev \ + libcairo2 libcairo2-dev \ + libpango-1.0-0 libpango1.0-dev libpangocairo-1.0-0 + +# or + +sudo pacman -S base-devel meson \ + wayland wayland-protocols cairo pango +``` + +## Configuration + +Copy `src/config.def.hpp` to `src/config.hpp`, and adjust if needed. + +## Building + +``` +cp src/config.def.hpp src/config.hpp +meson setup build +ninja -C build +sudo ninja -C build install +``` + +## Usage + +You must start somebar using dwl's `-s` flag, e.g. `dwl -s somebar`. + +Somebar can be controlled by writing to `$XDG_RUNTIME_DIR/somebar-0` +or the path defined by `-s` argument. +The following commands are supported: + +* `status TEXT`: Updates the status bar +* `hide MONITOR` Hides somebar on the specified monitor +* `show MONITOR` Shows somebar on the specified monitor +* `toggle MONITOR` Toggles somebar on the specified monitor + +MONITOR is an zxdg_output_v1 name, which can be determined e.g. using `weston-info`. +Additionally, MONITOR can be `all` (all monitors) or `selected` (the monitor with focus). + +Commands can be sent either by writing to the file name above, or equivalently by calling +somebar with the `-c` argument. For example: `somebar -c toggle all`. This is recommended +for shell scripts, as there is no race-free way to write to a file only if it exists. + +The maintainer of somebar also maintains +[someblocks](https://git.sr.ht/~raphi/someblocks/), +a fork of [dwmblocks](https://github.com/torrinfail/dwmblocks) that outputs +to somebar instead of dwm's bar. + +## IPC + +Out of the box, somebar cannot control dwl. Clicking on the tag bar has no +effect, because there is no communication channel from somebar back to dwl. + +If you apply the patch `contrib/ipc.patch`, then somebar will + +1. Not read stdin anymore, and instead use a wayland extension to read dwl's + state. This means you must close stdin yourself, if you choose to launch + somebar using dwl's -s flag. +2. somebar can use the same wayland extension to send commands back to dwl. + This means that clicking on tags will switch to that tag (this can of course + be customized in config.h). + +If you apply the IPC patch to somebar, then +**dwl must have the [wayland-ipc patch](https://git.sr.ht/~raphi/dwl/blob/master/patches/wayland-ipc.patch) applied too**, +since dwl must implement the wayland extension too. + +## Other patches + +Like all suckless software, somebar can be customized via patches. You can find some patches in the contrib folder with descriptions written in them. + +## License + +somebar - dwm-like bar for dwl + +Copyright (c) 2021 Raphael Robatsch + +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. diff --git a/.config/dwl/somebar/contrib/colorless-status.patch b/.config/dwl/somebar/contrib/colorless-status.patch new file mode 100644 index 0000000..f280070 --- /dev/null +++ b/.config/dwl/somebar/contrib/colorless-status.patch @@ -0,0 +1,15 @@ +From: medanisjbara anis2834133766619@gmail.com +Date: Mon, 14 Nov 2022 10:28:00 +Description: sets the color of status component to inactive +diff --git a/src/bar.cpp b/src/bar.cpp +index fab5a8f..aebe28b 100644 +--- a/src/bar.cpp ++++ b/src/bar.cpp +@@ -266,6 +266,7 @@ void Bar::renderStatus() + cairo_fill(_painter); + + _x = start; ++ setColorScheme(colorInactive); + renderComponent(_statusCmp); + } + diff --git a/.config/dwl/somebar/contrib/hide-vacant-tags.patch b/.config/dwl/somebar/contrib/hide-vacant-tags.patch new file mode 100644 index 0000000..7d27ce1 --- /dev/null +++ b/.config/dwl/somebar/contrib/hide-vacant-tags.patch @@ -0,0 +1,34 @@ +From: medanisjbara anis2834133766619@gmail.com +Date: Mon, 14 Nov 2022 22:52:00 +Description: somebar equivalent of https://dwm.suckless.org/patches/hide_vacant_tags +diff --git a/src/bar.cpp b/src/bar.cpp +index fab5a8f..38e7b5f 100644 +--- a/src/bar.cpp ++++ b/src/bar.cpp +@@ -240,12 +240,22 @@ void Bar::render() + + void Bar::renderTags() + { ++ bool focused; + for (auto &tag : _tags) { +- setColorScheme( +- tag.state & TagState::Active ? colorActive : colorInactive, +- tag.state & TagState::Urgent); +- renderComponent(tag.component); ++ focused = false; + auto indicators = std::min(tag.numClients, static_cast(_bufs->height/2)); ++ for (auto ind = 0; ind < indicators; ind++) { ++ if (tag.focusedClient){ ++ focused = true; ++ } ++ } ++ ++ if (tag.state & TagState::Active || focused){ ++ setColorScheme( ++ tag.state & TagState::Active ? colorActive : colorInactive, ++ tag.state & TagState::Urgent); ++ renderComponent(tag.component); ++ } + for (auto ind = 0; ind < indicators; ind++) { + auto w = ind == tag.focusedClient ? 7 : 1; + cairo_move_to(_painter, tag.component.x, ind*2+0.5); diff --git a/.config/dwl/somebar/contrib/indicator-size-props.patch b/.config/dwl/somebar/contrib/indicator-size-props.patch new file mode 100644 index 0000000..ac17520 --- /dev/null +++ b/.config/dwl/somebar/contrib/indicator-size-props.patch @@ -0,0 +1,54 @@ +From: medanisjbara anis2834133766619@gmail.com +Date: Mon, 15 Nov 2022 08:16:00 +Description: lets config.h customize indicators sizes +diff --git a/src/bar.cpp b/src/bar.cpp +index fab5a8f..c0e070c 100644 +--- a/src/bar.cpp ++++ b/src/bar.cpp +@@ -247,11 +247,11 @@ void Bar::renderTags() + renderComponent(tag.component); + auto indicators = std::min(tag.numClients, static_cast(_bufs->height/2)); + for (auto ind = 0; ind < indicators; ind++) { +- auto w = ind == tag.focusedClient ? 7 : 1; ++ auto w = ind == tag.focusedClient ? indprops.focused_width : indprops.width; + cairo_move_to(_painter, tag.component.x, ind*2+0.5); + cairo_rel_line_to(_painter, w, 0); + cairo_close_path(_painter); +- cairo_set_line_width(_painter, 1); ++ cairo_set_line_width(_painter, ind == tag.focusedClient ? indprops.focused_height : indprops.height); + cairo_stroke(_painter); + } + } +diff --git a/src/common.hpp b/src/common.hpp +index aed4480..acdca1b 100644 +--- a/src/common.hpp ++++ b/src/common.hpp +@@ -34,6 +34,13 @@ struct Button { + const Arg arg; + }; + ++struct IndicatorProps { ++ int width; ++ int height; ++ int focused_width; ++ int focused_height; ++}; ++ + extern wl_display* display; + extern wl_compositor* compositor; + extern wl_shm* shm; +diff --git a/src/config.def.hpp b/src/config.def.hpp +index 40a8c95..d51fee8 100644 +--- a/src/config.def.hpp ++++ b/src/config.def.hpp +@@ -25,3 +25,10 @@ static std::vector tagNames = { + constexpr Button buttons[] = { + { ClkStatusText, BTN_RIGHT, spawn, {.v = termcmd} }, + }; ++ ++constexpr IndicatorProps indprops = { ++ 5, /* unfocused indicator width */ ++ 5, /* unfocused indicator height */ ++ 7, /* focused indicator width */ ++ 1 /* focused indicator height */ ++}; diff --git a/.config/dwl/somebar/contrib/ipc.patch b/.config/dwl/somebar/contrib/ipc.patch new file mode 100644 index 0000000..0b11123 --- /dev/null +++ b/.config/dwl/somebar/contrib/ipc.patch @@ -0,0 +1,504 @@ +Replaces somebar's channel to dwl from stdin to a wayland extension. + +Normally, somebar reads dwl's state by reading from stdin. This requires +that somebar is started from dwl, and does not allow sending commands back +to dwl. + +This patch replaces this channel with a wayland protocol extension. somebar +can use this protocol extension to observe and update the dwl window management +state. + +Important! dwl must have the wayland-ipc patch applied for this to work! +https://git.sr.ht/~raphi/dwl/blob/master/patches/wayland-ipc.patch +diff --git a/protocols/meson.build b/protocols/meson.build +index 7bd222b..5752608 100644 +--- a/protocols/meson.build ++++ b/protocols/meson.build +@@ -15,6 +15,7 @@ wayland_xmls = [ + wl_protocol_dir + '/stable/xdg-shell/xdg-shell.xml', + wl_protocol_dir + '/unstable/xdg-output/xdg-output-unstable-v1.xml', + 'wlr-layer-shell-unstable-v1.xml', ++ 'net-tapesoftware-dwl-wm-unstable-v1.xml', + ] + wayland_sources = [ + wayland_scanner_code.process(wayland_xmls), +diff --git a/protocols/net-tapesoftware-dwl-wm-unstable-v1.xml b/protocols/net-tapesoftware-dwl-wm-unstable-v1.xml +new file mode 100644 +index 0000000..390f5a1 +--- /dev/null ++++ b/protocols/net-tapesoftware-dwl-wm-unstable-v1.xml +@@ -0,0 +1,164 @@ ++ ++ ++ ++ Copyright (c) 2021 Raphael Robatsch ++ ++ 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. ++ ++ ++ ++ ++ This interface is exposed as a global in the wl_registry. ++ ++ Clients can use this protocol to receive updates of the window manager ++ state (active tags, active layout, and focused window). ++ Clients can also control this state. ++ ++ After binding, the client will receive the available tags and layouts ++ with the 'tag' and 'layout' events. These can be used in subsequent ++ dwl_wm_monitor_v1.set_tags/set_layout requests, and to interpret the ++ dwl_wm_monitor_v1.layout/tag events. ++ ++ ++ ++ ++ This request indicates that the client will not use the dwl_wm ++ object any more. Objects that have been created through this instance ++ are not affected. ++ ++ ++ ++ ++ ++ Gets a dwl monitor for the specified output. The window manager ++ state on the output can be controlled using the monitor. ++ ++ ++ ++ ++ ++ ++ ++ This event is sent immediately after binding. ++ A roundtrip after binding guarantees that the client has received all tags. ++ ++ ++ ++ ++ ++ ++ This event is sent immediately after binding. ++ A roundtrip after binding guarantees that the client has received all layouts. ++ ++ ++ ++ ++ ++ ++ ++ Observes and controls one monitor. ++ ++ Events are double-buffered: Clients should cache all events and only ++ redraw themselves once the 'frame' event is sent. ++ ++ Requests are not double-buffered: The compositor will update itself ++ immediately. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ This request indicates that the client is done with this dwl_monitor. ++ All further requests are ignored. ++ ++ ++ ++ ++ ++ If 'selected' is nonzero, this monitor is the currently selected one. ++ ++ ++ ++ ++ ++ ++ Announces the update of a tag. num_clients and focused_client can be ++ used to draw client indicators. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Announces the update of the selected layout. ++ ++ ++ ++ ++ ++ ++ Announces the update of the selected client. ++ ++ ++ ++ ++ ++ ++ Sent after all other events belonging to the status update has been sent. ++ Clients should redraw themselves now. ++ ++ ++ ++ ++ ++ Changes are applied immediately. ++ ++ ++ ++ ++ ++ ++ ++ tags are updated as follows: ++ new_tags = (current_tags AND and_tags) XOR xor_tags ++ ++ Changes are applied immediately. ++ ++ ++ ++ ++ ++ ++ ++ Changes are applied immediately. ++ ++ ++ ++ ++ +diff --git a/src/common.hpp b/src/common.hpp +index aed4480..12a3e2e 100644 +--- a/src/common.hpp ++++ b/src/common.hpp +@@ -10,6 +10,7 @@ + #include + #include + #include "wlr-layer-shell-unstable-v1-client-protocol.h" ++#include "net-tapesoftware-dwl-wm-unstable-v1-client-protocol.h" + + struct Color { + Color() {} +@@ -38,7 +39,14 @@ extern wl_display* display; + extern wl_compositor* compositor; + extern wl_shm* shm; + extern zwlr_layer_shell_v1* wlrLayerShell; ++extern std::vector tagNames; ++extern std::vector layoutNames; + ++void view(Monitor& m, const Arg& arg); ++void toggleview(Monitor& m, const Arg& arg); ++void setlayout(Monitor& m, const Arg& arg); ++void tag(Monitor& m, const Arg& arg); ++void toggletag(Monitor& m, const Arg& arg); + void spawn(Monitor&, const Arg& arg); + void setCloexec(int fd); + [[noreturn]] void die(const char* why); +@@ -59,6 +67,7 @@ WL_DELETER(wl_output, wl_output_release); + WL_DELETER(wl_pointer, wl_pointer_release); + WL_DELETER(wl_seat, wl_seat_release); + WL_DELETER(wl_surface, wl_surface_destroy); ++WL_DELETER(znet_tapesoftware_dwl_wm_monitor_v1, znet_tapesoftware_dwl_wm_monitor_v1_release); + WL_DELETER(zwlr_layer_surface_v1, zwlr_layer_surface_v1_destroy); + + WL_DELETER(cairo_t, cairo_destroy); +diff --git a/src/config.def.hpp b/src/config.def.hpp +index 40a8c95..a9560cb 100644 +--- a/src/config.def.hpp ++++ b/src/config.def.hpp +@@ -16,12 +16,11 @@ constexpr ColorScheme colorInactive = {Color(0xbb, 0xbb, 0xbb), Color(0x22, 0x22 + constexpr ColorScheme colorActive = {Color(0xee, 0xee, 0xee), Color(0x00, 0x55, 0x77)}; + constexpr const char* termcmd[] = {"foot", nullptr}; + +-static std::vector tagNames = { +- "1", "2", "3", +- "4", "5", "6", +- "7", "8", "9", +-}; +- + constexpr Button buttons[] = { ++ { ClkTagBar, BTN_LEFT, view, {0} }, ++ { ClkTagBar, BTN_RIGHT, tag, {0} }, ++ { ClkTagBar, BTN_MIDDLE, toggletag, {0} }, ++ { ClkLayoutSymbol, BTN_LEFT, setlayout, {.ui = 0} }, ++ { ClkLayoutSymbol, BTN_RIGHT, setlayout, {.ui = 2} }, + { ClkStatusText, BTN_RIGHT, spawn, {.v = termcmd} }, + }; +diff --git a/src/main.cpp b/src/main.cpp +index 6198d8b..9e7549a 100644 +--- a/src/main.cpp ++++ b/src/main.cpp +@@ -3,7 +3,6 @@ + + #include + #include +-#include + #include + #include + #include +@@ -21,8 +20,8 @@ + #include "wlr-layer-shell-unstable-v1-client-protocol.h" + #include "xdg-output-unstable-v1-client-protocol.h" + #include "xdg-shell-client-protocol.h" ++#include "net-tapesoftware-dwl-wm-unstable-v1-client-protocol.h" + #include "common.hpp" +-#include "config.hpp" + #include "bar.hpp" + #include "line_buffer.hpp" + +@@ -34,6 +33,7 @@ struct Monitor { + bool desiredVisibility {true}; + bool hasData; + uint32_t tags; ++ wl_unique_ptr dwlMonitor; + }; + + struct SeatPointer { +@@ -54,8 +54,6 @@ static void updatemon(Monitor &mon); + static void onReady(); + static void setupStatusFifo(); + static void onStatus(); +-static void onStdin(); +-static void handleStdin(const std::string& line); + static void updateVisibility(const std::string& name, bool(*updater)(bool)); + static void onGlobalAdd(void*, wl_registry* registry, uint32_t name, const char* interface, uint32_t version); + static void onGlobalRemove(void*, wl_registry* registry, uint32_t name); +@@ -67,6 +65,9 @@ wl_display* display; + wl_compositor* compositor; + wl_shm* shm; + zwlr_layer_shell_v1* wlrLayerShell; ++znet_tapesoftware_dwl_wm_v1* dwlWm; ++std::vector tagNames; ++std::vector layoutNames; + static xdg_wm_base* xdgWmBase; + static zxdg_output_manager_v1* xdgOutputManager; + static wl_surface* cursorSurface; +@@ -85,6 +86,26 @@ static int statusFifoFd {-1}; + static int statusFifoWriter {-1}; + static bool quitting {false}; + ++void view(Monitor& m, const Arg& arg) ++{ ++ znet_tapesoftware_dwl_wm_monitor_v1_set_tags(m.dwlMonitor.get(), arg.ui, 1); ++} ++void toggleview(Monitor& m, const Arg& arg) ++{ ++ znet_tapesoftware_dwl_wm_monitor_v1_set_tags(m.dwlMonitor.get(), m.tags ^ arg.ui, 0); ++} ++void setlayout(Monitor& m, const Arg& arg) ++{ ++ znet_tapesoftware_dwl_wm_monitor_v1_set_layout(m.dwlMonitor.get(), arg.ui); ++} ++void tag(Monitor& m, const Arg& arg) ++{ ++ znet_tapesoftware_dwl_wm_monitor_v1_set_client_tags(m.dwlMonitor.get(), 0, arg.ui); ++} ++void toggletag(Monitor& m, const Arg& arg) ++{ ++ znet_tapesoftware_dwl_wm_monitor_v1_set_client_tags(m.dwlMonitor.get(), ~0, arg.ui); ++} + void spawn(Monitor&, const Arg& arg) + { + if (fork() == 0) { +@@ -189,11 +210,62 @@ static const struct wl_seat_listener seatListener = { + .name = [](void*, wl_seat*, const char* name) { } + }; + ++static const struct znet_tapesoftware_dwl_wm_v1_listener dwlWmListener = { ++ .tag = [](void*, znet_tapesoftware_dwl_wm_v1*, const char* name) { ++ tagNames.push_back(name); ++ }, ++ .layout = [](void*, znet_tapesoftware_dwl_wm_v1*, const char* name) { ++ layoutNames.push_back(name); ++ }, ++}; ++ ++static const struct znet_tapesoftware_dwl_wm_monitor_v1_listener dwlWmMonitorListener { ++ .selected = [](void* mv, znet_tapesoftware_dwl_wm_monitor_v1*, uint32_t selected) { ++ auto mon = static_cast(mv); ++ if (selected) { ++ selmon = mon; ++ } else if (selmon == mon) { ++ selmon = nullptr; ++ } ++ mon->bar.setSelected(selected); ++ }, ++ .tag = [](void* mv, znet_tapesoftware_dwl_wm_monitor_v1*, uint32_t tag, uint32_t state, uint32_t numClients, int32_t focusedClient) { ++ auto mon = static_cast(mv); ++ int tagState = TagState::None; ++ if (state & ZNET_TAPESOFTWARE_DWL_WM_MONITOR_V1_TAG_STATE_ACTIVE) ++ tagState |= TagState::Active; ++ if (state & ZNET_TAPESOFTWARE_DWL_WM_MONITOR_V1_TAG_STATE_URGENT) ++ tagState |= TagState::Urgent; ++ mon->bar.setTag(tag, tagState, numClients, focusedClient); ++ uint32_t mask = 1 << tag; ++ if (tagState & TagState::Active) { ++ mon->tags |= mask; ++ } else { ++ mon->tags &= ~mask; ++ } ++ }, ++ .layout = [](void* mv, znet_tapesoftware_dwl_wm_monitor_v1*, uint32_t layout) { ++ auto mon = static_cast(mv); ++ mon->bar.setLayout(layoutNames[layout]); ++ }, ++ .title = [](void* mv, znet_tapesoftware_dwl_wm_monitor_v1*, const char* title) { ++ auto mon = static_cast(mv); ++ mon->bar.setTitle(title); ++ }, ++ .frame = [](void* mv, znet_tapesoftware_dwl_wm_monitor_v1*) { ++ auto mon = static_cast(mv); ++ mon->hasData = true; ++ updatemon(*mon); ++ } ++}; ++ + void setupMonitor(uint32_t name, wl_output* output) { + auto& monitor = monitors.emplace_back(Monitor {name, {}, wl_unique_ptr {output}}); + monitor.bar.setStatus(lastStatus); + auto xdgOutput = zxdg_output_manager_v1_get_xdg_output(xdgOutputManager, monitor.wlOutput.get()); + zxdg_output_v1_add_listener(xdgOutput, &xdgOutputListener, &monitor); ++ monitor.dwlMonitor.reset(znet_tapesoftware_dwl_wm_v1_get_monitor(dwlWm, monitor.wlOutput.get())); ++ znet_tapesoftware_dwl_wm_monitor_v1_add_listener(monitor.dwlMonitor.get(), &dwlWmMonitorListener, &monitor); + } + + void updatemon(Monitor& mon) +@@ -219,6 +291,7 @@ void onReady() + requireGlobal(shm, "wl_shm"); + requireGlobal(wlrLayerShell, "zwlr_layer_shell_v1"); + requireGlobal(xdgOutputManager, "zxdg_output_manager_v1"); ++ requireGlobal(dwlWm, "znet_tapesoftware_dwl_wm_v1"); + setupStatusFifo(); + wl_display_roundtrip(display); // roundtrip so we receive all dwl tags etc. + +@@ -226,7 +299,6 @@ void onReady() + for (auto output : uninitializedOutputs) { + setupMonitor(output.first, output.second); + } +- wl_display_roundtrip(display); // wait for xdg_output names before we read stdin + } + + void setupStatusFifo() +@@ -259,66 +331,6 @@ void setupStatusFifo() + } + } + +-static LineBuffer<512> stdinBuffer; +-static void onStdin() +-{ +- auto res = stdinBuffer.readLines( +- [](void* p, size_t size) { return read(0, p, size); }, +- [](char* p, size_t size) { handleStdin({p, size}); }); +- if (res == 0) { +- quitting = true; +- } +-} +- +-static void handleStdin(const std::string& line) +-{ +- // this parses the lines that dwl sends in printstatus() +- std::string monName, command; +- auto stream = std::istringstream {line}; +- stream >> monName >> command; +- if (!stream.good()) { +- return; +- } +- auto mon = std::find_if(begin(monitors), end(monitors), [&](const Monitor& mon) { +- return mon.xdgName == monName; +- }); +- if (mon == end(monitors)) +- return; +- if (command == "title") { +- auto title = std::string {}; +- std::getline(stream, title); +- mon->bar.setTitle(title); +- } else if (command == "selmon") { +- uint32_t selected; +- stream >> selected; +- mon->bar.setSelected(selected); +- if (selected) { +- selmon = &*mon; +- } else if (selmon == &*mon) { +- selmon = nullptr; +- } +- } else if (command == "tags") { +- uint32_t occupied, tags, clientTags, urgent; +- stream >> occupied >> tags >> clientTags >> urgent; +- for (auto i=0u; ibar.setTag(i, state, occupied & tagMask ? 1 : 0, clientTags & tagMask ? 0 : -1); +- } +- mon->tags = tags; +- } else if (command == "layout") { +- auto layout = std::string {}; +- std::getline(stream, layout); +- mon->bar.setLayout(layout); +- } +- mon->hasData = true; +- updatemon(*mon); +-} +- + const std::string prefixStatus = "status "; + const std::string prefixShow = "show "; + const std::string prefixHide = "hide "; +@@ -393,6 +405,10 @@ void onGlobalAdd(void*, wl_registry* registry, uint32_t name, const char* interf + xdg_wm_base_add_listener(xdgWmBase, &xdgWmBaseListener, nullptr); + return; + } ++ if (reg.handle(dwlWm, znet_tapesoftware_dwl_wm_v1_interface, 1)) { ++ znet_tapesoftware_dwl_wm_v1_add_listener(dwlWm, &dwlWmListener, nullptr); ++ return; ++ } + if (wl_seat* wlSeat; reg.handle(wlSeat, wl_seat_interface, 7)) { + auto& seat = seats.emplace_back(Seat {name, wl_unique_ptr {wlSeat}}); + wl_seat_add_listener(wlSeat, &seatListener, &seat); +@@ -494,10 +510,6 @@ int main(int argc, char* argv[]) + .fd = displayFd, + .events = POLLIN, + }); +- pollfds.push_back({ +- .fd = STDIN_FILENO, +- .events = POLLIN, +- }); + if (fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK) < 0) { + diesys("fcntl F_SETFL"); + } +@@ -522,8 +534,6 @@ int main(int argc, char* argv[]) + ev.events = POLLIN; + waylandFlush(); + } +- } else if (ev.fd == STDIN_FILENO && (ev.revents & POLLIN)) { +- onStdin(); + } else if (ev.fd == statusFifoFd && (ev.revents & POLLIN)) { + onStatus(); + } else if (ev.fd == signalSelfPipe[0] && (ev.revents & POLLIN)) { diff --git a/.config/dwl/somebar/install.sh b/.config/dwl/somebar/install.sh new file mode 100755 index 0000000..199b5e4 --- /dev/null +++ b/.config/dwl/somebar/install.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +meson setup build +ninja -C build +sudo ninja -C build install +sudo cp -rfv /usr/local/bin/somebar /usr/bin/somebar +ninja -C build clean diff --git a/.config/dwl/somebar/meson.build b/.config/dwl/somebar/meson.build new file mode 100644 index 0000000..6ad5a0f --- /dev/null +++ b/.config/dwl/somebar/meson.build @@ -0,0 +1,31 @@ +project('somebar', ['c', 'cpp'], + version: '0.1.0', + default_options: [ + 'cpp_std=c++17', + 'cpp_args=-Wno-parentheses', + ]) + +wayland_dep = dependency('wayland-client') +wayland_cursor_dep = dependency('wayland-cursor') +cairo_dep = dependency('cairo') +pango_dep = dependency('pango') +pangocairo_dep = dependency('pangocairo') + +subdir('protocols') + +executable('somebar', + 'src/main.cpp', + 'src/shm_buffer.cpp', + 'src/bar.cpp', + wayland_sources, + dependencies: [ + wayland_dep, + wayland_cursor_dep, + cairo_dep, + pango_dep, + pangocairo_dep, + ], + install: true, + cpp_args: '-DSOMEBAR_VERSION="@0@"'.format(meson.project_version())) + +install_man('somebar.1') diff --git a/.config/dwl/somebar/protocols/meson.build b/.config/dwl/somebar/protocols/meson.build new file mode 100644 index 0000000..7bd222b --- /dev/null +++ b/.config/dwl/somebar/protocols/meson.build @@ -0,0 +1,22 @@ +# adapted from https://github.com/swaywm/swayidle/blob/0467c1e03a5780ed8e3ba611f099a838822ab550/meson.build +wayland_scanner = find_program('wayland-scanner') +wayland_protos_dep = dependency('wayland-protocols') +wl_protocol_dir = wayland_protos_dep.get_pkgconfig_variable('pkgdatadir') +wayland_scanner_code = generator( + wayland_scanner, + output: '@BASENAME@-protocol.c', + arguments: ['private-code', '@INPUT@', '@OUTPUT@']) +wayland_scanner_client = generator( + wayland_scanner, + output: '@BASENAME@-client-protocol.h', + arguments: ['client-header', '@INPUT@', '@OUTPUT@']) + +wayland_xmls = [ + wl_protocol_dir + '/stable/xdg-shell/xdg-shell.xml', + wl_protocol_dir + '/unstable/xdg-output/xdg-output-unstable-v1.xml', + 'wlr-layer-shell-unstable-v1.xml', +] +wayland_sources = [ + wayland_scanner_code.process(wayland_xmls), + wayland_scanner_client.process(wayland_xmls), +] diff --git a/.config/dwl/somebar/protocols/wlr-layer-shell-unstable-v1.xml b/.config/dwl/somebar/protocols/wlr-layer-shell-unstable-v1.xml new file mode 100644 index 0000000..78ba050 --- /dev/null +++ b/.config/dwl/somebar/protocols/wlr-layer-shell-unstable-v1.xml @@ -0,0 +1,390 @@ + + + + Copyright © 2017 Drew DeVault + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + Clients can use this interface to assign the surface_layer role to + wl_surfaces. Such surfaces are assigned to a "layer" of the output and + rendered with a defined z-depth respective to each other. They may also be + anchored to the edges and corners of a screen and specify input handling + semantics. This interface should be suitable for the implementation of + many desktop shell components, and a broad number of other applications + that interact with the desktop. + + + + + Create a layer surface for an existing surface. This assigns the role of + layer_surface, or raises a protocol error if another role is already + assigned. + + Creating a layer surface from a wl_surface which has a buffer attached + or committed is a client error, and any attempts by a client to attach + or manipulate a buffer prior to the first layer_surface.configure call + must also be treated as errors. + + 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. + + + + + + + + + + + + + + + + + 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. + + + + + + + + + + + + + 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. + + + + + + + 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. + + + + + Sets the size of the surface in surface-local coordinates. The + compositor will display the surface centered with respect to its + anchors. + + If you pass 0 for either value, the compositor will assign it and + inform you of the assignment in the configure event. You must set your + anchor to opposite edges in the dimensions you omit; not doing so is a + protocol error. Both values are 0 by default. + + Size is double-buffered, see wl_surface.commit. + + + + + + + + Requests that the compositor anchor the surface to the specified edges + and corners. If two orthogonal edges are specified (e.g. 'top' and + 'left'), then the anchor point will be the intersection of the edges + (e.g. the top left corner of the output); otherwise the anchor point + will be centered on that edge, or in the center if none is specified. + + Anchor is double-buffered, see wl_surface.commit. + + + + + + + Requests that the compositor avoids occluding an area with other + surfaces. The compositor's use of this information is + implementation-dependent - do not assume that this region will not + actually be occluded. + + A positive value is only meaningful if the surface is anchored to one + edge or an edge and both perpendicular edges. If the surface is not + anchored, anchored to only two perpendicular edges (a corner), anchored + to only two parallel edges or anchored to all edges, a positive value + will be treated the same as zero. + + A positive zone is the distance from the edge in surface-local + coordinates to consider exclusive. + + Surfaces that do not wish to have an exclusive zone may instead specify + how they should interact with surfaces that do. If set to zero, the + surface indicates that it would like to be moved to avoid occluding + surfaces with a positive exclusive zone. If set to -1, the surface + indicates that it would not like to be moved to accommodate for other + surfaces, and the compositor should extend it all the way to the edges + it is anchored to. + + For example, a panel might set its exclusive zone to 10, so that + maximized shell surfaces are not shown on top of it. A notification + might set its exclusive zone to 0, so that it is moved to avoid + occluding the panel, but shell surfaces are shown underneath it. A + wallpaper or lock screen might set their exclusive zone to -1, so that + they stretch below or over the panel. + + The default value is 0. + + Exclusive zone is double-buffered, see wl_surface.commit. + + + + + + + Requests that the surface be placed some distance away from the anchor + point on the output, in surface-local coordinates. Setting this value + for edges you are not anchored to has no effect. + + The exclusive zone includes the margin. + + Margin is double-buffered, see wl_surface.commit. + + + + + + + + + + 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. + + + + + 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. + + + + + 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. + + + + + 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. + + + + + + + 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. + + + + + + + This assigns an xdg_popup's parent to this layer_surface. This popup + should have been created via xdg_surface::get_popup with the parent set + to NULL, and this request must be invoked before committing the popup's + initial state. + + See the documentation of xdg_popup for more details about what an + xdg_popup is and how it is used. + + + + + + + When a configure event is received, if a client commits the + surface in response to the configure event, then the client + must make an ack_configure request sometime before the commit + request, passing along the serial of the configure event. + + If the client receives multiple configure events before it + can respond to one, it only has to ack the last configure event. + + A client is not required to commit immediately after sending + an ack_configure request - it may even ack_configure several times + before its next surface commit. + + A client may send multiple ack_configure requests before committing, but + only the last request sent before a commit indicates which configure + event the client really is responding to. + + + + + + + This request destroys the layer surface. + + + + + + The configure event asks the client to resize its surface. + + Clients should arrange their surface for the new states, and then send + an ack_configure request with the serial sent in this configure event at + some point before committing the new surface. + + The client is free to dismiss all but the last configure event it + received. + + The width and height arguments specify the size of the window in + surface-local coordinates. + + The size is a hint, in the sense that the client is free to ignore it if + it doesn't resize, pick a smaller size (to satisfy aspect ratio or + resize in steps of NxM pixels). If the client picks a smaller size and + is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the + surface will be centered on this axis. + + If the width or height arguments are zero, it means the client should + decide its own window dimension. + + + + + + + + + The closed event is sent by the compositor when the surface will no + longer be shown. The output may have been destroyed or the user may + have asked for it to be removed. Further changes to the surface will be + ignored. The client should destroy the resource after receiving this + event, and create a new surface if they so choose. + + + + + + + + + + + + + + + + + + + + + + Change the layer that the surface is rendered on. + + Layer is double-buffered, see wl_surface.commit. + + + + + diff --git a/.config/dwl/somebar/screenshot.png b/.config/dwl/somebar/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..7a800fbe6783f907f596c4bf26089736d8d9683a GIT binary patch literal 6715 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 literal 0 HcmV?d00001 diff --git a/.config/dwl/somebar/somebar.1 b/.config/dwl/somebar/somebar.1 new file mode 100644 index 0000000..d822770 --- /dev/null +++ b/.config/dwl/somebar/somebar.1 @@ -0,0 +1,55 @@ +.TH somebar 1 somebar\-1.0 +.SH NAME +somebar \- dwm-like bar for dwl +.SH SYNOPSIS +.B somebar +.RB [ \-h ] +.RB [ \-v ] +.RB [ \-s +.IR path ] +.RB [ \-c +.IR command +arguments... ] +.SH DESCRIPTION +somebar is a status bar for dwl, visually and functionally resembling the +dwm bar. +.SH USAGE +You must start somebar using dwl's `-s` flag, e.g. `dwl -s somebar`. + +Somebar can be controlled by writing to $XDG_RUNTIME_DIR/somebar-0, or the path +defined by the `-s` argument. The following commands are supported: +.TP +.B status TEXT +Updates the status bar +.TP +.B hide MONITOR +Hides somebar on the specified monitor +.TP +.B show MONITOR +Shows somebar on the specified monitor +.TP +.B toggle MONITOR +Toggles somebar on the specified monitor +.P +MONITOR is an zxdg_output_v1 name, which can be determined e.g. using `weston-info`. +Additionally, MONITOR can be `all` (all monitors) or `selected` (the monitor with focus). + +Commands can be sent either by writing to the file name above, or equivalently by calling +somebar with the `-c` argument. For example: `somebar -c toggle all`. This is recommended +for shell scripts, as there is no race-free way to write to a file only if it exists. +.SH OPTIONS +.TP +.B \-h +Displays a short help text and exits +.TP +.B \-v +Displays version information and exits +.TP +.B \-s +Sets the path to the somebar control FIFO. The default value is +$XDG_RUNTIME_DIR/somebar-0 +.TP +.B \-c +Sends a command to the control FIFO. See the USAGE section. +.SH BUGS +Send bug reports to ~raphi/public-inbox@lists.sr.ht diff --git a/.config/dwl/somebar/src/bar.cpp b/.config/dwl/somebar/src/bar.cpp new file mode 100644 index 0000000..fab5a8f --- /dev/null +++ b/.config/dwl/somebar/src/bar.cpp @@ -0,0 +1,315 @@ +// somebar - dwl barbar +// See LICENSE file for copyright and license details. + +#include +#include +#include "bar.hpp" +#include "cairo.h" +#include "config.hpp" +#include "pango/pango-font.h" +#include "pango/pango-fontmap.h" +#include "pango/pango-layout.h" + +const zwlr_layer_surface_v1_listener Bar::_layerSurfaceListener = { + [](void* owner, zwlr_layer_surface_v1*, uint32_t serial, uint32_t width, uint32_t height) + { + static_cast(owner)->layerSurfaceConfigure(serial, width, height); + } +}; +const wl_callback_listener Bar::_frameListener = { + [](void* owner, wl_callback* cb, uint32_t) + { + static_cast(owner)->render(); + wl_callback_destroy(cb); + } +}; + +struct Font { + PangoFontDescription* description; + int height {0}; +}; +static Font getFont() +{ + auto fontMap = pango_cairo_font_map_get_default(); + if (!fontMap) { + die("pango_cairo_font_map_get_default"); + } + auto fontDesc = pango_font_description_from_string(font); + if (!fontDesc) { + die("pango_font_description_from_string"); + } + auto tempContext = pango_font_map_create_context(fontMap); + if (!tempContext) { + die("pango_font_map_create_context"); + } + auto font = pango_font_map_load_font(fontMap, tempContext, fontDesc); + if (!font) { + die("pango_font_map_load_font"); + } + auto metrics = pango_font_get_metrics(font, pango_language_get_default()); + if (!metrics) { + die("pango_font_get_metrics"); + } + + auto res = Font {}; + res.description = fontDesc; + res.height = PANGO_PIXELS(pango_font_metrics_get_height(metrics)); + + pango_font_metrics_unref(metrics); + g_object_unref(font); + g_object_unref(tempContext); + return res; +} +static Font barfont = getFont(); + +BarComponent::BarComponent() { } +BarComponent::BarComponent(wl_unique_ptr layout) + : pangoLayout {std::move(layout)} +{ +} + +int BarComponent::width() const +{ + int w, h; + pango_layout_get_size(pangoLayout.get(), &w, &h); + return PANGO_PIXELS(w); +} + +void BarComponent::setText(const std::string& text) +{ + _text = std::make_unique(text); + pango_layout_set_text(pangoLayout.get(), _text->c_str(), _text->size()); +} + +Bar::Bar() +{ + _pangoContext.reset(pango_font_map_create_context(pango_cairo_font_map_get_default())); + if (!_pangoContext) { + die("pango_font_map_create_context"); + } + for (const auto& tagName : tagNames) { + _tags.push_back({ TagState::None, 0, 0, createComponent(tagName) }); + } + _layoutCmp = createComponent(); + _titleCmp = createComponent(); + _statusCmp = createComponent(); +} + +const wl_surface* Bar::surface() const +{ + return _surface.get(); +} + +bool Bar::visible() const +{ + return _surface.get(); +} + +void Bar::show(wl_output* output) +{ + if (visible()) { + return; + } + _surface.reset(wl_compositor_create_surface(compositor)); + _layerSurface.reset(zwlr_layer_shell_v1_get_layer_surface(wlrLayerShell, + _surface.get(), output, ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "net.tapesoftware.Somebar")); + zwlr_layer_surface_v1_add_listener(_layerSurface.get(), &_layerSurfaceListener, this); + auto anchor = topbar ? ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP : ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; + zwlr_layer_surface_v1_set_anchor(_layerSurface.get(), + anchor | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT); + + auto barSize = barfont.height + paddingY * 2; + zwlr_layer_surface_v1_set_size(_layerSurface.get(), 0, barSize); + zwlr_layer_surface_v1_set_exclusive_zone(_layerSurface.get(), barSize); + wl_surface_commit(_surface.get()); +} + +void Bar::hide() +{ + if (!visible()) { + return; + } + _layerSurface.reset(); + _surface.reset(); + _bufs.reset(); +} + +void Bar::setTag(int tag, int state, int numClients, int focusedClient) +{ + auto& t = _tags[tag]; + t.state = state; + t.numClients = numClients; + t.focusedClient = focusedClient; +} + +void Bar::setSelected(bool selected) +{ + _selected = selected; +} +void Bar::setLayout(const std::string& layout) +{ + _layoutCmp.setText(layout); +} +void Bar::setTitle(const std::string& title) +{ + _titleCmp.setText(title); +} +void Bar::setStatus(const std::string& status) +{ + _statusCmp.setText(status); +} + +void Bar::invalidate() +{ + if (_invalid || !visible()) { + return; + } + _invalid = true; + auto frame = wl_surface_frame(_surface.get()); + wl_callback_add_listener(frame, &_frameListener, this); + wl_surface_commit(_surface.get()); +} + +void Bar::click(Monitor* mon, int x, int, int btn) +{ + Arg arg = {0}; + Arg* argp = nullptr; + int control = ClkNone; + if (x > _statusCmp.x) { + control = ClkStatusText; + } else if (x > _titleCmp.x) { + control = ClkWinTitle; + } else if (x > _layoutCmp.x) { + control = ClkLayoutSymbol; + } else for (auto tag = _tags.size()-1; tag >= 0; tag--) { + if (x > _tags[tag].component.x) { + control = ClkTagBar; + arg.ui = 1<width && height == _bufs->height) { + return; + } + _bufs.emplace(width, height, WL_SHM_FORMAT_XRGB8888); + render(); +} + +void Bar::render() +{ + if (!_bufs) { + return; + } + auto img = wl_unique_ptr {cairo_image_surface_create_for_data( + _bufs->data(), + CAIRO_FORMAT_ARGB32, + _bufs->width, + _bufs->height, + _bufs->stride + )}; + auto painter = wl_unique_ptr {cairo_create(img.get())}; + _painter = painter.get(); + pango_cairo_update_context(_painter, _pangoContext.get()); + _x = 0; + + renderTags(); + setColorScheme(_selected ? colorActive : colorInactive); + renderComponent(_layoutCmp); + renderComponent(_titleCmp); + renderStatus(); + + _painter = nullptr; + wl_surface_attach(_surface.get(), _bufs->buffer(), 0, 0); + wl_surface_damage(_surface.get(), 0, 0, _bufs->width, _bufs->height); + wl_surface_commit(_surface.get()); + _bufs->flip(); + _invalid = false; +} + +void Bar::renderTags() +{ + for (auto &tag : _tags) { + setColorScheme( + tag.state & TagState::Active ? colorActive : colorInactive, + tag.state & TagState::Urgent); + renderComponent(tag.component); + auto indicators = std::min(tag.numClients, static_cast(_bufs->height/2)); + for (auto ind = 0; ind < indicators; ind++) { + auto w = ind == tag.focusedClient ? 7 : 1; + cairo_move_to(_painter, tag.component.x, ind*2+0.5); + cairo_rel_line_to(_painter, w, 0); + cairo_close_path(_painter); + cairo_set_line_width(_painter, 1); + cairo_stroke(_painter); + } + } +} + +void Bar::renderStatus() +{ + pango_cairo_update_layout(_painter, _statusCmp.pangoLayout.get()); + beginBg(); + auto start = _bufs->width - _statusCmp.width() - paddingX*2; + cairo_rectangle(_painter, _x, 0, _bufs->width-_x+start, _bufs->height); + cairo_fill(_painter); + + _x = start; + renderComponent(_statusCmp); +} + +void Bar::setColorScheme(const ColorScheme& scheme, bool invert) +{ + _colorScheme = invert + ? ColorScheme {scheme.bg, scheme.fg} + : ColorScheme {scheme.fg, scheme.bg}; +} +static void setColor(cairo_t* painter, const Color& color) +{ + cairo_set_source_rgba(painter, + color.r/255.0, color.g/255.0, color.b/255.0, color.a/255.0); +} +void Bar::beginFg() +{ + setColor(_painter, _colorScheme.fg); +} +void Bar::beginBg() +{ + setColor(_painter, _colorScheme.bg); +} + +void Bar::renderComponent(BarComponent& component) +{ + pango_cairo_update_layout(_painter, component.pangoLayout.get()); + auto size = component.width() + paddingX*2; + component.x = _x; + + beginBg(); + cairo_rectangle(_painter, _x, 0, size, _bufs->height); + cairo_fill(_painter); + cairo_move_to(_painter, _x+paddingX, paddingY); + + beginFg(); + pango_cairo_show_layout(_painter, component.pangoLayout.get()); + _x += size; +} + +BarComponent Bar::createComponent(const std::string &initial) +{ + auto layout = pango_layout_new(_pangoContext.get()); + pango_layout_set_font_description(layout, barfont.description); + auto res = BarComponent {wl_unique_ptr {layout}}; + res.setText(initial); + return res; +} diff --git a/.config/dwl/somebar/src/bar.hpp b/.config/dwl/somebar/src/bar.hpp new file mode 100644 index 0000000..176a1bc --- /dev/null +++ b/.config/dwl/somebar/src/bar.hpp @@ -0,0 +1,74 @@ +// somebar - dwl bar +// See LICENSE file for copyright and license details. + +#pragma once +#include +#include +#include +#include +#include "wlr-layer-shell-unstable-v1-client-protocol.h" +#include "common.hpp" +#include "shm_buffer.hpp" + +class BarComponent { + std::unique_ptr _text; +public: + BarComponent(); + explicit BarComponent(wl_unique_ptr layout); + int width() const; + void setText(const std::string& text); + wl_unique_ptr pangoLayout; + int x {0}; +}; + +struct Tag { + int state; + int numClients; + int focusedClient; + BarComponent component; +}; + +struct Monitor; +class Bar { + static const zwlr_layer_surface_v1_listener _layerSurfaceListener; + static const wl_callback_listener _frameListener; + + wl_unique_ptr _surface; + wl_unique_ptr _layerSurface; + wl_unique_ptr _pangoContext; + std::optional _bufs; + std::vector _tags; + BarComponent _layoutCmp, _titleCmp, _statusCmp; + bool _selected; + bool _invalid {false}; + + // only vaild during render() + cairo_t* _painter {nullptr}; + int _x; + ColorScheme _colorScheme; + + void layerSurfaceConfigure(uint32_t serial, uint32_t width, uint32_t height); + void render(); + void renderTags(); + void renderStatus(); + + // low-level rendering + void setColorScheme(const ColorScheme& scheme, bool invert = false); + void beginFg(); + void beginBg(); + void renderComponent(BarComponent& component); + BarComponent createComponent(const std::string& initial = {}); +public: + Bar(); + const wl_surface* surface() const; + bool visible() const; + void show(wl_output* output); + void hide(); + void setTag(int tag, int state, int numClients, int focusedClient); + void setSelected(bool selected); + void setLayout(const std::string& layout); + void setTitle(const std::string& title); + void setStatus(const std::string& status); + void invalidate(); + void click(Monitor* mon, int x, int y, int btn); +}; diff --git a/.config/dwl/somebar/src/common.hpp b/.config/dwl/somebar/src/common.hpp new file mode 100644 index 0000000..aed4480 --- /dev/null +++ b/.config/dwl/somebar/src/common.hpp @@ -0,0 +1,70 @@ +// somebar - dwl bar +// See LICENSE file for copyright and license details. + +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include "wlr-layer-shell-unstable-v1-client-protocol.h" + +struct Color { + Color() {} + constexpr Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a=255) : r(r), g(g), b(b), a(a) { } + uint8_t r, g, b, a {255}; +}; +struct ColorScheme { + Color fg, bg; +}; +union Arg { + unsigned int ui; + const void* v; +}; +struct Monitor; + +enum TagState { None, Active = 0x01, Urgent = 0x02 }; +enum Control { ClkNone, ClkTagBar, ClkLayoutSymbol, ClkWinTitle, ClkStatusText }; +struct Button { + int control; + int btn; // + void (*func)(Monitor& mon, const Arg& arg); + const Arg arg; +}; + +extern wl_display* display; +extern wl_compositor* compositor; +extern wl_shm* shm; +extern zwlr_layer_shell_v1* wlrLayerShell; + +void spawn(Monitor&, const Arg& arg); +void setCloexec(int fd); +[[noreturn]] void die(const char* why); +[[noreturn]] void diesys(const char* why); + +// wayland smart pointers +template +struct WlDeleter; +#define WL_DELETER(type, fn) template<> struct WlDeleter { \ + void operator()(type* v) { if(v) fn(v); } \ + } + +template +using wl_unique_ptr = std::unique_ptr>; + +WL_DELETER(wl_buffer, wl_buffer_destroy); +WL_DELETER(wl_output, wl_output_release); +WL_DELETER(wl_pointer, wl_pointer_release); +WL_DELETER(wl_seat, wl_seat_release); +WL_DELETER(wl_surface, wl_surface_destroy); +WL_DELETER(zwlr_layer_surface_v1, zwlr_layer_surface_v1_destroy); + +WL_DELETER(cairo_t, cairo_destroy); +WL_DELETER(cairo_surface_t, cairo_surface_destroy); + +WL_DELETER(PangoContext, g_object_unref); +WL_DELETER(PangoLayout, g_object_unref); + +#undef WL_DELETER diff --git a/.config/dwl/somebar/src/config.def.hpp b/.config/dwl/somebar/src/config.def.hpp new file mode 100644 index 0000000..40a8c95 --- /dev/null +++ b/.config/dwl/somebar/src/config.def.hpp @@ -0,0 +1,27 @@ +// somebar - dwl bar +// See LICENSE file for copyright and license details. + +#pragma once +#include "common.hpp" + +constexpr bool topbar = true; + +constexpr int paddingX = 10; +constexpr int paddingY = 3; + +// See https://docs.gtk.org/Pango/type_func.FontDescription.from_string.html +constexpr const char* font = "Sans 12"; + +constexpr ColorScheme colorInactive = {Color(0xbb, 0xbb, 0xbb), Color(0x22, 0x22, 0x22)}; +constexpr ColorScheme colorActive = {Color(0xee, 0xee, 0xee), Color(0x00, 0x55, 0x77)}; +constexpr const char* termcmd[] = {"foot", nullptr}; + +static std::vector tagNames = { + "1", "2", "3", + "4", "5", "6", + "7", "8", "9", +}; + +constexpr Button buttons[] = { + { ClkStatusText, BTN_RIGHT, spawn, {.v = termcmd} }, +}; diff --git a/.config/dwl/somebar/src/config.hpp b/.config/dwl/somebar/src/config.hpp new file mode 100644 index 0000000..2b7e880 --- /dev/null +++ b/.config/dwl/somebar/src/config.hpp @@ -0,0 +1,28 @@ +// somebar - dwl bar +// See LICENSE file for copyright and license details. + +#pragma once +#include "common.hpp" + +constexpr bool topbar = true; + +constexpr int paddingX = 8; +constexpr int paddingY = 3; + +// See https://docs.gtk.org/Pango/type_func.FontDescription.from_string.html +//constexpr const char* font = "Sans 12"; +constexpr const char* font = "UbuntuMono Nerd Font 12"; + +constexpr ColorScheme colorInactive = {Color(0xbb, 0xbb, 0xbb), Color(0x1f, 0x1f, 0x35)}; +constexpr ColorScheme colorActive = {Color(0xee, 0xee, 0xee), Color(0x66, 0x44, 0x77)}; +constexpr const char* termcmd[] = {"foot", nullptr}; + +static std::vector tagNames = { + "term", "www", "chat", + "files", "media", "game", + "mail", "dev", "vm", +}; + +constexpr Button buttons[] = { + { ClkStatusText, BTN_RIGHT, spawn, {.v = termcmd} }, +}; diff --git a/.config/dwl/somebar/src/line_buffer.hpp b/.config/dwl/somebar/src/line_buffer.hpp new file mode 100644 index 0000000..a5497bf --- /dev/null +++ b/.config/dwl/somebar/src/line_buffer.hpp @@ -0,0 +1,71 @@ +// somebar - dwl bar +// See LICENSE file for copyright and license details. + +#pragma once +#include +#include +#include + +// reads data from Reader, and passes complete lines to Consumer. +template +class LineBuffer { + using Iterator = typename std::array::iterator; + std::array _buffer; + Iterator _bufferedTo; + Iterator _consumedTo; + bool _discardLine {false}; +public: + LineBuffer() + : _bufferedTo {_buffer.begin()} + , _consumedTo {_buffer.begin()} + { + } + + template + ssize_t readLines(const Reader& reader, const Consumer& consumer) + { + while (true) { + auto bytesRead = reader(_bufferedTo, _buffer.end() - _bufferedTo); + if (bytesRead <= 0) { + return bytesRead; + } + _bufferedTo += bytesRead; + dispatchLines(consumer); + resetBuffer(); + } + } +private: + template + void dispatchLines(const Consumer& consumer) + { + while (true) { + auto separator = std::find(_consumedTo, _bufferedTo, '\n'); + if (separator == _bufferedTo) { + break; + } + size_t lineLength = separator - _consumedTo; + if (!_discardLine) { + consumer(_consumedTo, lineLength); + } + _consumedTo = separator + 1; + _discardLine = false; + } + } + + void resetBuffer() + { + size_t bytesRemaining = _bufferedTo - _consumedTo; + if (bytesRemaining == _buffer.size()) { + // line too long + _discardLine = true; + _consumedTo = _buffer.begin(); + _bufferedTo = _buffer.begin(); + } else { + // move the last partial message to the front of the buffer, so a full-sized + // message will fit + std::copy(_consumedTo, _bufferedTo, _buffer.begin()); + _consumedTo = _buffer.begin(); + _bufferedTo = _consumedTo + bytesRemaining; + } + } +}; diff --git a/.config/dwl/somebar/src/main.cpp b/.config/dwl/somebar/src/main.cpp new file mode 100644 index 0000000..6274959 --- /dev/null +++ b/.config/dwl/somebar/src/main.cpp @@ -0,0 +1,613 @@ +// somebar - dwl bar +// See LICENSE file for copyright and license details. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlr-layer-shell-unstable-v1-client-protocol.h" +#include "xdg-output-unstable-v1-client-protocol.h" +#include "xdg-shell-client-protocol.h" +#include "common.hpp" +#include "config.hpp" +#include "bar.hpp" +#include "line_buffer.hpp" + +struct Monitor { + uint32_t registryName; + std::string xdgName; + wl_unique_ptr wlOutput; + Bar bar; + bool desiredVisibility {true}; + bool hasData; + uint32_t tags; +}; + +struct SeatPointer { + wl_unique_ptr wlPointer; + Monitor* focusedMonitor; + int x, y; + std::vector btns; +}; +struct Seat { + uint32_t name; + wl_unique_ptr wlSeat; + std::optional pointer; +}; + +static Monitor* monitorFromSurface(const wl_surface* surface); +static void setupMonitor(uint32_t name, wl_output* output); +static void updatemon(Monitor &mon); +static void onReady(); +static void setupStatusFifo(); +static void onStatus(); +static void onStdin(); +static void handleStdin(const std::string& line); +static void updateVisibility(const std::string& name, bool(*updater)(bool)); +static void onGlobalAdd(void*, wl_registry* registry, uint32_t name, const char* interface, uint32_t version); +static void onGlobalRemove(void*, wl_registry* registry, uint32_t name); +static void requireGlobal(const void* p, const char* name); +static void waylandFlush(); +static void cleanup(); + +wl_display* display; +wl_compositor* compositor; +wl_shm* shm; +zwlr_layer_shell_v1* wlrLayerShell; +static xdg_wm_base* xdgWmBase; +static zxdg_output_manager_v1* xdgOutputManager; +static wl_surface* cursorSurface; +static wl_cursor_image* cursorImage; +static bool ready; +static std::list monitors; +static std::vector> uninitializedOutputs; +static std::list seats; +static Monitor* selmon; +static std::string lastStatus; +static std::string statusFifoName; +static std::vector pollfds; +static std::array signalSelfPipe; +static int displayFd {-1}; +static int statusFifoFd {-1}; +static int statusFifoWriter {-1}; +static bool quitting {false}; + +void spawn(Monitor&, const Arg& arg) +{ + if (fork() == 0) { + auto argv = static_cast(arg.v); + setsid(); + execvp(argv[0], argv); + fprintf(stderr, "somebar: execvp %s ", argv[0]); + perror(" failed"); + exit(1); + } +} + +static const struct xdg_wm_base_listener xdgWmBaseListener = { + [](void*, xdg_wm_base* sender, uint32_t serial) { + xdg_wm_base_pong(sender, serial); + } +}; + +static const struct zxdg_output_v1_listener xdgOutputListener = { + .logical_position = [](void*, zxdg_output_v1*, int, int) { }, + .logical_size = [](void*, zxdg_output_v1*, int, int) { }, + .done = [](void*, zxdg_output_v1*) { }, + .name = [](void* mp, zxdg_output_v1* xdgOutput, const char* name) { + auto& monitor = *static_cast(mp); + monitor.xdgName = name; + zxdg_output_v1_destroy(xdgOutput); + }, + .description = [](void*, zxdg_output_v1*, const char*) { }, +}; + +Monitor* monitorFromSurface(const wl_surface* surface) +{ + auto mon = std::find_if(begin(monitors), end(monitors), [surface](const Monitor& mon) { + return mon.bar.surface() == surface; + }); + return mon != end(monitors) ? &*mon : nullptr; +} +static const struct wl_pointer_listener pointerListener = { + .enter = [](void* sp, wl_pointer* pointer, uint32_t serial, + wl_surface* surface, wl_fixed_t x, wl_fixed_t y) + { + auto& seat = *static_cast(sp); + seat.pointer->focusedMonitor = monitorFromSurface(surface); + if (!cursorImage) { + auto cursorTheme = wl_cursor_theme_load(nullptr, 24, shm); + cursorImage = wl_cursor_theme_get_cursor(cursorTheme, "left_ptr")->images[0]; + cursorSurface = wl_compositor_create_surface(compositor); + wl_surface_attach(cursorSurface, wl_cursor_image_get_buffer(cursorImage), 0, 0); + wl_surface_commit(cursorSurface); + } + wl_pointer_set_cursor(pointer, serial, cursorSurface, + cursorImage->hotspot_x, cursorImage->hotspot_y); + }, + .leave = [](void* sp, wl_pointer*, uint32_t serial, wl_surface*) { + auto& seat = *static_cast(sp); + seat.pointer->focusedMonitor = nullptr; + }, + .motion = [](void* sp, wl_pointer*, uint32_t, wl_fixed_t x, wl_fixed_t y) { + auto& seat = *static_cast(sp); + seat.pointer->x = wl_fixed_to_int(x); + seat.pointer->y = wl_fixed_to_int(y); + }, + .button = [](void* sp, wl_pointer*, uint32_t, uint32_t, uint32_t button, uint32_t pressed) { + auto& seat = *static_cast(sp); + auto it = std::find(begin(seat.pointer->btns), end(seat.pointer->btns), button); + if (pressed == WL_POINTER_BUTTON_STATE_PRESSED && it == end(seat.pointer->btns)) { + seat.pointer->btns.push_back(button); + } else if (pressed == WL_POINTER_BUTTON_STATE_RELEASED && it != end(seat.pointer->btns)) { + seat.pointer->btns.erase(it); + } + }, + .axis = [](void* sp, wl_pointer*, uint32_t, uint32_t, wl_fixed_t) { }, + .frame = [](void* sp, wl_pointer*) { + auto& seat = *static_cast(sp); + auto mon = seat.pointer->focusedMonitor; + if (!mon) { + return; + } + for (auto btn : seat.pointer->btns) { + mon->bar.click(mon, seat.pointer->x, seat.pointer->y, btn); + } + seat.pointer->btns.clear(); + }, + .axis_source = [](void*, wl_pointer*, uint32_t) { }, + .axis_stop = [](void*, wl_pointer*, uint32_t, uint32_t) { }, + .axis_discrete = [](void*, wl_pointer*, uint32_t, int32_t) { }, +}; + +static const struct wl_seat_listener seatListener = { + .capabilities = [](void* sp, wl_seat*, uint32_t cap) + { + auto& seat = *static_cast(sp); + auto hasPointer = cap & WL_SEAT_CAPABILITY_POINTER; + if (!seat.pointer && hasPointer) { + auto &pointer = seat.pointer.emplace(); + pointer.wlPointer = wl_unique_ptr {wl_seat_get_pointer(seat.wlSeat.get())}; + wl_pointer_add_listener(seat.pointer->wlPointer.get(), &pointerListener, &seat); + } else if (seat.pointer && !hasPointer) { + seat.pointer.reset(); + } + }, + .name = [](void*, wl_seat*, const char* name) { } +}; + +void setupMonitor(uint32_t name, wl_output* output) { + auto& monitor = monitors.emplace_back(Monitor {name, {}, wl_unique_ptr {output}}); + monitor.bar.setStatus(lastStatus); + auto xdgOutput = zxdg_output_manager_v1_get_xdg_output(xdgOutputManager, monitor.wlOutput.get()); + zxdg_output_v1_add_listener(xdgOutput, &xdgOutputListener, &monitor); +} + +void updatemon(Monitor& mon) +{ + if (!mon.hasData) { + return; + } + if (mon.desiredVisibility) { + if (mon.bar.visible()) { + mon.bar.invalidate(); + } else { + mon.bar.show(mon.wlOutput.get()); + } + } else if (mon.bar.visible()) { + mon.bar.hide(); + } +} + +// called after we have received the initial batch of globals +void onReady() +{ + requireGlobal(compositor, "wl_compositor"); + requireGlobal(shm, "wl_shm"); + requireGlobal(wlrLayerShell, "zwlr_layer_shell_v1"); + requireGlobal(xdgOutputManager, "zxdg_output_manager_v1"); + setupStatusFifo(); + wl_display_roundtrip(display); // roundtrip so we receive all dwl tags etc. + + ready = true; + for (auto output : uninitializedOutputs) { + setupMonitor(output.first, output.second); + } + wl_display_roundtrip(display); // wait for xdg_output names before we read stdin +} + +bool createFifo(std::string path) +{ + auto result = mkfifo(path.c_str(), 0666); + if (result == 0) { + auto fd = open(path.c_str(), O_CLOEXEC | O_NONBLOCK | O_RDONLY); + if (fd < 0) { + diesys("open status fifo reader"); + } + statusFifoName = path; + statusFifoFd = fd; + + fd = open(path.c_str(), O_CLOEXEC | O_WRONLY); + if (fd < 0) { + diesys("open status fifo writer"); + } + statusFifoWriter = fd; + + pollfds.push_back({ + .fd = statusFifoFd, + .events = POLLIN, + }); + return true; + } else if (errno != EEXIST) { + diesys("mkfifo"); + } + + return false; +} + +void setupStatusFifo() +{ + if (!statusFifoName.empty()) { + createFifo(statusFifoName); + return; + } + + for (auto i=0; i<100; i++) { + auto path = std::string{getenv("XDG_RUNTIME_DIR")} + "/somebar-" + std::to_string(i); + if (createFifo(path)) { + return; + } + } +} + +static LineBuffer<512> stdinBuffer; +static void onStdin() +{ + auto res = stdinBuffer.readLines( + [](void* p, size_t size) { return read(0, p, size); }, + [](char* p, size_t size) { handleStdin({p, size}); }); + if (res == 0) { + quitting = true; + } +} + +static void handleStdin(const std::string& line) +{ + // this parses the lines that dwl sends in printstatus() + std::string monName, command; + auto stream = std::istringstream {line}; + stream >> monName >> command; + if (!stream.good()) { + return; + } + auto mon = std::find_if(begin(monitors), end(monitors), [&](const Monitor& mon) { + return mon.xdgName == monName; + }); + if (mon == end(monitors)) + return; + if (command == "title") { + auto title = std::string {}; + stream >> std::ws; + std::getline(stream, title); + mon->bar.setTitle(title); + } else if (command == "selmon") { + uint32_t selected; + stream >> selected; + mon->bar.setSelected(selected); + if (selected) { + selmon = &*mon; + } else if (selmon == &*mon) { + selmon = nullptr; + } + } else if (command == "tags") { + uint32_t occupied, tags, clientTags, urgent; + stream >> occupied >> tags >> clientTags >> urgent; + for (auto i=0u; ibar.setTag(i, state, occupied & tagMask ? 1 : 0, clientTags & tagMask ? 0 : -1); + } + mon->tags = tags; + } else if (command == "layout") { + auto layout = std::string {}; + stream >> std::ws; + std::getline(stream, layout); + mon->bar.setLayout(layout); + } + mon->hasData = true; + updatemon(*mon); +} + +const std::string prefixStatus = "status "; +const std::string prefixShow = "show "; +const std::string prefixHide = "hide "; +const std::string prefixToggle = "toggle "; +const std::string argAll = "all"; +const std::string argSelected = "selected"; + +static LineBuffer<512> statusBuffer; +void onStatus() +{ + statusBuffer.readLines( + [](void* p, size_t size) { + return read(statusFifoFd, p, size); + }, + [](const char* buffer, size_t n) { + auto str = std::string {buffer, n}; + if (str.rfind(prefixStatus, 0) == 0) { + lastStatus = str.substr(prefixStatus.size()); + for (auto &monitor : monitors) { + monitor.bar.setStatus(lastStatus); + monitor.bar.invalidate(); + } + } else if (str.rfind(prefixShow, 0) == 0) { + updateVisibility(str.substr(prefixShow.size()), [](bool) { return true; }); + } else if (str.rfind(prefixHide, 0) == 0) { + updateVisibility(str.substr(prefixHide.size()), [](bool) { return false; }); + } else if (str.rfind(prefixToggle, 0) == 0) { + updateVisibility(str.substr(prefixToggle.size()), [](bool vis) { return !vis; }); + } + }); +} + +void updateVisibility(const std::string& name, bool(*updater)(bool)) +{ + auto isCurrent = name == argSelected; + auto isAll = name == argAll; + for (auto& mon : monitors) { + if (isAll || + isCurrent && &mon == selmon || + mon.xdgName == name) { + auto newVisibility = updater(mon.desiredVisibility); + if (newVisibility != mon.desiredVisibility) { + mon.desiredVisibility = newVisibility; + updatemon(mon); + } + } + } +} + +struct HandleGlobalHelper { + wl_registry* registry; + uint32_t name; + const char* interface; + + template + bool handle(T& store, const wl_interface& iface, int version) { + if (strcmp(interface, iface.name)) { + return false; + } + store = static_cast(wl_registry_bind(registry, name, &iface, version)); + return true; + } +}; +void onGlobalAdd(void*, wl_registry* registry, uint32_t name, const char* interface, uint32_t version) +{ + auto reg = HandleGlobalHelper { registry, name, interface }; + if (reg.handle(compositor, wl_compositor_interface, 4)) return; + if (reg.handle(shm, wl_shm_interface, 1)) return; + if (reg.handle(wlrLayerShell, zwlr_layer_shell_v1_interface, 4)) return; + if (reg.handle(xdgOutputManager, zxdg_output_manager_v1_interface, 3)) return; + if (reg.handle(xdgWmBase, xdg_wm_base_interface, 2)) { + xdg_wm_base_add_listener(xdgWmBase, &xdgWmBaseListener, nullptr); + return; + } + if (wl_seat* wlSeat; reg.handle(wlSeat, wl_seat_interface, 7)) { + auto& seat = seats.emplace_back(Seat {name, wl_unique_ptr {wlSeat}}); + wl_seat_add_listener(wlSeat, &seatListener, &seat); + return; + } + if (wl_output* output; reg.handle(output, wl_output_interface, 1)) { + if (ready) { + setupMonitor(name, output); + } else { + uninitializedOutputs.push_back({name, output}); + } + return; + } +} +void onGlobalRemove(void*, wl_registry* registry, uint32_t name) +{ + monitors.remove_if([name](const Monitor &mon) { return mon.registryName == name; }); + seats.remove_if([name](const Seat &seat) { return seat.name == name; }); +} +static const struct wl_registry_listener registry_listener = { + .global = onGlobalAdd, + .global_remove = onGlobalRemove, +}; + +int main(int argc, char* argv[]) +{ + int opt; + while ((opt = getopt(argc, argv, "chvs:")) != -1) { + switch (opt) { + case 's': + statusFifoName = optarg; + break; + case 'h': + printf("Usage: %s [-h] [-v] [-s path to the fifo] [-c command]\n", argv[0]); + printf(" -h: Show this help\n"); + printf(" -v: Show somebar version\n"); + printf(" -s: Change path to the fifo (default is \"$XDG_RUNTIME_DIR/somebar-0\")\n"); + printf(" -c: Sends a command to sombar. See README for details.\n"); + printf("If any of these are specified (except -s), somebar exits after the action.\n"); + printf("Otherwise, somebar will display itself.\n"); + exit(0); + case 'v': + printf("somebar " SOMEBAR_VERSION "\n"); + exit(0); + case 'c': + if (optind >= argc) { + die("Expected command"); + } + if (statusFifoName.empty()) { + statusFifoName = std::string {getenv("XDG_RUNTIME_DIR")} + "/somebar-0"; + } + statusFifoWriter = open(statusFifoName.c_str(), O_WRONLY | O_CLOEXEC); + if (statusFifoWriter < 0) { + fprintf(stderr, "could not open %s: ", statusFifoName.c_str()); + perror(""); + exit(1); + } + auto str = std::string {}; + for (auto i = optind; i optind) str += " "; + str += argv[i]; + } + str += "\n"; + write(statusFifoWriter, str.c_str(), str.size()); + exit(0); + } + } + + if (pipe(signalSelfPipe.data()) < 0) { + diesys("pipe"); + } + setCloexec(signalSelfPipe[0]); + setCloexec(signalSelfPipe[1]); + + struct sigaction sighandler = {}; + sighandler.sa_handler = [](int) { + if (write(signalSelfPipe[1], "0", 1) < 0) { + diesys("write"); + } + }; + if (sigaction(SIGTERM, &sighandler, nullptr) < 0) { + diesys("sigaction"); + } + if (sigaction(SIGINT, &sighandler, nullptr) < 0) { + diesys("sigaction"); + } + + struct sigaction chld_handler = {}; + chld_handler.sa_handler = SIG_IGN; + if (sigaction(SIGCHLD, &chld_handler, nullptr) < 0) { + die("sigaction"); + } + + pollfds.push_back({ + .fd = signalSelfPipe[0], + .events = POLLIN, + }); + + display = wl_display_connect(nullptr); + if (!display) { + die("Failed to connect to Wayland display"); + } + displayFd = wl_display_get_fd(display); + + auto registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, nullptr); + wl_display_roundtrip(display); + onReady(); + + pollfds.push_back({ + .fd = displayFd, + .events = POLLIN, + }); + pollfds.push_back({ + .fd = STDIN_FILENO, + .events = POLLIN, + }); + if (fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK) < 0) { + diesys("fcntl F_SETFL"); + } + + while (!quitting) { + waylandFlush(); + if (poll(pollfds.data(), pollfds.size(), -1) < 0) { + if (errno != EINTR) { + diesys("poll"); + } + } else { + for (auto& ev : pollfds) { + if (ev.revents & POLLNVAL) { + die("poll revents contains POLLNVAL"); + } else if (ev.fd == displayFd) { + if (ev.revents & POLLIN) { + if (wl_display_dispatch(display) < 0) { + die("wl_display_dispatch"); + } + } + if (ev.revents & POLLOUT) { + ev.events = POLLIN; + waylandFlush(); + } + } else if (ev.fd == STDIN_FILENO && (ev.revents & POLLIN)) { + onStdin(); + } else if (ev.fd == statusFifoFd && (ev.revents & POLLIN)) { + onStatus(); + } else if (ev.fd == signalSelfPipe[0] && (ev.revents & POLLIN)) { + quitting = true; + } + } + } + } + cleanup(); +} + +void requireGlobal(const void* p, const char* name) +{ + if (p) return; + fprintf(stderr, "Wayland compositor does not export required global %s, aborting.\n", name); + cleanup(); + exit(1); +} + +void waylandFlush() +{ + wl_display_dispatch_pending(display); + if (wl_display_flush(display) < 0 && errno == EAGAIN) { + for (auto& ev : pollfds) { + if (ev.fd == displayFd) { + ev.events |= POLLOUT; + } + } + } +} + +void setCloexec(int fd) +{ + int flags = fcntl(fd, F_GETFD); + if (flags == -1) { + diesys("fcntl FD_GETFD"); + } + if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) { + diesys("fcntl FD_SETFD"); + } +} + +void cleanup() { + if (!statusFifoName.empty()) { + unlink(statusFifoName.c_str()); + } +} + +void die(const char* why) { + fprintf(stderr, "error: %s failed, aborting\n", why); + cleanup(); + exit(1); +} + +void diesys(const char* why) { + perror(why); + cleanup(); + exit(1); +} diff --git a/.config/dwl/somebar/src/shm_buffer.cpp b/.config/dwl/somebar/src/shm_buffer.cpp new file mode 100644 index 0000000..59baf6f --- /dev/null +++ b/.config/dwl/somebar/src/shm_buffer.cpp @@ -0,0 +1,85 @@ +// somebar - dwl bar +// See LICENSE file for copyright and license details. + +#include +#include +#include +#include +#include "shm_buffer.hpp" +#include "common.hpp" + +static int createAnonShm(); +constexpr int n = 2; + +ShmBuffer::ShmBuffer(int w, int h, wl_shm_format format) + : width(w) + , height(h) + , stride(w*4) +{ + auto oneSize = stride*size_t(h); + auto totalSize = oneSize * n; + auto fd = createAnonShm(); + if (fd < 0) { + diesys("memfd_create"); + } + if (ftruncate(fd, totalSize) < 0) { + diesys("ftruncate"); + } + auto pool = wl_shm_create_pool(shm, fd, totalSize); + auto ptr = reinterpret_cast(mmap(nullptr, totalSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); + if (!ptr) { + diesys("mmap"); + } + _mapping = MemoryMapping {ptr, totalSize}; + close(fd); + for (auto i=0; i { wl_shm_pool_create_buffer(pool, offset, width, height, stride, format) }, + }; + } + wl_shm_pool_destroy(pool); +} + +uint8_t* ShmBuffer::data() +{ + return _buffers[_current].data; +} + +wl_buffer* ShmBuffer::buffer() +{ + return _buffers[_current].buffer.get(); +} + +void ShmBuffer::flip() +{ + _current = 1-_current; +} + +#if defined(__linux__) +int createAnonShm() { + return memfd_create("wl_shm", MFD_CLOEXEC); +} +#elif defined(__FreeBSD__) +int createAnonShm() { + auto fd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0600); + setCloexec(fd); + return fd; +} +#elif defined(__OpenBSD__) +int createAnonShm() { + char name[] = "/wl_shm-XXXXXX"; + auto fd = shm_mkstemp(name); + if (fd >= 0) { + auto res = shm_unlink(name); + if (res < 0) { + return res; + } + } + setCloexec(fd); + return fd; +} +#else +#error "your system has no sane method of creating an anonymous shared memory object. no, calling shm_open in a loop is not sane." +#endif diff --git a/.config/dwl/somebar/src/shm_buffer.hpp b/.config/dwl/somebar/src/shm_buffer.hpp new file mode 100644 index 0000000..f6927dd --- /dev/null +++ b/.config/dwl/somebar/src/shm_buffer.hpp @@ -0,0 +1,45 @@ +// somebar - dwl bar +// See LICENSE file for copyright and license details. + +#pragma once +#include +#include +#include +#include "common.hpp" + +class MemoryMapping { + void* _ptr {nullptr}; + size_t _size {0}; +public: + MemoryMapping() { } + explicit MemoryMapping(void* ptr, size_t size) : _ptr(ptr), _size(size) { } + MemoryMapping(const MemoryMapping&) = delete; + MemoryMapping(MemoryMapping&& other) { swap(other); } + MemoryMapping& operator=(const MemoryMapping& other) = delete; + MemoryMapping& operator=(MemoryMapping&& other) { swap(other); return *this; } + ~MemoryMapping() { if (_ptr) munmap(_ptr, _size); } + void swap(MemoryMapping &other) { + using std::swap; + swap(_ptr, other._ptr); + swap(_size, other._size); + } +}; + +// double buffered shm +// format is must be 32-bit +class ShmBuffer { + struct Buf { + uint8_t* data {nullptr}; + wl_unique_ptr buffer; + }; + std::array _buffers; + int _current {0}; + MemoryMapping _mapping; +public: + const uint32_t width, height, stride; + + explicit ShmBuffer(int width, int height, wl_shm_format format); + uint8_t* data(); + wl_buffer* buffer(); + void flip(); +}; diff --git a/.config/dwl/startscreensaver.sh b/.config/dwl/startscreensaver.sh new file mode 100755 index 0000000..b48b194 --- /dev/null +++ b/.config/dwl/startscreensaver.sh @@ -0,0 +1,82 @@ +#!/bin/bash + +# Basic configuration variables +ScreensaverTime="1200" # 20 minutes +monitorOne="DP-1" # First monitor +monitorTwo="DP-2" # Second monitor +monitorThree="" # Third monitor + +# Load script for load monitors config quickly from resume +LoadConfigResume="${HOME}/.config/dwl/startwlrrandr.sh" + +# StateFile variable +stateFile="${HOME}/.config/dwl/screen-state" + +# Function for sleep monitors +function sleepMonitors() { + # Check monitor 3 + if [ -z "${monitorThree}" ] ; then + echo "Monitor 3 is empty or disabled" + else + echo "Sleep monitor 3" + wlr-randr --output ${monitorThree} --off + fi + # Check monitor 2 + if [ -z "${monitorTwo}" ] ; then + echo "Monitor 2 is empty or disabled" + else + echo "Sleep monitor 2" + wlr-randr --output ${monitorTwo} --off + fi + # Check monitor 1 + if [ -z "${monitorOne}" ] ; then + echo "Monitor 1 is empty or disabled" + else + echo "Sleep monitor 1" + wlr-randr --output ${monitorOne} --off + fi + echo "sleep" > ${stateFile} +} + +# Function for resume monitors +function resumeMonitors() { + # Check monitor 3 + if [ -z "${monitorThree}" ] ; then + echo "Monitor 3 is empty or disabled" + else + echo "Resume monitor 3" + wlr-randr --output ${monitorThree} --on + fi + # Check monitor 2 + if [ -z "${monitorTwo}" ] ; then + echo "Monitor 2 is empty or disabled" + else + echo "Resume monitor 2" + wlr-randr --output ${monitorTwo} --on + fi + # Check monitor 1 + if [ -z "${monitorOne}" ] ; then + echo "Monitor 1 is empty or disabled" + else + echo "Resume monitor 1" + wlr-randr --output ${monitorOne} --on + fi + # Load monitors config quickly + bash ${LoadConfigResume} screensaver + echo "resume" > ${stateFile} +} + +# Boot parameters +if [ -z "${1}" ] ; then + # Kill previous process + echo "Trying to kill previous process" + killall -9 swayidle + # Init swayidle command + sleep 3 + swayidle timeout ${ScreensaverTime} "bash ${0} sleep" resume "bash ${0} resume" +elif [ "${1}" == "sleep" ] ; then + sleepMonitors +elif [ "${1}" == "resume" ] ; then + resumeMonitors +fi + diff --git a/.config/dwl/startwlrrandr.sh b/.config/dwl/startwlrrandr.sh new file mode 100755 index 0000000..1ff0e68 --- /dev/null +++ b/.config/dwl/startwlrrandr.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# Ignore sleep when run script from startwlrscreensaver.sh +if [ "${1}" == "screensaver" ] ; then + echo "Load monitor configuration quickly" +else + sleep 2 +fi + +# Configuration for your monitor(s). Use wlr-randr and/or wdisplays for help +wlr-randr --output DP-1 --custom-mode 1600x1200@60Hz --pos 0,0 +wlr-randr --output DP-2 --custom-mode 1280x1024@60.020Hz --transform 90 --pos 1600,0 diff --git a/.config/dwl/util.c b/.config/dwl/util.c new file mode 100644 index 0000000..cca7c19 --- /dev/null +++ b/.config/dwl/util.c @@ -0,0 +1,35 @@ +/* See LICENSE.dwm file for copyright and license details. */ +#include +#include +#include +#include + +#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/.config/dwl/util.h b/.config/dwl/util.h new file mode 100644 index 0000000..4c94117 --- /dev/null +++ b/.config/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/.config/dwl/util.o b/.config/dwl/util.o new file mode 100644 index 0000000000000000000000000000000000000000..61cbbe5a4006590209e1127ea84b7b650fc55c4a GIT binary patch literal 2240 zcmbtV&r4KM6h2SK98G5?Yatjk!7XN>9*z--R*X624F(abMQv)FdFIgk>diH@f(&i( z5WznnLa1d67cCUIp=)mJLlea&%OHKeELF@ zVSo|?&cbe_P=I8M=DThZLeL49_`|Jt7<1=0cLa-Z=Q8W%PMYaVi{7 zv9WMG&2EI_msuqof6V5vEF6EvmR+}Yv_2XuN!=RE9kKv)kF)Qe-nJomv)!RW(tLJb^u^xcz7Th8yUS4k0$!e zK9e>K0n{ie9Ve!s35*(H>dXxpw;@Jyz%yXn9S373V)S&h2A7fCjrc*C`$={v6q#=t z32n+;zswyXn+ion+e5*jy%MZrX#D{E*sha;=AGT`W`nM)T?(1%MBAnD-Mt~U4>ck= zx}oo=haYZ$#~R>f1N=k-9OvWiQ|-?^C&UID@L^iy3uYF~^l&fa@)lG@&a!Q|Gg-0o zB{7MyU9d_pS(z4Dux9cCDwr?ZV0jk;`;t8I49?xV1An$Xc`9+b3wux%zN+D^8vaV+ z{yuLtKFvt=d9UGgw-ml1aetrB8ei}8O~dKos6M|myhFp==whKz|7KLh4@sQ9msH_V z^ht0q9@D*nAvi% zXqAvsDhtcRCwaUoGTB=)zFC?!D|Q)2DQ2;h8d_7=C+$qpQak%U8^v-u3YxhtNf~s> zb5c292tAmf^Ghm%v=usRl&CDAr%x`;l7!wJ$x&3oC7mEw#{COP+z%f^oO=FieFAH# zXCJCAYJIg|l~e00o5Te9?jKi0LVHaT_G=iqs!rL98m3c=ilBpaxK|OQcd6f1DyhhN z|Gxa+a~rut_1CY+`Y~#ziNC&pxq9#a?7-{t!K($brzmi~I` g>7PA95R>3J3N(@Jb`bi%P_Mow_kVAP={f%Tzm}#GR{#J2 literal 0 HcmV?d00001 diff --git a/.config/dwl/wlr-layer-shell-unstable-v1-protocol.h b/.config/dwl/wlr-layer-shell-unstable-v1-protocol.h new file mode 100644 index 0000000..3b4d7e7 --- /dev/null +++ b/.config/dwl/wlr-layer-shell-unstable-v1-protocol.h @@ -0,0 +1,606 @@ +/* Generated by wayland-scanner 1.21.0 */ + +#ifndef WLR_LAYER_SHELL_UNSTABLE_V1_SERVER_PROTOCOL_H +#define WLR_LAYER_SHELL_UNSTABLE_V1_SERVER_PROTOCOL_H + +#include +#include +#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 + *
    + *
    + * 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.
    + * 
    + */ +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/.config/dwl/xdg-shell-protocol.h b/.config/dwl/xdg-shell-protocol.h new file mode 100644 index 0000000..de94fef --- /dev/null +++ b/.config/dwl/xdg-shell-protocol.h @@ -0,0 +1,1928 @@ +/* Generated by wayland-scanner 1.21.0 */ + +#ifndef XDG_SHELL_SERVER_PROTOCOL_H +#define XDG_SHELL_SERVER_PROTOCOL_H + +#include +#include +#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 + *
    + *
    + * 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.
    + * 
    + */ +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 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 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. + * + * 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. + * + * 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, +}; +#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. + */ + 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. + * + * The width and height must be greater than zero. Setting an + * invalid size will raise an invalid_size error. 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. + */ + 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. + * + * 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, +}; +/** + * @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 +#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 a 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, a 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/.config/nwg-wrapper/conky_dwl.sh b/.config/nwg-wrapper/conky_dwl.sh new file mode 100755 index 0000000..76c583c --- /dev/null +++ b/.config/nwg-wrapper/conky_dwl.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash + +echo ' SYSTEM INFO' +echo '==============' +echo '' +show_kernel=$(${HOME}/.config/conky/scripts/kernel_version.sh) +show_time=$(${HOME}/.config/conky/scripts/current_date.sh) +show_uptime=$(${HOME}/.config/conky/scripts/show_uptime.sh) +show_volume=$(${HOME}/.config/conky/scripts/get_volume.sh) +show_disk=$(${HOME}/.config/conky/scripts/disk_info.sh) +show_memory=$(${HOME}/.config/conky/scripts/mem_info.sh) +show_cpu=$(${HOME}/.config/conky/scripts/cpu_info.sh) +show_gpu=$(${HOME}/.config/conky/scripts/gpu_info.sh) +show_updates=$(${HOME}/.config/conky/scripts/checkUpdates.sh) +echo ' Kernel:' ${show_kernel}'' +echo ' Time: '${show_time}'' +echo ' Uptime:' ${show_uptime}'' +echo ' Volume:' ${show_volume}'' +echo ' Disk:' ${show_disk}'' +echo ' Memory:' ${show_memory}'' +echo ' CPU:' ${show_cpu}'' +echo ' GPU:' ${show_gpu}'' +echo ' Updates' ${show_updates}'' +echo '' +echo ' DWL KEYBINDINGS' +echo '===================' +echo '' +echo ' Super +  = Kitty' +echo ' Super + וּ + space = Float Window' +echo ' Super + f = Fullscreen' +echo ' Super + p = Wofi (Run Mode)' +echo ' Super + o = Wofi (Drun Mode)' +echo ' Super + q = Rofi (Window Mode)' +echo ' Super + d = Dmenu' +echo ' Super + b = Mozilla Firefox' +echo ' Super + n = PCManFM' +echo ' Super + t = Wl-Screenshooter' +echo ' Super + g = Geany' +echo ' Super + m = Telegram' +echo ' Super + z = Wf-Recorder' +echo ' Super + x = Wdisplays' +echo ' Super + u = Xterm' +echo ' Super + i = LXAppearance' +echo ' Super + c = NetworkManager' +echo ' Super + h = Set Horizontal' +echo ' Super + v = Set Vertical' +echo '= Volume +5' +echo '= Volume -5' +echo '= Mute Volume' +echo ' Super + וּ + q = Kill Window' +echo ' Super + j = Focus Left' +echo ' Super + ; = Focus Right' +echo ' Super + l = Focus Up' +echo ' Super + k = Focus Down' +echo ' Super + וּ + e = Logout' +echo ' Super + דּ + וּ + l = Screen-off' +echo ' Super + r = Resize Window' +echo ' Super + וּ + j = Switch Left' +echo ' Super + וּ + ; = Switch Right' +echo ' Super + וּ + l = Switch Up' +echo ' Super + וּ + k = Switch Down' +echo ' Super + 1-9 = Select Workspace' +echo ' Super +  = Menu Logout' +#echo ""