diff options
| author | tslil clingman <tslil@posteo.de> | 2023-12-01 18:04:04 +0100 |
|---|---|---|
| committer | tslil clingman <tslil@posteo.de> | 2023-12-01 18:12:10 +0100 |
| commit | 119f17396c60900eaf7534f8106d4ce6ca0362e5 (patch) | |
| tree | 3d2074b5f295e8168312494381ab23eccc0ca1ec | |
| parent | 9bc372625e1fdafa50d44dcb9a8070ecdfc01b38 (diff) | |
[dwl] track only patches against upstream
| -rw-r--r-- | dwl/LICENSE | 692 | ||||
| -rw-r--r-- | dwl/LICENSE.dwm | 39 | ||||
| -rw-r--r-- | dwl/LICENSE.sway | 19 | ||||
| -rw-r--r-- | dwl/LICENSE.tinywl | 127 | ||||
| -rw-r--r-- | dwl/Makefile | 63 | ||||
| -rw-r--r-- | dwl/README.md | 173 | ||||
| -rw-r--r-- | dwl/bottomstack.patch | 142 | ||||
| -rw-r--r-- | dwl/bstack.patch | 179 | ||||
| -rw-r--r-- | dwl/client.h | 402 | ||||
| -rw-r--r-- | dwl/config.def.h | 170 | ||||
| -rw-r--r-- | dwl/config.h | 5 | ||||
| -rw-r--r-- | dwl/config.mk | 15 | ||||
| -rw-r--r-- | dwl/dwl.1 | 158 | ||||
| -rw-r--r-- | dwl/dwl.c | 2993 | ||||
| -rw-r--r-- | dwl/dwl.desktop | 5 | ||||
| -rwxr-xr-x | dwl/dwl.sh | 9 | ||||
| -rw-r--r-- | dwl/pertag.patch | 113 | ||||
| -rw-r--r-- | dwl/protocols/wlr-layer-shell-unstable-v1.xml | 390 | ||||
| -rw-r--r-- | dwl/rmaster.patch | 27 | ||||
| -rw-r--r-- | dwl/util.c | 35 | ||||
| -rw-r--r-- | dwl/util.h | 4 |
21 files changed, 277 insertions, 5483 deletions
diff --git a/dwl/LICENSE b/dwl/LICENSE deleted file mode 100644 index 658085a..0000000 --- a/dwl/LICENSE +++ /dev/null @@ -1,692 +0,0 @@ -dwl - dwm for Wayland - -Copyright © 2020 dwl team - -See also the files LICENSE.tinywl, LICENSE.dwm and LICENSE.sway. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - ----- - - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - <program> Copyright (C) <year> <name of author> - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -<https://www.gnu.org/licenses/>. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -<https://www.gnu.org/licenses/why-not-lgpl.html>. diff --git a/dwl/LICENSE.dwm b/dwl/LICENSE.dwm deleted file mode 100644 index 507e4dc..0000000 --- a/dwl/LICENSE.dwm +++ /dev/null @@ -1,39 +0,0 @@ -Portions of dwl based on dwm code are used under the following license: - -MIT/X Consortium License - -© 2006-2019 Anselm R Garbe <anselm@garbe.ca> -© 2006-2009 Jukka Salmi <jukka at salmi dot ch> -© 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com> -© 2007-2011 Peter Hartlich <sgkkr at hartlich dot com> -© 2007-2009 Szabolcs Nagy <nszabolcs at gmail dot com> -© 2007-2009 Christof Musik <christof at sendfax dot de> -© 2007-2009 Premysl Hruby <dfenze at gmail dot com> -© 2007-2008 Enno Gottox Boland <gottox at s01 dot de> -© 2008 Martin Hurton <martin dot hurton at gmail dot com> -© 2008 Neale Pickett <neale dot woozle dot org> -© 2009 Mate Nagy <mnagy at port70 dot net> -© 2010-2016 Hiltjo Posthuma <hiltjo@codemadness.org> -© 2010-2012 Connor Lane Smith <cls@lubutu.com> -© 2011 Christoph Lohmann <20h@r-36.net> -© 2015-2016 Quentin Rameau <quinq@fifth.space> -© 2015-2016 Eric Pruitt <eric.pruitt@gmail.com> -© 2016-2017 Markus Teich <markus.teich@stusta.mhn.de> - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/dwl/LICENSE.sway b/dwl/LICENSE.sway deleted file mode 100644 index 3e0cacc..0000000 --- a/dwl/LICENSE.sway +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2016-2017 Drew DeVault - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/dwl/LICENSE.tinywl b/dwl/LICENSE.tinywl deleted file mode 100644 index 7023690..0000000 --- a/dwl/LICENSE.tinywl +++ /dev/null @@ -1,127 +0,0 @@ -dwl is originally based on TinyWL, which is used under the following license: - -This work is licensed under CC0, which effectively puts it in the public domain. - ---- - -Creative Commons Legal Code - -CC0 1.0 Universal - - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE - LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN - ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS - INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES - REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS - PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM - THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED - HEREUNDER. - -Statement of Purpose - -The laws of most jurisdictions throughout the world automatically confer -exclusive Copyright and Related Rights (defined below) upon the creator -and subsequent owner(s) (each and all, an "owner") of an original work of -authorship and/or a database (each, a "Work"). - -Certain owners wish to permanently relinquish those rights to a Work for -the purpose of contributing to a commons of creative, cultural and -scientific works ("Commons") that the public can reliably and without fear -of later claims of infringement build upon, modify, incorporate in other -works, reuse and redistribute as freely as possible in any form whatsoever -and for any purposes, including without limitation commercial purposes. -These owners may contribute to the Commons to promote the ideal of a free -culture and the further production of creative, cultural and scientific -works, or to gain reputation or greater distribution for their Work in -part through the use and efforts of others. - -For these and/or other purposes and motivations, and without any -expectation of additional consideration or compensation, the person -associating CC0 with a Work (the "Affirmer"), to the extent that he or she -is an owner of Copyright and Related Rights in the Work, voluntarily -elects to apply CC0 to the Work and publicly distribute the Work under its -terms, with knowledge of his or her Copyright and Related Rights in the -Work and the meaning and intended legal effect of CC0 on those rights. - -1. Copyright and Related Rights. A Work made available under CC0 may be -protected by copyright and related or neighboring rights ("Copyright and -Related Rights"). Copyright and Related Rights include, but are not -limited to, the following: - - i. the right to reproduce, adapt, distribute, perform, display, - communicate, and translate a Work; - ii. moral rights retained by the original author(s) and/or performer(s); -iii. publicity and privacy rights pertaining to a person's image or - likeness depicted in a Work; - iv. rights protecting against unfair competition in regards to a Work, - subject to the limitations in paragraph 4(a), below; - v. rights protecting the extraction, dissemination, use and reuse of data - in a Work; - vi. database rights (such as those arising under Directive 96/9/EC of the - European Parliament and of the Council of 11 March 1996 on the legal - protection of databases, and under any national implementation - thereof, including any amended or successor version of such - directive); and -vii. other similar, equivalent or corresponding rights throughout the - world based on applicable law or treaty, and any national - implementations thereof. - -2. Waiver. To the greatest extent permitted by, but not in contravention -of, applicable law, Affirmer hereby overtly, fully, permanently, -irrevocably and unconditionally waives, abandons, and surrenders all of -Affirmer's Copyright and Related Rights and associated claims and causes -of action, whether now known or unknown (including existing as well as -future claims and causes of action), in the Work (i) in all territories -worldwide, (ii) for the maximum duration provided by applicable law or -treaty (including future time extensions), (iii) in any current or future -medium and for any number of copies, and (iv) for any purpose whatsoever, -including without limitation commercial, advertising or promotional -purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each -member of the public at large and to the detriment of Affirmer's heirs and -successors, fully intending that such Waiver shall not be subject to -revocation, rescission, cancellation, termination, or any other legal or -equitable action to disrupt the quiet enjoyment of the Work by the public -as contemplated by Affirmer's express Statement of Purpose. - -3. Public License Fallback. Should any part of the Waiver for any reason -be judged legally invalid or ineffective under applicable law, then the -Waiver shall be preserved to the maximum extent permitted taking into -account Affirmer's express Statement of Purpose. In addition, to the -extent the Waiver is so judged Affirmer hereby grants to each affected -person a royalty-free, non transferable, non sublicensable, non exclusive, -irrevocable and unconditional license to exercise Affirmer's Copyright and -Related Rights in the Work (i) in all territories worldwide, (ii) for the -maximum duration provided by applicable law or treaty (including future -time extensions), (iii) in any current or future medium and for any number -of copies, and (iv) for any purpose whatsoever, including without -limitation commercial, advertising or promotional purposes (the -"License"). The License shall be deemed effective as of the date CC0 was -applied by Affirmer to the Work. Should any part of the License for any -reason be judged legally invalid or ineffective under applicable law, such -partial invalidity or ineffectiveness shall not invalidate the remainder -of the License, and in such case Affirmer hereby affirms that he or she -will not (i) exercise any of his or her remaining Copyright and Related -Rights in the Work or (ii) assert any associated claims and causes of -action with respect to the Work, in either case contrary to Affirmer's -express Statement of Purpose. - -4. Limitations and Disclaimers. - - a. No trademark or patent rights held by Affirmer are waived, abandoned, - surrendered, licensed or otherwise affected by this document. - b. Affirmer offers the Work as-is and makes no representations or - warranties of any kind concerning the Work, express, implied, - statutory or otherwise, including without limitation warranties of - title, merchantability, fitness for a particular purpose, non - infringement, or the absence of latent or other defects, accuracy, or - the present or absence of errors, whether or not discoverable, all to - the greatest extent permissible under applicable law. - c. Affirmer disclaims responsibility for clearing rights of other persons - that may apply to the Work or any use thereof, including without - limitation any person's Copyright and Related Rights in the Work. - Further, Affirmer disclaims responsibility for obtaining any necessary - consents, permissions or other rights required for any use of the - Work. - d. Affirmer understands and acknowledges that Creative Commons is not a - party to this document and has no duty or obligation with respect to - this CC0 or use of the Work. diff --git a/dwl/Makefile b/dwl/Makefile deleted file mode 100644 index 5320e42..0000000 --- a/dwl/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -.POSIX: -.SUFFIXES: - -include config.mk - -# flags for compiling -DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L -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.desktop\ - dwl-$(VERSION) - tar -caf dwl-$(VERSION).tar.gz dwl-$(VERSION) - rm -rf dwl-$(VERSION) - -install: dwl - mkdir -p $(DESTDIR)$(PREFIX)/bin - cp -f dwl $(DESTDIR)$(PREFIX)/bin - chmod 755 $(DESTDIR)$(PREFIX)/bin/dwl - mkdir -p $(DESTDIR)$(MANDIR)/man1 - cp -f dwl.1 $(DESTDIR)$(MANDIR)/man1 - chmod 644 $(DESTDIR)$(MANDIR)/man1/dwl.1 - mkdir -p $(DESTDIR)$(DATADIR)/wayland-sessions - cp -f dwl.desktop $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop - chmod 644 $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop -uninstall: - rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop - -.SUFFIXES: .c .o -.c.o: - $(CC) $(CPPFLAGS) $(DWLCFLAGS) -c $< diff --git a/dwl/README.md b/dwl/README.md deleted file mode 100644 index 62ae872..0000000 --- a/dwl/README.md +++ /dev/null @@ -1,173 +0,0 @@ -# dwl - dwm for Wayland - -Join us on our IRC channel: [#dwl on Libera Chat] -Or on our [Discord server]. - -dwl is a compact, hackable compositor for [Wayland] based on [wlroots]. It is -intended to fill the same space in the Wayland world that dwm does in X11, -primarily in terms of philosophy, and secondarily in terms of functionality. -Like dwm, dwl is: - -- Easy to understand, hack on, and extend with patches -- One C source file (or a very small number) configurable via `config.h` -- Limited to 2200 SLOC to promote hackability -- Tied to as few external dependencies as possible - -dwl is not meant to provide every feature under the sun. Instead, like dwm, it -sticks to features which are necessary, simple, and straightforward to implement -given the base on which it is built. Implemented default features are: - -- Any features provided by dwm/Xlib: simple window borders, tags, keybindings, - client rules, mouse move/resize. Providing a built-in status bar is an - exception to this goal, to avoid dependencies on font rendering and/or - drawing libraries when an external bar could work well. -- Configurable multi-monitor layout support, including position and rotation -- Configurable HiDPI/multi-DPI support -- Idle-inhibit protocol which lets applications such as mpv disable idle - monitoring -- Provide information to external status bars via stdout/stdin -- Urgency hints via xdg-activate protocol -- Support screen lockers via ext-session-lock-v1 protocol -- Various Wayland protocols -- XWayland support as provided by wlroots (can be enabled in `config.mk`) -- Zero flickering - Wayland users naturally expect that "every frame is perfect" -- Layer shell popups (used by Waybar) -- Damage tracking provided by scenegraph API - -Features under consideration (possibly as patches) are: - -- Protocols made trivial by wlroots -- Implement the text-input and input-method protocols to support IME once ibus - implements input-method v2 (see https://github.com/ibus/ibus/pull/2256 and - https://github.com/djpohly/dwl/pull/235) - -Feature *non-goals* for the main codebase include: - -- Client-side decoration (any more than is necessary to tell the clients not to) -- Client-initiated window management, such as move, resize, and close, which can - be done through the compositor -- Animations and visual effects - -## Building dwl - -dwl has the following dependencies: -``` -libinput -wayland -wlroots (compiled with the libinput backend) -xkbcommon -wayland-protocols (compile-time only) -pkg-config (compile-time only) -``` -If you enable X11 support: -``` -libxcb -libxcb-wm -wlroots (compiled with X11 support) -Xwayland (runtime only) -``` - -Simply install these (and their `-devel` versions if your distro has separate -development packages) and run `make`. If you wish to build against a Git -version of wlroots, check out the [wlroots-next branch]. - -To enable XWayland, you should uncomment its flags in `config.mk`. - -## Configuration - -All configuration is done by editing `config.h` and recompiling, in the same -manner as dwm. There is no way to separately restart the window manager in -Wayland without restarting the entire display server, so any changes will take -effect the next time dwl is executed. - -As in the dwm community, we encourage users to share patches they have created. -Check out the [patches page on our wiki]! - -## Running dwl - -dwl can be run on any of the backends supported by wlroots. This means you can -run it as a separate window inside either an X11 or Wayland session, as well -as directly from a VT console. Depending on your distro's setup, you may need -to add your user to the `video` and `input` groups before you can run dwl on -a VT. If you are using `elogind` or `systemd-logind` you need to install -polkit; otherwise you need to add yourself in the `seat` group and -enable/start the seatd daemon. - -When dwl is run with no arguments, it will launch the server and begin handling -any shortcuts configured in `config.h`. There is no status bar or other -decoration initially; these are instead clients that can be run within -the Wayland session. -Do note that the background color is black. - -If you would like to run a script or command automatically at startup, you can -specify the command using the `-s` option. This command will be executed as a -shell command using `/bin/sh -c`. It serves a similar function to `.xinitrc`, -but differs in that the display server will not shut down when this process -terminates. Instead, dwl will send this process a SIGTERM at shutdown and wait -for it to terminate (if it hasn't already). This makes it ideal for execing into -a user service manager like [s6], [anopa], [runit], or [`systemd --user`]. - -Note: The `-s` command is run as a *child process* of dwl, which means that it -does not have the ability to affect the environment of dwl or of any processes -that it spawns. If you need to set environment variables that affect the entire -dwl session, these must be set prior to running dwl. For example, Wayland -requires a valid `XDG_RUNTIME_DIR`, which is usually set up by a session manager -such as `elogind` or `systemd-logind`. If your system doesn't do this -automatically, you will need to configure it prior to launching `dwl`, e.g.: - - export XDG_RUNTIME_DIR=/tmp/xdg-runtime-$(id -u) - mkdir -p $XDG_RUNTIME_DIR - dwl - -### Status information - -Information about selected layouts, current window title, app-id, and -selected/occupied/urgent tags is written to the stdin of the `-s` command (see -the `printstatus()` function for details). This information can be used to -populate an external status bar with a script that parses the information. -Failing to read this information will cause dwl to block, so if you do want to -run a startup command that does not consume the status information, you can -close standard input with the `<&-` shell redirection, for example: - - dwl -s 'foot --server <&-' - -If your startup command is a shell script, you can achieve the same inside the -script with the line - - exec <&- - -To get a list of status bars that work with dwl consult our [wiki]. - -## Replacements for X applications - -You can find a [list of useful resources on our wiki]. - -## Acknowledgements - -dwl began by extending the TinyWL example provided (CC0) by the sway/wlroots -developers. This was made possible in many cases by looking at how sway -accomplished something, then trying to do the same in as suckless a way as -possible. - -Many thanks to suckless.org and the dwm developers and community for the -inspiration, and to the various contributors to the project, including: - -- Alexander Courtis for the XWayland implementation -- Guido Cella for the layer-shell protocol implementation, patch maintenance, - and for helping to keep the project running -- Stivvo for output management and fullscreen support, and patch maintenance - - -[Discord server]: https://discord.gg/jJxZnrGPWN -[#dwl on Libera Chat]: https://web.libera.chat/?channels=#dwl -[Wayland]: https://wayland.freedesktop.org/ -[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots/ -[wlroots-next branch]: https://github.com/djpohly/dwl/tree/wlroots-next -[patches page on our wiki]: https://github.com/djpohly/dwl/wiki/Patches -[s6]: https://skarnet.org/software/s6/ -[anopa]: https://jjacky.com/anopa/ -[runit]: http://smarden.org/runit/faq.html#userservices -[`systemd --user`]: https://wiki.archlinux.org/title/Systemd/User -[wiki]: https://github.com/djpohly/dwl/wiki#compatible-status-bars -[list of useful resources on our wiki]: - https://github.com/djpohly/dwl/wiki#migrating-from-x diff --git a/dwl/bottomstack.patch b/dwl/bottomstack.patch deleted file mode 100644 index ed17954..0000000 --- a/dwl/bottomstack.patch +++ /dev/null @@ -1,142 +0,0 @@ -From 34d7666c923560b707def6e359efd49587de3fd5 Mon Sep 17 00:00:00 2001 -From: DanielMowitz <dmowitz@students.uni-mainz.de> -Date: Wed, 6 Oct 2021 18:59:55 +0200 -Subject: [PATCH] Add bottomstack patch. - -Authors - - * Anselm R Garbe - anselm@garbe.us - * Laslo Hunhold - dev@frign.de (6.1, git ports) - -Edited for dwl by - - * Daniel Mowitz - git.daniel@mowitz.rocks ---- - config.def.h | 4 + - config.def.h.orig | 116 ++ - dwl.c | 83 ++ - dwl.c.orig | 2608 +++++++++++++++++++++++++++++++++++++++++++++ - 4 files changed, 2811 insertions(+) - create mode 100644 config.def.h.orig - create mode 100644 dwl.c.orig - -diff --git a/config.def.h b/config.def.h -index 089aa379..8e20ecb1 100644 ---- a/config.def.h -+++ b/config.def.h -@@ -22,6 +22,8 @@ static const Layout layouts[] = { - { "[]=", tile }, - { "><>", NULL }, /* no layout function means floating behavior */ - { "[M]", monocle }, -+ { "TTT", bstack }, -+ { "===", bstackhoriz }, - }; - - /* monitors -@@ -82,6 +84,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, XKB_KEY_u, setlayout, {.v = &layouts[3]} }, -+ { MODKEY, XKB_KEY_o, setlayout, {.v = &layouts[4]} }, - { 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 6303c25f..3e611cb6 100644 ---- a/dwl.c -+++ b/dwl.c -@@ -301,6 +301,8 @@ static struct wlr_surface *xytolayersurface(struct wl_list *layer_surfaces, - double x, double y, double *sx, double *sy); - static Monitor *xytomon(double x, double y); - static void zoom(const Arg *arg); -+static void bstack(Monitor *m); -+static void bstackhoriz(Monitor *m); - - /* variables */ - static const char broken[] = "broken"; -@@ -2606,3 +2608,84 @@ main(int argc, char *argv[]) - usage: - BARF("Usage: %s [-s startup command]", argv[0]); - } -+ -+static void -+bstack(Monitor *m) -+{ -+ int w, h, mh, mx, tx, ty, tw; -+ unsigned int i, n = 0; -+ Client *c; -+ -+ wl_list_for_each(c, &clients, link) -+ if (VISIBLEON(c, m) && !c->isfloating) -+ n++; -+ if (n == 0) -+ return; -+ -+ if (n > m->nmaster) { -+ mh = m->nmaster ? m->mfact * m->w.height : 0; -+ tw = m->w.width / (n - m->nmaster); -+ ty = m->w.y + mh; -+ } else { -+ mh = m->w.height; -+ tw = m->w.width; -+ ty = m->w.y; -+ } -+ -+ i = mx = 0; -+ tx = m-> w.x; -+ wl_list_for_each(c, &clients, link) { -+ if (!VISIBLEON(c, m) || c->isfloating) -+ continue; -+ if (i < m->nmaster) { -+ w = (m->w.width - mx) / (MIN(n, m->nmaster) - i); -+ resize(c, m->w.x + mx, m->w.y, w - (2 * c->bw), mh - (2 * c->bw), 0); -+ mx += c->geom.width; -+ } else { -+ h = m->w.height - mh; -+ resize(c, tx, ty, tw - (2 * c->bw), h - (2 * c->bw), 0); -+ if (tw != m->w.width) -+ tx += c->geom.width; -+ } -+ i++; -+ } -+} -+ -+static void -+bstackhoriz(Monitor *m) { -+ int w, mh, mx, tx, ty, th; -+ unsigned int i, n = 0; -+ Client *c; -+ -+ wl_list_for_each(c, &clients, link) -+ if (VISIBLEON(c, m) && !c->isfloating) -+ n ++; -+ if (n == 0) -+ return; -+ -+ if (n > m->nmaster) { -+ mh = m->nmaster ? m->mfact * m->w.height : 0; -+ th = (m->w.height - mh) / (n - m->nmaster); -+ ty = m->w.y + mh; -+ } else { -+ th = mh = m->w.height; -+ ty = m->w.y; -+ } -+ -+ i = mx = 0; -+ tx = m-> w.x; -+ wl_list_for_each(c, &clients, link) { -+ if (!VISIBLEON(c,m) || c->isfloating) -+ continue; -+ if (i < m->nmaster) { -+ w = (m->w.width - mx) / (MIN(n, m->nmaster) - i); -+ resize(c, m->w.x + mx, m->w.y, w - (2 * c->bw), mh - (2 * c->bw), 0); -+ mx += c->geom.width; -+ } else { -+ resize(c, tx, ty, m->w.width - (2 * c->bw), th - (2 * c->bw), 0); -+ if (th != m->w.height) -+ ty += c->geom.height; -+ } -+ i++; -+ } -+} diff --git a/dwl/bstack.patch b/dwl/bstack.patch new file mode 100644 index 0000000..5b20051 --- /dev/null +++ b/dwl/bstack.patch @@ -0,0 +1,179 @@ +From 87898f8fbac5f917443d1d54e3c3797bf84a04d2 Mon Sep 17 00:00:00 2001 +From: wochap <gean.marroquin@gmail.com> +Date: Wed, 22 Nov 2023 19:02:09 -0500 +Subject: [PATCH 1/2] apply main...Abanoub8:bottomstack.patch + +--- + config.def.h | 4 +++ + dwl.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 88 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 4e30885b7..91f48d8bc 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -33,6 +33,8 @@ static const Layout layouts[] = { + { "[]=", tile }, + { "><>", NULL }, /* no layout function means floating behavior */ + { "[M]", monocle }, ++ { "TTT", bstack }, ++ { "===", bstackhoriz }, + }; + + /* monitors */ +@@ -132,6 +134,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, XKB_KEY_u, setlayout, {.v = &layouts[3]} }, ++ { MODKEY, XKB_KEY_o, setlayout, {.v = &layouts[4]} }, + { 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 a7d41b085..a6e9e125d 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -50,6 +50,7 @@ + #include <wlr/types/wlr_xdg_decoration_v1.h> + #include <wlr/types/wlr_xdg_output_v1.h> + #include <wlr/types/wlr_xdg_shell.h> ++#include <wlr/util/box.h> + #include <wlr/util/log.h> + #include <xkbcommon/xkbcommon.h> + #ifdef XWAYLAND +@@ -318,6 +319,8 @@ static Monitor *xytomon(double x, double y); + static void xytonode(double x, double y, struct wlr_surface **psurface, + Client **pc, LayerSurface **pl, double *nx, double *ny); + static void zoom(const Arg *arg); ++static void bstack(Monitor *m); ++static void bstackhoriz(Monitor *m); + + /* variables */ + static const char broken[] = "broken"; +@@ -2827,3 +2830,84 @@ main(int argc, char *argv[]) + usage: + die("Usage: %s [-v] [-d] [-s startup command]", argv[0]); + } ++ ++static void ++bstack(Monitor *m) ++{ ++ int w, h, mh, mx, tx, ty, tw; ++ unsigned int i, n = 0; ++ Client *c; ++ ++ wl_list_for_each(c, &clients, link) ++ if (VISIBLEON(c, m) && !c->isfloating) ++ n++; ++ if (n == 0) ++ return; ++ ++ if (n > m->nmaster) { ++ mh = m->nmaster ? m->mfact * m->w.height : 0; ++ tw = m->w.width / (n - m->nmaster); ++ ty = m->w.y + mh; ++ } else { ++ mh = m->w.height; ++ tw = m->w.width; ++ ty = m->w.y; ++ } ++ ++ i = mx = 0; ++ tx = m-> w.x; ++ wl_list_for_each(c, &clients, link) { ++ if (!VISIBLEON(c, m) || c->isfloating) ++ continue; ++ if (i < m->nmaster) { ++ w = (m->w.width - mx) / (MIN(n, m->nmaster) - i); ++ resize(c, (struct wlr_box) { .x = m->w.x + mx, .y = m->w.y, .width = w - (2 * c->bw), .height = mh - (2 * c->bw) }, 0); ++ mx += c->geom.width; ++ } else { ++ h = m->w.height - mh; ++ resize(c, (struct wlr_box) { .x = tx, .y = ty, .width = tw - (2 * c->bw), .height = h - (2 * c->bw) }, 0); ++ if (tw != m->w.width) ++ tx += c->geom.width; ++ } ++ i++; ++ } ++} ++ ++static void ++bstackhoriz(Monitor *m) { ++ int w, mh, mx, tx, ty, th; ++ unsigned int i, n = 0; ++ Client *c; ++ ++ wl_list_for_each(c, &clients, link) ++ if (VISIBLEON(c, m) && !c->isfloating) ++ n ++; ++ if (n == 0) ++ return; ++ ++ if (n > m->nmaster) { ++ mh = m->nmaster ? m->mfact * m->w.height : 0; ++ th = (m->w.height - mh) / (n - m->nmaster); ++ ty = m->w.y + mh; ++ } else { ++ th = mh = m->w.height; ++ ty = m->w.y; ++ } ++ ++ i = mx = 0; ++ tx = m-> w.x; ++ wl_list_for_each(c, &clients, link) { ++ if (!VISIBLEON(c,m) || c->isfloating) ++ continue; ++ if (i < m->nmaster) { ++ w = (m->w.width - mx) / (MIN(n, m->nmaster) - i); ++ resize(c, (struct wlr_box) { .x = m->w.x + mx, .y = m->w.y, .width = w - (2 * c->bw), .height = mh - (2 * c->bw) }, 0); ++ mx += c->geom.width; ++ } else { ++ resize(c, (struct wlr_box) { .x = tx, .y = ty, .width = m->w.width - (2 * c->bw), .height = th - (2 * c->bw) }, 0); ++ if (th != m->w.height) ++ ty += c->geom.height; ++ } ++ i++; ++ } ++} + +From 6d650c862e168fb6f9fbd78825945aeeca6f6270 Mon Sep 17 00:00:00 2001 +From: wochap <gean.marroquin@gmail.com> +Date: Wed, 22 Nov 2023 19:03:00 -0500 +Subject: [PATCH 2/2] fix main...Abanoub8:bottomstack.patch, remove gaps + +--- + dwl.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/dwl.c b/dwl.c +index a6e9e125d..638714fdc 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -2861,11 +2861,11 @@ bstack(Monitor *m) + continue; + if (i < m->nmaster) { + w = (m->w.width - mx) / (MIN(n, m->nmaster) - i); +- resize(c, (struct wlr_box) { .x = m->w.x + mx, .y = m->w.y, .width = w - (2 * c->bw), .height = mh - (2 * c->bw) }, 0); ++ resize(c, (struct wlr_box) { .x = m->w.x + mx, .y = m->w.y, .width = w, .height = mh }, 0); + mx += c->geom.width; + } else { + h = m->w.height - mh; +- resize(c, (struct wlr_box) { .x = tx, .y = ty, .width = tw - (2 * c->bw), .height = h - (2 * c->bw) }, 0); ++ resize(c, (struct wlr_box) { .x = tx, .y = ty, .width = tw, .height = h }, 0); + if (tw != m->w.width) + tx += c->geom.width; + } +@@ -2901,10 +2901,10 @@ bstackhoriz(Monitor *m) { + continue; + if (i < m->nmaster) { + w = (m->w.width - mx) / (MIN(n, m->nmaster) - i); +- resize(c, (struct wlr_box) { .x = m->w.x + mx, .y = m->w.y, .width = w - (2 * c->bw), .height = mh - (2 * c->bw) }, 0); ++ resize(c, (struct wlr_box) { .x = m->w.x + mx, .y = m->w.y, .width = w, .height = mh }, 0); + mx += c->geom.width; + } else { +- resize(c, (struct wlr_box) { .x = tx, .y = ty, .width = m->w.width - (2 * c->bw), .height = th - (2 * c->bw) }, 0); ++ resize(c, (struct wlr_box) { .x = tx, .y = ty, .width = m->w.width, .height = th }, 0); + if (th != m->w.height) + ty += c->geom.height; + } diff --git a/dwl/client.h b/dwl/client.h deleted file mode 100644 index cf1ed85..0000000 --- a/dwl/client.h +++ /dev/null @@ -1,402 +0,0 @@ -/* - * 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 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)) { - xcb_size_hints_t *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; -} - -static inline int -toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl) -{ - struct wlr_xdg_surface *xdg_surface; - struct wlr_surface *root_surface; - struct wlr_layer_surface_v1 *layer_surface; - Client *c = NULL; - LayerSurface *l = NULL; - int type = -1; -#ifdef XWAYLAND - struct wlr_xwayland_surface *xsurface; -#endif - - if (!s) - return type; - root_surface = wlr_surface_get_root_surface(s); - -#ifdef XWAYLAND - if (wlr_surface_is_xwayland_surface(root_surface) - && (xsurface = wlr_xwayland_surface_from_wlr_surface(root_surface))) { - c = xsurface->data; - type = c->type; - goto end; - } -#endif - - if (wlr_surface_is_layer_surface(root_surface) - && (layer_surface = wlr_layer_surface_v1_from_wlr_surface(root_surface))) { - l = layer_surface->data; - type = LayerShell; - goto end; - } - - if (wlr_surface_is_xdg_surface(root_surface) - && (xdg_surface = wlr_xdg_surface_from_wlr_surface(root_surface))) { - while (1) { - switch (xdg_surface->role) { - case WLR_XDG_SURFACE_ROLE_POPUP: - if (!xdg_surface->popup->parent) - return -1; - else if (!wlr_surface_is_xdg_surface(xdg_surface->popup->parent)) - return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc, pl); - - xdg_surface = wlr_xdg_surface_from_wlr_surface(xdg_surface->popup->parent); - break; - case WLR_XDG_SURFACE_ROLE_TOPLEVEL: - c = xdg_surface->data; - type = c->type; - goto end; - case WLR_XDG_SURFACE_ROLE_NONE: - return -1; - } - } - } - -end: - if (pl) - *pl = l; - if (pc) - *pc = c; - return type; -} - -/* The others */ -static inline void -client_activate_surface(struct wlr_surface *s, int activated) -{ - struct wlr_xdg_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->toplevel, activated); -} - -static inline uint32_t -client_set_bounds(Client *c, int32_t width, int32_t height) -{ -#ifdef XWAYLAND - if (client_is_x11(c)) - return 0; -#endif - if (c->surface.xdg->client->shell->version >= - XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION && width >= 0 && height >= 0) - return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height); - return 0; -} - -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 Client * -client_get_parent(Client *c) -{ - Client *p = NULL; -#ifdef XWAYLAND - if (client_is_x11(c) && c->surface.xwayland->parent) - toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL); -#endif - if (c->surface.xdg->toplevel->parent) - toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL); - - return p; -} - -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)); -} - -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_rendered_on_mon(Client *c, Monitor *m) -{ - /* This is needed for when you don't want to check formal assignment, - * but rather actual displaying of the pixels. - * Usually VISIBLEON suffices and is also faster. */ - struct wlr_surface_output *s; - if (!c->scene->node.enabled) - return 0; - wl_list_for_each(s, &client_surface(c)->current_outputs, link) - if (s->output == m->wlr_output) - return 1; - return 0; -} - -static inline int -client_is_stopped(Client *c) -{ - int pid; - siginfo_t in = {0}; -#ifdef XWAYLAND - if (client_is_x11(c)) - return 0; -#endif - - wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); - if (waitid(P_PID, pid, &in, WNOHANG|WCONTINUED|WSTOPPED|WNOWAIT) < 0) { - /* This process is not our child process, while is very unluckely that - * it is stopped, in order to do not skip frames assume that it is. */ - if (errno == ECHILD) - return 1; - } else if (in.si_pid) { - if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED) - return 1; - if (in.si_code == CLD_CONTINUED) - return 0; - } - - return 0; -} - -static inline int -client_is_unmanaged(Client *c) -{ -#ifdef XWAYLAND - 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->toplevel); -} - -static inline void -client_set_border_color(Client *c, const float color[static 4]) -{ - int i; - for (i = 0; i < 4; i++) - wlr_scene_rect_set_color(c->border[i], color); -} - -static inline void -client_set_fullscreen(Client *c, int fullscreen) -{ -#ifdef XWAYLAND - if (client_is_x11(c)) { - wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, fullscreen); - return; - } -#endif - wlr_xdg_toplevel_set_fullscreen(c->surface.xdg->toplevel, fullscreen); -} - -static inline uint32_t -client_set_size(Client *c, uint32_t width, uint32_t height) -{ -#ifdef XWAYLAND - if (client_is_x11(c)) { - wlr_xwayland_surface_configure(c->surface.xwayland, - c->geom.x, c->geom.y, width, height); - return 0; - } -#endif - if (width == c->surface.xdg->toplevel->current.width - && height ==c->surface.xdg->toplevel->current.height) - return 0; - return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, 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->toplevel, 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; -} diff --git a/dwl/config.def.h b/dwl/config.def.h deleted file mode 100644 index 91f48d8..0000000 --- a/dwl/config.def.h +++ /dev/null @@ -1,170 +0,0 @@ -/* Taken from https://github.com/djpohly/dwl/issues/466 */ -#define COLOR(hex) { ((hex >> 24) & 0xFF) / 255.0f, \ - ((hex >> 16) & 0xFF) / 255.0f, \ - ((hex >> 8) & 0xFF) / 255.0f, \ - (hex & 0xFF) / 255.0f } -/* appearance */ -static const int sloppyfocus = 1; /* focus follows mouse */ -static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */ -static const unsigned int borderpx = 1; /* border pixel of windows */ -static const float bordercolor[] = COLOR(0x444444ff); -static const float focuscolor[] = COLOR(0x005577ff); -static const float urgentcolor[] = COLOR(0xff0000ff); -/* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */ -static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; /* You can also use glsl colors */ - -/* tagging - TAGCOUNT must be no greater than 31 */ -#define TAGCOUNT (9) - -/* logging */ -static int log_level = WLR_ERROR; - -static const Rule rules[] = { - /* app_id title tags mask isfloating 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 }, - { "TTT", bstack }, - { "===", bstackhoriz }, -}; - -/* monitors */ -static const MonitorRule monrules[] = { - /* name mfact nmaster scale layout rotate/reflect x y */ - /* example of a HiDPI laptop monitor: - { "eDP-1", 0.5, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, - */ - /* defaults */ - { NULL, 0.55, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, -}; - -/* keyboard */ -static const struct xkb_rule_names xkb_rules = { - /* can specify fields: rules, model, layout, variant, options */ - /* example: - .options = "ctrl:nocaps", - */ - .options = 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; -/* You can choose between: -LIBINPUT_CONFIG_TAP_MAP_LRM -- 1/2/3 finger tap maps to left/right/middle -LIBINPUT_CONFIG_TAP_MAP_LMR -- 1/2/3 finger tap maps to left/middle/right -*/ -static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TAP_MAP_LRM; - -/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */ -#define MODKEY WLR_MODIFIER_ALT - -#define TAGKEYS(KEY,SKEY,TAG) \ - { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ - { MODKEY|WLR_MODIFIER_CTRL, KEY, toggleview, {.ui = 1 << TAG} }, \ - { MODKEY|WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG} }, \ - { MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,SKEY,toggletag, {.ui = 1 << TAG} } - -/* helper for spawning shell commands in the pre dwm-5.0 fashion */ -#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } - -/* commands */ -static const char *termcmd[] = { "foot", NULL }; -static const char *menucmd[] = { "bemenu-run", NULL }; - -static const 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, 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_u, setlayout, {.v = &layouts[3]} }, - { MODKEY, XKB_KEY_o, setlayout, {.v = &layouts[4]} }, - { 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/dwl/config.h b/dwl/config.h index 0b5e03f..5c2acf9 100644 --- a/dwl/config.h +++ b/dwl/config.h @@ -23,8 +23,9 @@ static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; static const Rule rules[] = { /* app_id title tags mask isfloating monitor keep_focus */ - { "firefox", "DWL_EMPTY_TITLE", 0, 1, -1, 0 }, - { "firefox", "Firefox — Sharing Indicator", 0, 1, -1, 0 } +// { "firefox", "DWL_EMPTY_TITLE", 0, 1, -1 }, +// { "firefox", "Firefox — Sharing Indicator", 0, 1, -1 } + { NULL, NULL, 0, 0, -1 } }; /* layout(s) */ diff --git a/dwl/config.mk b/dwl/config.mk deleted file mode 100644 index 4bc9b9d..0000000 --- a/dwl/config.mk +++ /dev/null @@ -1,15 +0,0 @@ -_VERSION = 0.4 -VERSION = `git describe --tags --dirty 2>/dev/null || echo $(_VERSION)` - -PKG_CONFIG = pkg-config - -# paths -PREFIX = /usr/local -MANDIR = $(PREFIX)/share/man -DATADIR = $(PREFIX)/share - -XWAYLAND = -XLIBS = -# Uncomment to build XWayland support -#XWAYLAND = -DXWAYLAND -#XLIBS = xcb xcb-icccm diff --git a/dwl/dwl.1 b/dwl/dwl.1 deleted file mode 100644 index ce1acf9..0000000 --- a/dwl/dwl.1 +++ /dev/null @@ -1,158 +0,0 @@ -.Dd January 8, 2021 -.Dt DWL 1 -.Os -.Sh NAME -.Nm dwl -.Nd dwm for Wayland -.Sh SYNOPSIS -.Nm -.Op Fl v -.Op Fl d -.Op Fl s Ar startup command -.Sh DESCRIPTION -.Nm -is a Wayland compositor based on wlroots. -It is intended to fill the same space in the Wayland world that -.Nm dwm -does for X11. -.Pp -When given the -.Fl v -option, -.Nm -writes its name and version to standard error and exits unsuccessfully. -.Pp -When given the -.Fl d -option, -.Nm -enables full wlroots logging, including debug information. -.Pp -When given the -.Fl s -option, -.Nm -starts a shell process running -.Ar command -when starting. -When stopping, it sends -.Dv SIGTERM -to the child process and waits for it to exit. -.Pp -Users are encouraged to customize -.Nm -by editing the sources, in particular -.Pa config.h . -The default key bindings are as follows: -.Bl -tag -width 20n -offset indent -compact -.It Mod-[1-9] -Show only all windows with a tag. -.It Mod-Ctrl-[1-9] -Show all windows with a tag. -.It Mod-Shift-[1-9] -Move window to a single tag. -.It Mod-Ctrl-Shift-[1-9] -Toggle tag for window. -.It Mod-p -Spawn -.Nm bemenu-run . -.It Mod-Shift-Return -Spawn -.Nm foot . -.It Mod-[jk] -Move focus down/up the stack. -.It Mod-[id] -Increase/decrease number of windows in master area. -.It Mod-[hl] -Decrease/increase master area. -.It Mod-Return -Move window on top of stack or switch top of stack with second window. -.It Mod-Tab -Show only all windows with previous tag. -.It Mod-Shift-c -Close window. -.It Mod-t -Switch to tabbed layout. -.It Mod-f -Switch to floating layout. -.It Mod-m -Switch to monocle layout. -.It Mod-Space -Switch to previous layout. -.It Mod-Shift-Space -Toggle floating state of window. -.It Mod-e -Toggle fullscreen state of window. -.It Mod-0 -Show all windows. -.It Mod-Shift-0 -Set all tags for window. -.It Mod-, -Move focus to previous monitor. -.It Mod-. -Move focus to next monitor. -.It Mod-Shift-, -Move window to previous monitor. -.It Mod-Shift-. -Move window to next monitor. -.It Mod-Shift-q -Quit -.Nm . -.El -These might differ depending on your keyboard layout. -.Sh ENVIRONMENT -These environment variables are used by -.Nm : -.Bl -tag -width XDG_RUNTIME_DIR -.It Ev XDG_RUNTIME_DIR -A directory where temporary user files, such as the Wayland socket, -are stored. -.It Ev XDG_CONFIG_DIR -A directory containing configuration of various programs and -libraries, including libxkbcommon. -.It Ev DISPLAY , WAYLAND_DISPLAY , WAYLAND_SOCKET -Tell how to connect to an underlying X11 or Wayland server. -.It Ev WLR_* -Various variables specific to wlroots. -.It Ev XKB_* , XLOCALEDIR , XCOMPOSEFILE -Various variables specific to libxkbcommon. -.It Ev XCURSOR_PATH -List of directories to search for XCursor themes in. -.It Ev HOME -A directory where there are always dear files there for you. -Waiting for you to clean them up. -.El -.Pp -These are set by -.Nm : -.Bl -tag -width WAYLAND_DISPLAY -.It Ev WAYLAND_DISPLAY -Tell how to connect to -.Nm . -.It Ev DISPLAY -If using -.Nm Xwayland , -tell how to connect to the -.Nm Xwayland -server. -.El -.Sh EXAMPLES -Start -.Nm -with s6 in the background: -.Dl dwl -s 's6-svscan <&-' -.Sh SEE ALSO -.Xr foot 1 , -.Xr bemenu 1 , -.Xr dwm 1 , -.Xr xkeyboard-config 7 -.Sh CAVEATS -The child process's standard input is connected with a pipe to -.Nm . -If the child process neither reads from the pipe nor closes its -standard input, -.Nm -will freeze after a while due to it blocking when writing to the full -pipe buffer. -.Sh BUGS -All of them. diff --git a/dwl/dwl.c b/dwl/dwl.c deleted file mode 100644 index 29b3c62..0000000 --- a/dwl/dwl.c +++ /dev/null @@ -1,2993 +0,0 @@ -/* - * See LICENSE file for copyright and license details. - */ -#include <getopt.h> -#include <libinput.h> -#include <limits.h> -#include <linux/input-event-codes.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/wait.h> -#include <time.h> -#include <unistd.h> -#include <wayland-server-core.h> -#include <wayland-util.h> -#include <wlr/backend.h> -#include <wlr/backend/libinput.h> -#include <wlr/render/allocator.h> -#include <wlr/render/wlr_renderer.h> -#include <wlr/types/wlr_compositor.h> -#include <wlr/types/wlr_cursor.h> -#include <wlr/types/wlr_data_control_v1.h> -#include <wlr/types/wlr_data_device.h> -#include <wlr/types/wlr_export_dmabuf_v1.h> -#include <wlr/types/wlr_gamma_control_v1.h> -#include <wlr/types/wlr_idle.h> -#include <wlr/types/wlr_idle_inhibit_v1.h> -#include <wlr/types/wlr_idle_notify_v1.h> -#include <wlr/types/wlr_input_device.h> -#include <wlr/types/wlr_input_inhibitor.h> -#include <wlr/types/wlr_keyboard.h> -#include <wlr/types/wlr_layer_shell_v1.h> -#include <wlr/types/wlr_output.h> -#include <wlr/types/wlr_output_layout.h> -#include <wlr/types/wlr_output_management_v1.h> -#include <wlr/types/wlr_pointer.h> -#include <wlr/types/wlr_presentation_time.h> -#include <wlr/types/wlr_primary_selection.h> -#include <wlr/types/wlr_primary_selection_v1.h> -#include <wlr/types/wlr_scene.h> -#include <wlr/types/wlr_screencopy_v1.h> -#include <wlr/types/wlr_seat.h> -#include <wlr/types/wlr_server_decoration.h> -#include <wlr/types/wlr_session_lock_v1.h> -#include <wlr/types/wlr_single_pixel_buffer_v1.h> -#include <wlr/types/wlr_subcompositor.h> -#include <wlr/types/wlr_viewporter.h> -#include <wlr/types/wlr_virtual_keyboard_v1.h> -#include <wlr/types/wlr_xcursor_manager.h> -#include <wlr/types/wlr_xdg_activation_v1.h> -#include <wlr/types/wlr_xdg_decoration_v1.h> -#include <wlr/types/wlr_xdg_output_v1.h> -#include <wlr/types/wlr_xdg_shell.h> -#include <wlr/util/log.h> -#include <xkbcommon/xkbcommon.h> -#ifdef XWAYLAND -#include <wlr/xwayland.h> -#include <xcb/xcb.h> -#include <xcb/xcb_icccm.h> -#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)) -#define LENGTH(X) (sizeof X / sizeof X[0]) -#define END(A) ((A) + LENGTH(A)) -#define TAGMASK ((1u << TAGCOUNT) - 1) -#define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) -#define IDLE_NOTIFY_ACTIVITY wlr_idle_notify_activity(idle, seat), wlr_idle_notifier_v1_notify_activity(idle_notifier, seat) - -/* enums */ -enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ -enum { XDGShell, LayerShell, X11Managed, X11Unmanaged }; /* client types */ -enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrFS, LyrTop, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */ -#ifdef XWAYLAND -enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar, - NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */ -#endif - -typedef union { - int i; - uint32_t ui; - float f; - const void *v; -} Arg; - -typedef struct { - unsigned int mod; - unsigned int button; - void (*func)(const Arg *); - const Arg arg; -} Button; - -typedef struct Pertag Pertag; -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_tree *scene; - struct wlr_scene_rect *border[4]; /* top, bottom, left, right */ - struct wlr_scene_tree *scene_surface; - struct wl_list link; - struct wl_list flink; - union { - struct wlr_xdg_surface *xdg; - struct wlr_xwayland_surface *xwayland; - } surface; - struct wl_listener commit; - struct wl_listener map; - struct wl_listener maximize; - struct wl_listener unmap; - struct wl_listener destroy; - struct wl_listener set_title; - struct wl_listener fullscreen; - struct 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; - uint32_t tags; - int isfloating, isurgent, isfullscreen; - uint32_t resize; /* configure serial of a pending resize */ -} Client; - -typedef struct { - uint32_t mod; - xkb_keysym_t keysym; - void (*func)(const Arg *); - const Arg arg; -} Key; - -typedef struct { - struct wl_list link; - struct wlr_keyboard *wlr_keyboard; - int nsyms; - const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */ - uint32_t mods; /* invalid if nsyms == 0 */ - struct wl_event_source *key_repeat_source; - - struct wl_listener modifiers; - struct wl_listener key; - 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_tree *scene; - struct wlr_scene_tree *popups; - struct wlr_scene_layer_surface_v1 *scene_layer; - struct wl_list link; - int mapped; - struct wlr_layer_surface_v1 *layer_surface; - - struct wl_listener destroy; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener surface_commit; -} LayerSurface; - -typedef struct { - const char *symbol; - void (*arrange)(Monitor *); -} Layout; - -struct Monitor { - struct wl_list link; - struct wlr_output *wlr_output; - struct wlr_scene_output *scene_output; - struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */ - struct wl_listener frame; - struct wl_listener destroy; - struct wl_listener destroy_lock_surface; - struct wlr_session_lock_surface_v1 *lock_surface; - struct wlr_box m; /* monitor area, layout-relative */ - struct wlr_box w; /* window area, layout-relative */ - struct wl_list layers[4]; /* LayerSurface::link */ - const Layout *lt; - unsigned int curtag, prevtag; /* current and previous tag */ - Pertag *pertag; - unsigned int sellt; - uint32_t tagset; - double mfact; - int nmaster; - char ltsymbol[16]; -}; - -typedef struct { - const char *name; - float mfact; - int nmaster; - float scale; - const Layout *lt; - enum wl_output_transform rr; - int x, y; -} MonitorRule; - -typedef struct { - const char *id; - const char *title; - uint32_t tags; - int isfloating; - int monitor; - int focus_client; -} Rule; - -typedef struct { - struct wlr_scene_tree *scene; - - struct wlr_session_lock_v1 *lock; - struct wl_listener new_surface; - struct wl_listener unlock; - struct wl_listener destroy; -} SessionLock; - -/* function declarations */ -static void applybounds(Client *c, struct wlr_box *bbox); -static void applyrules(Client *c); -static void arrange(Monitor *m); -static void arrangelayer(Monitor *m, struct wl_list *list, - struct wlr_box *usable_area, int exclusive); -static void arrangelayers(Monitor *m); -static void axisnotify(struct wl_listener *listener, void *data); -static void buttonpress(struct wl_listener *listener, void *data); -static void 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 createdecoration(struct wl_listener *listener, void *data); -static void createidleinhibitor(struct wl_listener *listener, void *data); -static void createkeyboard(struct wlr_keyboard *keyboard); -static void createlayersurface(struct wl_listener *listener, void *data); -static void createlocksurface(struct wl_listener *listener, void *data); -static void createmon(struct wl_listener *listener, void *data); -static void createnotify(struct wl_listener *listener, void *data); -static void createpointer(struct wlr_pointer *pointer); -static void cursorframe(struct wl_listener *listener, void *data); -static void destroydragicon(struct wl_listener *listener, void *data); -static void destroyidleinhibitor(struct wl_listener *listener, void *data); -static void destroylayersurfacenotify(struct wl_listener *listener, void *data); -static void destroylock(SessionLock *lock, int unlocked); -static void destroylocksurface(struct wl_listener *listener, void *data); -static void destroynotify(struct wl_listener *listener, void *data); -static void destroysessionlock(struct wl_listener *listener, void *data); -static void destroysessionmgr(struct wl_listener *listener, void *data); -static Monitor *dirtomon(enum wlr_direction dir); -static void focusclient(Client *c, int lift); -static void focusmon(const Arg *arg); -static void focusstack(const Arg *arg); -static Client *focustop(Monitor *m); -static void fullscreennotify(struct wl_listener *listener, void *data); -static void handlesig(int signo); -static void incnmaster(const Arg *arg); -static void inputdevice(struct wl_listener *listener, void *data); -static int keybinding(uint32_t mods, xkb_keysym_t sym); -static void keypress(struct wl_listener *listener, void *data); -static void keypressmod(struct wl_listener *listener, void *data); -static int keyrepeat(void *data); -static void killclient(const Arg *arg); -static void locksession(struct wl_listener *listener, void *data); -static void maplayersurfacenotify(struct wl_listener *listener, void *data); -static void mapnotify(struct wl_listener *listener, void *data); -static void maximizenotify(struct wl_listener *listener, void *data); -static void monocle(Monitor *m); -static void 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 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 void setcursor(struct wl_listener *listener, void *data); -static void setfloating(Client *c, int floating); -static void setfullscreen(Client *c, int fullscreen); -static void setlayout(const Arg *arg); -static void setmfact(const Arg *arg); -static void setmon(Client *c, Monitor *m, uint32_t newtags); -static void setpsel(struct wl_listener *listener, void *data); -static void setsel(struct wl_listener *listener, void *data); -static void setup(void); -static void spawn(const Arg *arg); -static void startdrag(struct wl_listener *listener, void *data); -static void tag(const Arg *arg); -static void tagmon(const Arg *arg); -static void tile(Monitor *m); -static void togglefloating(const Arg *arg); -static void togglefullscreen(const Arg *arg); -static void toggletag(const Arg *arg); -static void toggleview(const Arg *arg); -static void unlocksession(struct wl_listener *listener, void *data); -static void unmaplayersurfacenotify(struct wl_listener *listener, void *data); -static void unmapnotify(struct wl_listener *listener, void *data); -static void updatemons(struct wl_listener *listener, void *data); -static void updatetitle(struct wl_listener *listener, void *data); -static void urgent(struct wl_listener *listener, void *data); -static void view(const Arg *arg); -static void virtualkeyboard(struct wl_listener *listener, void *data); -static Monitor *xytomon(double x, double y); -static void xytonode(double x, double y, struct wlr_surface **psurface, - Client **pc, LayerSurface **pl, double *nx, double *ny); -static void zoom(const Arg *arg); -static void bstack(Monitor *m); -static void bstackhoriz(Monitor *m); - -/* variables */ -static const char broken[] = "broken"; -static const char *cursor_image = "left_ptr"; -static pid_t child_pid = -1; -static int locked; -static void *exclusive_focus; -static struct wl_display *dpy; -static struct wlr_backend *backend; -static struct wlr_scene *scene; -static struct wlr_scene_tree *layers[NUM_LAYERS]; -static struct wlr_scene_tree *drag_icon; -/* Map from ZWLR_LAYER_SHELL_* constants to Lyr* enum */ -static const int layermap[] = { LyrBg, LyrBottom, LyrTop, LyrOverlay }; -static struct wlr_renderer *drw; -static struct wlr_allocator *alloc; -static struct wlr_compositor *compositor; - -static struct wlr_xdg_shell *xdg_shell; -static struct wlr_xdg_activation_v1 *activation; -static struct wlr_xdg_decoration_manager_v1 *xdg_decoration_mgr; -static struct wl_list clients; /* tiling order */ -static struct wl_list fstack; /* focus order */ -static struct wlr_idle *idle; -static struct wlr_idle_notifier_v1 *idle_notifier; -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_session_lock_manager_v1 *session_lock_mgr; -static struct wlr_scene_rect *locked_bg; -static struct wlr_session_lock_v1 *cur_lock; - -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; - -/* 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_xdg_decoration = {.notify = createdecoration}; -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}; -static struct wl_listener session_lock_create_lock = {.notify = locksession}; -static struct wl_listener session_lock_mgr_destroy = {.notify = destroysessionmgr}; - -#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 xcb_atom_t getatom(xcb_connection_t *xc, const char *name); -static void sethints(struct wl_listener *listener, void *data); -static void xwaylandready(struct wl_listener *listener, void *data); -static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11}; -static struct wl_listener xwayland_ready = {.notify = xwaylandready}; -static struct wlr_xwayland *xwayland; -static xcb_atom_t netatom[NetLast]; -#endif - -/* configuration, allows nested code to access above variables */ -#include "config.h" - -/* attempt to encapsulate suck into one file */ -#include "client.h" - -struct Pertag { - int nmasters[TAGCOUNT + 1]; /* number of windows in master area */ - float mfacts[TAGCOUNT + 1]; /* mfacts per tag */ - unsigned int sellts[TAGCOUNT + 1]; /* selected layouts */ - const Layout *ltidxs[TAGCOUNT + 1]; /* matrix of tags and layouts indexes */ -}; - -/* compile-time check if all tags fit into an unsigned int bit array. */ -struct NumTags { - char limitexceeded[TAGCOUNT > 31 ? -1 : 1]; -}; - -/* 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 their max size to INT_MAX, which does not violate the - * protocol but it's unnecesary, as they can set their 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 -applyrules(Client *c) -{ - /* rule matching */ - const char *appid, *title; - uint32_t i, newtags = 0; - const Rule *r; - Monitor *mon = selmon, *m; - bool fix_focus_at_end = false; - - c->isfloating = client_is_float_type(c); - if (!(appid = client_get_appid(c))) - appid = broken; - if (!(title = client_get_title(c))) - title = broken; - - if (strnlen(title, 1) == 0) title = "DWL_EMPTY_TITLE"; - - for (r = rules; r < END(rules); r++) { - if ((!r->title || strstr(title, r->title)) - && (!r->id || strstr(appid, r->id))) { - c->isfloating = r->isfloating; - fix_focus_at_end |= (r->focus_client == 0); - newtags |= r->tags; - i = 0; - wl_list_for_each(m, &mons, link) - if (r->monitor == i++) - mon = m; - } - } - wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrFloat : LyrTile]); - setmon(c, mon, newtags); - if (fix_focus_at_end) { - Client *old; - wl_list_for_each(old, &fstack, flink) { - if (old!=c) { - focusclient(old, 0); - return; - }; - } - } -} - -void -arrange(Monitor *m) -{ - Client *c; - wl_list_for_each(c, &clients, link) - if (c->mon == m) - wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m)); - - wlr_scene_node_set_enabled(&m->fullscreen_bg->node, - (c = focustop(m)) && c->isfullscreen); - - strncpy(m->ltsymbol, m->lt->symbol, LENGTH(m->ltsymbol)); - - if (m->lt->arrange) - m->lt->arrange(m); - motionnotify(0); - checkidleinhibitor(NULL); -} - -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; - - if (exclusive != (state->exclusive_zone > 0)) - continue; - - wlr_scene_layer_surface_v1_configure(layersurface->scene_layer, &full_area, usable_area); - wlr_scene_node_set_position(&layersurface->popups->node, - layersurface->scene->node.x, layersurface->scene->node.y); - layersurface->geom.x = layersurface->scene->node.x; - layersurface->geom.y = layersurface->scene->node.y; - } -} - -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 (!locked && 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_pointer_axis_event *event = data; - IDLE_NOTIFY_ACTIVITY; - /* TODO: allow usage of scroll whell for mousebindings, it can be implemented - * checking the event's orientation and the delta of the event */ - /* Notify the client with pointer focus of the axis event. */ - wlr_seat_pointer_notify_axis(seat, - event->time_msec, event->orientation, event->delta, - event->delta_discrete, event->source); -} - -void -buttonpress(struct wl_listener *listener, void *data) -{ - struct wlr_pointer_button_event *event = data; - struct wlr_keyboard *keyboard; - uint32_t mods; - Client *c; - const Button *b; - - IDLE_NOTIFY_ACTIVITY; - - switch (event->state) { - case WLR_BUTTON_PRESSED: - cursor_mode = CurPressed; - if (locked) - break; - - /* Change focus if the button was _pressed_ over a client */ - xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL); - if (c && (!client_is_unmanaged(c) || client_wants_focus(c))) - focusclient(c, 1); - - keyboard = wlr_seat_get_keyboard(seat); - mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; - for (b = buttons; b < END(buttons); b++) { - if (CLEANMASK(mods) == CLEANMASK(b->mod) && - event->button == b->button && b->func) { - b->func(&b->arg); - return; - } - } - break; - case WLR_BUTTON_RELEASED: - /* If you released any buttons, we exit interactive move/resize mode. */ - if (!locked && 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, unused_lx, unused_ly; - struct wlr_idle_inhibitor_v1 *inhibitor; - wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { - struct wlr_surface *surface = wlr_surface_get_root_surface(inhibitor->surface); - struct wlr_scene_tree *tree = surface->data; - if (exclude != surface && (bypass_surface_visibility || (!tree - || wlr_scene_node_coords(&tree->node, &unused_lx, &unused_ly)))) { - inhibited = 1; - break; - } - } - - wlr_idle_set_enabled(idle, NULL, !inhibited); - wlr_idle_notifier_v1_set_inhibited(idle_notifier, 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_scene_node_destroy(&scene->tree.node); - 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_event_source_remove(kb->key_repeat_source); - 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_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); - wlr_scene_node_destroy(&m->fullscreen_bg->node); - - 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; - struct wlr_scene_tree *layer = layers[layermap[wlr_layer_surface->current.layer]]; - - /* 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 (layer != layersurface->scene->node.parent) { - wlr_scene_node_reparent(&layersurface->scene->node, layer); - wlr_scene_node_reparent(&layersurface->popups->node, 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->node, 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); - - /* mark a pending resize as completed */ - if (c->resize && c->resize <= c->surface.xdg->current.configure_serial) - c->resize = 0; -} - -void -createdecoration(struct wl_listener *listener, void *data) -{ - struct wlr_xdg_toplevel_decoration_v1 *dec = data; - wlr_xdg_toplevel_decoration_v1_set_mode(dec, WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); -} - -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_keyboard *keyboard) -{ - struct xkb_context *context; - struct xkb_keymap *keymap; - Keyboard *kb = keyboard->data = ecalloc(1, sizeof(*kb)); - kb->wlr_keyboard = keyboard; - - /* 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(keyboard, keymap); - xkb_keymap_unref(keymap); - xkb_context_unref(context); - wlr_keyboard_set_repeat_info(keyboard, repeat_rate, repeat_delay); - - /* Here we set up listeners for keyboard events. */ - LISTEN(&keyboard->events.modifiers, &kb->modifiers, keypressmod); - LISTEN(&keyboard->events.key, &kb->key, keypress); - LISTEN(&keyboard->base.events.destroy, &kb->destroy, cleanupkeyboard); - - wlr_seat_set_keyboard(seat, keyboard); - - kb->key_repeat_source = wl_event_loop_add_timer( - wl_display_get_event_loop(dpy), keyrepeat, kb); - - /* 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; - struct wlr_scene_tree *l = layers[layermap[wlr_layer_surface->pending.layer]]; - - 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); - return; - } - - 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_layer = wlr_scene_layer_surface_v1_create(l, wlr_layer_surface); - layersurface->scene = layersurface->scene_layer->tree; - layersurface->popups = wlr_layer_surface->surface->data = wlr_scene_tree_create(l); - - layersurface->scene->node.data = layersurface; - - 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 -createlocksurface(struct wl_listener *listener, void *data) -{ - SessionLock *lock = wl_container_of(listener, lock, new_surface); - struct wlr_session_lock_surface_v1 *lock_surface = data; - Monitor *m = lock_surface->output->data; - struct wlr_scene_tree *scene_tree = lock_surface->surface->data = - wlr_scene_subsurface_tree_create(lock->scene, lock_surface->surface); - m->lock_surface = lock_surface; - - wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y); - wlr_session_lock_surface_v1_configure(lock_surface, m->m.width, m->m.height); - - LISTEN(&lock_surface->events.destroy, &m->destroy_lock_surface, destroylocksurface); - - if (m == selmon) - client_notify_enter(lock_surface->surface, wlr_seat_get_keyboard(seat)); -} - -void -createmon(struct wl_listener *listener, void *data) -{ - /* This event is raised by the backend when a new output (aka a display or - * monitor) becomes available. */ - struct wlr_output *wlr_output = data; - const MonitorRule *r; - size_t i; - 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->tagset = 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 = r->lt; - wlr_output_set_transform(wlr_output, r->rr); - m->m.x = r->x; - m->m.y = r->y; - 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)); - - /* 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; - - /* Try to enable adaptive sync, note that not all monitors support it. - * wlr_output_commit() will deactivate it in case it cannot be enabled */ - wlr_output_enable_adaptive_sync(wlr_output, 1); - wlr_output_commit(wlr_output); - - wl_list_insert(&mons, &m->link); - printstatus(); - - /* The xdg-protocol specifies: - * - * If the fullscreened surface is not opaque, the compositor must make - * sure that other screen content not part of the same surface tree (made - * up of subsurfaces, popups or similarly coupled surfaces) are not - * visible below the fullscreened surface. - * - */ - /* updatemons() will resize and set correct position */ - m->fullscreen_bg = wlr_scene_rect_create(layers[LyrFS], 0, 0, fullscreen_bg); - wlr_scene_node_set_enabled(&m->fullscreen_bg->node, 0); - - m->pertag = calloc(1, sizeof(Pertag)); - m->curtag = m->prevtag = 1; - - for (i = 0; i <= TAGCOUNT; i++) { - m->pertag->nmasters[i] = m->nmaster; - m->pertag->mfacts[i] = m->mfact; - - m->pertag->ltidxs[i] = m->lt; - m->pertag->sellts[i] = m->sellt; - } - - /* Adds this to the output layout in the order it was configured in. - * - * The output layout utility automatically adds a wl_output global to the - * display, which Wayland clients can see to find out information about the - * output (such as DPI, scale factor, manufacturer, etc). - */ - m->scene_output = wlr_scene_output_create(scene, wlr_output); - if (m->m.x < 0 || m->m.y < 0) - wlr_output_layout_add_auto(output_layout, wlr_output); - else - wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y); - strncpy(m->ltsymbol, m->lt->symbol, LENGTH(m->ltsymbol)); -} - -void -createnotify(struct wl_listener *listener, void *data) -{ - /* This event is raised when wlr_xdg_shell receives a new xdg surface from a - * client, either a toplevel (application window) or popup, - * or when wlr_layer_shell receives a new popup from a layer. - * If you want to do something tricky with popups you should check if - * its parent is wlr_xdg_shell or wlr_layer_shell */ - struct wlr_xdg_surface *xdg_surface = data; - Client *c = NULL; - LayerSurface *l = NULL; - - if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { - struct wlr_box box; - int type = toplevel_from_wlr_surface(xdg_surface->surface, &c, &l); - if (!xdg_surface->popup->parent || type < 0) - return; - xdg_surface->surface->data = wlr_scene_xdg_surface_create( - xdg_surface->popup->parent->data, xdg_surface); - if ((l && !l->mon) || (c && !c->mon)) - return; - box = type == LayerShell ? l->mon->m : c->mon->w; - box.x -= (type == LayerShell ? l->geom.x : c->geom.x); - box.y -= (type == LayerShell ? l->geom.y : c->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); - LISTEN(&xdg_surface->toplevel->events.request_maximize, &c->maximize, - maximizenotify); -} - -void -createpointer(struct wlr_pointer *pointer) -{ - if (wlr_input_device_is_libinput(&pointer->base)) { - struct libinput_device *libinput_device = (struct libinput_device*) - wlr_libinput_get_device_handle(&pointer->base); - - 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); - libinput_device_config_tap_set_button_map(libinput_device, button_map); - } - - 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_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, &pointer->base); -} - -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 -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(focustop(selmon), 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(wlr_surface_get_root_surface(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->node); - free(layersurface); -} - -void -destroylock(SessionLock *lock, int unlock) -{ - wlr_seat_keyboard_notify_clear_focus(seat); - if ((locked = !unlock)) - goto destroy; - - wlr_scene_node_set_enabled(&locked_bg->node, 0); - - focusclient(focustop(selmon), 0); - motionnotify(0); - -destroy: - wl_list_remove(&lock->new_surface.link); - wl_list_remove(&lock->unlock.link); - wl_list_remove(&lock->destroy.link); - - wlr_scene_node_destroy(&lock->scene->node); - cur_lock = NULL; - free(lock); -} - -void -destroylocksurface(struct wl_listener *listener, void *data) -{ - Monitor *m = wl_container_of(listener, m, destroy_lock_surface); - struct wlr_session_lock_surface_v1 *surface, *lock_surface = m->lock_surface; - - m->lock_surface = NULL; - wl_list_remove(&m->destroy_lock_surface.link); - - if (lock_surface->surface != seat->keyboard_state.focused_surface) - return; - - if (locked && cur_lock && !wl_list_empty(&cur_lock->surfaces)) { - surface = wl_container_of(cur_lock->surfaces.next, surface, link); - client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat)); - } else if (!locked) { - focusclient(focustop(selmon), 1); - } else { - wlr_seat_keyboard_clear_focus(seat); - } -} - -void -destroynotify(struct wl_listener *listener, void *data) -{ - /* Called when the 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); -} - -void -destroysessionlock(struct wl_listener *listener, void *data) -{ - SessionLock *lock = wl_container_of(listener, lock, destroy); - destroylock(lock, 0); -} - -void -destroysessionmgr(struct wl_listener *listener, void *data) -{ - wl_list_remove(&session_lock_create_lock.link); - wl_list_remove(&session_lock_mgr_destroy.link); -} - -Monitor * -dirtomon(enum wlr_direction dir) -{ - struct wlr_output *next; - if (!wlr_output_layout_get(output_layout, selmon->wlr_output)) - return selmon; - if ((next = wlr_output_layout_adjacent_output(output_layout, - dir, selmon->wlr_output, selmon->m.x, selmon->m.y))) - return next->data; - if ((next = wlr_output_layout_farthest_output(output_layout, - dir ^ (WLR_DIRECTION_LEFT|WLR_DIRECTION_RIGHT), - selmon->wlr_output, selmon->m.x, selmon->m.y))) - return next->data; - return selmon; -} - -void -focusclient(Client *c, int lift) -{ - struct wlr_surface *old = seat->keyboard_state.focused_surface; - int unused_lx, unused_ly, old_client_type; - Client *old_c = NULL; - LayerSurface *old_l = NULL; - - if (locked) - return; - - /* Raise client in stacking order if requested */ - if (c && lift) - wlr_scene_node_raise_to_top(&c->scene->node); - - if (c && client_surface(c) == old) - return; - - if ((old_client_type = toplevel_from_wlr_surface(old, &old_c, &old_l)) == XDGShell) { - struct wlr_xdg_popup *popup, *tmp; - wl_list_for_each_safe(popup, tmp, &old_c->surface.xdg->popups, link) - wlr_xdg_popup_destroy(popup); - } - - /* Put the new client atop the focus stack and select its monitor */ - if (c && !client_is_unmanaged(c)) { - wl_list_remove(&c->flink); - wl_list_insert(&fstack, &c->flink); - selmon = c->mon; - c->isurgent = 0; - client_restack_surface(c); - /* Don't change border color if there is an exclusive focus or we are - * handling a drag operation */ - if (!exclusive_focus && !seat->drag) - client_set_border_color(c, focuscolor); - } - - /* Deactivate old client if focus is changing */ - if (old && (!c || client_surface(c) != old)) { - /* If an overlay is focused, don't focus or activate the client, - * but only update its position in fstack to render its border with focuscolor - * and focus it after the overlay is closed. */ - if (old_client_type == LayerShell && wlr_scene_node_coords( - &old_l->scene->node, &unused_lx, &unused_ly) - && old_l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) { - return; - } else if (old_c && old_c == exclusive_focus && client_wants_focus(old_c)) { - return; - /* Don't deactivate old client if the new one wants focus, as this causes issues with winecfg - * and probably other clients */ - } else if (old_c && !client_is_unmanaged(old_c) && (!c || !client_wants_focus(c))) { - client_set_border_color(old_c, bordercolor); - } - } - printstatus(); - - if (!c) { - /* With no client, all we have left is to clear focus */ - wlr_seat_keyboard_notify_clear_focus(seat); - return; - } - - /* Change cursor surface */ - motionnotify(0); - - /* Have a client, so focus its top-level wlr_surface */ - client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat)); - - /* Activate the new client */ - client_activate_surface(client_surface(c), 1); -} - -void -focusmon(const Arg *arg) -{ - int i = 0, nmons = wl_list_length(&mons); - if (nmons) - do /* don't switch to disabled mons */ - selmon = dirtomon(arg->i); - while (!selmon->wlr_output->enabled && i++ < nmons); - focusclient(focustop(selmon), 1); -} - -void -focusstack(const Arg *arg) -{ - /* Focus the next or previous client (in tiling order) on selmon */ - Client *c, *sel = focustop(selmon); - if (!sel || sel->isfullscreen) - return; - if (arg->i > 0) { - wl_list_for_each(c, &sel->link, link) { - if (&c->link == &clients) - continue; /* wrap past the sentinel node */ - if (VISIBLEON(c, selmon)) - break; /* found it */ - } - } else { - wl_list_for_each_reverse(c, &sel->link, link) { - if (&c->link == &clients) - continue; /* wrap past the sentinel node */ - if (VISIBLEON(c, selmon)) - break; /* found it */ - } - } - /* If only one client is visible on selmon, then c == sel */ - focusclient(c, 1); -} - -/* We probably should change the name of this, it sounds like - * will focus the topmost client of this mon, when actually will - * only return that client */ -Client * -focustop(Monitor *m) -{ - Client *c; - wl_list_for_each(c, &fstack, flink) - if (VISIBLEON(c, m)) - return c; - return NULL; -} - -void -fullscreennotify(struct wl_listener *listener, void *data) -{ - Client *c = wl_container_of(listener, c, fullscreen); - setfullscreen(c, client_wants_fullscreen(c)); -} - -void -handlesig(int signo) -{ - if (signo == SIGCHLD) { -#ifdef XWAYLAND - siginfo_t in; - /* wlroots expects to reap the XWayland process itself, so we - * use WNOWAIT to keep the child waitable until we know it's not - * XWayland. - */ - while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid - && (!xwayland || in.si_pid != xwayland->server->pid)) - waitpid(in.si_pid, NULL, 0); -#else - while (waitpid(-1, NULL, WNOHANG) > 0); -#endif - } else if (signo == SIGINT || signo == SIGTERM) { - quit(NULL); - } -} - -void -incnmaster(const Arg *arg) -{ - if (!arg || !selmon) - return; - selmon->nmaster = selmon->pertag->nmasters[selmon->curtag] = MAX(selmon->nmaster + arg->i, 0); - arrange(selmon); -} - -void -inputdevice(struct wl_listener *listener, void *data) -{ - /* This event is raised by the backend when a new input device becomes - * available. */ - struct wlr_input_device *device = data; - uint32_t caps; - - switch (device->type) { - case WLR_INPUT_DEVICE_KEYBOARD: - createkeyboard(wlr_keyboard_from_input_device(device)); - break; - case WLR_INPUT_DEVICE_POINTER: - createpointer(wlr_pointer_from_input_device(device)); - break; - default: - /* TODO handle other input device types */ - break; - } - - /* We need to let the wlr_seat know what our capabilities are, which is - * communiciated to the client. In dwl we always have a cursor, even if - * there are no pointer devices, so we always include that capability. */ - /* TODO do we actually require a cursor? */ - caps = WL_SEAT_CAPABILITY_POINTER; - if (!wl_list_empty(&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_keyboard_key_event *event = data; - - /* Translate libinput keycode -> xkbcommon */ - uint32_t keycode = event->keycode + 8; - /* Get a list of keysyms based on the keymap for this keyboard */ - const xkb_keysym_t *syms; - int nsyms = xkb_state_key_get_syms( - kb->wlr_keyboard->xkb_state, keycode, &syms); - - int handled = 0; - uint32_t mods = wlr_keyboard_get_modifiers(kb->wlr_keyboard); - - IDLE_NOTIFY_ACTIVITY; - - /* On _press_ if there is no active screen locker, - * attempt to process a compositor keybinding. */ - if (!locked && !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 && kb->wlr_keyboard->repeat_info.delay > 0) { - kb->mods = mods; - kb->keysyms = syms; - kb->nsyms = nsyms; - wl_event_source_timer_update(kb->key_repeat_source, - kb->wlr_keyboard->repeat_info.delay); - } else { - kb->nsyms = 0; - wl_event_source_timer_update(kb->key_repeat_source, 0); - } - - if (handled) - return; - - /* Pass unhandled keycodes along to the client. */ - wlr_seat_set_keyboard(seat, kb->wlr_keyboard); - 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->wlr_keyboard); - /* Send modifiers to the client. */ - wlr_seat_keyboard_notify_modifiers(seat, - &kb->wlr_keyboard->modifiers); -} - -int -keyrepeat(void *data) -{ - Keyboard *kb = data; - int i; - if (!kb->nsyms || kb->wlr_keyboard->repeat_info.rate <= 0) - return 0; - - wl_event_source_timer_update(kb->key_repeat_source, - 1000 / kb->wlr_keyboard->repeat_info.rate); - - for (i = 0; i < kb->nsyms; i++) - keybinding(kb->mods, kb->keysyms[i]); - - return 0; -} - -void -killclient(const Arg *arg) -{ - Client *sel = focustop(selmon); - if (sel) - client_send_close(sel); -} - -void -locksession(struct wl_listener *listener, void *data) -{ - struct wlr_session_lock_v1 *session_lock = data; - SessionLock *lock; - wlr_scene_node_set_enabled(&locked_bg->node, 1); - if (cur_lock) { - wlr_session_lock_v1_destroy(session_lock); - return; - } - lock = ecalloc(1, sizeof(*lock)); - focusclient(NULL, 0); - - lock->scene = wlr_scene_tree_create(layers[LyrBlock]); - cur_lock = lock->lock = session_lock; - locked = 1; - session_lock->data = lock; - - LISTEN(&session_lock->events.new_surface, &lock->new_surface, createlocksurface); - LISTEN(&session_lock->events.destroy, &lock->destroy, destroysessionlock); - LISTEN(&session_lock->events.unlock, &lock->unlock, unlocksession); - - wlr_session_lock_v1_send_locked(session_lock); -} - -void -maplayersurfacenotify(struct wl_listener *listener, void *data) -{ - LayerSurface *l = wl_container_of(listener, l, map); - motionnotify(0); -} - -void -mapnotify(struct wl_listener *listener, void *data) -{ - /* Called when the surface is mapped, or ready to display on-screen. */ - Client *p, *w, *c = wl_container_of(listener, c, map); - Monitor *m; - int i; - - /* Create scene tree for this client and its border */ - c->scene = wlr_scene_tree_create(layers[LyrTile]); - wlr_scene_node_set_enabled(&c->scene->node, c->type != XDGShell); - c->scene_surface = c->type == XDGShell - ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg) - : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); - 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->node.data = c->scene_surface->node.data = c; - - /* 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->node, layers[LyrFloat]); - wlr_scene_node_set_position(&c->scene->node, c->geom.x + borderpx, - c->geom.y + borderpx); - if (client_wants_focus(c)) { - focusclient(c, 1); - exclusive_focus = c; - } - goto unset_fullscreen; - } - - for (i = 0; i < 4; i++) { - c->border[i] = wlr_scene_rect_create(c->scene, 0, 0, bordercolor); - c->border[i]->node.data = c; - } - - /* Initialize client geometry with room for border */ - client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); - 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 */ - /* TODO: https://github.com/djpohly/dwl/pull/334#issuecomment-1330166324 */ - if (c->type == XDGShell && (p = client_get_parent(c))) { - c->isfloating = 1; - wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]); - setmon(c, p->mon, p->tags); - } else { - applyrules(c); - } - printstatus(); - -unset_fullscreen: - m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y); - wl_list_for_each(w, &clients, link) - if (w != c && w->isfullscreen && m == w->mon && (w->tags & c->tags)) - setfullscreen(w, 0); -} - -void -maximizenotify(struct wl_listener *listener, void *data) -{ - /* This event is raised when a client would like to maximize itself, - * typically because the user clicked on the maximize button on - * client-side decorations. dwl doesn't support maximization, but - * to conform to xdg-shell protocol we still must send a configure. - * wlr_xdg_surface_schedule_configure() is used to send an empty reply. */ - Client *c = wl_container_of(listener, c, maximize); - wlr_xdg_surface_schedule_configure(c->surface.xdg); -} - -void -monocle(Monitor *m) -{ - Client *c; - int n = 0; - - wl_list_for_each(c, &clients, link) { - if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) - continue; - resize(c, m->w, 0); - n++; - } - if (n) - snprintf(m->ltsymbol, LENGTH(m->ltsymbol), "[%d]", n); - if ((c = focustop(m))) - wlr_scene_node_raise_to_top(&c->scene->node); -} - -void -motionabsolute(struct wl_listener *listener, void *data) -{ - /* This event is forwarded by the cursor when a pointer emits an _absolute_ - * motion event, from 0..1 on each axis. This happens, for example, when - * wlroots is running under a Wayland window rather than KMS+DRM, and you - * move the mouse over the window. You could enter the window from any edge, - * so we have to warp the mouse there. There is also some hardware which - * emits these events. */ - struct wlr_pointer_motion_absolute_event *event = data; - wlr_cursor_warp_absolute(cursor, &event->pointer->base, event->x, event->y); - motionnotify(event->time_msec); -} - -void -motionnotify(uint32_t time) -{ - double sx = 0, sy = 0; - Client *c = NULL, *w = NULL; - LayerSurface *l = NULL; - int type; - struct wlr_surface *surface = NULL; - - /* time is 0 in internal calls meant to restore pointer focus. */ - if (time) { - IDLE_NOTIFY_ACTIVITY; - - /* Update selmon (even while dragging a window) */ - if (sloppyfocus) - selmon = xytomon(cursor->x, cursor->y); - } - - /* Update drag icon's position */ - wlr_scene_node_set_position(&drag_icon->node, cursor->x, cursor->y); - - /* If we are currently grabbing the mouse, handle and return */ - if (cursor_mode == CurMove) { - /* Move the grabbed client to the new position. */ - resize(grabc, (struct wlr_box){.x = 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 ((type = toplevel_from_wlr_surface( - seat->pointer_state.focused_surface, &w, &l)) >= 0) { - c = w; - surface = seat->pointer_state.focused_surface; - sx = cursor->x - (type == LayerShell ? l->geom.x : w->geom.x); - sy = cursor->y - (type == LayerShell ? l->geom.y : w->geom.y); - } - } - - /* If there's no client surface under the cursor, set the cursor image to a - * default. This is what makes the cursor image appear when you move it - * off of a client or over its border. */ - if (!surface && !seat->drag && (!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_pointer_motion_event *event = data; - /* The cursor doesn't move unless we tell it to. The cursor automatically - * handles constraining the motion to the output layout, as well as any - * special configuration applied for the specific input device which - * generated the event. You can pass NULL for the device if you want to move - * the cursor around without any input. */ - wlr_cursor_move(cursor, &event->pointer->base, 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) || grabc->isfullscreen) - 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); - wlr_output_enable_adaptive_sync(wlr_output, - config_head->state.adaptive_sync_enabled); - -apply_or_test: - if (test) { - ok &= wlr_output_test(wlr_output); - wlr_output_rollback(wlr_output); - } else { - ok &= wlr_output_commit(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; - uint32_t occ, urg, sel; - const char *appid, *title; - - 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))) { - title = client_get_title(c); - appid = client_get_appid(c); - printf("%s title %s\n", m->wlr_output->name, title ? title : broken); - printf("%s appid %s\n", m->wlr_output->name, appid ? appid : broken); - 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 appid \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, - sel, urg); - printf("%s layout %s\n", m->wlr_output->name, m->ltsymbol); - } - fflush(stdout); -} - -void -quit(const Arg *arg) -{ - wl_display_terminate(dpy); -} - -void -rendermon(struct wl_listener *listener, void *data) -{ - /* This function is called every time an output is ready to display a frame, - * generally at the output's refresh rate (e.g. 60Hz). */ - Monitor *m = wl_container_of(listener, m, frame); - Client *c; - struct timespec now; - - /* Render if no XDG clients have an outstanding resize and are visible on - * this monitor. */ - wl_list_for_each(c, &clients, link) - if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && !client_is_stopped(c)) - goto skip; - wlr_scene_output_commit(m->scene_output); - -skip: - /* Let clients know a frame has been rendered */ - clock_gettime(CLOCK_MONOTONIC, &now); - wlr_scene_output_send_frame_done(m->scene_output, &now); -} - -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; - client_set_bounds(c, geo.width, geo.height); - c->geom = geo; - applybounds(c, bbox); - - /* Update scene-graph, including borders */ - wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); - wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw); - wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw); - wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw); - wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw); - wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw); - wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw); - wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw); - wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw); - - /* this is a no-op if size hasn't changed */ - c->resize = client_set_size(c, c->geom.width - 2 * c->bw, - c->geom.height - 2 * c->bw); -} - -void -run(char *startup_cmd) -{ - /* Add a Unix socket to the Wayland display. */ - const char *socket = wl_display_add_socket_auto(dpy); - if (!socket) - die("startup: display_add_socket_auto"); - setenv("WAYLAND_DISPLAY", socket, 1); - - /* Start the backend. This will enumerate outputs and inputs, become the DRM - * master, etc */ - if (!wlr_backend_start(backend)) - die("startup: backend_start"); - - /* Now that the socket exists and the backend is started, run the startup command */ - if (startup_cmd) { - int piperw[2]; - if (pipe(piperw) < 0) - die("startup: pipe:"); - if ((child_pid = fork()) < 0) - die("startup: fork:"); - if (child_pid == 0) { - dup2(piperw[0], STDIN_FILENO); - close(piperw[0]); - close(piperw[1]); - execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL); - die("startup: execl:"); - } - dup2(piperw[1], STDOUT_FILENO); - close(piperw[1]); - close(piperw[0]); - } - printstatus(); - - /* At this point the outputs are initialized, choose initial selmon based on - * cursor position, and set default cursor image */ - selmon = xytomon(cursor->x, cursor->y); - - /* TODO hack to get cursor to display in its initial location (100, 100) - * instead of (0, 0) and then jumping. still may not be fully - * initialized, as the image/coordinates are not transformed for the - * monitor when displayed here */ - wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y); - wlr_xcursor_manager_set_cursor_image(cursor_mgr, cursor_image, cursor); - - // HACK - // focusmon(&(Arg){.i = WLR_DIRECTION_RIGHT }); - - /* Run the Wayland event loop. This does not return until you exit the - * compositor. Starting the backend rigged up all of the necessary event - * loop configuration to listen to libinput events, DRM events, generate - * frame events at the refresh rate, and so on. */ - wl_display_run(dpy); -} - -void -setcursor(struct wl_listener *listener, void *data) -{ - /* This event is raised by the seat when a client provides a cursor image */ - struct wlr_seat_pointer_request_set_cursor_event *event = data; - /* If we're "grabbing" the cursor, don't use the client's image, we will - * restore it after "grabbing" sending a leave event, followed by a enter - * event, which will result in the client requesting set the cursor surface */ - if (cursor_mode != CurNormal && cursor_mode != CurPressed) - return; - 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; - if (!c->mon) - return; - wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen - ? LyrFS : c->isfloating ? LyrFloat : LyrTile]); - arrange(c->mon); - printstatus(); -} - -void -setfullscreen(Client *c, int fullscreen) -{ - c->isfullscreen = fullscreen; - if (!c->mon) - return; - c->bw = fullscreen ? 0 : borderpx; - client_set_fullscreen(c, fullscreen); - wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen - ? LyrFS : c->isfloating ? LyrFloat : LyrTile]); - - if (fullscreen) { - c->prev = c->geom; - resize(c, c->mon->m, 0); - } else { - /* restore previous size instead of arrange for floating windows since - * client positions are set by the user and cannot be recalculated */ - resize(c, c->prev, 0); - } - arrange(c->mon); - printstatus(); -} - -void -setlayout(const Arg *arg) -{ - if (!selmon) - return; - if (!arg || !arg->v || arg->v != selmon->lt) - selmon->sellt = selmon->pertag->sellts[selmon->curtag] ^= 1; - if (arg && arg->v) - selmon->lt = selmon->pertag->ltidxs[selmon->curtag] = (Layout *)arg->v; - strncpy(selmon->ltsymbol, selmon->lt->symbol, LENGTH(selmon->ltsymbol)); - arrange(selmon); - printstatus(); -} - -/* arg > 1.0 will set mfact absolutely */ -void -setmfact(const Arg *arg) -{ - float f; - - if (!arg || !selmon || !selmon->lt->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 = selmon->pertag->mfacts[selmon->curtag] = f; - arrange(selmon); -} - -void -setmon(Client *c, Monitor *m, uint32_t newtags) -{ - Monitor *oldmon = c->mon; - - if (oldmon == m) - return; - c->mon = m; - c->prev = c->geom; - - /* Scene graph sends surface leave/enter events on move and resize */ - if (oldmon) - arrange(oldmon); - if (m) { - /* Make sure window actually overlaps with the monitor */ - resize(c, c->geom, 0); - c->tags = newtags ? newtags : m->tagset; /* assign tags of target monitor */ - setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ - setfloating(c, c->isfloating); - } - focusclient(focustop(selmon), 1); -} - -void -setpsel(struct wl_listener *listener, void *data) -{ - /* This event is raised by the seat when a client wants to set the selection, - * usually when the user copies something. wlroots allows compositors to - * ignore such requests if they so choose, but in dwl we always honor - */ - struct wlr_seat_request_set_primary_selection_event *event = data; - wlr_seat_set_primary_selection(seat, event->source, event->serial); -} - -void -setsel(struct wl_listener *listener, void *data) -{ - /* This event is raised by the seat when a client wants to set the selection, - * usually when the user copies something. wlroots allows compositors to - * ignore such requests if they so choose, but in dwl we always honor - */ - struct wlr_seat_request_set_selection_event *event = data; - wlr_seat_set_selection(seat, event->source, event->serial); -} - -void -setup(void) -{ - int i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE}; - struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig}; - sigemptyset(&sa.sa_mask); - - for (i = 0; i < LENGTH(sig); i++) - sigaction(sig[i], &sa, NULL); - - wlr_log_init(log_level, NULL); - - /* The Wayland display is managed by libwayland. It handles accepting - * clients from the Unix socket, manging Wayland globals, and so on. */ - dpy = wl_display_create(); - - /* The backend is a wlroots feature which abstracts the underlying input and - * output hardware. The autocreate option will choose the most suitable - * backend based on the current environment, such as opening an X11 window - * if an X11 server is running. 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(); - for (i = 0; i < NUM_LAYERS; i++) - layers[i] = wlr_scene_tree_create(&scene->tree); - drag_icon = wlr_scene_tree_create(&scene->tree); - wlr_scene_node_place_below(&drag_icon->node, &layers[LyrBlock]->node); - - /* 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); - wlr_single_pixel_buffer_manager_v1_create(dpy); - wlr_subcompositor_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_notifier = wlr_idle_notifier_v1_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, 4); - wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface); - - input_inhibit_mgr = wlr_input_inhibit_manager_create(dpy); - session_lock_mgr = wlr_session_lock_manager_v1_create(dpy); - wl_signal_add(&session_lock_mgr->events.new_lock, &session_lock_create_lock); - wl_signal_add(&session_lock_mgr->events.destroy, &session_lock_mgr_destroy); - locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height, - (float [4]){0.1, 0.1, 0.1, 1.0}); - wlr_scene_node_set_enabled(&locked_bg->node, 0); - - /* Use decoration protocols to negotiate server-side decorations */ - wlr_server_decoration_manager_set_default_mode( - wlr_server_decoration_manager_create(dpy), - WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); - xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy); - wl_signal_add(&xdg_decoration_mgr->events.new_toplevel_decoration, &new_xdg_decoration); - - /* - * Creates a cursor, which is a wlroots utility for tracking the cursor - * image shown on screen. - */ - cursor = wlr_cursor_create(); - wlr_cursor_attach_output_layout(cursor, output_layout); - - /* Creates an xcursor manager, another wlroots utility which loads up - * Xcursor themes to source cursor images from and makes sure that cursor - * images are available at all scale factors on the screen (necessary for - * HiDPI support). Scaled cursors will be loaded with each output. */ - cursor_mgr = wlr_xcursor_manager_create(NULL, 24); - setenv("XCURSOR_SIZE", "24", 1); - - /* - * wlr_cursor *only* displays an image on screen. It does not move around - * when the pointer moves. However, we can attach input devices to it, and - * it will generate aggregate events for all of them. In these events, we - * can choose how we want to process them, forwarding them to clients and - * moving the cursor around. More detail on this process is described in 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 -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(drag_icon, drag->icon->surface)->node; - wl_signal_add(&drag->icon->events.destroy, &drag_icon_destroy); -} - -void -tag(const Arg *arg) -{ - Client *sel = focustop(selmon); - if (!sel || (arg->ui & TAGMASK) == 0) - return; - - sel->tags = arg->ui & TAGMASK; - focusclient(focustop(selmon), 1); - arrange(selmon); - printstatus(); -} - -void -tagmon(const Arg *arg) -{ - Client *sel = focustop(selmon); - if (sel) - setmon(sel, dirtomon(arg->i), 0); -} - -void -tile(Monitor *m) -{ - unsigned int i, n = 0, mw, my, ty, r, h; - Client *c; - - wl_list_for_each(c, &clients, link) - if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) - n++; - if (n == 0) - return; - - if (n > m->nmaster) - mw = m->nmaster ? m->w.width * m->mfact : 0; - else - mw = m->w.width; - i = my = ty = 0; - wl_list_for_each(c, &clients, link) { - if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) - continue; - if (i < m->nmaster) { - r = MIN(n, m->nmaster) - i; - h = (m->w.height - my - gap * (r - 1)) / r; - resize(c, (struct wlr_box){ - .x = m->w.x + m->w.width - mw, - .y = m->w.y + my, - .width = mw, - .height = h - }, 0); - my += c->geom.height + gap; - } else { - r = n - i; - h = (m->w.height - ty - gap * (r-1)) / r; - resize(c, (struct wlr_box){ - .x = m->w.x, - .y = m->w.y + ty, - .width = m->w.width - mw - gap, - .height = h - }, 0); - ty += c->geom.height + gap; - } - i++; - } -} - -void -togglefloating(const Arg *arg) -{ - Client *sel = focustop(selmon); - /* return if fullscreen */ - if (sel && !sel->isfullscreen) - setfloating(sel, !sel->isfloating); -} - -void -togglefullscreen(const Arg *arg) -{ - Client *sel = focustop(selmon); - if (sel) - setfullscreen(sel, !sel->isfullscreen); -} - -void -toggletag(const Arg *arg) -{ - uint32_t newtags; - Client *sel = focustop(selmon); - if (!sel) - return; - newtags = sel->tags ^ (arg->ui & TAGMASK); - if (!newtags) - return; - - sel->tags = newtags; - focusclient(focustop(selmon), 1); - arrange(selmon); - printstatus(); -} - -void -toggleview(const Arg *arg) -{ - uint32_t newtagset = selmon ? selmon->tagset ^ (arg->ui & TAGMASK) : 0; - - if (!newtagset) - return; - - selmon->tagset = newtagset; - /* apply settings for this view */ - selmon->nmaster = selmon->pertag->nmasters[selmon->curtag]; - selmon->mfact = selmon->pertag->mfacts[selmon->curtag]; - selmon->sellt = selmon->pertag->sellts[selmon->curtag]; - selmon->lt = selmon->pertag->ltidxs[selmon->curtag]; - - focusclient(focustop(selmon), 1); - arrange(selmon); - printstatus(); -} - -void -unlocksession(struct wl_listener *listener, void *data) -{ - SessionLock *lock = wl_container_of(listener, lock, unlock); - destroylock(lock, 1); -} - -void -unmaplayersurfacenotify(struct wl_listener *listener, void *data) -{ - LayerSurface *layersurface = wl_container_of(listener, layersurface, unmap); - - layersurface->mapped = 0; - wlr_scene_node_set_enabled(&layersurface->scene->node, 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(focustop(selmon), 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 (client_is_unmanaged(c)) { - if (c == exclusive_focus) - exclusive_focus = NULL; - if (client_surface(c) == seat->keyboard_state.focused_surface) - focusclient(focustop(selmon), 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->node); - 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 */ - wlr_output_layout_get_box(output_layout, NULL, &sgeom); - - /* Make sure the clients are hidden when dwl is locked */ - wlr_scene_node_set_position(&locked_bg->node, sgeom.x, sgeom.y); - wlr_scene_rect_set_size(locked_bg, sgeom.width, sgeom.height); - - wl_list_for_each(m, &mons, link) { - if (!m->wlr_output->enabled) - continue; - config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output); - - /* Get the effective monitor geometry to use for surfaces */ - wlr_output_layout_get_box(output_layout, m->wlr_output, &(m->m)); - wlr_output_layout_get_box(output_layout, m->wlr_output, &(m->w)); - wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y); - - wlr_scene_node_set_position(&m->fullscreen_bg->node, m->m.x, m->m.y); - wlr_scene_rect_set_size(m->fullscreen_bg, m->m.width, m->m.height); - - if (m->lock_surface) { - struct wlr_scene_tree *scene_tree = m->lock_surface->surface->data; - wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y); - wlr_session_lock_surface_v1_configure(m->lock_surface, m->m.width, - m->m.height); - } - - /* Calculate the effective monitor geometry to use for clients */ - arrangelayers(m); - /* Don't move clients to the left output when plugging monitors */ - arrange(m); - - 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); - focusclient(focustop(selmon), 1); - if (selmon->lock_surface) { - client_notify_enter(selmon->lock_surface->surface, - wlr_seat_get_keyboard(seat)); - client_activate_surface(selmon->lock_surface->surface, 1); - } - } - - wlr_output_manager_v1_set_configuration(output_mgr, config); -} - -void -updatetitle(struct wl_listener *listener, void *data) -{ - Client *c = wl_container_of(listener, c, set_title); - if (c == focustop(c->mon)) - printstatus(); -} - -void -urgent(struct wl_listener *listener, void *data) -{ - struct wlr_xdg_activation_v1_request_activate_event *event = data; - Client *c = NULL; - toplevel_from_wlr_surface(event->surface, &c, NULL); - if (!c || c == focustop(selmon)) - return; - - if (client_is_mapped(c)) - client_set_border_color(c, urgentcolor); - c->isurgent = 1; - printstatus(); -} - -void -view(const Arg *arg) -{ - size_t i, tmptag; - - if (!selmon || (arg->ui & TAGMASK) == selmon->tagset) - return; - - if (arg->ui & TAGMASK) { - selmon->tagset = arg->ui & TAGMASK; - selmon->prevtag = selmon->curtag; - - if (arg->ui == ~0) - selmon->curtag = 0; - else { - for (i = 0; !(arg->ui & 1 << i); i++) ; - selmon->curtag = i + 1; - } - } else { - tmptag = selmon->prevtag; - selmon->prevtag = selmon->curtag; - selmon->curtag = tmptag; - selmon->tagset = 1 << (tmptag - 1); - } - - selmon->nmaster = selmon->pertag->nmasters[selmon->curtag]; - selmon->mfact = selmon->pertag->mfacts[selmon->curtag]; - selmon->sellt = selmon->pertag->sellts[selmon->curtag]; - selmon->lt = selmon->pertag->ltidxs[selmon->curtag]; - - focusclient(focustop(selmon), 1); - arrange(selmon); - printstatus(); -} - -void -virtualkeyboard(struct wl_listener *listener, void *data) -{ - struct wlr_virtual_keyboard_v1 *keyboard = data; - createkeyboard(&keyboard->keyboard); -} - -Monitor * -xytomon(double x, double y) -{ - struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y); - return o ? o->data : NULL; -} - -void -xytonode(double x, double y, struct wlr_surface **psurface, - Client **pc, LayerSurface **pl, double *nx, double *ny) -{ - struct wlr_scene_node *node, *pnode; - struct wlr_surface *surface = NULL; - Client *c = NULL; - LayerSurface *l = NULL; - int layer; - - for (layer = NUM_LAYERS - 1; !surface && layer >= 0; layer--) { - if (!(node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny))) - continue; - - if (node->type == WLR_SCENE_NODE_BUFFER) - surface = wlr_scene_surface_from_buffer( - wlr_scene_buffer_from_node(node))->surface; - /* Walk the tree to find a node that knows the client */ - for (pnode = node; pnode && !c; pnode = &pnode->parent->node) - c = pnode->data; - if (c && c->type == LayerShell) { - c = NULL; - l = pnode->data; - } - } - - if (psurface) *psurface = surface; - if (pc) *pc = c; - if (pl) *pl = l; -} - -void -zoom(const Arg *arg) -{ - Client *c, *sel = focustop(selmon); - - if (!sel || !selmon || !selmon->lt->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; - if (!c->mon) - return; - if (c->isfloating || c->type == X11Unmanaged) - resize(c, (struct wlr_box){.x = event->x, .y = event->y, - .width = event->width, .height = event->height}, 0); - else - arrange(c->mon); -} - -void -createnotifyx11(struct wl_listener *listener, void *data) -{ - struct wlr_xwayland_surface *xsurface = data; - Client *c; - - /* Allocate a Client for this surface */ - c = xsurface->data = ecalloc(1, sizeof(*c)); - c->surface.xwayland = xsurface; - c->type = xsurface->override_redirect ? X11Unmanaged : X11Managed; - c->bw = borderpx; - - /* Listen to the various events it can emit */ - LISTEN(&xsurface->events.map, &c->map, mapnotify); - LISTEN(&xsurface->events.unmap, &c->unmap, unmapnotify); - LISTEN(&xsurface->events.request_activate, &c->activate, activatex11); - LISTEN(&xsurface->events.request_configure, &c->configure, configurex11); - LISTEN(&xsurface->events.set_hints, &c->set_hints, sethints); - LISTEN(&xsurface->events.set_title, &c->set_title, updatetitle); - LISTEN(&xsurface->events.destroy, &c->destroy, destroynotify); - LISTEN(&xsurface->events.request_fullscreen, &c->fullscreen, fullscreennotify); -} - -xcb_atom_t -getatom(xcb_connection_t *xc, const char *name) -{ - xcb_atom_t atom = 0; - xcb_intern_atom_reply_t *reply; - xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xc, 0, strlen(name), name); - if ((reply = xcb_intern_atom_reply(xc, cookie, NULL))) - atom = reply->atom; - free(reply); - - return atom; -} - -void -sethints(struct wl_listener *listener, void *data) -{ - Client *c = wl_container_of(listener, c, set_hints); - if (c == focustop(selmon)) - return; - - c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints); - - if (c->isurgent && client_is_mapped(c)) - client_set_border_color(c, urgentcolor); - - 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:hdv")) != -1) { - if (c == 's') - startup_cmd = optarg; - else if (c == 'd') - log_level = WLR_DEBUG; - else if (c == 'v') - die("dwl " VERSION); - else - goto usage; - } - if (optind < argc) - goto usage; - - /* Wayland requires XDG_RUNTIME_DIR for creating its communications socket */ - if (!getenv("XDG_RUNTIME_DIR")) - die("XDG_RUNTIME_DIR must be set"); - setup(); - run(startup_cmd); - cleanup(); - return EXIT_SUCCESS; - - usage: - die("Usage: %s [-v] [-d] [-s startup command]", argv[0]); -} - -static void -bstack(Monitor *m) -{ - int w, h, mh, mx, tx, ty, tw; - unsigned int i, n = 0; - Client *c; - - wl_list_for_each(c, &clients, link) - if (VISIBLEON(c, m) && !c->isfloating) - n++; - if (n == 0) - return; - - if (n > m->nmaster) { - mh = m->nmaster ? m->mfact * m->w.height : 0; - tw = m->w.width / (n - m->nmaster); - ty = m->w.y + mh; - } else { - mh = m->w.height; - tw = m->w.width; - ty = m->w.y; - } - - i = mx = 0; - tx = m-> w.x; - wl_list_for_each(c, &clients, link) { - if (!VISIBLEON(c, m) || c->isfloating) - continue; - if (i < m->nmaster) { - w = (m->w.width - mx) / (MIN(n, m->nmaster) - i); - resize(c, (struct wlr_box){.x = m->w.x + mx, .y = m->w.y, .width = w - (2 * c->bw), .height = mh - (2 * c->bw)}, 0); - mx += c->geom.width; - } else { - h = m->w.height - mh; - resize(c, (struct wlr_box){.x = tx, .y = ty, .width = tw - (2 * c->bw), .height = h - (2 * c->bw)}, 0); - if (tw != m->w.width) - tx += c->geom.width; - } - i++; - } -} - -static void -bstackhoriz(Monitor *m) { - int w, mh, mx, tx, ty, th; - unsigned int i, n = 0; - Client *c; - - wl_list_for_each(c, &clients, link) - if (VISIBLEON(c, m) && !c->isfloating) - n ++; - if (n == 0) - return; - - if (n > m->nmaster) { - mh = m->nmaster ? m->mfact * m->w.height : 0; - th = (m->w.height - mh) / (n - m->nmaster); - ty = m->w.y + mh; - } else { - th = mh = m->w.height; - ty = m->w.y; - } - - i = mx = 0; - tx = m-> w.x; - wl_list_for_each(c, &clients, link) { - if (!VISIBLEON(c,m) || c->isfloating) - continue; - if (i < m->nmaster) { - w = (m->w.width - mx) / (MIN(n, m->nmaster) - i); - resize(c, (struct wlr_box){.x = m->w.x + mx, .y = m->w.y, .width = w - (2 * c->bw), .height = mh - (2 * c->bw)}, 0); - mx += c->geom.width; - } else { - resize(c, (struct wlr_box){.x = tx, .y = ty, .width = m->w.width - (2 * c->bw), .height = th - (2 * c->bw)}, 0); - if (th != m->w.height) - ty += c->geom.height; - } - i++; - } -} diff --git a/dwl/dwl.desktop b/dwl/dwl.desktop deleted file mode 100644 index e1380f7..0000000 --- a/dwl/dwl.desktop +++ /dev/null @@ -1,5 +0,0 @@ -[Desktop Entry] -Name=dwl -Comment=dwm for Wayland -Exec=dwl -Type=Application diff --git a/dwl/dwl.sh b/dwl/dwl.sh new file mode 100755 index 0000000..190db66 --- /dev/null +++ b/dwl/dwl.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +killall dunst; dunst & + +swaybg -o DP-3 -i /home/tslil/store/pictures/dp3_back & +swaybg -o DP-1 -m tile -i /home/tslil/store/pictures/dp1_back & + +yambar & +cat - > /home/tslil/.cache/dwltags diff --git a/dwl/pertag.patch b/dwl/pertag.patch index d762efa..a0c66d8 100644 --- a/dwl/pertag.patch +++ b/dwl/pertag.patch @@ -1,17 +1,17 @@ -From d8415ff1f2a8bd347cfcae334815eac1589ee069 Mon Sep 17 00:00:00 2001 -From: Guido Cella <guido@guidocella.xyz> -Date: Sun, 20 Mar 2022 21:22:13 +0100 -Subject: [PATCH] Port pertag +From 8750e1255f6c8b799165186cd6cfdfa7af3ee56d Mon Sep 17 00:00:00 2001 +From: mortezadadgar <mortezadadgar97@gmail.com> +Date: Sat, 26 Aug 2023 20:37:22 +0330 +Subject: [PATCH] Applied pertag --- - dwl.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- - 1 file changed, 73 insertions(+), 5 deletions(-) + dwl.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 70 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c -index b4fa1efe..8f0bb0df 100644 +index 4ff5c37f7..6c104bbb0 100644 --- a/dwl.c +++ b/dwl.c -@@ -88,6 +88,7 @@ typedef struct { +@@ -94,6 +94,7 @@ typedef struct { const Arg arg; } Button; @@ -19,37 +19,45 @@ index b4fa1efe..8f0bb0df 100644 typedef struct Monitor Monitor; typedef struct { /* Must keep these three elements in this order */ -@@ -177,6 +178,7 @@ struct Monitor { - struct wlr_box w; /* window area, layout-relative */ +@@ -185,6 +186,7 @@ struct Monitor { + struct wlr_box w; /* window area, layout-relative */ struct wl_list layers[4]; /* LayerSurface::link */ const Layout *lt[2]; + Pertag *pertag; unsigned int seltags; unsigned int sellt; - unsigned int tagset[2]; -@@ -377,6 +379,14 @@ static Atom netatom[NetLast]; + uint32_t tagset[2]; +@@ -413,6 +415,14 @@ static Atom netatom[NetLast]; /* attempt to encapsulate suck into one file */ #include "client.h" +struct Pertag { + unsigned int curtag, prevtag; /* current and previous tag */ -+ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ -+ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ -+ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ -+ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ ++ int nmasters[TAGCOUNT + 1]; /* number of windows in master area */ ++ float mfacts[TAGCOUNT + 1]; /* mfacts per tag */ ++ unsigned int sellts[TAGCOUNT + 1]; /* selected layouts */ ++ const Layout *ltidxs[TAGCOUNT + 1][2]; /* matrix of tags and layouts indexes */ +}; + - /* compile-time check if all tags fit into an unsigned int bit array. */ - struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + /* function implementations */ + void + applybounds(Client *c, struct wlr_box *bbox) +@@ -703,6 +713,7 @@ cleanupmon(struct wl_listener *listener, void *data) + wlr_scene_output_destroy(m->scene_output); + wlr_scene_node_destroy(&m->fullscreen_bg->node); -@@ -974,6 +984,18 @@ createmon(struct wl_listener *listener, void *data) ++ free(m->pertag); + closemon(m); + free(m); + } +@@ -944,6 +955,18 @@ createmon(struct wl_listener *listener, void *data) wl_list_insert(&mons, &m->link); printstatus(); + m->pertag = calloc(1, sizeof(Pertag)); + m->pertag->curtag = m->pertag->prevtag = 1; + -+ for (i = 0; i <= LENGTH(tags); i++) { ++ for (i = 0; i <= TAGCOUNT; i++) { + m->pertag->nmasters[i] = m->nmaster; + m->pertag->mfacts[i] = m->mfact; + @@ -58,10 +66,10 @@ index b4fa1efe..8f0bb0df 100644 + m->pertag->sellts[i] = m->sellt; + } + - /* Adds this to the output layout in the order it was configured in. + /* The xdg-protocol specifies: * - * The output layout utility automatically adds a wl_output global to the -@@ -1283,7 +1305,7 @@ incnmaster(const Arg *arg) + * If the fullscreened surface is not opaque, the compositor must make +@@ -1355,7 +1378,7 @@ incnmaster(const Arg *arg) { if (!arg || !selmon) return; @@ -70,7 +78,7 @@ index b4fa1efe..8f0bb0df 100644 arrange(selmon); } -@@ -1973,9 +1995,9 @@ setlayout(const Arg *arg) +@@ -2060,9 +2083,9 @@ setlayout(const Arg *arg) if (!selmon) return; if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) @@ -79,10 +87,10 @@ index b4fa1efe..8f0bb0df 100644 if (arg && arg->v) - selmon->lt[selmon->sellt] = (Layout *)arg->v; + selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; - /* TODO change layout symbol? */ + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, LENGTH(selmon->ltsymbol)); arrange(selmon); printstatus(); -@@ -1992,7 +2014,7 @@ setmfact(const Arg *arg) +@@ -2079,7 +2102,7 @@ setmfact(const Arg *arg) f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; if (f < 0.1 || f > 0.9) return; @@ -91,38 +99,38 @@ index b4fa1efe..8f0bb0df 100644 arrange(selmon); } -@@ -2348,9 +2370,30 @@ void +@@ -2423,10 +2446,30 @@ void toggleview(const Arg *arg) { - unsigned int newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0; + uint32_t newtagset = selmon ? selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK) : 0; + size_t i; - if (newtagset) { - selmon->tagset[selmon->seltags] = newtagset; -+ -+ if (newtagset == ~0) { -+ selmon->pertag->prevtag = selmon->pertag->curtag; -+ selmon->pertag->curtag = 0; -+ } + if (!newtagset) + return; + ++ if (newtagset == ~0) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = 0; ++ } + -+ /* test if the user did not select the same tag */ -+ if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) { -+ selmon->pertag->prevtag = selmon->pertag->curtag; -+ for (i = 0; !(newtagset & 1 << i); i++) ; -+ selmon->pertag->curtag = i + 1; -+ } ++ /* test if the user did not select the same tag */ ++ if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ for (i = 0; !(newtagset & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } + -+ /* apply settings for this view */ -+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; -+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; -+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; -+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; -+ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ /* apply settings for this view */ ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; + - focusclient(focustop(selmon), 1); - arrange(selmon); - } -@@ -2468,11 +2511,36 @@ urgent(struct wl_listener *listener, void *data) + selmon->tagset[selmon->seltags] = newtagset; + focusclient(focustop(selmon), 1); + arrange(selmon); +@@ -2596,11 +2639,33 @@ urgent(struct wl_listener *listener, void *data) void view(const Arg *arg) { @@ -130,9 +138,6 @@ index b4fa1efe..8f0bb0df 100644 + if (!selmon || (arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) return; -+ -+ if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) -+ selmon->seltags ^= 1; /* toggle sel tagset */ - if (arg->ui & TAGMASK) + if (arg->ui & TAGMASK) { diff --git a/dwl/protocols/wlr-layer-shell-unstable-v1.xml b/dwl/protocols/wlr-layer-shell-unstable-v1.xml deleted file mode 100644 index d62fd51..0000000 --- a/dwl/protocols/wlr-layer-shell-unstable-v1.xml +++ /dev/null @@ -1,390 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<protocol name="wlr_layer_shell_unstable_v1"> - <copyright> - Copyright © 2017 Drew DeVault - - Permission to use, copy, modify, distribute, and sell this - software and its documentation for any purpose is hereby granted - without fee, provided that the above copyright notice appear in - all copies and that both that copyright notice and this permission - notice appear in supporting documentation, and that the name of - the copyright holders not be used in advertising or publicity - pertaining to distribution of the software without specific, - written prior permission. The copyright holders make no - representations about the suitability of this software for any - purpose. It is provided "as is" without express or implied - warranty. - - THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS - SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF - THIS SOFTWARE. - </copyright> - - <interface name="zwlr_layer_shell_v1" version="4"> - <description summary="create surfaces that are layers of the desktop"> - Clients can use this interface to assign the surface_layer role to - wl_surfaces. Such surfaces are assigned to a "layer" of the output and - rendered with a defined z-depth respective to each other. They may also be - anchored to the edges and corners of a screen and specify input handling - semantics. This interface should be suitable for the implementation of - many desktop shell components, and a broad number of other applications - that interact with the desktop. - </description> - - <request name="get_layer_surface"> - <description summary="create a layer_surface from a surface"> - Create a layer surface for an existing surface. This assigns the role of - layer_surface, or raises a protocol error if another role is already - assigned. - - Creating a layer surface from a wl_surface which has a buffer attached - or committed is a client error, and any attempts by a client to attach - or manipulate a buffer prior to the first layer_surface.configure call - must also be treated as errors. - - After creating a layer_surface object and setting it up, the client - must perform an initial commit without any buffer attached. - The compositor will reply with a layer_surface.configure event. - The client must acknowledge it and is then allowed to attach a buffer - to map the surface. - - You may pass NULL for output to allow the compositor to decide which - output to use. Generally this will be the one that the user most - recently interacted with. - - Clients can specify a namespace that defines the purpose of the layer - surface. - </description> - <arg name="id" type="new_id" interface="zwlr_layer_surface_v1"/> - <arg name="surface" type="object" interface="wl_surface"/> - <arg name="output" type="object" interface="wl_output" allow-null="true"/> - <arg name="layer" type="uint" enum="layer" summary="layer to add this surface to"/> - <arg name="namespace" type="string" summary="namespace for the layer surface"/> - </request> - - <enum name="error"> - <entry name="role" value="0" summary="wl_surface has another role"/> - <entry name="invalid_layer" value="1" summary="layer value is invalid"/> - <entry name="already_constructed" value="2" summary="wl_surface has a buffer attached or committed"/> - </enum> - - <enum name="layer"> - <description summary="available layers for surfaces"> - These values indicate which layers a surface can be rendered in. They - are ordered by z depth, bottom-most first. Traditional shell surfaces - will typically be rendered between the bottom and top layers. - Fullscreen shell surfaces are typically rendered at the top layer. - Multiple surfaces can share a single layer, and ordering within a - single layer is undefined. - </description> - - <entry name="background" value="0"/> - <entry name="bottom" value="1"/> - <entry name="top" value="2"/> - <entry name="overlay" value="3"/> - </enum> - - <!-- Version 3 additions --> - - <request name="destroy" type="destructor" since="3"> - <description summary="destroy the layer_shell object"> - This request indicates that the client will not use the layer_shell - object any more. Objects that have been created through this instance - are not affected. - </description> - </request> - </interface> - - <interface name="zwlr_layer_surface_v1" version="4"> - <description summary="layer metadata interface"> - An interface that may be implemented by a wl_surface, for surfaces that - are designed to be rendered as a layer of a stacked desktop-like - environment. - - Layer surface state (layer, size, anchor, exclusive zone, - margin, interactivity) is double-buffered, and will be applied at the - time wl_surface.commit of the corresponding wl_surface is called. - - Attaching a null buffer to a layer surface unmaps it. - - Unmapping a layer_surface means that the surface cannot be shown by the - compositor until it is explicitly mapped again. The layer_surface - returns to the state it had right after layer_shell.get_layer_surface. - The client can re-map the surface by performing a commit without any - buffer attached, waiting for a configure event and handling it as usual. - </description> - - <request name="set_size"> - <description summary="sets the size of the surface"> - Sets the size of the surface in surface-local coordinates. The - compositor will display the surface centered with respect to its - anchors. - - If you pass 0 for either value, the compositor will assign it and - inform you of the assignment in the configure event. You must set your - anchor to opposite edges in the dimensions you omit; not doing so is a - protocol error. Both values are 0 by default. - - Size is double-buffered, see wl_surface.commit. - </description> - <arg name="width" type="uint"/> - <arg name="height" type="uint"/> - </request> - - <request name="set_anchor"> - <description summary="configures the anchor point of the surface"> - Requests that the compositor anchor the surface to the specified edges - and corners. If two orthogonal edges are specified (e.g. 'top' and - 'left'), then the anchor point will be the intersection of the edges - (e.g. the top left corner of the output); otherwise the anchor point - will be centered on that edge, or in the center if none is specified. - - Anchor is double-buffered, see wl_surface.commit. - </description> - <arg name="anchor" type="uint" enum="anchor"/> - </request> - - <request name="set_exclusive_zone"> - <description summary="configures the exclusive geometry of this surface"> - Requests that the compositor avoids occluding an area with other - surfaces. The compositor's use of this information is - implementation-dependent - do not assume that this region will not - actually be occluded. - - A positive value is only meaningful if the surface is anchored to one - edge or an edge and both perpendicular edges. If the surface is not - anchored, anchored to only two perpendicular edges (a corner), anchored - to only two parallel edges or anchored to all edges, a positive value - will be treated the same as zero. - - A positive zone is the distance from the edge in surface-local - coordinates to consider exclusive. - - Surfaces that do not wish to have an exclusive zone may instead specify - how they should interact with surfaces that do. If set to zero, the - surface indicates that it would like to be moved to avoid occluding - surfaces with a positive exclusive zone. If set to -1, the surface - indicates that it would not like to be moved to accommodate for other - surfaces, and the compositor should extend it all the way to the edges - it is anchored to. - - For example, a panel might set its exclusive zone to 10, so that - maximized shell surfaces are not shown on top of it. A notification - might set its exclusive zone to 0, so that it is moved to avoid - occluding the panel, but shell surfaces are shown underneath it. A - wallpaper or lock screen might set their exclusive zone to -1, so that - they stretch below or over the panel. - - The default value is 0. - - Exclusive zone is double-buffered, see wl_surface.commit. - </description> - <arg name="zone" type="int"/> - </request> - - <request name="set_margin"> - <description summary="sets a margin from the anchor point"> - Requests that the surface be placed some distance away from the anchor - point on the output, in surface-local coordinates. Setting this value - for edges you are not anchored to has no effect. - - The exclusive zone includes the margin. - - Margin is double-buffered, see wl_surface.commit. - </description> - <arg name="top" type="int"/> - <arg name="right" type="int"/> - <arg name="bottom" type="int"/> - <arg name="left" type="int"/> - </request> - - <enum name="keyboard_interactivity"> - <description summary="types of keyboard interaction possible for a layer shell surface"> - Types of keyboard interaction possible for layer shell surfaces. The - rationale for this is twofold: (1) some applications are not interested - in keyboard events and not allowing them to be focused can improve the - desktop experience; (2) some applications will want to take exclusive - keyboard focus. - </description> - - <entry name="none" value="0"> - <description summary="no keyboard focus is possible"> - This value indicates that this surface is not interested in keyboard - events and the compositor should never assign it the keyboard focus. - - This is the default value, set for newly created layer shell surfaces. - - This is useful for e.g. desktop widgets that display information or - only have interaction with non-keyboard input devices. - </description> - </entry> - <entry name="exclusive" value="1"> - <description summary="request exclusive keyboard focus"> - Request exclusive keyboard focus if this surface is above the shell surface layer. - - For the top and overlay layers, the seat will always give - exclusive keyboard focus to the top-most layer which has keyboard - interactivity set to exclusive. If this layer contains multiple - surfaces with keyboard interactivity set to exclusive, the compositor - determines the one receiving keyboard events in an implementation- - defined manner. In this case, no guarantee is made when this surface - will receive keyboard focus (if ever). - - For the bottom and background layers, the compositor is allowed to use - normal focus semantics. - - This setting is mainly intended for applications that need to ensure - they receive all keyboard events, such as a lock screen or a password - prompt. - </description> - </entry> - <entry name="on_demand" value="2" since="4"> - <description summary="request regular keyboard focus semantics"> - This requests the compositor to allow this surface to be focused and - unfocused by the user in an implementation-defined manner. The user - should be able to unfocus this surface even regardless of the layer - it is on. - - Typically, the compositor will want to use its normal mechanism to - manage keyboard focus between layer shell surfaces with this setting - and regular toplevels on the desktop layer (e.g. click to focus). - Nevertheless, it is possible for a compositor to require a special - interaction to focus or unfocus layer shell surfaces (e.g. requiring - a click even if focus follows the mouse normally, or providing a - keybinding to switch focus between layers). - - This setting is mainly intended for desktop shell components (e.g. - panels) that allow keyboard interaction. Using this option can allow - implementing a desktop shell that can be fully usable without the - mouse. - </description> - </entry> - </enum> - - <request name="set_keyboard_interactivity"> - <description summary="requests keyboard events"> - Set how keyboard events are delivered to this surface. By default, - layer shell surfaces do not receive keyboard events; this request can - be used to change this. - - This setting is inherited by child surfaces set by the get_popup - request. - - Layer surfaces receive pointer, touch, and tablet events normally. If - you do not want to receive them, set the input region on your surface - to an empty region. - - Keyboard interactivity is double-buffered, see wl_surface.commit. - </description> - <arg name="keyboard_interactivity" type="uint" enum="keyboard_interactivity"/> - </request> - - <request name="get_popup"> - <description summary="assign this layer_surface as an xdg_popup parent"> - This assigns an xdg_popup's parent to this layer_surface. This popup - should have been created via xdg_surface::get_popup with the parent set - to NULL, and this request must be invoked before committing the popup's - initial state. - - See the documentation of xdg_popup for more details about what an - xdg_popup is and how it is used. - </description> - <arg name="popup" type="object" interface="xdg_popup"/> - </request> - - <request name="ack_configure"> - <description summary="ack a configure event"> - When a configure event is received, if a client commits the - surface in response to the configure event, then the client - must make an ack_configure request sometime before the commit - request, passing along the serial of the configure event. - - If the client receives multiple configure events before it - can respond to one, it only has to ack the last configure event. - - A client is not required to commit immediately after sending - an ack_configure request - it may even ack_configure several times - before its next surface commit. - - A client may send multiple ack_configure requests before committing, but - only the last request sent before a commit indicates which configure - event the client really is responding to. - </description> - <arg name="serial" type="uint" summary="the serial from the configure event"/> - </request> - - <request name="destroy" type="destructor"> - <description summary="destroy the layer_surface"> - This request destroys the layer surface. - </description> - </request> - - <event name="configure"> - <description summary="suggest a surface change"> - The configure event asks the client to resize its surface. - - Clients should arrange their surface for the new states, and then send - an ack_configure request with the serial sent in this configure event at - some point before committing the new surface. - - The client is free to dismiss all but the last configure event it - received. - - The width and height arguments specify the size of the window in - surface-local coordinates. - - The size is a hint, in the sense that the client is free to ignore it if - it doesn't resize, pick a smaller size (to satisfy aspect ratio or - resize in steps of NxM pixels). If the client picks a smaller size and - is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the - surface will be centered on this axis. - - If the width or height arguments are zero, it means the client should - decide its own window dimension. - </description> - <arg name="serial" type="uint"/> - <arg name="width" type="uint"/> - <arg name="height" type="uint"/> - </event> - - <event name="closed"> - <description summary="surface should be closed"> - The closed event is sent by the compositor when the surface will no - longer be shown. The output may have been destroyed or the user may - have asked for it to be removed. Further changes to the surface will be - ignored. The client should destroy the resource after receiving this - event, and create a new surface if they so choose. - </description> - </event> - - <enum name="error"> - <entry name="invalid_surface_state" value="0" summary="provided surface state is invalid"/> - <entry name="invalid_size" value="1" summary="size is invalid"/> - <entry name="invalid_anchor" value="2" summary="anchor bitfield is invalid"/> - <entry name="invalid_keyboard_interactivity" value="3" summary="keyboard interactivity is invalid"/> - </enum> - - <enum name="anchor" bitfield="true"> - <entry name="top" value="1" summary="the top edge of the anchor rectangle"/> - <entry name="bottom" value="2" summary="the bottom edge of the anchor rectangle"/> - <entry name="left" value="4" summary="the left edge of the anchor rectangle"/> - <entry name="right" value="8" summary="the right edge of the anchor rectangle"/> - </enum> - - <!-- Version 2 additions --> - - <request name="set_layer" since="2"> - <description summary="change the layer of the surface"> - Change the layer that the surface is rendered on. - - Layer is double-buffered, see wl_surface.commit. - </description> - <arg name="layer" type="uint" enum="zwlr_layer_shell_v1.layer" summary="layer to move this surface to"/> - </request> - </interface> -</protocol> diff --git a/dwl/rmaster.patch b/dwl/rmaster.patch new file mode 100644 index 0000000..f6afd59 --- /dev/null +++ b/dwl/rmaster.patch @@ -0,0 +1,27 @@ +From fb5d9aab92bf5eae32b62d345290f61fec08a2fe Mon Sep 17 00:00:00 2001 +From: tslil clingman +Date: Sun, 26 Nov 2023 16:38:01 +0100 +Subject: [PATCH] rmaster + +--- + dwl.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/dwl.c b/dwl.c +index 47e238e..3e9bd4a 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -2451,11 +2451,11 @@ tile(Monitor *m) + 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, ++ resize(c, (struct wlr_box){.x = m->w.x + m->w.width - mw, .y = m->w.y + my, .width = mw, + .height = (m->w.height - my) / (MIN(n, m->nmaster) - i)}, 0); + my += c->geom.height; + } else { +- resize(c, (struct wlr_box){.x = m->w.x + mw, .y = m->w.y + ty, ++ resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + ty, + .width = m->w.width - mw, .height = (m->w.height - ty) / (n - i)}, 0); + ty += c->geom.height; + } diff --git a/dwl/util.c b/dwl/util.c deleted file mode 100644 index cca7c19..0000000 --- a/dwl/util.c +++ /dev/null @@ -1,35 +0,0 @@ -/* See LICENSE.dwm file for copyright and license details. */ -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "util.h" - -void -die(const char *fmt, ...) { - va_list ap; - - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - - if (fmt[0] && fmt[strlen(fmt)-1] == ':') { - fputc(' ', stderr); - perror(NULL); - } else { - fputc('\n', stderr); - } - - exit(1); -} - -void * -ecalloc(size_t nmemb, size_t size) -{ - void *p; - - if (!(p = calloc(nmemb, size))) - die("calloc:"); - return p; -} diff --git a/dwl/util.h b/dwl/util.h deleted file mode 100644 index 4c94117..0000000 --- a/dwl/util.h +++ /dev/null @@ -1,4 +0,0 @@ -/* See LICENSE.dwm file for copyright and license details. */ - -void die(const char *fmt, ...); -void *ecalloc(size_t nmemb, size_t size); |
