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
*/