diff --git a/LICENSE.dwl b/LICENSE.dwl deleted file mode 100644 index 658085a4..00000000 --- a/LICENSE.dwl +++ /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. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/LICENSE.dwm b/LICENSE.dwm deleted file mode 100644 index 507e4dce..00000000 --- a/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 -© 2006-2009 Jukka Salmi -© 2006-2007 Sander van Dijk -© 2007-2011 Peter Hartlich -© 2007-2009 Szabolcs Nagy -© 2007-2009 Christof Musik -© 2007-2009 Premysl Hruby -© 2007-2008 Enno Gottox Boland -© 2008 Martin Hurton -© 2008 Neale Pickett -© 2009 Mate Nagy -© 2010-2016 Hiltjo Posthuma -© 2010-2012 Connor Lane Smith -© 2011 Christoph Lohmann <20h@r-36.net> -© 2015-2016 Quentin Rameau -© 2015-2016 Eric Pruitt -© 2016-2017 Markus Teich - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/LICENSE.sway b/LICENSE.sway deleted file mode 100644 index 3e0cacc2..00000000 --- a/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/LICENSE.tinywl b/LICENSE.tinywl deleted file mode 100644 index 70236904..00000000 --- a/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/LICENSE.wlroots b/LICENSE.wlroots deleted file mode 100644 index fe85581c..00000000 --- a/LICENSE.wlroots +++ /dev/null @@ -1,21 +0,0 @@ -Copyright (c) 2017, 2018 Drew DeVault -Copyright (c) 2014 Jari Vetoniemi -Copyright (c) 2023 The wlroots contributors - -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/docs/bindings/keys.md b/docs/bindings/keys.md index 6c8a8c58..d0c13a0a 100644 --- a/docs/bindings/keys.md +++ b/docs/bindings/keys.md @@ -114,6 +114,13 @@ bindr=Super,Super_L,spawn,rofi -show run | `exchange_stack_client` | `next/prev` | Exchange window position in stack. | | `zoom` | - | Swap focused window with Master. | +### Group +| Command | Param | Description | +| :--- | :--- | :--- | +| `groupjoin` | `left/right/up/down` | Join group by direction. | +| `groupfocus` | `prev/next` | Focus group member by direction. | +| `groupleave` | - | Leave group. | + ### Tags & Monitors | Command | Param | Description | @@ -170,11 +177,12 @@ bindr=Super,Super_L,spawn,rofi -show run | `setkeymode` | `mode` | Set keymode. | | `switch_keyboard_layout` | `[index]` | Switch keyboard layout. Optional index (0, 1, 2...) to switch to specific layout. | | `setoption` | `key,value` | Set config option temporarily. | -| `disable_monitor` | `monitor_spec` | Shutdown monitor. Accepts a [monitor spec](/docs/configuration/monitors#monitor-spec-format). | -| `enable_monitor` | `monitor_spec` | Power on monitor. Accepts a [monitor spec](/docs/configuration/monitors#monitor-spec-format). | -| `toggle_monitor` | `monitor_spec` | Toggle monitor power. Accepts a [monitor spec](/docs/configuration/monitors#monitor-spec-format). | -| `chvt` | `1-9` | Change virtual terminal (tty, equivalent to using ctrl+alt+Fkeys) | - +| `sleep_monitor` | `monitor_spec` | Shutdown monitor power but not remove. Accepts a [monitor spec](/docs/configuration/monitors#monitor-spec-format). | +| `wakeup_monitor` | `monitor_spec` | Turn on monitor power. Accepts a [monitor spec](/docs/configuration/monitors#monitor-spec-format). | +| `sleep_toggle_monitor` | `monitor_spec` | Toggle monitor power but not remove. Accepts a [monitor spec](/docs/configuration/monitors#monitor-spec-format). +| `disable_monitor` | `monitor_spec` | remove monitor. Accepts a [monitor spec](/docs/configuration/monitors#monitor-spec-format). | +| `enable_monitor` | `monitor_spec` | add monitor. Accepts a [monitor spec](/docs/configuration/monitors#monitor-spec-format). | +| `toggle_monitor` | `monitor_spec` | Toggle monitor add/remove. Accepts a [monitor spec](/docs/configuration/monitors#monitor-spec-format). | ### Media Controls diff --git a/docs/configuration/miscellaneous.md b/docs/configuration/miscellaneous.md index cd8d167d..32dc5b42 100644 --- a/docs/configuration/miscellaneous.md +++ b/docs/configuration/miscellaneous.md @@ -8,10 +8,9 @@ description: Advanced settings for XWayland, focus behavior, and system integrat | Setting | Default | Description | | :--- | :--- | :--- | | `xwayland_persistence` | `1` | Keep XWayland running even when no X11 apps are open (reduces startup lag). | -| `syncobj_enable` | `0` | Enable `drm_syncobj` timeline support (helps with gaming stutter/lag). **Requires restart.** | +| `syncobj_enable` | `1` | Enable `drm_syncobj` timeline support (helps with gaming stutter/lag). **Requires restart.** | | `allow_lock_transparent` | `0` | Allow the lock screen to be transparent. | | `allow_shortcuts_inhibit` | `1` | Allow shortcuts to be inhibited by clients. | -| `vrr` | - | Set via [monitor rule](/docs/configuration/monitors#monitor-rules). | ## Focus & Input diff --git a/docs/configuration/monitors.md b/docs/configuration/monitors.md index a8001ae0..fba8f407 100644 --- a/docs/configuration/monitors.md +++ b/docs/configuration/monitors.md @@ -30,8 +30,10 @@ monitorrule=name:Values,Parameter:Values,Parameter:Values | `y` | integer | 0-99999 | Y position | | `scale` | float | 0.01-100.0 | Monitor scale | | `vrr` | integer | 0, 1 | Enable variable refresh rate | +| `hdr` | integer | 0, 1 | Enable hdr support | | `rr` | integer | 0-7 | Monitor transform | | `custom` | integer | 0, 1 | Enable custom mode (not supported on all displays — may cause black screen) | +| `disable` | integer | 0, 1 | Disable the monitor | ### Transform Values @@ -102,6 +104,21 @@ Tearing allows games to bypass the compositor's VSync for lower latency. | :--- | :--- | :--- | | `allow_tearing` | `0` | Global tearing control: `0` (Disable), `1` (Enable), `2` (Fullscreen only). | +## HDR +| Setting | Default | Description | +| :--- | :--- | :--- | +| `hdr_depth` | `2`| Set the hdr depth for the current display. `0` is Default, `1` is HDR8, `2` is HDR10. | + +- you should enable HDR in monitorrule first, refer to [Monitors — Monitor Rules](/docs/configuration/monitors#monitor-rules) +- you must set `env=WLR_RENDERER,vulkan` before mango starts. + +#### for example(must relogin once after setting): +```conf +env=WLR_RENDERER,vulkan +monitorrule=name:eDP-1,model:0x15F5,width:1920,height:1080,refresh:60,x:0,y:0,scale:1,vrr:0,rr:0:hdr:1 +``` + + ### Configuration **Enable Globally:** @@ -130,16 +147,9 @@ windowrule=force_tearing:1,title:vkcube > **Warning:** Some graphics cards require setting the `WLR_DRM_NO_ATOMIC` environment variable before mango starts to successfully enable tearing. -Add this to `/etc/environment` and reboot: - -```bash -WLR_DRM_NO_ATOMIC=1 +Add this to config and relogin mango: ``` - -Or run mango with the environment variable: - -```bash -WLR_DRM_NO_ATOMIC=1 mango +env=WLR_DRM_NO_ATOMIC,1 ``` --- @@ -156,7 +166,7 @@ WLR_DRM_DEVICES=/dev/dri/card1 mango WLR_DRM_DEVICES=/dev/dri/card0:/dev/dri/card1 mango ``` -Some GPUs have compatibility issues with `syncobj_enable=1` — it may crash apps like `kitty` that use syncobj. Set `WLR_DRM_NO_ATOMIC=1` in `/etc/environment` and reboot to resolve this. +Some GPUs have compatibility issues with `syncobj_enable=1` — it may crash apps like `kitty` that use syncobj. Set `env=WLR_DRM_NO_ATOMIC,1` in `config.conf` and relogin to resolve this. --- diff --git a/docs/faq.md b/docs/faq.md index 9c9288de..85c9f09e 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -65,7 +65,8 @@ Then force it for your specific game: windowrule=force_tearing:1,title:Counter-Strike 2 ``` -> **Warning:** Some graphics cards require setting `WLR_DRM_NO_ATOMIC=1` before mango starts for tearing to work. Add it to `/etc/environment` and reboot, or launch mango with `WLR_DRM_NO_ATOMIC=1 mango`. See [Monitors — Tearing](/docs/configuration/monitors#tearing-game-mode) for details. +> **Warning:** Some graphics cards require setting `env=WLR_DRM_NO_ATOMIC,1` in config before mango starts for tearing to work. +> See [Monitors — Tearing](/docs/configuration/monitors#tearing-game-mode) for details. --- diff --git a/docs/visuals/status-bar.md b/docs/visuals/status-bar.md index f2924e83..99014b62 100644 --- a/docs/visuals/status-bar.md +++ b/docs/visuals/status-bar.md @@ -7,8 +7,6 @@ description: Configure Waybar for mangowm. mangowm is compatible with Waybar's `ext/workspaces` module (Wayland standard) or the `dwl/tags` module. We recommend `ext/workspaces` for the best experience. -> **Tip:** You can also use the `dwl/tags` module, but `ext/workspaces` provides better integration with mangowm's features. The `ext/workspaces` module requires **Waybar > 0.14.0**. - ### `config.jsonc` Add the following to your Waybar configuration: @@ -16,23 +14,42 @@ Add the following to your Waybar configuration: ```jsonc { "modules-left": [ - "ext/workspaces", - "dwl/window" + "mango/workspaces", + "mango/layout", + "mango/window" ], - "ext/workspaces": { - "format": "{icon}", - "ignore-hidden": true, - "on-click": "activate", - "on-click-right": "deactivate", - "sort-by-id": true + "modules-right": [ + "mango/language", + "mango/keymode", + ], + "mango/workspaces": { + "format": "{icon}", + "hide-empty": true, + "on-click": "activate", + "on-click-right": "toggle", + "overview-label": "OVERVIEW", + }, + "mango/keymode": { + "format": "{}", + // "format-default": " Default", + // "format-test": " Test", + }, + "mango/window": { + "format": "{}", + "icon-size": 20 + }, + "mango/layout": { + "format": "{}", + // "format-S": "Scroller", + // "format-T": "Tile", + }, + "mango/language": { + "format": "{short}", }, - "dwl/window": { - "format": "[{layout}] {title}" - } } ``` -## Styling +## Styling Example You can style the tags using standard CSS in `style.css`. @@ -40,27 +57,13 @@ You can style the tags using standard CSS in `style.css`. ```css #workspaces { - border-radius: 4px; - border-width: 2px; - border-style: solid; border-color: #c9b890; - margin-left: 4px; - padding-left: 10px; - padding-right: 6px; background: rgba(40, 40, 40, 0.76); } #workspaces button { - border: none; background: none; - box-shadow: inherit; - text-shadow: inherit; color: #ddca9e; - padding: 1px; - padding-left: 1px; - padding-right: 1px; - margin-right: 2px; - margin-left: 2px; } #workspaces button.hidden { @@ -79,61 +82,44 @@ You can style the tags using standard CSS in `style.css`. #workspaces button.active { background-color: #ddca9e; color: #282828; - margin-top: 5px; - margin-bottom: 5px; - padding-top: 1px; - padding-bottom: 0px; - border-radius: 3px; } #workspaces button.urgent { background-color: #ef5e5e; color: #282828; - margin-top: 5px; - margin-bottom: 5px; - padding-top: 1px; - padding-bottom: 0px; - border-radius: 3px; } -#tags { - background-color: transparent; -} - -#tags button { - background-color: #fff; - color: #a585cd; -} - -#tags button:not(.occupied):not(.focused) { - font-size: 0; - min-width: 0; - min-height: 0; - margin: -17px; - padding: 0; - color: transparent; - background-color: transparent; -} - -#tags button.occupied { - background-color: #fff; - color: #cdc885; -} - -#tags button.focused { - background-color: rgb(186, 142, 213); - color: #fff; -} - -#tags button.urgent { - background: rgb(171, 101, 101); - color: #fff; +#workspaces button.overview { + background-color: #ef5e5e; + color: #282828; } #window { - background-color: rgb(237, 196, 147); - color: rgb(63, 37, 5); + background-color: #CA9297; + color: #282828; } + +window#waybar.empty #window { + background: none; + margin: 0px; + padding: 0px; +} + +#layout { + background-color: #CA9297; + color: #282828; +} + +#language { + background-color: #CA9297; + color: #282828; +} + +#keymode { + background-color: #CA9297; + color: #282828; +} + ``` ## Complete Configuration Example diff --git a/docs/visuals/theming.md b/docs/visuals/theming.md index 2f9993be..75c90f37 100644 --- a/docs/visuals/theming.md +++ b/docs/visuals/theming.md @@ -69,17 +69,17 @@ You can also color-code windows based on their state: ### Tab Bar For Monocle Layout | Setting | Default | Description | | :--- | :--- | :--- | -| `tab_bar_height` | `50` | Height of the tab bar for monocle layout. | -| `tab_bar_decorate_fg_color` | `0xc4939dff` | text color. -| `tab_bar_decorate_bg_color` | `0x201b14ff` | background color.| -| `tab_bar_decorate_focus_fg_color` | `0x201b14ff` | text color for focus. | -| `tab_bar_decorate_focus_bg_color` | `0xc4939dff` | background color for focus.| -| `tab_bar_decorate_border_color` | `0x8BAA9Bff` | border color.| -| `tab_bar_decorate_border_width` | `4` | border width.| -| `tab_bar_decorate_corner_radius` | `5` | corner radius.| -| `tab_bar_decorate_padding_x` | `0` | horizontal padding.| -| `tab_bar_decorate_padding_y` | `0` | vertical padding.| -| `tab_bar_decorate_font_desc` | `monospace Bold 16` | font set.| +| `group_bar_height` | `50` | Height of the tab bar for monocle layout. | +| `group_bar_decorate_fg_color` | `0xc4939dff` | text color. +| `group_bar_decorate_bg_color` | `0x201b14ff` | background color.| +| `group_bar_decorate_focus_fg_color` | `0x201b14ff` | text color for focus. | +| `group_bar_decorate_focus_bg_color` | `0xc4939dff` | background color for focus.| +| `group_bar_decorate_border_color` | `0x8BAA9Bff` | border color.| +| `group_bar_decorate_border_width` | `4` | border width.| +| `group_bar_decorate_corner_radius` | `5` | corner radius.| +| `group_bar_decorate_padding_x` | `0` | horizontal padding.| +| `group_bar_decorate_padding_y` | `0` | vertical padding.| +| `group_bar_decorate_font_desc` | `monospace Bold 16` | font set.| ## Borders diff --git a/docs/window-management/rules.md b/docs/window-management/rules.md index b5ae81b1..3ef98d35 100644 --- a/docs/window-management/rules.md +++ b/docs/window-management/rules.md @@ -35,6 +35,9 @@ windowrule=Parameter:Values,Parameter:Values,appid:Values,title:Values | `single_scratchpad` | integer | `0` / `1` (default 1) | Only show one out of named scratchpads or the normal scratchpad | | `allow_shortcuts_inhibit` | integer | `0` / `1` (default 1) | Allow shortcuts to be inhibited by clients | | `idleinhibit_when_focus` | integer | `0` / `1` (default 0) | Automatically keep idle inhibit active when this window is focused | +| `vrr_only_fullscreen` | integer | `0` / `1` (default 0) | VRR only fullscreen,you need to turn `vrr` to `0` in monitor rule first | +| `shield_when_capture` | integer | `0` / `1` | Shield window when captured | + ### Geometry & Position @@ -138,7 +141,7 @@ windowrule=offsetx:20,offsety:-30,width:800,height:600,appid:alacritty # Send to specific tag and monitor windowrule=tags:9,monitor:HDMI-A-1,appid:discord -# Terminal swallowing setup +# Terminal swallowdby setup windowrule=isterm:1,appid:st windowrule=noswallow:1,appid:foot @@ -237,6 +240,7 @@ layerrule=layer_name:Values,Parameter:Values,Parameter:Values | `noblur` | integer | `0` / `1` | Disable blur | | `noanim` | integer | `0` / `1` | Disable layer animation | | `noshadow` | integer | `0` / `1` | Disable layer shadow | +| `shield_when_capture`| integer | `0` / `1` | Shield layer when captured.(it is better to combination with `noanim:1`) | > **Tip:** For animation types, see [Animations](/docs/visuals/animations#animation-types). For visual effects, see [Window Effects](/docs/visuals/effects). diff --git a/meson.build b/meson.build index c0c22202..5f0870f4 100644 --- a/meson.build +++ b/meson.build @@ -30,12 +30,12 @@ libdrm = dependency('libdrm') xcb = dependency('xcb', required : get_option('xwayland')) xlibs = dependency('xcb-icccm', required : get_option('xwayland')) wayland_server_dep = dependency('wayland-server',version: '>=1.23.1') -wlroots_dep = dependency('wlroots-0.19',version: '>=0.19.0') +wlroots_dep = dependency('wlroots-0.20',version: '>=0.20.0') xkbcommon_dep = dependency('xkbcommon') libinput_dep = dependency('libinput',version: '>=1.27.1') libwayland_client_dep = dependency('wayland-client') pcre2_dep = dependency('libpcre2-8') -libscenefx_dep = dependency('scenefx-0.4',version: '>=0.4.1') +libscenefx_dep = dependency('scenefx-0.5',version: '>=0.5.0') pixman_dep = dependency('pixman-1') cjson_dep = dependency('libcjson') pangocairo_dep = dependency('pangocairo') @@ -97,7 +97,7 @@ executable('mango', 'src/mango.c', 'src/common/util.c', 'src/draw/text-node.c', - 'src/ext-protocol/wlr_ext_workspace_v1.c', + wayland_sources, dependencies : [ libm, @@ -121,7 +121,6 @@ executable('mango', ) # build mmsg -dwl_ipc_protocol = 'protocols/dwl-ipc-unstable-v2.xml' wayland_scanner_client_header = generator( wayland_scanner, @@ -138,8 +137,6 @@ wayland_scanner_private_code = generator( # use generator in mmsg target executable('mmsg', 'mmsg/mmsg.c', - wayland_scanner_private_code.process(dwl_ipc_protocol), - wayland_scanner_client_header.process(dwl_ipc_protocol), dependencies: [ libwayland_client_dep ], diff --git a/protocols/dwl-ipc-unstable-v2.xml b/protocols/dwl-ipc-unstable-v2.xml deleted file mode 100644 index 5852107e..00000000 --- a/protocols/dwl-ipc-unstable-v2.xml +++ /dev/null @@ -1,253 +0,0 @@ - - - - - This protocol allows clients to update and get updates from dwl. - - Warning! The protocol described in this file is experimental and - backward incompatible changes may be made. Backward compatible - changes may be added together with the corresponding interface - version bump. - Backward incompatible changes are done by bumping the version - number in the protocol and interface names and resetting the - interface version. Once the protocol is to be declared stable, - the 'z' prefix and the version number in the protocol and - interface names are removed and the interface version number is - reset. - - - - - This interface is exposed as a global in wl_registry. - - Clients can use this interface to get a dwl_ipc_output. - After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events. - The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client. - - - - - Indicates that the client will not the dwl_ipc_manager object anymore. - Objects created through this instance are not affected. - - - - - - Get a dwl_ipc_outout for the specified wl_output. - - - - - - - - This event is sent after binding. - A roundtrip after binding guarantees the client recieved all tags. - - - - - - - This event is sent after binding. - A roundtrip after binding guarantees the client recieved all layouts. - - - - - - - - Observe and control a dwl output. - - Events are double-buffered: - Clients should cache events and redraw when a dwl_ipc_output.frame event is sent. - - Request are not double-buffered: - The compositor will update immediately upon request. - - - - - - - - - - - Indicates to that the client no longer needs this dwl_ipc_output. - - - - - - Indicates the client should hide or show themselves. - If the client is visible then hide, if hidden then show. - - - - - - Indicates if the output is active. Zero is invalid, nonzero is valid. - - - - - - - Indicates that a tag has been updated. - - - - - - - - - - Indicates a new layout is selected. - - - - - - - Indicates the title has changed. - - - - - - - Indicates the appid has changed. - - - - - - - Indicates the layout has changed. Since layout symbols are dynamic. - As opposed to the zdwl_ipc_manager.layout event, this should take precendence when displaying. - You can ignore the zdwl_ipc_output.layout event. - - - - - - - Indicates that a sequence of status updates have finished and the client should redraw. - - - - - - - - - - - - The tags are updated as follows: - new_tags = (current_tags AND and_tags) XOR xor_tags - - - - - - - - - - - - This request allows clients to instruct the compositor to quit mango. - - - - - - - - - - - - - - - - Indicates if the selected client on this output is fullscreen. - - - - - - - Indicates if the selected client on this output is floating. - - - - - - - Indicates if x coordinates of the selected client. - - - - - - - Indicates if y coordinates of the selected client. - - - - - - - Indicates if width of the selected client. - - - - - - - Indicates if height of the selected client. - - - - - - - last map layer. - - - - - - - current keyboard layout. - - - - - - - current keybind mode. - - - - - - - scale factor of monitor. - - - - - - - diff --git a/protocols/meson.build b/protocols/meson.build index 922a76ed..925bf42a 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -21,7 +21,6 @@ wayland_xmls = [ wl_protocol_dir + '/staging/ext-workspace/ext-workspace-v1.xml', wl_protocol_dir + '/staging/tearing-control/tearing-control-v1.xml', 'wlr-foreign-toplevel-management-unstable-v1.xml', - 'dwl-ipc-unstable-v2.xml', 'wlr-layer-shell-unstable-v1.xml', 'wlr-output-power-management-unstable-v1.xml', ] diff --git a/src/action/client.h b/src/action/client.h index 876284cd..98f986ad 100644 --- a/src/action/client.h +++ b/src/action/client.h @@ -46,8 +46,8 @@ static void finish_exchange_arrange_and_focus(Client *c1, Client *c2, } else { arrange(c1->mon, false, false); } - wl_list_remove(&c2->flink); - wl_list_insert(&c1->flink, &c2->flink); + + wl_list_safe_reinsert_next(&c1->flink, &c2->flink); if (config.warpcursor) warp_cursor(c1); @@ -57,7 +57,14 @@ void client_tile_resize(Client *c, struct wlr_box geo, int32_t interact) { if (!ISFAKETILED(c)) return; - if (!c->isfullscreen && !c->ismaximizescreen) { + if (!c->mon->isoverview && !c->isfullscreen && + (c->group_next || c->group_prev)) { + geo.y = geo.y + config.group_bar_height; + geo.height -= config.group_bar_height; + } + + if ((!c->isfullscreen && !c->ismaximizescreen) || + is_scroller_layout(c->mon)) { resize(c, geo, interact); } } @@ -73,7 +80,7 @@ void client_active(Client *c) { return; } - if (c->swallowing || !c->mon) + if (c->swallowdby || !c->mon) return; if (c->isminimized) { @@ -104,19 +111,199 @@ void client_add_jump_label_node(Client *c) { wlr_scene_node_set_enabled(&c->jump_label_node->scene_buffer->node, false); } -void client_add_tab_bar_node(Client *c) { +void client_add_group_bar(Client *c) { - if (config.tab_bar_height <= 0) { + if (config.group_bar_height <= 0) { return; } - MangoNodeData *mangonodedata = ecalloc(1, sizeof(MangoNodeData)); - mangonodedata->node_data = c; - mangonodedata->type = MANGO_TITLE_NODE; + uint32_t layer = c->isoverlay ? LyrOverlay + : c->isfloating || c->isfullscreen ? LyrTop + : c->ismaximizescreen ? LyrMaximize + : LyrTile; - c->tab_bar_node = mango_tab_bar_node_create( - mangonodedata, layers[LyrDecorate], config.tabdata, 0, 0); - wlr_scene_node_lower_to_bottom(&c->tab_bar_node->scene_buffer->node); - wlr_scene_node_set_enabled(&c->tab_bar_node->scene_buffer->node, false); - mango_tab_bar_node_update(c->tab_bar_node, client_get_title(c), 1.0); + c->group_bar = mango_group_bar_create(c, GroupBar, layers[layer], + config.groupbardata, 0, 0); + wlr_scene_node_lower_to_bottom(&c->group_bar->scene_buffer->node); + wlr_scene_node_set_enabled(&c->group_bar->scene_buffer->node, false); + mango_group_bar_update(c->group_bar, client_get_title(c), + c->mon ? c->mon->wlr_output->scale + : selmon ? selmon->wlr_output->scale + : 1.0f); } + +void client_focus_group_member(Client *c) { + if (!c->group_prev && !c->group_next) + return; + + if (c->isgroupfocusing) + return; + + Client *head = c; + while (head->group_prev) + head = head->group_prev; + + Client *cur_focusing = NULL; + while (head) { + if (head->isgroupfocusing) { + cur_focusing = head; + break; + } + head = head->group_next; + } + + if (!cur_focusing || !cur_focusing->mon) + return; + + if (cur_focusing && cur_focusing->mon->isoverview) + return; + + cur_focusing->isgroupfocusing = false; + c->mon = cur_focusing->mon; + client_replace(c, cur_focusing, true, false); + mango_group_bar_set_focus(cur_focusing->group_bar, false); + + c->isgroupfocusing = true; + mango_group_bar_set_focus(c->group_bar, true); + + client_reparent_group(c); + + focusclient(c, 1); + + arrange(c->mon, false, false); +} + +void client_check_tab_node_visible(Client *c) { + + if (!c || !c->mon) + return; + + Client *head = c; + while (head->group_prev) + head = head->group_prev; + + Client *cur = head; + while (cur) { + if (!c->mon->isoverview && cur->group_bar && + (cur->group_next || cur->group_prev) && TAGMATCH(c, c->mon) && + ISNORMAL(c) && !c->isfullscreen) { + wlr_scene_node_set_enabled(&cur->group_bar->scene_buffer->node, + true); + } else { + wlr_scene_node_set_enabled(&cur->group_bar->scene_buffer->node, + false); + } + cur = cur->group_next; + } +} + +void client_raise_group(Client *c) { + if (!c || !c->mon) + return; + + Client *head = c; + while (head->group_prev) + head = head->group_prev; + + Client *cur = head; + while (cur) { + if (cur->group_bar) { + wlr_scene_node_raise_to_top(&cur->group_bar->scene_buffer->node); + } + wlr_scene_node_raise_to_top(&cur->scene->node); + cur = cur->group_next; + } +} + +void client_reparent_group(Client *c) { + if (!c || !c->mon) + return; + + int32_t layer = c->isoverlay ? LyrOverlay + : c->isfloating || c->isfullscreen ? LyrTop + : c->ismaximizescreen ? LyrMaximize + : LyrTile; + + Client *head = c; + while (head->group_prev) + head = head->group_prev; + + Client *cur = head; + while (cur) { + if (cur->group_bar) { + wlr_scene_node_reparent(&cur->group_bar->scene_buffer->node, + layers[layer]); + } + wlr_scene_node_reparent(&cur->scene->node, layers[layer]); + cur = cur->group_next; + } +} + +void client_handle_decorate_click(MangoGroupBar *gb) { + + if (!gb) + return; + + if (gb->node_data) { + Client *c = gb->node_data; + client_focus_group_member(c); + } +} + +void client_set_group_mon(Client *c, Monitor *m) { + Client *head = c; + while (head->group_prev) + head = head->group_prev; + + Client *cur = head; + while (cur) { + client_change_mon(cur, m); + cur = cur->group_next; + } +} + +void client_set_group_config(Client *c) { + Client *head = c; + while (head->group_prev) + head = head->group_prev; + + Client *cur = head; + while (cur) { + mango_jump_label_node_apply_config(cur->jump_label_node, + &config.jumplabeldata); + wlr_scene_rect_set_color(cur->droparea, config.dropcolor); + wlr_scene_rect_set_color(cur->splitindicator[0], config.splitcolor); + wlr_scene_rect_set_color(cur->splitindicator[1], config.splitcolor); + mango_group_bar_apply_config(cur->group_bar, &config.groupbardata); + cur = cur->group_next; + } +} + +void client_group_detach(Client *c) { + if (c->group_prev) + c->group_prev->group_next = c->group_next; + if (c->group_next) + c->group_next->group_prev = c->group_prev; + c->group_prev = NULL; + c->group_next = NULL; + c->isgroupfocusing = false; +} + +void client_group_replace(Client *old, Client *new) { + client_group_detach(new); + + new->group_prev = old->group_prev; + new->group_next = old->group_next; + if (old->group_prev) + old->group_prev->group_next = new; + if (old->group_next) + old->group_next->group_prev = new; + old->group_prev = NULL; + old->group_next = NULL; + + if (old->is_logic_hide || (!new->group_prev && !new->group_next)) { + new->isgroupfocusing = false; + } else { + new->isgroupfocusing = old->isgroupfocusing; + } +} \ No newline at end of file diff --git a/src/action/monitor.h b/src/action/monitor.h new file mode 100644 index 00000000..434fb159 --- /dev/null +++ b/src/action/monitor.h @@ -0,0 +1,61 @@ +bool mango_scene_output_commit(struct wlr_scene_output *scene_output, + struct wlr_output_state *state) { + struct wlr_output *wlr_output = scene_output->output; + Monitor *m = wlr_output->data; + bool committed = false; + + bool frame_allow_tearing = check_tearing_frame_allow(m); + + if (!wlr_scene_output_needs_frame(scene_output)) + return true; + + // 构建状态,将场景的 Buffer 附着到 state 上 + if (!wlr_scene_output_build_state(scene_output, state, NULL)) + return false; + + if (frame_allow_tearing) { + state->tearing_page_flip = true; + } else { + state->tearing_page_flip = false; + } + + // 测试是否支持撕裂 + if (state->tearing_page_flip == true) { + if (!wlr_output_test_state(wlr_output, state)) { + // 如果 DRM 拒绝(例如当前输出/驱动不支持撕裂),降级关闭撕裂 + state->tearing_page_flip = false; + } + } + + // 提交状态 + committed = wlr_output_commit_state(wlr_output, state); + if (!committed && state->tearing_page_flip) { + // 重试一次 + state->tearing_page_flip = false; + committed = wlr_output_commit_state(wlr_output, state); + } + + if (committed) { + if (state == &m->pending) { + wlr_output_state_finish(&m->pending); + wlr_output_state_init(&m->pending); + } + } else { + wlr_log(WLR_INFO, "Failed to commit output %s", m->wlr_output->name); + return false; + } + + return committed; +} + +bool mango_output_commit(Monitor *m) { + + bool committed = wlr_output_commit_state(m->wlr_output, &m->pending); + if (committed) { + wlr_output_state_finish(&m->pending); + wlr_output_state_init(&m->pending); + } else { + wlr_log(WLR_ERROR, "Failed to commit frame"); + } + return committed; +} \ No newline at end of file diff --git a/src/animation/client.h b/src/animation/client.h index 79544cd2..03466f37 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -1,7 +1,27 @@ #include "wlr/util/log.h" + +static inline bool client_is_ignore_output_clip(Client *c) { + return c == grabc || (!ISSCROLLTILED(c) && !c->animation.tagining && + !c->animation.tagouting); +} + +static inline struct ivec2 compute_edge_offsets(Client *c) { + struct ivec2 offsets = {0}; + if (client_is_ignore_output_clip(c)) + return offsets; + + struct wlr_box cur = c->animation.current; + offsets.width = + GEZERO(cur.x + cur.width - c->mon->m.x - c->mon->m.width); // right + offsets.height = + GEZERO(cur.y + cur.height - c->mon->m.y - c->mon->m.height); // bottom + offsets.x = GEZERO(c->mon->m.x - cur.x); // left + offsets.y = GEZERO(c->mon->m.y - cur.y); // top + return offsets; +} + void client_actual_size(Client *c, int32_t *width, int32_t *height) { *width = c->animation.current.width - 2 * (int32_t)c->bw; - *height = c->animation.current.height - 2 * (int32_t)c->bw; } @@ -9,48 +29,52 @@ void set_rect_size(struct wlr_scene_rect *rect, int32_t width, int32_t height) { wlr_scene_rect_set_size(rect, GEZERO(width), GEZERO(height)); } -enum corner_location set_client_corner_location(Client *c) { - enum corner_location current_corner_location = CORNER_LOCATION_ALL; +struct fx_corner_radii set_client_corner_location(Client *c) { + struct fx_corner_radii current_corner_location = + corner_radii_all(config.border_radius); + + if (client_is_ignore_output_clip(c)) + return current_corner_location; + struct wlr_box target_geom = config.animations ? c->animation.current : c->geom; if (target_geom.x + config.border_radius <= c->mon->m.x) { - current_corner_location &= ~CORNER_LOCATION_LEFT; + current_corner_location.top_left = 0; + current_corner_location.bottom_left = 0; } if (target_geom.x + target_geom.width - config.border_radius >= c->mon->m.x + c->mon->m.width) { - current_corner_location &= ~CORNER_LOCATION_RIGHT; + current_corner_location.top_right = 0; + current_corner_location.bottom_right = 0; } if (target_geom.y + config.border_radius <= c->mon->m.y) { - current_corner_location &= ~CORNER_LOCATION_TOP; + current_corner_location.top_left = 0; + current_corner_location.top_right = 0; } if (target_geom.y + target_geom.height - config.border_radius >= c->mon->m.y + c->mon->m.height) { - current_corner_location &= ~CORNER_LOCATION_BOTTOM; + current_corner_location.bottom_left = 0; + current_corner_location.bottom_right = 0; } return current_corner_location; } bool is_horizontal_stack_layout(Monitor *m) { - if (m->pertag->curtag && (m->pertag->ltidxs[m->pertag->curtag]->id == TILE || m->pertag->ltidxs[m->pertag->curtag]->id == DECK)) return true; - return false; } bool is_horizontal_right_stack_layout(Monitor *m) { - if (m->pertag->curtag && - (m->pertag->ltidxs[m->pertag->curtag]->id == RIGHT_TILE)) + m->pertag->ltidxs[m->pertag->curtag]->id == RIGHT_TILE) return true; - return false; } int32_t is_special_animation_rule(Client *c) { - if (is_scroller_layout(c->mon) && !c->isfloating) { return DOWN; } else if (c->mon->visible_tiling_clients == 1 && !c->isfloating) { @@ -171,30 +195,25 @@ void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int32_t sx, BufferData *buffer_data = (BufferData *)data; if (buffer_data->should_scale && buffer_data->height_scale < 1 && - buffer_data->width_scale < 1) { + buffer_data->width_scale < 1) buffer_data->should_scale = false; - } if (buffer_data->should_scale && buffer_data->height_scale == 1 && - buffer_data->width_scale < 1) { + buffer_data->width_scale < 1) buffer_data->should_scale = false; - } if (buffer_data->should_scale && buffer_data->height_scale < 1 && - buffer_data->width_scale == 1) { + buffer_data->width_scale == 1) buffer_data->should_scale = false; - } struct wlr_scene_surface *scene_surface = wlr_scene_surface_try_from_buffer(buffer); - if (scene_surface == NULL) return; struct wlr_surface *surface = scene_surface->surface; if (buffer_data->should_scale) { - int32_t surface_width = surface->current.width; int32_t surface_height = surface->current.height; @@ -206,53 +225,47 @@ void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int32_t sx, : buffer_data->height_scale * surface_height; if (surface_width > buffer_data->width && - wlr_subsurface_try_from_wlr_surface(surface) == NULL) { + wlr_subsurface_try_from_wlr_surface(surface) == NULL) surface_width = buffer_data->width; - } if (surface_height > buffer_data->height && - wlr_subsurface_try_from_wlr_surface(surface) == NULL) { + wlr_subsurface_try_from_wlr_surface(surface) == NULL) surface_height = buffer_data->height; - } if (surface_width > buffer_data->width && - wlr_subsurface_try_from_wlr_surface(surface) != NULL) { + wlr_subsurface_try_from_wlr_surface(surface) != NULL) return; - } if (surface_height > buffer_data->height && - wlr_subsurface_try_from_wlr_surface(surface) != NULL) { + wlr_subsurface_try_from_wlr_surface(surface) != NULL) return; - } - if (surface_height > 0 && surface_width > 0) { + if (surface_height > 0 && surface_width > 0) wlr_scene_buffer_set_dest_size(buffer, surface_width, surface_height); - } } - // TODO: blur set, opacity set if (wlr_xdg_popup_try_from_wlr_surface(surface) != NULL) return; - wlr_scene_buffer_set_corner_radius(buffer, config.border_radius, - buffer_data->corner_location); + wlr_scene_buffer_set_corner_radii(buffer, buffer_data->corner_location); } void scene_buffer_apply_overview_effect(struct wlr_scene_buffer *buffer, int32_t sx, int32_t sy, void *data) { BufferData *buffer_data = (BufferData *)data; - int32_t surface_width = 0; - int32_t surface_height = 0; + int32_t surface_width = 0, surface_height = 0; bool is_subsurface = false; struct wlr_scene_tree *parent_tree = buffer->node.parent; - if (parent_tree->node.data != NULL) { - SnapshotMetadata *meta = (SnapshotMetadata *)parent_tree->node.data; + SnapshotMetadata *meta = (SnapshotMetadata *)parent_tree->node.data; + if (parent_tree->node.data != NULL && meta->type == Snapshot) { surface_width = meta->orig_width; surface_height = meta->orig_height; is_subsurface = meta->is_subsurface; + } else { + return; } surface_height = surface_height * buffer_data->height_scale; @@ -268,40 +281,36 @@ void scene_buffer_apply_overview_effect(struct wlr_scene_buffer *buffer, if (is_subsurface) return; - wlr_scene_buffer_set_corner_radius(buffer, config.border_radius, - buffer_data->corner_location); + wlr_scene_buffer_set_corner_radii(buffer, buffer_data->corner_location); } void buffer_set_effect(Client *c, BufferData data) { - if (!c || c->iskilling) return; if (c->animation.tagouting || c->animation.tagouted || - c->animation.tagining) { + c->animation.tagining) data.should_scale = false; - } if (c == grabc) data.should_scale = false; - if (c->isnoradius || c->isfullscreen || - (config.no_radius_when_single && c->mon && - c->mon->visible_tiling_clients == 1)) { - data.corner_location = CORNER_LOCATION_NONE; - } + if (c->isfullscreen || (config.no_radius_when_single && c->mon && + c->mon->visible_tiling_clients == 1)) + data.corner_location = corner_radii_none(); - if (c->overview_scene_surface) { + if (config.blur && !c->noblur) + wlr_scene_blur_set_corner_radii(c->blur, data.corner_location); + + if (c->overview_scene_surface) wlr_scene_node_for_each_buffer( &c->scene_surface->node, scene_buffer_apply_overview_effect, &data); - } else { + else wlr_scene_node_for_each_buffer(&c->scene_surface->node, scene_buffer_apply_effect, &data); - } } -void client_draw_shadow(Client *c) { - +void client_draw_shadow(Client *c, struct ivec2 offsets) { if (c->iskilling || !client_surface(c)->mapped || c->isnoshadow) return; @@ -316,24 +325,25 @@ void client_draw_shadow(Client *c) { } bool hit_no_border = check_hit_no_border(c); - enum corner_location current_corner_location = + struct fx_corner_radii current_corner_location = c->isfullscreen || (config.no_radius_when_single && c->mon && c->mon->visible_tiling_clients == 1) - ? CORNER_LOCATION_NONE - : CORNER_LOCATION_ALL; + ? corner_radii_none() + : set_client_corner_location(c); - int32_t bwoffset = c->bw != 0 && hit_no_border ? (int32_t)c->bw : 0; + int32_t bw = (int32_t)c->bw; + int32_t bwoffset = bw != 0 && hit_no_border ? bw : 0; int32_t width, height; client_actual_size(c, &width, &height); - int32_t delta = config.shadows_size + (int32_t)c->bw - bwoffset; + int32_t delta = config.shadows_size + bw - bwoffset; struct wlr_box client_box = { .x = bwoffset, .y = bwoffset, - .width = width + 2 * (int32_t)c->bw - 2 * bwoffset, - .height = height + 2 * (int32_t)c->bw - 2 * bwoffset, + .width = width + 2 * bw - 2 * bwoffset, + .height = height + 2 * bw - 2 * bwoffset, }; struct wlr_box shadow_box = { @@ -350,70 +360,212 @@ void client_draw_shadow(Client *c) { struct clipped_region clipped_region = { .area = intersection_box, - .corner_radius = config.border_radius, .corners = current_corner_location, }; + struct wlr_box cur = c->animation.current; struct wlr_box absolute_shadow_box = { - .x = shadow_box.x + c->animation.current.x, - .y = shadow_box.y + c->animation.current.y, + .x = shadow_box.x + cur.x, + .y = shadow_box.y + cur.y, .width = shadow_box.width, .height = shadow_box.height, }; - int32_t right_offset, bottom_offset, left_offset, top_offset; - - if (c == grabc) { - right_offset = 0; - bottom_offset = 0; - left_offset = 0; - top_offset = 0; + int32_t left, right, top, bottom; + if (client_is_ignore_output_clip(c)) { + left = right = top = bottom = 0; } else { - right_offset = - GEZERO(absolute_shadow_box.x + absolute_shadow_box.width - - c->mon->m.x - c->mon->m.width); - bottom_offset = - GEZERO(absolute_shadow_box.y + absolute_shadow_box.height - - c->mon->m.y - c->mon->m.height); - - left_offset = GEZERO(c->mon->m.x - absolute_shadow_box.x); - top_offset = GEZERO(c->mon->m.y - absolute_shadow_box.y); + right = GEZERO(absolute_shadow_box.x + absolute_shadow_box.width - + c->mon->m.x - c->mon->m.width); + bottom = GEZERO(absolute_shadow_box.y + absolute_shadow_box.height - + c->mon->m.y - c->mon->m.height); + left = GEZERO(c->mon->m.x - absolute_shadow_box.x); + top = GEZERO(c->mon->m.y - absolute_shadow_box.y); } - left_offset = MANGO_MIN(left_offset, shadow_box.width); - right_offset = MANGO_MIN(right_offset, shadow_box.width); - top_offset = MANGO_MIN(top_offset, shadow_box.height); - bottom_offset = MANGO_MIN(bottom_offset, shadow_box.height); + left = MANGO_MIN(left, shadow_box.width); + right = MANGO_MIN(right, shadow_box.width); + top = MANGO_MIN(top, shadow_box.height); + bottom = MANGO_MIN(bottom, shadow_box.height); - wlr_scene_node_set_position(&c->shadow->node, shadow_box.x + left_offset, - shadow_box.y + top_offset); + wlr_scene_node_set_position(&c->shadow->node, shadow_box.x + left, + shadow_box.y + top); - wlr_scene_shadow_set_size( - c->shadow, GEZERO(shadow_box.width - left_offset - right_offset), - GEZERO(shadow_box.height - top_offset - bottom_offset)); + wlr_scene_shadow_set_size(c->shadow, + GEZERO(shadow_box.width - left - right), + GEZERO(shadow_box.height - top - bottom)); - clipped_region.area.x = clipped_region.area.x - left_offset; - clipped_region.area.y = clipped_region.area.y - top_offset; + clipped_region.area.x = clipped_region.area.x - left; + clipped_region.area.y = clipped_region.area.y - top; wlr_scene_shadow_set_clipped_region(c->shadow, clipped_region); } -void global_draw_tab_bar(Client *c, int32_t x, int32_t y, int32_t width, - int32_t height) { - if (!c->tab_bar_node) +void client_draw_groupbar(Client *c, struct ivec2 offsets) { + if (!c || !c->group_bar) return; - if (height <= 0) { - wlr_scene_node_set_enabled(&c->tab_bar_node->scene_buffer->node, false); + if (!c->group_next && !c->group_prev && + c->group_bar->scene_buffer->node.enabled) { + wlr_scene_node_set_enabled(&c->group_bar->scene_buffer->node, false); + return; } - wlr_scene_node_set_position(&c->tab_bar_node->scene_buffer->node, x, y); - wlr_scene_node_set_enabled(&c->tab_bar_node->scene_buffer->node, true); - mango_tab_bar_node_set_size(c->tab_bar_node, width, height); + if (c->is_logic_hide) + return; + + if (!c->group_next && !c->group_prev) + return; + + Client *head = c; + while (head->group_prev) + head = head->group_prev; + + int count = 0; + Client *cur = head; + while (cur) { + count++; + cur = cur->group_next; + } + + int32_t tab_x = c->animation.current.x; + int32_t tab_y = c->animation.current.y - config.group_bar_height; + int32_t tw = c->animation.current.width; + int32_t th = config.group_bar_height; + + int32_t top_over = offsets.y; // top + int32_t bottom_over = offsets.height; // bottom + int32_t left_over = offsets.x; // left + int32_t right_over = offsets.width; // right + + if (top_over > 0) { + tab_y = c->mon->m.y; + th = config.group_bar_height - top_over; + } + if (bottom_over > 0) + th = th - bottom_over; + if (right_over > 0) + tw = tw - right_over; + if (left_over > 0) { + tab_x = c->mon->m.x; + tw = tw - left_over; + } + + if (tw <= 0 || th <= 0) { + cur = head; + while (cur) { + if (cur->group_bar) + wlr_scene_node_set_enabled(&cur->group_bar->scene_buffer->node, + false); + cur = cur->group_next; + } + return; + } else { + client_check_tab_node_visible(c); + } + + int32_t bar_w = tw / count; + int32_t rem = tw % count; + int32_t x = tab_x; + cur = head; + + for (int i = 0; i < count && cur; i++) { + int32_t w = bar_w + (i < rem ? 1 : 0); + global_draw_group_bar(cur, x, tab_y, w, th); + x += w; + cur = cur->group_next; + } } -void apply_split_border(Client *c, bool hit_no_border) { +void client_draw_shield(Client *c, struct ivec2 clip_box) { + int32_t shield_x = 0; + int32_t shield_y = 0; + int32_t shield_width = 0; + int32_t shield_height = 0; + + if (active_capture_count <= 0 || !c->shield_when_capture) { + if (c->shield->node.enabled) { + wlr_scene_node_lower_to_bottom(&c->shield->node); + wlr_scene_node_set_position(&c->shield->node, 0, 0); + wlr_scene_rect_set_size(c->shield, c->animation.current.width, + c->animation.current.height); + wlr_scene_node_set_enabled(&c->shield->node, false); + } + return; + } + + if (client_is_ignore_output_clip(c)) { + shield_x = c->bw; + shield_y = c->bw; + shield_width = c->animation.current.width - 2 * (int32_t)c->bw; + shield_height = c->animation.current.height - 2 * (int32_t)c->bw; + } else { + shield_x = clip_box.x + (int32_t)c->bw; + shield_y = clip_box.y + (int32_t)c->bw; + shield_width = c->animation.current.width - 2 * (int32_t)c->bw - + clip_box.width - clip_box.x; + shield_height = c->animation.current.height - 2 * (int32_t)c->bw - + clip_box.height - clip_box.y; + } + + if (shield_width <= 0 || shield_height <= 0) { + wlr_scene_node_set_enabled(&c->shield->node, false); + return; + } + + wlr_scene_node_raise_to_top(&c->shield->node); + wlr_scene_node_set_position(&c->shield->node, shield_x, shield_y); + wlr_scene_rect_set_size(c->shield, shield_width, shield_height); + wlr_scene_node_set_enabled(&c->shield->node, true); +} + +void client_draw_blur(Client *c, struct ivec2 clip_box) { + if (c->isfullscreen) { + if (c->blur->node.enabled) + wlr_scene_node_set_enabled(&c->blur->node, false); + return; + } + + int32_t blur_x = 0; + int32_t blur_y = 0; + int32_t blur_width = 0; + int32_t blur_height = 0; + + if (config.blur && !c->noblur) { + + if (client_is_ignore_output_clip(c)) { + blur_x = c->bw; + blur_y = c->bw; + blur_width = c->animation.current.width - 2 * (int32_t)c->bw; + blur_height = c->animation.current.height - 2 * (int32_t)c->bw; + } + + blur_x = clip_box.x + (int32_t)c->bw; + blur_y = clip_box.y + (int32_t)c->bw; + blur_width = c->animation.current.width - 2 * (int32_t)c->bw - + clip_box.width - clip_box.x; + blur_height = c->animation.current.height - 2 * (int32_t)c->bw - + clip_box.height - clip_box.y; + wlr_scene_node_set_enabled(&c->blur->node, true); + wlr_scene_node_set_position(&c->blur->node, blur_x, blur_y); + wlr_scene_blur_set_size(c->blur, blur_width, blur_height); + } else { + wlr_scene_node_set_enabled(&c->blur->node, false); + } +} + +void global_draw_group_bar(Client *c, int32_t x, int32_t y, int32_t width, + int32_t height) { + if (!c->group_bar) + return; + + wlr_scene_node_set_position(&c->group_bar->scene_buffer->node, x, y); + mango_group_bar_set_size(c->group_bar, width, height); +} + +void client_draw_split_border(Client *c, bool hit_no_border, + struct ivec2 offsets) { if (c->iskilling || !c->mon || !client_surface(c)->mapped) return; @@ -421,78 +573,55 @@ void apply_split_border(Client *c, bool hit_no_border) { if (hit_no_border || !ISTILED(c) || layout->id != DWINDLE || !config.dwindle_manual_split || c->isfullscreen) { - if (c->splitindicator[0]->node.enabled) { + if (c->splitindicator[0]->node.enabled) wlr_scene_node_set_enabled(&c->splitindicator[0]->node, false); - } - if (c->splitindicator[1]->node.enabled) { + if (c->splitindicator[1]->node.enabled) wlr_scene_node_set_enabled(&c->splitindicator[1]->node, false); - } return; + } + + DwindleNode **root = &c->mon->pertag->dwindle_root[c->mon->pertag->curtag]; + DwindleNode *dnode = dwindle_find_leaf(*root, c); + if (!dnode) { + wlr_scene_node_set_enabled(&c->splitindicator[0]->node, false); + wlr_scene_node_set_enabled(&c->splitindicator[1]->node, false); + return; + } + + if (dnode->custom_leaf_split_h) { + wlr_scene_node_set_enabled(&c->splitindicator[0]->node, false); + wlr_scene_node_set_enabled(&c->splitindicator[1]->node, true); } else { - - DwindleNode **root = - &c->mon->pertag->dwindle_root[c->mon->pertag->curtag]; - DwindleNode *dnode = dwindle_find_leaf(*root, c); - - if (!dnode) { - wlr_scene_node_set_enabled(&c->splitindicator[0]->node, false); - wlr_scene_node_set_enabled(&c->splitindicator[1]->node, false); - return; - } else { - if (dnode->custom_leaf_split_h) { - wlr_scene_node_set_enabled(&c->splitindicator[0]->node, false); - wlr_scene_node_set_enabled(&c->splitindicator[1]->node, true); - } else { - wlr_scene_node_set_enabled(&c->splitindicator[0]->node, true); - wlr_scene_node_set_enabled(&c->splitindicator[1]->node, false); - } - } + wlr_scene_node_set_enabled(&c->splitindicator[0]->node, true); + wlr_scene_node_set_enabled(&c->splitindicator[1]->node, false); } struct wlr_box fullgeom = c->animation.current; - // 一但在GEZERO如果使用无符号,那么其他数据也会转换为无符号导致没有负数出错 int32_t bw = (int32_t)c->bw; - - int32_t right_offset, bottom_offset, left_offset, top_offset; - - if (c == grabc) { - right_offset = 0; - bottom_offset = 0; - left_offset = 0; - top_offset = 0; - } else { - right_offset = - GEZERO(c->animation.current.x + c->animation.current.width - - c->mon->m.x - c->mon->m.width); - bottom_offset = - GEZERO(c->animation.current.y + c->animation.current.height - - c->mon->m.y - c->mon->m.height); - - left_offset = GEZERO(c->mon->m.x - c->animation.current.x); - top_offset = GEZERO(c->mon->m.y - c->animation.current.y); - } + int32_t left = offsets.x, right = offsets.width, top = offsets.y, + bottom = offsets.height; int32_t border_down_width = GEZERO(fullgeom.width - 2 * config.border_radius - - GEZERO((left_offset + right_offset) - config.border_radius)); + GEZERO((left + right) - config.border_radius)); int32_t border_down_height = - GEZERO(bw - bottom_offset - GEZERO(top_offset + bw - fullgeom.height)); + GEZERO(bw - bottom - GEZERO(top + bw - fullgeom.height)); int32_t border_right_width = - GEZERO(bw - right_offset - GEZERO(left_offset + bw - fullgeom.width)); + GEZERO(bw - right - GEZERO(left + bw - fullgeom.width)); int32_t border_right_height = GEZERO(fullgeom.height - 2 * config.border_radius - - GEZERO((top_offset + bottom_offset) - config.border_radius)); + GEZERO((top + bottom) - config.border_radius)); - int32_t border_down_x = GEZERO(config.border_radius + - GEZERO(left_offset - config.border_radius)); - int32_t border_down_y = GEZERO(fullgeom.height - bw) + - GEZERO(top_offset + bw - fullgeom.height); + int32_t border_down_x = + GEZERO(config.border_radius + GEZERO(left - config.border_radius)); + int32_t border_down_y = + GEZERO(fullgeom.height - bw) + GEZERO(top + bw - fullgeom.height); int32_t border_right_x = - GEZERO(fullgeom.width - bw) + GEZERO(left_offset + bw - fullgeom.width); - int32_t border_right_y = GEZERO(config.border_radius + - GEZERO(top_offset - config.border_radius)); + GEZERO(fullgeom.width - bw) + GEZERO(left + bw - fullgeom.width); + int32_t border_right_y = + GEZERO(config.border_radius + GEZERO(top - config.border_radius)); set_rect_size(c->splitindicator[0], border_down_width, border_down_height); set_rect_size(c->splitindicator[1], border_right_width, @@ -503,33 +632,31 @@ void apply_split_border(Client *c, bool hit_no_border) { border_right_y); } -void apply_border(Client *c) { +void client_draw_border(Client *c, struct ivec2 offsets) { if (!c || c->iskilling || !client_surface(c)->mapped) return; if (c->isfullscreen) { if (c->border->node.enabled) { wlr_scene_node_set_position(&c->scene_surface->node, 0, 0); + wlr_scene_node_set_enabled(&c->splitindicator[0]->node, false); + wlr_scene_node_set_enabled(&c->splitindicator[1]->node, false); wlr_scene_node_set_enabled(&c->border->node, false); } return; } else { - if (!c->border->node.enabled) { + if (!c->border->node.enabled) wlr_scene_node_set_enabled(&c->border->node, true); - } } bool hit_no_border = check_hit_no_border(c); + client_draw_split_border(c, hit_no_border, offsets); - apply_split_border(c, hit_no_border); - - enum corner_location current_corner_location; - if (c->isfullscreen || (config.no_radius_when_single && c->mon && - c->mon->visible_tiling_clients == 1)) { - current_corner_location = CORNER_LOCATION_NONE; - } else { - current_corner_location = set_client_corner_location(c); - } + struct fx_corner_radii current_corner_location = + c->isfullscreen || (config.no_radius_when_single && c->mon && + c->mon->visible_tiling_clients == 1) + ? corner_radii_none() + : set_client_corner_location(c); if (hit_no_border && config.smartgaps) { c->bw = 0; @@ -544,136 +671,81 @@ void apply_border(Client *c) { c->fake_no_border = false; } - struct wlr_box clip_box = c->animation.current; - // 一但在GEZERO如果使用无符号,那么其他数据也会转换为无符号导致没有负数出错 + struct wlr_box cur = c->animation.current; int32_t bw = (int32_t)c->bw; + int32_t left = offsets.x, right = offsets.width, top = offsets.y, + bottom = offsets.height; - int32_t right_offset, bottom_offset, left_offset, top_offset; + int32_t inner_surface_width = GEZERO(cur.width - 2 * bw); + int32_t inner_surface_height = GEZERO(cur.height - 2 * bw); + int32_t inner_surface_x = GEZERO(bw - left); + int32_t inner_surface_y = GEZERO(bw - top); - if (c == grabc) { - right_offset = 0; - bottom_offset = 0; - left_offset = 0; - top_offset = 0; - } else { - right_offset = - GEZERO(c->animation.current.x + c->animation.current.width - - c->mon->m.x - c->mon->m.width); - bottom_offset = - GEZERO(c->animation.current.y + c->animation.current.height - - c->mon->m.y - c->mon->m.height); + int32_t rect_x = left; + int32_t rect_y = top; + int32_t rect_width = GEZERO(cur.width - left - right); + int32_t rect_height = GEZERO(cur.height - top - bottom); - left_offset = GEZERO(c->mon->m.x - c->animation.current.x); - top_offset = GEZERO(c->mon->m.y - c->animation.current.y); - } - - int32_t inner_surface_width = GEZERO(clip_box.width - 2 * bw); - int32_t inner_surface_height = GEZERO(clip_box.height - 2 * bw); - - int32_t inner_surface_x = GEZERO(bw - left_offset); - int32_t inner_surface_y = GEZERO(bw - top_offset); - - int32_t rect_x = left_offset; - int32_t rect_y = top_offset; - - int32_t rect_width = - GEZERO(c->animation.current.width - left_offset - right_offset); - int32_t rect_height = - GEZERO(c->animation.current.height - top_offset - bottom_offset); - - if (left_offset > c->bw) - inner_surface_width = - inner_surface_width - left_offset + (int32_t)c->bw; - - if (top_offset > c->bw) + if (left > c->bw) + inner_surface_width = inner_surface_width - left + bw; + if (top > c->bw) + inner_surface_height = inner_surface_height - top + bw; + if (right > 0) + inner_surface_width = MANGO_MIN(cur.width, inner_surface_width + right); + if (bottom > 0) inner_surface_height = - inner_surface_height - top_offset + (int32_t)c->bw; - - if (right_offset > 0) { - inner_surface_width = - MANGO_MIN(clip_box.width, inner_surface_width + right_offset); - } - - if (bottom_offset > 0) { - inner_surface_height = - MANGO_MIN(clip_box.height, inner_surface_height + bottom_offset); - } + MANGO_MIN(cur.height, inner_surface_height + bottom); struct clipped_region clipped_region = { .area = {inner_surface_x, inner_surface_y, inner_surface_width, inner_surface_height}, - .corner_radius = config.border_radius, .corners = current_corner_location, }; wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw); wlr_scene_rect_set_size(c->border, rect_width, rect_height); wlr_scene_node_set_position(&c->border->node, rect_x, rect_y); - wlr_scene_rect_set_corner_radius(c->border, config.border_radius, - current_corner_location); + wlr_scene_rect_set_corner_radii(c->border, current_corner_location); wlr_scene_rect_set_clipped_region(c->border, clipped_region); } -struct ivec2 clip_to_hide(Client *c, struct wlr_box *clip_box) { - int32_t offsetx = 0, offsety = 0, offsetw = 0, offseth = 0; - struct ivec2 offset = {0, 0, 0, 0}; +struct ivec2 clip_to_hide(Client *c, struct wlr_box *clip_box, + struct ivec2 offsets) { + struct ivec2 offset = {0}; if (!ISSCROLLTILED(c) && !c->animation.tagining && !c->animation.tagouted && !c->animation.tagouting) return offset; - int32_t bottom_out_offset = - GEZERO(c->animation.current.y + c->animation.current.height - - c->mon->m.y - c->mon->m.height); - int32_t right_out_offset = - GEZERO(c->animation.current.x + c->animation.current.width - - c->mon->m.x - c->mon->m.width); - int32_t left_out_offset = GEZERO(c->mon->m.x - c->animation.current.x); - int32_t top_out_offset = GEZERO(c->mon->m.y - c->animation.current.y); - - // 必须转换为int,否计算会没有负数导致判断错误 int32_t bw = (int32_t)c->bw; + int32_t left = offsets.x, right = offsets.width, top = offsets.y, + bottom = offsets.height; - /* - 计算窗口表面超出屏幕四个方向的偏差,避免窗口超出屏幕 - 需要主要border超出屏幕的时候不计算如偏差之内而是 - 要等窗口表面超出才开始计算偏差 - */ - if (ISSCROLLTILED(c) || c->animation.tagining || c->animation.tagouted || - c->animation.tagouting) { - if (left_out_offset > 0) { - offsetx = GEZERO(left_out_offset - bw); - clip_box->x = clip_box->x + offsetx; - clip_box->width = clip_box->width - offsetx; - } else if (right_out_offset > 0) { - offsetw = GEZERO(right_out_offset - bw); - clip_box->width = clip_box->width - offsetw; - } - - if (top_out_offset > 0) { - offsety = GEZERO(top_out_offset - bw); - clip_box->y = clip_box->y + offsety; - clip_box->height = clip_box->height - offsety; - } else if (bottom_out_offset > 0) { - offseth = GEZERO(bottom_out_offset - bw); - clip_box->height = clip_box->height - offseth; - } + if (left > 0) { + offset.x = GEZERO(left - bw); + clip_box->x += offset.x; + clip_box->width -= offset.x; + } else if (right > 0) { + offset.width = GEZERO(right - bw); + clip_box->width -= offset.width; } - // 窗口表面超出屏幕四个方向的偏差 - offset.x = offsetx; - offset.y = offsety; - offset.width = offsetw; - offset.height = offseth; + if (top > 0) { + offset.y = GEZERO(top - bw); + clip_box->y += offset.y; + clip_box->height -= offset.y; + } else if (bottom > 0) { + offset.height = GEZERO(bottom - bw); + clip_box->height -= offset.height; + } if ((clip_box->width + bw <= 0 || clip_box->height + bw <= 0) && (ISSCROLLTILED(c) || c->animation.tagouting || c->animation.tagining)) { c->is_clip_to_hide = true; wlr_scene_node_set_enabled(&c->scene->node, false); - } else if (c->is_clip_to_hide && VISIBLEON(c, c->mon) && - (!c->is_monocle_hide || !is_monocle_layout(c->mon))) { + } else if (c->is_clip_to_hide && VISIBLEON(c, c->mon)) { c->is_clip_to_hide = false; - c->is_monocle_hide = false; + c->is_logic_hide = false; wlr_scene_node_set_enabled(&c->scene->node, true); } @@ -687,9 +759,8 @@ void client_set_drop_area(Client *c) { if (!c || !c->mon) return; - if (!c->enable_drop_area_draw && !c->droparea->node.enabled) { + if (!c->enable_drop_area_draw && !c->droparea->node.enabled) return; - } if (!c->enable_drop_area_draw && c->droparea->node.enabled) { wlr_scene_node_lower_to_bottom(&c->droparea->node); @@ -705,12 +776,10 @@ void client_set_drop_area(Client *c) { int32_t client_width = c->geom.width - 2 * bw; int32_t client_height = c->geom.height - 2 * bw; - // 光标在窗口客户区内的相对坐标 double rel_x = cursor->x - c->geom.x - bw; double rel_y = cursor->y - c->geom.y - bw; struct wlr_box drop_box; - const Layout *cur_layout = c->mon->pertag->ltidxs[c->mon->pertag->curtag]; bool dwindle_familiar = cur_layout->id == DWINDLE && config.dwindle_drop_simple_split; @@ -750,7 +819,6 @@ void client_set_drop_area(Client *c) { } } else if (cur_layout->id == TILE || cur_layout->id == DECK || cur_layout->id == CENTER_TILE || cur_layout->id == RIGHT_TILE) { - if (c->ismaster) { if (c->mon->visible_tiling_clients == 1) { if (rel_x < client_width * 0.5) { @@ -812,7 +880,6 @@ void client_set_drop_area(Client *c) { drop_box.height = client_height; drop_direction = UNDIR; } - } else { if (rel_x < client_width * 0.5) { drop_direction = LEFT; @@ -828,7 +895,6 @@ void client_set_drop_area(Client *c) { drop_box.height = client_height; } } - } else { double dist_left = rel_x; double dist_right = client_width - rel_x; @@ -863,26 +929,28 @@ void client_set_drop_area(Client *c) { } } - if (!first_draw && c->drop_direction == drop_direction) { + if (!first_draw && c->drop_direction == drop_direction) return; - } c->drop_direction = drop_direction; wlr_scene_node_set_position(&c->droparea->node, drop_box.x, drop_box.y); wlr_scene_rect_set_size(c->droparea, drop_box.width, drop_box.height); } -void client_apply_clip(Client *c, float factor) { +/* ---------- central rendering entry point ---------- */ +void client_apply_clip(Client *c, float factor) { if (c->iskilling || !client_surface(c)->mapped) return; + struct ivec2 offsets = compute_edge_offsets(c); + struct wlr_box clip_box; bool should_render_client_surface = false; - struct ivec2 offset; + struct ivec2 surface_clip_offset; BufferData buffer_data; - enum corner_location current_corner_location = + struct fx_corner_radii current_corner_location = set_client_corner_location(c); if (!config.animations && !c->overview_scene_surface) { @@ -892,20 +960,28 @@ void client_apply_clip(Client *c, float factor) { c->geom; client_get_clip(c, &clip_box); + surface_clip_offset = clip_to_hide(c, &clip_box, offsets); - offset = clip_to_hide(c, &clip_box); - - apply_border(c); - client_draw_shadow(c); + client_draw_border(c, offsets); + client_draw_shadow(c, offsets); + client_draw_groupbar(c, offsets); + client_draw_blur(c, surface_clip_offset); + client_draw_shield(c, surface_clip_offset); if (clip_box.width <= 0 || clip_box.height <= 0) { - return; + should_render_client_surface = false; + wlr_scene_node_set_enabled(&c->scene_surface->node, false); + } else { + should_render_client_surface = true; + wlr_scene_node_set_enabled(&c->scene_surface->node, true); } - if (!c->overview_scene_surface) { + if (!should_render_client_surface) + return; + + if (!c->overview_scene_surface) wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip_box); - } buffer_set_effect(c, (BufferData){1.0f, 1.0f, clip_box.width, clip_box.height, @@ -913,11 +989,9 @@ void client_apply_clip(Client *c, float factor) { return; } - // 获取窗口动画实时位置矩形 int32_t width, height; client_actual_size(c, &width, &height); - // 计算出除了边框的窗口实际剪切大小 struct wlr_box geometry; client_get_geometry(c, &geometry); clip_box = (struct wlr_box){ @@ -932,14 +1006,14 @@ void client_apply_clip(Client *c, float factor) { clip_box.y = 0; } - // 检测窗口是否需要剪切超出屏幕部分,如果需要就调整实际要剪切的矩形 - offset = clip_to_hide(c, &clip_box); + surface_clip_offset = clip_to_hide(c, &clip_box, offsets); - // 应用窗口装饰 - apply_border(c); - client_draw_shadow(c); + client_draw_border(c, offsets); + client_draw_shadow(c, offsets); + client_draw_groupbar(c, offsets); + client_draw_shield(c, surface_clip_offset); + client_draw_blur(c, surface_clip_offset); - // 如果窗口剪切区域已经剪切到0,则不渲染窗口表面 if (clip_box.width <= 0 || clip_box.height <= 0) { should_render_client_surface = false; wlr_scene_node_set_enabled(&c->scene_surface->node, false); @@ -948,21 +1022,18 @@ void client_apply_clip(Client *c, float factor) { wlr_scene_node_set_enabled(&c->scene_surface->node, true); } - // 不用在执行下面的窗口表面剪切和缩放等效果操作 - if (!should_render_client_surface) { + if (!should_render_client_surface) return; - } - // 应用窗口表面剪切 - if (!c->overview_scene_surface) { + if (!c->overview_scene_surface) wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip_box); - } - // 获取剪切后的表面的实际大小用于计算缩放 - int32_t acutal_surface_width = geometry.width - offset.x - offset.width; - int32_t acutal_surface_height = geometry.height - offset.y - offset.height; + int32_t actual_surface_width = + geometry.width - surface_clip_offset.x - surface_clip_offset.width; + int32_t actual_surface_height = + geometry.height - surface_clip_offset.y - surface_clip_offset.height; - if (acutal_surface_width <= 0 || acutal_surface_height <= 0) + if (actual_surface_width <= 0 || actual_surface_height <= 0) return; buffer_data.should_scale = true; @@ -975,9 +1046,9 @@ void client_apply_clip(Client *c, float factor) { buffer_data.height_scale = 1.0; } else { buffer_data.width_scale = - (float)buffer_data.width / acutal_surface_width; + (float)buffer_data.width / actual_surface_width; buffer_data.height_scale = - (float)buffer_data.height / acutal_surface_height; + (float)buffer_data.height / actual_surface_height; } buffer_set_effect(c, buffer_data); @@ -987,8 +1058,6 @@ void fadeout_client_animation_next_tick(Client *c) { if (!c) return; - BufferData buffer_data; - struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -998,14 +1067,13 @@ void fadeout_client_animation_next_tick(Client *c) { ? (double)passed_time / (double)c->animation.duration : 1.0; - int32_t type = c->animation.action = c->animation.action; + int32_t type = c->animation.action; double factor = find_animation_curve_at(animation_passed, type); int32_t width = c->animation.initial.width + (c->current.width - c->animation.initial.width) * factor; int32_t height = c->animation.initial.height + (c->current.height - c->animation.initial.height) * factor; - int32_t x = c->animation.initial.x + (c->current.x - c->animation.initial.x) * factor; int32_t y = c->animation.initial.y + @@ -1022,10 +1090,8 @@ void fadeout_client_animation_next_tick(Client *c) { double opacity_eased_progress = find_animation_curve_at(animation_passed, OPAFADEOUT); - double percent = config.fadeout_begin_opacity - (opacity_eased_progress * config.fadeout_begin_opacity); - double opacity = MANGO_MAX(percent, 0); if (config.animation_fade_out && !c->nofadeout) @@ -1036,12 +1102,11 @@ void fadeout_client_animation_next_tick(Client *c) { strcmp(c->animation_type_close, "zoom") == 0) || (!c->animation_type_close && strcmp(config.animation_type_close, "zoom") == 0)) { - + BufferData buffer_data; buffer_data.width = width; buffer_data.height = height; buffer_data.width_scale = animation_passed; buffer_data.height_scale = animation_passed; - wlr_scene_node_for_each_buffer( &c->scene->node, snap_scene_buffer_apply_effect, &buffer_data); } @@ -1050,7 +1115,6 @@ void fadeout_client_animation_next_tick(Client *c) { wl_list_remove(&c->fadeout_link); wlr_scene_node_destroy(&c->scene->node); free(c); - c = NULL; } } @@ -1067,15 +1131,10 @@ void client_animation_next_tick(Client *c) { int32_t type = c->animation.action == NONE ? MOVE : c->animation.action; double factor = find_animation_curve_at(animation_passed, type); - Client *pointer_c = NULL; - double sx = 0, sy = 0; - struct wlr_surface *surface = NULL; - int32_t width = c->animation.initial.width + (c->current.width - c->animation.initial.width) * factor; int32_t height = c->animation.initial.height + (c->current.height - c->animation.initial.height) * factor; - int32_t x = c->animation.initial.x + (c->current.x - c->animation.initial.x) * factor; int32_t y = c->animation.initial.y + @@ -1090,16 +1149,10 @@ void client_animation_next_tick(Client *c) { }; c->is_pending_open_animation = false; - client_apply_clip(c, factor); if (animation_passed >= 1.0) { - - // clear the open action state - // To prevent him from being mistaken that - // it's still in the opening animation in resize c->animation.action = MOVE; - c->animation.tagining = false; c->animation.running = false; c->animation.overining = false; @@ -1111,36 +1164,34 @@ void client_animation_next_tick(Client *c) { c->animation.current = c->geom; } - xytonode(cursor->x, cursor->y, NULL, &pointer_c, NULL, &sx, &sy); - - surface = + Client *pointer_c = NULL; + double sx, sy; + xytonode(cursor->x, cursor->y, NULL, &pointer_c, NULL, NULL, &sx, &sy); + struct wlr_surface *surface = pointer_c && pointer_c == c ? client_surface(pointer_c) : NULL; - // avoid game window force grab pointer in overview mode - if (surface && pointer_c == selmon->sel && !selmon->isoverview) { + if (surface && pointer_c == selmon->sel && !selmon->isoverview) wlr_seat_pointer_notify_enter(seat, surface, sx, sy); - } - // end flush in next frame, not the current frame c->need_output_flush = false; } } void init_fadeout_client(Client *c) { - if (!c->mon || client_is_unmanaged(c)) return; - if (!c->scene) { + if (!c->scene) + return; + + if (c->shield_when_capture && active_capture_count > 0) return; - } if ((c->animation_type_close && strcmp(c->animation_type_close, "none") == 0) || (!c->animation_type_close && - strcmp(config.animation_type_close, "none") == 0)) { + strcmp(config.animation_type_close, "none") == 0)) return; - } Client *fadeout_client = ecalloc(1, sizeof(*fadeout_client)); @@ -1169,9 +1220,6 @@ void init_fadeout_client(Client *c) { fadeout_client->bw = c->bw; fadeout_client->nofadeout = c->nofadeout; - // 这里snap节点的坐标设置是使用的相对坐标,所以不能加上原来坐标 - // 这跟普通node有区别 - fadeout_client->animation.initial.x = 0; fadeout_client->animation.initial.y = 0; @@ -1189,10 +1237,9 @@ void init_fadeout_client(Client *c) { strcmp(config.animation_type_close, "slide") == 0)) { fadeout_client->current.y = c->geom.y + c->geom.height / 2 > c->mon->m.y + c->mon->m.height / 2 - ? c->mon->m.height - - (c->animation.current.y - c->mon->m.y) // down out - : c->mon->m.y - c->geom.height; // up out - fadeout_client->current.x = 0; // x无偏差,垂直划出 + ? c->mon->m.height - (c->animation.current.y - c->mon->m.y) + : c->mon->m.y - c->geom.height; + fadeout_client->current.x = 0; } else { fadeout_client->current.y = (fadeout_client->geom.height - @@ -1212,52 +1259,44 @@ void init_fadeout_client(Client *c) { wlr_scene_node_set_enabled(&fadeout_client->scene->node, true); wl_list_insert(&fadeout_clients, &fadeout_client->fadeout_link); - // 请求刷新屏幕 request_fresh_all_monitors(); } void client_commit(Client *c) { - c->current = c->pending; // 设置动画的结束位置 + c->current = c->pending; if (c->animation.should_animate) { - if (!c->animation.running) { + if (!c->animation.running) c->animation.current = c->animainit_geom; - } c->animation.initial = c->animainit_geom; c->animation.time_started = get_now_in_ms(); - - // 标记动画开始 c->animation.running = true; c->animation.should_animate = false; } - // 请求刷新屏幕 request_fresh_all_monitors(); } void client_set_pending_state(Client *c) { - if (!c || c->iskilling) return; - if (!config.animations) { + if (!config.animations) c->animation.should_animate = false; - } else if (config.animations && c->animation.tagining) { + else if (config.animations && c->animation.tagining) c->animation.should_animate = true; - } else if (c == grabc || (!c->is_pending_open_animation && - wlr_box_equal(&c->current, &c->pending))) { + else if (c == grabc || (!c->is_pending_open_animation && + wlr_box_equal(&c->current, &c->pending))) c->animation.should_animate = false; - } else { + else c->animation.should_animate = true; - } if (((c->animation_type_open && strcmp(c->animation_type_open, "none") == 0) || (!c->animation_type_open && strcmp(config.animation_type_open, "none") == 0)) && - c->animation.action == OPEN) { + c->animation.action == OPEN) c->animation.duration = 0; - } if (c->istagswitching) { c->animation.duration = 0; @@ -1274,58 +1313,46 @@ void client_set_pending_state(Client *c) { c->animation.duration = 0; } - // 开始动画 client_commit(c); c->dirty = true; } void resize(Client *c, struct wlr_box geo, int32_t interact) { - - // 动画设置的起始函数,这里用来计算一些动画的起始值 - // 动画起始位置大小是由于c->animainit_geom确定的 - if (!c || !c->mon || !client_surface(c)->mapped) return; - struct wlr_box *bbox; - struct wlr_box clip; - if (!c->mon) return; c->need_output_flush = true; c->dirty = true; - // float_geom = c->geom; - bbox = (interact || c->isfloating || c->isfullscreen) ? &sgeom : &c->mon->w; + struct wlr_box *bbox = + (interact || c->isfloating || c->isfullscreen) ? &sgeom : &c->mon->w; + struct wlr_box clip; if (is_scroller_layout(c->mon) && (!c->isfloating || c == grabc)) { c->geom = geo; c->geom.width = MANGO_MAX(1 + 2 * (int32_t)c->bw, c->geom.width); c->geom.height = MANGO_MAX(1 + 2 * (int32_t)c->bw, c->geom.height); - } else { // 这里会限制不允许窗口划出屏幕 + } else { c->geom = geo; - applybounds( - c, - bbox); // 去掉这个推荐的窗口大小,因为有时推荐的窗口特别大导致平铺异常 + applybounds(c, bbox); } if (!c->isnosizehint && !c->ismaximizescreen && !c->isfullscreen && - c->isfloating) { + c->isfloating) client_set_size_bound(c); - } - if (!c->is_pending_open_animation) { + if (!c->is_pending_open_animation) c->animation.begin_fade_in = false; - } - if (c->animation.overining) { + if (c->animation.overining) c->animation.action = OVERVIEW; - } else if (c->animation.action == OPEN && !c->animation.tagining && - !c->animation.tagouting && - wlr_box_equal(&c->geom, &c->current)) { - c->animation.action = c->animation.action; - } else if (c->animation.tagouting) { + else if (c->animation.action == OPEN && !c->animation.tagining && + !c->animation.tagouting && wlr_box_equal(&c->geom, &c->current)) + ; /* keep current action */ + else if (c->animation.tagouting) { c->animation.duration = config.animation_duration_tag; c->animation.action = TAG; } else if (c->animation.tagining) { @@ -1339,21 +1366,18 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) { c->animation.action = MOVE; } - // 动画起始位置大小设置 - if (c->animation.tagouting) { + if (c->animation.tagouting) c->animainit_geom = c->animation.current; - } else if (c->animation.tagining) { + else if (c->animation.tagining) { c->animainit_geom.height = c->animation.current.height; c->animainit_geom.width = c->animation.current.width; - } else if (c->is_pending_open_animation) { + } else if (c->is_pending_open_animation) set_client_open_animation(c, c->geom); - } else { + else c->animainit_geom = c->animation.current; - } - if (c->isnoborder || c->iskilling) { + if (c->isnoborder || c->iskilling) c->bw = 0; - } bool hit_no_border = check_hit_no_border(c); if (hit_no_border && config.smartgaps) { @@ -1361,65 +1385,59 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) { c->fake_no_border = true; } - // c->geom 是真实的窗口大小和位置,跟过度的动画无关,用于计算布局 - if (!c->mon->isoverview || !config.ov_no_resize) { + if (!c->mon->isoverview || !config.ov_no_resize) c->configure_serial = client_set_size(c, c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw); - } - if (c->configure_serial != 0) { + if (c->configure_serial != 0) c->mon->resizing_count_pending++; - } if (c == grabc) { + struct ivec2 offsets = compute_edge_offsets(c); + c->animation.running = false; c->need_output_flush = false; - c->animainit_geom = c->current = c->pending = c->animation.current = c->geom; wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); - client_draw_shadow(c); - apply_border(c); + client_draw_border(c, offsets); client_get_clip(c, &clip); + client_draw_groupbar(c, offsets); + client_draw_shadow(c, offsets); + + struct ivec2 surface_clip_offset = clip_to_hide(c, &clip, offsets); + client_draw_shield(c, surface_clip_offset); + client_draw_blur(c, surface_clip_offset); + wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip); return; } - // 如果不是工作区切换时划出去的窗口,就让动画的结束位置,就是上面的真实位置和大小 - // c->pending 决定动画的终点,一般在其他调用resize的函数的附近设置了 - if (!c->animation.tagouting && !c->iskilling) { + + if (!c->animation.tagouting && !c->iskilling) c->pending = c->geom; - } - if (c->swallowedby && c->animation.action == OPEN) { - c->animainit_geom = c->swallowedby->animation.current; - } + if (c->swallowing && c->animation.action == OPEN) + c->animainit_geom = c->swallowing->animation.current; - if (c->swallowing) { + if (c->swallowdby) c->animainit_geom = c->geom; - } if ((c->isglobal || c->isunglobal) && c->isfloating && - c->animation.action == TAG) { + c->animation.action == TAG) c->animainit_geom = c->geom; - } - if (c->scratchpad_switching_mon && c->isfloating) { + if (c->scratchpad_switching_mon && c->isfloating) c->animainit_geom = c->geom; - } if (config.animations && config.ov_no_resize && c->mon->isoverview && - c != c->mon->sel && c->animation.action == OVERVIEW) { + c != c->mon->sel && c->animation.action == OVERVIEW) set_overview_enter_animation(c); - } - if (!config.animations && config.ov_no_resize && c->mon->isoverview) { + if (!config.animations && config.ov_no_resize && c->mon->isoverview) c->animainit_geom = c->geom; - } - // 开始应用动画设置 client_set_pending_state(c); - setborder_color(c); } @@ -1449,7 +1467,6 @@ void client_set_focused_opacity_animation(Client *c) { c->opacity_animation.current_border_color, sizeof(c->opacity_animation.initial_border_color)); c->opacity_animation.initial_opacity = c->opacity_animation.current_opacity; - c->opacity_animation.running = true; } @@ -1464,20 +1481,16 @@ void client_set_unfocused_opacity_animation(Client *c) { c->opacity_animation.duration = config.animation_duration_focus; memcpy(c->opacity_animation.target_border_color, border_color, sizeof(c->opacity_animation.target_border_color)); - // Start opacity animation to unfocused c->opacity_animation.target_opacity = c->unfocused_opacity; c->opacity_animation.time_started = get_now_in_ms(); - memcpy(c->opacity_animation.initial_border_color, c->opacity_animation.current_border_color, sizeof(c->opacity_animation.initial_border_color)); c->opacity_animation.initial_opacity = c->opacity_animation.current_opacity; - c->opacity_animation.running = true; } bool client_apply_focus_opacity(Client *c) { - // Animate focus transitions (opacity + border color) float *border_color = get_border_color(c); if (c->isfullscreen) { c->opacity_animation.running = false; @@ -1495,26 +1508,30 @@ bool client_apply_focus_opacity(Client *c) { double opacity_eased_progress = find_animation_curve_at(linear_progress, OPAFADEIN); - float percent = config.animation_fade_in && !c->nofadein ? opacity_eased_progress : 1.0; float opacity = c == selmon->sel ? c->focused_opacity : c->unfocused_opacity; - float target_opacity = percent * (1.0 - config.fadein_begin_opacity) + config.fadein_begin_opacity; - if (target_opacity > opacity) { + if (target_opacity > opacity) target_opacity = opacity; - } + memcpy(c->opacity_animation.current_border_color, c->opacity_animation.target_border_color, sizeof(c->opacity_animation.current_border_color)); c->opacity_animation.current_opacity = target_opacity; client_set_opacity(c, target_opacity); + if (config.blur && !c->noblur && !config.blur_optimized) { + float blur_val = MIN(percent * (1.0 - config.fadein_begin_opacity) + + config.fadein_begin_opacity, + 1.0); + wlr_scene_blur_set_strength(c->blur, blur_val); + wlr_scene_blur_set_alpha(c->blur, blur_val); + } client_set_border_color(c, c->opacity_animation.target_border_color); } else if (config.animations && c->opacity_animation.running) { - struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -1534,7 +1551,6 @@ bool client_apply_focus_opacity(Client *c) { eased_progress; client_set_opacity(c, c->opacity_animation.current_opacity); - // Animate border color for (int32_t i = 0; i < 4; i++) { c->opacity_animation.current_border_color[i] = c->opacity_animation.initial_border_color[i] + @@ -1543,11 +1559,10 @@ bool client_apply_focus_opacity(Client *c) { eased_progress; } client_set_border_color(c, c->opacity_animation.current_border_color); - if (linear_progress >= 1.0f) { + if (linear_progress >= 1.0f) c->opacity_animation.running = false; - } else { + else return true; - } } else if (c == selmon->sel) { c->opacity_animation.running = false; c->opacity_animation.current_opacity = c->focused_opacity; @@ -1566,13 +1581,11 @@ bool client_apply_focus_opacity(Client *c) { } bool client_draw_frame(Client *c) { - if (!c || !client_surface(c)->mapped) return false; - if (!c->need_output_flush) { + if (!c->need_output_flush) return client_apply_focus_opacity(c); - } if (config.animations && c->animation.running) { client_animation_next_tick(c); @@ -1584,6 +1597,5 @@ bool client_draw_frame(Client *c) { client_apply_clip(c, 1.0); c->need_output_flush = false; } - client_apply_focus_opacity(c); - return true; -} + return client_apply_focus_opacity(c); +} \ No newline at end of file diff --git a/src/animation/common.h b/src/animation/common.h index 6120d79c..00a23b9e 100644 --- a/src/animation/common.h +++ b/src/animation/common.h @@ -30,7 +30,7 @@ struct dvec2 calculate_animation_curve_at(double t, int32_t type) { void handle_snapshot_meta_destroy(struct wl_listener *listener, void *data) { SnapshotMetadata *meta = wl_container_of(listener, meta, destroy); - wl_list_remove(&meta->destroy.link); // 安全移除监听器 + wl_list_remove(&meta->destroy.link); free(meta); } @@ -175,6 +175,7 @@ static bool scene_node_snapshot(struct wlr_scene_node *node, int32_t lx, } meta->orig_width = scene_buffer->dst_width; meta->orig_height = scene_buffer->dst_height; + meta->type = Snapshot; struct wlr_scene_surface *scene_surface = wlr_scene_surface_try_from_buffer(scene_buffer); @@ -212,11 +213,8 @@ static bool scene_node_snapshot(struct wlr_scene_node *node, int32_t lx, // Effects wlr_scene_buffer_set_opacity(snapshot_buffer, scene_buffer->opacity); - wlr_scene_buffer_set_corner_radius(snapshot_buffer, - scene_buffer->corner_radius, - scene_buffer->corners); - - wlr_scene_buffer_set_backdrop_blur(snapshot_buffer, false); + wlr_scene_buffer_set_corner_radii(snapshot_buffer, + scene_buffer->corners); if (scene_surface != NULL && scene_surface->surface->buffer != NULL) { wlr_scene_buffer_set_buffer(snapshot_buffer, @@ -248,6 +246,8 @@ static bool scene_node_snapshot(struct wlr_scene_node *node, int32_t lx, break; } + case WLR_SCENE_NODE_BLUR: + break; case WLR_SCENE_NODE_OPTIMIZED_BLUR: return true; } diff --git a/src/animation/layer.h b/src/animation/layer.h index 7ccabe33..e0c99793 100644 --- a/src/animation/layer.h +++ b/src/animation/layer.h @@ -1,13 +1,11 @@ void layer_actual_size(LayerSurface *l, int32_t *width, int32_t *height) { - struct wlr_box box; if (l->animation.running) { *width = l->animation.current.width; *height = l->animation.current.height; } else { - get_layer_target_geometry(l, &box); - *width = box.width; - *height = box.height; + *width = l->geom.width; + *height = l->geom.height; } } @@ -151,6 +149,34 @@ void set_layer_dir_animaiton(LayerSurface *l, struct wlr_box *geo) { } } +void layer_draw_shield(LayerSurface *l) { + int32_t width, height; + + if (!l->mapped) + return; + + if (active_capture_count > 0 && l->shield_when_capture) { + + layer_actual_size(l, &width, &height); + + if (width <= 0 || height <= 0) { + wlr_scene_node_set_enabled(&l->shield->node, false); + return; + } + + wlr_scene_node_raise_to_top(&l->shield->node); + wlr_scene_node_set_position(&l->shield->node, 0, 0); + wlr_scene_rect_set_size(l->shield, width, height); + wlr_scene_node_set_enabled(&l->shield->node, true); + } else { + if (l->shield->node.enabled) { + wlr_scene_node_lower_to_bottom(&l->shield->node); + wlr_scene_node_set_position(&l->shield->node, 0, 0); + wlr_scene_node_set_enabled(&l->shield->node, false); + } + } +} + void layer_draw_shadow(LayerSurface *l) { if (!l->mapped || !l->shadow) @@ -187,8 +213,7 @@ void layer_draw_shadow(LayerSurface *l) { struct clipped_region clipped_region = { .area = intersection_box, - .corner_radius = config.border_radius, - .corners = config.border_radius_location_default, + .corners = corner_radii_all(config.border_radius), }; wlr_scene_node_set_position(&l->shadow->node, shadow_box.x, shadow_box.y); @@ -328,9 +353,14 @@ void layer_animation_next_tick(LayerSurface *l) { (1.0 - config.fadein_begin_opacity), 1.0f); - if (config.animation_fade_in) + if (config.animation_fade_in) { + if (config.blur && !l->noblur && !config.blur_optimized) { + wlr_scene_blur_set_strength(l->blur, opacity); + wlr_scene_blur_set_alpha(l->blur, opacity); + } wlr_scene_node_for_each_buffer(&l->scene->node, scene_buffer_apply_opacity, &opacity); + } wlr_scene_node_set_position(&l->scene->node, x, y); @@ -358,6 +388,10 @@ void layer_animation_next_tick(LayerSurface *l) { .height = height, }; + if (config.blur && config.blur_layer && !l->noblur && l->blur) + wlr_scene_blur_set_size(l->blur, l->animation.current.width, + l->animation.current.height); + if (animation_passed >= 1.0) { l->animation.running = false; l->need_output_flush = false; @@ -374,6 +408,10 @@ void init_fadeout_layers(LayerSurface *l) { if (!l->mon || !l->scene) return; + if (l->shield_when_capture) { + return; + } + if ((l->animation_type_close && strcmp(l->animation_type_close, "none") == 0) || (!l->animation_type_close && @@ -567,8 +605,10 @@ bool layer_draw_frame(LayerSurface *l) { if (config.animations && config.layer_animations && l->animation.running && !l->noanim) { layer_animation_next_tick(l); + layer_draw_shield(l); layer_draw_shadow(l); } else { + layer_draw_shield(l); layer_draw_shadow(l); l->need_output_flush = false; } diff --git a/src/animation/tag.h b/src/animation/tag.h index 859ee1b8..4395fa67 100644 --- a/src/animation/tag.h +++ b/src/animation/tag.h @@ -45,10 +45,9 @@ void set_tagin_animation(Monitor *m, Client *c) { void set_arrange_visible(Monitor *m, Client *c, bool want_animation) { - if (!ISTILED(c) || ((!c->is_clip_to_hide || !is_scroller_layout(c->mon)) && - (!c->is_monocle_hide || !is_monocle_layout(c->mon)))) { + if (!ISTILED(c) || (!c->is_clip_to_hide || !is_scroller_layout(c->mon))) { c->is_clip_to_hide = false; - c->is_monocle_hide = false; + c->is_logic_hide = false; wlr_scene_node_set_enabled(&c->scene->node, true); wlr_scene_node_set_enabled(&c->scene_surface->node, true); } diff --git a/src/common/util.c b/src/common/util.c index 8e562b19..fb5cb93c 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -205,4 +205,30 @@ void wl_list_swap(struct wl_list *l1, struct wl_list *l2) { tmp2_prev->next = l1; tmp2_next->prev = l1; } +} + +void wl_list_safe_reinsert_prev(struct wl_list *l1, struct wl_list *l2) { + if (!l1 || !l2) + return; + if (l1 == l2) + return; + if (l1->prev == l2) + return; + + wl_list_remove(l2); + wl_list_init(l2); + wl_list_insert(l1->prev, l2); +} + +void wl_list_safe_reinsert_next(struct wl_list *l1, struct wl_list *l2) { + if (!l1 || !l2) + return; + if (l1 == l2) + return; + if (l1->next == l2) + return; + + wl_list_remove(l2); + wl_list_init(l2); + wl_list_insert(l1, l2); } \ No newline at end of file diff --git a/src/common/util.h b/src/common/util.h index c7f83f2b..52b509a7 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -12,4 +12,6 @@ char *join_strings(char *arr[], const char *sep); char *join_strings_with_suffix(char *arr[], const char *suffix, const char *sep); char *string_printf(const char *fmt, ...); -void wl_list_swap(struct wl_list *l1, struct wl_list *l2); \ No newline at end of file +void wl_list_swap(struct wl_list *l1, struct wl_list *l2); +void wl_list_safe_reinsert_prev(struct wl_list *l1, struct wl_list *l2); +void wl_list_safe_reinsert_next(struct wl_list *l1, struct wl_list *l2); \ No newline at end of file diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 61af421b..e4b6d7a8 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -22,6 +22,11 @@ enum { NUM_TYPE_MINUS, NUM_TYPE_PLUS, NUM_TYPE_DEFAULT }; enum { KEY_TYPE_CODE, KEY_TYPE_SYM }; +enum render_bit_depth { + MANGO_RENDER_BIT_DEPTH_DEFAULT = 0, + MANGO_RENDER_BIT_DEPTH_8, + MANGO_RENDER_BIT_DEPTH_10, +}; typedef struct { uint32_t keycode1; uint32_t keycode2; @@ -74,11 +79,13 @@ typedef struct { int32_t isunglobal; int32_t isglobal; int32_t isoverlay; + int32_t shield_when_capture; int32_t allow_shortcuts_inhibit; int32_t ignore_maximize; int32_t ignore_minimize; int32_t isnosizehint; int32_t idleinhibit_when_focus; + int32_t vrr_only_fullscreen; char *monitor; int32_t offsetx; int32_t offsety; @@ -113,6 +120,8 @@ typedef struct { float refresh; // Refresh rate int32_t vrr; // variable refresh rate int32_t custom; // enable custom mode + int32_t hdr; // enable hdr mode + int32_t disable; // prefer disable } ConfigMonitorRule; // 修改后的宏定义 @@ -179,6 +188,7 @@ typedef struct { char *layer_name; // 布局名称 char *animation_type_open; char *animation_type_close; + int32_t shield_when_capture; int32_t noblur; int32_t noanim; int32_t noshadow; @@ -332,7 +342,7 @@ typedef struct { uint32_t gappoh; uint32_t gappov; uint32_t borderpx; - uint32_t tab_bar_height; + uint32_t group_bar_height; float scratchpad_width_ratio; float scratchpad_height_ratio; float rootcolor[4]; @@ -410,7 +420,9 @@ typedef struct { struct xkb_context *ctx; struct xkb_keymap *keymap; DecorateDrawData jumplabeldata; - DecorateDrawData tabdata; + DecorateDrawData groupbardata; + + int32_t hdr_depth; } Config; typedef int32_t (*FuncType)(const Arg *); @@ -418,7 +430,7 @@ Config config; bool parse_config_file(Config *config, const char *file_path, bool must_exist); bool apply_rule_to_state(Monitor *m, const ConfigMonitorRule *rule, - struct wlr_output_state *state, int vrr, int custom); + struct wlr_output_state *state); bool monitor_matches_rule(Monitor *m, const ConfigMonitorRule *rule); // Helper function to trim whitespace from start and end of a string @@ -1010,9 +1022,17 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, if (strcmp(func_name, "focusstack") == 0) { func = focusstack; (*arg).i = parse_circle_direction(arg_value); + } else if (strcmp(func_name, "groupfocus") == 0) { + func = groupfocus; + (*arg).i = parse_circle_direction(arg_value); } else if (strcmp(func_name, "focusdir") == 0) { func = focusdir; (*arg).i = parse_direction(arg_value); + } else if (strcmp(func_name, "groupjoin") == 0) { + func = groupjoin; + (*arg).i = parse_direction(arg_value); + } else if (strcmp(func_name, "groupleave") == 0) { + func = groupleave; } else if (strcmp(func_name, "focusid") == 0) { func = focusid; } else if (strcmp(func_name, "incnmaster") == 0) { @@ -1277,6 +1297,15 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, } else if (strcmp(func_name, "toggle_monitor") == 0) { func = toggle_monitor; (*arg).v = strdup(arg_value); + } else if (strcmp(func_name, "sleep_monitor") == 0) { + func = sleep_monitor; + (*arg).v = strdup(arg_value); + } else if (strcmp(func_name, "wakeup_monitor") == 0) { + func = wakeup_monitor; + (*arg).v = strdup(arg_value); + } else if (strcmp(func_name, "sleep_toggle_monitor") == 0) { + func = sleep_toggle_monitor; + (*arg).v = strdup(arg_value); } else if (strcmp(func_name, "scroller_stack") == 0) { func = scroller_stack; (*arg).i = parse_direction(arg_value); @@ -1510,6 +1539,8 @@ bool parse_option(Config *config, char *key, char *value) { config->drag_floating_refresh_interval = atof(value); } else if (strcmp(key, "allow_tearing") == 0) { config->allow_tearing = atoi(value); + } else if (strcmp(key, "hdr_depth") == 0) { + config->hdr_depth = atoi(value); } else if (strcmp(key, "allow_shortcuts_inhibit") == 0) { config->allow_shortcuts_inhibit = atoi(value); } else if (strcmp(key, "allow_lock_transparent") == 0) { @@ -1765,76 +1796,76 @@ bool parse_option(Config *config, char *key, char *value) { config->cursor_size = atoi(value); } else if (strcmp(key, "cursor_theme") == 0) { config->cursor_theme = strdup(value); - } else if (strcmp(key, "tab_bar_decorate_font_desc") == 0) { - config->tabdata.font_desc = strdup(value); - } else if (strcmp(key, "tab_bar_decorate_fg_color") == 0) { + } else if (strcmp(key, "group_bar_decorate_font_desc") == 0) { + config->groupbardata.font_desc = strdup(value); + } else if (strcmp(key, "group_bar_decorate_fg_color") == 0) { int64_t color = parse_color(value); if (color == -1) { fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Invalid " - "tab_bar_decorate_fg_color " + "group_bar_decorate_fg_color " "format: %s\n", value); return false; } else { - convert_hex_to_rgba(config->tabdata.fg_color, color); + convert_hex_to_rgba(config->groupbardata.fg_color, color); } - } else if (strcmp(key, "tab_bar_decorate_bg_color") == 0) { + } else if (strcmp(key, "group_bar_decorate_bg_color") == 0) { int64_t color = parse_color(value); if (color == -1) { fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Invalid " - "tab_bar_decorate_bg_color " + "group_bar_decorate_bg_color " "format: %s\n", value); return false; } else { - convert_hex_to_rgba(config->tabdata.bg_color, color); + convert_hex_to_rgba(config->groupbardata.bg_color, color); } - } else if (strcmp(key, "tab_bar_decorate_focus_fg_color") == 0) { + } else if (strcmp(key, "group_bar_decorate_focus_fg_color") == 0) { int64_t color = parse_color(value); if (color == -1) { fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Invalid " - "tab_bar_decorate_focus_fg_color " + "group_bar_decorate_focus_fg_color " "format: %s\n", value); return false; } else { - convert_hex_to_rgba(config->tabdata.focus_fg_color, color); + convert_hex_to_rgba(config->groupbardata.focus_fg_color, color); } - } else if (strcmp(key, "tab_bar_decorate_focus_bg_color") == 0) { + } else if (strcmp(key, "group_bar_decorate_focus_bg_color") == 0) { int64_t color = parse_color(value); if (color == -1) { fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Invalid " - "tab_bar_decorate_focus_bg_color " + "group_bar_decorate_focus_bg_color " "format: %s\n", value); return false; } else { - convert_hex_to_rgba(config->tabdata.focus_bg_color, color); + convert_hex_to_rgba(config->groupbardata.focus_bg_color, color); } - } else if (strcmp(key, "tab_bar_decorate_border_color") == 0) { + } else if (strcmp(key, "group_bar_decorate_border_color") == 0) { int64_t color = parse_color(value); if (color == -1) { fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Invalid " - "tab_bar_decorate_border_color " + "group_bar_decorate_border_color " "format: %s\n", value); return false; } else { - convert_hex_to_rgba(config->tabdata.border_color, color); + convert_hex_to_rgba(config->groupbardata.border_color, color); } - } else if (strcmp(key, "tab_bar_decorate_border_width") == 0) { - config->tabdata.border_width = CLAMP_INT(atoi(value), 0, 100); - } else if (strcmp(key, "tab_bar_decorate_corner_radius") == 0) { - config->tabdata.corner_radius = CLAMP_INT(atoi(value), 0, 100); - } else if (strcmp(key, "tab_bar_decorate_padding_x") == 0) { - config->tabdata.padding_x = CLAMP_INT(atoi(value), 0, 100); - } else if (strcmp(key, "tab_bar_decorate_padding_y") == 0) { - config->tabdata.padding_y = CLAMP_INT(atoi(value), 0, 100); + } else if (strcmp(key, "group_bar_decorate_border_width") == 0) { + config->groupbardata.border_width = CLAMP_INT(atoi(value), 0, 100); + } else if (strcmp(key, "group_bar_decorate_corner_radius") == 0) { + config->groupbardata.corner_radius = CLAMP_INT(atoi(value), 0, 100); + } else if (strcmp(key, "group_bar_decorate_padding_x") == 0) { + config->groupbardata.padding_x = CLAMP_INT(atoi(value), 0, 100); + } else if (strcmp(key, "group_bar_decorate_padding_y") == 0) { + config->groupbardata.padding_y = CLAMP_INT(atoi(value), 0, 100); } else if (strcmp(key, "jump_label_decorate_font_desc") == 0) { config->jumplabeldata.font_desc = strdup(value); } else if (strcmp(key, "jump_label_decorate_fg_color") == 0) { @@ -1951,8 +1982,8 @@ bool parse_option(Config *config, char *key, char *value) { config->scratchpad_height_ratio = atof(value); } else if (strcmp(key, "borderpx") == 0) { config->borderpx = atoi(value); - } else if (strcmp(key, "tab_bar_height") == 0) { - config->tab_bar_height = atoi(value); + } else if (strcmp(key, "group_bar_height") == 0) { + config->group_bar_height = atoi(value); } else if (strcmp(key, "rootcolor") == 0) { int64_t color = parse_color(value); if (color == -1) { @@ -2106,7 +2137,9 @@ bool parse_option(Config *config, char *key, char *value) { rule->height = -1; rule->refresh = 0.0f; rule->vrr = 0; + rule->hdr = 0; rule->custom = 0; + rule->disable = 0; bool parse_error = false; char *token = strtok(value, ","); @@ -2144,6 +2177,10 @@ bool parse_option(Config *config, char *key, char *value) { rule->refresh = CLAMP_FLOAT(atof(val), 0.001f, 1000.0f); } else if (strcmp(key, "vrr") == 0) { rule->vrr = CLAMP_INT(atoi(val), 0, 1); + } else if (strcmp(key, "hdr") == 0) { + rule->hdr = CLAMP_INT(atoi(val), 0, 1); + } else if (strcmp(key, "disable") == 0) { + rule->disable = CLAMP_INT(atoi(val), 0, 1); } else if (strcmp(key, "custom") == 0) { rule->custom = CLAMP_INT(atoi(val), 0, 1); } else { @@ -2274,6 +2311,7 @@ bool parse_option(Config *config, char *key, char *value) { rule->layer_name = NULL; rule->animation_type_open = NULL; rule->animation_type_close = NULL; + rule->shield_when_capture = 0; rule->noblur = 0; rule->noanim = 0; rule->noshadow = 0; @@ -2296,6 +2334,8 @@ bool parse_option(Config *config, char *key, char *value) { rule->animation_type_open = strdup(val); } else if (strcmp(key, "animation_type_close") == 0) { rule->animation_type_close = strdup(val); + } else if (strcmp(key, "shield_when_capture") == 0) { + rule->shield_when_capture = CLAMP_INT(atoi(val), 0, 1); } else if (strcmp(key, "noblur") == 0) { rule->noblur = CLAMP_INT(atoi(val), 0, 1); } else if (strcmp(key, "noanim") == 0) { @@ -2349,11 +2389,13 @@ bool parse_option(Config *config, char *key, char *value) { rule->isunglobal = -1; rule->isglobal = -1; rule->isoverlay = -1; + rule->shield_when_capture = -1; rule->allow_shortcuts_inhibit = -1; rule->ignore_maximize = -1; rule->ignore_minimize = -1; rule->isnosizehint = -1; rule->idleinhibit_when_focus = -1; + rule->vrr_only_fullscreen = -1; rule->isterm = -1; rule->allow_csd = -1; rule->force_fakemaximize = -1; @@ -2456,6 +2498,8 @@ bool parse_option(Config *config, char *key, char *value) { rule->focused_opacity = atof(val); } else if (strcmp(key, "isoverlay") == 0) { rule->isoverlay = atoi(val); + } else if (strcmp(key, "shield_when_capture") == 0) { + rule->shield_when_capture = atoi(val); } else if (strcmp(key, "allow_shortcuts_inhibit") == 0) { rule->allow_shortcuts_inhibit = atoi(val); } else if (strcmp(key, "ignore_maximize") == 0) { @@ -2466,6 +2510,8 @@ bool parse_option(Config *config, char *key, char *value) { rule->isnosizehint = atoi(val); } else if (strcmp(key, "idleinhibit_when_focus") == 0) { rule->idleinhibit_when_focus = atoi(val); + } else if (strcmp(key, "vrr_only_fullscreen") == 0) { + rule->vrr_only_fullscreen = atoi(val); } else if (strcmp(key, "isterm") == 0) { rule->isterm = atoi(val); } else if (strcmp(key, "allow_csd") == 0) { @@ -3401,9 +3447,9 @@ void free_config(void) { config.jumplabeldata.font_desc = NULL; } - if (config.tabdata.font_desc) { - free((void *)config.tabdata.font_desc); - config.tabdata.font_desc = NULL; + if (config.groupbardata.font_desc) { + free((void *)config.groupbardata.font_desc); + config.groupbardata.font_desc = NULL; } if (config.tablet_map_to_mon) { @@ -3496,6 +3542,7 @@ void override_config(void) { config.drag_tile_to_tile = CLAMP_INT(config.drag_tile_to_tile, 0, 1); config.drag_tile_small = CLAMP_INT(config.drag_tile_small, 0, 1); config.allow_tearing = CLAMP_INT(config.allow_tearing, 0, 2); + config.hdr_depth = CLAMP_INT(config.hdr_depth, 0, 2); config.allow_shortcuts_inhibit = CLAMP_INT(config.allow_shortcuts_inhibit, 0, 1); config.allow_lock_transparent = @@ -3569,7 +3616,7 @@ void override_config(void) { config.scratchpad_height_ratio = CLAMP_FLOAT(config.scratchpad_height_ratio, 0.1f, 1.0f); config.borderpx = CLAMP_INT(config.borderpx, 0, 200); - config.tab_bar_height = CLAMP_INT(config.tab_bar_height, 0, 500); + config.group_bar_height = CLAMP_INT(config.group_bar_height, 0, 500); config.smartgaps = CLAMP_INT(config.smartgaps, 0, 1); config.blur = CLAMP_INT(config.blur, 0, 1); config.blur_layer = CLAMP_INT(config.blur_layer, 0, 1); @@ -3598,12 +3645,14 @@ void override_config(void) { config.unfocused_opacity = CLAMP_FLOAT(config.unfocused_opacity, 0.0f, 1.0f); - config.tabdata.border_width = - CLAMP_INT(config.tabdata.border_width, 0, 100); - config.tabdata.corner_radius = - CLAMP_INT(config.tabdata.corner_radius, 0, 100); - config.tabdata.padding_x = CLAMP_INT(config.tabdata.padding_x, 0, 100); - config.tabdata.padding_y = CLAMP_INT(config.tabdata.padding_y, 0, 100); + config.groupbardata.border_width = + CLAMP_INT(config.groupbardata.border_width, 0, 100); + config.groupbardata.corner_radius = + CLAMP_INT(config.groupbardata.corner_radius, 0, 100); + config.groupbardata.padding_x = + CLAMP_INT(config.groupbardata.padding_x, 0, 100); + config.groupbardata.padding_y = + CLAMP_INT(config.groupbardata.padding_y, 0, 100); config.jumplabeldata.border_width = CLAMP_INT(config.jumplabeldata.border_width, 0, 100); @@ -3683,11 +3732,12 @@ void set_value_default() { config.view_current_to_back = 0; config.single_scratchpad = 1; config.xwayland_persistence = 1; - config.syncobj_enable = 0; + config.syncobj_enable = 1; config.tag_carousel = 0; config.drag_tile_refresh_interval = 8.0f; config.drag_floating_refresh_interval = 8.0f; config.allow_tearing = TEARING_DISABLED; + config.hdr_depth = MANGO_RENDER_BIT_DEPTH_10; config.allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; config.allow_lock_transparent = 0; config.no_border_when_single = 0; @@ -3701,7 +3751,7 @@ void set_value_default() { config.idleinhibit_ignore_visible = 0; config.borderpx = 4; - config.tab_bar_height = 50; + config.group_bar_height = 50; config.overviewgappi = 5; config.overviewgappo = 30; config.cursor_hide_timeout = 0; @@ -3738,7 +3788,6 @@ void set_value_default() { config.blur_layer = 0; config.blur_optimized = 1; config.border_radius = 0; - config.border_radius_location_default = CORNER_LOCATION_ALL; config.blur_params.num_passes = 1; config.blur_params.radius = 5; config.blur_params.noise = 0.02f; @@ -3789,30 +3838,30 @@ void set_value_default() { config.animation_curve_opafadeout[2] = 0.5; config.animation_curve_opafadeout[3] = 0.5; - config.tabdata.fg_color[0] = 0xc4 / 255.0f; - config.tabdata.fg_color[1] = 0x93 / 255.0f; - config.tabdata.fg_color[2] = 0x9d / 255.0f; - config.tabdata.fg_color[3] = 1.0f; - config.tabdata.bg_color[0] = 0x32 / 255.0f; - config.tabdata.bg_color[1] = 0x32 / 255.0f; - config.tabdata.bg_color[2] = 0x32 / 255.0f; - config.tabdata.bg_color[3] = 1.0f; - config.tabdata.focus_fg_color[0] = 0xed / 255.0f; - config.tabdata.focus_fg_color[1] = 0xa6 / 255.0f; - config.tabdata.focus_fg_color[2] = 0xb4 / 255.0f; - config.tabdata.focus_fg_color[3] = 1.0f; - config.tabdata.focus_bg_color[0] = 0x4e / 255.0f; - config.tabdata.focus_bg_color[1] = 0x45 / 255.0f; - config.tabdata.focus_bg_color[2] = 0x3c / 255.0f; - config.tabdata.focus_bg_color[3] = 1.0f; - config.tabdata.border_color[0] = 0x8b / 255.0f; - config.tabdata.border_color[1] = 0xaa / 255.0f; - config.tabdata.border_color[2] = 0x9b / 255.0f; - config.tabdata.border_color[3] = 1.0f; - config.tabdata.border_width = 4; - config.tabdata.corner_radius = 5; - config.tabdata.padding_x = 0; - config.tabdata.padding_y = 0; + config.groupbardata.fg_color[0] = 0xc4 / 255.0f; + config.groupbardata.fg_color[1] = 0x93 / 255.0f; + config.groupbardata.fg_color[2] = 0x9d / 255.0f; + config.groupbardata.fg_color[3] = 1.0f; + config.groupbardata.bg_color[0] = 0x32 / 255.0f; + config.groupbardata.bg_color[1] = 0x32 / 255.0f; + config.groupbardata.bg_color[2] = 0x32 / 255.0f; + config.groupbardata.bg_color[3] = 1.0f; + config.groupbardata.focus_fg_color[0] = 0xed / 255.0f; + config.groupbardata.focus_fg_color[1] = 0xa6 / 255.0f; + config.groupbardata.focus_fg_color[2] = 0xb4 / 255.0f; + config.groupbardata.focus_fg_color[3] = 1.0f; + config.groupbardata.focus_bg_color[0] = 0x4e / 255.0f; + config.groupbardata.focus_bg_color[1] = 0x45 / 255.0f; + config.groupbardata.focus_bg_color[2] = 0x3c / 255.0f; + config.groupbardata.focus_bg_color[3] = 1.0f; + config.groupbardata.border_color[0] = 0x8b / 255.0f; + config.groupbardata.border_color[1] = 0xaa / 255.0f; + config.groupbardata.border_color[2] = 0x9b / 255.0f; + config.groupbardata.border_color[3] = 1.0f; + config.groupbardata.border_width = 4; + config.groupbardata.corner_radius = 5; + config.groupbardata.padding_x = 0; + config.groupbardata.padding_y = 0; config.jumplabeldata.fg_color[0] = 0xc4 / 255.0f; config.jumplabeldata.fg_color[1] = 0x93 / 255.0f; @@ -3952,7 +4001,7 @@ bool parse_config(void) { config.tag_rules_count = 0; config.cursor_theme = NULL; config.jumplabeldata.font_desc = NULL; - config.tabdata.font_desc = NULL; + config.groupbardata.font_desc = NULL; config.tablet_map_to_mon = NULL; strcpy(config.keymode, "default"); @@ -4017,16 +4066,13 @@ void reset_blur_params(void) { void reapply_monitor_rules(void) { ConfigMonitorRule *mr; Monitor *m = NULL; - int32_t ji, vrr, custom; + int32_t ji; int32_t mx, my; - struct wlr_output_state state; wl_list_for_each(m, &mons, link) { if (!m->wlr_output->enabled) continue; - wlr_output_state_init(&state); - for (ji = 0; ji < config.monitor_rules_count; ji++) { if (config.monitor_rules_count < 1) break; @@ -4036,18 +4082,33 @@ void reapply_monitor_rules(void) { if (monitor_matches_rule(m, mr)) { mx = mr->x == INT32_MAX ? m->m.x : mr->x; my = mr->y == INT32_MAX ? m->m.y : mr->y; - vrr = mr->vrr >= 0 ? mr->vrr : 0; - custom = mr->custom >= 0 ? mr->custom : 0; - (void)apply_rule_to_state(m, mr, &state, vrr, custom); + apply_rule_to_state(m, mr, &m->pending); + wlr_output_layout_add(output_layout, m->wlr_output, mx, my); - wlr_output_commit_state(m->wlr_output, &state); break; } } - wlr_output_state_finish(&state); + if (m->prefer_disable) { + wlr_output_state_set_enabled(&m->pending, false); + } else { + wlr_output_state_set_enabled(&m->pending, true); + } + + if (m->hdr_enable) { + output_state_setup_hdr(m, false, &m->pending); + } + + if (!(mango_scene_output_commit(m->scene_output, &m->pending))) { + if (m->hdr_enable) { + output_state_setup_hdr(m, true, &m->pending); + } + } + wlr_output_effective_resolution(m->wlr_output, &m->m.width, + &m->m.height); } + updatemons(NULL, NULL); } @@ -4116,14 +4177,7 @@ void reapply_property(void) { if (!c->isnoborder && !c->isfullscreen) { c->bw = config.borderpx; } - - mango_jump_label_node_apply_config(c->jump_label_node, - &config.jumplabeldata); - mango_tab_bar_node_apply_config(c->tab_bar_node, &config.tabdata); - - wlr_scene_rect_set_color(c->droparea, config.dropcolor); - wlr_scene_rect_set_color(c->splitindicator[0], config.splitcolor); - wlr_scene_rect_set_color(c->splitindicator[1], config.splitcolor); + client_set_group_config(c); } } } diff --git a/src/dispatch/bind_declare.h b/src/dispatch/bind_declare.h index 6960b001..5f6e0f85 100644 --- a/src/dispatch/bind_declare.h +++ b/src/dispatch/bind_declare.h @@ -2,6 +2,8 @@ int32_t minimized(const Arg *arg); int32_t restore_minimized(const Arg *arg); int32_t toggle_scratchpad(const Arg *arg); int32_t focusdir(const Arg *arg); +int32_t groupjoin(const Arg *arg); +int32_t groupleave(const Arg *arg); int32_t toggleoverview(const Arg *arg); int32_t togglejump(const Arg *arg); int32_t set_proportion(const Arg *arg); @@ -38,6 +40,7 @@ int32_t toggleglobal(const Arg *arg); int32_t incnmaster(const Arg *arg); int32_t focusmon(const Arg *arg); int32_t focusstack(const Arg *arg); +int32_t groupfocus(const Arg *arg); int32_t chvt(const Arg *arg); int32_t reload_config(const Arg *arg); int32_t smartmovewin(const Arg *arg); @@ -70,6 +73,9 @@ int32_t setoption(const Arg *arg); int32_t disable_monitor(const Arg *arg); int32_t enable_monitor(const Arg *arg); int32_t toggle_monitor(const Arg *arg); +int32_t sleep_monitor(const Arg *arg); +int32_t wakeup_monitor(const Arg *arg); +int32_t sleep_toggle_monitor(const Arg *arg); int32_t scroller_stack(const Arg *arg); int32_t toggle_all_floating(const Arg *arg); int32_t dwindle_toggle_split_direction(const Arg *arg); diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index f3d5c0a7..8559a7f5 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -156,6 +156,94 @@ int32_t focusdir(const Arg *arg) { return 0; } +int32_t groupjoin(const Arg *arg) { + + if (!selmon) + return 0; + + Monitor *oldmon = NULL; + + Client *need_join_client = arg->tc ? arg->tc : selmon->sel; + if (!need_join_client || !need_join_client->mon) + return 0; + + if (need_join_client->mon->isoverview) + return 0; + + Client *need_replace_client = NULL; + need_replace_client = direction_select(arg); + + if (!need_replace_client || !need_replace_client->mon) + return 0; + + if (need_join_client == need_replace_client) + return 0; + + if (need_join_client->group_next || need_join_client->group_prev) { + groupleave(&(Arg){.tc = need_join_client}); + } + + if (need_join_client->mon != need_replace_client->mon) { + oldmon = need_join_client->mon; + need_join_client->mon = need_replace_client->mon; + } + + if (!need_replace_client->group_prev && !need_replace_client->group_next) { + need_replace_client->isgroupfocusing = true; + } + + need_join_client->group_next = need_replace_client; + + if (need_replace_client->group_prev) { + need_replace_client->group_prev->group_next = need_join_client; + } + + need_join_client->group_prev = need_replace_client->group_prev; + + need_replace_client->group_prev = need_join_client; + + client_focus_group_member(need_join_client); + arrange(need_join_client->mon, false, false); + + // oldmon可能已经死掉了 + if (oldmon) { + arrange(oldmon, false, false); + } + + return 0; +} + +int32_t groupleave(const Arg *arg) { + + if (!selmon) + return 0; + Client *tc = arg->tc ? arg->tc : selmon->sel; + if (!tc || !tc->mon || !tc->isgroupfocusing) + return 0; + if (!tc->group_next && !tc->group_prev) { + return 0; + } + + if (tc->mon->isoverview) + return 0; + + Client *rc = tc->group_next ? tc->group_next : tc->group_prev; + + client_focus_group_member(rc); + client_group_detach(tc); + + tc->isgroupfocusing = false; + tc->is_logic_hide = false; + + if (!rc->group_prev && !rc->group_next) { + rc->isgroupfocusing = false; + } + + arrange(tc->mon, false, false); + + return 0; +} + int32_t focuslast(const Arg *arg) { Client *c = NULL; Client *tc = NULL; @@ -261,6 +349,34 @@ int32_t focusstack(const Arg *arg) { return 0; } +int32_t groupfocus(const Arg *arg) { + Client *c = arg->tc ? arg->tc : selmon->sel; + if (!c || !c->mon) + return 0; + + if (!c->group_prev && !c->group_next) { + return 0; + } + + if (c->mon->isoverview) + return 0; + + Client *tc = NULL; + + if (arg->i == NEXT) { + tc = c->group_next; + } else { + tc = c->group_prev; + } + + if (!tc) + return 0; + + client_focus_group_member(tc); + arrange(tc->mon, false, false); + return 0; +} + int32_t incnmaster(const Arg *arg) { if (!arg || !selmon) return 0; @@ -366,7 +482,7 @@ int32_t moveresize(const Arg *arg) { if (cursor_mode != CurNormal && cursor_mode != CurPressed) return 0; - xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); + xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL, NULL); if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen || grabc->ismaximizescreen) { grabc = NULL; @@ -1427,15 +1543,7 @@ int32_t toggleoverlay(const Arg *arg) { c->isoverlay ^= 1; - if (c->isoverlay) { - wlr_scene_node_reparent(&c->scene->node, layers[LyrOverlay]); - wlr_scene_node_raise_to_top(&c->scene->node); - } else if (client_should_overtop(c) && c->isfloating) { - wlr_scene_node_reparent(&c->scene->node, layers[LyrTop]); - } else { - wlr_scene_node_reparent(&c->scene->node, - layers[c->isfloating ? LyrTop : LyrTile]); - } + client_reparent_group(c); setborder_color(c); return 0; } @@ -1825,12 +1933,12 @@ int32_t togglejump(const Arg *arg) { int32_t disable_monitor(const Arg *arg) { Monitor *m = NULL; - struct wlr_output_state state = {0}; + wl_list_for_each(m, &mons, link) { if (match_monitor_spec(arg->v, m)) { - wlr_output_state_set_enabled(&state, false); - wlr_output_commit_state(m->wlr_output, &state); - m->asleep = 1; + wlr_output_state_set_enabled(&m->pending, false); + mango_output_commit(m); + m->only_sleep = 0; updatemons(NULL, NULL); break; } @@ -1840,12 +1948,11 @@ int32_t disable_monitor(const Arg *arg) { int32_t enable_monitor(const Arg *arg) { Monitor *m = NULL; - struct wlr_output_state state = {0}; wl_list_for_each(m, &mons, link) { if (match_monitor_spec(arg->v, m)) { - wlr_output_state_set_enabled(&state, true); - wlr_output_commit_state(m->wlr_output, &state); - m->asleep = 0; + wlr_output_state_set_enabled(&m->pending, true); + mango_output_commit(m); + m->only_sleep = 0; updatemons(NULL, NULL); break; } @@ -1855,12 +1962,54 @@ int32_t enable_monitor(const Arg *arg) { int32_t toggle_monitor(const Arg *arg) { Monitor *m = NULL; - struct wlr_output_state state = {0}; wl_list_for_each(m, &mons, link) { if (match_monitor_spec(arg->v, m)) { - wlr_output_state_set_enabled(&state, !m->wlr_output->enabled); - wlr_output_commit_state(m->wlr_output, &state); - m->asleep = !m->wlr_output->enabled; + wlr_output_state_set_enabled(&m->pending, !m->wlr_output->enabled); + mango_output_commit(m); + m->only_sleep = 0; + updatemons(NULL, NULL); + break; + } + } + return 0; +} + +int32_t sleep_monitor(const Arg *arg) { + Monitor *m = NULL; + + wl_list_for_each(m, &mons, link) { + if (match_monitor_spec(arg->v, m)) { + wlr_output_state_set_enabled(&m->pending, false); + mango_output_commit(m); + m->only_sleep = 1; + updatemons(NULL, NULL); + break; + } + } + return 0; +} + +int32_t wakeup_monitor(const Arg *arg) { + Monitor *m = NULL; + wl_list_for_each(m, &mons, link) { + if (match_monitor_spec(arg->v, m)) { + wlr_output_state_set_enabled(&m->pending, true); + mango_output_commit(m); + m->only_sleep = 0; + updatemons(NULL, NULL); + break; + } + } + return 0; +} + +int32_t sleep_toggle_monitor(const Arg *arg) { + Monitor *m = NULL; + wl_list_for_each(m, &mons, link) { + if (match_monitor_spec(arg->v, m)) { + wlr_output_state_set_enabled(&m->pending, !m->wlr_output->enabled); + mango_output_commit(m); + m->only_sleep = !m->wlr_output->enabled; updatemons(NULL, NULL); break; } @@ -1912,13 +2061,11 @@ int32_t scroller_apply_stack(Client *c, Client *target_client, if (direction == LEFT || direction == UP) { if (c != stack_head) { - wl_list_remove(&c->link); - wl_list_insert(stack_head->link.prev, &c->link); + wl_list_safe_reinsert_prev(&stack_head->link, &c->link); } } else if (direction == RIGHT || direction == DOWN) { if (c != stack_tail) { - wl_list_remove(&c->link); - wl_list_insert(&stack_tail->link, &c->link); + wl_list_safe_reinsert_next(&stack_head->link, &c->link); } } sync_scroller_state_to_clients(m, tag); @@ -2001,7 +2148,8 @@ int32_t dwindle_set_split_direction(Client *c, bool istoggle, bool horizontal) { leaf->custom_leaf_split_h = false; } bool hit_no_border = check_hit_no_border(c); - apply_split_border(c, hit_no_border); + struct ivec2 offsets = compute_edge_offsets(c); + client_draw_split_border(c, hit_no_border, offsets); return 0; } @@ -2040,6 +2188,13 @@ int32_t focusid(const Arg *arg) { return 0; Client *c = arg->tc; + + if (c->swallowdby) + return 0; + + if (c->group_next || c->group_prev) + client_focus_group_member(c); + client_active(c); return 0; } \ No newline at end of file diff --git a/src/draw/text-node.c b/src/draw/text-node.c index c85b25dc..7e65b17e 100644 --- a/src/draw/text-node.c +++ b/src/draw/text-node.c @@ -59,10 +59,9 @@ static const struct wlr_buffer_impl text_buffer_impl = { .end_data_ptr_access = text_buffer_end_data_ptr_access, }; -struct mango_jump_label_node * -mango_jump_label_node_create(struct wlr_scene_tree *parent, - DecorateDrawData data) { - struct mango_jump_label_node *node = calloc(1, sizeof(*node)); +MangoJumpLabel *mango_jump_label_node_create(struct wlr_scene_tree *parent, + DecorateDrawData data) { + MangoJumpLabel *node = calloc(1, sizeof(*node)); if (!node) return NULL; @@ -104,7 +103,7 @@ mango_jump_label_node_create(struct wlr_scene_tree *parent, return node; } -void mango_jump_label_node_destroy(struct mango_jump_label_node *node) { +void mango_jump_label_node_destroy(MangoJumpLabel *node) { if (!node) return; @@ -136,8 +135,8 @@ void mango_jump_label_node_destroy(struct mango_jump_label_node *node) { free(node); } -void mango_jump_label_node_set_background(struct mango_jump_label_node *node, - float r, float g, float b, float a) { +void mango_jump_label_node_set_background(MangoJumpLabel *node, float r, + float g, float b, float a) { if (!node) return; node->bg_color[0] = r; @@ -146,9 +145,9 @@ void mango_jump_label_node_set_background(struct mango_jump_label_node *node, node->bg_color[3] = a; } -void mango_jump_label_node_set_border(struct mango_jump_label_node *node, - float r, float g, float b, float a, - int32_t width, int32_t radius) { +void mango_jump_label_node_set_border(MangoJumpLabel *node, float r, float g, + float b, float a, int32_t width, + int32_t radius) { if (!node) return; node->border_color[0] = r; @@ -159,17 +158,16 @@ void mango_jump_label_node_set_border(struct mango_jump_label_node *node, node->corner_radius = radius; } -void mango_jump_label_node_set_padding(struct mango_jump_label_node *node, - int32_t pad_x, int32_t pad_y) { +void mango_jump_label_node_set_padding(MangoJumpLabel *node, int32_t pad_x, + int32_t pad_y) { if (!node) return; node->padding_x = pad_x >= 0 ? pad_x : 0; node->padding_y = pad_y >= 0 ? pad_y : 0; } -static void get_text_pixel_size(struct mango_jump_label_node *node, - const char *text, float scale, int32_t *out_w, - int32_t *out_h) { +static void get_text_pixel_size(MangoJumpLabel *node, const char *text, + float scale, int32_t *out_w, int32_t *out_h) { if (node->measure_scale != scale) { pango_cairo_context_set_resolution(node->measure_context, 96.0 * scale); node->measure_scale = scale; @@ -184,6 +182,10 @@ static void get_text_pixel_size(struct mango_jump_label_node *node, static void draw_rounded_rect(cairo_t *cr, double x, double y, double w, double h, double r) { + // 宽高非正时不绘制任何东西 + if (w <= 0.0 || h <= 0.0) + return; + double degrees = G_PI / 180.0; cairo_new_sub_path(cr); cairo_arc(cr, x + w - r, y + r, r, -90 * degrees, 0 * degrees); @@ -193,14 +195,14 @@ static void draw_rounded_rect(cairo_t *cr, double x, double y, double w, cairo_close_path(cr); } -void mango_jump_label_node_update(struct mango_jump_label_node *node, - const char *text, float scale) { +void mango_jump_label_node_update(MangoJumpLabel *node, const char *text, + float scale) { if (!node || !text) return; if (scale <= 0.0f) scale = 1.0f; - /* 脏检查,加入 focused 状态 */ + // 脏检查 if (node->cached_scale == scale && node->cached_font_desc && strcmp(node->cached_font_desc, node->font_desc) == 0 && node->cached_text && strcmp(node->cached_text, text) == 0 && @@ -222,7 +224,7 @@ void mango_jump_label_node_update(struct mango_jump_label_node *node, return; } - /* 更新缓存 */ + // 更新缓存 g_free(node->cached_text); node->cached_text = g_strdup(text); g_free(node->cached_font_desc); @@ -266,6 +268,7 @@ void mango_jump_label_node_update(struct mango_jump_label_node *node, int32_t box_logical_w = logical_text_w + 2 * node->padding_x; int32_t box_logical_h = logical_text_h + 2 * node->padding_y; + // 物理像素尺寸包含边框,避免边框越界 int32_t required_pixel_w = (int32_t)((box_logical_w + 2 * node->border_width) * scale + 0.5f); int32_t required_pixel_h = @@ -318,13 +321,15 @@ void mango_jump_label_node_update(struct mango_jump_label_node *node, radius = bg_w / 2.0; if (radius > bg_h / 2.0) radius = bg_h / 2.0; + if (radius < 0.0) + radius = 0.0; const float *active_bg = node->focused ? node->focus_bg_color : node->bg_color; const float *active_fg = node->focused ? node->focus_fg_color : node->fg_color; - bool draw_bg = (active_bg[3] > 0.0f); // 使用 active_bg + bool draw_bg = (active_bg[3] > 0.0f) && (bg_w > 0.0 && bg_h > 0.0); bool draw_border = (node->border_width > 0) && (node->border_color[3] > 0.0f); @@ -340,25 +345,28 @@ void mango_jump_label_node_update(struct mango_jump_label_node *node, } } - cairo_save(cr); - double text_x = (node->border_width + node->padding_x) * scale; - double text_y = (node->border_width + node->padding_y) * scale; - cairo_translate(cr, text_x, text_y); + // 文本绘制仅在背景区域有有效空间时进行 + if (bg_w > 0.0 && bg_h > 0.0) { + cairo_save(cr); + double text_x = (node->border_width + node->padding_x) * scale; + double text_y = (node->border_width + node->padding_y) * scale; + cairo_translate(cr, text_x, text_y); - PangoContext *ctx = pango_cairo_create_context(cr); - pango_cairo_context_set_resolution(ctx, 96.0 * scale); - PangoLayout *layout = pango_layout_new(ctx); - PangoFontDescription *desc = get_cached_font_desc(node->font_desc); - pango_layout_set_font_description(layout, desc); - pango_layout_set_text(layout, text, -1); + PangoContext *ctx = pango_cairo_create_context(cr); + pango_cairo_context_set_resolution(ctx, 96.0 * scale); + PangoLayout *layout = pango_layout_new(ctx); + PangoFontDescription *desc = get_cached_font_desc(node->font_desc); + pango_layout_set_font_description(layout, desc); + pango_layout_set_text(layout, text, -1); - cairo_set_source_rgba(cr, active_fg[0], active_fg[1], active_fg[2], - active_fg[3]); - pango_cairo_show_layout(cr, layout); + cairo_set_source_rgba(cr, active_fg[0], active_fg[1], active_fg[2], + active_fg[3]); + pango_cairo_show_layout(cr, layout); - g_object_unref(layout); - g_object_unref(ctx); - cairo_restore(cr); + g_object_unref(layout); + g_object_unref(ctx); + cairo_restore(cr); + } if (draw_border) { cairo_set_source_rgba(cr, node->border_color[0], node->border_color[1], @@ -371,15 +379,35 @@ void mango_jump_label_node_update(struct mango_jump_label_node *node, double bw = bg_w + border; double bh = bg_h + border; - if (radius > 0.0) { - double outer_radius = radius + half_lw; - if (outer_radius < 0.0) - outer_radius = 0.0; - draw_rounded_rect(cr, bx, by, bw, bh, outer_radius); - } else { - cairo_rectangle(cr, bx, by, bw, bh); + // 确保边框矩形不越界且宽高为正 + if (bx < 0.0) { + bw += bx; // bx 为负,bw 缩小 + bx = 0.0; + } + if (by < 0.0) { + bh += by; + by = 0.0; + } + if (bx + bw > (double)node->surface_pixel_w) + bw = (double)node->surface_pixel_w - bx; + if (by + bh > (double)node->surface_pixel_h) + bh = (double)node->surface_pixel_h - by; + if (bw < 0.0) + bw = 0.0; + if (bh < 0.0) + bh = 0.0; + + if (bw > 0.0 && bh > 0.0) { + if (radius > 0.0) { + double outer_radius = radius + half_lw; + if (outer_radius < 0.0) + outer_radius = 0.0; + draw_rounded_rect(cr, bx, by, bw, bh, outer_radius); + } else { + cairo_rectangle(cr, bx, by, bw, bh); + } + cairo_stroke(cr); } - cairo_stroke(cr); } cairo_surface_flush(node->surface); @@ -407,67 +435,71 @@ void mango_jump_label_node_update(struct mango_jump_label_node *node, node->logical_height); } -void mango_jump_label_node_set_focus(struct mango_jump_label_node *node, - bool focused) { +void mango_jump_label_node_set_focus(MangoJumpLabel *node, bool focused) { if (!node || node->focused == focused) return; node->focused = focused; - // 使用缓存的文本和缩放触发重绘(如果无文本则不重绘) if (node->cached_text && node->cached_scale > 0.0f) { mango_jump_label_node_update(node, node->cached_text, node->cached_scale); } } -struct mango_tab_bar_node * -mango_tab_bar_node_create(void *mango_node_data, struct wlr_scene_tree *parent, - DecorateDrawData data, int32_t width, - int32_t height) { - struct mango_tab_bar_node *node = calloc(1, sizeof(*node)); - if (!node) +MangoGroupBar *mango_group_bar_create(void *cdata, uint32_t type, + struct wlr_scene_tree *parent, + DecorateDrawData data, int32_t width, + int32_t height) { + MangoGroupBar *mangobar = calloc(1, sizeof(*mangobar)); + if (!mangobar) return NULL; - node->scene_buffer = wlr_scene_buffer_create(parent, NULL); - if (!node->scene_buffer) { - free(node); + mangobar->scene_buffer = wlr_scene_buffer_create(parent, NULL); + if (!mangobar->scene_buffer) { + free(mangobar); return NULL; } - memcpy(node->fg_color, data.fg_color, sizeof(node->fg_color)); - memcpy(node->bg_color, data.bg_color, sizeof(node->bg_color)); - memcpy(node->focus_fg_color, data.focus_fg_color, - sizeof(node->focus_fg_color)); - memcpy(node->focus_bg_color, data.focus_bg_color, - sizeof(node->focus_bg_color)); - memcpy(node->border_color, data.border_color, sizeof(node->border_color)); - node->border_width = data.border_width; - node->corner_radius = data.corner_radius; - node->padding_x = data.padding_x; - node->padding_y = data.padding_y; - node->font_desc = + memcpy(mangobar->fg_color, data.fg_color, sizeof(mangobar->fg_color)); + memcpy(mangobar->bg_color, data.bg_color, sizeof(mangobar->bg_color)); + memcpy(mangobar->focus_fg_color, data.focus_fg_color, + sizeof(mangobar->focus_fg_color)); + memcpy(mangobar->focus_bg_color, data.focus_bg_color, + sizeof(mangobar->focus_bg_color)); + memcpy(mangobar->border_color, data.border_color, + sizeof(mangobar->border_color)); + mangobar->border_width = data.border_width; + mangobar->corner_radius = data.corner_radius; + mangobar->padding_x = data.padding_x; + mangobar->padding_y = data.padding_y; + mangobar->font_desc = g_strdup(data.font_desc ? data.font_desc : "monospace Bold 16"); - node->target_width = width; - node->target_height = height; - node->focused = false; - node->cached_focused = false; + mangobar->target_width = width; + mangobar->target_height = height; + mangobar->focused = false; + mangobar->cached_focused = false; - node->measure_surface = + mangobar->measure_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); - node->measure_cr = cairo_create(node->measure_surface); - node->measure_context = pango_cairo_create_context(node->measure_cr); - node->measure_layout = pango_layout_new(node->measure_context); - node->measure_scale = 1.0f; + mangobar->measure_cr = cairo_create(mangobar->measure_surface); + mangobar->measure_context = + pango_cairo_create_context(mangobar->measure_cr); + mangobar->measure_layout = pango_layout_new(mangobar->measure_context); + mangobar->measure_scale = 1.0f; - node->cached_scale = -1.0f; - node->last_text = NULL; - node->last_scale = 0.0f; - node->scene_buffer->node.data = mango_node_data; + mangobar->cached_scale = -1.0f; + mangobar->last_text = NULL; + mangobar->last_scale = 0.0f; - return node; + mangobar->type = type; + mangobar->node_data = cdata; + + mangobar->scene_buffer->node.data = mangobar; + + return mangobar; } -void mango_tab_bar_node_destroy(struct mango_tab_bar_node *node) { +void mango_group_bar_destroy(MangoGroupBar *node) { if (!node) return; @@ -492,19 +524,17 @@ void mango_tab_bar_node_destroy(struct mango_tab_bar_node *node) { if (node->measure_cr) cairo_destroy(node->measure_cr); - void *data = node->scene_buffer->node.data; wlr_scene_node_destroy(&node->scene_buffer->node); g_free(node->font_desc); g_free(node->cached_text); g_free(node->cached_font_desc); g_free(node->last_text); - free(data); free(node); } -void mango_tab_bar_node_set_size(struct mango_tab_bar_node *node, int32_t width, - int32_t height) { +void mango_group_bar_set_size(MangoGroupBar *node, int32_t width, + int32_t height) { if (!node) return; @@ -522,11 +552,11 @@ void mango_tab_bar_node_set_size(struct mango_tab_bar_node *node, int32_t width, const char *redraw_text = node->last_text ? node->last_text : ""; float redraw_scale = node->last_scale > 0.0f ? node->last_scale : 1.0f; - mango_tab_bar_node_update(node, redraw_text, redraw_scale); + mango_group_bar_update(node, redraw_text, redraw_scale); } -void mango_tab_bar_node_update(struct mango_tab_bar_node *node, - const char *text, float scale) { +void mango_group_bar_update(MangoGroupBar *node, const char *text, + float scale) { if (!node || !text) return; if (scale <= 0.0f) @@ -538,7 +568,7 @@ void mango_tab_bar_node_update(struct mango_tab_bar_node *node, node->last_text = safe_text; // 所有权转移 node->last_scale = scale; - // 脏检查加入 focused + // 脏检查 if (node->cached_scale == scale && node->cached_font_desc && strcmp(node->cached_font_desc, node->font_desc) == 0 && node->cached_text && strcmp(node->cached_text, safe_text) == 0 && @@ -608,8 +638,18 @@ void mango_tab_bar_node_update(struct mango_tab_bar_node *node, if (box_logical_h < 0) box_logical_h = 0; + // surface 物理尺寸包含边框,避免边框绘制越界 int32_t required_pixel_w = (int32_t)(node->target_width * scale + 0.5f); int32_t required_pixel_h = (int32_t)(node->target_height * scale + 0.5f); + // 如果边框会伸出 target 区域,则扩展 surface 尺寸以完全容纳 + double border_phys = node->border_width * scale; + if (border_phys > 0.0) { + // 边框描边会向外延伸 half line width,所以需要额外空间 + int extra_w = (int32_t)ceil(border_phys * 0.5); + int extra_h = (int32_t)ceil(border_phys * 0.5); + required_pixel_w += extra_w; + required_pixel_h += extra_h; + } if (required_pixel_w < 1) required_pixel_w = 1; if (required_pixel_h < 1) @@ -641,7 +681,6 @@ void mango_tab_bar_node_update(struct mango_tab_bar_node *node, cairo_paint(cr); cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - double border_phys = node->border_width * scale; double bg_x = border_phys; double bg_y = border_phys; double bg_w = box_logical_w * scale; @@ -657,13 +696,15 @@ void mango_tab_bar_node_update(struct mango_tab_bar_node *node, radius = bg_w / 2.0; if (radius > bg_h / 2.0) radius = bg_h / 2.0; + if (radius < 0.0) + radius = 0.0; const float *active_bg = node->focused ? node->focus_bg_color : node->bg_color; const float *active_fg = node->focused ? node->focus_fg_color : node->fg_color; - bool draw_bg = (active_bg[3] > 0.0f); + bool draw_bg = (active_bg[3] > 0.0f) && (bg_w > 0.0 && bg_h > 0.0); bool draw_border = (node->border_width > 0) && (node->border_color[3] > 0.0f); @@ -679,43 +720,46 @@ void mango_tab_bar_node_update(struct mango_tab_bar_node *node, } } - int32_t text_area_logical_w = box_logical_w - 2 * node->padding_x; - int32_t text_area_logical_h = box_logical_h - 2 * node->padding_y; - if (text_area_logical_w > 0 && text_area_logical_h > 0) { - cairo_save(cr); + // 仅在背景区域有空间时进行 + if (bg_w > 0.0 && bg_h > 0.0) { + int32_t text_area_logical_w = box_logical_w - 2 * node->padding_x; + int32_t text_area_logical_h = box_logical_h - 2 * node->padding_y; + if (text_area_logical_w > 0 && text_area_logical_h > 0) { + cairo_save(cr); - double text_x = (node->border_width + node->padding_x) * scale; - double text_y = (node->border_width + node->padding_y) * scale; - double text_area_w = text_area_logical_w * scale; - double text_area_h = text_area_logical_h * scale; + double text_x = (node->border_width + node->padding_x) * scale; + double text_y = (node->border_width + node->padding_y) * scale; + double text_area_w = text_area_logical_w * scale; + double text_area_h = text_area_logical_h * scale; - PangoContext *ctx = pango_cairo_create_context(cr); - pango_cairo_context_set_resolution(ctx, 96.0 * scale); - PangoLayout *layout = pango_layout_new(ctx); - PangoFontDescription *desc = get_cached_font_desc(node->font_desc); - pango_layout_set_font_description(layout, desc); - pango_layout_set_text(layout, safe_text, -1); + PangoContext *ctx = pango_cairo_create_context(cr); + pango_cairo_context_set_resolution(ctx, 96.0 * scale); + PangoLayout *layout = pango_layout_new(ctx); + PangoFontDescription *desc = get_cached_font_desc(node->font_desc); + pango_layout_set_font_description(layout, desc); + pango_layout_set_text(layout, safe_text, -1); - pango_layout_set_wrap(layout, PANGO_WRAP_NONE); - pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); - pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); - pango_layout_set_width(layout, (int)(text_area_w * PANGO_SCALE)); + pango_layout_set_wrap(layout, PANGO_WRAP_NONE); + pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); + pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); + pango_layout_set_width(layout, (int)(text_area_w * PANGO_SCALE)); - int text_pixel_w, text_pixel_h; - pango_layout_get_pixel_size(layout, &text_pixel_w, &text_pixel_h); - double y_offset = (text_area_h - text_pixel_h) / 2.0; - if (y_offset < 0) - y_offset = 0; + int text_pixel_w, text_pixel_h; + pango_layout_get_pixel_size(layout, &text_pixel_w, &text_pixel_h); + double y_offset = (text_area_h - text_pixel_h) / 2.0; + if (y_offset < 0) + y_offset = 0; - cairo_translate(cr, text_x, text_y + y_offset); + cairo_translate(cr, text_x, text_y + y_offset); - cairo_set_source_rgba(cr, active_fg[0], active_fg[1], active_fg[2], - active_fg[3]); - pango_cairo_show_layout(cr, layout); + cairo_set_source_rgba(cr, active_fg[0], active_fg[1], active_fg[2], + active_fg[3]); + pango_cairo_show_layout(cr, layout); - g_object_unref(layout); - g_object_unref(ctx); - cairo_restore(cr); + g_object_unref(layout); + g_object_unref(ctx); + cairo_restore(cr); + } } if (draw_border) { @@ -729,15 +773,35 @@ void mango_tab_bar_node_update(struct mango_tab_bar_node *node, double bw = bg_w + border_phys; double bh = bg_h + border_phys; - if (radius > 0.0) { - double outer_radius = radius + half_lw; - if (outer_radius < 0.0) - outer_radius = 0.0; - draw_rounded_rect(cr, bx, by, bw, bh, outer_radius); - } else { - cairo_rectangle(cr, bx, by, bw, bh); + // 确保边框矩形不越界且宽高为正 + if (bx < 0.0) { + bw += bx; + bx = 0.0; + } + if (by < 0.0) { + bh += by; + by = 0.0; + } + if (bx + bw > (double)node->surface_pixel_w) + bw = (double)node->surface_pixel_w - bx; + if (by + bh > (double)node->surface_pixel_h) + bh = (double)node->surface_pixel_h - by; + if (bw < 0.0) + bw = 0.0; + if (bh < 0.0) + bh = 0.0; + + if (bw > 0.0 && bh > 0.0) { + if (radius > 0.0) { + double outer_radius = radius + half_lw; + if (outer_radius < 0.0) + outer_radius = 0.0; + draw_rounded_rect(cr, bx, by, bw, bh, outer_radius); + } else { + cairo_rectangle(cr, bx, by, bw, bh); + } + cairo_stroke(cr); } - cairo_stroke(cr); } cairo_surface_flush(node->surface); @@ -765,19 +829,18 @@ void mango_tab_bar_node_update(struct mango_tab_bar_node *node, node->logical_height); } -void mango_tab_bar_node_set_focus(struct mango_tab_bar_node *node, - bool focused) { +void mango_group_bar_set_focus(MangoGroupBar *node, bool focused) { if (!node || node->focused == focused) return; node->focused = focused; if (node->last_text) { float scale = node->last_scale > 0.0f ? node->last_scale : 1.0f; - mango_tab_bar_node_update(node, node->last_text, scale); + mango_group_bar_update(node, node->last_text, scale); } } -void mango_tab_bar_node_set_colors(struct mango_tab_bar_node *node, - const float fg[4], const float bg[4]) { +void mango_group_bar_set_colors(MangoGroupBar *node, const float fg[4], + const float bg[4]) { if (!node) return; @@ -786,11 +849,11 @@ void mango_tab_bar_node_set_colors(struct mango_tab_bar_node *node, if (!node->focused && node->last_text) { float scale = node->last_scale > 0.0f ? node->last_scale : 1.0f; - mango_tab_bar_node_update(node, node->last_text, scale); + mango_group_bar_update(node, node->last_text, scale); } } -void mango_jump_label_node_apply_config(struct mango_jump_label_node *node, +void mango_jump_label_node_apply_config(MangoJumpLabel *node, const DecorateDrawData *data) { if (!node || !data) return; @@ -817,8 +880,8 @@ void mango_jump_label_node_apply_config(struct mango_jump_label_node *node, } } -void mango_tab_bar_node_apply_config(struct mango_tab_bar_node *node, - const DecorateDrawData *data) { +void mango_group_bar_apply_config(MangoGroupBar *node, + const DecorateDrawData *data) { if (!node || !data) return; @@ -840,6 +903,6 @@ void mango_tab_bar_node_apply_config(struct mango_tab_bar_node *node, if (node->last_text) { float scale = node->last_scale > 0.0f ? node->last_scale : 1.0f; - mango_tab_bar_node_update(node, node->last_text, scale); + mango_group_bar_update(node, node->last_text, scale); } } \ No newline at end of file diff --git a/src/draw/text-node.h b/src/draw/text-node.h index 079af908..23ac4f9a 100644 --- a/src/draw/text-node.h +++ b/src/draw/text-node.h @@ -26,8 +26,7 @@ struct mango_text_buffer { struct wlr_buffer base; cairo_surface_t *surface; }; - -struct mango_jump_label_node { +typedef struct { struct wlr_scene_buffer *scene_buffer; struct mango_text_buffer *buffer; cairo_surface_t *surface; @@ -70,13 +69,15 @@ struct mango_jump_label_node { int32_t logical_width; int32_t logical_height; -}; +} MangoJumpLabel; -struct mango_tab_bar_node { +typedef struct { + uint32_t type; // must at first in struct struct wlr_scene_buffer *scene_buffer; struct mango_text_buffer *buffer; cairo_surface_t *surface; int surface_pixel_w, surface_pixel_h; + void *node_data; // 存储窗口指针 // 初始配置 float fg_color[4]; @@ -126,41 +127,38 @@ struct mango_tab_bar_node { int32_t logical_width; int32_t logical_height; -}; +} MangoGroupBar; void mango_text_global_finish(void); -struct mango_jump_label_node * -mango_jump_label_node_create(struct wlr_scene_tree *parent, - DecorateDrawData data); -void mango_jump_label_node_destroy(struct mango_jump_label_node *node); -void mango_jump_label_node_set_background(struct mango_jump_label_node *node, - float r, float g, float b, float a); -void mango_jump_label_node_set_border(struct mango_jump_label_node *node, - float r, float g, float b, float a, - int32_t width, int32_t radius); -void mango_jump_label_node_set_padding(struct mango_jump_label_node *node, - int32_t pad_x, int32_t pad_y); -void mango_jump_label_node_update(struct mango_jump_label_node *node, - const char *text, float scale); +MangoJumpLabel *mango_jump_label_node_create(struct wlr_scene_tree *parent, + DecorateDrawData data); +void mango_jump_label_node_destroy(MangoJumpLabel *node); +void mango_jump_label_node_set_background(MangoJumpLabel *node, float r, + float g, float b, float a); +void mango_jump_label_node_set_border(MangoJumpLabel *node, float r, float g, + float b, float a, int32_t width, + int32_t radius); +void mango_jump_label_node_set_padding(MangoJumpLabel *node, int32_t pad_x, + int32_t pad_y); +void mango_jump_label_node_update(MangoJumpLabel *node, const char *text, + float scale); -struct mango_tab_bar_node * -mango_tab_bar_node_create(void *mango_node_data, struct wlr_scene_tree *parent, - DecorateDrawData data, int32_t width, int32_t height); -void mango_tab_bar_node_destroy(struct mango_tab_bar_node *node); -void mango_tab_bar_node_set_size(struct mango_tab_bar_node *node, int32_t width, - int32_t height); -void mango_tab_bar_node_update(struct mango_tab_bar_node *node, - const char *text, float scale); +MangoGroupBar *mango_group_bar_create(void *cdata, uint32_t type, + struct wlr_scene_tree *parent, + DecorateDrawData data, int32_t width, + int32_t height); +void mango_group_bar_destroy(MangoGroupBar *node); +void mango_group_bar_set_size(MangoGroupBar *node, int32_t width, + int32_t height); +void mango_group_bar_update(MangoGroupBar *node, const char *text, float scale); -void mango_jump_label_node_set_focus(struct mango_jump_label_node *node, - bool focused); -void mango_tab_bar_node_set_focus(struct mango_tab_bar_node *node, - bool focused); +void mango_jump_label_node_set_focus(MangoJumpLabel *node, bool focused); +void mango_group_bar_set_focus(MangoGroupBar *node, bool focused); -void mango_tab_bar_node_set_colors(struct mango_tab_bar_node *node, - const float fg[4], const float bg[4]); -void mango_jump_label_node_apply_config(struct mango_jump_label_node *node, +void mango_group_bar_set_colors(MangoGroupBar *node, const float fg[4], + const float bg[4]); +void mango_jump_label_node_apply_config(MangoJumpLabel *node, const DecorateDrawData *data); -void mango_tab_bar_node_apply_config(struct mango_tab_bar_node *node, - const DecorateDrawData *data); +void mango_group_bar_apply_config(MangoGroupBar *node, + const DecorateDrawData *data); #endif // jump_label_node_H \ No newline at end of file diff --git a/src/ext-protocol/all.h b/src/ext-protocol/all.h index fac2779d..f0282626 100644 --- a/src/ext-protocol/all.h +++ b/src/ext-protocol/all.h @@ -1,6 +1,6 @@ -#include "dwl-ipc.h" #include "ext-workspace.h" #include "foreign-toplevel.h" +#include "hdr.h" #include "tablet.h" #include "tearing.h" #include "text-input.h" diff --git a/src/ext-protocol/dwl-ipc.h b/src/ext-protocol/dwl-ipc.h deleted file mode 100644 index 53d96309..00000000 --- a/src/ext-protocol/dwl-ipc.h +++ /dev/null @@ -1,309 +0,0 @@ -#include "dwl-ipc-unstable-v2-protocol.h" - -static void dwl_ipc_manager_bind(struct wl_client *client, void *data, - uint32_t version, uint32_t id); -static void dwl_ipc_manager_destroy(struct wl_resource *resource); -static void dwl_ipc_manager_get_output(struct wl_client *client, - struct wl_resource *resource, - uint32_t id, struct wl_resource *output); -static void dwl_ipc_manager_release(struct wl_client *client, - struct wl_resource *resource); -static void dwl_ipc_output_destroy(struct wl_resource *resource); -static void dwl_ipc_output_printstatus(Monitor *monitor); -static void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output); -static void dwl_ipc_output_set_client_tags(struct wl_client *client, - struct wl_resource *resource, - uint32_t and_tags, - uint32_t xor_tags); -static void dwl_ipc_output_set_layout(struct wl_client *client, - struct wl_resource *resource, - uint32_t index); -static void dwl_ipc_output_set_tags(struct wl_client *client, - struct wl_resource *resource, - uint32_t tagmask, uint32_t toggle_tagset); -static void dwl_ipc_output_quit(struct wl_client *client, - struct wl_resource *resource); -static void dwl_ipc_output_dispatch(struct wl_client *client, - struct wl_resource *resource, - const char *dispatch, const char *arg1, - const char *arg2, const char *arg3, - const char *arg4, const char *arg5); -static void dwl_ipc_output_release(struct wl_client *client, - struct wl_resource *resource); - -/* global event handlers */ -static struct zdwl_ipc_manager_v2_interface dwl_manager_implementation = { - .release = dwl_ipc_manager_release, - .get_output = dwl_ipc_manager_get_output}; -static struct zdwl_ipc_output_v2_interface dwl_output_implementation = { - .release = dwl_ipc_output_release, - .set_tags = dwl_ipc_output_set_tags, - .quit = dwl_ipc_output_quit, - .dispatch = dwl_ipc_output_dispatch, - .set_layout = dwl_ipc_output_set_layout, - .set_client_tags = dwl_ipc_output_set_client_tags}; - -void dwl_ipc_manager_bind(struct wl_client *client, void *data, - uint32_t version, uint32_t id) { - struct wl_resource *manager_resource = - wl_resource_create(client, &zdwl_ipc_manager_v2_interface, version, id); - if (!manager_resource) { - wl_client_post_no_memory(client); - return; - } - wl_resource_set_implementation(manager_resource, - &dwl_manager_implementation, NULL, - dwl_ipc_manager_destroy); - - zdwl_ipc_manager_v2_send_tags(manager_resource, LENGTH(tags)); - - for (uint32_t i = 0; i < LENGTH(layouts); i++) - zdwl_ipc_manager_v2_send_layout(manager_resource, layouts[i].symbol); -} - -void dwl_ipc_manager_destroy(struct wl_resource *resource) { - /* No state to destroy */ -} - -void dwl_ipc_manager_get_output(struct wl_client *client, - struct wl_resource *resource, uint32_t id, - struct wl_resource *output) { - DwlIpcOutput *ipc_output; - struct wlr_output *op = wlr_output_from_resource(output); - if (!op) - return; - Monitor *monitor = op->data; - struct wl_resource *output_resource = - wl_resource_create(client, &zdwl_ipc_output_v2_interface, - wl_resource_get_version(resource), id); - if (!output_resource) - return; - - ipc_output = ecalloc(1, sizeof(*ipc_output)); - ipc_output->resource = output_resource; - ipc_output->mon = monitor; - wl_resource_set_implementation(output_resource, &dwl_output_implementation, - ipc_output, dwl_ipc_output_destroy); - wl_list_insert(&monitor->dwl_ipc_outputs, &ipc_output->link); - dwl_ipc_output_printstatus_to(ipc_output); -} - -void dwl_ipc_manager_release(struct wl_client *client, - struct wl_resource *resource) { - wl_resource_destroy(resource); -} - -static void dwl_ipc_output_destroy(struct wl_resource *resource) { - DwlIpcOutput *ipc_output = wl_resource_get_user_data(resource); - wl_list_remove(&ipc_output->link); - free(ipc_output); -} - -// 修改IPC输出函数,接受掩码参数 -void dwl_ipc_output_printstatus(Monitor *monitor) { - DwlIpcOutput *ipc_output; - wl_list_for_each(ipc_output, &monitor->dwl_ipc_outputs, link) - dwl_ipc_output_printstatus_to(ipc_output); -} - -// 修改主IPC输出函数,根据掩码发送相应事件 -void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output) { - Monitor *monitor = ipc_output->mon; - Client *c = NULL, *focused = NULL; - struct wlr_keyboard *keyboard; - xkb_layout_index_t current; - int32_t tagmask, state, numclients, focused_client, tag; - const char *title, *appid, *symbol; - char kb_layout[32]; - focused = focustop(monitor); - zdwl_ipc_output_v2_send_active(ipc_output->resource, monitor == selmon); - - for (tag = 0; tag < LENGTH(tags); tag++) { - numclients = state = focused_client = 0; - tagmask = 1 << tag; - if ((tagmask & monitor->tagset[monitor->seltags]) != 0) - state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_ACTIVE; - wl_list_for_each(c, &clients, link) { - if (c->mon != monitor) - continue; - if (!(c->tags & tagmask)) - continue; - if (c == focused) - focused_client = 1; - if (c->isurgent) - state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_URGENT; - numclients++; - } - zdwl_ipc_output_v2_send_tag(ipc_output->resource, tag, state, - numclients, focused_client); - } - - title = focused ? client_get_title(focused) : ""; - appid = focused ? client_get_appid(focused) : ""; - - if (monitor->isoverview) { - symbol = overviewlayout.symbol; - } else { - symbol = monitor->pertag->ltidxs[monitor->pertag->curtag]->symbol; - } - - keyboard = &kb_group->wlr_group->keyboard; - current = xkb_state_serialize_layout(keyboard->xkb_state, - XKB_STATE_LAYOUT_EFFECTIVE); - get_layout_abbr(kb_layout, - xkb_keymap_layout_get_name(keyboard->keymap, current)); - - zdwl_ipc_output_v2_send_layout( - ipc_output->resource, - monitor->pertag->ltidxs[monitor->pertag->curtag] - layouts); - zdwl_ipc_output_v2_send_title(ipc_output->resource, title ? title : broken); - zdwl_ipc_output_v2_send_appid(ipc_output->resource, appid ? appid : broken); - zdwl_ipc_output_v2_send_layout_symbol(ipc_output->resource, symbol); - if (wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_FULLSCREEN_SINCE_VERSION) { - zdwl_ipc_output_v2_send_fullscreen(ipc_output->resource, - focused ? focused->isfullscreen : 0); - } - if (wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION) { - zdwl_ipc_output_v2_send_floating(ipc_output->resource, - focused ? focused->isfloating : 0); - } - if (wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_X_SINCE_VERSION) { - zdwl_ipc_output_v2_send_x(ipc_output->resource, - focused ? focused->geom.x : 0); - } - if (wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_Y_SINCE_VERSION) { - zdwl_ipc_output_v2_send_y(ipc_output->resource, - focused ? focused->geom.y : 0); - } - if (wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_WIDTH_SINCE_VERSION) { - zdwl_ipc_output_v2_send_width(ipc_output->resource, - focused ? focused->geom.width : 0); - } - if (wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_HEIGHT_SINCE_VERSION) { - zdwl_ipc_output_v2_send_height(ipc_output->resource, - focused ? focused->geom.height : 0); - } - if (wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_LAST_LAYER_SINCE_VERSION) { - zdwl_ipc_output_v2_send_last_layer(ipc_output->resource, - monitor->last_open_surface); - } - - if (wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_KB_LAYOUT_SINCE_VERSION) { - zdwl_ipc_output_v2_send_kb_layout(ipc_output->resource, kb_layout); - } - - if (wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_KEYMODE_SINCE_VERSION) { - zdwl_ipc_output_v2_send_keymode(ipc_output->resource, keymode.mode); - } - - if (wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_SCALEFACTOR_SINCE_VERSION) { - zdwl_ipc_output_v2_send_scalefactor(ipc_output->resource, - monitor->wlr_output->scale * 100); - } - - zdwl_ipc_output_v2_send_frame(ipc_output->resource); -} - -void dwl_ipc_output_set_client_tags(struct wl_client *client, - struct wl_resource *resource, - uint32_t and_tags, uint32_t xor_tags) { - DwlIpcOutput *ipc_output; - Monitor *monitor = NULL; - Client *selected_client = NULL; - uint32_t newtags = 0; - - ipc_output = wl_resource_get_user_data(resource); - if (!ipc_output) - return; - - monitor = ipc_output->mon; - selected_client = focustop(monitor); - if (!selected_client) - return; - - newtags = (selected_client->tags & and_tags) ^ xor_tags; - if (!newtags) - return; - - selected_client->tags = newtags; - if (selmon == monitor) - focusclient(focustop(monitor), 1); - arrange(selmon, false, false); - printstatus(IPC_WATCH_ARRANGGE); -} - -void dwl_ipc_output_set_layout(struct wl_client *client, - struct wl_resource *resource, uint32_t index) { - DwlIpcOutput *ipc_output; - Monitor *monitor = NULL; - - ipc_output = wl_resource_get_user_data(resource); - if (!ipc_output) - return; - - monitor = ipc_output->mon; - if (index >= LENGTH(layouts)) - index = 0; - - monitor->pertag->ltidxs[monitor->pertag->curtag] = &layouts[index]; - clear_fullscreen_and_maximized_state(monitor); - arrange(monitor, false, false); - printstatus(IPC_WATCH_ARRANGGE); -} - -void dwl_ipc_output_set_tags(struct wl_client *client, - struct wl_resource *resource, uint32_t tagmask, - uint32_t toggle_tagset) { - DwlIpcOutput *ipc_output; - Monitor *monitor = NULL; - uint32_t newtags = tagmask & TAGMASK; - - ipc_output = wl_resource_get_user_data(resource); - if (!ipc_output) - return; - monitor = ipc_output->mon; - - view_in_mon(&(Arg){.ui = newtags}, true, monitor, true); -} - -void dwl_ipc_output_quit(struct wl_client *client, - struct wl_resource *resource) { - quit(&(Arg){0}); -} - -void dwl_ipc_output_dispatch(struct wl_client *client, - struct wl_resource *resource, const char *dispatch, - const char *arg1, const char *arg2, - const char *arg3, const char *arg4, - const char *arg5) { - - int32_t (*func)(const Arg *); - Arg arg; - func = parse_func_name((char *)dispatch, &arg, (char *)arg1, (char *)arg2, - (char *)arg3, (char *)arg4, (char *)arg5); - if (func) { - func(&arg); - } - - if (arg.v) - free(arg.v); - if (arg.v2) - free(arg.v2); - if (arg.v3) - free(arg.v3); -} - -void dwl_ipc_output_release(struct wl_client *client, - struct wl_resource *resource) { - wl_resource_destroy(resource); -} diff --git a/src/ext-protocol/ext-workspace.h b/src/ext-protocol/ext-workspace.h index eea0f455..70bc2f6c 100644 --- a/src/ext-protocol/ext-workspace.h +++ b/src/ext-protocol/ext-workspace.h @@ -1,4 +1,4 @@ -#include "wlr_ext_workspace_v1.h" +#include #define EXT_WORKSPACE_ENABLE_CAPS \ EXT_WORKSPACE_HANDLE_V1_WORKSPACE_CAPABILITIES_ACTIVATE | \ @@ -148,7 +148,7 @@ static void add_workspace_by_tag(int32_t tag, Monitor *m) { wlr_ext_workspace_handle_v1_set_name(workspace->ext_workspace, name); } -void dwl_ext_workspace_printstatus(Monitor *m) { +void mango_ext_workspace_printstatus(Monitor *m) { struct workspace *w; uint32_t tag_status = 0; @@ -199,7 +199,7 @@ void refresh_monitors_workspaces_status(Monitor *m) { } } - dwl_ext_workspace_printstatus(m); + mango_ext_workspace_printstatus(m); } void workspaces_init() { diff --git a/src/ext-protocol/foreign-toplevel.h b/src/ext-protocol/foreign-toplevel.h index a8c49c77..eb5e7f0b 100644 --- a/src/ext-protocol/foreign-toplevel.h +++ b/src/ext-protocol/foreign-toplevel.h @@ -12,7 +12,7 @@ void handle_foreign_maximize_request(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, foreign_maximize_request); struct wlr_foreign_toplevel_handle_v1_maximized_event *event = data; - if (c->swallowing || !c->mon) + if (c->swallowdby || !c->mon) return; if (c->ismaximizescreen && !event->maximized) { @@ -30,7 +30,7 @@ void handle_foreign_minimize_request(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, foreign_minimize_request); struct wlr_foreign_toplevel_handle_v1_minimized_event *event = data; - if (c->swallowing || !c->mon) + if (c->swallowdby || !c->mon) return; if (!c->isminimized && event->minimized) { @@ -55,7 +55,7 @@ void handle_foreign_fullscreen_request(struct wl_listener *listener, Client *c = wl_container_of(listener, c, foreign_fullscreen_request); struct wlr_foreign_toplevel_handle_v1_fullscreen_event *event = data; - if (c->swallowing || !c->mon) + if (c->swallowdby || !c->mon) return; if (c->isfullscreen && !event->fullscreen) { diff --git a/src/ext-protocol/hdr.h b/src/ext-protocol/hdr.h new file mode 100644 index 00000000..7b82a983 --- /dev/null +++ b/src/ext-protocol/hdr.h @@ -0,0 +1,131 @@ +#include + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +static uint32_t output_formats_8bit[] = { + DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_RGBX8888, + DRM_FORMAT_BGRX8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_ABGR8888, + DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_RGB888, + DRM_FORMAT_BGR888, +}; + +static uint32_t output_formats_10bit[] = { + DRM_FORMAT_XRGB2101010, DRM_FORMAT_XBGR2101010, DRM_FORMAT_RGBX1010102, + DRM_FORMAT_BGRX1010102, DRM_FORMAT_ARGB2101010, DRM_FORMAT_ABGR2101010, + DRM_FORMAT_RGBA1010102, DRM_FORMAT_BGRA1010102, +}; + +static bool output_set_render_format(Monitor *m, uint32_t candidates[], + size_t count, + struct wlr_output_state *state) { + for (size_t i = 0; i < count; i++) { + wlr_output_state_set_render_format(state, candidates[i]); + if (wlr_output_test_state(m->wlr_output, state)) + return true; + } + return false; +} + +static bool output_format_in_candidates(uint32_t format, uint32_t candidates[], + size_t count) { + for (size_t i = 0; i < count; i++) + if (candidates[i] == format) + return true; + return false; +} + +static enum render_bit_depth bit_depth_from_format(uint32_t render_format) { + if (output_format_in_candidates(render_format, output_formats_10bit, + ARRAY_SIZE(output_formats_10bit))) + return MANGO_RENDER_BIT_DEPTH_10; + if (output_format_in_candidates(render_format, output_formats_8bit, + ARRAY_SIZE(output_formats_8bit))) + return MANGO_RENDER_BIT_DEPTH_8; + return MANGO_RENDER_BIT_DEPTH_DEFAULT; +} + +static bool output_supports_hdr(const struct wlr_output *output, + const char **reason) { + const char *r = NULL; + if (!(output->supported_primaries & WLR_COLOR_NAMED_PRIMARIES_BT2020)) + r = "BT2020 primaries not supported"; + else if (!(output->supported_transfer_functions & + WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ)) + r = "PQ transfer function not supported"; + else if (!drw->features.output_color_transform) + r = "renderer doesn't support output color transforms"; + if (reason) + *reason = r; + return !r; +} + +void output_enable_hdr(Monitor *m, struct wlr_output_state *os, bool enabled, + bool silent) { + if (enabled && !output_supports_hdr(m->wlr_output, NULL)) + enabled = false; + + if (!enabled) { + if (m->wlr_output->supported_primaries || + m->wlr_output->supported_transfer_functions) { + if (!silent) + wlr_log(WLR_DEBUG, "Disabling HDR on output %s", + m->wlr_output->name); + wlr_output_state_set_image_description(os, NULL); + } + return; + } + + if (!silent) + wlr_log(WLR_DEBUG, "Enabling HDR on output %s", m->wlr_output->name); + struct wlr_output_image_description desc = { + .primaries = WLR_COLOR_NAMED_PRIMARIES_BT2020, + .transfer_function = WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ, + }; + wlr_output_state_set_image_description(os, &desc); +} + +void output_state_setup_hdr(Monitor *m, bool silent, + struct wlr_output_state *state) { + uint32_t render_format = m->wlr_output->render_format; + const char *unsupported_reason = NULL; + bool hdr_supported = + output_supports_hdr(m->wlr_output, &unsupported_reason); + bool hdr_succeeded = false; + + enum render_bit_depth depth = config.hdr_depth; + if (depth == MANGO_RENDER_BIT_DEPTH_DEFAULT) + depth = bit_depth_from_format(render_format); + + if (!hdr_supported && depth == MANGO_RENDER_BIT_DEPTH_10) { + if (!silent) + wlr_log(WLR_INFO, "Cannot enable HDR on output %s: %s", + m->wlr_output->name, unsupported_reason); + depth = MANGO_RENDER_BIT_DEPTH_8; + } + + if (depth == MANGO_RENDER_BIT_DEPTH_10 && + bit_depth_from_format(render_format) == depth) { + hdr_succeeded = true; // 上次已经成功设置10位,直接复用 + } else if (depth == MANGO_RENDER_BIT_DEPTH_10) { + hdr_succeeded = output_set_render_format( + m, output_formats_10bit, ARRAY_SIZE(output_formats_10bit), state); + if (!hdr_succeeded) { + if (!silent) + wlr_log(WLR_INFO, + "No 10 bit color formats supported, HDR disabled."); + if (!output_set_render_format(m, output_formats_8bit, + ARRAY_SIZE(output_formats_8bit), + state)) + if (!silent) + wlr_log(WLR_ERROR, "No 8 bit color formats either!"); + } + } else { + // 明确要求8位或自动降级 + if (!output_set_render_format(m, output_formats_8bit, + ARRAY_SIZE(output_formats_8bit), state)) + if (!silent) + wlr_log(WLR_ERROR, "No 8 bit color formats supported!"); + } + + output_enable_hdr(m, state, hdr_succeeded, silent); +} \ No newline at end of file diff --git a/src/ext-protocol/tablet.h b/src/ext-protocol/tablet.h index 34c82dbf..afa0ebc1 100644 --- a/src/ext-protocol/tablet.h +++ b/src/ext-protocol/tablet.h @@ -281,7 +281,7 @@ void tablettoolmotion(struct TabletTool *tool, bool change_x, bool change_y, if (config.sloppyfocus) selmon = xytomon(cursor->x, cursor->y); - xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy); + xytonode(cursor->x, cursor->y, &surface, &c, NULL, NULL, &sx, &sy); if (cursor_mode == CurPressed && !seat->drag && surface != seat->pointer_state.focused_surface && toplevel_from_wlr_surface(seat->pointer_state.focused_surface, &w, diff --git a/src/ext-protocol/tearing.h b/src/ext-protocol/tearing.h index 5a9851e4..90143423 100644 --- a/src/ext-protocol/tearing.h +++ b/src/ext-protocol/tearing.h @@ -1,3 +1,4 @@ +#include #include struct tearing_controller { @@ -64,6 +65,9 @@ bool check_tearing_frame_allow(Monitor *m) { return false; } + if (!selmon) + return false; + Client *c = selmon->sel; /* tearing is only allowed for the output with the active client */ @@ -94,79 +98,3 @@ bool check_tearing_frame_allow(Monitor *m) { /* honor tearing as requested by action */ return c->force_tearing == STATE_ENABLED; } - -bool custom_wlr_scene_output_commit(struct wlr_scene_output *scene_output, - struct wlr_output_state *state) { - struct wlr_output *wlr_output = scene_output->output; - Monitor *m = wlr_output->data; - - // 检查是否需要帧 - if (!wlr_scene_output_needs_frame(scene_output)) { - wlr_log(WLR_DEBUG, "No frame needed for output %s", wlr_output->name); - return true; - } - - // 构建输出状态 - if (!wlr_scene_output_build_state(scene_output, state, NULL)) { - wlr_log(WLR_ERROR, "Failed to build output state for %s", - wlr_output->name); - return false; - } - - // 测试撕裂翻页 - if (state->tearing_page_flip) { - if (!wlr_output_test_state(wlr_output, state)) { - state->tearing_page_flip = false; - } - } - - // 尝试提交 - bool committed = wlr_output_commit_state(wlr_output, state); - - // 如果启用撕裂翻页但提交失败,重试禁用撕裂翻页 - if (!committed && state->tearing_page_flip) { - wlr_log(WLR_DEBUG, "Retrying commit without tearing for %s", - wlr_output->name); - state->tearing_page_flip = false; - committed = wlr_output_commit_state(wlr_output, state); - } - - // 处理状态清理 - if (committed) { - wlr_log(WLR_DEBUG, "Successfully committed output %s", - wlr_output->name); - if (state == &m->pending) { - wlr_output_state_finish(&m->pending); - wlr_output_state_init(&m->pending); - } - } else { - wlr_log(WLR_ERROR, "Failed to commit output %s", wlr_output->name); - // 即使提交失败,也清理状态避免积累 - if (state == &m->pending) { - wlr_output_state_finish(&m->pending); - wlr_output_state_init(&m->pending); - } - return false; - } - - return true; -} - -void apply_tear_state(Monitor *m) { - if (wlr_scene_output_needs_frame(m->scene_output)) { - wlr_output_state_init(&m->pending); - if (wlr_scene_output_build_state(m->scene_output, &m->pending, NULL)) { - struct wlr_output_state *pending = &m->pending; - pending->tearing_page_flip = true; - - if (!custom_wlr_scene_output_commit(m->scene_output, pending)) { - wlr_log(WLR_ERROR, "Failed to commit output %s", - m->scene_output->output->name); - } - } else { - wlr_log(WLR_ERROR, "Failed to build state for output %s", - m->scene_output->output->name); - wlr_output_state_finish(&m->pending); - } - } -} \ No newline at end of file diff --git a/src/ext-protocol/text-input.h b/src/ext-protocol/text-input.h index e9f221a4..32a69bee 100644 --- a/src/ext-protocol/text-input.h +++ b/src/ext-protocol/text-input.h @@ -2,7 +2,7 @@ #include #include -struct dwl_input_method_relay { +struct mango_input_method_relay { struct wl_list text_inputs; struct wlr_input_method_v2 *input_method; struct wlr_surface *focused_surface; @@ -26,11 +26,12 @@ struct dwl_input_method_relay { struct wl_listener focused_surface_destroy; }; -struct dwl_input_method_popup { +struct mango_input_method_popup { + uint32_t type; // must at first in struct struct wlr_input_popup_surface_v2 *popup_surface; struct wlr_scene_tree *tree; struct wlr_scene_tree *scene_surface; - struct dwl_input_method_relay *relay; + struct mango_input_method_relay *relay; struct wl_list link; struct wl_listener destroy; @@ -38,7 +39,7 @@ struct dwl_input_method_popup { }; struct text_input { - struct dwl_input_method_relay *relay; + struct mango_input_method_relay *relay; struct wlr_text_input_v3 *input; struct wl_list link; @@ -50,20 +51,20 @@ struct text_input { struct wlr_input_method_manager_v2 *input_method_manager; struct wlr_text_input_manager_v3 *text_input_manager; -struct dwl_input_method_relay *dwl_input_method_relay; +struct mango_input_method_relay *mango_input_method_relay; /*-------------------封装给外部调用-------------------------------*/ -bool dwl_im_keyboard_grab_forward_key(KeyboardGroup *keyboard, - struct wlr_keyboard_key_event *event); +bool mango_im_keyboard_grab_forward_key(KeyboardGroup *keyboard, + struct wlr_keyboard_key_event *event); -bool dwl_im_keyboard_grab_forward_modifiers(KeyboardGroup *keyboard); +bool mango_im_keyboard_grab_forward_modifiers(KeyboardGroup *keyboard); -struct dwl_input_method_relay *dwl_im_relay_create(); +struct mango_input_method_relay *mango_im_relay_create(); -void dwl_im_relay_finish(struct dwl_input_method_relay *relay); +void mango_im_relay_finish(struct mango_input_method_relay *relay); -void dwl_im_relay_set_focus(struct dwl_input_method_relay *relay, - struct wlr_surface *surface); +void mango_im_relay_set_focus(struct mango_input_method_relay *relay, + struct wlr_surface *surface); /*----------------------------------------------------------*/ /*------------------协议内部代码------------------------------*/ @@ -97,7 +98,7 @@ is_keyboard_emulated_by_input_method(struct wlr_keyboard *keyboard, static struct wlr_input_method_keyboard_grab_v2 * get_keyboard_grab(KeyboardGroup *keyboard) { struct wlr_input_method_v2 *input_method = - dwl_input_method_relay->input_method; + mango_input_method_relay->input_method; if (!input_method || !input_method->keyboard_grab) { return NULL; } @@ -114,7 +115,7 @@ get_keyboard_grab(KeyboardGroup *keyboard) { return input_method->keyboard_grab; } -bool dwl_im_keyboard_grab_forward_modifiers(KeyboardGroup *keyboard) { +bool mango_im_keyboard_grab_forward_modifiers(KeyboardGroup *keyboard) { struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = get_keyboard_grab(keyboard); @@ -132,8 +133,8 @@ bool dwl_im_keyboard_grab_forward_modifiers(KeyboardGroup *keyboard) { } } -bool dwl_im_keyboard_grab_forward_key(KeyboardGroup *keyboard, - struct wlr_keyboard_key_event *event) { +bool mango_im_keyboard_grab_forward_key(KeyboardGroup *keyboard, + struct wlr_keyboard_key_event *event) { struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = get_keyboard_grab(keyboard); @@ -149,7 +150,7 @@ bool dwl_im_keyboard_grab_forward_key(KeyboardGroup *keyboard, } static struct text_input * -get_active_text_input(struct dwl_input_method_relay *relay) { +get_active_text_input(struct mango_input_method_relay *relay) { struct text_input *text_input; if (!relay->input_method) { @@ -164,7 +165,7 @@ get_active_text_input(struct dwl_input_method_relay *relay) { return NULL; } -static void update_active_text_input(struct dwl_input_method_relay *relay) { +static void update_active_text_input(struct mango_input_method_relay *relay) { struct text_input *active_text_input = get_active_text_input(relay); if (relay->input_method && relay->active_text_input != active_text_input) { @@ -180,7 +181,7 @@ static void update_active_text_input(struct dwl_input_method_relay *relay) { } static void -update_text_inputs_focused_surface(struct dwl_input_method_relay *relay) { +update_text_inputs_focused_surface(struct mango_input_method_relay *relay) { struct text_input *text_input; wl_list_for_each(text_input, &relay->text_inputs, link) { struct wlr_text_input_v3 *input = text_input->input; @@ -206,8 +207,8 @@ update_text_inputs_focused_surface(struct dwl_input_method_relay *relay) { } } -static void update_popup_position(struct dwl_input_method_popup *popup) { - struct dwl_input_method_relay *relay = popup->relay; +static void update_popup_position(struct mango_input_method_popup *popup) { + struct mango_input_method_relay *relay = popup->relay; struct text_input *text_input = relay->active_text_input; struct wlr_box cursor_rect; struct wlr_xdg_surface *xdg_surface; @@ -281,8 +282,8 @@ static void update_popup_position(struct dwl_input_method_popup *popup) { }); } -static void update_popups_position(struct dwl_input_method_relay *relay) { - struct dwl_input_method_popup *popup; +static void update_popups_position(struct mango_input_method_relay *relay) { + struct mango_input_method_popup *popup; wl_list_for_each(popup, &relay->popups, link) { update_popup_position(popup); } @@ -290,11 +291,10 @@ static void update_popups_position(struct dwl_input_method_relay *relay) { static void handle_input_method_commit(struct wl_listener *listener, void *data) { - struct dwl_input_method_relay *relay = + struct mango_input_method_relay *relay = wl_container_of(listener, relay, input_method_commit); - struct wlr_input_method_v2 *input_method = data; struct text_input *text_input; - assert(relay->input_method == input_method); + struct wlr_input_method_v2 *input_method = relay->input_method; text_input = relay->active_text_input; if (!text_input) { @@ -322,9 +322,10 @@ static void handle_input_method_commit(struct wl_listener *listener, static void handle_keyboard_grab_destroy(struct wl_listener *listener, void *data) { - struct dwl_input_method_relay *relay = + struct mango_input_method_relay *relay = wl_container_of(listener, relay, keyboard_grab_destroy); - struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data; + struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = + relay->input_method->keyboard_grab; wl_list_remove(&relay->keyboard_grab_destroy.link); if (keyboard_grab->keyboard) { @@ -335,7 +336,7 @@ static void handle_keyboard_grab_destroy(struct wl_listener *listener, static void handle_input_method_grab_keyboard(struct wl_listener *listener, void *data) { - struct dwl_input_method_relay *relay = + struct mango_input_method_relay *relay = wl_container_of(listener, relay, input_method_grab_keyboard); struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data; @@ -354,9 +355,8 @@ static void handle_input_method_grab_keyboard(struct wl_listener *listener, static void handle_input_method_destroy(struct wl_listener *listener, void *data) { - struct dwl_input_method_relay *relay = + struct mango_input_method_relay *relay = wl_container_of(listener, relay, input_method_destroy); - assert(relay->input_method == data); wl_list_remove(&relay->input_method_commit.link); wl_list_remove(&relay->input_method_grab_keyboard.link); wl_list_remove(&relay->input_method_new_popup_surface.link); @@ -369,7 +369,7 @@ static void handle_input_method_destroy(struct wl_listener *listener, static void handle_popup_surface_destroy(struct wl_listener *listener, void *data) { - struct dwl_input_method_popup *popup = + struct mango_input_method_popup *popup = wl_container_of(listener, popup, destroy); wlr_scene_node_destroy(&popup->tree->node); wl_list_remove(&popup->destroy.link); @@ -380,18 +380,18 @@ static void handle_popup_surface_destroy(struct wl_listener *listener, static void handle_popup_surface_commit(struct wl_listener *listener, void *data) { - struct dwl_input_method_popup *popup = + struct mango_input_method_popup *popup = wl_container_of(listener, popup, commit); update_popup_position(popup); } static void handle_input_method_new_popup_surface(struct wl_listener *listener, void *data) { - struct dwl_input_method_relay *relay = + struct mango_input_method_relay *relay = wl_container_of(listener, relay, input_method_new_popup_surface); - struct dwl_input_method_popup *popup = - ecalloc(1, sizeof(struct dwl_input_method_popup)); + struct mango_input_method_popup *popup = + ecalloc(1, sizeof(struct mango_input_method_popup)); popup->popup_surface = data; popup->relay = relay; @@ -405,6 +405,8 @@ static void handle_input_method_new_popup_surface(struct wl_listener *listener, popup->tree = wlr_scene_tree_create(layers[LyrIMPopup]); popup->scene_surface = wlr_scene_subsurface_tree_create( popup->tree, popup->popup_surface->surface); + + popup->type = XdgImPopup; popup->scene_surface->node.data = popup; wl_list_insert(&relay->popups, &popup->link); @@ -413,7 +415,7 @@ static void handle_input_method_new_popup_surface(struct wl_listener *listener, } static void handle_new_input_method(struct wl_listener *listener, void *data) { - struct dwl_input_method_relay *relay = + struct mango_input_method_relay *relay = wl_container_of(listener, relay, new_input_method); struct wlr_input_method_v2 *input_method = data; if (seat != input_method->seat) { @@ -449,7 +451,7 @@ static void handle_new_input_method(struct wl_listener *listener, void *data) { update_active_text_input(relay); } -static void send_state_to_input_method(struct dwl_input_method_relay *relay) { +static void send_state_to_input_method(struct mango_input_method_relay *relay) { struct wlr_input_method_v2 *input_method = relay->input_method; struct wlr_text_input_v3 *input = relay->active_text_input->input; @@ -474,7 +476,7 @@ static void send_state_to_input_method(struct dwl_input_method_relay *relay) { static void handle_text_input_enable(struct wl_listener *listener, void *data) { struct text_input *text_input = wl_container_of(listener, text_input, enable); - struct dwl_input_method_relay *relay = text_input->relay; + struct mango_input_method_relay *relay = text_input->relay; update_active_text_input(relay); if (relay->active_text_input == text_input) { @@ -495,7 +497,7 @@ static void handle_text_input_disable(struct wl_listener *listener, static void handle_text_input_commit(struct wl_listener *listener, void *data) { struct text_input *text_input = wl_container_of(listener, text_input, commit); - struct dwl_input_method_relay *relay = text_input->relay; + struct mango_input_method_relay *relay = text_input->relay; if (relay->active_text_input == text_input) { update_popups_position(relay); @@ -517,7 +519,7 @@ static void handle_text_input_destroy(struct wl_listener *listener, } static void handle_new_text_input(struct wl_listener *listener, void *data) { - struct dwl_input_method_relay *relay = + struct mango_input_method_relay *relay = wl_container_of(listener, relay, new_text_input); struct wlr_text_input_v3 *wlr_text_input = data; struct text_input *text_input = ecalloc(1, sizeof(struct text_input)); @@ -547,26 +549,26 @@ static void handle_new_text_input(struct wl_listener *listener, void *data) { static void handle_focused_surface_destroy(struct wl_listener *listener, void *data) { - struct dwl_input_method_relay *relay = + struct mango_input_method_relay *relay = wl_container_of(listener, relay, focused_surface_destroy); assert(relay->focused_surface == data); - dwl_im_relay_set_focus(relay, NULL); + mango_im_relay_set_focus(relay, NULL); } -struct dwl_input_method_relay *dwl_im_relay_create() { - struct dwl_input_method_relay *relay = - ecalloc(1, sizeof(struct dwl_input_method_relay)); +struct mango_input_method_relay *mango_im_relay_create() { + struct mango_input_method_relay *relay = + ecalloc(1, sizeof(struct mango_input_method_relay)); wl_list_init(&relay->text_inputs); wl_list_init(&relay->popups); relay->popup_tree = wlr_scene_tree_create(&scene->tree); relay->new_text_input.notify = handle_new_text_input; - wl_signal_add(&text_input_manager->events.text_input, + wl_signal_add(&text_input_manager->events.new_text_input, &relay->new_text_input); relay->new_input_method.notify = handle_new_input_method; - wl_signal_add(&input_method_manager->events.input_method, + wl_signal_add(&input_method_manager->events.new_input_method, &relay->new_input_method); relay->focused_surface_destroy.notify = handle_focused_surface_destroy; @@ -574,14 +576,14 @@ struct dwl_input_method_relay *dwl_im_relay_create() { return relay; } -void dwl_im_relay_finish(struct dwl_input_method_relay *relay) { +void mango_im_relay_finish(struct mango_input_method_relay *relay) { wl_list_remove(&relay->new_text_input.link); wl_list_remove(&relay->new_input_method.link); free(relay); } -void dwl_im_relay_set_focus(struct dwl_input_method_relay *relay, - struct wlr_surface *surface) { +void mango_im_relay_set_focus(struct mango_input_method_relay *relay, + struct wlr_surface *surface) { if (relay->focused_surface == surface) { return; } diff --git a/src/ext-protocol/wlr_ext_workspace_v1.c b/src/ext-protocol/wlr_ext_workspace_v1.c deleted file mode 100644 index dca93e93..00000000 --- a/src/ext-protocol/wlr_ext_workspace_v1.c +++ /dev/null @@ -1,975 +0,0 @@ -#include "wlr_ext_workspace_v1.h" -#include "ext-workspace-v1-protocol.h" -#include -#include -#include -#include - -#define EXT_WORKSPACE_V1_VERSION 1 - -struct wlr_ext_workspace_v1_group_output { - struct wlr_output *output; - struct wlr_ext_workspace_group_handle_v1 *group; - struct wl_listener output_bind; - struct wl_listener output_destroy; - struct wl_list link; -}; - -// These structs wrap wl_resource of each interface to access the request queue -// (wlr_ext_workspace_manager_v1_resource.requests) assigned per manager -// resource - -struct wlr_ext_workspace_manager_v1_resource { - struct wl_resource *resource; - struct wlr_ext_workspace_manager_v1 *manager; - struct wl_list requests; // wlr_ext_workspace_v1_request.link - struct wl_list workspace_resources; // wlr_ext_workspace_v1_resource.link - struct wl_list group_resources; // wlr_ext_workspace_group_v1_resource.link - struct wl_list link; // wlr_ext_workspace_manager_v1.resources -}; - -struct wlr_ext_workspace_group_v1_resource { - struct wl_resource *resource; - struct wlr_ext_workspace_group_handle_v1 *group; - struct wlr_ext_workspace_manager_v1_resource *manager; - struct wl_list link; // wlr_ext_workspace_group_v1.resources - struct wl_list - manager_resource_link; // wlr_ext_workspace_manager_v1_resource.group_resources -}; - -struct wlr_ext_workspace_v1_resource { - struct wl_resource *resource; - struct wlr_ext_workspace_handle_v1 *workspace; - struct wlr_ext_workspace_manager_v1_resource *manager; - struct wl_list link; // wlr_ext_workspace_v1.resources - struct wl_list - manager_resource_link; // wlr_ext_workspace_manager_v1_resource.workspace_resources -}; - -static const struct ext_workspace_group_handle_v1_interface group_impl; - -static struct wlr_ext_workspace_group_v1_resource * -group_resource_from_resource(struct wl_resource *resource) { - assert(wl_resource_instance_of( - resource, &ext_workspace_group_handle_v1_interface, &group_impl)); - return wl_resource_get_user_data(resource); -} - -static const struct ext_workspace_handle_v1_interface workspace_impl; - -static struct wlr_ext_workspace_v1_resource * -workspace_resource_from_resource(struct wl_resource *resource) { - assert(wl_resource_instance_of(resource, &ext_workspace_handle_v1_interface, - &workspace_impl)); - return wl_resource_get_user_data(resource); -} - -static const struct ext_workspace_manager_v1_interface manager_impl; - -static struct wlr_ext_workspace_manager_v1_resource * -manager_resource_from_resource(struct wl_resource *resource) { - assert(wl_resource_instance_of( - resource, &ext_workspace_manager_v1_interface, &manager_impl)); - return wl_resource_get_user_data(resource); -} - -static void workspace_handle_destroy(struct wl_client *client, - struct wl_resource *resource) { - wl_resource_destroy(resource); -} - -static void workspace_handle_activate(struct wl_client *client, - struct wl_resource *workspace_resource) { - struct wlr_ext_workspace_v1_resource *workspace_res = - workspace_resource_from_resource(workspace_resource); - if (!workspace_res) { - return; - } - - struct wlr_ext_workspace_v1_request *req = calloc(1, sizeof(*req)); - if (!req) { - wl_resource_post_no_memory(workspace_resource); - return; - } - req->type = WLR_EXT_WORKSPACE_V1_REQUEST_ACTIVATE; - req->activate.workspace = workspace_res->workspace; - wl_list_insert(workspace_res->manager->requests.prev, &req->link); -} - -static void -workspace_handle_deactivate(struct wl_client *client, - struct wl_resource *workspace_resource) { - struct wlr_ext_workspace_v1_resource *workspace_res = - workspace_resource_from_resource(workspace_resource); - if (!workspace_res) { - return; - } - - struct wlr_ext_workspace_v1_request *req = calloc(1, sizeof(*req)); - if (!req) { - wl_resource_post_no_memory(workspace_resource); - return; - } - req->type = WLR_EXT_WORKSPACE_V1_REQUEST_DEACTIVATE; - req->deactivate.workspace = workspace_res->workspace; - wl_list_insert(workspace_res->manager->requests.prev, &req->link); -} - -static void workspace_handle_assign(struct wl_client *client, - struct wl_resource *workspace_resource, - struct wl_resource *group_resource) { - struct wlr_ext_workspace_v1_resource *workspace_res = - workspace_resource_from_resource(workspace_resource); - struct wlr_ext_workspace_group_v1_resource *group_res = - group_resource_from_resource(group_resource); - if (!workspace_res || !group_res) { - return; - } - - struct wlr_ext_workspace_v1_request *req = calloc(1, sizeof(*req)); - if (!req) { - wl_resource_post_no_memory(workspace_resource); - return; - } - req->type = WLR_EXT_WORKSPACE_V1_REQUEST_ASSIGN; - req->assign.group = group_res->group; - req->assign.workspace = workspace_res->workspace; - wl_list_insert(workspace_res->manager->requests.prev, &req->link); -} - -static void workspace_handle_remove(struct wl_client *client, - struct wl_resource *workspace_resource) { - struct wlr_ext_workspace_v1_resource *workspace_res = - workspace_resource_from_resource(workspace_resource); - if (!workspace_res) { - return; - } - - struct wlr_ext_workspace_v1_request *req = calloc(1, sizeof(*req)); - if (!req) { - wl_resource_post_no_memory(workspace_resource); - return; - } - req->type = WLR_EXT_WORKSPACE_V1_REQUEST_REMOVE; - req->remove.workspace = workspace_res->workspace; - wl_list_insert(workspace_res->manager->requests.prev, &req->link); -} - -static const struct ext_workspace_handle_v1_interface workspace_impl = { - .destroy = workspace_handle_destroy, - .activate = workspace_handle_activate, - .deactivate = workspace_handle_deactivate, - .assign = workspace_handle_assign, - .remove = workspace_handle_remove, -}; - -static void group_handle_create_workspace(struct wl_client *client, - struct wl_resource *group_resource, - const char *name) { - struct wlr_ext_workspace_group_v1_resource *group_res = - group_resource_from_resource(group_resource); - if (!group_res) { - return; - } - - struct wlr_ext_workspace_v1_request *req = calloc(1, sizeof(*req)); - if (!req) { - wl_resource_post_no_memory(group_resource); - return; - } - req->create_workspace.name = strdup(name); - if (!req->create_workspace.name) { - free(req); - wl_resource_post_no_memory(group_resource); - return; - } - req->type = WLR_EXT_WORKSPACE_V1_REQUEST_CREATE_WORKSPACE; - req->create_workspace.group = group_res->group; - wl_list_insert(group_res->manager->requests.prev, &req->link); -} - -static void group_handle_destroy(struct wl_client *client, - struct wl_resource *resource) { - wl_resource_destroy(resource); -} - -static const struct ext_workspace_group_handle_v1_interface group_impl = { - .create_workspace = group_handle_create_workspace, - .destroy = group_handle_destroy, -}; - -static void destroy_workspace_resource( - struct wlr_ext_workspace_v1_resource *workspace_res) { - wl_list_remove(&workspace_res->link); - wl_list_remove(&workspace_res->manager_resource_link); - wl_resource_set_user_data(workspace_res->resource, NULL); - free(workspace_res); -} - -static void workspace_resource_destroy(struct wl_resource *resource) { - struct wlr_ext_workspace_v1_resource *workspace_res = - workspace_resource_from_resource(resource); - if (workspace_res) { - destroy_workspace_resource(workspace_res); - } -} - -static struct wlr_ext_workspace_v1_resource *create_workspace_resource( - struct wlr_ext_workspace_handle_v1 *workspace, - struct wlr_ext_workspace_manager_v1_resource *manager_res) { - struct wlr_ext_workspace_v1_resource *workspace_res = - calloc(1, sizeof(*workspace_res)); - if (!workspace_res) { - return NULL; - } - - struct wl_client *client = wl_resource_get_client(manager_res->resource); - workspace_res->resource = - wl_resource_create(client, &ext_workspace_handle_v1_interface, - wl_resource_get_version(manager_res->resource), 0); - if (!workspace_res->resource) { - free(workspace_res); - return NULL; - } - wl_resource_set_implementation(workspace_res->resource, &workspace_impl, - workspace_res, workspace_resource_destroy); - - workspace_res->workspace = workspace; - workspace_res->manager = manager_res; - wl_list_insert(&workspace->resources, &workspace_res->link); - wl_list_insert(&manager_res->workspace_resources, - &workspace_res->manager_resource_link); - - return workspace_res; -} - -static void -destroy_group_resource(struct wlr_ext_workspace_group_v1_resource *group_res) { - wl_list_remove(&group_res->link); - wl_list_remove(&group_res->manager_resource_link); - wl_resource_set_user_data(group_res->resource, NULL); - free(group_res); -} - -static void group_handle_resource_destroy(struct wl_resource *resource) { - struct wlr_ext_workspace_group_v1_resource *group_res = - group_resource_from_resource(resource); - if (group_res) { - destroy_group_resource(group_res); - } -} - -static struct wlr_ext_workspace_group_v1_resource *create_group_resource( - struct wlr_ext_workspace_group_handle_v1 *group, - struct wlr_ext_workspace_manager_v1_resource *manager_res) { - struct wlr_ext_workspace_group_v1_resource *group_res = - calloc(1, sizeof(*group_res)); - if (!group_res) { - return NULL; - } - - struct wl_client *client = wl_resource_get_client(manager_res->resource); - uint32_t version = wl_resource_get_version(manager_res->resource); - group_res->resource = wl_resource_create( - client, &ext_workspace_group_handle_v1_interface, version, 0); - if (group_res->resource == NULL) { - free(group_res); - return NULL; - } - wl_resource_set_implementation(group_res->resource, &group_impl, group_res, - group_handle_resource_destroy); - - group_res->group = group; - group_res->manager = manager_res; - wl_list_insert(&group->resources, &group_res->link); - wl_list_insert(&manager_res->group_resources, - &group_res->manager_resource_link); - - return group_res; -} - -static void -destroy_requests(struct wlr_ext_workspace_manager_v1_resource *manager_res) { - struct wlr_ext_workspace_v1_request *req, *tmp; - wl_list_for_each_safe(req, tmp, &manager_res->requests, link) { - if (req->type == WLR_EXT_WORKSPACE_V1_REQUEST_CREATE_WORKSPACE) { - free(req->create_workspace.name); - } - wl_list_remove(&req->link); - free(req); - } -} - -static void -clear_requests_by(struct wlr_ext_workspace_manager_v1_resource *manager_res, - struct wlr_ext_workspace_group_handle_v1 *group, - struct wlr_ext_workspace_handle_v1 *workspace) { - struct wlr_ext_workspace_v1_request *req, *tmp; - wl_list_for_each_safe(req, tmp, &manager_res->requests, link) { - switch (req->type) { - case WLR_EXT_WORKSPACE_V1_REQUEST_CREATE_WORKSPACE: - if (group && req->create_workspace.group == group) { - req->create_workspace.group = NULL; - } - break; - case WLR_EXT_WORKSPACE_V1_REQUEST_ACTIVATE: - if (workspace && req->activate.workspace == workspace) { - req->activate.workspace = NULL; - } - break; - case WLR_EXT_WORKSPACE_V1_REQUEST_DEACTIVATE: - if (workspace && req->deactivate.workspace == workspace) { - req->deactivate.workspace = NULL; - } - break; - case WLR_EXT_WORKSPACE_V1_REQUEST_ASSIGN: - if (workspace && req->assign.workspace == workspace) { - req->assign.workspace = NULL; - } - if (group && req->assign.group == group) { - req->assign.group = NULL; - } - break; - case WLR_EXT_WORKSPACE_V1_REQUEST_REMOVE: - if (workspace && req->remove.workspace == workspace) { - req->remove.workspace = NULL; - } - break; - } - } -} - -static void manager_handle_commit(struct wl_client *client, - struct wl_resource *resource) { - struct wlr_ext_workspace_manager_v1_resource *manager_res = - manager_resource_from_resource(resource); - if (!manager_res) { - return; - } - - struct wlr_ext_workspace_v1_commit_event commit_event = { - .requests = &manager_res->requests, - }; - wl_signal_emit_mutable(&manager_res->manager->events.commit, &commit_event); - destroy_requests(manager_res); -} - -static void handle_idle(void *data) { - struct wlr_ext_workspace_manager_v1 *manager = data; - - struct wlr_ext_workspace_manager_v1_resource *manager_res; - wl_list_for_each(manager_res, &manager->resources, link) { - ext_workspace_manager_v1_send_done(manager_res->resource); - } - manager->idle_source = NULL; -} - -static void -manager_schedule_done(struct wlr_ext_workspace_manager_v1 *manager) { - if (!manager->idle_source) { - manager->idle_source = - wl_event_loop_add_idle(manager->event_loop, handle_idle, manager); - } -} - -static void -workspace_send_details(struct wlr_ext_workspace_v1_resource *workspace_res) { - struct wlr_ext_workspace_handle_v1 *workspace = workspace_res->workspace; - struct wl_resource *resource = workspace_res->resource; - - ext_workspace_handle_v1_send_capabilities(resource, workspace->caps); - if (workspace->coordinates.size > 0) { - ext_workspace_handle_v1_send_coordinates(resource, - &workspace->coordinates); - } - if (workspace->name) { - ext_workspace_handle_v1_send_name(resource, workspace->name); - } - if (workspace->id) { - ext_workspace_handle_v1_send_id(resource, workspace->id); - } - ext_workspace_handle_v1_send_state(resource, workspace->state); - manager_schedule_done(workspace->manager); -} - -static void manager_handle_stop(struct wl_client *client, - struct wl_resource *resource) { - ext_workspace_manager_v1_send_finished(resource); - wl_resource_destroy(resource); -} - -static const struct ext_workspace_manager_v1_interface manager_impl = { - .commit = manager_handle_commit, - .stop = manager_handle_stop, -}; - -static void destroy_manager_resource( - struct wlr_ext_workspace_manager_v1_resource *manager_res) { - destroy_requests(manager_res); - - struct wlr_ext_workspace_v1_resource *workspace_res, *tmp2; - wl_list_for_each_safe(workspace_res, tmp2, - &manager_res->workspace_resources, - manager_resource_link) { - destroy_workspace_resource(workspace_res); - } - struct wlr_ext_workspace_group_v1_resource *group_res, *tmp3; - wl_list_for_each_safe(group_res, tmp3, &manager_res->group_resources, - manager_resource_link) { - destroy_group_resource(group_res); - } - - wl_list_remove(&manager_res->link); - wl_resource_set_user_data(manager_res->resource, NULL); - free(manager_res); -} - -static void manager_resource_destroy(struct wl_resource *resource) { - struct wlr_ext_workspace_manager_v1_resource *manager_res = - manager_resource_from_resource(resource); - if (manager_res) { - destroy_manager_resource(manager_res); - } -} - -static void -group_send_details(struct wlr_ext_workspace_group_v1_resource *group_res) { - struct wlr_ext_workspace_group_handle_v1 *group = group_res->group; - struct wl_resource *resource = group_res->resource; - struct wl_client *client = wl_resource_get_client(resource); - - ext_workspace_group_handle_v1_send_capabilities(resource, group->caps); - - struct wlr_ext_workspace_v1_group_output *group_output; - wl_list_for_each(group_output, &group->outputs, link) { - struct wl_resource *output_resource; - wl_resource_for_each(output_resource, - &group_output->output->resources) { - if (wl_resource_get_client(output_resource) == client) { - ext_workspace_group_handle_v1_send_output_enter( - resource, output_resource); - } - } - } - - manager_schedule_done(group->manager); -} - -static void manager_bind(struct wl_client *client, void *data, uint32_t version, - uint32_t id) { - struct wlr_ext_workspace_manager_v1 *manager = data; - - struct wlr_ext_workspace_manager_v1_resource *manager_res = - calloc(1, sizeof(*manager_res)); - if (!manager_res) { - wl_client_post_no_memory(client); - return; - } - - manager_res->manager = manager; - wl_list_init(&manager_res->requests); - wl_list_init(&manager_res->workspace_resources); - wl_list_init(&manager_res->group_resources); - - manager_res->resource = wl_resource_create( - client, &ext_workspace_manager_v1_interface, version, id); - if (!manager_res->resource) { - free(manager_res); - wl_client_post_no_memory(client); - return; - } - wl_resource_set_implementation(manager_res->resource, &manager_impl, - manager_res, manager_resource_destroy); - wl_list_insert(&manager->resources, &manager_res->link); - - struct wlr_ext_workspace_group_handle_v1 *group; - wl_list_for_each(group, &manager->groups, link) { - struct wlr_ext_workspace_group_v1_resource *group_res = - create_group_resource(group, manager_res); - if (!group_res) { - wl_resource_post_no_memory(manager_res->resource); - continue; - } - ext_workspace_manager_v1_send_workspace_group(manager_res->resource, - group_res->resource); - group_send_details(group_res); - } - - struct wlr_ext_workspace_handle_v1 *workspace; - wl_list_for_each(workspace, &manager->workspaces, link) { - struct wlr_ext_workspace_v1_resource *workspace_res = - create_workspace_resource(workspace, manager_res); - if (!workspace_res) { - wl_resource_post_no_memory(manager_res->resource); - continue; - } - ext_workspace_manager_v1_send_workspace(manager_res->resource, - workspace_res->resource); - workspace_send_details(workspace_res); - - if (!workspace->group) { - continue; - } - struct wlr_ext_workspace_group_v1_resource *group_res; - wl_list_for_each(group_res, &workspace->group->resources, link) { - if (group_res->manager == manager_res) { - ext_workspace_group_handle_v1_send_workspace_enter( - group_res->resource, workspace_res->resource); - } - } - } - - ext_workspace_manager_v1_send_done(manager_res->resource); -} - -static void manager_handle_display_destroy(struct wl_listener *listener, - void *data) { - struct wlr_ext_workspace_manager_v1 *manager = - wl_container_of(listener, manager, display_destroy); - - wl_signal_emit_mutable(&manager->events.destroy, NULL); - assert(wl_list_empty(&manager->events.commit.listener_list)); - assert(wl_list_empty(&manager->events.destroy.listener_list)); - - struct wlr_ext_workspace_group_handle_v1 *group, *tmp; - wl_list_for_each_safe(group, tmp, &manager->groups, link) { - wlr_ext_workspace_group_handle_v1_destroy(group); - } - - struct wlr_ext_workspace_handle_v1 *workspace, *tmp2; - wl_list_for_each_safe(workspace, tmp2, &manager->workspaces, link) { - wlr_ext_workspace_handle_v1_destroy(workspace); - } - - struct wlr_ext_workspace_manager_v1_resource *manager_res, *tmp3; - wl_list_for_each_safe(manager_res, tmp3, &manager->resources, link) { - destroy_manager_resource(manager_res); - } - - if (manager->idle_source) { - wl_event_source_remove(manager->idle_source); - } - - wl_list_remove(&manager->display_destroy.link); - wl_global_destroy(manager->global); - free(manager); -} - -struct wlr_ext_workspace_manager_v1 * -wlr_ext_workspace_manager_v1_create(struct wl_display *display, - uint32_t version) { - assert(version <= EXT_WORKSPACE_V1_VERSION); - - struct wlr_ext_workspace_manager_v1 *manager = calloc(1, sizeof(*manager)); - if (!manager) { - return NULL; - } - - manager->global = - wl_global_create(display, &ext_workspace_manager_v1_interface, version, - manager, manager_bind); - if (!manager->global) { - free(manager); - return NULL; - } - - manager->event_loop = wl_display_get_event_loop(display); - - manager->display_destroy.notify = manager_handle_display_destroy; - wl_display_add_destroy_listener(display, &manager->display_destroy); - - wl_list_init(&manager->groups); - wl_list_init(&manager->workspaces); - wl_list_init(&manager->resources); - wl_signal_init(&manager->events.commit); - wl_signal_init(&manager->events.destroy); - - return manager; -} - -struct wlr_ext_workspace_group_handle_v1 * -wlr_ext_workspace_group_handle_v1_create( - struct wlr_ext_workspace_manager_v1 *manager, uint32_t caps) { - struct wlr_ext_workspace_group_handle_v1 *group = calloc(1, sizeof(*group)); - if (!group) { - return NULL; - } - - group->manager = manager; - group->caps = caps; - - wl_list_init(&group->outputs); - wl_list_init(&group->resources); - wl_signal_init(&group->events.destroy); - - wl_list_insert(manager->groups.prev, &group->link); - - struct wlr_ext_workspace_manager_v1_resource *manager_res; - wl_list_for_each(manager_res, &manager->resources, link) { - struct wlr_ext_workspace_group_v1_resource *group_res = - create_group_resource(group, manager_res); - if (!group_res) { - continue; - } - ext_workspace_manager_v1_send_workspace_group(manager_res->resource, - group_res->resource); - group_send_details(group_res); - } - - manager_schedule_done(manager); - - return group; -} - -static void -workspace_send_group(struct wlr_ext_workspace_handle_v1 *workspace, - struct wlr_ext_workspace_group_handle_v1 *group, - bool enter) { - - struct wlr_ext_workspace_v1_resource *workspace_res; - wl_list_for_each(workspace_res, &workspace->resources, link) { - struct wlr_ext_workspace_group_v1_resource *group_res; - wl_list_for_each(group_res, &group->resources, link) { - if (group_res->manager != workspace_res->manager) { - continue; - } - if (enter) { - ext_workspace_group_handle_v1_send_workspace_enter( - group_res->resource, workspace_res->resource); - } else { - ext_workspace_group_handle_v1_send_workspace_leave( - group_res->resource, workspace_res->resource); - } - } - } - - manager_schedule_done(workspace->manager); -} - -static void -destroy_group_output(struct wlr_ext_workspace_v1_group_output *group_output) { - wl_list_remove(&group_output->output_bind.link); - wl_list_remove(&group_output->output_destroy.link); - wl_list_remove(&group_output->link); - free(group_output); -} - -static void group_send_output(struct wlr_ext_workspace_group_handle_v1 *group, - struct wlr_output *output, bool enter) { - - struct wlr_ext_workspace_group_v1_resource *group_res; - wl_list_for_each(group_res, &group->resources, link) { - struct wl_client *client = wl_resource_get_client(group_res->resource); - - struct wl_resource *output_resource; - wl_resource_for_each(output_resource, &output->resources) { - if (wl_resource_get_client(output_resource) != client) { - continue; - } - if (enter) { - ext_workspace_group_handle_v1_send_output_enter( - group_res->resource, output_resource); - } else { - ext_workspace_group_handle_v1_send_output_leave( - group_res->resource, output_resource); - } - } - } - - manager_schedule_done(group->manager); -} - -void wlr_ext_workspace_group_handle_v1_destroy( - struct wlr_ext_workspace_group_handle_v1 *group) { - if (!group) { - return; - } - - wl_signal_emit_mutable(&group->events.destroy, NULL); - - assert(wl_list_empty(&group->events.destroy.listener_list)); - - struct wlr_ext_workspace_handle_v1 *workspace; - wl_list_for_each(workspace, &group->manager->workspaces, link) { - if (workspace->group == group) { - workspace_send_group(workspace, group, false); - workspace->group = NULL; - } - } - - struct wlr_ext_workspace_group_v1_resource *group_res, *tmp; - wl_list_for_each_safe(group_res, tmp, &group->resources, link) { - ext_workspace_group_handle_v1_send_removed(group_res->resource); - destroy_group_resource(group_res); - } - - struct wlr_ext_workspace_manager_v1_resource *manager_res; - wl_list_for_each(manager_res, &group->manager->resources, link) { - clear_requests_by(manager_res, group, NULL); - } - - struct wlr_ext_workspace_v1_group_output *group_output, *tmp3; - wl_list_for_each_safe(group_output, tmp3, &group->outputs, link) { - group_send_output(group, group_output->output, false); - destroy_group_output(group_output); - } - - manager_schedule_done(group->manager); - - wl_list_remove(&group->link); - free(group); -} - -static void handle_output_bind(struct wl_listener *listener, void *data) { - struct wlr_ext_workspace_v1_group_output *group_output = - wl_container_of(listener, group_output, output_bind); - struct wlr_output_event_bind *event = data; - struct wl_client *client = wl_resource_get_client(event->resource); - - struct wlr_ext_workspace_group_v1_resource *group_res; - wl_list_for_each(group_res, &group_output->group->resources, link) { - if (wl_resource_get_client(group_res->resource) == client) { - ext_workspace_group_handle_v1_send_output_enter(group_res->resource, - event->resource); - } - } - - manager_schedule_done(group_output->group->manager); -} - -static void handle_output_destroy(struct wl_listener *listener, void *data) { - struct wlr_ext_workspace_v1_group_output *group_output = - wl_container_of(listener, group_output, output_destroy); - group_send_output(group_output->group, group_output->output, false); - destroy_group_output(group_output); -} - -static struct wlr_ext_workspace_v1_group_output * -get_group_output(struct wlr_ext_workspace_group_handle_v1 *group, - struct wlr_output *output) { - struct wlr_ext_workspace_v1_group_output *group_output; - wl_list_for_each(group_output, &group->outputs, link) { - if (group_output->output == output) { - return group_output; - } - } - return NULL; -} - -void wlr_ext_workspace_group_handle_v1_output_enter( - struct wlr_ext_workspace_group_handle_v1 *group, - struct wlr_output *output) { - if (get_group_output(group, output)) { - return; - } - struct wlr_ext_workspace_v1_group_output *group_output = - calloc(1, sizeof(*group_output)); - if (!group_output) { - return; - } - group_output->output = output; - group_output->group = group; - wl_list_insert(&group->outputs, &group_output->link); - - group_output->output_bind.notify = handle_output_bind; - wl_signal_add(&output->events.bind, &group_output->output_bind); - group_output->output_destroy.notify = handle_output_destroy; - wl_signal_add(&output->events.destroy, &group_output->output_destroy); - - group_send_output(group, output, true); -} - -void wlr_ext_workspace_group_handle_v1_output_leave( - struct wlr_ext_workspace_group_handle_v1 *group, - struct wlr_output *output) { - struct wlr_ext_workspace_v1_group_output *group_output = - get_group_output(group, output); - if (!group_output) { - return; - } - - group_send_output(group, output, false); - destroy_group_output(group_output); -} - -struct wlr_ext_workspace_handle_v1 * -wlr_ext_workspace_handle_v1_create(struct wlr_ext_workspace_manager_v1 *manager, - const char *id, uint32_t caps) { - struct wlr_ext_workspace_handle_v1 *workspace = - calloc(1, sizeof(*workspace)); - if (!workspace) { - return NULL; - } - - workspace->manager = manager; - workspace->caps = caps; - - if (id) { - workspace->id = strdup(id); - if (!workspace->id) { - free(workspace); - return NULL; - } - } - - wl_list_init(&workspace->resources); - wl_array_init(&workspace->coordinates); - wl_signal_init(&workspace->events.destroy); - - wl_list_insert(manager->workspaces.prev, &workspace->link); - - struct wlr_ext_workspace_manager_v1_resource *manager_res; - wl_list_for_each(manager_res, &manager->resources, link) { - struct wlr_ext_workspace_v1_resource *workspace_res = - create_workspace_resource(workspace, manager_res); - if (!workspace_res) { - continue; - } - ext_workspace_manager_v1_send_workspace(manager_res->resource, - workspace_res->resource); - workspace_send_details(workspace_res); - } - - manager_schedule_done(manager); - - return workspace; -} - -void wlr_ext_workspace_handle_v1_destroy( - struct wlr_ext_workspace_handle_v1 *workspace) { - if (!workspace) { - return; - } - - wl_signal_emit_mutable(&workspace->events.destroy, NULL); - - assert(wl_list_empty(&workspace->events.destroy.listener_list)); - - if (workspace->group) { - workspace_send_group(workspace, workspace->group, false); - } - - struct wlr_ext_workspace_v1_resource *workspace_res, *tmp; - wl_list_for_each_safe(workspace_res, tmp, &workspace->resources, link) { - ext_workspace_handle_v1_send_removed(workspace_res->resource); - destroy_workspace_resource(workspace_res); - } - - struct wlr_ext_workspace_manager_v1_resource *manager_res; - wl_list_for_each(manager_res, &workspace->manager->resources, link) { - clear_requests_by(manager_res, NULL, workspace); - } - - manager_schedule_done(workspace->manager); - - wl_list_remove(&workspace->link); - wl_array_release(&workspace->coordinates); - free(workspace->id); - free(workspace->name); - free(workspace); -} - -void wlr_ext_workspace_handle_v1_set_group( - struct wlr_ext_workspace_handle_v1 *workspace, - struct wlr_ext_workspace_group_handle_v1 *group) { - if (workspace->group == group) { - return; - } - - if (workspace->group) { - workspace_send_group(workspace, workspace->group, false); - } - workspace->group = group; - if (group) { - workspace_send_group(workspace, group, true); - } -} - -void wlr_ext_workspace_handle_v1_set_name( - struct wlr_ext_workspace_handle_v1 *workspace, const char *name) { - assert(name); - - if (workspace->name && strcmp(workspace->name, name) == 0) { - return; - } - - free(workspace->name); - workspace->name = strdup(name); - if (workspace->name == NULL) { - return; - } - - struct wlr_ext_workspace_v1_resource *workspace_res; - wl_list_for_each(workspace_res, &workspace->resources, link) { - ext_workspace_handle_v1_send_name(workspace_res->resource, - workspace->name); - } - - manager_schedule_done(workspace->manager); -} - -void wlr_ext_workspace_handle_v1_set_coordinates( - struct wlr_ext_workspace_handle_v1 *workspace, const uint32_t *coords, - size_t coords_len) { - size_t size = coords_len * sizeof(coords[0]); - if (size == workspace->coordinates.size && - (size == 0 || memcmp(workspace->coordinates.data, coords, size) == 0)) { - return; - } - - wl_array_release(&workspace->coordinates); - wl_array_init(&workspace->coordinates); - struct wl_array arr = { - .data = (void *)coords, - .size = size, - }; - wl_array_copy(&workspace->coordinates, &arr); - - struct wlr_ext_workspace_v1_resource *workspace_res; - wl_list_for_each(workspace_res, &workspace->resources, link) { - ext_workspace_handle_v1_send_coordinates(workspace_res->resource, - &workspace->coordinates); - } - - manager_schedule_done(workspace->manager); -} - -static void workspace_set_state(struct wlr_ext_workspace_handle_v1 *workspace, - enum ext_workspace_handle_v1_state state, - bool enabled) { - uint32_t old_state = workspace->state; - if (enabled) { - workspace->state |= state; - } else { - workspace->state &= ~state; - } - if (old_state == workspace->state) { - return; - } - - struct wlr_ext_workspace_v1_resource *workspace_res; - wl_list_for_each(workspace_res, &workspace->resources, link) { - ext_workspace_handle_v1_send_state(workspace_res->resource, - workspace->state); - } - - manager_schedule_done(workspace->manager); -} - -void wlr_ext_workspace_handle_v1_set_active( - struct wlr_ext_workspace_handle_v1 *workspace, bool enabled) { - workspace_set_state(workspace, EXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE, - enabled); -} - -void wlr_ext_workspace_handle_v1_set_urgent( - struct wlr_ext_workspace_handle_v1 *workspace, bool enabled) { - workspace_set_state(workspace, EXT_WORKSPACE_HANDLE_V1_STATE_URGENT, - enabled); -} - -void wlr_ext_workspace_handle_v1_set_hidden( - struct wlr_ext_workspace_handle_v1 *workspace, bool enabled) { - workspace_set_state(workspace, EXT_WORKSPACE_HANDLE_V1_STATE_HIDDEN, - enabled); -} diff --git a/src/ext-protocol/wlr_ext_workspace_v1.h b/src/ext-protocol/wlr_ext_workspace_v1.h deleted file mode 100644 index 183d5801..00000000 --- a/src/ext-protocol/wlr_ext_workspace_v1.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * This an unstable interface of wlroots. No guarantees are made regarding the - * future consistency of this API. - */ -#ifndef WLR_USE_UNSTABLE -#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" -#endif - -#ifndef WLR_TYPES_WLR_EXT_WORKSPACE_V1_H -#define WLR_TYPES_WLR_EXT_WORKSPACE_V1_H - -#include -#include - -struct wlr_output; - -enum wlr_ext_workspace_v1_request_type { - WLR_EXT_WORKSPACE_V1_REQUEST_CREATE_WORKSPACE, - WLR_EXT_WORKSPACE_V1_REQUEST_ACTIVATE, - WLR_EXT_WORKSPACE_V1_REQUEST_DEACTIVATE, - WLR_EXT_WORKSPACE_V1_REQUEST_ASSIGN, - WLR_EXT_WORKSPACE_V1_REQUEST_REMOVE, -}; - -struct wlr_ext_workspace_v1_request { - enum wlr_ext_workspace_v1_request_type type; - struct wl_list link; // wlr_ext_workspace_manager_v1_resource.requests - union { - struct { - char *name; - struct wlr_ext_workspace_group_handle_v1 - *group; // NULL if destroyed - } create_workspace; - struct { - struct wlr_ext_workspace_handle_v1 *workspace; // NULL if destroyed - } activate; - struct { - struct wlr_ext_workspace_handle_v1 *workspace; // NULL if destroyed - } deactivate; - struct { - struct wlr_ext_workspace_handle_v1 *workspace; // NULL if destroyed - struct wlr_ext_workspace_group_handle_v1 - *group; // NULL if destroyed - } assign; - struct { - struct wlr_ext_workspace_handle_v1 *workspace; // NULL if destroyed - } remove; - }; -}; - -struct wlr_ext_workspace_v1_commit_event { - struct wl_list *requests; // wlr_ext_workspace_v1_request.link -}; - -struct wlr_ext_workspace_manager_v1 { - struct wl_global *global; - struct wl_list groups; // wlr_ext_workspace_group_handle_v1.link - struct wl_list workspaces; // wlr_ext_workspace_handle_v1.link - - struct { - struct wl_signal commit; // wlr_ext_workspace_v1_commit_event - struct wl_signal destroy; - } events; - - void *data; - - struct { - struct wl_list resources; // wlr_ext_workspace_manager_v1_resource.link - struct wl_event_source *idle_source; - struct wl_event_loop *event_loop; - struct wl_listener display_destroy; - }; -}; - -struct wlr_ext_workspace_group_handle_v1 { - struct wlr_ext_workspace_manager_v1 *manager; - uint32_t caps; // ext_workspace_group_handle_v1_group_capabilities - struct { - struct wl_signal destroy; - } events; - - struct wl_list link; // wlr_ext_workspace_manager_v1.groups - - void *data; - - struct { - struct wl_list outputs; // wlr_ext_workspace_v1_group_output.link - struct wl_list resources; // wlr_ext_workspace_manager_v1_resource.link - }; -}; - -struct wlr_ext_workspace_handle_v1 { - struct wlr_ext_workspace_manager_v1 *manager; - struct wlr_ext_workspace_group_handle_v1 *group; // May be NULL - char *id; - char *name; - struct wl_array coordinates; - uint32_t caps; // ext_workspace_handle_v1_workspace_capabilities - uint32_t state; // ext_workspace_handle_v1_state - - struct { - struct wl_signal destroy; - } events; - - struct wl_list link; // wlr_ext_workspace_manager_v1.workspaces - - void *data; - - struct { - struct wl_list resources; // wlr_ext_workspace_v1_resource.link - }; -}; - -struct wlr_ext_workspace_manager_v1 * -wlr_ext_workspace_manager_v1_create(struct wl_display *display, - uint32_t version); - -struct wlr_ext_workspace_group_handle_v1 * -wlr_ext_workspace_group_handle_v1_create( - struct wlr_ext_workspace_manager_v1 *manager, uint32_t caps); -void wlr_ext_workspace_group_handle_v1_destroy( - struct wlr_ext_workspace_group_handle_v1 *group); - -void wlr_ext_workspace_group_handle_v1_output_enter( - struct wlr_ext_workspace_group_handle_v1 *group, struct wlr_output *output); -void wlr_ext_workspace_group_handle_v1_output_leave( - struct wlr_ext_workspace_group_handle_v1 *group, struct wlr_output *output); - -struct wlr_ext_workspace_handle_v1 * -wlr_ext_workspace_handle_v1_create(struct wlr_ext_workspace_manager_v1 *manager, - const char *id, uint32_t caps); -void wlr_ext_workspace_handle_v1_destroy( - struct wlr_ext_workspace_handle_v1 *workspace); - -void wlr_ext_workspace_handle_v1_set_group( - struct wlr_ext_workspace_handle_v1 *workspace, - struct wlr_ext_workspace_group_handle_v1 *group); -void wlr_ext_workspace_handle_v1_set_name( - struct wlr_ext_workspace_handle_v1 *workspace, const char *name); -void wlr_ext_workspace_handle_v1_set_coordinates( - struct wlr_ext_workspace_handle_v1 *workspace, const uint32_t *coords, - size_t coords_len); -void wlr_ext_workspace_handle_v1_set_active( - struct wlr_ext_workspace_handle_v1 *workspace, bool enabled); -void wlr_ext_workspace_handle_v1_set_urgent( - struct wlr_ext_workspace_handle_v1 *workspace, bool enabled); -void wlr_ext_workspace_handle_v1_set_hidden( - struct wlr_ext_workspace_handle_v1 *workspace, bool enabled); - -#endif diff --git a/src/fetch/client.h b/src/fetch/client.h index a44f4ca7..869f3da3 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -31,7 +31,7 @@ Client *termforwin(Client *w) { return NULL; wl_list_for_each(c, &fstack, flink) { - if (c->isterm && !c->swallowing && c->pid && + if (c->isterm && !c->swallowdby && c->pid && isdescprocess(c->pid, w->pid)) { return c; } @@ -48,9 +48,9 @@ Client *get_client_by_id_or_title(const char *arg_id, const char *arg_title) { continue; } - if (c->swallowedby) { - appid = client_get_appid(c->swallowedby); - title = client_get_title(c->swallowedby); + if (c->swallowing) { + appid = client_get_appid(c->swallowing); + title = client_get_title(c->swallowing); } else { appid = client_get_appid(c); title = client_get_title(c); @@ -184,11 +184,11 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, break; wl_list_for_each(c, &clients, link) { - if (!c || c == tc) + if (!c || !c->mon || c == tc) continue; if (!findfloating && c->isfloating) continue; - if (c->is_monocle_hide) + if (!VISIBLEON(c, c->mon)) continue; if (c->isunglobal) continue; @@ -197,11 +197,6 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, if (!(c->tags & c->mon->tagset[c->mon->seltags])) continue; - if (step == 0 && ((!tc->mon->isoverview && - !client_is_in_same_stack(tc, c, NULL)) || - c->mon != tc->mon)) - continue; - int32_t c_l = c->geom.x; int32_t c_r = c->geom.x + c->geom.width; int32_t c_t = c->geom.y; @@ -257,17 +252,24 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, if (!match_dir) continue; + if (step == 0) { + if (c->mon != tc->mon) + continue; + if (!tc->mon->isoverview && + !client_is_in_same_stack(tc, c, NULL)) + continue; + if (orth_dist != 0) + continue; + } + int64_t penalty = 0; if (main_dist < 0) { - penalty = 10000000000LL; // 主方向重叠(反方向)的极大惩罚 + penalty = 10000000000LL; main_dist = -main_dist; } - // 正交方向无重叠惩罚,优先选择在同一行/列的窗口 int64_t no_overlap_penalty = 0; if (orth_dist > 0) { - // LEFT/RIGHT 时 orth_dist 是垂直间距,>0 表示垂直无重叠 - // UP/DOWN 时 orth_dist 是水平间距,>0 表示水平无重叠 no_overlap_penalty = 10000000LL; } @@ -442,7 +444,7 @@ Client *get_focused_stack_client(Client *sc, Client *custom_focus_client) { return sc; wl_list_for_each(tc, &fstack, flink) { - if (tc->iskilling || tc->isunglobal || tc->is_monocle_hide) + if (tc->iskilling || tc->isunglobal) continue; if (!VISIBLEON(tc, sc->mon)) continue; diff --git a/src/fetch/common.h b/src/fetch/common.h index acb5d0e8..285120d5 100644 --- a/src/fetch/common.h +++ b/src/fetch/common.h @@ -100,23 +100,30 @@ static bool layer_ignores_focus(LayerSurface *l) { } void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, - LayerSurface **pl, double *nx, double *ny) { - struct wlr_scene_node *node, *pnode; + LayerSurface **pl, MangoGroupBar **gb, double *nx, double *ny) { + struct wlr_scene_node *node = NULL, *pnode = NULL; struct wlr_surface *surface = NULL; Client *c = NULL; LayerSurface *l = NULL; + MangoGroupBar *mangogroupbar = NULL; int32_t layer; Client *ovc = NULL; - for (layer = NUM_LAYERS - 1; !surface && layer >= 0; layer--) { + if (psurface) + *psurface = NULL; + if (pc) + *pc = NULL; + if (pl) + *pl = NULL; + if (gb) + *gb = NULL; + for (layer = NUM_LAYERS - 1; layer >= 0; layer--) { if (layer == LyrFadeOut) continue; - if (!(node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny))) - continue; - - if (!node->enabled) + node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny); + if (!node) continue; if (node->type == WLR_SCENE_NODE_BUFFER) { @@ -125,32 +132,44 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, wlr_scene_buffer_from_node(node)); if (scene_surface) { surface = scene_surface->surface; - } else { - continue; } } - /* start from the topmost layer, - find a sureface that can be focused by pointer, - impopup neither a client nor a layer surface.*/ if (layer == LyrIMPopup) { c = NULL; l = NULL; } else { - for (pnode = node; pnode && !c; pnode = &pnode->parent->node) - c = pnode->data; - if (c && c->type == LayerShell) { - l = (LayerSurface *)c; - c = NULL; + void *data = NULL; + for (pnode = node; pnode; pnode = &pnode->parent->node) { + if (pnode->data) { + data = pnode->data; + break; + } + } + + if (data) { + Client *temp_c = (Client *)data; + if (temp_c->type == LayerShell) { + l = (LayerSurface *)temp_c; + } else if (temp_c->type == GroupBar) { + mangogroupbar = (MangoGroupBar *)temp_c; + } else if (temp_c->type == XDGShell || temp_c->type == X11) { + c = temp_c; + } } } if (node->type == WLR_SCENE_NODE_RECT) { - if (c) { + if (c && (c->type == XDGShell || c->type == X11)) { surface = client_surface(c); } - break; + + if (l && l->type == LayerShell) { + surface = l->layer_surface->surface; + } } + + break; } if (psurface) @@ -159,6 +178,8 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, *pc = c; if (pl) *pl = l; + if (gb) + *gb = mangogroupbar; if (selmon && selmon->isoverview && config.ov_no_resize) { ovc = xytoclient(x, y); @@ -174,12 +195,12 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, if (ovc && (!l || layer_ignores_focus(l) || is_below)) { if (pc) *pc = ovc; - if (psurface) *psurface = ovc ? client_surface(ovc) : NULL; - - if (pl && ovc) + if (pl) *pl = NULL; + if (gb) + *gb = NULL; } } } \ No newline at end of file diff --git a/src/fetch/monitor.h b/src/fetch/monitor.h index c5a5869a..0bff62f5 100644 --- a/src/fetch/monitor.h +++ b/src/fetch/monitor.h @@ -181,4 +181,4 @@ bool match_monitor_spec(char *spec, Monitor *m) { free(serial_rule); return match; -} \ No newline at end of file +} diff --git a/src/ipc/ipc.h b/src/ipc/ipc.h index 03e0746e..af1e9c64 100644 --- a/src/ipc/ipc.h +++ b/src/ipc/ipc.h @@ -143,11 +143,17 @@ static cJSON *build_client_json(Client *c) { cJSON_AddNumberToObject(obj, "id", c->id); cJSON_AddNumberToObject(obj, "pid", c->pid); + cJSON_AddStringToObject(obj, "foreign_toplevel_id", + c->ext_foreign_toplevel->identifier); cJSON_AddStringToObject(obj, "title", client_get_title(c)); cJSON_AddStringToObject(obj, "appid", client_get_appid(c)); cJSON_AddStringToObject(obj, "monitor", c->mon ? c->mon->wlr_output->name : ""); cJSON_AddItemToObject(obj, "tags", tags_mask_to_array(c->tags)); + cJSON_AddBoolToObject(obj, "is_swallowing", c->swallowing ? true : false); + cJSON_AddBoolToObject(obj, "is_swallowedby", c->swallowdby ? true : false); + cJSON_AddBoolToObject(obj, "is_group", c->group_prev || c->group_next); + cJSON_AddBoolToObject(obj, "is_visible", c->mon && VISIBLEON(c, c->mon)); cJSON_AddBoolToObject(obj, "is_focused", c->isfocusing); cJSON_AddBoolToObject(obj, "is_fullscreen", c->isfullscreen); cJSON_AddBoolToObject(obj, "is_floating", c->isfloating); diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 4782b3ea..7f41f378 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -20,7 +20,7 @@ void set_size_per(Monitor *m, Client *c) { } } - if (!found) { + if (!found || c->isfloating) { c->master_mfact_per = m->pertag->mfacts[m->pertag->curtag]; c->master_inner_per = 1.0f; c->stack_inner_per = 1.0f; @@ -37,21 +37,6 @@ void set_size_per(Monitor *m, Client *c) { } } -void monocle_set_focus(Client *c, bool focused) { - - if (!c || !c->mon) - return; - - c->is_monocle_hide = !focused; - mango_tab_bar_node_set_focus(c->tab_bar_node, focused); - wlr_scene_node_set_enabled(&c->scene->node, focused); - - if (!focused) { - c->animation.current = c->animainit_geom = c->animation.initial = - c->pending = c->current = c->geom; - } -} - void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx, int32_t offsety, uint32_t time, int32_t type) { @@ -1147,14 +1132,8 @@ void pre_caculate_before_arrange(Monitor *m, bool want_animation, client_add_jump_label_node(c); } - if (m->pertag->ltidxs[m->pertag->curtag]->id == MONOCLE && - !c->tab_bar_node) { - client_add_tab_bar_node(c); - } - - if (c->tab_bar_node && c->mon == m) { - wlr_scene_node_set_enabled(&c->tab_bar_node->scene_buffer->node, - false); + if (c->group_bar->scene_buffer->node.enabled) { + client_check_tab_node_visible(c); } if (c->mon == m && (c->isglobal || c->isunglobal)) { diff --git a/src/layout/dwindle.h b/src/layout/dwindle.h index 5e56a6bf..e291c69b 100644 --- a/src/layout/dwindle.h +++ b/src/layout/dwindle.h @@ -261,7 +261,7 @@ static void dwindle_assign(DwindleNode *node, int32_t ax, int32_t ay, !node->client->ismaximizescreen) { struct wlr_box box = {ax, ay, MANGO_MAX(1, aw), MANGO_MAX(1, ah)}; - resize(node->client, box, 0); + client_tile_resize(node->client, box, 0); } } return; diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index 96c0ed54..aa60100b 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -290,18 +290,37 @@ void center_tile(Monitor *m) { int32_t should_overspread = config.center_master_overspread && (n <= nmasters); + int32_t left_num = 0; + int32_t right_num = 0; + for (int j = 0; j < stack_num; j++) { + if ((j % 2) ^ (n % 2 == 0)) { + right_num++; + } else { + left_num++; + } + } + int32_t master_surplus_height = - (m->w.height - 2 * cur_gappov - cur_gappiv * ie * (master_num - 1)); + (m->w.height - 2 * cur_gappov - + cur_gappiv * ie * (master_num > 0 ? master_num - 1 : 0)); float master_surplus_ratio = 1.0; + int32_t init_master_surplus = master_surplus_height; int32_t slave_left_surplus_height = - (m->w.height - 2 * cur_gappov - cur_gappiv * ie * (stack_num / 2 - 1)); + (m->w.height - 2 * cur_gappov - + cur_gappiv * ie * (left_num > 0 ? left_num - 1 : 0)); float slave_left_surplus_ratio = 1.0; + int32_t init_slave_left_surplus = slave_left_surplus_height; int32_t slave_right_surplus_height = (m->w.height - 2 * cur_gappov - - cur_gappiv * ie * ((stack_num + 1) / 2 - 1)); + cur_gappiv * ie * (right_num > 0 ? right_num - 1 : 0)); float slave_right_surplus_ratio = 1.0; + int32_t init_slave_right_surplus = slave_right_surplus_height; + + int32_t init_single_stack_surplus = + (m->w.height - 2 * cur_gappov - + cur_gappiv * ie * (stack_num > 0 ? stack_num - 1 : 0)); if (n > nmasters || !should_overspread) { // 计算主区域宽度(居中模式) @@ -349,6 +368,8 @@ void center_tile(Monitor *m) { if (c->master_inner_per > 0.0f) { h = master_surplus_height * c->master_inner_per / master_surplus_ratio; + if (r == 1) + h = m->w.height - my - cur_gappov; master_surplus_height = master_surplus_height - h; master_surplus_ratio = master_surplus_ratio - c->master_inner_per; @@ -357,8 +378,12 @@ void center_tile(Monitor *m) { h = (m->w.height - my - cur_gappov - cur_gappiv * ie * (r - 1)) / r; - c->master_inner_per = h / (m->w.height - my - cur_gappov - - cur_gappiv * ie * (r - 1)); + if (r == 1) + h = m->w.height - my - cur_gappov; + c->master_inner_per = + init_master_surplus > 0 + ? ((float)h / (float)init_master_surplus) + : 0; c->master_mfact_per = mfact; } @@ -377,16 +402,20 @@ void center_tile(Monitor *m) { // 单个堆叠窗口 r = n - i; if (c->stack_inner_per > 0.0f) { - h = (m->w.height - 2 * cur_gappov - - cur_gappiv * ie * (stack_num - 1)) * - c->stack_inner_per; + h = init_single_stack_surplus * c->stack_inner_per; + if (r == 1) + h = m->w.height - ety - cur_gappov; c->master_mfact_per = mfact; } else { h = (m->w.height - ety - cur_gappov - cur_gappiv * ie * (r - 1)) / r; - c->stack_inner_per = h / (m->w.height - ety - cur_gappov - - cur_gappiv * ie * (r - 1)); + if (r == 1) + h = m->w.height - ety - cur_gappov; + c->stack_inner_per = + init_single_stack_surplus > 0 + ? ((float)h / (float)init_single_stack_surplus) + : 0; c->master_mfact_per = mfact; } @@ -403,7 +432,7 @@ void center_tile(Monitor *m) { .width = tw, .height = h}, 0); - ety += h + cur_gappiv * ie; // 使用理论高度累加 + ety += h + cur_gappiv * ie; } else { // 多个堆叠窗口:交替放在左右两侧 r = (n - i + 1) / 2; @@ -413,6 +442,8 @@ void center_tile(Monitor *m) { if (c->stack_inner_per > 0.0f) { h = slave_right_surplus_height * c->stack_inner_per / slave_right_surplus_ratio; + if (r == 1) + h = m->w.height - ety - cur_gappov; slave_right_surplus_height = slave_right_surplus_height - h; slave_right_surplus_ratio = @@ -422,9 +453,12 @@ void center_tile(Monitor *m) { h = (m->w.height - ety - cur_gappov - cur_gappiv * ie * (r - 1)) / r; + if (r == 1) + h = m->w.height - ety - cur_gappov; c->stack_inner_per = - h / (m->w.height - ety - cur_gappov - - cur_gappiv * ie * (r - 1)); + init_slave_right_surplus > 0 + ? ((float)h / (float)init_slave_right_surplus) + : 0; c->master_mfact_per = mfact; } @@ -436,12 +470,14 @@ void center_tile(Monitor *m) { .width = tw, .height = h}, 0); - ety += h + cur_gappiv * ie; // 使用理论高度累加 + ety += h + cur_gappiv * ie; } else { // 左侧堆叠窗口 if (c->stack_inner_per > 0.0f) { h = slave_left_surplus_height * c->stack_inner_per / slave_left_surplus_ratio; + if (r == 1) + h = m->w.height - oty - cur_gappov; slave_left_surplus_height = slave_left_surplus_height - h; slave_left_surplus_ratio = @@ -451,9 +487,12 @@ void center_tile(Monitor *m) { h = (m->w.height - oty - cur_gappov - cur_gappiv * ie * (r - 1)) / r; + if (r == 1) + h = m->w.height - oty - cur_gappov; c->stack_inner_per = - h / (m->w.height - oty - cur_gappov - - cur_gappiv * ie * (r - 1)); + init_slave_left_surplus > 0 + ? ((float)h / (float)init_slave_left_surplus) + : 0; c->master_mfact_per = mfact; } @@ -464,7 +503,7 @@ void center_tile(Monitor *m) { .width = tw, .height = h}, 0); - oty += h + cur_gappiv * ie; // 使用理论高度累加 + oty += h + cur_gappiv * ie; } } } @@ -545,83 +584,32 @@ void deck(Monitor *m) { } } -void monocle(Monitor *m) { - Client *c = NULL, *fc = NULL; +void // 17 +monocle(Monitor *m) { + Client *c = NULL; struct wlr_box geom; + int32_t cur_gappov = enablegaps ? m->gappov : 0; int32_t cur_gappoh = enablegaps ? m->gappoh : 0; - int32_t cur_gapiv = enablegaps ? m->gappiv : 0; - int32_t cur_gapih = enablegaps ? m->gappih : 0; - if (config.smartgaps && m->visible_fake_tiling_clients == 1) { - cur_gappov = cur_gappoh = cur_gapiv = cur_gapih = 0; - } - - int n = m->visible_fake_tiling_clients; - if (n == 0) - return; - - wl_list_for_each(c, &fstack, flink) { - if (c->iskilling || c->isunglobal || !ISFAKETILED(c)) - continue; - if (VISIBLEON(c, m)) { - fc = c; - break; - } - } - - if (n == 1) { - geom.x = m->w.x + cur_gappoh; - geom.y = m->w.y + cur_gappov; - geom.width = m->w.width - 2 * cur_gappoh; - geom.height = m->w.height - 2 * cur_gappov; - client_tile_resize(fc, geom, 0); - monocle_set_focus(fc, true); - return; - } - - int tab_bar_height = config.tab_bar_height; - - int tab_bar_inner_gap_height = - config.tab_bar_height > 0 ? 2 * cur_gapiv : 0; - int tab_bar_y_offset = config.tab_bar_height > 0 ? cur_gapiv : 0; - - int tab_y = m->w.y + cur_gappov; - int main_y = tab_y + tab_bar_height + tab_bar_y_offset; - int main_height = m->w.height - 2 * cur_gappov - tab_bar_inner_gap_height - - tab_bar_height; - - int tab_area_width = m->w.width - 2 * cur_gappoh; - - int total_gaps = (n - 1) * cur_gapih; - int base_width = (tab_area_width - total_gaps) / n; - int remainder = (tab_area_width - total_gaps) % n; - - int tab_x = m->w.x + cur_gappoh; - int idx = 0; + cur_gappoh = config.smartgaps && m->visible_fake_tiling_clients == 1 + ? 0 + : cur_gappoh; + cur_gappov = config.smartgaps && m->visible_fake_tiling_clients == 1 + ? 0 + : cur_gappov; wl_list_for_each(c, &clients, link) { if (!VISIBLEON(c, m) || !ISFAKETILED(c)) continue; - - if (c == fc) { - monocle_set_focus(c, true); - } else { - monocle_set_focus(c, false); - } - geom.x = m->w.x + cur_gappoh; - geom.y = main_y; + geom.y = m->w.y + cur_gappov; geom.width = m->w.width - 2 * cur_gappoh; - geom.height = main_height; + geom.height = m->w.height - 2 * cur_gappov; client_tile_resize(c, geom, 0); - - int tw = base_width + (idx < remainder ? 1 : 0); - global_draw_tab_bar(c, tab_x, tab_y, tw, tab_bar_height); - - tab_x += tw + cur_gapih; - idx++; } + if ((c = focustop(m))) + wlr_scene_node_raise_to_top(&c->scene->node); } // 网格布局窗口大小和位置计算 diff --git a/src/layout/overview.h b/src/layout/overview.h index 1ae9e7a0..e1054531 100644 --- a/src/layout/overview.h +++ b/src/layout/overview.h @@ -1,4 +1,3 @@ - typedef struct { float x, y, w, h; } OvPlacedRect; @@ -232,16 +231,20 @@ void overview_scale(Monitor *m) { float base_x = m->w.x + target_gappo + dx; float base_y = m->w.y + target_gappo + dy; + // 收集所有客户端的目标几何,最后统一调用 client_tile_resize + struct wlr_box overview_boxes[n]; // C99 VLA,n > 0 时有效 for (int k = 0; k < n; k++) { - Client *cl = items[k].c; - struct wlr_box geom; - geom.x = (int)(base_x + placed[k].x + 0.5f); - geom.y = (int)(base_y + placed[k].y + 0.5f); float w = items[k].orig_w * best_s; float h = items[k].orig_h * best_s; - geom.width = (int)(geom.x + w + 0.5f) - geom.x; - geom.height = (int)(geom.y + h + 0.5f) - geom.y; - resize(cl, geom, 0); + int ix = (int)(base_x + placed[k].x + 0.5f); + int iy = (int)(base_y + placed[k].y + 0.5f); + int iw = (int)(ix + w + 0.5f) - ix; + int ih = (int)(iy + h + 0.5f) - iy; + overview_boxes[k] = (struct wlr_box){ix, iy, iw, ih}; + } + + for (int k = 0; k < n; k++) { + client_tile_resize(items[k].c, overview_boxes[k], 0); } } @@ -280,74 +283,69 @@ void overview_resize(Monitor *m) { return; } + // 临时存储每个客户端的目标几何 + struct wlr_box boxes[n]; // C99 VLA + if (n == 1) { int32_t cw = (m->w.width - 2 * target_gappo) * single_width_ratio; int32_t ch = (m->w.height - 2 * target_gappo) * single_height_ratio; - c_arr[0]->geom.x = m->w.x + (m->w.width - cw) / 2; - c_arr[0]->geom.y = m->w.y + (m->w.height - ch) / 2; - c_arr[0]->geom.width = cw; - c_arr[0]->geom.height = ch; - resize(c_arr[0], c_arr[0]->geom, 0); - free(c_arr); - return; - } - - if (n == 2) { + boxes[0].x = m->w.x + (m->w.width - cw) / 2; + boxes[0].y = m->w.y + (m->w.height - ch) / 2; + boxes[0].width = cw; + boxes[0].height = ch; + } else if (n == 2) { int32_t cw = (m->w.width - 2 * target_gappo - target_gappi) / 2; int32_t ch = (m->w.height - 2 * target_gappo) * 0.65f; - c_arr[0]->geom.x = m->w.x + target_gappo; - c_arr[0]->geom.y = m->w.y + (m->w.height - ch) / 2 + target_gappo; - c_arr[0]->geom.width = cw; - c_arr[0]->geom.height = ch; - resize(c_arr[0], c_arr[0]->geom, 0); + boxes[0].x = m->w.x + target_gappo; + boxes[0].y = m->w.y + (m->w.height - ch) / 2 + target_gappo; + boxes[0].width = cw; + boxes[0].height = ch; - c_arr[1]->geom.x = m->w.x + cw + target_gappo + target_gappi; - c_arr[1]->geom.y = m->w.y + (m->w.height - ch) / 2 + target_gappo; - c_arr[1]->geom.width = cw; - c_arr[1]->geom.height = ch; - resize(c_arr[1], c_arr[1]->geom, 0); + boxes[1].x = m->w.x + cw + target_gappo + target_gappi; + boxes[1].y = m->w.y + (m->w.height - ch) / 2 + target_gappo; + boxes[1].width = cw; + boxes[1].height = ch; + } else { + int32_t cols = 1; + while (cols * cols < n) + cols++; + int32_t rows = (n + cols - 1) / cols; - free(c_arr); - return; - } + int32_t ch = + (m->w.height - 2 * target_gappo - (rows - 1) * target_gappi) / rows; + int32_t cw = + (m->w.width - 2 * target_gappo - (cols - 1) * target_gappi) / cols; - int32_t cols = 1; - while (cols * cols < n) { - cols++; - } - int32_t rows = (n + cols - 1) / cols; + if (ch < 1) + ch = 1; + if (cw < 1) + cw = 1; - int32_t ch = - (m->w.height - 2 * target_gappo - (rows - 1) * target_gappi) / rows; - int32_t cw = - (m->w.width - 2 * target_gappo - (cols - 1) * target_gappi) / cols; - - if (ch < 1) - ch = 1; - if (cw < 1) - cw = 1; - - int32_t overcols = n % cols; - int32_t dx = 0; - if (overcols) { - dx = (m->w.width - overcols * cw - (overcols - 1) * target_gappi) / 2 - - target_gappo; - } - - for (int i = 0; i < n; i++) { - int32_t cx = m->w.x + (i % cols) * (cw + target_gappi); - int32_t cy = m->w.y + (i / cols) * (ch + target_gappi); - - if (overcols && i >= n - overcols) { - cx += dx; + int32_t overcols = n % cols; + int32_t dx = 0; + if (overcols) { + dx = (m->w.width - overcols * cw - (overcols - 1) * target_gappi) / + 2 - + target_gappo; } - c_arr[i]->geom.x = cx + target_gappo; - c_arr[i]->geom.y = cy + target_gappo; - c_arr[i]->geom.width = cw; - c_arr[i]->geom.height = ch; - resize(c_arr[i], c_arr[i]->geom, 0); + for (int i = 0; i < n; i++) { + int32_t cx = m->w.x + (i % cols) * (cw + target_gappi); + int32_t cy = m->w.y + (i / cols) * (ch + target_gappi); + if (overcols && i >= n - overcols) + cx += dx; + + boxes[i].x = cx + target_gappo; + boxes[i].y = cy + target_gappo; + boxes[i].width = cw; + boxes[i].height = ch; + } + } + + // 统一应用所有几何变更,使用 client_tile_resize + for (int k = 0; k < n; k++) { + client_tile_resize(c_arr[k], boxes[k], 0); } free(c_arr); @@ -365,10 +363,9 @@ void create_jump_hints(Monitor *m) { char c_char = jump_labels[label_idx]; c->jump_char = c_char; - // 把字符变成字符串 char label_text[2] = {c_char, '\0'}; - - mango_jump_label_node_update(c->jump_label_node, label_text, 1.0f); + mango_jump_label_node_update(c->jump_label_node, label_text, + m->wlr_output->scale); wlr_scene_node_set_enabled(&c->jump_label_node->scene_buffer->node, true); wlr_scene_node_raise_to_top( @@ -385,12 +382,10 @@ void create_jump_hints(Monitor *m) { void begin_jump_mode(Monitor *m) { m->is_jump_mode = 1; } void finish_jump_mode(Monitor *m) { - Client *c = NULL; - - if (!m->is_jump_mode) { + if (!m->is_jump_mode) return; - } + Client *c; wl_list_for_each(c, &clients, link) { if (VISIBLEON(c, m)) { if (c->jump_label_node->scene_buffer->node.enabled) { @@ -400,12 +395,10 @@ void finish_jump_mode(Monitor *m) { } } } - m->is_jump_mode = 0; } void overview(Monitor *m) { - if (config.ov_no_resize) { overview_scale(m); } else { @@ -415,4 +408,4 @@ void overview(Monitor *m) { if (m->is_jump_mode) { create_jump_hints(m); } -} \ No newline at end of file +} diff --git a/src/layout/scroll.h b/src/layout/scroll.h index b800c5cf..6d290607 100644 --- a/src/layout/scroll.h +++ b/src/layout/scroll.h @@ -36,7 +36,6 @@ scroller_node_create(struct TagScrollerState *st, Client *c) { return n; } -/* 从 tag 状态中移除一个节点并释放 */ static void scroller_node_remove(struct TagScrollerState *st, struct ScrollerStackNode *target) { if (!st || !target) @@ -223,7 +222,7 @@ void arrange_stack_node(struct ScrollerStackNode *head, struct wlr_box geometry, .y = current_y, .width = geometry.width, .height = client_height}; - resize(iter->client, client_geom, 0); + client_tile_resize(iter->client, client_geom, 0); remain_proportion -= iter->stack_proportion; remain_client_height -= client_height; current_y += client_height + gappiv; @@ -272,7 +271,7 @@ void arrange_stack_vertical_node(struct ScrollerStackNode *head, .x = current_x, .height = geometry.height, .width = client_width}; - resize(iter->client, client_geom, 0); + client_tile_resize(iter->client, client_geom, 0); remain_proportion -= iter->stack_proportion; remain_client_width -= client_width; current_x += client_width + gappih; @@ -508,6 +507,7 @@ void scroller(Monitor *m) { void vertical_scroller(Monitor *m) { uint32_t tag = m->pertag->curtag; + int32_t bar_height = 0; struct TagScrollerState *st = ensure_scroller_state(m, tag); Client *c = NULL; float scroller_default_proportion_single = @@ -696,7 +696,12 @@ void vertical_scroller(Monitor *m) { arrange_stack_vertical_node(heads[focus_index], target_geom, cur_gappih); } else { - target_geom.y = root_client->geom.y; + bar_height = !root_client->isfullscreen && (root_client->group_prev || + root_client->group_next) + ? config.group_bar_height + : 0; + + target_geom.y = root_client->geom.y - bar_height; vertical_check_scroller_root_inside_mon(heads[focus_index]->client, &target_geom); arrange_stack_vertical_node(heads[focus_index], target_geom, @@ -709,8 +714,15 @@ void vertical_scroller(Monitor *m) { up_geom.width = m->w.width - 2 * cur_gappoh; up_geom.height = max_client_height * cur->scroller_proportion; vertical_scroll_adjust_fullandmax(cur->client, &up_geom); + + bar_height = !heads[focus_index - i + 1]->client->isfullscreen && + (heads[focus_index - i + 1]->client->group_prev || + heads[focus_index - i + 1]->client->group_next) + ? config.group_bar_height + : 0; + up_geom.y = heads[focus_index - i + 1]->client->geom.y - cur_gappiv - - up_geom.height; + up_geom.height - bar_height; arrange_stack_vertical_node(cur, up_geom, cur_gappih); } @@ -773,16 +785,14 @@ void scroller_insert_stack(Client *c, Client *target_client, if (tnode->prev_in_stack) tnode->prev_in_stack->next_in_stack = newnode; tnode->prev_in_stack = newnode; - wl_list_remove(&c->link); - wl_list_insert(tnode->client->link.prev, &c->link); + wl_list_safe_reinsert_prev(&tnode->client->link, &c->link); } else { newnode->prev_in_stack = tnode; newnode->next_in_stack = tnode->next_in_stack; if (tnode->next_in_stack) tnode->next_in_stack->prev_in_stack = newnode; tnode->next_in_stack = newnode; - wl_list_remove(&c->link); - wl_list_insert(&tnode->client->link, &c->link); + wl_list_safe_reinsert_next(&tnode->client->link, &c->link); } /* 处理堆叠头部的全屏/最大化状态*/ @@ -821,13 +831,11 @@ void scroller_drop_tile(Client *c, Client *closest, int vertical) { return; } else if (closest->drop_direction == UP) { if (c != stack_head) { - wl_list_remove(&c->link); - wl_list_insert(stack_head->link.prev, &c->link); + wl_list_safe_reinsert_prev(&stack_head->link, &c->link); } } else if (closest->drop_direction == DOWN) { if (c != stack_tail) { - wl_list_remove(&c->link); - wl_list_insert(&stack_tail->link, &c->link); + wl_list_safe_reinsert_next(&stack_head->link, &c->link); } } } else { @@ -841,13 +849,11 @@ void scroller_drop_tile(Client *c, Client *closest, int vertical) { return; } else if (closest->drop_direction == LEFT) { if (c != stack_head) { - wl_list_remove(&c->link); - wl_list_insert(stack_head->link.prev, &c->link); + wl_list_safe_reinsert_prev(&stack_head->link, &c->link); } } else if (closest->drop_direction == RIGHT) { if (c != stack_tail) { - wl_list_remove(&c->link); - wl_list_insert(&stack_tail->link, &c->link); + wl_list_safe_reinsert_next(&stack_head->link, &c->link); } } } @@ -902,7 +908,6 @@ static void update_scroller_state(Monitor *m) { break; } - /* 移除不再可见的节点 */ struct ScrollerStackNode *n = st->all_first; while (n) { bool found = false; diff --git a/src/mango.c b/src/mango.c index 5549686c..0f4aeecd 100644 --- a/src/mango.c +++ b/src/mango.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -32,6 +31,8 @@ #include #include #include +#include +#include #include #include #include @@ -41,8 +42,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -114,6 +117,8 @@ #define ISTILED(A) \ (A && !(A)->isfloating && !(A)->isminimized && !(A)->iskilling && \ !(A)->ismaximizescreen && !(A)->isfullscreen && !(A)->isunglobal) +#define ISNORMAL(A) \ + (A && !(A)->isminimized && !(A)->iskilling && !(A)->isunglobal) #define ISSCROLLTILED(A) \ (A && !(A)->isfloating && !(A)->isminimized && !(A)->iskilling && \ !(A)->isunglobal) @@ -121,9 +126,13 @@ (A && !(A)->isfloating && !(A)->isminimized && !(A)->iskilling && \ !(A)->isunglobal) #define VISIBLEON(C, M) \ - ((C) && (M) && (C)->mon == (M) && \ + ((C) && (M) && (C)->mon == (M) && !(C)->is_logic_hide && \ (((C)->tags & (M)->tagset[(M)->seltags] || (C)->isglobal || \ (C)->isunglobal))) + +#define TAGMATCH(C, M) \ + ((C) && (M) && (C)->mon == (M) && (((C)->tags & (M)->tagset[(M)->seltags]))) + #define LENGTH(X) (sizeof X / sizeof X[0]) #define END(A) ((A) + LENGTH(A)) #define TAGMASK ((1 << LENGTH(tags)) - 1) @@ -163,14 +172,22 @@ enum { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT }; enum { VERTICAL, HORIZONTAL }; enum { SWIPE_UP, SWIPE_DOWN, SWIPE_LEFT, SWIPE_RIGHT }; enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ -enum { XDGShell, LayerShell, X11 }; /* client types */ -enum { AxisUp, AxisDown, AxisLeft, AxisRight }; // 滚轮滚动的方向 +enum { + XDGShell, + LayerShell, + X11, + Snapshot, + XdgPopup, + XdgImPopup, + GroupBar +}; /* client types */ +enum { AxisUp, AxisDown, AxisLeft, AxisRight }; // 滚轮滚动的方向 enum { LyrBg, LyrBlur, LyrBottom, - LyrDecorate, LyrTile, + LyrMaximize, LyrTop, LyrFadeOut, LyrOverlay, @@ -179,8 +196,6 @@ enum { NUM_LAYERS }; /* scene layers */ -enum mango_node_type { MANGO_TITLE_NODE, MANGO_jump_label_node }; - #ifdef XWAYLAND enum { NetWMWindowTypeDialog, @@ -246,12 +261,6 @@ typedef struct { uint32_t ui2; Client *tc; } Arg; - -typedef struct { - enum mango_node_type type; - void *node_data; -} MangoNodeData; - typedef struct { uint32_t mod; uint32_t button; @@ -286,7 +295,7 @@ typedef struct { InputDevice *input_dev; } Switch; -struct dwl_animation { +struct mango_animation { bool should_animate; bool running; bool tagining; @@ -302,7 +311,7 @@ struct dwl_animation { int32_t action; }; -struct dwl_opacity_animation { +struct mango_opacity_animation { bool running; float current_opacity; float target_opacity; @@ -319,13 +328,13 @@ typedef struct { float height_scale; int32_t width; int32_t height; - enum corner_location corner_location; + struct fx_corner_radii corner_location; bool should_scale; } BufferData; struct Client { /* Must keep these three elements in this order */ - uint32_t type; /* XDGShell or X11* */ + uint32_t type; // must at first in struct struct wlr_box geom, pending, float_geom, animainit_geom, overview_backup_geom, current, drag_begin_geom; /* layout-relative, includes border */ @@ -335,10 +344,16 @@ struct Client { struct wlr_scene_rect *droparea; struct wlr_scene_rect *splitindicator[4]; struct wlr_scene_shadow *shadow; + struct wlr_scene_rect *shield; + struct wlr_scene_blur *blur; struct wlr_scene_tree *scene_surface; + struct wlr_scene_tree *image_capture_tree; + struct wlr_scene *image_capture_scene; + struct wlr_ext_image_capture_source_v1 *image_capture_source; + struct wlr_scene_surface *image_capture_scene_surface; struct wlr_scene_tree *overview_scene_surface; - struct mango_jump_label_node *jump_label_node; - struct mango_tab_bar_node *tab_bar_node; + MangoJumpLabel *jump_label_node; + MangoGroupBar *group_bar; struct wl_list link; struct wl_list flink; struct wl_list fadeout_link; @@ -370,7 +385,8 @@ struct Client { struct wlr_foreign_toplevel_handle_v1 *foreign_toplevel; int32_t isfloating, isurgent, isfullscreen, isfakefullscreen, need_float_size_reduce, isminimized, isoverlay, isnosizehint, - ignore_maximize, ignore_minimize, idleinhibit_when_focus; + ignore_maximize, ignore_minimize, idleinhibit_when_focus, + vrr_only_fullscreen; int32_t ismaximizescreen; int32_t overview_backup_bw; int32_t fullscreen_backup_x, fullscreen_backup_y, fullscreen_backup_w, @@ -406,21 +422,21 @@ struct Client { int32_t iskilling; int32_t istagswitching; int32_t isnamedscratchpad; - bool is_monocle_hide; + int32_t shield_when_capture; bool is_pending_open_animation; bool is_restoring_from_ov; float scroller_proportion; float stack_proportion; float old_stack_proportion; bool need_output_flush; - struct dwl_animation animation; - struct dwl_opacity_animation opacity_animation; + struct mango_animation animation; + struct mango_opacity_animation opacity_animation; int32_t isterm, noswallow; int32_t allow_csd; int32_t force_fakemaximize; int32_t force_tiled_state; pid_t pid; - Client *swallowing, *swallowedby; + Client *swallowdby, *swallowing; bool is_clip_to_hide; bool drag_to_tile; bool scratchpad_switching_mon; @@ -434,6 +450,7 @@ struct Client { float unfocused_opacity; char oldmonname[128]; int32_t noblur; + struct wlr_ext_foreign_toplevel_handle_v1 *ext_foreign_toplevel; double master_mfact_per, master_inner_per, stack_inner_per; double old_master_mfact_per, old_master_inner_per, old_stack_inner_per; double old_scroller_pproportion; @@ -457,14 +474,12 @@ struct Client { int32_t grid_col_idx; int32_t grid_row_idx; uint32_t id; + Client *group_prev; + Client *group_next; + bool isgroupfocusing; + bool is_logic_hide; }; -typedef struct { - struct wl_list link; - struct wl_resource *resource; - Monitor *mon; -} DwlIpcOutput; - typedef struct { uint32_t mod; xkb_keysym_t keysym; @@ -496,12 +511,14 @@ typedef struct { typedef struct { /* Must keep these three elements in this order */ - uint32_t type; /* LayerShell */ + uint32_t type; // must at first in struct struct wlr_box geom, current, pending, animainit_geom; Monitor *mon; struct wlr_scene_tree *scene; struct wlr_scene_tree *popups; + struct wlr_scene_rect *shield; struct wlr_scene_shadow *shadow; + struct wlr_scene_blur *blur; struct wlr_scene_layer_surface_v1 *scene_layer; struct wl_list link; struct wl_list fadeout_link; @@ -513,18 +530,20 @@ typedef struct { struct wl_listener unmap; struct wl_listener surface_commit; - struct dwl_animation animation; + struct mango_animation animation; bool dirty; int32_t noblur; int32_t noanim; int32_t noshadow; char *animation_type_open; char *animation_type_close; + bool shield_when_capture; bool need_output_flush; bool being_unmapped; } LayerSurface; typedef struct { + uint32_t type; // must at first in struct struct wlr_xdg_popup *wlr_popup; struct wl_listener destroy; struct wl_listener commit; @@ -558,7 +577,6 @@ struct Monitor { uint32_t resizing_count_pending; uint32_t resizing_count_current; - struct wl_list dwl_ipc_outputs; int32_t gappih; /* horizontal gap between windows */ int32_t gappiv; /* vertical gap between windows */ int32_t gappoh; /* horizontal outer gaps */ @@ -570,7 +588,7 @@ struct Monitor { int32_t isoverview; int32_t is_jump_mode; int32_t is_in_hotarea; - int32_t asleep; + int32_t only_sleep; uint32_t visible_clients; uint32_t visible_tiling_clients; uint32_t visible_scroll_tiling_clients; @@ -580,6 +598,10 @@ struct Monitor { struct wlr_ext_workspace_group_handle_v1 *ext_group; bool iscleanuping; int8_t carousel_anim_dir; + bool vrr_global_enable; + bool is_vrr_opening; + bool hdr_enable; + bool prefer_disable; }; typedef struct { @@ -596,6 +618,11 @@ typedef struct { struct wl_listener destroy; } SessionLock; +struct capture_session_tracker { + struct wl_listener session_destroy; + struct wlr_ext_image_copy_capture_session_v1 *session; +}; + typedef struct DwindleNode DwindleNode; struct DwindleNode { bool is_split; @@ -631,6 +658,7 @@ struct TagScrollerState { }; typedef struct { + uint32_t type; // must at first in struct int32_t orig_width; int32_t orig_height; bool is_subsurface; @@ -780,13 +808,18 @@ static void virtualkeyboard(struct wl_listener *listener, void *data); static void virtualpointer(struct wl_listener *listener, void *data); static void warp_cursor(const Client *c); static Monitor *xytomon(double x, double y); +static Monitor *get_monitor_nearest_to(int32_t x, int32_t y); +static void handle_iamge_copy_capture_new_session(struct wl_listener *listener, + void *data); static void xytonode(double x, double y, struct wlr_surface **psurface, - Client **pc, LayerSurface **pl, double *nx, double *ny); + Client **pc, LayerSurface **pl, MangoGroupBar **tb, + double *nx, double *ny); static void clear_fullscreen_flag(Client *c); static pid_t getparentprocess(pid_t p); static int32_t isdescprocess(pid_t p, pid_t c); static Client *termforwin(Client *w); -static void swallow(Client *c, Client *w); +static void client_replace(Client *c, Client *w, bool is_group_change_member, + bool is_swallow); static void warp_cursor_to_selmon(Monitor *m); uint32_t want_restore_fullscreen(Client *target_client); @@ -810,7 +843,7 @@ get_nearest_output_mode(struct wlr_output *output, int32_t width, static void client_commit(Client *c); static void layer_commit(LayerSurface *l); -static void apply_border(Client *c); +static void client_draw_border(Client *c, struct ivec2 offsets); static void client_set_opacity(Client *c, double opacity); static void init_baked_points(void); static void scene_buffer_apply_opacity(struct wlr_scene_buffer *buffer, @@ -846,7 +879,7 @@ static double find_animation_curve_at(double t, int32_t type); static void apply_opacity_to_rect_nodes(Client *c, struct wlr_scene_node *node, double animation_passed); -static enum corner_location set_client_corner_location(Client *c); +static struct fx_corner_radii set_client_corner_location(Client *c); static double all_output_frame_duration_ms(); static struct wlr_scene_tree * wlr_scene_tree_snapshot(struct wlr_scene_node *node, @@ -918,6 +951,21 @@ static void overview_backup_surface(Client *c); static void create_jump_hints(Monitor *m); static void finish_jump_mode(Monitor *m); static void begin_jump_mode(Monitor *m); +static void global_draw_group_bar(Client *c, int32_t x, int32_t y, + int32_t width, int32_t height); + +static void client_reparent_group(Client *c); +static void client_change_mon(Client *c, Monitor *m); +static void check_vrr_enable(Client *c); +static void output_state_setup_hdr(Monitor *m, bool silent, + struct wlr_output_state *state); +static void output_enable_hdr(Monitor *m, struct wlr_output_state *os, + bool enabled, bool silent); +static bool mango_scene_output_commit(struct wlr_scene_output *scene_output, + struct wlr_output_state *state); +static bool mango_output_commit(Monitor *m); +static bool check_tearing_frame_allow(Monitor *m); +static void client_set_group_config(Client *c); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -955,6 +1003,7 @@ static struct wlr_keyboard_shortcuts_inhibit_manager_v1 *keyboard_shortcuts_inhibit; static struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr; static struct wlr_output_power_manager_v1 *power_mgr; +static struct wlr_ext_image_copy_capture_manager_v1 *ext_image_copy_capture_mgr; static struct wlr_pointer_gestures_v1 *pointer_gestures; static struct wlr_drm_lease_v1_manager *drm_lease_manager; struct mango_print_status_manager *print_status_manager; @@ -981,7 +1030,13 @@ static struct wl_list keyboard_shortcut_inhibitors; static uint32_t cursor_mode; static Client *grabc, *dropc; static int32_t rzcorner; -static int32_t grabcx, grabcy; /* client-relative */ +static int32_t grabcx, grabcy; /* client-relative */ + +static struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 + *ext_foreign_toplevel_image_capture_source_manager_v1; +static struct wl_listener new_foreign_toplevel_capture_request; +static struct wlr_ext_foreign_toplevel_list_v1 *foreign_toplevel_list; + static int32_t drag_begin_cursorx, drag_begin_cursory; /* client-relative */ static bool start_drag_window = false; static int32_t last_apply_drap_time = 0; @@ -1019,6 +1074,7 @@ static struct wl_event_source *keep_idle_inhibit_source; static bool cursor_hidden = false; static bool tag_combo = false; static const char *cli_config_path = NULL; +static int active_capture_count = 0; static bool cli_debug_log = false; static KeyMode keymode = { .mode = {'d', 'e', 'f', 'a', 'u', 'l', 't', '\0'}, @@ -1084,6 +1140,8 @@ static struct wl_listener output_mgr_apply = {.notify = outputmgrapply}; static struct wl_listener output_mgr_test = {.notify = outputmgrtest}; static struct wl_listener output_power_mgr_set_mode = {.notify = powermgrsetmode}; +static struct wl_listener ext_image_copy_capture_mgr_new_session = { + .notify = handle_iamge_copy_capture_new_session}; 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}; @@ -1117,6 +1175,7 @@ static struct wl_event_source *sync_keymap; #endif #include "action/client.h" +#include "action/monitor.h" #include "animation/client.h" #include "animation/common.h" #include "animation/layer.h" @@ -1231,8 +1290,7 @@ void show_scratchpad(Client *c) { } c->oldtags = c->mon->tagset[c->mon->seltags]; - wl_list_remove(&c->link); // 从原来位置移除 - wl_list_insert(clients.prev->next, &c->link); // 插入开头 + wl_list_safe_reinsert_next(&clients, &c->link); show_hide_client(c); setborder_color(c); } @@ -1245,7 +1303,8 @@ void client_update_oldmonname_record(Client *c, Monitor *m) { c->oldmonname[sizeof(c->oldmonname) - 1] = '\0'; } -void swallow(Client *c, Client *w) { +void client_replace(Client *c, Client *w, bool is_group_change_member, + bool is_swallow) { c->bw = w->bw; c->isfloating = w->isfloating; c->isurgent = w->isurgent; @@ -1260,9 +1319,16 @@ void swallow(Client *c, Client *w) { c->scroller_proportion = w->scroller_proportion; c->isglobal = w->isglobal; c->overview_backup_geom = w->overview_backup_geom; - - /* 调整 w 的邻居指针,让它们指向 c */ + c->animation.current = w->animation.current; c->stack_proportion = w->stack_proportion; + c->is_logic_hide = w->is_logic_hide; + + if (is_swallow || !is_group_change_member) { + client_group_replace(w, c); + } + + w->is_logic_hide = true; + mango_group_bar_set_focus(c->group_bar, c->isgroupfocusing); if (w->overview_scene_surface) { wlr_scene_node_destroy(&w->scene_surface->node); @@ -1274,13 +1340,18 @@ void swallow(Client *c, Client *w) { overview_backup_surface(c); } - if (w->tab_bar_node) { - wlr_scene_node_set_enabled(&w->tab_bar_node->scene_buffer->node, false); + if (w->group_bar && !is_group_change_member) { + wlr_scene_node_set_enabled(&w->group_bar->scene_buffer->node, false); } - /* 全局链表替换 */ - wl_list_insert(&w->link, &c->link); - wl_list_insert(&w->flink, &c->flink); + wl_list_safe_reinsert_next(&w->link, &c->link); + wl_list_safe_reinsert_prev(&w->flink, &c->flink); + wlr_scene_node_set_enabled(&w->scene->node, false); + + if (!c->is_logic_hide) { + wlr_scene_node_set_enabled(&c->scene->node, true); + wlr_scene_node_set_enabled(&c->scene_surface->node, true); + } if (w->foreign_toplevel) { wlr_foreign_toplevel_handle_v1_output_leave(w->foreign_toplevel, @@ -1289,10 +1360,6 @@ void swallow(Client *c, Client *w) { w->foreign_toplevel = NULL; } - wlr_scene_node_set_enabled(&w->scene->node, false); - wlr_scene_node_set_enabled(&c->scene->node, true); - wlr_scene_node_set_enabled(&c->scene_surface->node, true); - if (!c->foreign_toplevel && c->mon) add_foreign_toplevel(c); else if (c->foreign_toplevel && c->mon) { @@ -1329,12 +1396,10 @@ void swallow(Client *c, Client *w) { struct TagScrollerState *st = w->mon->pertag->scroller_state[t]; if (!st) continue; - /* 先移除 c 在任意 tag 中的旧节点 */ struct ScrollerStackNode *cn = find_scroller_node(st, c); if (cn) scroller_node_remove(st, cn); - /* 将 w 的节点(如果存在)转给 c */ struct ScrollerStackNode *wn = find_scroller_node(st, w); if (wn) wn->client = c; @@ -1548,10 +1613,12 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) { APPLY_INT_PROP(c, r, isnamedscratchpad); APPLY_INT_PROP(c, r, isglobal); APPLY_INT_PROP(c, r, isoverlay); + APPLY_INT_PROP(c, r, shield_when_capture); APPLY_INT_PROP(c, r, ignore_maximize); APPLY_INT_PROP(c, r, ignore_minimize); APPLY_INT_PROP(c, r, isnosizehint); APPLY_INT_PROP(c, r, idleinhibit_when_focus); + APPLY_INT_PROP(c, r, vrr_only_fullscreen); APPLY_INT_PROP(c, r, isunglobal); APPLY_INT_PROP(c, r, noblur); APPLY_INT_PROP(c, r, allow_shortcuts_inhibit); @@ -1619,7 +1686,7 @@ void client_reset_mon_tags(Client *c, Monitor *mon, uint32_t newtags) { } void check_match_tag_floating_rule(Client *c, Monitor *mon) { - if (c->tags && !c->isfloating && mon && !c->swallowedby && + if (c->tags && !c->isfloating && mon && !c->swallowing && mon->pertag->open_as_floating[get_tags_first_tag_num(c->tags)]) { c->isfloating = 1; } @@ -1749,13 +1816,11 @@ void applyrules(Client *c) { !c->surface.xdg->initial_commit) { Client *p = termforwin(c); if (p && !p->isminimized) { - c->swallowedby = p; - p->swallowing = c; - wl_list_remove(&c->link); - wl_list_remove(&c->flink); - swallow(c, p); - wl_list_remove(&p->link); - wl_list_remove(&p->flink); + c->swallowing = p; + p->swallowdby = c; + + client_replace(c, p, false, true); + mon = p->mon; newtags = p->tags; } @@ -1770,8 +1835,7 @@ void applyrules(Client *c) { (!c->istagsilent || !newtags || newtags & mon->tagset[mon->seltags]); if (!should_init_get_focus) { - wl_list_remove(&c->flink); - wl_list_insert(fstack.prev, &c->flink); + wl_list_safe_reinsert_prev(&fstack, &c->flink); } setmon(c, mon, newtags, should_init_get_focus); @@ -1807,8 +1871,7 @@ void applyrules(Client *c) { } if (c->isfloating && !c->iscustompos && !c->isnamedscratchpad) { - wl_list_remove(&c->link); - wl_list_insert(clients.prev, &c->link); + wl_list_safe_reinsert_prev(&clients, &c->link); set_float_malposition(c); } @@ -1951,7 +2014,8 @@ void apply_window_snap(Client *c) { void focuslayer(LayerSurface *l) { focusclient(NULL, 0); - dwl_im_relay_set_focus(dwl_input_method_relay, l->layer_surface->surface); + mango_im_relay_set_focus(mango_input_method_relay, + l->layer_surface->surface); client_notify_enter(l->layer_surface->surface, wlr_seat_get_keyboard(seat)); } @@ -2170,6 +2234,10 @@ int32_t ongesture(struct wlr_pointer_swipe_end_event *event) { void swipe_begin(struct wl_listener *listener, void *data) { struct wlr_pointer_swipe_begin_event *event = data; + if (config.disable_trackpad) { + return; + } + // Forward swipe begin event to client wlr_pointer_gestures_v1_send_swipe_begin(pointer_gestures, seat, event->time_msec, event->fingers); @@ -2178,6 +2246,10 @@ void swipe_begin(struct wl_listener *listener, void *data) { void swipe_update(struct wl_listener *listener, void *data) { struct wlr_pointer_swipe_update_event *event = data; + if (config.disable_trackpad) { + return; + } + swipe_fingers = event->fingers; // Accumulate swipe distance swipe_dx += event->dx; @@ -2190,6 +2262,11 @@ void swipe_update(struct wl_listener *listener, void *data) { void swipe_end(struct wl_listener *listener, void *data) { struct wlr_pointer_swipe_end_event *event = data; + + if (config.disable_trackpad) { + return; + } + ongesture(event); swipe_dx = 0; swipe_dy = 0; @@ -2201,6 +2278,10 @@ void swipe_end(struct wl_listener *listener, void *data) { void pinch_begin(struct wl_listener *listener, void *data) { struct wlr_pointer_pinch_begin_event *event = data; + if (config.disable_trackpad) { + return; + } + // Forward pinch begin event to client wlr_pointer_gestures_v1_send_pinch_begin(pointer_gestures, seat, event->time_msec, event->fingers); @@ -2209,6 +2290,10 @@ void pinch_begin(struct wl_listener *listener, void *data) { void pinch_update(struct wl_listener *listener, void *data) { struct wlr_pointer_pinch_update_event *event = data; + if (config.disable_trackpad) { + return; + } + // Forward pinch update event to client wlr_pointer_gestures_v1_send_pinch_update( pointer_gestures, seat, event->time_msec, event->dx, event->dy, @@ -2218,6 +2303,10 @@ void pinch_update(struct wl_listener *listener, void *data) { void pinch_end(struct wl_listener *listener, void *data) { struct wlr_pointer_pinch_end_event *event = data; + if (config.disable_trackpad) { + return; + } + // Forward pinch end event to client wlr_pointer_gestures_v1_send_pinch_end(pointer_gestures, seat, event->time_msec, event->cancelled); @@ -2226,6 +2315,10 @@ void pinch_end(struct wl_listener *listener, void *data) { void hold_begin(struct wl_listener *listener, void *data) { struct wlr_pointer_hold_begin_event *event = data; + if (config.disable_trackpad) { + return; + } + // Forward hold begin event to client wlr_pointer_gestures_v1_send_hold_begin(pointer_gestures, seat, event->time_msec, event->fingers); @@ -2234,6 +2327,10 @@ void hold_begin(struct wl_listener *listener, void *data) { void hold_end(struct wl_listener *listener, void *data) { struct wlr_pointer_hold_end_event *event = data; + if (config.disable_trackpad) { + return; + } + // Forward hold end event to client wlr_pointer_gestures_v1_send_hold_end(pointer_gestures, seat, event->time_msec, event->cancelled); @@ -2277,8 +2374,7 @@ void place_drag_tile_client(Client *c) { if (closest->drop_direction == UNDIR) { setfloating(c, 0); - wl_list_remove(&c->link); - wl_list_insert(closest->link.prev, &c->link); + wl_list_safe_reinsert_prev(&closest->link, &c->link); arrange(closest->mon, false, false); return; } @@ -2305,11 +2401,9 @@ void place_drag_tile_client(Client *c) { } if (closest->drop_direction == LEFT || closest->drop_direction == UP) { - wl_list_remove(&c->link); - wl_list_insert(closest->link.prev, &c->link); + wl_list_safe_reinsert_prev(&closest->link, &c->link); } else { - wl_list_remove(&c->link); - wl_list_insert(&closest->link, &c->link); + wl_list_safe_reinsert_next(&closest->link, &c->link); } } @@ -2338,6 +2432,7 @@ bool handle_buttonpress(struct wlr_pointer_button_event *event) { uint32_t hard_mods, mods; Client *c = NULL; LayerSurface *l = NULL; + MangoGroupBar *gb = NULL; struct wlr_surface *surface; Client *tmpc = NULL; int32_t ji; @@ -2359,7 +2454,7 @@ bool handle_buttonpress(struct wlr_pointer_button_event *event) { if (locked) break; - xytonode(cursor->x, cursor->y, &surface, NULL, NULL, NULL, NULL); + xytonode(cursor->x, cursor->y, &surface, NULL, NULL, &gb, NULL, NULL); if (toplevel_from_wlr_surface(surface, &c, &l) >= 0) { if (c && c->scene->node.enabled && (!client_is_unmanaged(c) || client_wants_focus(c))) @@ -2390,15 +2485,7 @@ bool handle_buttonpress(struct wlr_pointer_button_event *event) { } // handle click on tile node - struct wlr_scene_node *node = wlr_scene_node_at( - &layers[LyrDecorate]->node, cursor->x, cursor->y, NULL, NULL); - if (node && node->data) { - MangoNodeData *mangonodedata = (MangoNodeData *)node->data; - if (mangonodedata->type == MANGO_TITLE_NODE) { - Client *c = mangonodedata->node_data; - focusclient(c, 1); - } - } + client_handle_decorate_click(gb); // 当鼠标焦点在layer上的时候,不检测虚拟键盘的mod状态, // 避免layer虚拟键盘锁死mod按键状态 @@ -2560,8 +2647,10 @@ void cleanuplisteners(void) { wl_list_remove(&request_start_drag.link); wl_list_remove(&start_drag.link); wl_list_remove(&new_session_lock.link); + wl_list_remove(&new_foreign_toplevel_capture_request.link); wl_list_remove(&tearing_new_object.link); wl_list_remove(&keyboard_shortcuts_inhibit_new_inhibitor.link); + wl_list_remove(&ext_image_copy_capture_mgr_new_session.link); if (drm_lease_manager) { wl_list_remove(&drm_lease_request.link); } @@ -2590,7 +2679,7 @@ void cleanup(void) { destroykeyboardgroup(&kb_group->destroy, NULL); - dwl_im_relay_finish(dwl_input_method_relay); + mango_im_relay_finish(mango_input_method_relay); /* If it's not destroyed manually it will cause a use-after-free of * wlr_seat. Destroy it until it's fixed in the wlroots side */ @@ -2678,9 +2767,9 @@ void closemon(Monitor *m) { c->foreign_toplevel = NULL; } - c->mon = NULL; + client_set_group_mon(c, NULL); } else { - client_change_mon(c, selmon); + client_set_group_mon(c, selmon); } // record the oldmonname which is used to restore if (c->oldmonname[0] == '\0') { @@ -2702,12 +2791,16 @@ static void iter_layer_scene_buffers(struct wlr_scene_buffer *buffer, return; } - wlr_scene_buffer_set_backdrop_blur(buffer, true); - wlr_scene_buffer_set_backdrop_blur_ignore_transparent(buffer, true); + LayerSurface *l = (LayerSurface *)user_data; + + wlr_scene_node_set_enabled(&l->blur->node, true); + wlr_scene_blur_set_transparency_mask_source(l->blur, buffer); + wlr_scene_blur_set_size(l->blur, l->geom.width, l->geom.height); + if (config.blur_optimized) { - wlr_scene_buffer_set_backdrop_blur_optimized(buffer, true); + wlr_scene_blur_set_should_only_blur_bottom_layer(l->blur, true); } else { - wlr_scene_buffer_set_backdrop_blur_optimized(buffer, false); + wlr_scene_blur_set_should_only_blur_bottom_layer(l->blur, false); } } @@ -2744,6 +2837,7 @@ void maplayersurfacenotify(struct wl_listener *listener, void *data) { l->noanim = 0; l->dirty = false; + l->shield_when_capture = false; l->noblur = 0; l->shadow = NULL; l->need_output_flush = true; @@ -2756,6 +2850,7 @@ void maplayersurfacenotify(struct wl_listener *listener, void *data) { l->layer_surface->namespace)) { r = &config.layer_rules[ji]; + APPLY_INT_PROP(l, r, shield_when_capture); APPLY_INT_PROP(l, r, noblur); APPLY_INT_PROP(l, r, noanim); APPLY_INT_PROP(l, r, noshadow); @@ -2764,15 +2859,26 @@ void maplayersurfacenotify(struct wl_listener *listener, void *data) { } } + // 初始化屏蔽 + l->shield = + wlr_scene_rect_create(l->scene, 0, 0, (float[4]){0, 0, 0, 0xff}); + l->shield->node.data = l; + wlr_scene_node_lower_to_bottom(&l->shield->node); + wlr_scene_node_set_enabled(&l->shield->node, false); + // 初始化阴影 - if (layer_surface->current.exclusive_zone == 0 && - layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM && + if (layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM && layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND) { - l->shadow = - wlr_scene_shadow_create(l->scene, 0, 0, config.border_radius, - config.shadows_blur, config.shadowscolor); - wlr_scene_node_lower_to_bottom(&l->shadow->node); - wlr_scene_node_set_enabled(&l->shadow->node, true); + if (layer_surface->current.exclusive_zone == 0) { + l->shadow = wlr_scene_shadow_create( + l->scene, 0, 0, config.border_radius, config.shadows_blur, + config.shadowscolor); + wlr_scene_node_lower_to_bottom(&l->shadow->node); + wlr_scene_node_set_enabled(&l->shadow->node, true); + } + + l->blur = wlr_scene_blur_create(l->scene, 0, 0); + wlr_scene_node_lower_to_bottom(&l->blur->node); } // 初始化动画 @@ -2780,6 +2886,9 @@ void maplayersurfacenotify(struct wl_listener *listener, void *data) { l->animation.duration = config.animation_duration_open; l->animation.action = OPEN; layer_set_pending_state(l); + } else { + l->animainit_geom = l->animation.current = l->current = l->pending = + l->geom; } // 刷新布局,让窗口能感应到exclude_zone变化以及设置独占表面 arrangelayers(l->mon); @@ -2823,20 +2932,26 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) { get_layer_target_geometry(l, &box); - if (config.animations && config.layer_animations && !l->noanim && - l->mapped && - layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM && - layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND && - !wlr_box_equal(&box, &l->geom)) { - + if (!wlr_box_equal(&box, &l->geom)) { l->geom.x = box.x; l->geom.y = box.y; l->geom.width = box.width; l->geom.height = box.height; - l->animation.action = MOVE; - l->animation.duration = config.animation_duration_move; - l->need_output_flush = true; - layer_set_pending_state(l); + + if (config.animations && config.layer_animations && !l->noanim && + l->mapped && + layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM && + layer_surface->current.layer != + ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND) { + l->animation.action = MOVE; + l->animation.duration = config.animation_duration_move; + l->need_output_flush = true; + layer_set_pending_state(l); + } else { + l->animainit_geom = l->animation.current = l->current = l->pending = + l->geom; + l->need_output_flush = true; + } } if (config.blur && config.blur_layer) { @@ -2844,7 +2959,8 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) { if (!l->noblur && layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM && layer_surface->current.layer != - ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND) { + ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND && + l->blur) { wlr_scene_node_for_each_buffer(&l->scene->node, iter_layer_scene_buffers, l); @@ -3052,6 +3168,8 @@ static void createpopup(struct wl_listener *listener, void *data) { if (!popup) return; + popup->type = XdgPopup; + popup->destroy.notify = destroypopup; wl_signal_add(&wlr_popup->events.destroy, &popup->destroy); @@ -3242,17 +3360,24 @@ struct wlr_output_mode *get_nearest_output_mode(struct wlr_output *output, } void enable_adaptive_sync(Monitor *m, struct wlr_output_state *state) { + wlr_output_state_set_adaptive_sync_enabled(state, true); if (!wlr_output_test_state(m->wlr_output, state)) { wlr_output_state_set_adaptive_sync_enabled(state, false); wlr_log(WLR_DEBUG, "failed to enable adaptive sync for output %s", m->wlr_output->name); } else { + m->is_vrr_opening = true; wlr_log(WLR_INFO, "adaptive sync enabled for output %s", m->wlr_output->name); } } +void disable_adaptive_sync(Monitor *m, struct wlr_output_state *state) { + wlr_output_state_set_adaptive_sync_enabled(state, false); + m->is_vrr_opening = false; +} + bool monitor_matches_rule(Monitor *m, const ConfigMonitorRule *rule) { if (rule->name != NULL && !regex_match(rule->name, m->wlr_output->name)) return false; @@ -3271,25 +3396,29 @@ bool monitor_matches_rule(Monitor *m, const ConfigMonitorRule *rule) { /* 将规则中的显示参数应用到 wlr_output_state 中,返回是否设置了自定义模式 */ bool apply_rule_to_state(Monitor *m, const ConfigMonitorRule *rule, - struct wlr_output_state *state, int vrr, int custom) { + struct wlr_output_state *state) { bool mode_set = false; + m->vrr_global_enable = rule->vrr >= 0 ? rule->vrr : 0; + m->hdr_enable = rule->hdr >= 0 ? rule->hdr : 0; + m->prefer_disable = rule->disable >= 0 ? rule->disable : 0; + if (rule->width > 0 && rule->height > 0 && rule->refresh > 0) { struct wlr_output_mode *internal_mode = get_nearest_output_mode( m->wlr_output, rule->width, rule->height, rule->refresh); if (internal_mode) { wlr_output_state_set_mode(state, internal_mode); mode_set = true; - } else if (custom || wlr_output_is_headless(m->wlr_output)) { + } else if (rule->custom || wlr_output_is_headless(m->wlr_output)) { wlr_output_state_set_custom_mode( state, rule->width, rule->height, (int32_t)roundf(rule->refresh * 1000)); mode_set = true; } } - if (vrr) { + if (m->vrr_global_enable) { enable_adaptive_sync(m, state); } else { - wlr_output_state_set_adaptive_sync_enabled(state, false); + disable_adaptive_sync(m, state); } wlr_output_state_set_scale(state, rule->scale); wlr_output_state_set_transform(state, rule->rr); @@ -3302,8 +3431,7 @@ void createmon(struct wl_listener *listener, void *data) { struct wlr_output *wlr_output = data; const ConfigMonitorRule *r; uint32_t i; - int32_t ji, vrr, custom; - struct wlr_output_state state; + int32_t ji; Monitor *m = NULL; bool custom_monitor_mode = false; @@ -3328,12 +3456,15 @@ void createmon(struct wl_listener *listener, void *data) { m->resizing_count_pending = 0; m->resizing_count_current = 0; m->carousel_anim_dir = 0; + m->vrr_global_enable = false; + m->is_vrr_opening = false; + + m->hdr_enable = false; + m->prefer_disable = false; m->wlr_output = wlr_output; m->wlr_output->data = m; - wl_list_init(&m->dwl_ipc_outputs); - for (i = 0; i < LENGTH(m->layers); i++) wl_list_init(&m->layers[i]); @@ -3349,9 +3480,9 @@ void createmon(struct wl_listener *listener, void *data) { float scale = 1; enum wl_output_transform rr = WL_OUTPUT_TRANSFORM_NORMAL; - wlr_output_state_init(&state); - wlr_output_state_set_scale(&state, scale); - wlr_output_state_set_transform(&state, rr); + wlr_output_state_init(&m->pending); + wlr_output_state_set_scale(&m->pending, scale); + wlr_output_state_set_transform(&m->pending, rr); for (ji = 0; ji < config.monitor_rules_count; ji++) { if (config.monitor_rules_count < 1) @@ -3362,12 +3493,8 @@ void createmon(struct wl_listener *listener, void *data) { if (monitor_matches_rule(m, r)) { m->m.x = r->x == INT32_MAX ? INT32_MAX : r->x; m->m.y = r->y == INT32_MAX ? INT32_MAX : r->y; - vrr = r->vrr >= 0 ? r->vrr : 0; - custom = r->custom >= 0 ? r->custom : 0; - scale = r->scale; - rr = r->rr; - if (apply_rule_to_state(m, r, &state, vrr, custom)) { + if (apply_rule_to_state(m, r, &m->pending)) { custom_monitor_mode = true; } break; // 只应用第一个匹配规则 @@ -3375,7 +3502,7 @@ void createmon(struct wl_listener *listener, void *data) { } if (!custom_monitor_mode) - wlr_output_state_set_mode(&state, + wlr_output_state_set_mode(&m->pending, wlr_output_preferred_mode(wlr_output)); /* Set up event listeners */ @@ -3384,9 +3511,20 @@ void createmon(struct wl_listener *listener, void *data) { LISTEN(&wlr_output->events.request_state, &m->request_state, requestmonstate); - wlr_output_state_set_enabled(&state, 1); - wlr_output_commit_state(wlr_output, &state); - wlr_output_state_finish(&state); + if (m->prefer_disable) { + wlr_output_state_set_enabled(&m->pending, false); + } else { + wlr_output_state_set_enabled(&m->pending, true); + } + + if (m->hdr_enable) { + output_state_setup_hdr(m, false, &m->pending); + } + + // 虚拟显示器在加入显示器链前必须先配置,否则会崩溃 + if (wlr_output_is_headless(m->wlr_output)) { + mango_output_commit(m); + } wl_list_insert(&mons, &m->link); @@ -3435,6 +3573,13 @@ void createmon(struct wl_listener *listener, void *data) { else wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y); + // 无头显示器不不要支持hdr + if (!wlr_output_is_headless(m->wlr_output)) { + mango_scene_output_commit(m->scene_output, &m->pending); + } + + wlr_output_effective_resolution(m->wlr_output, &m->m.width, &m->m.height); + if (config.blur) { m->blur = wlr_scene_optimized_blur_create(&scene->tree, 0, 0); wlr_scene_node_set_position(&m->blur->node, m->m.x, m->m.y); @@ -3482,30 +3627,22 @@ void destroyinputdevice(struct wl_listener *listener, void *data) { InputDevice *input_dev = wl_container_of(listener, input_dev, destroy_listener); - // 清理设备特定数据 if (input_dev->device_data) { - // 根据设备类型进行特定清理 switch (input_dev->wlr_device->type) { case WLR_INPUT_DEVICE_SWITCH: { Switch *sw = (Switch *)input_dev->device_data; - // 移除 toggle 监听器 wl_list_remove(&sw->toggle.link); - // 释放 Switch 内存 free(sw); break; } - // 可以添加其他设备类型的清理代码 default: break; } input_dev->device_data = NULL; } - // 从设备列表中移除 wl_list_remove(&input_dev->link); - // 移除 destroy 监听器 wl_list_remove(&input_dev->destroy_listener.link); - // 释放内存 free(input_dev); } @@ -3855,8 +3992,9 @@ void focusclient(Client *c, int32_t lift) { return; /* Raise client in stacking order if requested */ - if (c && lift) - wlr_scene_node_raise_to_top(&c->scene->node); // 将视图提升到顶层 + if (c && lift) { + client_raise_group(c); + } if (c && client_surface(c) == old_keyboard_focus_surface && selmon && selmon->sel) @@ -3877,6 +4015,7 @@ void focusclient(Client *c, int32_t lift) { c->isfocusing = true; check_keep_idle_inhibit(c); + check_vrr_enable(c); if (last_focus_client && !last_focus_client->iskilling && last_focus_client != c) { @@ -3956,8 +4095,9 @@ void focusclient(Client *c, int32_t lift) { selmon->sel = NULL; // clear text input focus state - dwl_im_relay_set_focus(dwl_input_method_relay, NULL); + mango_im_relay_set_focus(mango_input_method_relay, NULL); wlr_seat_keyboard_notify_clear_focus(seat); + check_vrr_enable(c); if (active_constraint) { cursorconstrain(NULL); } @@ -3970,7 +4110,7 @@ void focusclient(Client *c, int32_t lift) { // set text input focus // must before client_notify_enter, // otherwise the position of text_input will be wrong. - dwl_im_relay_set_focus(dwl_input_method_relay, client_surface(c)); + mango_im_relay_set_focus(mango_input_method_relay, client_surface(c)); /* Have a client, so focus its top-level wlr_surface */ client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat)); @@ -4007,6 +4147,7 @@ void requestmonstate(struct wl_listener *listener, void *data) { const struct wlr_output_event_request_state *event = data; if (event->state->committed == WLR_OUTPUT_STATE_MODE) { + switch (event->state->mode_type) { case WLR_OUTPUT_STATE_MODE_FIXED: wlr_output_state_set_mode(&m->pending, event->state->mode); @@ -4333,7 +4474,7 @@ void keypress(struct wl_listener *listener, void *data) { if (hit_global) { return; } - if (!dwl_im_keyboard_grab_forward_key(group, event)) { + if (!mango_im_keyboard_grab_forward_key(group, event)) { wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); /* Pass unhandled keycodes along to the client. */ wlr_seat_keyboard_notify_key(seat, event->time_msec, event->keycode, @@ -4346,7 +4487,7 @@ void keypressmod(struct wl_listener *listener, void *data) { * pressed. We simply communicate this to the client. */ KeyboardGroup *group = wl_container_of(listener, group, modifiers); - if (!dwl_im_keyboard_grab_forward_modifiers(group)) { + if (!mango_im_keyboard_grab_forward_modifiers(group)) { wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); /* Send modifiers to the client. */ @@ -4410,24 +4551,23 @@ static void iter_xdg_scene_buffers(struct wlr_scene_buffer *buffer, int32_t sx, return; if (config.blur && c && !c->noblur) { - wlr_scene_buffer_set_backdrop_blur(buffer, true); - wlr_scene_buffer_set_backdrop_blur_ignore_transparent(buffer, false); if (config.blur_optimized) { - wlr_scene_buffer_set_backdrop_blur_optimized(buffer, true); + wlr_scene_blur_set_should_only_blur_bottom_layer(c->blur, true); } else { - wlr_scene_buffer_set_backdrop_blur_optimized(buffer, false); + wlr_scene_blur_set_should_only_blur_bottom_layer(c->blur, false); } - } else { - wlr_scene_buffer_set_backdrop_blur(buffer, false); } } void init_client_properties(Client *c) { + c->is_logic_hide = false; + c->isgroupfocusing = false; + c->group_prev = NULL; + c->group_next = NULL; c->grid_col_per = 1.0f; c->grid_row_per = 1.0f; - c->is_monocle_hide = false; c->jump_label_node = NULL; - c->tab_bar_node = NULL; + c->group_bar = NULL; c->overview_scene_surface = NULL; c->drop_direction = UNDIR; c->enable_drop_area_draw = false; @@ -4445,8 +4585,8 @@ void init_client_properties(Client *c) { c->overview_ismaximizescreenbak = 0; c->overview_isfloatingbak = 0; c->pid = 0; + c->swallowdby = NULL; c->swallowing = NULL; - c->swallowedby = NULL; c->ismaster = 0; c->old_ismaster = 0; c->isleftstack = 0; @@ -4501,6 +4641,7 @@ void init_client_properties(Client *c) { c->force_tearing = 0; c->allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; c->idleinhibit_when_focus = 0; + c->vrr_only_fullscreen = 0; c->scroller_proportion_single = 0.0f; c->float_geom.width = 0; c->float_geom.height = 0; @@ -4514,6 +4655,13 @@ void init_client_properties(Client *c) { sizeof(c->opacity_animation.current_border_color)); c->opacity_animation.initial_opacity = c->unfocused_opacity; c->opacity_animation.current_opacity = c->unfocused_opacity; + c->animation.tagining = false; + c->animation.running = false; + c->animation.overining = false; + c->animation.tagouting = false; + c->animation.tagouted = false; + wl_list_init(&c->link); + wl_list_init(&c->flink); } void // old fix to 0.5 @@ -4556,6 +4704,18 @@ mapnotify(struct wl_listener *listener, void *data) { c->geom.height += 2 * c->bw; c->overview_backup_geom = c->geom; + struct wlr_ext_foreign_toplevel_handle_v1_state foreign_toplevel_state = { + .app_id = client_get_appid(c), + .title = client_get_title(c), + }; + + c->image_capture_scene = wlr_scene_create(); + c->ext_foreign_toplevel = wlr_ext_foreign_toplevel_handle_v1_create( + foreign_toplevel_list, &foreign_toplevel_state); + c->ext_foreign_toplevel->data = c; + c->image_capture_scene_surface = wlr_scene_surface_create( + &c->image_capture_scene->tree, client_surface(c)); + /* Handle unmanaged clients first so we can return prior create borders */ #ifdef XWAYLAND @@ -4587,6 +4747,8 @@ mapnotify(struct wl_listener *listener, void *data) { wlr_scene_node_set_enabled(&c->splitindicator[i]->node, false); } + client_add_group_bar(c); + c->droparea = wlr_scene_rect_create(c->scene, 0, 0, config.dropcolor); wlr_scene_node_lower_to_bottom(&c->droparea->node); wlr_scene_node_set_position(&c->droparea->node, 0, 0); @@ -4596,17 +4758,26 @@ mapnotify(struct wl_listener *listener, void *data) { c->scene, 0, 0, c->isurgent ? config.urgentcolor : config.bordercolor); wlr_scene_node_lower_to_bottom(&c->border->node); wlr_scene_node_set_position(&c->border->node, 0, 0); - wlr_scene_rect_set_corner_radius(c->border, config.border_radius, - config.border_radius_location_default); + wlr_scene_rect_set_corner_radii(c->border, + corner_radii_all(config.border_radius)); wlr_scene_node_set_enabled(&c->border->node, true); c->shadow = wlr_scene_shadow_create(c->scene, 0, 0, config.border_radius, config.shadows_blur, config.shadowscolor); + c->blur = wlr_scene_blur_create(c->scene, 0, 0); + wlr_scene_node_lower_to_bottom(&c->blur->node); + wlr_scene_node_lower_to_bottom(&c->shadow->node); wlr_scene_node_set_enabled(&c->shadow->node, true); + c->shield = + wlr_scene_rect_create(c->scene, 0, 0, (float[4]){0, 0, 0, 0xff}); + c->shield->node.data = c; + wlr_scene_node_lower_to_bottom(&c->shield->node); + wlr_scene_node_set_enabled(&c->shield->node, false); + if (config.new_is_master && selmon && !is_scroller_layout(selmon)) // tile at the top wl_list_insert(&clients, &c->link); // 新窗口是master,头部入栈 @@ -4831,7 +5002,7 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, } /* Find the client under the pointer and send the event along. */ - xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy); + xytonode(cursor->x, cursor->y, &surface, &c, NULL, NULL, &sx, &sy); if (cursor_mode == CurPressed && !seat->drag && surface != seat->pointer_state.focused_surface && @@ -4952,6 +5123,29 @@ void outputmgrapply(struct wl_listener *listener, void *data) { outputmgrapplyortest(config, 0); } +static void +handle_new_foreign_toplevel_capture_request(struct wl_listener *listener, + void *data) { + struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request + *request = data; + Client *c = request->toplevel_handle->data; + + if (c->shield_when_capture) + return; + + if (c->image_capture_source == NULL) { + c->image_capture_source = + wlr_ext_image_capture_source_v1_create_with_scene_node( + &c->image_capture_scene->tree.node, event_loop, alloc, drw); + if (c->image_capture_source == NULL) { + return; + } + } + + wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request_accept( + request, c->image_capture_source); +} + void // 0.7 custom outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int32_t test) { /* @@ -4970,7 +5164,7 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int32_t test) { /* Ensure displays previously disabled by * wlr-output-power-management-v1 are properly handled*/ - m->asleep = 0; + m->only_sleep = 0; wlr_output_state_init(&state); wlr_output_state_set_enabled(&state, config_head->state.enabled); @@ -4987,8 +5181,12 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int32_t test) { wlr_output_state_set_transform(&state, config_head->state.transform); wlr_output_state_set_scale(&state, config_head->state.scale); - wlr_output_state_set_adaptive_sync_enabled( - &state, config_head->state.adaptive_sync_enabled); + + if (config_head->state.adaptive_sync_enabled) { + enable_adaptive_sync(m, &state); + } else { + disable_adaptive_sync(m, &state); + } apply_or_test: ok &= test ? wlr_output_test_state(wlr_output, &state) @@ -5060,18 +5258,63 @@ void printstatus(enum ipc_watch_type type) { wl_signal_emit(&mango_print_status, &type); } +// 会话销毁时的回调 +void handle_session_destroy(struct wl_listener *listener, void *data) { + struct capture_session_tracker *tracker = + wl_container_of(listener, tracker, session_destroy); + active_capture_count--; + wl_list_remove(&tracker->session_destroy.link); + + Client *c = NULL; + wl_list_for_each(c, &clients, link) { + if (c->shield_when_capture && !c->iskilling && VISIBLEON(c, c->mon)) { + arrange(c->mon, false, false); + } + } + + wlr_log(WLR_DEBUG, "Capture session ended, active count: %d", + active_capture_count); + free(tracker); +} + +// 新会话创建时的回调 +void handle_iamge_copy_capture_new_session(struct wl_listener *listener, + void *data) { + struct wlr_ext_image_copy_capture_session_v1 *session = data; + + struct capture_session_tracker *tracker = calloc(1, sizeof(*tracker)); + if (!tracker) { + wlr_log(WLR_ERROR, "Failed to allocate capture session tracker"); + return; + } + tracker->session = session; + tracker->session_destroy.notify = handle_session_destroy; + // 监听会话的 destroy 信号,以便在会话结束时减少计数 + wl_signal_add(&session->events.destroy, &tracker->session_destroy); + + active_capture_count++; + + Client *c = NULL; + wl_list_for_each(c, &clients, link) { + if (c->shield_when_capture && !c->iskilling && VISIBLEON(c, c->mon)) { + arrange(c->mon, false, false); + } + } + + wlr_log(WLR_DEBUG, "New capture session started, active count: %d", + active_capture_count); +} + void powermgrsetmode(struct wl_listener *listener, void *data) { struct wlr_output_power_v1_set_mode_event *event = data; - struct wlr_output_state state = {0}; Monitor *m = event->output->data; if (!m) return; - wlr_output_state_set_enabled(&state, event->mode); - wlr_output_commit_state(m->wlr_output, &state); - - m->asleep = !event->mode; + wlr_output_state_set_enabled(&m->pending, event->mode); + mango_output_commit(m); + m->only_sleep = !event->mode; updatemons(NULL, NULL); } @@ -5127,7 +5370,6 @@ void rendermon(struct wl_listener *listener, void *data) { LayerSurface *l = NULL, *tmpl = NULL; int32_t i; struct wl_list *layer_list; - bool frame_allow_tearing = false; struct timespec now; bool need_more_frames = false; @@ -5138,8 +5380,6 @@ void rendermon(struct wl_listener *listener, void *data) { if (!m->wlr_output->enabled || !allow_frame_scheduling) return; - frame_allow_tearing = check_tearing_frame_allow(m); - // 绘制层和淡出效果 for (i = 0; i < LENGTH(m->layers); i++) { layer_list = &m->layers[i]; @@ -5149,6 +5389,9 @@ void rendermon(struct wl_listener *listener, void *data) { } wl_list_for_each_safe(c, tmp, &fadeout_clients, fadeout_link) { + if (c->is_logic_hide) + continue; + need_more_frames = client_draw_fadeout_frame(c) || need_more_frames; } @@ -5158,6 +5401,9 @@ void rendermon(struct wl_listener *listener, void *data) { // 绘制客户端 wl_list_for_each(c, &clients, link) { + if (c->is_logic_hide) + continue; + need_more_frames = client_draw_frame(c) || need_more_frames; if (!config.animations && !grabc && c->configure_serial && client_is_rendered_on_mon(c, m)) { @@ -5170,12 +5416,7 @@ void rendermon(struct wl_listener *listener, void *data) { monitor_stop_skip_frame_timer(m); } - // 只有在需要帧时才构建和提交状态 - if (config.allow_tearing && frame_allow_tearing) { - apply_tear_state(m); - } else { - wlr_scene_output_commit(m->scene_output, NULL); - } + mango_scene_output_commit(m->scene_output, &m->pending); skip: // 发送帧完成通知 @@ -5307,8 +5548,6 @@ cleanup: void // 17 run(char *startup_cmd) { - set_env(); - /* Add a Unix socket to the Wayland display. */ const char *socket = wl_display_add_socket_auto(dpy); if (!socket) @@ -5481,13 +5720,10 @@ setfloating(Client *c, int32_t floating) { } } - if (c->isoverlay) { - wlr_scene_node_reparent(&c->scene->node, layers[LyrOverlay]); - } else if (client_should_overtop(c) && c->isfloating) { - wlr_scene_node_reparent(&c->scene->node, layers[LyrTop]); - } else { - wlr_scene_node_reparent(&c->scene->node, - layers[c->isfloating ? LyrTop : LyrTile]); + client_reparent_group(c); + + if (c->isfloating) { + set_size_per(c->mon, c); } if (!c->force_fakemaximize) @@ -5512,11 +5748,18 @@ setfloating(Client *c, int32_t floating) { } void reset_maximizescreen_size(Client *c) { - c->geom.x = c->mon->w.x + config.gappoh; - c->geom.y = c->mon->w.y + config.gappov; - c->geom.width = c->mon->w.width - 2 * config.gappoh; - c->geom.height = c->mon->w.height - 2 * config.gappov; - resize(c, c->geom, 0); + struct wlr_box geom; + geom.x = c->mon->w.x + config.gappoh; + geom.y = c->mon->w.y + config.gappov; + geom.width = c->mon->w.width - 2 * config.gappoh; + geom.height = c->mon->w.height - 2 * config.gappov; + + if (c->group_next || c->group_prev) { + geom.height -= config.group_bar_height; + geom.y += config.group_bar_height; + } + + resize(c, geom, 0); } void exit_scroller_stack(Client *c) { @@ -5529,7 +5772,7 @@ void exit_scroller_stack(Client *c) { struct ScrollerStackNode *n = find_scroller_node(st, c); if (n) { scroller_node_remove(st, n); - return; /* 节点已移除,客户端指针已在函数内清空 */ + return; } } } @@ -5557,6 +5800,12 @@ void setmaximizescreen(Client *c, int32_t maximizescreen, bool rearrange) { maximizescreen_box.y = c->mon->w.y + config.gappov; maximizescreen_box.width = c->mon->w.width - 2 * config.gappoh; maximizescreen_box.height = c->mon->w.height - 2 * config.gappov; + + if (c->group_next || c->group_prev) { + maximizescreen_box.height -= config.group_bar_height; + maximizescreen_box.y += config.group_bar_height; + } + wlr_scene_node_raise_to_top(&c->scene->node); if (!is_scroller_layout(c->mon) || c->isfloating) resize(c, maximizescreen_box, 0); @@ -5566,8 +5815,7 @@ void setmaximizescreen(Client *c, int32_t maximizescreen, bool rearrange) { setfloating(c, 1); } - wlr_scene_node_reparent(&c->scene->node, - layers[c->isfloating ? LyrTop : LyrTile]); + client_reparent_group(c); if (!c->force_fakemaximize && !c->ismaximizescreen) { client_set_maximized(c, false); @@ -5627,15 +5875,8 @@ void setfullscreen(Client *c, int32_t fullscreen, setfloating(c, 1); } - if (c->isoverlay) { - wlr_scene_node_reparent(&c->scene->node, layers[LyrOverlay]); - } else if (client_should_overtop(c) && c->isfloating) { - wlr_scene_node_reparent(&c->scene->node, layers[LyrTop]); - } else { - wlr_scene_node_reparent( - &c->scene->node, - layers[fullscreen || c->isfloating ? LyrTop : LyrTile]); - } + client_reparent_group(c); + check_vrr_enable(c); if (rearrange) arrange(c->mon, false, false); @@ -5888,8 +6129,7 @@ void handle_print_status(struct wl_listener *listener, void *data) { ipc_notify_last_surface_ws_name(m); } - dwl_ext_workspace_printstatus(m); - dwl_ipc_output_printstatus(m); + mango_ext_workspace_printstatus(m); } } @@ -5904,6 +6144,8 @@ void setup(void) { } init_baked_points(); + set_env(); + int32_t drm_fd, i; int32_t sig[] = {SIGCHLD, SIGINT, SIGTERM}; // 不设置SIGPIPE,因为ipc发送失败不应该影响主程序 @@ -5958,6 +6200,48 @@ void setup(void) { if (!(drw = fx_renderer_create(backend))) die("couldn't create renderer"); + if (drw->features.input_color_transform) { + const enum wp_color_manager_v1_render_intent render_intents[] = { + WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL, + }; + size_t transfer_functions_len = 0; + enum wp_color_manager_v1_transfer_function *transfer_functions = + wlr_color_manager_v1_transfer_function_list_from_renderer( + drw, &transfer_functions_len); + + size_t primaries_len = 0; + enum wp_color_manager_v1_primaries *primaries = + wlr_color_manager_v1_primaries_list_from_renderer(drw, + &primaries_len); + + struct wlr_color_manager_v1 *cm = wlr_color_manager_v1_create( + dpy, 2, + &(struct wlr_color_manager_v1_options){ + .features = + { + .parametric = true, + .set_mastering_display_primaries = true, + }, + .render_intents = render_intents, + .render_intents_len = ARRAY_SIZE(render_intents), + .transfer_functions = transfer_functions, + .transfer_functions_len = transfer_functions_len, + .primaries = primaries, + .primaries_len = primaries_len, + }); + + free(transfer_functions); + free(primaries); + + if (cm) { + wlr_scene_set_color_manager_v1(scene, cm); + } else { + wlr_log(WLR_ERROR, "unable to create color manager"); + } + } + + wlr_color_representation_manager_v1_create_with_renderer(dpy, 1, drw); + wl_signal_add(&drw->events.lost, &gpu_reset); /* Create shm, drm and linux_dmabuf interfaces by ourselves. @@ -6002,11 +6286,17 @@ void setup(void) { wlr_subcompositor_create(dpy); wlr_alpha_modifier_v1_create(dpy); wlr_ext_data_control_manager_v1_create(dpy, 1); + wlr_fixes_create(dpy, 1); // 在 setup 函数中 wl_signal_init(&mango_print_status); wl_signal_add(&mango_print_status, &print_status_listener); + ext_image_copy_capture_mgr = + wlr_ext_image_copy_capture_manager_v1_create(dpy, 1); + wl_signal_add(&ext_image_copy_capture_mgr->events.new_session, + &ext_image_copy_capture_mgr_new_session); + /* Initializes the interface used to implement urgency hints */ activation = wlr_xdg_activation_v1_create(dpy); wl_signal_add(&activation->events.request_activate, &request_activate); @@ -6017,6 +6307,15 @@ void setup(void) { power_mgr = wlr_output_power_manager_v1_create(dpy); wl_signal_add(&power_mgr->events.set_mode, &output_power_mgr_set_mode); + foreign_toplevel_list = wlr_ext_foreign_toplevel_list_v1_create(dpy, 1); + ext_foreign_toplevel_image_capture_source_manager_v1 = + wlr_ext_foreign_toplevel_image_capture_source_manager_v1_create(dpy, 1); + new_foreign_toplevel_capture_request.notify = + handle_new_foreign_toplevel_capture_request; + wl_signal_add(&ext_foreign_toplevel_image_capture_source_manager_v1->events + .new_request, + &new_foreign_toplevel_capture_request); + tearing_control = wlr_tearing_control_manager_v1_create(dpy, 1); tearing_new_object.notify = handle_tearing_new_object; wl_signal_add(&tearing_control->events.new_object, &tearing_new_object); @@ -6185,7 +6484,7 @@ void setup(void) { input_method_manager = wlr_input_method_manager_v2_create(dpy); text_input_manager = wlr_text_input_manager_v3_create(dpy); - dwl_input_method_relay = dwl_im_relay_create(); + mango_input_method_relay = mango_im_relay_create(); drm_lease_manager = wlr_drm_lease_v1_manager_create(dpy, backend); if (drm_lease_manager) { @@ -6195,9 +6494,6 @@ void setup(void) { wlr_log(WLR_INFO, "VR will not be available."); } - wl_global_create(dpy, &zdwl_ipc_manager_v2_interface, 2, NULL, - dwl_ipc_manager_bind); - // 创建顶层管理句柄 foreign_toplevel_manager = wlr_foreign_toplevel_manager_v1_create(dpy); struct wlr_xdg_foreign_registry *foreign_registry = @@ -6414,6 +6710,39 @@ void check_keep_idle_inhibit(Client *c) { } } +void check_vrr_enable(Client *c) { + + Monitor *m = c && c->mon ? c->mon : selmon; + + if (!m) + return; + + if (!c && m && !m->iscleanuping && m->is_vrr_opening && + !m->vrr_global_enable) { + disable_adaptive_sync(m, &m->pending); + mango_output_commit(m); + return; + } + + if (!c) + return; + + if (VISIBLEON(c, c->mon) && c->vrr_only_fullscreen && c->isfullscreen && + !c->mon->is_vrr_opening) { + enable_adaptive_sync(c->mon, &m->pending); + mango_output_commit(m); + return; + } + + if (!c->mon->is_vrr_opening && c->mon->vrr_global_enable) { + enable_adaptive_sync(c->mon, &m->pending); + mango_output_commit(m); + } else if (c->mon->is_vrr_opening && !c->mon->vrr_global_enable) { + disable_adaptive_sync(c->mon, &m->pending); + mango_output_commit(m); + } +} + int32_t keep_idle_inhibit(void *data) { if (!idle_inhibit_mgr) { @@ -6490,9 +6819,14 @@ void unmapnotify(struct wl_listener *listener, void *data) { // If the client is in a stack, remove it from the stack - if (c->swallowedby) { - c->swallowedby->mon = c->mon; - swallow(c->swallowedby, c); + if (c->swallowing) { + c->swallowing->mon = c->mon; + client_replace(c->swallowing, c, false, true); + } else if ((c->group_next || c->group_prev) && c->isgroupfocusing) { + Client *group_replacement = + c->group_next ? c->group_next : c->group_prev; + group_replacement->mon = c->mon; + client_replace(group_replacement, c, false, false); } else { scroller_remove_client(c); dwindle_remove_client(c); @@ -6520,9 +6854,9 @@ void unmapnotify(struct wl_listener *listener, void *data) { } if (c->mon && c->mon == selmon) { - if (next_node && !c->swallowedby) { + if (next_node && !c->swallowing) { nextfocus = next_node->client; - } else if (prev_node && !c->swallowedby) { + } else if (prev_node && !c->swallowing) { nextfocus = prev_node->client; } else { nextfocus = focustop(selmon); @@ -6541,7 +6875,11 @@ void unmapnotify(struct wl_listener *listener, void *data) { if (client_is_unmanaged(c)) { #ifdef XWAYLAND if (client_is_x11(c)) { - wl_list_remove(&c->set_geometry.link); + if (c->set_geometry.link.prev && c->set_geometry.link.next && + c->set_geometry.link.prev != &c->set_geometry.link) { + wl_list_remove(&c->set_geometry.link); + wl_list_init(&c->set_geometry.link); + } } #endif if (c == exclusive_focus) @@ -6549,11 +6887,12 @@ void unmapnotify(struct wl_listener *listener, void *data) { if (client_surface(c) == seat->keyboard_state.focused_surface) focusclient(focustop(selmon), 1); } else { - if (!c->swallowing) - wl_list_remove(&c->link); + + client_group_detach(c); + + wl_list_remove(&c->link); setmon(c, NULL, 0, true); - if (!c->swallowing) - wl_list_remove(&c->flink); + wl_list_remove(&c->flink); } if (c->foreign_toplevel) { @@ -6561,29 +6900,45 @@ void unmapnotify(struct wl_listener *listener, void *data) { c->foreign_toplevel = NULL; } - if (c->swallowedby) { - setmaximizescreen(c->swallowedby, c->ismaximizescreen, true); - setfullscreen(c->swallowedby, c->isfullscreen, true); - c->swallowedby->swallowing = NULL; - c->swallowedby = NULL; + if (c->ext_foreign_toplevel) { + wlr_ext_foreign_toplevel_handle_v1_destroy(c->ext_foreign_toplevel); + c->ext_foreign_toplevel = NULL; } if (c->swallowing) { - c->swallowing->swallowedby = NULL; + setmaximizescreen(c->swallowing, c->ismaximizescreen, true); + setfullscreen(c->swallowing, c->isfullscreen, true); + c->swallowing->swallowdby = NULL; c->swallowing = NULL; } - c->stack_proportion = 0.0f; + if (c->swallowdby) { + c->swallowdby->swallowing = NULL; + c->swallowdby = NULL; + } if (c->jump_label_node) { mango_jump_label_node_destroy(c->jump_label_node); c->jump_label_node = NULL; } - if (c->tab_bar_node) { - mango_tab_bar_node_destroy(c->tab_bar_node); - c->tab_bar_node = NULL; + + if (c->group_bar) { + mango_group_bar_destroy(c->group_bar); + c->group_bar = NULL; } + if (c->image_capture_tree) { + wlr_scene_node_destroy(&c->image_capture_tree->node); + c->image_capture_tree = NULL; + } + if (c->image_capture_scene) { + wlr_scene_node_destroy(&c->image_capture_scene->tree.node); + c->image_capture_scene = NULL; + } + + c->image_capture_source = NULL; + init_client_properties(c); + wlr_scene_node_destroy(&c->scene->node); printstatus(IPC_WATCH_ARRANGGE); motionnotify(0, NULL, 0, 0, 0, 0); @@ -6606,14 +6961,19 @@ void updatemons(struct wl_listener *listener, void *data) { /* First remove from the layout the disabled monitors */ wl_list_for_each(m, &mons, link) { - if (m->wlr_output->enabled || m->asleep) + if (m->wlr_output->enabled) continue; config_head = wlr_output_configuration_head_v1_create(output_config, m->wlr_output); config_head->state.enabled = 0; + + if (m->only_sleep) { + continue; + } /* Remove this output from the layout to avoid cursor enter inside * it */ wlr_output_layout_remove(output_layout, m->wlr_output); + closemon(m); m->m = m->w = (struct wlr_box){0}; } @@ -6736,9 +7096,18 @@ void updatetitle(struct wl_listener *listener, void *data) { const char *title; title = client_get_title(c); - mango_tab_bar_node_update(c->tab_bar_node, title, 1.0); + mango_group_bar_update(c->group_bar, title, + c->mon ? c->mon->wlr_output->scale : 1.0f); if (title && c->foreign_toplevel) wlr_foreign_toplevel_handle_v1_set_title(c->foreign_toplevel, title); + if (title && c->ext_foreign_toplevel) { + wlr_ext_foreign_toplevel_handle_v1_update_state( + c->ext_foreign_toplevel, + &(struct wlr_ext_foreign_toplevel_handle_v1_state){ + .title = title, + .app_id = c->ext_foreign_toplevel->app_id, + }); + } if (c == focustop(c->mon)) printstatus(IPC_WATCH_ARRANGGE); } @@ -6959,7 +7328,7 @@ void activatex11(struct wl_listener *listener, void *data) { if (!c || c->iskilling || !c->foreign_toplevel || client_is_unmanaged(c)) return; - if (c && c->swallowing) + if (c && c->swallowdby) return; if (c->isminimized) { @@ -7109,11 +7478,13 @@ void xwaylandready(struct wl_listener *listener, void *data) { wlr_xwayland_set_seat(xwayland, seat); /* Set the default XWayland cursor to match the rest of dwl. */ - if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "default", 1))) - wlr_xwayland_set_cursor( - xwayland, xcursor->images[0]->buffer, xcursor->images[0]->width * 4, - xcursor->images[0]->width, xcursor->images[0]->height, - xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y); + if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "default", 1))) { + struct wlr_xcursor_image *image = xcursor->images[0]; + struct wlr_buffer *buffer = wlr_xcursor_image_get_buffer(image); + wlr_xwayland_set_cursor(xwayland, buffer, xcursor->images[0]->hotspot_x, + xcursor->images[0]->hotspot_y); + } + /* xwayland can't auto sync the keymap, so we do it manually and we need to wait the xwayland completely inited */