Merge pull request #2 from bnema/feat/client-protocol-coverage
feat(protocol): expand Wayland client bindings and remove numeric allocations
127 files · +26285 -284
A LICENSES/LGPL-2.1-or-later.txt +176 -0
| @@ -0,0 +1,176 @@ | |||
| 1 | + | GNU LESSER GENERAL PUBLIC LICENSE | |
| 2 | + | ||
| 3 | + | Version 2.1, February 1999 | |
| 4 | + | ||
| 5 | + | Copyright (C) 1991, 1999 Free Software Foundation, Inc. | |
| 6 | + | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
| 7 | + | ||
| 8 | + | Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. | |
| 9 | + | ||
| 10 | + | [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] | |
| 11 | + | ||
| 12 | + | Preamble | |
| 13 | + | ||
| 14 | + | The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. | |
| 15 | + | ||
| 16 | + | This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. | |
| 17 | + | ||
| 18 | + | When we speak of free software, we are referring to freedom of use, 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 this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. | |
| 19 | + | ||
| 20 | + | To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. | |
| 21 | + | ||
| 22 | + | For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. | |
| 23 | + | ||
| 24 | + | We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. | |
| 25 | + | ||
| 26 | + | To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. | |
| 27 | + | ||
| 28 | + | Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. | |
| 29 | + | ||
| 30 | + | Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. | |
| 31 | + | ||
| 32 | + | When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. | |
| 33 | + | ||
| 34 | + | We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. | |
| 35 | + | ||
| 36 | + | For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. | |
| 37 | + | ||
| 38 | + | In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. | |
| 39 | + | ||
| 40 | + | Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. | |
| 41 | + | ||
| 42 | + | The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. | |
| 43 | + | ||
| 44 | + | GNU LESSER GENERAL PUBLIC LICENSE | |
| 45 | + | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |
| 46 | + | ||
| 47 | + | 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". | |
| 48 | + | ||
| 49 | + | A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. | |
| 50 | + | ||
| 51 | + | The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) | |
| 52 | + | ||
| 53 | + | "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. | |
| 54 | + | ||
| 55 | + | Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. | |
| 56 | + | ||
| 57 | + | 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. | |
| 58 | + | ||
| 59 | + | You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. | |
| 60 | + | ||
| 61 | + | 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: | |
| 62 | + | ||
| 63 | + | a) The modified work must itself be a software library. | |
| 64 | + | ||
| 65 | + | b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. | |
| 66 | + | ||
| 67 | + | c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. | |
| 68 | + | ||
| 69 | + | d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. | |
| 70 | + | ||
| 71 | + | (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) | |
| 72 | + | ||
| 73 | + | These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. | |
| 74 | + | ||
| 75 | + | Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. | |
| 76 | + | ||
| 77 | + | In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. | |
| 78 | + | ||
| 79 | + | 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. | |
| 80 | + | ||
| 81 | + | Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. | |
| 82 | + | ||
| 83 | + | This option is useful when you wish to copy part of the code of the Library into a program that is not a library. | |
| 84 | + | ||
| 85 | + | 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. | |
| 86 | + | ||
| 87 | + | If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. | |
| 88 | + | ||
| 89 | + | 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. | |
| 90 | + | ||
| 91 | + | However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. | |
| 92 | + | ||
| 93 | + | When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. | |
| 94 | + | ||
| 95 | + | If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) | |
| 96 | + | ||
| 97 | + | Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. | |
| 98 | + | ||
| 99 | + | 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. | |
| 100 | + | ||
| 101 | + | You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: | |
| 102 | + | ||
| 103 | + | a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) | |
| 104 | + | ||
| 105 | + | b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. | |
| 106 | + | ||
| 107 | + | c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. | |
| 108 | + | ||
| 109 | + | d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. | |
| 110 | + | ||
| 111 | + | e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. | |
| 112 | + | ||
| 113 | + | For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. | |
| 114 | + | ||
| 115 | + | It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. | |
| 116 | + | ||
| 117 | + | 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: | |
| 118 | + | ||
| 119 | + | a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. | |
| 120 | + | ||
| 121 | + | b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. | |
| 122 | + | ||
| 123 | + | 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. | |
| 124 | + | ||
| 125 | + | 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. | |
| 126 | + | ||
| 127 | + | 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. | |
| 128 | + | ||
| 129 | + | 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. | |
| 130 | + | ||
| 131 | + | If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. | |
| 132 | + | ||
| 133 | + | It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. | |
| 134 | + | ||
| 135 | + | This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. | |
| 136 | + | ||
| 137 | + | 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. | |
| 138 | + | ||
| 139 | + | 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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. | |
| 140 | + | ||
| 141 | + | Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. | |
| 142 | + | ||
| 143 | + | 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. | |
| 144 | + | ||
| 145 | + | NO WARRANTY | |
| 146 | + | ||
| 147 | + | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | |
| 148 | + | ||
| 149 | + | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | |
| 150 | + | ||
| 151 | + | END OF TERMS AND CONDITIONS | |
| 152 | + | ||
| 153 | + | How to Apply These Terms to Your New Libraries | |
| 154 | + | ||
| 155 | + | If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). | |
| 156 | + | ||
| 157 | + | To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. | |
| 158 | + | ||
| 159 | + | one line to give the library's name and an idea of what it does. | |
| 160 | + | Copyright (C) year name of author | |
| 161 | + | ||
| 162 | + | This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. | |
| 163 | + | ||
| 164 | + | This library 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 Lesser General Public License for more details. | |
| 165 | + | ||
| 166 | + | You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. | |
| 167 | + | ||
| 168 | + | You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: | |
| 169 | + | ||
| 170 | + | Yoyodyne, Inc., hereby disclaims all copyright interest in | |
| 171 | + | the library `Frob' (a library for tweaking knobs) written | |
| 172 | + | by James Random Hacker. | |
| 173 | + | ||
| 174 | + | signature of Ty Coon, 1 April 1990 | |
| 175 | + | Ty Coon, President of Vice | |
| 176 | + | That's all there is to it! | |
M README.md +43 -6
| @@ -4,7 +4,7 @@ A performance-focused Wayland client library that provides the foundational prot | |||
| 4 | 4 | ||
| 5 | 5 | ## Overview | |
| 6 | 6 | ||
| 7 | - | WLTurbo is a low-level Wayland client library that handles core protocol communication. It serves as the base layer for higher-level libraries like [libwldevices-go](https://github.com/bnema/libwldevices-go) which implement specific Wayland protocol extensions. | |
| 7 | + | WLTurbo is a low-level Wayland client library with generated core and extension bindings. Applications and higher-level libraries use it to communicate with any compositor that advertises the required protocols. | |
| 8 | 8 | ||
| 9 | 9 | ## Architecture | |
| 10 | 10 | ||
| @@ -15,11 +15,24 @@ WLTurbo provides the foundational Wayland client infrastructure: | |||
| 15 | 15 | - **Connection Management**: Unix socket communication with the compositor | |
| 16 | 16 | - **Memory Management**: Shared memory support via file descriptor passing | |
| 17 | 17 | ||
| 18 | - | Higher-level protocol implementations (virtual input devices, output management, etc.) are intentionally left to specialized libraries that build on top of WLTurbo. | |
| 18 | + | Bindings handle wire messages and object lifecycle. Applications own rendering, input interpretation, capability fallbacks and desktop policy. WLTurbo provides client bindings, not compositor-side server implementations. | |
| 19 | 19 | ||
| 20 | 20 | ## Generated protocols | |
| 21 | 21 | ||
| 22 | - | `protocol/core` provides core Wayland (including data-device); `protocol/xdgshell` provides xdg-shell; `protocol/linuxdmabuf` provides linux-dmabuf v4 feedback; `protocol/drmsyncobj` provides linux-drm-syncobj v1; `protocol/viewporter` provides viewporter; `protocol/fractionalscale` provides fractional-scale v1; and `protocol/textinput` provides text-input v3. Bindings handle wire messages and object lifecycle; applications decide compositor policy. | |
| 22 | + | Packages under `protocol/` cover: | |
| 23 | + | ||
| 24 | + | | Area | Packages | | |
| 25 | + | |---|---| | |
| 26 | + | | Core and windows | `core`, `xdgshell`, `xdgdecoration`, `xdgactivation` | | |
| 27 | + | | Buffers and scaling | `linuxdmabuf`, `drmsyncobj`, `viewporter`, `fractionalscale` | | |
| 28 | + | | Presentation and color | `presentation`, `tearingcontrol`, `fifo`, `committiming`, `contenttype`, `alphamodifier`, `colormanagement`, `colorrepresentation`, `drmlease` | | |
| 29 | + | | Input | `cursorshape`, `tablet`, `textinput`, `relativepointer`, `pointerconstraints`, `pointerwarp`, `shortcutsinhibit`, `virtualkeyboard`, `inputmethod` | | |
| 30 | + | | Clipboard | Core data-device, `primaryselection`, `datacontrol` (ext-data-control) | | |
| 31 | + | | Desktop and outputs | `layershell`, `xdgoutput`, `outputmanagement`, `outputpower`, `workspace`, `foreigntoplevel` (wlr), `extforeigntoplevel`, `kdeserverdecoration` | | |
| 32 | + | | Idle | `idleinhibit`, `idlenotify` | | |
| 33 | + | | Capture | `screencopy` (wlr), `imagecapturesource`, `imagecopycapture` | | |
| 34 | + | ||
| 35 | + | Each package contains the upstream XML, generated Go bindings and a generation command. [Protocol sources](protocol/SOURCE.md) records pinned upstream revisions and checksums. A binding's presence does not imply that the compositor implements it. | |
| 23 | 36 | ||
| 24 | 37 | After `display.Roundtrip()` discovers globals, call `display.Registry().BindNegotiated(interfaceName, supportedVersion, proxy)` to bind at the lesser of the advertised and supported versions. It returns the negotiated version; use `errors.Is(err, wlturbo.ErrGlobalNotFound)` to handle absent optional globals. | |
| 25 | 38 | ||
| @@ -29,7 +42,7 @@ After `display.Roundtrip()` discovers globals, call `display.Registry().BindNego | |||
| 29 | 42 | - **Descriptor ownership**: received FDs belong to the event that declares them and are closed if a handler does not take them. | |
| 30 | 43 | - **Object lifecycle**: destroyed objects stay as zombies until `delete_id`, so events already in flight are dropped instead of failing the connection. | |
| 31 | 44 | - **Version checks**: generated requests newer than the bound object version return `ErrVersionTooLow` before anything is sent. | |
| 32 | - | - **Allocation-free requests**: marshaling fixed-size requests does not allocate. | |
| 45 | + | - **Allocation-free numeric paths**: numeric generated requests without object creation or descriptors, and typed numeric events, do not allocate after warm-up; representative cases have allocation regression tests. Object creation, received strings and descriptors have separate allocation costs. | |
| 33 | 46 | ||
| 34 | 47 | ## Quick Start | |
| 35 | 48 | ||
| @@ -58,7 +71,27 @@ func main() { | |||
| 58 | 71 | } | |
| 59 | 72 | ``` | |
| 60 | 73 | ||
| 61 | - | For device control and input injection, use [libwldevices-go](https://github.com/bnema/libwldevices-go) which builds on top of WLTurbo. | |
| 74 | + | For higher-level device control, [libwldevices-go](https://github.com/bnema/libwldevices-go) builds on WLTurbo. | |
| 75 | + | ||
| 76 | + | ## Development checks | |
| 77 | + | ||
| 78 | + | ```sh | |
| 79 | + | GOWORK=off go generate ./... | |
| 80 | + | GOWORK=off go test ./... | |
| 81 | + | GOWORK=off go test -race ./... | |
| 82 | + | GOWORK=off go vet ./... | |
| 83 | + | GOWORK=off go test ./protocol -run '^$' -bench . -benchmem | |
| 84 | + | ``` | |
| 85 | + | ||
| 86 | + | Tests verify that checked-in bindings reproduce from the vendored XML. Socketpair tests exercise wire messages, versions, object lifecycle and file descriptors without a compositor. | |
| 87 | + | ||
| 88 | + | For isolated integration tests, build [NeferWL](https://github.com/bnema/neferwl) with its headless backend and pass its executable path: | |
| 89 | + | ||
| 90 | + | ```sh | |
| 91 | + | env GOWORK=off WLTURBO_HEADLESS=/path/to/neferwl go test ./protocol -run Headless -v -count=1 -timeout=90s | |
| 92 | + | ``` | |
| 93 | + | ||
| 94 | + | The tests start a separate compositor with temporary runtime/config directories and no terminal or Xwayland. They do not use the running desktop session. Headless tests do not validate physical display timing, DRM leasing or hardware HDR output. | |
| 62 | 95 | ||
| 63 | 96 | ## Requirements | |
| 64 | 97 | ||
| @@ -68,7 +101,11 @@ For device control and input injection, use [libwldevices-go](https://github.com | |||
| 68 | 101 | ||
| 69 | 102 | ## License | |
| 70 | 103 | ||
| 71 | - | MIT License - see LICENSE file for details | |
| 104 | + | The transport and scanner are MIT-licensed; see [LICENSE](LICENSE). | |
| 105 | + | Vendored protocol XML and generated bindings retain upstream notices and terms. | |
| 106 | + | In particular, `kdeserverdecoration` is LGPL-2.1-or-later. See | |
| 107 | + | [protocol sources](protocol/SOURCE.md), the generated file headers and the | |
| 108 | + | [included LGPL text](LICENSES/LGPL-2.1-or-later.txt). | |
| 72 | 109 | ||
| 73 | 110 | ## Contributing | |
| 74 | 111 | ||
M client.go +66 -27
| @@ -230,12 +230,14 @@ func (d *Display) SendRequest(objectID uint32, opcode uint16, args ...interface{ | |||
| 230 | 230 | ||
| 231 | 231 | // SendRequestWithFDs sends a request with file descriptors | |
| 232 | 232 | func (d *Display) SendRequestWithFDs(objectID uint32, opcode uint16, fds []int, args ...interface{}) error { | |
| 233 | - | return d.sendRequest(objectID, opcode, fds, nil, args) | |
| 233 | + | return d.sendRequest(objectID, opcode, fds, nil, args, nil) | |
| 234 | 234 | } | |
| 235 | 235 | ||
| 236 | 236 | // sendRequest marshals a request, then runs guard and writes the message | |
| 237 | 237 | // under the send lock. Guard failures and marshaling errors write nothing. | |
| 238 | - | func (d *Display) sendRequest(objectID uint32, opcode uint16, fds []int, guard func() error, args []interface{}) error { | |
| 238 | + | // The body is args (boxed, legacy path) followed by vals (typed path); a | |
| 239 | + | // caller uses one of the two. | |
| 240 | + | func (d *Display) sendRequest(objectID uint32, opcode uint16, fds []int, guard func() error, args []interface{}, vals []Arg) error { | |
| 239 | 241 | // Get buffer from pool | |
| 240 | 242 | buf := bufferPool.Get().(*bytes.Buffer) | |
| 241 | 243 | defer func() { | |
| @@ -253,6 +255,11 @@ func (d *Display) sendRequest(objectID uint32, opcode uint16, fds []int, guard f | |||
| 253 | 255 | return fmt.Errorf("failed to marshal argument: %w", err) | |
| 254 | 256 | } | |
| 255 | 257 | } | |
| 258 | + | for i := range vals { | |
| 259 | + | if err := marshalValue(buf, &vals[i]); err != nil { | |
| 260 | + | return fmt.Errorf("failed to marshal argument: %w", err) | |
| 261 | + | } | |
| 262 | + | } | |
| 256 | 263 | ||
| 257 | 264 | // Update header with actual size in bytes | |
| 258 | 265 | bufLen := buf.Len() | |
| @@ -279,6 +286,61 @@ func putUint32(buf *bytes.Buffer, v uint32) { | |||
| 279 | 286 | _, _ = buf.Write(w[:]) | |
| 280 | 287 | } | |
| 281 | 288 | ||
| 289 | + | // putString appends a wire string: length including the terminating NUL, the | |
| 290 | + | // bytes, the NUL, and padding to a 32-bit boundary. | |
| 291 | + | func putString(buf *bytes.Buffer, v string) error { | |
| 292 | + | strlen := len(v) + 1 | |
| 293 | + | if strlen > 0xffff-HeaderSize { | |
| 294 | + | return fmt.Errorf("string too long: %d bytes", strlen) | |
| 295 | + | } | |
| 296 | + | putUint32(buf, uint32(strlen)) // Safe: checked above | |
| 297 | + | _, _ = buf.WriteString(v) | |
| 298 | + | _ = buf.WriteByte(0) | |
| 299 | + | for i := (4 - (strlen % 4)) % 4; i > 0; i-- { | |
| 300 | + | _ = buf.WriteByte(0) | |
| 301 | + | } | |
| 302 | + | return nil | |
| 303 | + | } | |
| 304 | + | ||
| 305 | + | // putArray appends a wire array: length, the bytes and padding to a 32-bit | |
| 306 | + | // boundary. | |
| 307 | + | func putArray(buf *bytes.Buffer, v []byte) error { | |
| 308 | + | arrlen := len(v) | |
| 309 | + | if arrlen > 0xffff-HeaderSize { | |
| 310 | + | return fmt.Errorf("array too long: %d bytes", arrlen) | |
| 311 | + | } | |
| 312 | + | putUint32(buf, uint32(arrlen)) | |
| 313 | + | _, _ = buf.Write(v) | |
| 314 | + | for i := (4 - (arrlen % 4)) % 4; i > 0; i-- { | |
| 315 | + | _ = buf.WriteByte(0) | |
| 316 | + | } | |
| 317 | + | return nil | |
| 318 | + | } | |
| 319 | + | ||
| 320 | + | // marshalValue marshals one typed argument. It shares the string and array | |
| 321 | + | // encoders with marshalArg, so both paths produce identical bytes. | |
| 322 | + | func marshalValue(buf *bytes.Buffer, a *Arg) error { | |
| 323 | + | switch a.kind { | |
| 324 | + | case argWord: | |
| 325 | + | putUint32(buf, a.word) | |
| 326 | + | case argString: | |
| 327 | + | return putString(buf, a.str) | |
| 328 | + | case argArray: | |
| 329 | + | return putArray(buf, a.arr) | |
| 330 | + | case argObject: | |
| 331 | + | if a.obj != nil { | |
| 332 | + | putUint32(buf, a.obj.ID()) | |
| 333 | + | } else { | |
| 334 | + | putUint32(buf, 0) | |
| 335 | + | } | |
| 336 | + | case argFD: | |
| 337 | + | // Carried by SCM_RIGHTS only; no body word. | |
| 338 | + | default: | |
| 339 | + | return errors.New("unsupported argument: zero or invalid Arg") | |
| 340 | + | } | |
| 341 | + | return nil | |
| 342 | + | } | |
| 343 | + | ||
| 282 | 344 | // marshalArg marshals a single argument | |
| 283 | 345 | func (d *Display) marshalArg(buf *bytes.Buffer, arg interface{}) error { | |
| 284 | 346 | switch v := arg.(type) { | |
| @@ -289,32 +351,9 @@ func (d *Display) marshalArg(buf *bytes.Buffer, arg interface{}) error { | |||
| 289 | 351 | case Fixed: | |
| 290 | 352 | putUint32(buf, uint32(v)) | |
| 291 | 353 | case string: | |
| 292 | - | // String format: length (including null) + string + null + padding | |
| 293 | - | strlen := len(v) + 1 | |
| 294 | - | if strlen > 0xffff-HeaderSize { | |
| 295 | - | return fmt.Errorf("string too long: %d bytes", strlen) | |
| 296 | - | } | |
| 297 | - | putUint32(buf, uint32(strlen)) // Safe: checked above | |
| 298 | - | _, _ = buf.WriteString(v) | |
| 299 | - | _ = buf.WriteByte(0) | |
| 300 | - | // Pad to 32-bit boundary | |
| 301 | - | padding := (4 - (strlen % 4)) % 4 | |
| 302 | - | for i := 0; i < padding; i++ { | |
| 303 | - | _ = buf.WriteByte(0) | |
| 304 | - | } | |
| 354 | + | return putString(buf, v) | |
| 305 | 355 | case []byte: | |
| 306 | - | // Array format: length + data + padding | |
| 307 | - | arrlen := len(v) | |
| 308 | - | if arrlen > 0xffff-HeaderSize { | |
| 309 | - | return fmt.Errorf("array too long: %d bytes", arrlen) | |
| 310 | - | } | |
| 311 | - | putUint32(buf, uint32(arrlen)) | |
| 312 | - | _, _ = buf.Write(v) | |
| 313 | - | // Pad to 32-bit boundary | |
| 314 | - | padding := (4 - (arrlen % 4)) % 4 | |
| 315 | - | for i := 0; i < padding; i++ { | |
| 316 | - | _ = buf.WriteByte(0) | |
| 317 | - | } | |
| 356 | + | return putArray(buf, v) | |
| 318 | 357 | case Object: | |
| 319 | 358 | if v != nil { | |
| 320 | 359 | putUint32(buf, v.ID()) | |
M core.go +43 -11
| @@ -75,10 +75,7 @@ func (c *Context) SendRequest(proxy Proxy, opcode uint32, args ...interface{}) e | |||
| 75 | 75 | // SendRequestWithFDs sends a request with file descriptors through the context. | |
| 76 | 76 | // On error the FDs remain owned by the caller. | |
| 77 | 77 | func (c *Context) SendRequestWithFDs(proxy Proxy, opcode uint32, fds []int, args ...interface{}) error { | |
| 78 | - | if err := c.CheckProxy(proxy); err != nil { | |
| 79 | - | return err | |
| 80 | - | } | |
| 81 | - | return c.display.sendRequest(proxy.ID(), uint16(opcode), fds, func() error { return c.CheckProxy(proxy) }, args) | |
| 78 | + | return c.sendChecked(proxy, opcode, fds, c.CheckProxy, args, nil) | |
| 82 | 79 | } | |
| 83 | 80 | ||
| 84 | 81 | // CheckProxy rejects stale and foreign proxies before any bytes are written. | |
| @@ -96,7 +93,8 @@ func (c *Context) CheckProxy(proxy Proxy) error { | |||
| 96 | 93 | return nil | |
| 97 | 94 | } | |
| 98 | 95 | ||
| 99 | - | // Request describes one protocol request for Context.Request. | |
| 96 | + | // Request describes one protocol request for Context.Request and | |
| 97 | + | // Context.RequestArgs. | |
| 100 | 98 | type Request struct { | |
| 101 | 99 | Proxy Proxy | |
| 102 | 100 | Opcode uint32 | |
| @@ -112,7 +110,35 @@ type Request struct { | |||
| 112 | 110 | // sends, and then either closes the sent descriptors or, on error, | |
| 113 | 111 | // unregisters Child and leaves the descriptors with the caller. Child must | |
| 114 | 112 | // already have this context; it is passed in args at its wire position. | |
| 113 | + | // | |
| 114 | + | // Every argument is boxed into an interface, and a descriptor is a uintptr | |
| 115 | + | // placeholder that r.FDs is not checked against. Generated bindings use | |
| 116 | + | // RequestArgs instead, which marshals the same bytes without allocating. | |
| 115 | 117 | func (c *Context) Request(r Request, args ...interface{}) error { | |
| 118 | + | return c.request(r, args, nil, false) | |
| 119 | + | } | |
| 120 | + | ||
| 121 | + | // RequestArgs is Request with typed arguments: same lifecycle, same wire | |
| 122 | + | // bytes, no per-argument interface boxing. Child, when set, must be passed as | |
| 123 | + | // an ArgObject at its wire position. The number of ArgFD markers must equal | |
| 124 | + | // len(r.FDs); a mismatch fails before the child is allocated, the send guard | |
| 125 | + | // runs or anything is written, and leaves the descriptors with the caller. | |
| 126 | + | func (c *Context) RequestArgs(r Request, args ...Arg) error { | |
| 127 | + | return c.request(r, nil, args, true) | |
| 128 | + | } | |
| 129 | + | ||
| 130 | + | func (c *Context) request(r Request, args []interface{}, vals []Arg, typed bool) error { | |
| 131 | + | if typed { | |
| 132 | + | markers := 0 | |
| 133 | + | for i := range vals { | |
| 134 | + | if vals[i].kind == argFD { | |
| 135 | + | markers++ | |
| 136 | + | } | |
| 137 | + | } | |
| 138 | + | if markers != len(r.FDs) { | |
| 139 | + | return fmt.Errorf("wlturbo: %s: %d fd arguments but %d descriptors", r.Name, markers, len(r.FDs)) | |
| 140 | + | } | |
| 141 | + | } | |
| 116 | 142 | if err := c.CheckProxy(r.Proxy); err != nil { | |
| 117 | 143 | return err | |
| 118 | 144 | } | |
| @@ -132,9 +158,9 @@ func (c *Context) Request(r Request, args ...interface{}) error { | |||
| 132 | 158 | } | |
| 133 | 159 | var err error | |
| 134 | 160 | if r.Destructor { | |
| 135 | - | err = c.SendDestructorWithFDs(r.Proxy, r.Opcode, r.FDs, args...) | |
| 161 | + | err = c.sendChecked(r.Proxy, r.Opcode, r.FDs, c.claimDestroy, args, vals) | |
| 136 | 162 | } else { | |
| 137 | - | err = c.SendRequestWithFDs(r.Proxy, r.Opcode, r.FDs, args...) | |
| 163 | + | err = c.sendChecked(r.Proxy, r.Opcode, r.FDs, c.CheckProxy, args, vals) | |
| 138 | 164 | } | |
| 139 | 165 | if err != nil { | |
| 140 | 166 | if r.Child != nil { | |
| @@ -148,6 +174,15 @@ func (c *Context) Request(r Request, args ...interface{}) error { | |||
| 148 | 174 | return nil | |
| 149 | 175 | } | |
| 150 | 176 | ||
| 177 | + | // sendChecked validates the proxy, then sends with check run under the send | |
| 178 | + | // lock (CheckProxy for plain requests, claimDestroy for destructors). | |
| 179 | + | func (c *Context) sendChecked(proxy Proxy, opcode uint32, fds []int, check func(Proxy) error, args []interface{}, vals []Arg) error { | |
| 180 | + | if err := c.CheckProxy(proxy); err != nil { | |
| 181 | + | return err | |
| 182 | + | } | |
| 183 | + | return c.display.sendRequest(proxy.ID(), uint16(opcode), fds, func() error { return check(proxy) }, args, vals) | |
| 184 | + | } | |
| 185 | + | ||
| 151 | 186 | // SendDestructor sends a destructor request exactly once. The proxy is | |
| 152 | 187 | // claimed (unregistered) under the connection send lock, after marshaling | |
| 153 | 188 | // and immediately before the write: concurrent destructors and later requests | |
| @@ -161,10 +196,7 @@ func (c *Context) SendDestructor(proxy Proxy, opcode uint32, args ...interface{} | |||
| 161 | 196 | // SendDestructorWithFDs is SendDestructor for requests carrying FDs. On error | |
| 162 | 197 | // the FDs remain owned by the caller. | |
| 163 | 198 | func (c *Context) SendDestructorWithFDs(proxy Proxy, opcode uint32, fds []int, args ...interface{}) error { | |
| 164 | - | if err := c.CheckProxy(proxy); err != nil { | |
| 165 | - | return err | |
| 166 | - | } | |
| 167 | - | return c.display.sendRequest(proxy.ID(), uint16(opcode), fds, func() error { return c.claimDestroy(proxy) }, args) | |
| 199 | + | return c.sendChecked(proxy, opcode, fds, c.claimDestroy, args, nil) | |
| 168 | 200 | } | |
| 169 | 201 | ||
| 170 | 202 | func (c *Context) claimDestroy(proxy Proxy) error { | |
M docs/protocol-migration.md +11 -0
| @@ -27,3 +27,14 @@ explicit external mapping, then only bootstrap display/registry. Generate with | |||
| 27 | 27 | `GOWORK=off go generate ./...`; metadata and XML license are in | |
| 28 | 28 | `protocol/SOURCE.md`. Extension packages under `protocol/` use the same scanner | |
| 29 | 29 | and public core mappings; the generator carries no compositor policy. | |
| 30 | + | ||
| 31 | + | Generated requests use `Context.RequestArgs` with typed `Arg` values to avoid | |
| 32 | + | boxing numeric arguments. Custom proxies may use the same API; `Context.Request` | |
| 33 | + | and the raw send methods remain available. Both request APIs share version, | |
| 34 | + | child-object, destructor and descriptor lifecycle handling. Strings and arrays | |
| 35 | + | passed as arguments are borrowed until the synchronous request returns. | |
| 36 | + | ||
| 37 | + | For client code in compositor tests, replace handwritten protocol proxies with | |
| 38 | + | these generated constructors and typed handlers. Keep compositor-side server | |
| 39 | + | implementations in the compositor repository. Negotiate optional globals and | |
| 40 | + | handle their absence rather than testing the compositor's name. | |
A internal/scanner/license_test.go +53 -0
| @@ -0,0 +1,53 @@ | |||
| 1 | + | package scanner | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "crypto/sha256" | |
| 5 | + | "fmt" | |
| 6 | + | "os" | |
| 7 | + | "strings" | |
| 8 | + | "testing" | |
| 9 | + | ) | |
| 10 | + | ||
| 11 | + | func TestIncludedLGPLLicense(t *testing.T) { | |
| 12 | + | content, err := os.ReadFile("../../LICENSES/LGPL-2.1-or-later.txt") | |
| 13 | + | if err != nil { | |
| 14 | + | t.Fatal(err) | |
| 15 | + | } | |
| 16 | + | const expected = "5749785c8bdefafcb5d798270ed0a967036fe2ca63dcedade1627565dfef81d2" | |
| 17 | + | if got := fmt.Sprintf("%x", sha256.Sum256(content)); got != expected { | |
| 18 | + | t.Fatalf("LGPL text checksum %s, want %s", got, expected) | |
| 19 | + | } | |
| 20 | + | } | |
| 21 | + | ||
| 22 | + | func TestGeneratedSourceRetainsProtocolLicense(t *testing.T) { | |
| 23 | + | for _, source := range []string{ | |
| 24 | + | "../../protocol/kdeserverdecoration/server-decoration.xml", | |
| 25 | + | "../../protocol/layershell/wlr-layer-shell-unstable-v1.xml", | |
| 26 | + | "../../protocol/wayland.xml", | |
| 27 | + | } { | |
| 28 | + | t.Run(source, func(t *testing.T) { | |
| 29 | + | s := NewScanner() | |
| 30 | + | if err := s.ParseXML(source); err != nil { | |
| 31 | + | t.Fatal(err) | |
| 32 | + | } | |
| 33 | + | s.CrossPackage = map[string]string{ | |
| 34 | + | "wl_surface": "github.com/bnema/wlturbo/protocol/core", | |
| 35 | + | "wl_output": "github.com/bnema/wlturbo/protocol/core", | |
| 36 | + | "xdg_popup": "github.com/bnema/wlturbo/protocol/xdgshell", | |
| 37 | + | } | |
| 38 | + | generated, err := s.Generate("core") | |
| 39 | + | if err != nil { | |
| 40 | + | t.Fatal(err) | |
| 41 | + | } | |
| 42 | + | header, _, ok := strings.Cut(string(generated), "\npackage core") | |
| 43 | + | if !ok { | |
| 44 | + | t.Fatal("package declaration missing") | |
| 45 | + | } | |
| 46 | + | for _, line := range strings.Split(strings.TrimSpace(s.protocol.Copyright), "\n") { | |
| 47 | + | if text := strings.TrimSpace(line); text != "" && !strings.Contains(header, text) { | |
| 48 | + | t.Errorf("upstream license line missing from header: %q", text) | |
| 49 | + | } | |
| 50 | + | } | |
| 51 | + | }) | |
| 52 | + | } | |
| 53 | + | } | |
A internal/scanner/protocols_test.go +113 -0
| @@ -0,0 +1,113 @@ | |||
| 1 | + | package scanner | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "bytes" | |
| 5 | + | "os" | |
| 6 | + | "path/filepath" | |
| 7 | + | "strings" | |
| 8 | + | "testing" | |
| 9 | + | ) | |
| 10 | + | ||
| 11 | + | // Check every checked-in binding against its generation command, including | |
| 12 | + | // external type mappings. Regeneration must not depend on the host's XML files. | |
| 13 | + | func TestVendoredProtocolsReproduce(t *testing.T) { | |
| 14 | + | root := filepath.Join("..", "..", "protocol") | |
| 15 | + | referenced := make(map[string]bool) | |
| 16 | + | err := filepath.WalkDir(root, func(path string, entry os.DirEntry, err error) error { | |
| 17 | + | if err != nil { | |
| 18 | + | return err | |
| 19 | + | } | |
| 20 | + | if entry.IsDir() || entry.Name() != "generate.go" { | |
| 21 | + | return nil | |
| 22 | + | } | |
| 23 | + | content, err := os.ReadFile(path) | |
| 24 | + | if err != nil { | |
| 25 | + | return err | |
| 26 | + | } | |
| 27 | + | for _, line := range strings.Split(string(content), "\n") { | |
| 28 | + | if !strings.HasPrefix(line, "//go:generate go run ") { | |
| 29 | + | continue | |
| 30 | + | } | |
| 31 | + | fields := strings.Fields(line) | |
| 32 | + | if len(fields) < 5 || !strings.HasSuffix(fields[3], "/cmd/wlturbo-scanner") { | |
| 33 | + | t.Fatalf("%s: expected direct go run of cmd/wlturbo-scanner", path) | |
| 34 | + | } | |
| 35 | + | args := fields[4:] | |
| 36 | + | var pkg, output, input string | |
| 37 | + | imports := make(map[string]string) | |
| 38 | + | for i := 0; i < len(args); i++ { | |
| 39 | + | switch args[i] { | |
| 40 | + | case "-p", "-o", "-import": | |
| 41 | + | if i+1 == len(args) { | |
| 42 | + | t.Fatalf("%s: missing value for %s", path, args[i]) | |
| 43 | + | } | |
| 44 | + | flag, value := args[i], args[i+1] | |
| 45 | + | i++ | |
| 46 | + | switch flag { | |
| 47 | + | case "-p": | |
| 48 | + | pkg = value | |
| 49 | + | case "-o": | |
| 50 | + | output = value | |
| 51 | + | case "-import": | |
| 52 | + | iface, target, ok := strings.Cut(value, "=") | |
| 53 | + | if !ok { | |
| 54 | + | t.Fatalf("%s: invalid import %q", path, value) | |
| 55 | + | } | |
| 56 | + | imports[iface] = target | |
| 57 | + | } | |
| 58 | + | default: | |
| 59 | + | if strings.HasPrefix(args[i], "-") || input != "" { | |
| 60 | + | t.Fatalf("%s: unexpected generation argument %q", path, args[i]) | |
| 61 | + | } | |
| 62 | + | input = args[i] | |
| 63 | + | } | |
| 64 | + | } | |
| 65 | + | if pkg == "" || output == "" || input == "" { | |
| 66 | + | t.Fatalf("%s: incomplete generation command", path) | |
| 67 | + | } | |
| 68 | + | dir := filepath.Dir(path) | |
| 69 | + | xmlPath := filepath.Clean(filepath.Join(dir, input)) | |
| 70 | + | if referenced[xmlPath] { | |
| 71 | + | t.Fatalf("%s generated more than once", xmlPath) | |
| 72 | + | } | |
| 73 | + | referenced[xmlPath] = true | |
| 74 | + | t.Run(pkg, func(t *testing.T) { | |
| 75 | + | s := NewScanner() | |
| 76 | + | s.CrossPackage = imports | |
| 77 | + | if err := s.ParseXML(xmlPath); err != nil { | |
| 78 | + | t.Fatal(err) | |
| 79 | + | } | |
| 80 | + | generated, err := s.Generate(pkg) | |
| 81 | + | if err != nil { | |
| 82 | + | t.Fatal(err) | |
| 83 | + | } | |
| 84 | + | checkedIn, err := os.ReadFile(filepath.Join(dir, output)) | |
| 85 | + | if err != nil { | |
| 86 | + | t.Fatal(err) | |
| 87 | + | } | |
| 88 | + | if !bytes.Equal(generated, checkedIn) { | |
| 89 | + | t.Fatal("bindings are stale; run GOWORK=off go generate ./...") | |
| 90 | + | } | |
| 91 | + | }) | |
| 92 | + | } | |
| 93 | + | return nil | |
| 94 | + | }) | |
| 95 | + | if err != nil { | |
| 96 | + | t.Fatal(err) | |
| 97 | + | } | |
| 98 | + | if len(referenced) == 0 { | |
| 99 | + | t.Fatal("no vendored protocols found") | |
| 100 | + | } | |
| 101 | + | err = filepath.WalkDir(root, func(path string, entry os.DirEntry, err error) error { | |
| 102 | + | if err != nil { | |
| 103 | + | return err | |
| 104 | + | } | |
| 105 | + | if !entry.IsDir() && filepath.Ext(path) == ".xml" && !referenced[path] { | |
| 106 | + | t.Errorf("%s has no generation command", path) | |
| 107 | + | } | |
| 108 | + | return nil | |
| 109 | + | }) | |
| 110 | + | if err != nil { | |
| 111 | + | t.Fatal(err) | |
| 112 | + | } | |
| 113 | + | } | |
A internal/scanner/requestargs_test.go +243 -0
| @@ -0,0 +1,243 @@ | |||
| 1 | + | package scanner | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "os" | |
| 5 | + | "os/exec" | |
| 6 | + | "path/filepath" | |
| 7 | + | "strings" | |
| 8 | + | "testing" | |
| 9 | + | ) | |
| 10 | + | ||
| 11 | + | const requestArgsXML = `<protocol name="argsfix"> | |
| 12 | + | <interface name="args_obj" version="1"> | |
| 13 | + | <request name="mixed"> | |
| 14 | + | <arg name="serial" type="uint"/><arg name="dx" type="int"/><arg name="fx" type="fixed"/> | |
| 15 | + | <arg name="name" type="string"/><arg name="blob" type="array"/> | |
| 16 | + | <arg name="peer" type="object" interface="args_obj" allow-null="true"/> | |
| 17 | + | </request> | |
| 18 | + | <request name="make"><arg name="id" type="new_id" interface="args_obj"/><arg name="n" type="uint"/></request> | |
| 19 | + | <request name="give"><arg name="tag" type="string"/><arg name="fd" type="fd"/><arg name="size" type="uint"/></request> | |
| 20 | + | <request name="destroy" type="destructor"/> | |
| 21 | + | </interface></protocol>` | |
| 22 | + | ||
| 23 | + | func generateArgsFixture(t *testing.T) string { | |
| 24 | + | t.Helper() | |
| 25 | + | path := filepath.Join(t.TempDir(), "argsfix.xml") | |
| 26 | + | if err := os.WriteFile(path, []byte(requestArgsXML), 0600); err != nil { | |
| 27 | + | t.Fatal(err) | |
| 28 | + | } | |
| 29 | + | s := NewScanner() | |
| 30 | + | if err := s.ParseXML(path); err != nil { | |
| 31 | + | t.Fatal(err) | |
| 32 | + | } | |
| 33 | + | b, err := s.Generate("argsfix") | |
| 34 | + | if err != nil { | |
| 35 | + | t.Fatal(err) | |
| 36 | + | } | |
| 37 | + | return string(b) | |
| 38 | + | } | |
| 39 | + | ||
| 40 | + | // Generated requests must use typed arguments only: no interface{} boxing | |
| 41 | + | // path and no uintptr placeholder for descriptors. | |
| 42 | + | func TestGeneratedRequestsUseTypedArgs(t *testing.T) { | |
| 43 | + | text := generateArgsFixture(t) | |
| 44 | + | for _, want := range []string{ | |
| 45 | + | "RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: \"args_obj.mixed\"}, wl.ArgUint(serial), wl.ArgInt(dx), wl.ArgFixed(fx), wl.ArgString(name), wl.ArgArray(blob), wl.ArgObject(arg5))", | |
| 46 | + | "Child: child}, wl.ArgObject(child), wl.ArgUint(n))", | |
| 47 | + | "FDs: []int{fd}}, wl.ArgString(tag), wl.ArgFD(), wl.ArgUint(size))", | |
| 48 | + | "Destructor: true})", | |
| 49 | + | } { | |
| 50 | + | if !strings.Contains(text, want) { | |
| 51 | + | t.Errorf("generated code missing %q\n%s", want, text) | |
| 52 | + | } | |
| 53 | + | } | |
| 54 | + | for _, bad := range []string{".Request(wl.Request", "uintptr("} { | |
| 55 | + | if strings.Contains(text, bad) { | |
| 56 | + | t.Errorf("generated code still contains %q", bad) | |
| 57 | + | } | |
| 58 | + | } | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | // The generated requests compile against the transport, put the exact wire | |
| 62 | + | // bytes on the socket, and do not allocate for realistic numeric values. | |
| 63 | + | func TestGeneratedRequestsWireAndAllocations(t *testing.T) { | |
| 64 | + | goBin, err := exec.LookPath("go") | |
| 65 | + | if err != nil { | |
| 66 | + | t.Skip("go unavailable") | |
| 67 | + | } | |
| 68 | + | root, err := filepath.Abs("../..") | |
| 69 | + | if err != nil { | |
| 70 | + | t.Fatal(err) | |
| 71 | + | } | |
| 72 | + | dir := t.TempDir() | |
| 73 | + | write := func(name, content string) { | |
| 74 | + | if err := os.WriteFile(filepath.Join(dir, name), []byte(content), 0600); err != nil { | |
| 75 | + | t.Fatal(err) | |
| 76 | + | } | |
| 77 | + | } | |
| 78 | + | write("args.go", generateArgsFixture(t)) | |
| 79 | + | write("go.mod", "module example.com/argsfix\n\ngo 1.27\n\nrequire github.com/bnema/wlturbo v0.0.0\nreplace github.com/bnema/wlturbo => "+root+"\n") | |
| 80 | + | write("args_test.go", `package argsfix | |
| 81 | + | ||
| 82 | + | import ( | |
| 83 | + | "bytes" | |
| 84 | + | "net" | |
| 85 | + | "os" | |
| 86 | + | "testing" | |
| 87 | + | "time" | |
| 88 | + | ||
| 89 | + | "github.com/bnema/wlturbo" | |
| 90 | + | "golang.org/x/sys/unix" | |
| 91 | + | ) | |
| 92 | + | ||
| 93 | + | type sink struct{ last []byte } | |
| 94 | + | ||
| 95 | + | func (c *sink) Read([]byte) (int, error) { return 0, net.ErrClosed } | |
| 96 | + | func (c *sink) Write(p []byte) (int, error) { | |
| 97 | + | c.last = append(c.last[:0], p...) | |
| 98 | + | return len(p), nil | |
| 99 | + | } | |
| 100 | + | func (c *sink) Close() error { return nil } | |
| 101 | + | func (c *sink) LocalAddr() net.Addr { return a{} } | |
| 102 | + | func (c *sink) RemoteAddr() net.Addr { return a{} } | |
| 103 | + | func (c *sink) SetDeadline(time.Time) error { return nil } | |
| 104 | + | func (c *sink) SetReadDeadline(time.Time) error { return nil } | |
| 105 | + | func (c *sink) SetWriteDeadline(time.Time) error { return nil } | |
| 106 | + | ||
| 107 | + | type a struct{} | |
| 108 | + | ||
| 109 | + | func (a) Network() string { return "t" } | |
| 110 | + | func (a) String() string { return "t" } | |
| 111 | + | ||
| 112 | + | func setup(t testing.TB) (*wlturbo.Display, *sink, *ArgsObj) { | |
| 113 | + | c := &sink{} | |
| 114 | + | d, err := wlturbo.ConnectFromConn(c) | |
| 115 | + | if err != nil { | |
| 116 | + | t.Fatal(err) | |
| 117 | + | } | |
| 118 | + | o := NewArgsObj(d.Context()) | |
| 119 | + | o.SetID(d.AllocateID()) | |
| 120 | + | d.Context().Register(o) | |
| 121 | + | return d, c, o | |
| 122 | + | } | |
| 123 | + | ||
| 124 | + | func TestMixedWire(t *testing.T) { | |
| 125 | + | _, c, o := setup(t) | |
| 126 | + | peer := NewArgsObj(o.Context()) | |
| 127 | + | peer.SetID(0x1234) | |
| 128 | + | if err := o.Mixed(1000, -2, wlturbo.Fixed(512), "ab", []byte{9, 8, 7}, peer); err != nil { | |
| 129 | + | t.Fatal(err) | |
| 130 | + | } | |
| 131 | + | want := []byte{ | |
| 132 | + | byte(o.ID()), 0, 0, 0, 0, 0, 40, 0, | |
| 133 | + | 0xe8, 3, 0, 0, | |
| 134 | + | 0xfe, 0xff, 0xff, 0xff, | |
| 135 | + | 0, 2, 0, 0, | |
| 136 | + | 3, 0, 0, 0, 'a', 'b', 0, 0, | |
| 137 | + | 3, 0, 0, 0, 9, 8, 7, 0, | |
| 138 | + | 0x34, 0x12, 0, 0, | |
| 139 | + | } | |
| 140 | + | if !bytes.Equal(c.last, want) { | |
| 141 | + | t.Fatalf("got %x want %x", c.last, want) | |
| 142 | + | } | |
| 143 | + | if err := o.Mixed(1, 2, 3, "", nil, nil); err != nil { | |
| 144 | + | t.Fatal(err) | |
| 145 | + | } | |
| 146 | + | if got := c.last[len(c.last)-4:]; !bytes.Equal(got, []byte{0, 0, 0, 0}) { | |
| 147 | + | t.Fatalf("nil object = %x", got) | |
| 148 | + | } | |
| 149 | + | } | |
| 150 | + | ||
| 151 | + | func TestMixedAllocFree(t *testing.T) { | |
| 152 | + | _, _, o := setup(t) | |
| 153 | + | blob := []byte("blob") | |
| 154 | + | n := testing.AllocsPerRun(200, func() { | |
| 155 | + | if err := o.Mixed(123456, -70000, wlturbo.Fixed(1<<20), "hello", blob, nil); err != nil { | |
| 156 | + | t.Fatal(err) | |
| 157 | + | } | |
| 158 | + | }) | |
| 159 | + | if n != 0 { | |
| 160 | + | t.Fatalf("Mixed: %v allocs/op, want 0", n) | |
| 161 | + | } | |
| 162 | + | } | |
| 163 | + | ||
| 164 | + | func TestChildAndDestructor(t *testing.T) { | |
| 165 | + | d, c, o := setup(t) | |
| 166 | + | kid, err := o.Make(77777) | |
| 167 | + | if err != nil { | |
| 168 | + | t.Fatal(err) | |
| 169 | + | } | |
| 170 | + | if kid.ID() == 0 || c.last[8] != byte(kid.ID()) { | |
| 171 | + | t.Fatalf("child id %d not on the wire: %x", kid.ID(), c.last) | |
| 172 | + | } | |
| 173 | + | if err := o.Destroy(); err != nil { | |
| 174 | + | t.Fatal(err) | |
| 175 | + | } | |
| 176 | + | n := len(c.last) | |
| 177 | + | c.last = c.last[:0] | |
| 178 | + | if err := o.Destroy(); err == nil { | |
| 179 | + | t.Fatal("second destructor succeeded") | |
| 180 | + | } | |
| 181 | + | if len(c.last) != 0 || n == 0 { | |
| 182 | + | t.Fatal("wrote after destructor") | |
| 183 | + | } | |
| 184 | + | _ = d | |
| 185 | + | } | |
| 186 | + | ||
| 187 | + | func TestFDRequest(t *testing.T) { | |
| 188 | + | sp, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0) | |
| 189 | + | if err != nil { | |
| 190 | + | t.Fatal(err) | |
| 191 | + | } | |
| 192 | + | fa, fb := os.NewFile(uintptr(sp[0]), "a"), os.NewFile(uintptr(sp[1]), "b") | |
| 193 | + | ca, err := net.FileConn(fa) | |
| 194 | + | fa.Close() | |
| 195 | + | if err != nil { | |
| 196 | + | fb.Close() | |
| 197 | + | t.Fatal(err) | |
| 198 | + | } | |
| 199 | + | defer ca.Close() | |
| 200 | + | cb, err := net.FileConn(fb) | |
| 201 | + | fb.Close() | |
| 202 | + | if err != nil { | |
| 203 | + | t.Fatal(err) | |
| 204 | + | } | |
| 205 | + | defer cb.Close() | |
| 206 | + | d, err := wlturbo.ConnectFromConn(ca) | |
| 207 | + | if err != nil { | |
| 208 | + | t.Fatal(err) | |
| 209 | + | } | |
| 210 | + | defer d.Close() | |
| 211 | + | o := NewArgsObj(d.Context()) | |
| 212 | + | o.SetID(d.AllocateID()) | |
| 213 | + | d.Context().Register(o) | |
| 214 | + | fd, err := unix.Open(os.DevNull, unix.O_RDONLY|unix.O_CLOEXEC, 0) | |
| 215 | + | if err != nil { | |
| 216 | + | t.Fatal(err) | |
| 217 | + | } | |
| 218 | + | if err := o.Give("t", fd, 5); err != nil { | |
| 219 | + | t.Fatal(err) | |
| 220 | + | } | |
| 221 | + | if _, err := unix.FcntlInt(uintptr(fd), unix.F_GETFD, 0); err == nil { | |
| 222 | + | t.Fatal("fd not closed after send") | |
| 223 | + | } | |
| 224 | + | // The connection first sends wl_display.get_registry (12 bytes). | |
| 225 | + | buf := make([]byte, 12+8+8+4) | |
| 226 | + | oob := make([]byte, unix.CmsgSpace(4)) | |
| 227 | + | n, oobn, _, _, err := cb.(*net.UnixConn).ReadMsgUnix(buf, oob) | |
| 228 | + | if err != nil || n != len(buf) || oobn == 0 { | |
| 229 | + | t.Fatalf("n=%d oobn=%d err=%v", n, oobn, err) | |
| 230 | + | } | |
| 231 | + | // The descriptor has no body word: string(8) + uint(4) only. | |
| 232 | + | if buf[12+4] != 2 || buf[12+8+8] != 5 || buf[12+6] != 20 { | |
| 233 | + | t.Fatalf("message = %x", buf[12:]) | |
| 234 | + | } | |
| 235 | + | } | |
| 236 | + | `) | |
| 237 | + | cmd := exec.Command(goBin, "test", "./...") | |
| 238 | + | cmd.Dir = dir | |
| 239 | + | cmd.Env = append(os.Environ(), "GOWORK=off", "GOFLAGS=-mod=mod") | |
| 240 | + | if out, err := cmd.CombinedOutput(); err != nil { | |
| 241 | + | t.Fatalf("generated request test: %v\n%s", err, out) | |
| 242 | + | } | |
| 243 | + | } | |
M internal/scanner/scanner.go +26 -4
| @@ -162,6 +162,7 @@ type templateData struct { | |||
| 162 | 162 | Package string | |
| 163 | 163 | Protocol string | |
| 164 | 164 | Source string | |
| 165 | + | Copyright string | |
| 165 | 166 | ImportBlock string | |
| 166 | 167 | Constants []constantData | |
| 167 | 168 | Interfaces []interfaceData | |
| @@ -252,6 +253,15 @@ func (s *Scanner) prepareTemplateData(packageName string) (templateData, error) | |||
| 252 | 253 | Protocol: s.protocol.Name, | |
| 253 | 254 | Source: s.source, | |
| 254 | 255 | } | |
| 256 | + | if notice := strings.TrimSpace(s.protocol.Copyright); notice != "" { | |
| 257 | + | var comment strings.Builder | |
| 258 | + | for _, line := range strings.Split(notice, "\n") { | |
| 259 | + | comment.WriteString("// ") | |
| 260 | + | comment.WriteString(strings.TrimSpace(line)) | |
| 261 | + | comment.WriteByte('\n') | |
| 262 | + | } | |
| 263 | + | data.Copyright = comment.String() | |
| 264 | + | } | |
| 255 | 265 | ||
| 256 | 266 | imports := []string{TransportImport} | |
| 257 | 267 | usedCross := make(map[string]bool) | |
| @@ -449,17 +459,29 @@ func (s *Scanner) processRequest(iface Interface, req Request, opcode int) (requ | |||
| 449 | 459 | fmt.Sprintf("if %s != nil {", name), | |
| 450 | 460 | fmt.Sprintf("\t%s = %s", holder, name), | |
| 451 | 461 | "}") | |
| 452 | - | expr = holder | |
| 462 | + | expr = "wl.ArgObject(" + holder + ")" | |
| 453 | 463 | ||
| 454 | 464 | case "fd": | |
| 455 | 465 | // Descriptors travel out of band: the body carries no value for | |
| 456 | 466 | // them, and the descriptor list is attached to the request. | |
| 457 | 467 | params = append(params, name+" int") | |
| 458 | 468 | fdExprs = append(fdExprs, name) | |
| 459 | - | expr = "uintptr(" + name + ")" | |
| 469 | + | expr = "wl.ArgFD()" | |
| 460 | 470 | ||
| 461 | 471 | default: | |
| 462 | 472 | params = append(params, name+" "+goType) | |
| 473 | + | switch arg.Type { | |
| 474 | + | case "int": | |
| 475 | + | expr = "wl.ArgInt(" + name + ")" | |
| 476 | + | case "uint": | |
| 477 | + | expr = "wl.ArgUint(" + name + ")" | |
| 478 | + | case "fixed": | |
| 479 | + | expr = "wl.ArgFixed(" + name + ")" | |
| 480 | + | case "string": | |
| 481 | + | expr = "wl.ArgString(" + name + ")" | |
| 482 | + | case "array": | |
| 483 | + | expr = "wl.ArgArray(" + name + ")" | |
| 484 | + | } | |
| 463 | 485 | } | |
| 464 | 486 | ||
| 465 | 487 | argSlots = append(argSlots, argSlot{expr: expr}) | |
| @@ -479,7 +501,7 @@ func (s *Scanner) processRequest(iface Interface, req Request, opcode int) (requ | |||
| 479 | 501 | ||
| 480 | 502 | for _, slot := range argSlots { | |
| 481 | 503 | if slot.newID { | |
| 482 | - | argExprs = append(argExprs, data.ChildVar) | |
| 504 | + | argExprs = append(argExprs, "wl.ArgObject("+data.ChildVar+")") | |
| 483 | 505 | continue | |
| 484 | 506 | } | |
| 485 | 507 | argExprs = append(argExprs, slot.expr) | |
| @@ -490,7 +512,7 @@ func (s *Scanner) processRequest(iface Interface, req Request, opcode int) (requ | |||
| 490 | 512 | if len(argExprs) > 0 { | |
| 491 | 513 | args = ", " + strings.Join(argExprs, ", ") | |
| 492 | 514 | } | |
| 493 | - | // Context.Request owns the lifecycle: destructors claim the proxy | |
| 515 | + | // Context.RequestArgs owns the lifecycle: destructors claim the proxy | |
| 494 | 516 | // atomically, children are registered before the send and descriptors are | |
| 495 | 517 | // closed only after a successful send. | |
| 496 | 518 | data.ArgList = args | |
A internal/scanner/sources_test.go +71 -0
| @@ -0,0 +1,71 @@ | |||
| 1 | + | package scanner | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "crypto/sha256" | |
| 5 | + | "fmt" | |
| 6 | + | "os" | |
| 7 | + | "path/filepath" | |
| 8 | + | "regexp" | |
| 9 | + | "strings" | |
| 10 | + | "testing" | |
| 11 | + | ) | |
| 12 | + | ||
| 13 | + | func TestProtocolSourceChecksums(t *testing.T) { | |
| 14 | + | root := filepath.Join("..", "..", "protocol") | |
| 15 | + | content, err := os.ReadFile(filepath.Join(root, "SOURCE.md")) | |
| 16 | + | if err != nil { | |
| 17 | + | t.Fatal(err) | |
| 18 | + | } | |
| 19 | + | coreChecksum := regexp.MustCompile("(?m)^SHA-256: `([a-f0-9]{64})`\\.").FindSubmatch(content) | |
| 20 | + | if coreChecksum == nil { | |
| 21 | + | t.Fatal("core protocol source checksum is missing") | |
| 22 | + | } | |
| 23 | + | // Extension tables record upstream path, vendored path and SHA-256. | |
| 24 | + | rows := regexp.MustCompile("(?m)^\\| `[^`]+` \\| `([^`]+)` \\| `([a-f0-9]{64})` \\|$").FindAllSubmatch(content, -1) | |
| 25 | + | if len(rows) == 0 { | |
| 26 | + | t.Fatal("no protocol source checksums found") | |
| 27 | + | } | |
| 28 | + | rows = append(rows, [][]byte{nil, []byte("wayland.xml"), coreChecksum[1]}) | |
| 29 | + | recorded := make(map[string]bool) | |
| 30 | + | for _, row := range rows { | |
| 31 | + | path, want := string(row[1]), string(row[2]) | |
| 32 | + | if !filepath.IsLocal(path) { | |
| 33 | + | t.Fatalf("source path must be repository-relative: %q", path) | |
| 34 | + | } | |
| 35 | + | if recorded[path] { | |
| 36 | + | t.Fatalf("duplicate source record: %s", path) | |
| 37 | + | } | |
| 38 | + | recorded[path] = true | |
| 39 | + | t.Run(path, func(t *testing.T) { | |
| 40 | + | data, err := os.ReadFile(filepath.Join(root, path)) | |
| 41 | + | if err != nil { | |
| 42 | + | t.Fatal(err) | |
| 43 | + | } | |
| 44 | + | if got := fmt.Sprintf("%x", sha256.Sum256(data)); got != want { | |
| 45 | + | t.Fatalf("SHA-256 %s, recorded %s", got, want) | |
| 46 | + | } | |
| 47 | + | if !strings.Contains(string(data), "<copyright>") { | |
| 48 | + | t.Fatal("vendored XML is missing upstream copyright/license") | |
| 49 | + | } | |
| 50 | + | }) | |
| 51 | + | } | |
| 52 | + | err = filepath.WalkDir(root, func(path string, entry os.DirEntry, err error) error { | |
| 53 | + | if err != nil { | |
| 54 | + | return err | |
| 55 | + | } | |
| 56 | + | if entry.IsDir() || filepath.Ext(path) != ".xml" { | |
| 57 | + | return nil | |
| 58 | + | } | |
| 59 | + | rel, err := filepath.Rel(root, path) | |
| 60 | + | if err != nil { | |
| 61 | + | return err | |
| 62 | + | } | |
| 63 | + | if !recorded[filepath.ToSlash(rel)] { | |
| 64 | + | t.Errorf("%s has no source/checksum record", rel) | |
| 65 | + | } | |
| 66 | + | return nil | |
| 67 | + | }) | |
| 68 | + | if err != nil { | |
| 69 | + | t.Fatal(err) | |
| 70 | + | } | |
| 71 | + | } | |
M internal/scanner/template.go +7 -5
| @@ -3,14 +3,16 @@ package scanner | |||
| 3 | 3 | // protocolTemplate is the template for generating WLTurbo-backed Go bindings. | |
| 4 | 4 | // | |
| 5 | 5 | // Generated objects embed wl.BaseProxy, send every request through | |
| 6 | - | // wl.Context.Request (which owns version checks, child registration and FD | |
| 7 | - | // cleanup), and dispatch | |
| 8 | - | // typed events to registered handlers. Nothing in the generated code opens a | |
| 6 | + | // wl.Context.RequestArgs (typed arguments, no interface boxing; it owns | |
| 7 | + | // version checks, child registration and FD cleanup), and dispatch typed | |
| 8 | + | // events to registered handlers. Nothing in the generated code opens a | |
| 9 | 9 | // socket or frames messages itself: that is the transport's job. | |
| 10 | 10 | const protocolTemplate = `// Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 11 | 11 | // Protocol: {{.Protocol}} | |
| 12 | 12 | // Source: {{.Source}} | |
| 13 | - | ||
| 13 | + | {{if .Copyright}} | |
| 14 | + | // Upstream protocol copyright and license: | |
| 15 | + | {{.Copyright}}{{end}} | |
| 14 | 16 | package {{.Package}} | |
| 15 | 17 | ||
| 16 | 18 | {{.ImportBlock}} | |
| @@ -62,7 +64,7 @@ func (o *{{$iface.GoName}}) {{.GoName}}({{.Params}}) {{.Results}} { | |||
| 62 | 64 | {{.ChildVar}}.SetContext(o.Context()) | |
| 63 | 65 | {{- end}} | |
| 64 | 66 | {{- end}} | |
| 65 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: {{.Opcode}}, Name: "{{$iface.Name}}.{{.Name}}" | |
| 67 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: {{.Opcode}}, Name: "{{$iface.Name}}.{{.Name}}" | |
| 66 | 68 | {{- if gt .Since 1}}, Since: {{.Since}}{{end}} | |
| 67 | 69 | {{- if .Destructor}}, Destructor: true{{end}} | |
| 68 | 70 | {{- if .CreatesChild}}, Child: {{.ChildVar}}{{end}} | |
M protocol/SOURCE.md +69 -4
| @@ -6,11 +6,11 @@ | |||
| 6 | 6 | SHA-256: `cc860987e54f8d85c940e97fa1270c69b6e4ad31fbcf5a7f00107ce1157f5e07`. | |
| 7 | 7 | License: MIT (full copyright and grant in `wayland.xml` `<copyright>`). | |
| 8 | 8 | ||
| 9 | - | ## Required extensions | |
| 9 | + | ## wayland-protocols extensions | |
| 10 | 10 | ||
| 11 | 11 | The following XML files come from `https://gitlab.freedesktop.org/wayland/wayland-protocols`, | |
| 12 | 12 | tag `1.49` (peeled commit `ee78491a237eaff9389a0ccf8680521d074407d3`). | |
| 13 | - | Each file includes its upstream `<copyright>` and MIT-style license grant. | |
| 13 | + | Each XML retains its upstream `<copyright>` and license grant; consult the file for its exact terms. | |
| 14 | 14 | SHA-256 (of the vendored XML bytes): | |
| 15 | 15 | ||
| 16 | 16 | | Upstream path (under tag 1.49) | Vendored path | SHA-256 | | |
| @@ -23,6 +23,71 @@ SHA-256 (of the vendored XML bytes): | |||
| 23 | 23 | | `unstable/text-input/text-input-unstable-v3.xml` | `textinput/text-input-unstable-v3.xml` | `160815cda13c285a30df1971d8f0a5b3aac07071537df59916d2f748b18e4f59` | | |
| 24 | 24 | | `staging/cursor-shape/cursor-shape-v1.xml` | `cursorshape/cursor-shape-v1.xml` | `bb57d91e53a79dadab7c612dab87c233393cee73673feefa7442cfbfdd9aed2f` | | |
| 25 | 25 | | `stable/tablet/tablet-v2.xml` | `tablet/tablet-v2.xml` | `ac1128b26c779cf90b9ed71182ba5e34a7262826789adae206d825a4d45908b4` | | |
| 26 | + | | `staging/alpha-modifier/alpha-modifier-v1.xml` | `alphamodifier/alpha-modifier-v1.xml` | `f0b4a43b9e48783fafdb46319fa72b34a41afd932f8613d7cadaf7203f2ffa35` | | |
| 27 | + | | `staging/color-management/color-management-v1.xml` | `colormanagement/color-management-v1.xml` | `18a2678e3352c3be3fbeed20005d48852b7235d0d78f08b9c987a0b8e91449f9` | | |
| 28 | + | | `staging/color-representation/color-representation-v1.xml` | `colorrepresentation/color-representation-v1.xml` | `b824688e0e5c1d01e12afe1d3f82503092ec7599affcd6471fda6d296d4f7e3b` | | |
| 29 | + | | `staging/commit-timing/commit-timing-v1.xml` | `committiming/commit-timing-v1.xml` | `ff3fcf31d13d44bad756a50fda663a43008bacbbd2bf8cba3a1bf5ffe7f54172` | | |
| 30 | + | | `staging/content-type/content-type-v1.xml` | `contenttype/content-type-v1.xml` | `203d17a26baa2ab4a8c2c9cb737c953fa3263c73a0a8aa6e552a41b3eac2196d` | | |
| 31 | + | | `staging/ext-data-control/ext-data-control-v1.xml` | `datacontrol/ext-data-control-v1.xml` | `293deba5dfdb974fbcf8dcf891a30a51a36a8bba0047dc6bdf6a03194089b7fb` | | |
| 32 | + | | `staging/drm-lease/drm-lease-v1.xml` | `drmlease/drm-lease-v1.xml` | `18f325e92285473eca0567ea1038abb16849b8638b36e458ff551f3ca68ef80c` | | |
| 33 | + | | `staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml` | `extforeigntoplevel/ext-foreign-toplevel-list-v1.xml` | `6b2ffb3a07d679d1c4170263adfefb9a7c37dd34ed3db5180bf58cb8ff8fbd0b` | | |
| 34 | + | | `staging/fifo/fifo-v1.xml` | `fifo/fifo-v1.xml` | `0b6c31dfe6bca19b712745c9de7a4a398558cfa1087b1938e96fd3b10ffc1069` | | |
| 35 | + | | `unstable/idle-inhibit/idle-inhibit-unstable-v1.xml` | `idleinhibit/idle-inhibit-unstable-v1.xml` | `c2ac9f002c6669ca6c02eb9b587b8e9108e3ce6deab4a2de58b576f4f864ca38` | | |
| 36 | + | | `staging/ext-idle-notify/ext-idle-notify-v1.xml` | `idlenotify/ext-idle-notify-v1.xml` | `e56a9c22684e6b46655f7221b798328e304c1efc8f63f01241a1cf8c070f4c30` | | |
| 37 | + | | `staging/ext-image-capture-source/ext-image-capture-source-v1.xml` | `imagecapturesource/ext-image-capture-source-v1.xml` | `4ef41d15e4cdb9f550158391358ceec724a6708b43b7efedec03121a6bb8458d` | | |
| 38 | + | | `staging/ext-image-copy-capture/ext-image-copy-capture-v1.xml` | `imagecopycapture/ext-image-copy-capture-v1.xml` | `41a446653f788fabb404cab3168c0bd667c1ff4b54f1f0bb1e18810a1f47d73f` | | |
| 39 | + | | `unstable/pointer-constraints/pointer-constraints-unstable-v1.xml` | `pointerconstraints/pointer-constraints-unstable-v1.xml` | `f980fac900ba1dcfbbe97f588fc17b893926bd2b57624563653a1bfe4d035948` | | |
| 40 | + | | `staging/pointer-warp/pointer-warp-v1.xml` | `pointerwarp/pointer-warp-v1.xml` | `1389e89c68c6f6d231fd2dcda57fa9c75c5230d0ac1deffa8d80a7648e197e66` | | |
| 41 | + | | `stable/presentation-time/presentation-time.xml` | `presentation/presentation-time.xml` | `dffac93bcb2bb1d8c385e72b8a8c2c0d4d79a336866322f3ba886dce2b27b1e2` | | |
| 42 | + | | `unstable/primary-selection/primary-selection-unstable-v1.xml` | `primaryselection/primary-selection-unstable-v1.xml` | `d568482ba84df6e531698b1f531810860995ca24d69495427fe43aee6017f52c` | | |
| 43 | + | | `unstable/relative-pointer/relative-pointer-unstable-v1.xml` | `relativepointer/relative-pointer-unstable-v1.xml` | `ab4930dd3084f732b6fdd12ee6dbd0a112a758ed8a57b170366391dbeb1a22ff` | | |
| 44 | + | | `unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml` | `shortcutsinhibit/keyboard-shortcuts-inhibit-unstable-v1.xml` | `9117d9e8ec02e9a3c3c55803b41e1227e76986f555f7c12eeb29f796fa63e69b` | | |
| 45 | + | | `staging/tearing-control/tearing-control-v1.xml` | `tearingcontrol/tearing-control-v1.xml` | `846895b4a90ba1ddd75673cefc596480beef318f1694ec7dbca0fec54bb27043` | | |
| 46 | + | | `staging/ext-workspace/ext-workspace-v1.xml` | `workspace/ext-workspace-v1.xml` | `9b449d9d5d40f6032eba9813d18093b84f249a2cf38d6755dec7bca7eb96b0f3` | | |
| 47 | + | | `staging/xdg-activation/xdg-activation-v1.xml` | `xdgactivation/xdg-activation-v1.xml` | `d8418be2d5738d50aff788bef1c7574f33f26659aa045447ff2ef9b78c58fe01` | | |
| 48 | + | | `unstable/xdg-decoration/xdg-decoration-unstable-v1.xml` | `xdgdecoration/xdg-decoration-unstable-v1.xml` | `68753c4a85a28659e3aa1fe0f138329a8bf3dff0b4789f4663a2c7fedbfecf2f` | | |
| 49 | + | | `unstable/xdg-output/xdg-output-unstable-v1.xml` | `xdgoutput/xdg-output-unstable-v1.xml` | `363d547c3eefe8959160cac903ff90b311d4b183005557d73640d9df2cfd7f79` | | |
| 26 | 50 | ||
| 27 | - | `tablet-v2.xml` is vendored because `wp_cursor_shape_manager_v1.get_tablet_tool_v2` | |
| 28 | - | references `zwp_tablet_tool_v2`. | |
| 51 | + | ## wlr-protocols | |
| 52 | + | ||
| 53 | + | Source: `https://gitlab.freedesktop.org/wlroots/wlr-protocols`, commit | |
| 54 | + | `bf4fc79abc359eea5a0edec0ac6d4a2b2955f82a`. The XML files retain their upstream | |
| 55 | + | license grants, including the no-fee/no-advertising terms where applicable. | |
| 56 | + | ||
| 57 | + | | Upstream path | Vendored path | SHA-256 | | |
| 58 | + | |---|---|---| | |
| 59 | + | | `unstable/wlr-layer-shell-unstable-v1.xml` | `layershell/wlr-layer-shell-unstable-v1.xml` | `87e0b9c837aecd6977f76f3c47d73088b7159871f5d979dc1840f6cadb5e2ed8` | | |
| 60 | + | | `unstable/wlr-screencopy-unstable-v1.xml` | `screencopy/wlr-screencopy-unstable-v1.xml` | `131b8f9b4aad0c8a9cf705e90d2a1511a5ca0c477637fd3400cf1cc4fa963fb8` | | |
| 61 | + | | `unstable/wlr-foreign-toplevel-management-unstable-v1.xml` | `foreigntoplevel/wlr-foreign-toplevel-management-unstable-v1.xml` | `4ecc4588858e29fe680a33521e1f22bcf22071d66d1553fe96b4ddec03d591d2` | | |
| 62 | + | | `unstable/wlr-output-management-unstable-v1.xml` | `outputmanagement/wlr-output-management-unstable-v1.xml` | `65b0f82a6cf129bf1a1c31a2428795abd33886c15ddd5f3ad97e5922d7bdc3a7` | | |
| 63 | + | | `unstable/wlr-output-power-management-unstable-v1.xml` | `outputpower/wlr-output-power-management-unstable-v1.xml` | `7ebd98f3449d246a57829e4b4dd9fbc3ef98e3dd42fa94ea102f14f490eb20de` | | |
| 64 | + | ||
| 65 | + | ## wlroots input protocols | |
| 66 | + | ||
| 67 | + | Source: `https://gitlab.freedesktop.org/wlroots/wlroots`, tag `0.19.0`, peeled | |
| 68 | + | commit `13a62a23a258d96f902c740310d5c7c59784a4d1`. Both XML files retain their | |
| 69 | + | MIT-style license grants. | |
| 70 | + | ||
| 71 | + | | Upstream path | Vendored path | SHA-256 | | |
| 72 | + | |---|---|---| | |
| 73 | + | | `protocol/virtual-keyboard-unstable-v1.xml` | `virtualkeyboard/virtual-keyboard-unstable-v1.xml` | `7ad7870003ecd592cae47dc19d277a609b7f18fd7b7be012623cf3225a7294f5` | | |
| 74 | + | | `protocol/input-method-unstable-v2.xml` | `inputmethod/input-method-unstable-v2.xml` | `99414dbad9458e71aa1fa01bc45f94ca6685787bfcb4d98948f72c1b45b60703` | | |
| 75 | + | ||
| 76 | + | ## KDE server decoration | |
| 77 | + | ||
| 78 | + | Source: `https://invent.kde.org/libraries/plasma-wayland-protocols`, tag | |
| 79 | + | `v1.23.0`, peeled commit `c5ac4db818f4a575a6ccfe0065b73ecfaba6e93e`. | |
| 80 | + | The XML and its generated `kdeserverdecoration` bindings retain | |
| 81 | + | **LGPL-2.1-or-later**, including the copied protocol documentation. They are not | |
| 82 | + | relicensed under WLTurbo's MIT license. The [license text](../LICENSES/LGPL-2.1-or-later.txt) | |
| 83 | + | is included; generated files retain the upstream notice. | |
| 84 | + | ||
| 85 | + | | Upstream path | Vendored path | SHA-256 | | |
| 86 | + | |---|---|---| | |
| 87 | + | | `src/protocols/server-decoration.xml` | `kdeserverdecoration/server-decoration.xml` | `c5f857734bb190dc9adfb65fb05550a6245f12af1a2be5eefd05be199805a68c` | | |
| 88 | + | ||
| 89 | + | ## Cross-package types | |
| 90 | + | ||
| 91 | + | Cross-package references use canonical generated types. Cursor-shape depends on | |
| 92 | + | `tablet`; xdg-decoration and layer-shell depend on `xdgshell`; image-copy-capture | |
| 93 | + | depends on `imagecapturesource`, which depends on `extforeigntoplevel`. | |
A protocol/alphamodifier/alpha-modifier-v1.xml +103 -0
| @@ -0,0 +1,103 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="alpha_modifier_v1"> | |
| 3 | + | <copyright> | |
| 4 | + | Copyright © 2024 Xaver Hugl | |
| 5 | + | ||
| 6 | + | Permission is hereby granted, free of charge, to any person obtaining a | |
| 7 | + | copy of this software and associated documentation files (the "Software"), | |
| 8 | + | to deal in the Software without restriction, including without limitation | |
| 9 | + | the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 10 | + | and/or sell copies of the Software, and to permit persons to whom the | |
| 11 | + | Software is furnished to do so, subject to the following conditions: | |
| 12 | + | ||
| 13 | + | The above copyright notice and this permission notice (including the next | |
| 14 | + | paragraph) shall be included in all copies or substantial portions of the | |
| 15 | + | Software. | |
| 16 | + | ||
| 17 | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 18 | + | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 19 | + | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 20 | + | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 21 | + | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 22 | + | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 23 | + | DEALINGS IN THE SOFTWARE. | |
| 24 | + | </copyright> | |
| 25 | + | ||
| 26 | + | <interface name="wp_alpha_modifier_v1" version="1"> | |
| 27 | + | <description summary="surface alpha modifier manager"> | |
| 28 | + | This interface allows a client to set a factor for the alpha values on a | |
| 29 | + | surface, which can be used to offload such operations to the compositor, | |
| 30 | + | which can in turn for example offload them to KMS. | |
| 31 | + | ||
| 32 | + | Warning! The protocol described in this file is currently in the testing | |
| 33 | + | phase. Backward compatible changes may be added together with the | |
| 34 | + | corresponding interface version bump. Backward incompatible changes can | |
| 35 | + | only be done by creating a new major version of the extension. | |
| 36 | + | </description> | |
| 37 | + | ||
| 38 | + | <request name="destroy" type="destructor"> | |
| 39 | + | <description summary="destroy the alpha modifier manager object"> | |
| 40 | + | Destroy the alpha modifier manager. This doesn't destroy objects | |
| 41 | + | created with the manager. | |
| 42 | + | </description> | |
| 43 | + | </request> | |
| 44 | + | ||
| 45 | + | <enum name="error"> | |
| 46 | + | <entry name="already_constructed" value="0" | |
| 47 | + | summary="wl_surface already has a alpha modifier object"/> | |
| 48 | + | </enum> | |
| 49 | + | ||
| 50 | + | <request name="get_surface"> | |
| 51 | + | <description summary="create a new alpha modifier surface object"> | |
| 52 | + | Create a new alpha modifier surface object associated with the | |
| 53 | + | given wl_surface. If there is already such an object associated with | |
| 54 | + | the wl_surface, the already_constructed error will be raised. | |
| 55 | + | </description> | |
| 56 | + | <arg name="id" type="new_id" interface="wp_alpha_modifier_surface_v1"/> | |
| 57 | + | <arg name="surface" type="object" interface="wl_surface"/> | |
| 58 | + | </request> | |
| 59 | + | </interface> | |
| 60 | + | ||
| 61 | + | <interface name="wp_alpha_modifier_surface_v1" version="1"> | |
| 62 | + | <description summary="alpha modifier object for a surface"> | |
| 63 | + | This interface allows the client to set a factor for the alpha values on | |
| 64 | + | a surface, which can be used to offload such operations to the compositor. | |
| 65 | + | The default factor is UINT32_MAX. | |
| 66 | + | ||
| 67 | + | This object has to be destroyed before the associated wl_surface. Once the | |
| 68 | + | wl_surface is destroyed, all request on this object will raise the | |
| 69 | + | no_surface error. | |
| 70 | + | </description> | |
| 71 | + | ||
| 72 | + | <enum name="error"> | |
| 73 | + | <entry name="no_surface" value="0" summary="wl_surface was destroyed"/> | |
| 74 | + | </enum> | |
| 75 | + | ||
| 76 | + | <request name="destroy" type="destructor"> | |
| 77 | + | <description summary="destroy the alpha modifier object"> | |
| 78 | + | This destroys the object, and is equivalent to set_multiplier with | |
| 79 | + | a value of UINT32_MAX, with the same double-buffered semantics as | |
| 80 | + | set_multiplier. | |
| 81 | + | </description> | |
| 82 | + | </request> | |
| 83 | + | ||
| 84 | + | <request name="set_multiplier"> | |
| 85 | + | <description summary="specify the alpha multiplier"> | |
| 86 | + | Sets the alpha multiplier for the surface. The alpha multiplier is | |
| 87 | + | double-buffered state, see wl_surface.commit for details. | |
| 88 | + | ||
| 89 | + | This factor is applied in the compositor's blending space, as an | |
| 90 | + | additional step after the processing of per-pixel alpha values for the | |
| 91 | + | wl_surface. The exact meaning of the factor is thus undefined, unless | |
| 92 | + | the blending space is specified in a different extension. | |
| 93 | + | ||
| 94 | + | This multiplier is applied even if the buffer attached to the | |
| 95 | + | wl_surface doesn't have an alpha channel; in that case an alpha value | |
| 96 | + | of one is used instead. | |
| 97 | + | ||
| 98 | + | Zero means completely transparent, UINT32_MAX means completely opaque. | |
| 99 | + | </description> | |
| 100 | + | <arg name="factor" type="uint"/> | |
| 101 | + | </request> | |
| 102 | + | </interface> | |
| 103 | + | </protocol> | |
A protocol/alphamodifier/alpha-modifier-v1_generated.go +138 -0
| @@ -0,0 +1,138 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: alpha_modifier_v1 | |
| 3 | + | // Source: alpha-modifier-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2024 Xaver Hugl | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package alphamodifier | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | cross_wl_surface "github.com/bnema/wlturbo/protocol/core" | |
| 31 | + | "github.com/bnema/wlturbo/wl" | |
| 32 | + | ) | |
| 33 | + | ||
| 34 | + | // ERROR_ALREADY_CONSTRUCTED is the error already_constructed value. | |
| 35 | + | const ERROR_ALREADY_CONSTRUCTED = 0 | |
| 36 | + | ||
| 37 | + | // ERROR_NO_SURFACE is the error no_surface value. | |
| 38 | + | const ERROR_NO_SURFACE = 0 | |
| 39 | + | ||
| 40 | + | // WpAlphaModifierInterface is the protocol interface name. | |
| 41 | + | const WpAlphaModifierInterface = "wp_alpha_modifier_v1" | |
| 42 | + | ||
| 43 | + | // WpAlphaModifier is the generated binding for wp_alpha_modifier_v1 version 1. | |
| 44 | + | type WpAlphaModifier struct { | |
| 45 | + | wl.BaseProxy | |
| 46 | + | } | |
| 47 | + | ||
| 48 | + | // NewWpAlphaModifier returns an unbound WpAlphaModifier. | |
| 49 | + | func NewWpAlphaModifier(ctx *wl.Context) *WpAlphaModifier { | |
| 50 | + | obj := &WpAlphaModifier{} | |
| 51 | + | obj.SetContext(ctx) | |
| 52 | + | ctx.Register(obj) | |
| 53 | + | return obj | |
| 54 | + | } | |
| 55 | + | ||
| 56 | + | // Destroy the alpha modifier manager. This doesn't destroy objects created with the manager. | |
| 57 | + | func (o *WpAlphaModifier) Destroy() error { | |
| 58 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_alpha_modifier_v1.destroy", Destructor: true}); err != nil { | |
| 59 | + | return err | |
| 60 | + | } | |
| 61 | + | return nil | |
| 62 | + | } | |
| 63 | + | ||
| 64 | + | // Create a new alpha modifier surface object associated with the given wl_surface. If there is already such an object associated with the wl_surface, the already_constructed error will be raised. | |
| 65 | + | func (o *WpAlphaModifier) GetSurface(surface *cross_wl_surface.Surface) (*WpAlphaModifierSurface, error) { | |
| 66 | + | var arg1 wl.Object | |
| 67 | + | if surface != nil { | |
| 68 | + | arg1 = surface | |
| 69 | + | } | |
| 70 | + | child := &WpAlphaModifierSurface{} | |
| 71 | + | child.SetContext(o.Context()) | |
| 72 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_alpha_modifier_v1.get_surface", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 73 | + | return nil, err | |
| 74 | + | } | |
| 75 | + | return child, nil | |
| 76 | + | } | |
| 77 | + | ||
| 78 | + | // EventSignature returns the declared event argument types in wire order. | |
| 79 | + | func (o *WpAlphaModifier) EventSignature(opcode uint16) (string, bool) { | |
| 80 | + | switch opcode { | |
| 81 | + | default: | |
| 82 | + | return "", false | |
| 83 | + | } | |
| 84 | + | } | |
| 85 | + | ||
| 86 | + | // Dispatch decodes one event on wp_alpha_modifier_v1 and calls the registered handlers. | |
| 87 | + | func (o *WpAlphaModifier) Dispatch(event *wl.Event) { | |
| 88 | + | switch event.Opcode { | |
| 89 | + | default: | |
| 90 | + | } | |
| 91 | + | } | |
| 92 | + | ||
| 93 | + | // WpAlphaModifierSurfaceInterface is the protocol interface name. | |
| 94 | + | const WpAlphaModifierSurfaceInterface = "wp_alpha_modifier_surface_v1" | |
| 95 | + | ||
| 96 | + | // WpAlphaModifierSurface is the generated binding for wp_alpha_modifier_surface_v1 version 1. | |
| 97 | + | type WpAlphaModifierSurface struct { | |
| 98 | + | wl.BaseProxy | |
| 99 | + | } | |
| 100 | + | ||
| 101 | + | // NewWpAlphaModifierSurface returns an unbound WpAlphaModifierSurface. | |
| 102 | + | func NewWpAlphaModifierSurface(ctx *wl.Context) *WpAlphaModifierSurface { | |
| 103 | + | obj := &WpAlphaModifierSurface{} | |
| 104 | + | obj.SetContext(ctx) | |
| 105 | + | ctx.Register(obj) | |
| 106 | + | return obj | |
| 107 | + | } | |
| 108 | + | ||
| 109 | + | // This destroys the object, and is equivalent to set_multiplier with a value of UINT32_MAX, with the same double-buffered semantics as set_multiplier. | |
| 110 | + | func (o *WpAlphaModifierSurface) Destroy() error { | |
| 111 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_alpha_modifier_surface_v1.destroy", Destructor: true}); err != nil { | |
| 112 | + | return err | |
| 113 | + | } | |
| 114 | + | return nil | |
| 115 | + | } | |
| 116 | + | ||
| 117 | + | // Sets the alpha multiplier for the surface. The alpha multiplier is double-buffered state, see wl_surface.commit for details. This factor is applied in the compositor's blending space, as an additional step after the processing of per-pixel alpha values for the wl_surface. The exact meaning of the factor is thus undefined, unless the blending space is specified in a different extension. This multiplier is applied even if the buffer attached to the wl_surface doesn't have an alpha channel; in that case an alpha value of one is used instead. Zero means completely transparent, UINT32_MAX means completely opaque. | |
| 118 | + | func (o *WpAlphaModifierSurface) SetMultiplier(factor uint32) error { | |
| 119 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_alpha_modifier_surface_v1.set_multiplier"}, wl.ArgUint(factor)); err != nil { | |
| 120 | + | return err | |
| 121 | + | } | |
| 122 | + | return nil | |
| 123 | + | } | |
| 124 | + | ||
| 125 | + | // EventSignature returns the declared event argument types in wire order. | |
| 126 | + | func (o *WpAlphaModifierSurface) EventSignature(opcode uint16) (string, bool) { | |
| 127 | + | switch opcode { | |
| 128 | + | default: | |
| 129 | + | return "", false | |
| 130 | + | } | |
| 131 | + | } | |
| 132 | + | ||
| 133 | + | // Dispatch decodes one event on wp_alpha_modifier_surface_v1 and calls the registered handlers. | |
| 134 | + | func (o *WpAlphaModifierSurface) Dispatch(event *wl.Event) { | |
| 135 | + | switch event.Opcode { | |
| 136 | + | default: | |
| 137 | + | } | |
| 138 | + | } | |
A protocol/alphamodifier/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package alphamodifier | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p alphamodifier -o alpha-modifier-v1_generated.go -import wl_surface=github.com/bnema/wlturbo/protocol/core alpha-modifier-v1.xml | |
A protocol/colormanagement/color-management-v1.xml +1756 -0
| @@ -0,0 +1,1756 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="color_management_v1"> | |
| 3 | + | <copyright> | |
| 4 | + | Copyright 2019 Sebastian Wick | |
| 5 | + | Copyright 2019 Erwin Burema | |
| 6 | + | Copyright 2020 AMD | |
| 7 | + | Copyright 2020-2024 Collabora, Ltd. | |
| 8 | + | Copyright 2024 Xaver Hugl | |
| 9 | + | Copyright 2022-2025 Red Hat, Inc. | |
| 10 | + | ||
| 11 | + | Permission is hereby granted, free of charge, to any person obtaining a | |
| 12 | + | copy of this software and associated documentation files (the "Software"), | |
| 13 | + | to deal in the Software without restriction, including without limitation | |
| 14 | + | the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 15 | + | and/or sell copies of the Software, and to permit persons to whom the | |
| 16 | + | Software is furnished to do so, subject to the following conditions: | |
| 17 | + | ||
| 18 | + | The above copyright notice and this permission notice (including the next | |
| 19 | + | paragraph) shall be included in all copies or substantial portions of the | |
| 20 | + | Software. | |
| 21 | + | ||
| 22 | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 23 | + | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 24 | + | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 25 | + | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 26 | + | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 27 | + | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 28 | + | DEALINGS IN THE SOFTWARE. | |
| 29 | + | </copyright> | |
| 30 | + | ||
| 31 | + | <description summary="color management protocol"> | |
| 32 | + | The aim of the color management extension is to allow clients to know | |
| 33 | + | the color properties of outputs, and to tell the compositor about the color | |
| 34 | + | properties of their content on surfaces. All surface contents must be | |
| 35 | + | readily intended for some display, but not necessarily for the display at | |
| 36 | + | hand. Doing this enables a compositor to perform automatic color management | |
| 37 | + | of content for different outputs according to how content is intended to | |
| 38 | + | look like. | |
| 39 | + | ||
| 40 | + | For an introduction, see the section "Color management" in the Wayland | |
| 41 | + | documentation at https://wayland.freedesktop.org/docs/html/ . | |
| 42 | + | ||
| 43 | + | The color properties are represented as an image description object which | |
| 44 | + | is immutable after it has been created. A wl_output always has an | |
| 45 | + | associated image description that clients can observe. A wl_surface | |
| 46 | + | always has an associated preferred image description as a hint chosen by | |
| 47 | + | the compositor that clients can also observe. Clients can set an image | |
| 48 | + | description on a wl_surface to denote the color characteristics of the | |
| 49 | + | surface contents. | |
| 50 | + | ||
| 51 | + | An image description essentially defines a display and (indirectly) its | |
| 52 | + | viewing environment. An image description includes SDR and HDR colorimetry | |
| 53 | + | and encoding, HDR metadata, and some parameters related to the viewing | |
| 54 | + | environment. An image description does not include the properties set | |
| 55 | + | through color-representation extension. It is expected that the | |
| 56 | + | color-representation extension is used in conjunction with the | |
| 57 | + | color-management extension when necessary, particularly with the YUV family | |
| 58 | + | of pixel formats. | |
| 59 | + | ||
| 60 | + | The normative appendix for this protocol is in the appendix.md file beside | |
| 61 | + | this XML file. | |
| 62 | + | ||
| 63 | + | The color-and-hdr repository | |
| 64 | + | (https://gitlab.freedesktop.org/pq/color-and-hdr) contains | |
| 65 | + | background information on the protocol design and legacy color management. | |
| 66 | + | It also contains a glossary, learning resources for digital color, tools, | |
| 67 | + | samples and more. | |
| 68 | + | ||
| 69 | + | The terminology used in this protocol is based on common color science and | |
| 70 | + | color encoding terminology where possible. The glossary in the color-and-hdr | |
| 71 | + | repository shall be the authority on the definition of terms in this | |
| 72 | + | protocol. | |
| 73 | + | ||
| 74 | + | Warning! The protocol described in this file is currently in the testing | |
| 75 | + | phase. Backward compatible changes may be added together with the | |
| 76 | + | corresponding interface version bump. Backward incompatible changes can | |
| 77 | + | only be done by creating a new major version of the extension. | |
| 78 | + | </description> | |
| 79 | + | ||
| 80 | + | <interface name="wp_color_manager_v1" version="3"> | |
| 81 | + | <description summary="color manager singleton"> | |
| 82 | + | A singleton global interface used for getting color management extensions | |
| 83 | + | for wl_surface and wl_output objects, and for creating client defined | |
| 84 | + | image description objects. The extension interfaces allow | |
| 85 | + | getting the image description of outputs and setting the image | |
| 86 | + | description of surfaces. | |
| 87 | + | ||
| 88 | + | Compositors should never remove this global. | |
| 89 | + | </description> | |
| 90 | + | ||
| 91 | + | <request name="destroy" type="destructor"> | |
| 92 | + | <description summary="destroy the color manager"> | |
| 93 | + | Destroy the wp_color_manager_v1 object. This does not affect any other | |
| 94 | + | objects in any way. | |
| 95 | + | </description> | |
| 96 | + | </request> | |
| 97 | + | ||
| 98 | + | <enum name="error"> | |
| 99 | + | <entry name="unsupported_feature" value="0" | |
| 100 | + | summary="request not supported"/> | |
| 101 | + | <entry name="surface_exists" value="1" | |
| 102 | + | summary="color management surface exists already"/> | |
| 103 | + | </enum> | |
| 104 | + | ||
| 105 | + | <enum name="render_intent"> | |
| 106 | + | <description summary="rendering intents"> | |
| 107 | + | See the ICC.1:2022 specification from the International Color Consortium | |
| 108 | + | for more details about rendering intents. | |
| 109 | + | ||
| 110 | + | The principles of ICC defined rendering intents apply with all types of | |
| 111 | + | image descriptions, not only those with ICC file profiles. | |
| 112 | + | ||
| 113 | + | Compositors must support the perceptual rendering intent. Other | |
| 114 | + | rendering intents are optional. | |
| 115 | + | </description> | |
| 116 | + | ||
| 117 | + | <entry name="perceptual" value="0" | |
| 118 | + | summary="perceptual"/> | |
| 119 | + | <entry name="relative" value="1" | |
| 120 | + | summary="media-relative colorimetric"/> | |
| 121 | + | <entry name="saturation" value="2" | |
| 122 | + | summary="saturation"/> | |
| 123 | + | <entry name="absolute" value="3" | |
| 124 | + | summary="ICC-absolute colorimetric"/> | |
| 125 | + | <entry name="relative_bpc" value="4" | |
| 126 | + | summary="media-relative colorimetric + black point compensation"/> | |
| 127 | + | <entry name="absolute_no_adaptation" value="5" since="2"> | |
| 128 | + | <description summary="ICC-absolute colorimetric without adaptation"> | |
| 129 | + | This rendering intent is a modified absolute rendering intent that | |
| 130 | + | assumes the viewer is not adapted to the display white point, so no | |
| 131 | + | chromatic adaptation between surface and display is done. | |
| 132 | + | This can be useful for color proofing applications. | |
| 133 | + | </description> | |
| 134 | + | </entry> | |
| 135 | + | </enum> | |
| 136 | + | ||
| 137 | + | <enum name="feature"> | |
| 138 | + | <description summary="compositor supported features"/> | |
| 139 | + | ||
| 140 | + | <entry name="icc_v2_v4" value="0" | |
| 141 | + | summary="create_icc_creator request"/> | |
| 142 | + | <entry name="parametric" value="1" | |
| 143 | + | summary="create_parametric_creator request"/> | |
| 144 | + | <entry name="set_primaries" value="2" | |
| 145 | + | summary="parametric set_primaries request"/> | |
| 146 | + | <entry name="set_tf_power" value="3" | |
| 147 | + | summary="parametric set_tf_power request"/> | |
| 148 | + | <entry name="set_luminances" value="4" | |
| 149 | + | summary="parametric set_luminances request"/> | |
| 150 | + | <entry name="set_mastering_display_primaries" value="5"> | |
| 151 | + | <description summary="parametric set_mastering_display_primaries request"> | |
| 152 | + | The compositor supports set_mastering_display_primaries request with a | |
| 153 | + | target color volume fully contained inside the primary color volume. | |
| 154 | + | </description> | |
| 155 | + | </entry> | |
| 156 | + | <entry name="extended_target_volume" value="6"> | |
| 157 | + | <description summary="parametric target exceeds primary color volume"> | |
| 158 | + | The compositor additionally supports target color volumes that | |
| 159 | + | extend outside of the primary color volume. | |
| 160 | + | ||
| 161 | + | This can only be advertised if feature set_mastering_display_primaries | |
| 162 | + | is supported as well. | |
| 163 | + | </description> | |
| 164 | + | </entry> | |
| 165 | + | <entry name="windows_scrgb" value="7" | |
| 166 | + | summary="create_windows_scrgb request"/> | |
| 167 | + | <entry name="windows_bt2100" value="8" | |
| 168 | + | summary="create_windows_bt2100 request"/> | |
| 169 | + | </enum> | |
| 170 | + | ||
| 171 | + | <enum name="primaries"> | |
| 172 | + | <description summary="named color primaries"> | |
| 173 | + | Named color primaries used to encode well-known sets of primaries. | |
| 174 | + | ||
| 175 | + | A value of 0 is invalid and will never be present in the list of enums. | |
| 176 | + | </description> | |
| 177 | + | ||
| 178 | + | <entry name="srgb" value="1"> | |
| 179 | + | <description summary="Color primaries for the sRGB color space as defined by the BT.709 standard"> | |
| 180 | + | Color primaries as defined by | |
| 181 | + | - Rec. ITU-R BT.709-6 | |
| 182 | + | - Rec. ITU-R BT.1361-0 conventional colour gamut system and extended | |
| 183 | + | colour gamut system (historical) | |
| 184 | + | - IEC 61966-2-1 sRGB or sYCC | |
| 185 | + | - IEC 61966-2-4 | |
| 186 | + | - Society of Motion Picture and Television Engineers (SMPTE) RP 177 | |
| 187 | + | (1993) Annex B | |
| 188 | + | </description> | |
| 189 | + | </entry> | |
| 190 | + | <entry name="pal_m" value="2"> | |
| 191 | + | <description summary="Color primaries for PAL-M as defined by the BT.470 standard"> | |
| 192 | + | Color primaries as defined by | |
| 193 | + | - Rec. ITU-R BT.470-6 System M (historical) | |
| 194 | + | - United States National Television System Committee 1953 | |
| 195 | + | Recommendation for transmission standards for color television | |
| 196 | + | - United States Federal Communications Commission (2003) Title 47 Code | |
| 197 | + | of Federal Regulations 73.682 (a)(20) | |
| 198 | + | </description> | |
| 199 | + | </entry> | |
| 200 | + | <entry name="pal" value="3"> | |
| 201 | + | <description summary="Color primaries for PAL as defined by the BT.601 standard"> | |
| 202 | + | Color primaries as defined by | |
| 203 | + | - Rec. ITU-R BT.470-6 System B, G (historical) | |
| 204 | + | - Rec. ITU-R BT.601-7 625 | |
| 205 | + | - Rec. ITU-R BT.1358-0 625 (historical) | |
| 206 | + | - Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM | |
| 207 | + | </description> | |
| 208 | + | </entry> | |
| 209 | + | <entry name="ntsc" value="4"> | |
| 210 | + | <description summary="Color primaries for NTSC as defined by the BT.601 standard"> | |
| 211 | + | Color primaries as defined by | |
| 212 | + | - Rec. ITU-R BT.601-7 525 | |
| 213 | + | - Rec. ITU-R BT.1358-1 525 or 625 (historical) | |
| 214 | + | - Rec. ITU-R BT.1700-0 NTSC | |
| 215 | + | - SMPTE 170M (2004) | |
| 216 | + | - SMPTE 240M (1999) (historical) | |
| 217 | + | </description> | |
| 218 | + | </entry> | |
| 219 | + | <entry name="generic_film" value="5"> | |
| 220 | + | <description summary="Generic film with colour filters using Illuminant C"> | |
| 221 | + | Color primaries as defined by Recommendation ITU-T H.273 | |
| 222 | + | "Coding-independent code points for video signal type identification" | |
| 223 | + | for "generic film". | |
| 224 | + | </description> | |
| 225 | + | </entry> | |
| 226 | + | <entry name="bt2020" value="6"> | |
| 227 | + | <description summary="Color primaries as defined by the BT.2020 and BT.2100 standard"> | |
| 228 | + | Color primaries as defined by | |
| 229 | + | - Rec. ITU-R BT.2020-2 | |
| 230 | + | - Rec. ITU-R BT.2100-0 | |
| 231 | + | </description> | |
| 232 | + | </entry> | |
| 233 | + | <entry name="cie1931_xyz" value="7"> | |
| 234 | + | <description summary="Color primaries of the full CIE 1931 XYZ color space"> | |
| 235 | + | Color primaries as defined as the maximum of the CIE 1931 XYZ color | |
| 236 | + | space by | |
| 237 | + | - SMPTE ST 428-1 | |
| 238 | + | - (CIE 1931 XYZ as in ISO 11664-1) | |
| 239 | + | </description> | |
| 240 | + | </entry> | |
| 241 | + | <entry name="dci_p3" value="8"> | |
| 242 | + | <description summary="Color primaries of the DCI P3 color space as defined by the SMPTE RP 431 standard"> | |
| 243 | + | Color primaries as defined by Digital Cinema System and published in | |
| 244 | + | SMPTE RP 431-2 (2011). | |
| 245 | + | </description> | |
| 246 | + | </entry> | |
| 247 | + | <entry name="display_p3" value="9"> | |
| 248 | + | <description summary="Color primaries of Display P3 variant of the DCI-P3 color space as defined by the SMPTE EG 432 standard"> | |
| 249 | + | Color primaries as defined by Digital Cinema System and published in | |
| 250 | + | SMPTE EG 432-1 (2010). | |
| 251 | + | </description> | |
| 252 | + | </entry> | |
| 253 | + | <entry name="adobe_rgb" value="10"> | |
| 254 | + | <description summary="Color primaries of the Adobe RGB color space as defined by the ISO 12640 standard"> | |
| 255 | + | Color primaries as defined by Adobe as "Adobe RGB" and later published | |
| 256 | + | by ISO 12640-4 (2011). | |
| 257 | + | </description> | |
| 258 | + | </entry> | |
| 259 | + | </enum> | |
| 260 | + | ||
| 261 | + | <enum name="transfer_function"> | |
| 262 | + | <description summary="named transfer functions"> | |
| 263 | + | Named transfer functions used to represent well-known transfer | |
| 264 | + | characteristics of displays. | |
| 265 | + | ||
| 266 | + | A value of 0 is invalid and will never be present in the list of enums. | |
| 267 | + | ||
| 268 | + | See appendix.md for the formulae. | |
| 269 | + | </description> | |
| 270 | + | ||
| 271 | + | <entry name="bt1886" value="1"> | |
| 272 | + | <description summary="BT.1886 display transfer characteristic"> | |
| 273 | + | Rec. ITU-R BT.1886 is the display transfer characteristic assumed by | |
| 274 | + | - Rec. ITU-R BT.601-7 525 and 625 | |
| 275 | + | - Rec. ITU-R BT.709-6 | |
| 276 | + | - Rec. ITU-R BT.2020-2 | |
| 277 | + | ||
| 278 | + | This TF implies these default luminances from Rec. ITU-R BT.2035: | |
| 279 | + | - primary color volume minimum: 0.01 cd/m² | |
| 280 | + | - primary color volume maximum: 100 cd/m² | |
| 281 | + | - reference white: 100 cd/m² | |
| 282 | + | </description> | |
| 283 | + | </entry> | |
| 284 | + | <entry name="gamma22" value="2"> | |
| 285 | + | <description summary="Assumed display gamma 2.2 transfer function"> | |
| 286 | + | Transfer characteristics as defined by | |
| 287 | + | - Rec. ITU-R BT.470-6 System M (historical) | |
| 288 | + | - United States National Television System Committee 1953 | |
| 289 | + | Recommendation for transmission standards for color television | |
| 290 | + | - United States Federal Communications Commission (2003) Title 47 Code | |
| 291 | + | of Federal Regulations 73.682 (a) (20) | |
| 292 | + | - Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM | |
| 293 | + | - IEC 61966-2-1 (reference display) | |
| 294 | + | </description> | |
| 295 | + | </entry> | |
| 296 | + | <entry name="gamma28" value="3"> | |
| 297 | + | <description summary="Assumed display gamma 2.8 transfer function"> | |
| 298 | + | Transfer characteristics as defined by | |
| 299 | + | - Rec. ITU-R BT.470-6 System B, G (historical) | |
| 300 | + | </description> | |
| 301 | + | </entry> | |
| 302 | + | <entry name="st240" value="4"> | |
| 303 | + | <description summary="SMPTE ST 240 transfer function"> | |
| 304 | + | Transfer characteristics as defined by | |
| 305 | + | - SMPTE ST 240 (1999) | |
| 306 | + | </description> | |
| 307 | + | </entry> | |
| 308 | + | <entry name="ext_linear" value="5"> | |
| 309 | + | <description summary="extended linear transfer function"> | |
| 310 | + | Linear transfer function defined over all real numbers. | |
| 311 | + | Normalised electrical values are equal the normalised optical values. | |
| 312 | + | </description> | |
| 313 | + | </entry> | |
| 314 | + | <entry name="log_100" value="6"> | |
| 315 | + | <description summary="logarithmic 100:1 transfer function"> | |
| 316 | + | Logarithmic transfer characteristic (100:1 range). | |
| 317 | + | </description> | |
| 318 | + | </entry> | |
| 319 | + | <entry name="log_316" value="7"> | |
| 320 | + | <description summary="logarithmic (100*Sqrt(10) : 1) transfer function"> | |
| 321 | + | Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range). | |
| 322 | + | </description> | |
| 323 | + | </entry> | |
| 324 | + | <entry name="xvycc" value="8"> | |
| 325 | + | <description summary="IEC 61966-2-4 transfer function"> | |
| 326 | + | Transfer characteristics as defined by | |
| 327 | + | - IEC 61966-2-4 | |
| 328 | + | </description> | |
| 329 | + | </entry> | |
| 330 | + | <entry name="srgb" value="9" deprecated-since="2"> | |
| 331 | + | <description summary="Deprecated (ambiguous sRGB transfer function)"> | |
| 332 | + | Transfer characteristics as defined by | |
| 333 | + | - IEC 61966-2-1 sRGB | |
| 334 | + | ||
| 335 | + | As a rule of thumb, use gamma22 for video, motion picture and | |
| 336 | + | computer graphics, or compound_power_2_4 for ICC calibrated print | |
| 337 | + | workflows. | |
| 338 | + | </description> | |
| 339 | + | </entry> | |
| 340 | + | <entry name="ext_srgb" value="10" deprecated-since="2"> | |
| 341 | + | <description summary="Deprecated (Extended sRGB piece-wise transfer function)"> | |
| 342 | + | Transfer characteristics as defined by | |
| 343 | + | - IEC 61966-2-1 sYCC | |
| 344 | + | </description> | |
| 345 | + | </entry> | |
| 346 | + | <entry name="st2084_pq" value="11"> | |
| 347 | + | <description summary="perceptual quantizer transfer function"> | |
| 348 | + | Transfer characteristics as defined by | |
| 349 | + | - SMPTE ST 2084 (2014) for 10-, 12-, 14- and 16-bit systems | |
| 350 | + | - Rec. ITU-R BT.2100-2 perceptual quantization (PQ) system | |
| 351 | + | ||
| 352 | + | This TF implies these default luminances | |
| 353 | + | - primary color volume minimum: 0.005 cd/m² | |
| 354 | + | - primary color volume maximum: 10000 cd/m² | |
| 355 | + | - reference white: 203 cd/m² | |
| 356 | + | ||
| 357 | + | The difference between the primary color volume minimum and maximum | |
| 358 | + | must be approximately 10000 cd/m² as that is the swing of the EOTF | |
| 359 | + | defined by ST 2084 and BT.2100. The default value for the | |
| 360 | + | reference white is a protocol addition: it is suggested by | |
| 361 | + | Report ITU-R BT.2408-7 and is not part of ST 2084 or BT.2100. | |
| 362 | + | </description> | |
| 363 | + | </entry> | |
| 364 | + | <entry name="st428" value="12"> | |
| 365 | + | <description summary="SMPTE ST 428 transfer function"> | |
| 366 | + | Transfer characteristics as defined by | |
| 367 | + | - SMPTE ST 428-1 (2019) | |
| 368 | + | </description> | |
| 369 | + | </entry> | |
| 370 | + | <entry name="hlg" value="13"> | |
| 371 | + | <description summary="hybrid log-gamma transfer function"> | |
| 372 | + | Transfer characteristics as defined by | |
| 373 | + | - ARIB STD-B67 (2015) | |
| 374 | + | - Rec. ITU-R BT.2100-2 hybrid log-gamma (HLG) system | |
| 375 | + | ||
| 376 | + | This TF implies these default luminances | |
| 377 | + | - primary color volume minimum: 0.005 cd/m² | |
| 378 | + | - primary color volume maximum: 1000 cd/m² | |
| 379 | + | - reference white: 203 cd/m² | |
| 380 | + | ||
| 381 | + | HLG is a relative display-referred signal with a specified | |
| 382 | + | non-linear mapping to the display peak luminance (the HLG OOTF). | |
| 383 | + | All absolute luminance values used here for HLG assume a 1000 cd/m² | |
| 384 | + | peak display. | |
| 385 | + | ||
| 386 | + | The default value for the reference white is a protocol addition: | |
| 387 | + | it is suggested by Report ITU-R BT.2408-7 and is not part of | |
| 388 | + | ARIB STD-B67 or BT.2100. | |
| 389 | + | </description> | |
| 390 | + | </entry> | |
| 391 | + | <entry name="compound_power_2_4" value="14" since="2"> | |
| 392 | + | <description summary="IEC 61966-2-1 encoding function"> | |
| 393 | + | Encoding characteristics as defined by IEC 61966-2-1, for displays | |
| 394 | + | that invert the encoding function. | |
| 395 | + | </description> | |
| 396 | + | </entry> | |
| 397 | + | </enum> | |
| 398 | + | ||
| 399 | + | <request name="get_output"> | |
| 400 | + | <description summary="create a color management interface for a wl_output"> | |
| 401 | + | This creates a new wp_color_management_output_v1 object for the | |
| 402 | + | given wl_output. | |
| 403 | + | ||
| 404 | + | See the wp_color_management_output_v1 interface for more details. | |
| 405 | + | </description> | |
| 406 | + | ||
| 407 | + | <arg name="id" type="new_id" interface="wp_color_management_output_v1"/> | |
| 408 | + | <arg name="output" type="object" interface="wl_output"/> | |
| 409 | + | </request> | |
| 410 | + | ||
| 411 | + | <request name="get_surface"> | |
| 412 | + | <description summary="create a color management interface for a wl_surface"> | |
| 413 | + | If a wp_color_management_surface_v1 object already exists for the given | |
| 414 | + | wl_surface, the protocol error surface_exists is raised. | |
| 415 | + | ||
| 416 | + | This creates a new color wp_color_management_surface_v1 object for the | |
| 417 | + | given wl_surface. | |
| 418 | + | ||
| 419 | + | See the wp_color_management_surface_v1 interface for more details. | |
| 420 | + | </description> | |
| 421 | + | ||
| 422 | + | <arg name="id" type="new_id" interface="wp_color_management_surface_v1"/> | |
| 423 | + | <arg name="surface" type="object" interface="wl_surface"/> | |
| 424 | + | </request> | |
| 425 | + | ||
| 426 | + | <request name="get_surface_feedback"> | |
| 427 | + | <description summary="create a color management feedback interface"> | |
| 428 | + | This creates a new color wp_color_management_surface_feedback_v1 object | |
| 429 | + | for the given wl_surface. | |
| 430 | + | ||
| 431 | + | See the wp_color_management_surface_feedback_v1 interface for more | |
| 432 | + | details. | |
| 433 | + | </description> | |
| 434 | + | ||
| 435 | + | <arg name="id" type="new_id" | |
| 436 | + | interface="wp_color_management_surface_feedback_v1"/> | |
| 437 | + | <arg name="surface" type="object" interface="wl_surface"/> | |
| 438 | + | </request> | |
| 439 | + | ||
| 440 | + | <request name="create_icc_creator"> | |
| 441 | + | <description summary="make a new ICC-based image description creator object"> | |
| 442 | + | Makes a new ICC-based image description creator object with all | |
| 443 | + | properties initially unset. The client can then use the object's | |
| 444 | + | interface to define all the required properties for an image description | |
| 445 | + | and finally create a wp_image_description_v1 object. | |
| 446 | + | ||
| 447 | + | This request can be used when the compositor advertises | |
| 448 | + | wp_color_manager_v1.feature.icc_v2_v4. | |
| 449 | + | Otherwise this request raises the protocol error unsupported_feature. | |
| 450 | + | </description> | |
| 451 | + | ||
| 452 | + | <arg name="obj" | |
| 453 | + | type="new_id" interface="wp_image_description_creator_icc_v1" | |
| 454 | + | summary="the new creator object"/> | |
| 455 | + | </request> | |
| 456 | + | ||
| 457 | + | <request name="create_parametric_creator"> | |
| 458 | + | <description summary="make a new parametric image description creator object"> | |
| 459 | + | Makes a new parametric image description creator object with all | |
| 460 | + | properties initially unset. The client can then use the object's | |
| 461 | + | interface to define all the required properties for an image description | |
| 462 | + | and finally create a wp_image_description_v1 object. | |
| 463 | + | ||
| 464 | + | This request can be used when the compositor advertises | |
| 465 | + | wp_color_manager_v1.feature.parametric. | |
| 466 | + | Otherwise this request raises the protocol error unsupported_feature. | |
| 467 | + | </description> | |
| 468 | + | ||
| 469 | + | <arg name="obj" | |
| 470 | + | type="new_id" interface="wp_image_description_creator_params_v1" | |
| 471 | + | summary="the new creator object"/> | |
| 472 | + | </request> | |
| 473 | + | ||
| 474 | + | <request name="create_windows_scrgb"> | |
| 475 | + | <description summary="create Windows-scRGB image description object"> | |
| 476 | + | This creates a pre-defined image description for the so-called | |
| 477 | + | Windows-scRGB stimulus encoding. This comes from the Windows 10 handling | |
| 478 | + | of its own definition of an scRGB color space for an HDR screen | |
| 479 | + | driven in BT.2100/PQ signalling mode. | |
| 480 | + | ||
| 481 | + | Windows-scRGB uses sRGB (BT.709) color primaries and white point. | |
| 482 | + | The transfer characteristic is extended linear. | |
| 483 | + | ||
| 484 | + | The nominal color channel value range is extended, meaning it includes | |
| 485 | + | negative and greater than 1.0 values. Negative values are used to | |
| 486 | + | escape the sRGB color gamut boundaries. To make use of the extended | |
| 487 | + | range, the client needs to use a pixel format that can represent those | |
| 488 | + | values, e.g. floating-point 16 bits per channel. | |
| 489 | + | ||
| 490 | + | Nominal color value R=G=B=0.0 corresponds to BT.2100/PQ system | |
| 491 | + | 0 cd/m², and R=G=B=1.0 corresponds to BT.2100/PQ system 80 cd/m². | |
| 492 | + | The maximum is R=G=B=125.0 corresponding to 10k cd/m². | |
| 493 | + | ||
| 494 | + | Windows-scRGB is displayed by Windows 10 by converting it to | |
| 495 | + | BT.2100/PQ, maintaining the CIE 1931 chromaticity and mapping the | |
| 496 | + | luminance as above. No adjustment is made to the signal to account | |
| 497 | + | for the viewing conditions. | |
| 498 | + | ||
| 499 | + | The reference white level of Windows-scRGB is unknown. If a | |
| 500 | + | reference white level must be assumed for compositor processing, it | |
| 501 | + | should be R=G=B=2.5375 corresponding to 203 cd/m² of Report ITU-R | |
| 502 | + | BT.2408-7. | |
| 503 | + | ||
| 504 | + | The target color volume of Windows-scRGB is unknown. The color gamut | |
| 505 | + | may be anything between sRGB and BT.2100. | |
| 506 | + | ||
| 507 | + | Note: EGL_EXT_gl_colorspace_scrgb_linear definition differs from | |
| 508 | + | Windows-scRGB by using R=G=B=1.0 as the reference white level, while | |
| 509 | + | Windows-scRGB reference white level is unknown or varies. However, | |
| 510 | + | it seems probable that Windows implements both | |
| 511 | + | EGL_EXT_gl_colorspace_scrgb_linear and Vulkan | |
| 512 | + | VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT as Windows-scRGB. | |
| 513 | + | ||
| 514 | + | This request can be used when the compositor advertises | |
| 515 | + | wp_color_manager_v1.feature.windows_scrgb. | |
| 516 | + | Otherwise this request raises the protocol error unsupported_feature. | |
| 517 | + | ||
| 518 | + | The resulting image description object does not allow get_information | |
| 519 | + | request. The wp_image_description_v1.ready event shall be sent. | |
| 520 | + | </description> | |
| 521 | + | ||
| 522 | + | <arg name="image_description" | |
| 523 | + | type="new_id" interface="wp_image_description_v1"/> | |
| 524 | + | </request> | |
| 525 | + | ||
| 526 | + | <event name="supported_intent"> | |
| 527 | + | <description summary="supported rendering intent"> | |
| 528 | + | When this object is created, it shall immediately send this event once | |
| 529 | + | for each rendering intent the compositor supports. | |
| 530 | + | ||
| 531 | + | A compositor must not advertise intents that are deprecated in the | |
| 532 | + | bound version of the interface. | |
| 533 | + | </description> | |
| 534 | + | ||
| 535 | + | <arg name="render_intent" type="uint" enum="render_intent" | |
| 536 | + | summary="rendering intent"/> | |
| 537 | + | </event> | |
| 538 | + | ||
| 539 | + | <event name="supported_feature"> | |
| 540 | + | <description summary="supported features"> | |
| 541 | + | When this object is created, it shall immediately send this event once | |
| 542 | + | for each compositor supported feature listed in the enumeration. | |
| 543 | + | ||
| 544 | + | A compositor must not advertise features that are deprecated in the | |
| 545 | + | bound version of the interface. | |
| 546 | + | </description> | |
| 547 | + | ||
| 548 | + | <arg name="feature" type="uint" enum="feature" | |
| 549 | + | summary="supported feature"/> | |
| 550 | + | </event> | |
| 551 | + | ||
| 552 | + | <event name="supported_tf_named"> | |
| 553 | + | <description summary="supported named transfer characteristic"> | |
| 554 | + | When this object is created, it shall immediately send this event once | |
| 555 | + | for each named transfer function the compositor supports with the | |
| 556 | + | parametric image description creator. | |
| 557 | + | ||
| 558 | + | A compositor must not advertise transfer functions that are deprecated | |
| 559 | + | in the bound version of the interface. | |
| 560 | + | </description> | |
| 561 | + | ||
| 562 | + | <arg name="tf" type="uint" enum="transfer_function" | |
| 563 | + | summary="Named transfer function"/> | |
| 564 | + | </event> | |
| 565 | + | ||
| 566 | + | <event name="supported_primaries_named"> | |
| 567 | + | <description summary="supported named primaries"> | |
| 568 | + | When this object is created, it shall immediately send this event once | |
| 569 | + | for each named set of primaries the compositor supports with the | |
| 570 | + | parametric image description creator. | |
| 571 | + | ||
| 572 | + | A compositor must not advertise names that are deprecated in the | |
| 573 | + | bound version of the interface. | |
| 574 | + | </description> | |
| 575 | + | ||
| 576 | + | <arg name="primaries" type="uint" enum="primaries" | |
| 577 | + | summary="Named color primaries"/> | |
| 578 | + | </event> | |
| 579 | + | ||
| 580 | + | <event name="done"> | |
| 581 | + | <description summary="all features have been sent"> | |
| 582 | + | This event is sent when all supported rendering intents, features, | |
| 583 | + | transfer functions and named primaries have been sent. | |
| 584 | + | </description> | |
| 585 | + | </event> | |
| 586 | + | ||
| 587 | + | <request name="get_image_description" since="2"> | |
| 588 | + | <description summary="create an image description from a reference"> | |
| 589 | + | This request retrieves the image description backing a reference. | |
| 590 | + | ||
| 591 | + | The get_information request can be used if and only if the request that | |
| 592 | + | creates the reference allows it. | |
| 593 | + | </description> | |
| 594 | + | ||
| 595 | + | <arg name="image_description" | |
| 596 | + | type="new_id" interface="wp_image_description_v1"/> | |
| 597 | + | <arg name="reference" | |
| 598 | + | type="object" interface="wp_image_description_reference_v1"/> | |
| 599 | + | </request> | |
| 600 | + | ||
| 601 | + | <request name="create_windows_bt2100" since="3"> | |
| 602 | + | <description summary="create Windows-BT.2100 image description object"> | |
| 603 | + | This creates a pre-defined image description for the so-called | |
| 604 | + | Windows-BT.2100 stimulus encoding. This comes from the Windows 10 | |
| 605 | + | handling of its own definition of a BT.2100 color space for an HDR | |
| 606 | + | screen driven in BT.2100/PQ signalling mode. | |
| 607 | + | ||
| 608 | + | Windows-BT.2100 uses BT.2020 color primaries and white point. | |
| 609 | + | The transfer characteristic is st2084_pq. | |
| 610 | + | ||
| 611 | + | Windows-BT.2100 is generally displayed by Windows 10 without any | |
| 612 | + | adjustments to the signal to account for viewing conditions. | |
| 613 | + | ||
| 614 | + | The reference white level of Windows-BT.2100 is unknown. If a | |
| 615 | + | reference white level must be assumed for compositor processing, it | |
| 616 | + | should be 203 cd/m² of Report ITU-R BT.2408-7. | |
| 617 | + | ||
| 618 | + | The target color volume of Windows-BT.2100 is unknown. The color gamut | |
| 619 | + | may be anything up to BT.2100. | |
| 620 | + | ||
| 621 | + | This request can be used when the compositor advertises | |
| 622 | + | wp_color_manager_v1.feature.windows_bt2100. | |
| 623 | + | Otherwise this request raises the protocol error unsupported_feature. | |
| 624 | + | ||
| 625 | + | The resulting image description object does not allow get_information | |
| 626 | + | request. The wp_image_description_v1.ready event shall be sent. | |
| 627 | + | </description> | |
| 628 | + | ||
| 629 | + | <arg name="image_description" | |
| 630 | + | type="new_id" interface="wp_image_description_v1"/> | |
| 631 | + | </request> | |
| 632 | + | </interface> | |
| 633 | + | ||
| 634 | + | <interface name="wp_color_management_output_v1" version="3"> | |
| 635 | + | <description summary="output color properties"> | |
| 636 | + | A wp_color_management_output_v1 describes the color properties of an | |
| 637 | + | output. | |
| 638 | + | ||
| 639 | + | The wp_color_management_output_v1 is associated with the wl_output global | |
| 640 | + | underlying the wl_output object. Therefore the client destroying the | |
| 641 | + | wl_output object has no impact, but the compositor removing the output | |
| 642 | + | global makes the wp_color_management_output_v1 object inert. | |
| 643 | + | </description> | |
| 644 | + | ||
| 645 | + | <request name="destroy" type="destructor"> | |
| 646 | + | <description summary="destroy the color management output"> | |
| 647 | + | Destroy the color wp_color_management_output_v1 object. This does not | |
| 648 | + | affect any remaining protocol objects. | |
| 649 | + | </description> | |
| 650 | + | </request> | |
| 651 | + | ||
| 652 | + | <event name="image_description_changed"> | |
| 653 | + | <description summary="image description changed"> | |
| 654 | + | This event is sent whenever the image description of the output changed, | |
| 655 | + | followed by one wl_output.done event common to output events across all | |
| 656 | + | extensions. | |
| 657 | + | ||
| 658 | + | If the client wants to use the updated image description, it needs to do | |
| 659 | + | get_image_description again, because image description objects are | |
| 660 | + | immutable. | |
| 661 | + | </description> | |
| 662 | + | </event> | |
| 663 | + | ||
| 664 | + | <request name="get_image_description"> | |
| 665 | + | <description summary="get the image description of the output"> | |
| 666 | + | This creates a new wp_image_description_v1 object for the current image | |
| 667 | + | description of the output. There always is exactly one image description | |
| 668 | + | active for an output so the client should destroy the image description | |
| 669 | + | created by earlier invocations of this request. This request is usually | |
| 670 | + | sent as a reaction to the image_description_changed event or when | |
| 671 | + | creating a wp_color_management_output_v1 object. | |
| 672 | + | ||
| 673 | + | The image description of an output represents the color encoding the | |
| 674 | + | output expects. There might be performance and power advantages, as well | |
| 675 | + | as improved color reproduction, if a content update matches the image | |
| 676 | + | description of the output it is being shown on. If a content update is | |
| 677 | + | shown on any other output than the one it matches the image description | |
| 678 | + | of, then the color reproduction on those outputs might be considerably | |
| 679 | + | worse. | |
| 680 | + | ||
| 681 | + | The created wp_image_description_v1 object preserves the image | |
| 682 | + | description of the output from the time the object was created. | |
| 683 | + | ||
| 684 | + | The resulting image description object allows get_information request. | |
| 685 | + | ||
| 686 | + | If this protocol object is inert, the resulting image description object | |
| 687 | + | shall immediately deliver the wp_image_description_v1.failed event with | |
| 688 | + | the no_output cause. | |
| 689 | + | ||
| 690 | + | If the interface version is inadequate for the output's image | |
| 691 | + | description, meaning that the client does not support all the events | |
| 692 | + | needed to deliver the crucial information, the resulting image | |
| 693 | + | description object shall immediately deliver the | |
| 694 | + | wp_image_description_v1.failed event with the low_version cause. | |
| 695 | + | ||
| 696 | + | Otherwise the object shall immediately deliver the ready event. | |
| 697 | + | </description> | |
| 698 | + | ||
| 699 | + | <arg name="image_description" | |
| 700 | + | type="new_id" interface="wp_image_description_v1"/> | |
| 701 | + | </request> | |
| 702 | + | </interface> | |
| 703 | + | ||
| 704 | + | <interface name="wp_color_management_surface_v1" version="3"> | |
| 705 | + | <description summary="color management extension to a surface"> | |
| 706 | + | A wp_color_management_surface_v1 allows the client to set the color | |
| 707 | + | space and HDR properties of a surface. | |
| 708 | + | ||
| 709 | + | If the wl_surface associated with the wp_color_management_surface_v1 is | |
| 710 | + | destroyed, the wp_color_management_surface_v1 object becomes inert. | |
| 711 | + | </description> | |
| 712 | + | ||
| 713 | + | <request name="destroy" type="destructor"> | |
| 714 | + | <description summary="destroy the color management interface for a surface"> | |
| 715 | + | Destroy the wp_color_management_surface_v1 object and do the same as | |
| 716 | + | unset_image_description. | |
| 717 | + | </description> | |
| 718 | + | </request> | |
| 719 | + | ||
| 720 | + | <enum name="error"> | |
| 721 | + | <description summary="protocol errors"/> | |
| 722 | + | <entry name="render_intent" value="0" | |
| 723 | + | summary="unsupported rendering intent"/> | |
| 724 | + | <entry name="image_description" value="1" | |
| 725 | + | summary="invalid image description"/> | |
| 726 | + | <entry name="inert" value="2" | |
| 727 | + | summary="forbidden request on inert object"/> | |
| 728 | + | </enum> | |
| 729 | + | ||
| 730 | + | <request name="set_image_description"> | |
| 731 | + | <description summary="set the surface image description"> | |
| 732 | + | If this protocol object is inert, the protocol error inert is raised. | |
| 733 | + | ||
| 734 | + | Set the image description of the underlying surface. The image | |
| 735 | + | description and rendering intent are double-buffered state, see | |
| 736 | + | wl_surface.commit. | |
| 737 | + | ||
| 738 | + | It is the client's responsibility to understand the image description | |
| 739 | + | it sets on a surface, and to provide content that matches that image | |
| 740 | + | description. Compositors might convert images to match their own or any | |
| 741 | + | other image descriptions. | |
| 742 | + | ||
| 743 | + | Image descriptions which are not ready (see wp_image_description_v1) | |
| 744 | + | are forbidden in this request, and in such case the protocol error | |
| 745 | + | image_description is raised. | |
| 746 | + | ||
| 747 | + | All image descriptions which are ready (see wp_image_description_v1) | |
| 748 | + | are allowed and must always be accepted by the compositor. | |
| 749 | + | ||
| 750 | + | When an image description is set on a surface, it establishes an | |
| 751 | + | explicit link between surface pixel values and surface colorimetry. | |
| 752 | + | This link may be undefined for some pixel values, see the image | |
| 753 | + | description creator interfaces for the conditions. Non-finite | |
| 754 | + | floating-point values (NaN, Inf) always have an undefined colorimetry. | |
| 755 | + | ||
| 756 | + | A rendering intent provides the client's preference on how surface | |
| 757 | + | colorimetry should be mapped to each output. The render_intent value | |
| 758 | + | must be one advertised by the compositor with | |
| 759 | + | wp_color_manager_v1.render_intent event, otherwise the protocol error | |
| 760 | + | render_intent is raised. | |
| 761 | + | ||
| 762 | + | By default, a surface does not have an associated image description | |
| 763 | + | nor a rendering intent. The handling of color on such surfaces is | |
| 764 | + | compositor implementation defined. Compositors should handle such | |
| 765 | + | surfaces as sRGB, but may handle them differently if they have specific | |
| 766 | + | requirements. | |
| 767 | + | ||
| 768 | + | Setting the image description has copy semantics; after this request, | |
| 769 | + | the image description can be immediately destroyed without affecting | |
| 770 | + | the pending state of the surface. | |
| 771 | + | </description> | |
| 772 | + | ||
| 773 | + | <arg name="image_description" | |
| 774 | + | type="object" interface="wp_image_description_v1"/> | |
| 775 | + | <arg name="render_intent" | |
| 776 | + | type="uint" enum="wp_color_manager_v1.render_intent" | |
| 777 | + | summary="rendering intent"/> | |
| 778 | + | </request> | |
| 779 | + | ||
| 780 | + | <request name="unset_image_description"> | |
| 781 | + | <description summary="remove the surface image description"> | |
| 782 | + | If this protocol object is inert, the protocol error inert is raised. | |
| 783 | + | ||
| 784 | + | This request removes any image description from the surface. See | |
| 785 | + | set_image_description for how a compositor handles a surface without | |
| 786 | + | an image description. This is double-buffered state, see | |
| 787 | + | wl_surface.commit. | |
| 788 | + | </description> | |
| 789 | + | </request> | |
| 790 | + | </interface> | |
| 791 | + | ||
| 792 | + | <interface name="wp_color_management_surface_feedback_v1" version="3"> | |
| 793 | + | <description summary="color management extension to a surface"> | |
| 794 | + | A wp_color_management_surface_feedback_v1 allows the client to get the | |
| 795 | + | preferred image description of a surface. | |
| 796 | + | ||
| 797 | + | If the wl_surface associated with this object is destroyed, the | |
| 798 | + | wp_color_management_surface_feedback_v1 object becomes inert. | |
| 799 | + | </description> | |
| 800 | + | ||
| 801 | + | <request name="destroy" type="destructor"> | |
| 802 | + | <description summary="destroy the color management interface for a surface"> | |
| 803 | + | Destroy the wp_color_management_surface_feedback_v1 object. | |
| 804 | + | </description> | |
| 805 | + | </request> | |
| 806 | + | ||
| 807 | + | <enum name="error"> | |
| 808 | + | <description summary="protocol errors"/> | |
| 809 | + | <entry name="inert" value="0" | |
| 810 | + | summary="forbidden request on inert object"/> | |
| 811 | + | <entry name="unsupported_feature" value="1" | |
| 812 | + | summary="attempted to use an unsupported feature"/> | |
| 813 | + | </enum> | |
| 814 | + | ||
| 815 | + | <event name="preferred_changed" deprecated-since="2"> | |
| 816 | + | <description summary="the preferred image description changed (32-bit)"> | |
| 817 | + | Starting from interface version 2, 'preferred_changed2' is sent instead | |
| 818 | + | of this event. See the 'preferred_changed2' event for the definition. | |
| 819 | + | </description> | |
| 820 | + | ||
| 821 | + | <arg name="identity" type="uint" | |
| 822 | + | summary="the 32-bit image description id number"/> | |
| 823 | + | </event> | |
| 824 | + | ||
| 825 | + | <request name="get_preferred"> | |
| 826 | + | <description summary="get the preferred image description"> | |
| 827 | + | If this protocol object is inert, the protocol error inert is raised. | |
| 828 | + | ||
| 829 | + | The preferred image description represents the compositor's preferred | |
| 830 | + | color encoding for this wl_surface at the current time. There might be | |
| 831 | + | performance and power advantages, as well as improved color | |
| 832 | + | reproduction, if the image description of a content update matches the | |
| 833 | + | preferred image description. | |
| 834 | + | ||
| 835 | + | This creates a new wp_image_description_v1 object for the currently | |
| 836 | + | preferred image description for the wl_surface. The client should | |
| 837 | + | stop using and destroy the image descriptions created by earlier | |
| 838 | + | invocations of this request for the associated wl_surface. | |
| 839 | + | This request is usually sent as a reaction to the preferred_changed | |
| 840 | + | event or when creating a wp_color_management_surface_feedback_v1 object | |
| 841 | + | if the client is capable of adapting to image descriptions. | |
| 842 | + | ||
| 843 | + | The created wp_image_description_v1 object preserves the preferred image | |
| 844 | + | description of the wl_surface from the time the object was created. | |
| 845 | + | ||
| 846 | + | The resulting image description object allows get_information request. | |
| 847 | + | ||
| 848 | + | If the image description is parametric, the client should set it on its | |
| 849 | + | wl_surface only if the image description is an exact match with the | |
| 850 | + | client content. Particularly if everything else matches, but the target | |
| 851 | + | color volume is greater than what the client needs, the client should | |
| 852 | + | create its own parameric image description with its exact parameters. | |
| 853 | + | ||
| 854 | + | If the interface version is inadequate for the preferred image | |
| 855 | + | description, meaning that the client does not support all the | |
| 856 | + | events needed to deliver the crucial information, the resulting image | |
| 857 | + | description object shall immediately deliver the | |
| 858 | + | wp_image_description_v1.failed event with the low_version cause, | |
| 859 | + | otherwise the object shall immediately deliver the ready event. | |
| 860 | + | </description> | |
| 861 | + | ||
| 862 | + | <arg name="image_description" | |
| 863 | + | type="new_id" interface="wp_image_description_v1"/> | |
| 864 | + | </request> | |
| 865 | + | ||
| 866 | + | <request name="get_preferred_parametric"> | |
| 867 | + | <description summary="get the preferred image description"> | |
| 868 | + | The same description as for get_preferred applies, except the returned | |
| 869 | + | image description is guaranteed to be parametric. This is meant for | |
| 870 | + | clients that can only deal with parametric image descriptions. | |
| 871 | + | ||
| 872 | + | If the compositor doesn't support parametric image descriptions, the | |
| 873 | + | unsupported_feature error is emitted. | |
| 874 | + | </description> | |
| 875 | + | ||
| 876 | + | <arg name="image_description" | |
| 877 | + | type="new_id" interface="wp_image_description_v1"/> | |
| 878 | + | </request> | |
| 879 | + | ||
| 880 | + | <!-- Version 2 additions --> | |
| 881 | + | ||
| 882 | + | <event name="preferred_changed2" since="2"> | |
| 883 | + | <description summary="the preferred image description changed"> | |
| 884 | + | The preferred image description is the one which likely has the most | |
| 885 | + | performance and/or quality benefits for the compositor if used by the | |
| 886 | + | client for its wl_surface contents. This event is sent whenever the | |
| 887 | + | compositor changes the wl_surface's preferred image description. | |
| 888 | + | ||
| 889 | + | This event sends the identity of the new preferred state as the argument, | |
| 890 | + | so clients who are aware of the image description already can reuse it. | |
| 891 | + | Otherwise, if the client client wants to know what the preferred image | |
| 892 | + | description is, it shall use the get_preferred request. | |
| 893 | + | ||
| 894 | + | The preferred image description is not automatically used for anything. | |
| 895 | + | It is only a hint, and clients may set any valid image description with | |
| 896 | + | set_image_description, but there might be performance and color accuracy | |
| 897 | + | improvements by providing the wl_surface contents in the preferred | |
| 898 | + | image description. Therefore clients that can, should render according | |
| 899 | + | to the preferred image description | |
| 900 | + | </description> | |
| 901 | + | ||
| 902 | + | <arg name="identity_hi" type="uint" | |
| 903 | + | summary="high 32 bits of the 64-bit image description id number"/> | |
| 904 | + | <arg name="identity_lo" type="uint" | |
| 905 | + | summary="low 32 bits of the 64-bit image description id number"/> | |
| 906 | + | </event> | |
| 907 | + | ||
| 908 | + | </interface> | |
| 909 | + | ||
| 910 | + | <interface name="wp_image_description_creator_icc_v1" version="3"> | |
| 911 | + | <description summary="holder of image description ICC information"> | |
| 912 | + | This type of object is used for collecting all the information required | |
| 913 | + | to create a wp_image_description_v1 object from an ICC file. A complete | |
| 914 | + | set of required parameters consists of these properties: | |
| 915 | + | - ICC file | |
| 916 | + | ||
| 917 | + | Each required property must be set exactly once if the client is to create | |
| 918 | + | an image description. The set requests verify that a property was not | |
| 919 | + | already set. The create request verifies that all required properties are | |
| 920 | + | set. There may be several alternative requests for setting each property, | |
| 921 | + | and in that case the client must choose one of them. | |
| 922 | + | ||
| 923 | + | Once all properties have been set, the create request must be used to | |
| 924 | + | create the image description object, destroying the creator in the | |
| 925 | + | process. | |
| 926 | + | ||
| 927 | + | The link between a pixel value (a device value in ICC) and its respective | |
| 928 | + | colorimetry is defined by the details of the particular ICC profile. | |
| 929 | + | Those details also determine when colorimetry becomes undefined. | |
| 930 | + | </description> | |
| 931 | + | ||
| 932 | + | <enum name="error"> | |
| 933 | + | <description summary="protocol errors"/> | |
| 934 | + | ||
| 935 | + | <entry name="incomplete_set" value="0" | |
| 936 | + | summary="incomplete parameter set"/> | |
| 937 | + | <entry name="already_set" value="1" | |
| 938 | + | summary="property already set"/> | |
| 939 | + | <entry name="bad_fd" value="2" | |
| 940 | + | summary="fd not seekable and readable"/> | |
| 941 | + | <entry name="bad_size" value="3" | |
| 942 | + | summary="no or too much data"/> | |
| 943 | + | <entry name="out_of_file" value="4" | |
| 944 | + | summary="offset + length exceeds file size"/> | |
| 945 | + | </enum> | |
| 946 | + | ||
| 947 | + | <request name="create" type="destructor"> | |
| 948 | + | <description summary="Create the image description object from ICC data"> | |
| 949 | + | Create an image description object based on the ICC information | |
| 950 | + | previously set on this object. A compositor must parse the ICC data in | |
| 951 | + | some undefined but finite amount of time. | |
| 952 | + | ||
| 953 | + | The completeness of the parameter set is verified. If the set is not | |
| 954 | + | complete, the protocol error incomplete_set is raised. For the | |
| 955 | + | definition of a complete set, see the description of this interface. | |
| 956 | + | ||
| 957 | + | If the particular combination of the information is not supported | |
| 958 | + | by the compositor, the resulting image description object shall | |
| 959 | + | immediately deliver the wp_image_description_v1.failed event with the | |
| 960 | + | 'unsupported' cause. If a valid image description was created from the | |
| 961 | + | information, the wp_image_description_v1.ready event will eventually | |
| 962 | + | be sent instead. | |
| 963 | + | ||
| 964 | + | This request destroys the wp_image_description_creator_icc_v1 object. | |
| 965 | + | ||
| 966 | + | The resulting image description object does not allow get_information | |
| 967 | + | request. | |
| 968 | + | </description> | |
| 969 | + | ||
| 970 | + | <arg name="image_description" | |
| 971 | + | type="new_id" interface="wp_image_description_v1"/> | |
| 972 | + | </request> | |
| 973 | + | ||
| 974 | + | <request name="set_icc_file"> | |
| 975 | + | <description summary="set the ICC profile file"> | |
| 976 | + | Sets the ICC profile file to be used as the basis of the image | |
| 977 | + | description. | |
| 978 | + | ||
| 979 | + | The data shall be found through the given fd at the given offset, having | |
| 980 | + | the given length. The fd must be seekable and readable. Violating these | |
| 981 | + | requirements raises the bad_fd protocol error. | |
| 982 | + | ||
| 983 | + | If reading the data fails due to an error independent of the client, the | |
| 984 | + | compositor shall send the wp_image_description_v1.failed event on the | |
| 985 | + | created wp_image_description_v1 with the 'operating_system' cause. | |
| 986 | + | ||
| 987 | + | The maximum size of the ICC profile is 32 MB. If length is greater than | |
| 988 | + | that or zero, the protocol error bad_size is raised. If offset + length | |
| 989 | + | exceeds the file size, the protocol error out_of_file is raised. | |
| 990 | + | ||
| 991 | + | A compositor may read the file at any time starting from this request | |
| 992 | + | and only until whichever happens first: | |
| 993 | + | - If create request was issued, the wp_image_description_v1 object | |
| 994 | + | delivers either failed or ready event; or | |
| 995 | + | - if create request was not issued, this | |
| 996 | + | wp_image_description_creator_icc_v1 object is destroyed. | |
| 997 | + | ||
| 998 | + | A compositor shall not modify the contents of the file, and the fd may | |
| 999 | + | be sealed for writes and size changes. The client must ensure to its | |
| 1000 | + | best ability that the data does not change while the compositor is | |
| 1001 | + | reading it. | |
| 1002 | + | ||
| 1003 | + | The data must represent a valid ICC profile. The ICC profile version | |
| 1004 | + | must be 2 or 4, it must be a 3 channel profile and the class must be | |
| 1005 | + | Display or ColorSpace. Violating these requirements will not result in a | |
| 1006 | + | protocol error, but will eventually send the | |
| 1007 | + | wp_image_description_v1.failed event on the created | |
| 1008 | + | wp_image_description_v1 with the 'unsupported' cause. | |
| 1009 | + | ||
| 1010 | + | See the International Color Consortium specification ICC.1:2022 for more | |
| 1011 | + | details about ICC profiles. | |
| 1012 | + | ||
| 1013 | + | If ICC file has already been set on this object, the protocol error | |
| 1014 | + | already_set is raised. | |
| 1015 | + | </description> | |
| 1016 | + | ||
| 1017 | + | <arg name="icc_profile" type="fd" | |
| 1018 | + | summary="ICC profile"/> | |
| 1019 | + | <arg name="offset" type="uint" | |
| 1020 | + | summary="byte offset in fd to start of ICC data"/> | |
| 1021 | + | <arg name="length" type="uint" | |
| 1022 | + | summary="length of ICC data in bytes"/> | |
| 1023 | + | </request> | |
| 1024 | + | </interface> | |
| 1025 | + | ||
| 1026 | + | <interface name="wp_image_description_creator_params_v1" version="3"> | |
| 1027 | + | <description summary="holder of image description parameters"> | |
| 1028 | + | This type of object is used for collecting all the parameters required | |
| 1029 | + | to create a wp_image_description_v1 object. A complete set of required | |
| 1030 | + | parameters consists of these properties: | |
| 1031 | + | - transfer characteristic function (tf) | |
| 1032 | + | - chromaticities of primaries and white point (primary color volume) | |
| 1033 | + | ||
| 1034 | + | The following properties are optional and have a well-defined default | |
| 1035 | + | if not explicitly set: | |
| 1036 | + | - primary color volume luminance range | |
| 1037 | + | - reference white luminance level | |
| 1038 | + | - mastering display primaries and white point (target color volume) | |
| 1039 | + | - mastering luminance range | |
| 1040 | + | ||
| 1041 | + | The following properties are optional and will be ignored | |
| 1042 | + | if not explicitly set: | |
| 1043 | + | - maximum content light level | |
| 1044 | + | - maximum frame-average light level | |
| 1045 | + | ||
| 1046 | + | Each required property must be set exactly once if the client is to create | |
| 1047 | + | an image description. The set requests verify that a property was not | |
| 1048 | + | already set. The create request verifies that all required properties are | |
| 1049 | + | set. There may be several alternative requests for setting each property, | |
| 1050 | + | and in that case the client must choose one of them. | |
| 1051 | + | ||
| 1052 | + | Once all properties have been set, the create request must be used to | |
| 1053 | + | create the image description object, destroying the creator in the | |
| 1054 | + | process. | |
| 1055 | + | ||
| 1056 | + | A viewer, who is viewing the display defined by the resulting image | |
| 1057 | + | description (the viewing environment included), is assumed to be fully | |
| 1058 | + | adapted to the primary color volume's white point. | |
| 1059 | + | ||
| 1060 | + | Any of the following conditions will cause the colorimetry of a pixel | |
| 1061 | + | to become undefined: | |
| 1062 | + | - Values outside of the defined range of the transfer characteristic. | |
| 1063 | + | - Tristimulus that exceeds the target color volume. | |
| 1064 | + | - If extended_target_volume is not supported: tristimulus that exceeds | |
| 1065 | + | the primary color volume. | |
| 1066 | + | ||
| 1067 | + | The closest correspondence to an image description created through this | |
| 1068 | + | interface is the Display class of profiles in ICC. | |
| 1069 | + | </description> | |
| 1070 | + | ||
| 1071 | + | <enum name="error"> | |
| 1072 | + | <description summary="protocol errors"/> | |
| 1073 | + | ||
| 1074 | + | <entry name="incomplete_set" value="0" | |
| 1075 | + | summary="incomplete parameter set"/> | |
| 1076 | + | <entry name="already_set" value="1" | |
| 1077 | + | summary="property already set"/> | |
| 1078 | + | <entry name="unsupported_feature" value="2" | |
| 1079 | + | summary="request not supported"/> | |
| 1080 | + | <entry name="invalid_tf" value="3" | |
| 1081 | + | summary="invalid transfer characteristic"/> | |
| 1082 | + | <entry name="invalid_primaries_named" value="4" | |
| 1083 | + | summary="invalid primaries named"/> | |
| 1084 | + | <entry name="invalid_luminance" value="5" | |
| 1085 | + | summary="invalid luminance value or range"/> | |
| 1086 | + | </enum> | |
| 1087 | + | ||
| 1088 | + | <request name="create" type="destructor"> | |
| 1089 | + | <description summary="Create the image description object using params"> | |
| 1090 | + | Create an image description object based on the parameters previously | |
| 1091 | + | set on this object. | |
| 1092 | + | ||
| 1093 | + | The completeness of the parameter set is verified. If the set is not | |
| 1094 | + | complete, the protocol error incomplete_set is raised. For the | |
| 1095 | + | definition of a complete set, see the description of this interface. | |
| 1096 | + | ||
| 1097 | + | When both max_cll and max_fall are set, max_fall must be less or equal | |
| 1098 | + | to max_cll otherwise the invalid_luminance protocol error is raised. | |
| 1099 | + | ||
| 1100 | + | In version 1, these following conditions also result in the | |
| 1101 | + | invalid_luminance protocol error. Version 2 and later do not have this | |
| 1102 | + | requirement. | |
| 1103 | + | - When max_cll is set, it must be greater than min L and less or equal | |
| 1104 | + | to max L of the mastering luminance range. | |
| 1105 | + | - When max_fall is set, it must be greater than min L and less or equal | |
| 1106 | + | to max L of the mastering luminance range. | |
| 1107 | + | ||
| 1108 | + | If the particular combination of the parameter set is not supported | |
| 1109 | + | by the compositor, the resulting image description object shall | |
| 1110 | + | immediately deliver the wp_image_description_v1.failed event with the | |
| 1111 | + | 'unsupported' cause. If a valid image description was created from the | |
| 1112 | + | parameter set, the wp_image_description_v1.ready event will eventually | |
| 1113 | + | be sent instead. | |
| 1114 | + | ||
| 1115 | + | This request destroys the wp_image_description_creator_params_v1 | |
| 1116 | + | object. | |
| 1117 | + | ||
| 1118 | + | The resulting image description object does not allow get_information | |
| 1119 | + | request. | |
| 1120 | + | </description> | |
| 1121 | + | ||
| 1122 | + | <arg name="image_description" | |
| 1123 | + | type="new_id" interface="wp_image_description_v1"/> | |
| 1124 | + | </request> | |
| 1125 | + | ||
| 1126 | + | <request name="set_tf_named"> | |
| 1127 | + | <description summary="named transfer characteristic"> | |
| 1128 | + | Sets the transfer characteristic using explicitly enumerated named | |
| 1129 | + | functions. | |
| 1130 | + | ||
| 1131 | + | When the resulting image description is attached to an image, the | |
| 1132 | + | content should be decoded according to the industry standard | |
| 1133 | + | practices for the transfer characteristic. | |
| 1134 | + | ||
| 1135 | + | Only names advertised with wp_color_manager_v1 event supported_tf_named | |
| 1136 | + | are allowed. Other values shall raise the protocol error invalid_tf. | |
| 1137 | + | ||
| 1138 | + | If transfer characteristic has already been set on this object, the | |
| 1139 | + | protocol error already_set is raised. | |
| 1140 | + | </description> | |
| 1141 | + | ||
| 1142 | + | <arg name="tf" type="uint" enum="wp_color_manager_v1.transfer_function" | |
| 1143 | + | summary="named transfer function"/> | |
| 1144 | + | </request> | |
| 1145 | + | ||
| 1146 | + | <request name="set_tf_power"> | |
| 1147 | + | <description summary="transfer characteristic as a power curve"> | |
| 1148 | + | Sets the color component transfer characteristic to a power curve with | |
| 1149 | + | the given exponent. Negative values are handled by mirroring the | |
| 1150 | + | positive half of the curve through the origin. The valid domain and | |
| 1151 | + | range of the curve are all finite real numbers. This curve represents | |
| 1152 | + | the conversion from electrical to optical color channel values. | |
| 1153 | + | ||
| 1154 | + | The curve exponent shall be multiplied by 10000 to get the argument eexp | |
| 1155 | + | value to carry the precision of 4 decimals. | |
| 1156 | + | ||
| 1157 | + | The curve exponent must be at least 1.0 and at most 10.0. Otherwise the | |
| 1158 | + | protocol error invalid_tf is raised. | |
| 1159 | + | ||
| 1160 | + | If transfer characteristic has already been set on this object, the | |
| 1161 | + | protocol error already_set is raised. | |
| 1162 | + | ||
| 1163 | + | This request can be used when the compositor advertises | |
| 1164 | + | wp_color_manager_v1.feature.set_tf_power. Otherwise this request raises | |
| 1165 | + | the protocol error unsupported_feature. | |
| 1166 | + | </description> | |
| 1167 | + | ||
| 1168 | + | <arg name="eexp" type="uint" summary="the exponent * 10000"/> | |
| 1169 | + | </request> | |
| 1170 | + | ||
| 1171 | + | <request name="set_primaries_named"> | |
| 1172 | + | <description summary="named primaries"> | |
| 1173 | + | Sets the color primaries and white point using explicitly named sets. | |
| 1174 | + | This describes the primary color volume which is the basis for color | |
| 1175 | + | value encoding. | |
| 1176 | + | ||
| 1177 | + | Only names advertised with wp_color_manager_v1 event | |
| 1178 | + | supported_primaries_named are allowed. Other values shall raise the | |
| 1179 | + | protocol error invalid_primaries_named. | |
| 1180 | + | ||
| 1181 | + | If primaries have already been set on this object, the protocol error | |
| 1182 | + | already_set is raised. | |
| 1183 | + | </description> | |
| 1184 | + | ||
| 1185 | + | <arg name="primaries" type="uint" enum="wp_color_manager_v1.primaries" | |
| 1186 | + | summary="named primaries"/> | |
| 1187 | + | </request> | |
| 1188 | + | ||
| 1189 | + | <request name="set_primaries"> | |
| 1190 | + | <description summary="primaries as chromaticity coordinates"> | |
| 1191 | + | Sets the color primaries and white point using CIE 1931 xy chromaticity | |
| 1192 | + | coordinates. This describes the primary color volume which is the basis | |
| 1193 | + | for color value encoding. | |
| 1194 | + | ||
| 1195 | + | Each coordinate value is multiplied by 1 million to get the argument | |
| 1196 | + | value to carry precision of 6 decimals. | |
| 1197 | + | ||
| 1198 | + | If primaries have already been set on this object, the protocol error | |
| 1199 | + | already_set is raised. | |
| 1200 | + | ||
| 1201 | + | This request can be used if the compositor advertises | |
| 1202 | + | wp_color_manager_v1.feature.set_primaries. Otherwise this request raises | |
| 1203 | + | the protocol error unsupported_feature. | |
| 1204 | + | </description> | |
| 1205 | + | ||
| 1206 | + | <arg name="r_x" type="int" summary="Red x * 1M"/> | |
| 1207 | + | <arg name="r_y" type="int" summary="Red y * 1M"/> | |
| 1208 | + | <arg name="g_x" type="int" summary="Green x * 1M"/> | |
| 1209 | + | <arg name="g_y" type="int" summary="Green y * 1M"/> | |
| 1210 | + | <arg name="b_x" type="int" summary="Blue x * 1M"/> | |
| 1211 | + | <arg name="b_y" type="int" summary="Blue y * 1M"/> | |
| 1212 | + | <arg name="w_x" type="int" summary="White x * 1M"/> | |
| 1213 | + | <arg name="w_y" type="int" summary="White y * 1M"/> | |
| 1214 | + | </request> | |
| 1215 | + | ||
| 1216 | + | <request name="set_luminances"> | |
| 1217 | + | <description summary="primary color volume luminance range and reference white"> | |
| 1218 | + | Sets the primary color volume luminance range and the reference white | |
| 1219 | + | luminance level. These values include the minimum display emission, but | |
| 1220 | + | not external flare. The minimum display emission is assumed to have | |
| 1221 | + | the chromaticity of the primary color volume white point. | |
| 1222 | + | ||
| 1223 | + | The default luminances from | |
| 1224 | + | https://www.color.org/chardata/rgb/srgb.xalter are | |
| 1225 | + | - primary color volume minimum: 0.2 cd/m² | |
| 1226 | + | - primary color volume maximum: 80 cd/m² | |
| 1227 | + | - reference white: 80 cd/m² | |
| 1228 | + | ||
| 1229 | + | Setting a named transfer characteristic can imply other default | |
| 1230 | + | luminances. | |
| 1231 | + | ||
| 1232 | + | The default luminances get overwritten when this request is used. | |
| 1233 | + | With transfer_function.st2084_pq the given 'max_lum' value is ignored, | |
| 1234 | + | and 'max_lum' is taken as 'min_lum' + 10000 cd/m². | |
| 1235 | + | ||
| 1236 | + | 'min_lum' and 'max_lum' specify the minimum and maximum luminances of | |
| 1237 | + | the primary color volume as reproduced by the targeted display. | |
| 1238 | + | ||
| 1239 | + | 'reference_lum' specifies the luminance of the reference white as | |
| 1240 | + | reproduced by the targeted display, and reflects the targeted viewing | |
| 1241 | + | environment. | |
| 1242 | + | ||
| 1243 | + | Compositors should make sure that all content is anchored, meaning that | |
| 1244 | + | an input signal level of 'reference_lum' on one image description and | |
| 1245 | + | another input signal level of 'reference_lum' on another image | |
| 1246 | + | description should produce the same output level, even though the | |
| 1247 | + | 'reference_lum' on both image representations can be different. | |
| 1248 | + | ||
| 1249 | + | 'reference_lum' may be higher than 'max_lum'. In that case reaching | |
| 1250 | + | the reference white output level in image content requires the | |
| 1251 | + | 'extended_target_volume' feature support. | |
| 1252 | + | ||
| 1253 | + | If 'max_lum' or 'reference_lum' are less than or equal to 'min_lum', | |
| 1254 | + | the protocol error invalid_luminance is raised. | |
| 1255 | + | ||
| 1256 | + | The minimum luminance is multiplied by 10000 to get the argument | |
| 1257 | + | 'min_lum' value and carries precision of 4 decimals. The maximum | |
| 1258 | + | luminance and reference white luminance values are unscaled. | |
| 1259 | + | ||
| 1260 | + | If the primary color volume luminance range and the reference white | |
| 1261 | + | luminance level have already been set on this object, the protocol error | |
| 1262 | + | already_set is raised. | |
| 1263 | + | ||
| 1264 | + | This request can be used if the compositor advertises | |
| 1265 | + | wp_color_manager_v1.feature.set_luminances. Otherwise this request | |
| 1266 | + | raises the protocol error unsupported_feature. | |
| 1267 | + | </description> | |
| 1268 | + | ||
| 1269 | + | <arg name="min_lum" type="uint" | |
| 1270 | + | summary="minimum luminance (cd/m²) * 10000"/> | |
| 1271 | + | <arg name="max_lum" type="uint" | |
| 1272 | + | summary="maximum luminance (cd/m²)"/> | |
| 1273 | + | <arg name="reference_lum" type="uint" | |
| 1274 | + | summary="reference white luminance (cd/m²)"/> | |
| 1275 | + | </request> | |
| 1276 | + | ||
| 1277 | + | <request name="set_mastering_display_primaries"> | |
| 1278 | + | <description summary="mastering display primaries as chromaticity coordinates"> | |
| 1279 | + | Provides the color primaries and white point of the mastering display | |
| 1280 | + | using CIE 1931 xy chromaticity coordinates. This is compatible with the | |
| 1281 | + | SMPTE ST 2086 definition of HDR static metadata. | |
| 1282 | + | ||
| 1283 | + | The mastering display primaries and mastering display luminances define | |
| 1284 | + | the target color volume. | |
| 1285 | + | ||
| 1286 | + | If mastering display primaries are not explicitly set, the target color | |
| 1287 | + | volume is assumed to have the same primaries as the primary color volume. | |
| 1288 | + | ||
| 1289 | + | The target color volume is defined by all tristimulus values between 0.0 | |
| 1290 | + | and 1.0 (inclusive) of the color space defined by the given mastering | |
| 1291 | + | display primaries and white point. The colorimetry is identical between | |
| 1292 | + | the container color space and the mastering display color space, | |
| 1293 | + | including that no chromatic adaptation is applied even if the white | |
| 1294 | + | points differ. | |
| 1295 | + | ||
| 1296 | + | The target color volume can exceed the primary color volume to allow for | |
| 1297 | + | a greater color volume with an existing color space definition (for | |
| 1298 | + | example scRGB). It can be smaller than the primary color volume to | |
| 1299 | + | minimize gamut and tone mapping distances for big color spaces (HDR | |
| 1300 | + | metadata). | |
| 1301 | + | ||
| 1302 | + | To make use of the entire target color volume a suitable pixel format | |
| 1303 | + | has to be chosen (e.g. floating point to exceed the primary color | |
| 1304 | + | volume, or abusing limited quantization range as with xvYCC). | |
| 1305 | + | ||
| 1306 | + | Each coordinate value is multiplied by 1 million to get the argument | |
| 1307 | + | value to carry precision of 6 decimals. | |
| 1308 | + | ||
| 1309 | + | If mastering display primaries have already been set on this object, the | |
| 1310 | + | protocol error already_set is raised. | |
| 1311 | + | ||
| 1312 | + | This request can be used if the compositor advertises | |
| 1313 | + | wp_color_manager_v1.feature.set_mastering_display_primaries. Otherwise | |
| 1314 | + | this request raises the protocol error unsupported_feature. The | |
| 1315 | + | advertisement implies support only for target color volumes fully | |
| 1316 | + | contained within the primary color volume. | |
| 1317 | + | ||
| 1318 | + | If a compositor additionally supports target color volume exceeding the | |
| 1319 | + | primary color volume, it must advertise | |
| 1320 | + | wp_color_manager_v1.feature.extended_target_volume. If a client uses | |
| 1321 | + | target color volume exceeding the primary color volume and the | |
| 1322 | + | compositor does not support it, the result is implementation defined. | |
| 1323 | + | Compositors are recommended to detect this case and fail the image | |
| 1324 | + | description gracefully, but it may as well result in color artifacts. | |
| 1325 | + | </description> | |
| 1326 | + | ||
| 1327 | + | <arg name="r_x" type="int" summary="Red x * 1M"/> | |
| 1328 | + | <arg name="r_y" type="int" summary="Red y * 1M"/> | |
| 1329 | + | <arg name="g_x" type="int" summary="Green x * 1M"/> | |
| 1330 | + | <arg name="g_y" type="int" summary="Green y * 1M"/> | |
| 1331 | + | <arg name="b_x" type="int" summary="Blue x * 1M"/> | |
| 1332 | + | <arg name="b_y" type="int" summary="Blue y * 1M"/> | |
| 1333 | + | <arg name="w_x" type="int" summary="White x * 1M"/> | |
| 1334 | + | <arg name="w_y" type="int" summary="White y * 1M"/> | |
| 1335 | + | </request> | |
| 1336 | + | ||
| 1337 | + | <request name="set_mastering_luminance"> | |
| 1338 | + | <description summary="display mastering luminance range"> | |
| 1339 | + | Sets the luminance range that was used during the content mastering | |
| 1340 | + | process as the minimum and maximum absolute luminance L. These values | |
| 1341 | + | include the minimum display emission and ambient flare luminances, | |
| 1342 | + | assumed to be optically additive and have the chromaticity of the | |
| 1343 | + | primary color volume white point. This should be | |
| 1344 | + | compatible with the SMPTE ST 2086 definition of HDR static metadata. | |
| 1345 | + | ||
| 1346 | + | The mastering display primaries and mastering display luminances define | |
| 1347 | + | the target color volume. | |
| 1348 | + | ||
| 1349 | + | If mastering luminances are not explicitly set, the target color volume | |
| 1350 | + | is assumed to have the same min and max luminances as the primary color | |
| 1351 | + | volume. | |
| 1352 | + | ||
| 1353 | + | If max L is less than or equal to min L, the protocol error | |
| 1354 | + | invalid_luminance is raised. | |
| 1355 | + | ||
| 1356 | + | Min L value is multiplied by 10000 to get the argument min_lum value | |
| 1357 | + | and carry precision of 4 decimals. Max L value is unscaled for max_lum. | |
| 1358 | + | ||
| 1359 | + | This request can be used if the compositor advertises | |
| 1360 | + | wp_color_manager_v1.feature.set_mastering_display_primaries. Otherwise | |
| 1361 | + | this request raises the protocol error unsupported_feature. The | |
| 1362 | + | advertisement implies support only for target color volumes fully | |
| 1363 | + | contained within the primary color volume. | |
| 1364 | + | ||
| 1365 | + | If a compositor additionally supports target color volume exceeding the | |
| 1366 | + | primary color volume, it must advertise | |
| 1367 | + | wp_color_manager_v1.feature.extended_target_volume. If a client uses | |
| 1368 | + | target color volume exceeding the primary color volume and the | |
| 1369 | + | compositor does not support it, the result is implementation defined. | |
| 1370 | + | Compositors are recommended to detect this case and fail the image | |
| 1371 | + | description gracefully, but it may as well result in color artifacts. | |
| 1372 | + | </description> | |
| 1373 | + | ||
| 1374 | + | <arg name="min_lum" type="uint" summary="min L (cd/m²) * 10000"/> | |
| 1375 | + | <arg name="max_lum" type="uint" summary="max L (cd/m²)"/> | |
| 1376 | + | </request> | |
| 1377 | + | ||
| 1378 | + | <request name="set_max_cll"> | |
| 1379 | + | <description summary="maximum content light level"> | |
| 1380 | + | Sets the maximum content light level (max_cll) as defined by CTA-861-H. | |
| 1381 | + | ||
| 1382 | + | max_cll is undefined by default. | |
| 1383 | + | </description> | |
| 1384 | + | ||
| 1385 | + | <arg name="max_cll" type="uint" summary="Maximum content light level (cd/m²)"/> | |
| 1386 | + | </request> | |
| 1387 | + | ||
| 1388 | + | <request name="set_max_fall"> | |
| 1389 | + | <description summary="maximum frame-average light level"> | |
| 1390 | + | Sets the maximum frame-average light level (max_fall) as defined by | |
| 1391 | + | CTA-861-H. | |
| 1392 | + | ||
| 1393 | + | max_fall is undefined by default. | |
| 1394 | + | </description> | |
| 1395 | + | ||
| 1396 | + | <arg name="max_fall" type="uint" summary="Maximum frame-average light level (cd/m²)"/> | |
| 1397 | + | </request> | |
| 1398 | + | </interface> | |
| 1399 | + | ||
| 1400 | + | <interface name="wp_image_description_v1" version="3"> | |
| 1401 | + | <description summary="Colorimetric image description"> | |
| 1402 | + | An image description carries information about the pixel color encoding | |
| 1403 | + | and its intended display and viewing environment. The image description is | |
| 1404 | + | attached to a wl_surface via | |
| 1405 | + | wp_color_management_surface_v1.set_image_description. A compositor can use | |
| 1406 | + | this information to decode pixel values into colorimetrically meaningful | |
| 1407 | + | quantities, which allows the compositor to transform the surface contents | |
| 1408 | + | to become suitable for various displays and viewing environments. | |
| 1409 | + | ||
| 1410 | + | Note, that the wp_image_description_v1 object is not ready to be used | |
| 1411 | + | immediately after creation. The object eventually delivers either the | |
| 1412 | + | 'ready' or the 'failed' event, specified in all requests creating it. The | |
| 1413 | + | object is deemed "ready" after receiving the 'ready' event. | |
| 1414 | + | ||
| 1415 | + | An object which is not ready is illegal to use, it can only be destroyed. | |
| 1416 | + | Any other request in this interface shall result in the 'not_ready' | |
| 1417 | + | protocol error. Attempts to use an object which is not ready through other | |
| 1418 | + | interfaces shall raise protocol errors defined there. | |
| 1419 | + | ||
| 1420 | + | Once created and regardless of how it was created, a | |
| 1421 | + | wp_image_description_v1 object always refers to one fixed image | |
| 1422 | + | description. It cannot change after creation. | |
| 1423 | + | </description> | |
| 1424 | + | ||
| 1425 | + | <request name="destroy" type="destructor"> | |
| 1426 | + | <description summary="destroy the image description"> | |
| 1427 | + | Destroy this object. It is safe to destroy an object which is not ready. | |
| 1428 | + | ||
| 1429 | + | Destroying a wp_image_description_v1 object has no side-effects, not | |
| 1430 | + | even if a wp_color_management_surface_v1.set_image_description has not | |
| 1431 | + | yet been followed by a wl_surface.commit. | |
| 1432 | + | </description> | |
| 1433 | + | </request> | |
| 1434 | + | ||
| 1435 | + | <enum name="error"> | |
| 1436 | + | <description summary="protocol errors"/> | |
| 1437 | + | ||
| 1438 | + | <entry name="not_ready" value="0" | |
| 1439 | + | summary="attempted to use an object which is not ready"/> | |
| 1440 | + | <entry name="no_information" value="1" | |
| 1441 | + | summary="get_information not allowed"/> | |
| 1442 | + | </enum> | |
| 1443 | + | ||
| 1444 | + | <enum name="cause"> | |
| 1445 | + | <description summary="generic reason for failure"/> | |
| 1446 | + | ||
| 1447 | + | <entry name="low_version" value="0" | |
| 1448 | + | summary="interface version too low"/> | |
| 1449 | + | <entry name="unsupported" value="1" | |
| 1450 | + | summary="unsupported image description data"/> | |
| 1451 | + | <entry name="operating_system" value="2" | |
| 1452 | + | summary="error independent of the client"/> | |
| 1453 | + | <entry name="no_output" value="3" | |
| 1454 | + | summary="the relevant output no longer exists"/> | |
| 1455 | + | </enum> | |
| 1456 | + | ||
| 1457 | + | <event name="failed"> | |
| 1458 | + | <description summary="graceful error on creating the image description"> | |
| 1459 | + | If creating a wp_image_description_v1 object fails for a reason that is | |
| 1460 | + | not defined as a protocol error, this event is sent. | |
| 1461 | + | ||
| 1462 | + | The requests that create image description objects define whether and | |
| 1463 | + | when this can occur. Only such creation requests can trigger this event. | |
| 1464 | + | This event cannot be triggered after the image description was | |
| 1465 | + | successfully formed. | |
| 1466 | + | ||
| 1467 | + | Once this event has been sent, the wp_image_description_v1 object will | |
| 1468 | + | never become ready and it can only be destroyed. | |
| 1469 | + | </description> | |
| 1470 | + | ||
| 1471 | + | <arg name="cause" type="uint" enum="cause" | |
| 1472 | + | summary="generic reason"/> | |
| 1473 | + | <arg name="msg" type="string" | |
| 1474 | + | summary="ad hoc human-readable explanation"/> | |
| 1475 | + | </event> | |
| 1476 | + | ||
| 1477 | + | <event name="ready" deprecated-since="2"> | |
| 1478 | + | <description summary="the object is ready to be used (32-bit)"> | |
| 1479 | + | Starting from interface version 2, the 'ready2' event is sent instead | |
| 1480 | + | of this event. | |
| 1481 | + | ||
| 1482 | + | For the definition of this event, see the 'ready2' event. The | |
| 1483 | + | difference to this event is as follows. | |
| 1484 | + | ||
| 1485 | + | The id number is valid only as long as the protocol object is alive. If | |
| 1486 | + | all protocol objects referring to the same image description record are | |
| 1487 | + | destroyed, the id number may be recycled for a different image | |
| 1488 | + | description record. | |
| 1489 | + | </description> | |
| 1490 | + | ||
| 1491 | + | <arg name="identity" type="uint" | |
| 1492 | + | summary="the 32-bit image description id number"/> | |
| 1493 | + | </event> | |
| 1494 | + | ||
| 1495 | + | <request name="get_information"> | |
| 1496 | + | <description summary="get information about the image description"> | |
| 1497 | + | Creates a wp_image_description_info_v1 object which delivers the | |
| 1498 | + | information that makes up the image description. | |
| 1499 | + | ||
| 1500 | + | Not all image description protocol objects allow get_information | |
| 1501 | + | request. Whether it is allowed or not is defined by the request that | |
| 1502 | + | created the object. If get_information is not allowed, the protocol | |
| 1503 | + | error no_information is raised. | |
| 1504 | + | </description> | |
| 1505 | + | ||
| 1506 | + | <arg name="information" | |
| 1507 | + | type="new_id" interface="wp_image_description_info_v1"/> | |
| 1508 | + | </request> | |
| 1509 | + | ||
| 1510 | + | <!-- Version 2 additions --> | |
| 1511 | + | ||
| 1512 | + | <event name="ready2" since="2"> | |
| 1513 | + | <description summary="the object is ready to be used"> | |
| 1514 | + | Once this event has been sent, the wp_image_description_v1 object is | |
| 1515 | + | deemed "ready". Ready objects can be used to send requests and can be | |
| 1516 | + | used through other interfaces. | |
| 1517 | + | ||
| 1518 | + | Every ready wp_image_description_v1 protocol object refers to an | |
| 1519 | + | underlying image description record in the compositor. Multiple protocol | |
| 1520 | + | objects may end up referring to the same record. Clients may identify | |
| 1521 | + | these "copies" by comparing their id numbers: if the numbers from two | |
| 1522 | + | protocol objects are identical, the protocol objects refer to the same | |
| 1523 | + | image description record. Two different image description records | |
| 1524 | + | cannot have the same id number simultaneously. The id number does not | |
| 1525 | + | change during the lifetime of the image description record. | |
| 1526 | + | ||
| 1527 | + | Image description id number is not a protocol object id. Zero is | |
| 1528 | + | reserved as an invalid id number. It shall not be possible for a client | |
| 1529 | + | to refer to an image description by its id number in protocol. The id | |
| 1530 | + | numbers might not be portable between Wayland connections. A compositor | |
| 1531 | + | shall not send an invalid id number. | |
| 1532 | + | ||
| 1533 | + | Compositors must not recycle image description id numbers. | |
| 1534 | + | ||
| 1535 | + | This identity allows clients to de-duplicate image description records | |
| 1536 | + | and avoid get_information request if they already have the image | |
| 1537 | + | description information. | |
| 1538 | + | </description> | |
| 1539 | + | ||
| 1540 | + | <arg name="identity_hi" type="uint" | |
| 1541 | + | summary="high 32 bits of the 64-bit image description id number"/> | |
| 1542 | + | <arg name="identity_lo" type="uint" | |
| 1543 | + | summary="low 32 bits of the 64-bit image description id number"/> | |
| 1544 | + | </event> | |
| 1545 | + | </interface> | |
| 1546 | + | ||
| 1547 | + | <interface name="wp_image_description_info_v1" version="3"> | |
| 1548 | + | <description summary="Colorimetric image description information"> | |
| 1549 | + | Sends all matching events describing an image description object exactly | |
| 1550 | + | once and finally sends the 'done' event. | |
| 1551 | + | ||
| 1552 | + | This means | |
| 1553 | + | - if the image description is parametric, it must send | |
| 1554 | + | - primaries | |
| 1555 | + | - named_primaries, if applicable | |
| 1556 | + | - at least one of tf_power and tf_named, as applicable | |
| 1557 | + | - luminances | |
| 1558 | + | - target_primaries | |
| 1559 | + | - target_luminance | |
| 1560 | + | - if the image description is parametric, it may send, if applicable, | |
| 1561 | + | - target_max_cll | |
| 1562 | + | - target_max_fall | |
| 1563 | + | - if the image description contains an ICC profile, it must send the | |
| 1564 | + | icc_file event | |
| 1565 | + | ||
| 1566 | + | Once a wp_image_description_info_v1 object has delivered a 'done' event it | |
| 1567 | + | is automatically destroyed. | |
| 1568 | + | ||
| 1569 | + | Every wp_image_description_info_v1 created from the same | |
| 1570 | + | wp_image_description_v1 shall always return the exact same data. | |
| 1571 | + | </description> | |
| 1572 | + | ||
| 1573 | + | <event name="done" type="destructor"> | |
| 1574 | + | <description summary="end of information"> | |
| 1575 | + | Signals the end of information events and destroys the object. | |
| 1576 | + | </description> | |
| 1577 | + | </event> | |
| 1578 | + | ||
| 1579 | + | <event name="icc_file"> | |
| 1580 | + | <description summary="ICC profile matching the image description"> | |
| 1581 | + | The icc argument provides a file descriptor to the client which may be | |
| 1582 | + | memory-mapped to provide the ICC profile matching the image description. | |
| 1583 | + | The fd is read-only, and if mapped then it must be mapped with | |
| 1584 | + | MAP_PRIVATE by the client. | |
| 1585 | + | ||
| 1586 | + | The ICC profile version and other details are determined by the | |
| 1587 | + | compositor. There is no provision for a client to ask for a specific | |
| 1588 | + | kind of a profile. | |
| 1589 | + | </description> | |
| 1590 | + | ||
| 1591 | + | <arg name="icc" type="fd" summary="ICC profile file descriptor"/> | |
| 1592 | + | <arg name="icc_size" type="uint" summary="ICC profile size, in bytes"/> | |
| 1593 | + | <!-- Offset always 0, compositor must not expose unnecessary data. --> | |
| 1594 | + | </event> | |
| 1595 | + | ||
| 1596 | + | <event name="primaries"> | |
| 1597 | + | <description summary="primaries as chromaticity coordinates"> | |
| 1598 | + | Delivers the primary color volume primaries and white point using CIE | |
| 1599 | + | 1931 xy chromaticity coordinates. | |
| 1600 | + | ||
| 1601 | + | Each coordinate value is multiplied by 1 million to get the argument | |
| 1602 | + | value to carry precision of 6 decimals. | |
| 1603 | + | </description> | |
| 1604 | + | ||
| 1605 | + | <arg name="r_x" type="int" summary="Red x * 1M"/> | |
| 1606 | + | <arg name="r_y" type="int" summary="Red y * 1M"/> | |
| 1607 | + | <arg name="g_x" type="int" summary="Green x * 1M"/> | |
| 1608 | + | <arg name="g_y" type="int" summary="Green y * 1M"/> | |
| 1609 | + | <arg name="b_x" type="int" summary="Blue x * 1M"/> | |
| 1610 | + | <arg name="b_y" type="int" summary="Blue y * 1M"/> | |
| 1611 | + | <arg name="w_x" type="int" summary="White x * 1M"/> | |
| 1612 | + | <arg name="w_y" type="int" summary="White y * 1M"/> | |
| 1613 | + | </event> | |
| 1614 | + | ||
| 1615 | + | <event name="primaries_named"> | |
| 1616 | + | <description summary="named primaries"> | |
| 1617 | + | Delivers the primary color volume primaries and white point using an | |
| 1618 | + | explicitly enumerated named set. | |
| 1619 | + | </description> | |
| 1620 | + | ||
| 1621 | + | <arg name="primaries" type="uint" enum="wp_color_manager_v1.primaries" | |
| 1622 | + | summary="named primaries"/> | |
| 1623 | + | </event> | |
| 1624 | + | ||
| 1625 | + | <event name="tf_power"> | |
| 1626 | + | <description summary="transfer characteristic as a power curve"> | |
| 1627 | + | The color component transfer characteristic of this image description is | |
| 1628 | + | a pure power curve. This event provides the exponent of the power | |
| 1629 | + | function. This curve represents the conversion from electrical to | |
| 1630 | + | optical pixel or color values. | |
| 1631 | + | ||
| 1632 | + | The curve exponent has been multiplied by 10000 to get the argument eexp | |
| 1633 | + | value to carry the precision of 4 decimals. | |
| 1634 | + | </description> | |
| 1635 | + | ||
| 1636 | + | <arg name="eexp" type="uint" summary="the exponent * 10000"/> | |
| 1637 | + | </event> | |
| 1638 | + | ||
| 1639 | + | <event name="tf_named"> | |
| 1640 | + | <description summary="named transfer characteristic"> | |
| 1641 | + | Delivers the transfer characteristic using an explicitly enumerated | |
| 1642 | + | named function. | |
| 1643 | + | </description> | |
| 1644 | + | ||
| 1645 | + | <arg name="tf" type="uint" enum="wp_color_manager_v1.transfer_function" | |
| 1646 | + | summary="named transfer function"/> | |
| 1647 | + | </event> | |
| 1648 | + | ||
| 1649 | + | <event name="luminances"> | |
| 1650 | + | <description summary="primary color volume luminance range and reference white"> | |
| 1651 | + | Delivers the primary color volume luminance range and the reference | |
| 1652 | + | white luminance level. These values include the minimum display emission | |
| 1653 | + | and ambient flare luminances, assumed to be optically additive and have | |
| 1654 | + | the chromaticity of the primary color volume white point. | |
| 1655 | + | ||
| 1656 | + | The minimum luminance is multiplied by 10000 to get the argument | |
| 1657 | + | 'min_lum' value and carries precision of 4 decimals. The maximum | |
| 1658 | + | luminance and reference white luminance values are unscaled. | |
| 1659 | + | </description> | |
| 1660 | + | ||
| 1661 | + | <arg name="min_lum" type="uint" | |
| 1662 | + | summary="minimum luminance (cd/m²) * 10000"/> | |
| 1663 | + | <arg name="max_lum" type="uint" | |
| 1664 | + | summary="maximum luminance (cd/m²)"/> | |
| 1665 | + | <arg name="reference_lum" type="uint" | |
| 1666 | + | summary="reference white luminance (cd/m²)"/> | |
| 1667 | + | </event> | |
| 1668 | + | ||
| 1669 | + | <event name="target_primaries"> | |
| 1670 | + | <description summary="target primaries as chromaticity coordinates"> | |
| 1671 | + | Provides the color primaries and white point of the target color volume | |
| 1672 | + | using CIE 1931 xy chromaticity coordinates. This is compatible with the | |
| 1673 | + | SMPTE ST 2086 definition of HDR static metadata for mastering displays. | |
| 1674 | + | ||
| 1675 | + | While primary color volume is about how color is encoded, the target | |
| 1676 | + | color volume is the actually displayable color volume. | |
| 1677 | + | ||
| 1678 | + | Each coordinate value is multiplied by 1 million to get the argument | |
| 1679 | + | value to carry precision of 6 decimals. | |
| 1680 | + | </description> | |
| 1681 | + | ||
| 1682 | + | <arg name="r_x" type="int" summary="Red x * 1M"/> | |
| 1683 | + | <arg name="r_y" type="int" summary="Red y * 1M"/> | |
| 1684 | + | <arg name="g_x" type="int" summary="Green x * 1M"/> | |
| 1685 | + | <arg name="g_y" type="int" summary="Green y * 1M"/> | |
| 1686 | + | <arg name="b_x" type="int" summary="Blue x * 1M"/> | |
| 1687 | + | <arg name="b_y" type="int" summary="Blue y * 1M"/> | |
| 1688 | + | <arg name="w_x" type="int" summary="White x * 1M"/> | |
| 1689 | + | <arg name="w_y" type="int" summary="White y * 1M"/> | |
| 1690 | + | </event> | |
| 1691 | + | ||
| 1692 | + | <event name="target_luminance"> | |
| 1693 | + | <description summary="target luminance range"> | |
| 1694 | + | Provides the luminance range that the image description is targeting as | |
| 1695 | + | the minimum and maximum absolute luminance L. These values include the | |
| 1696 | + | minimum display emission and ambient flare luminances, assumed to be | |
| 1697 | + | optically additive and have the chromaticity of the primary color | |
| 1698 | + | volume white point. This should be compatible with the SMPTE ST 2086 | |
| 1699 | + | definition of HDR static metadata. | |
| 1700 | + | ||
| 1701 | + | This luminance range is only theoretical and may not correspond to the | |
| 1702 | + | luminance of light emitted on an actual display. | |
| 1703 | + | ||
| 1704 | + | Min L value is multiplied by 10000 to get the argument min_lum value and | |
| 1705 | + | carry precision of 4 decimals. Max L value is unscaled for max_lum. | |
| 1706 | + | </description> | |
| 1707 | + | ||
| 1708 | + | <arg name="min_lum" type="uint" summary="min L (cd/m²) * 10000"/> | |
| 1709 | + | <arg name="max_lum" type="uint" summary="max L (cd/m²)"/> | |
| 1710 | + | </event> | |
| 1711 | + | ||
| 1712 | + | <event name="target_max_cll"> | |
| 1713 | + | <description summary="target maximum content light level"> | |
| 1714 | + | Provides the targeted max_cll of the image description. max_cll is | |
| 1715 | + | defined by CTA-861-H. | |
| 1716 | + | ||
| 1717 | + | This luminance is only theoretical and may not correspond to the | |
| 1718 | + | luminance of light emitted on an actual display. | |
| 1719 | + | </description> | |
| 1720 | + | ||
| 1721 | + | <arg name="max_cll" type="uint" | |
| 1722 | + | summary="Maximum content light-level (cd/m²)"/> | |
| 1723 | + | </event> | |
| 1724 | + | ||
| 1725 | + | <event name="target_max_fall"> | |
| 1726 | + | <description summary="target maximum frame-average light level"> | |
| 1727 | + | Provides the targeted max_fall of the image description. max_fall is | |
| 1728 | + | defined by CTA-861-H. | |
| 1729 | + | ||
| 1730 | + | This luminance is only theoretical and may not correspond to the | |
| 1731 | + | luminance of light emitted on an actual display. | |
| 1732 | + | </description> | |
| 1733 | + | ||
| 1734 | + | <arg name="max_fall" type="uint" | |
| 1735 | + | summary="Maximum frame-average light level (cd/m²)"/> | |
| 1736 | + | </event> | |
| 1737 | + | </interface> | |
| 1738 | + | ||
| 1739 | + | <interface name="wp_image_description_reference_v1" version="1" frozen="true"> | |
| 1740 | + | <description summary="Reference to an image description"> | |
| 1741 | + | This object is a reference to an image description. This interface is | |
| 1742 | + | frozen at version 1 to allow other protocols to create | |
| 1743 | + | wp_image_description_v1 objects. | |
| 1744 | + | ||
| 1745 | + | The wp_color_manager_v1.get_image_description request can be used to | |
| 1746 | + | retrieve the underlying image description. | |
| 1747 | + | </description> | |
| 1748 | + | ||
| 1749 | + | <request name="destroy" type="destructor"> | |
| 1750 | + | <description summary="destroy the reference"> | |
| 1751 | + | Destroy this object. This has no effect on the referenced image | |
| 1752 | + | description. | |
| 1753 | + | </description> | |
| 1754 | + | </request> | |
| 1755 | + | </interface> | |
| 1756 | + | </protocol> | |
A protocol/colormanagement/color-management-v1_generated.go +1554 -0
| @@ -0,0 +1,1554 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: color_management_v1 | |
| 3 | + | // Source: color-management-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright 2019 Sebastian Wick | |
| 7 | + | // Copyright 2019 Erwin Burema | |
| 8 | + | // Copyright 2020 AMD | |
| 9 | + | // Copyright 2020-2024 Collabora, Ltd. | |
| 10 | + | // Copyright 2024 Xaver Hugl | |
| 11 | + | // Copyright 2022-2025 Red Hat, Inc. | |
| 12 | + | // | |
| 13 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 14 | + | // copy of this software and associated documentation files (the "Software"), | |
| 15 | + | // to deal in the Software without restriction, including without limitation | |
| 16 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 17 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 18 | + | // Software is furnished to do so, subject to the following conditions: | |
| 19 | + | // | |
| 20 | + | // The above copyright notice and this permission notice (including the next | |
| 21 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 22 | + | // Software. | |
| 23 | + | // | |
| 24 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 25 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 26 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 27 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 28 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 29 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 30 | + | // DEALINGS IN THE SOFTWARE. | |
| 31 | + | ||
| 32 | + | package colormanagement | |
| 33 | + | ||
| 34 | + | import ( | |
| 35 | + | "sync" | |
| 36 | + | ||
| 37 | + | cross_wl_output "github.com/bnema/wlturbo/protocol/core" | |
| 38 | + | cross_wl_surface "github.com/bnema/wlturbo/protocol/core" | |
| 39 | + | "github.com/bnema/wlturbo/wl" | |
| 40 | + | ) | |
| 41 | + | ||
| 42 | + | // WP_COLOR_MANAGER_V1_ERROR_UNSUPPORTED_FEATURE is the error unsupported_feature value. | |
| 43 | + | const WP_COLOR_MANAGER_V1_ERROR_UNSUPPORTED_FEATURE = 0 | |
| 44 | + | ||
| 45 | + | // ERROR_SURFACE_EXISTS is the error surface_exists value. | |
| 46 | + | const ERROR_SURFACE_EXISTS = 1 | |
| 47 | + | ||
| 48 | + | // RENDER_INTENT_PERCEPTUAL is the render_intent perceptual value. | |
| 49 | + | const RENDER_INTENT_PERCEPTUAL = 0 | |
| 50 | + | ||
| 51 | + | // RENDER_INTENT_RELATIVE is the render_intent relative value. | |
| 52 | + | const RENDER_INTENT_RELATIVE = 1 | |
| 53 | + | ||
| 54 | + | // RENDER_INTENT_SATURATION is the render_intent saturation value. | |
| 55 | + | const RENDER_INTENT_SATURATION = 2 | |
| 56 | + | ||
| 57 | + | // RENDER_INTENT_ABSOLUTE is the render_intent absolute value. | |
| 58 | + | const RENDER_INTENT_ABSOLUTE = 3 | |
| 59 | + | ||
| 60 | + | // RENDER_INTENT_RELATIVE_BPC is the render_intent relative_bpc value. | |
| 61 | + | const RENDER_INTENT_RELATIVE_BPC = 4 | |
| 62 | + | ||
| 63 | + | // RENDER_INTENT_ABSOLUTE_NO_ADAPTATION is the render_intent absolute_no_adaptation value. | |
| 64 | + | const RENDER_INTENT_ABSOLUTE_NO_ADAPTATION = 5 | |
| 65 | + | ||
| 66 | + | // FEATURE_ICC_V2_V4 is the feature icc_v2_v4 value. | |
| 67 | + | const FEATURE_ICC_V2_V4 = 0 | |
| 68 | + | ||
| 69 | + | // FEATURE_PARAMETRIC is the feature parametric value. | |
| 70 | + | const FEATURE_PARAMETRIC = 1 | |
| 71 | + | ||
| 72 | + | // FEATURE_SET_PRIMARIES is the feature set_primaries value. | |
| 73 | + | const FEATURE_SET_PRIMARIES = 2 | |
| 74 | + | ||
| 75 | + | // FEATURE_SET_TF_POWER is the feature set_tf_power value. | |
| 76 | + | const FEATURE_SET_TF_POWER = 3 | |
| 77 | + | ||
| 78 | + | // FEATURE_SET_LUMINANCES is the feature set_luminances value. | |
| 79 | + | const FEATURE_SET_LUMINANCES = 4 | |
| 80 | + | ||
| 81 | + | // FEATURE_SET_MASTERING_DISPLAY_PRIMARIES is the feature set_mastering_display_primaries value. | |
| 82 | + | const FEATURE_SET_MASTERING_DISPLAY_PRIMARIES = 5 | |
| 83 | + | ||
| 84 | + | // FEATURE_EXTENDED_TARGET_VOLUME is the feature extended_target_volume value. | |
| 85 | + | const FEATURE_EXTENDED_TARGET_VOLUME = 6 | |
| 86 | + | ||
| 87 | + | // FEATURE_WINDOWS_SCRGB is the feature windows_scrgb value. | |
| 88 | + | const FEATURE_WINDOWS_SCRGB = 7 | |
| 89 | + | ||
| 90 | + | // FEATURE_WINDOWS_BT2100 is the feature windows_bt2100 value. | |
| 91 | + | const FEATURE_WINDOWS_BT2100 = 8 | |
| 92 | + | ||
| 93 | + | // PRIMARIES_SRGB is the primaries srgb value. | |
| 94 | + | const PRIMARIES_SRGB = 1 | |
| 95 | + | ||
| 96 | + | // PRIMARIES_PAL_M is the primaries pal_m value. | |
| 97 | + | const PRIMARIES_PAL_M = 2 | |
| 98 | + | ||
| 99 | + | // PRIMARIES_PAL is the primaries pal value. | |
| 100 | + | const PRIMARIES_PAL = 3 | |
| 101 | + | ||
| 102 | + | // PRIMARIES_NTSC is the primaries ntsc value. | |
| 103 | + | const PRIMARIES_NTSC = 4 | |
| 104 | + | ||
| 105 | + | // PRIMARIES_GENERIC_FILM is the primaries generic_film value. | |
| 106 | + | const PRIMARIES_GENERIC_FILM = 5 | |
| 107 | + | ||
| 108 | + | // PRIMARIES_BT2020 is the primaries bt2020 value. | |
| 109 | + | const PRIMARIES_BT2020 = 6 | |
| 110 | + | ||
| 111 | + | // PRIMARIES_CIE1931_XYZ is the primaries cie1931_xyz value. | |
| 112 | + | const PRIMARIES_CIE1931_XYZ = 7 | |
| 113 | + | ||
| 114 | + | // PRIMARIES_DCI_P3 is the primaries dci_p3 value. | |
| 115 | + | const PRIMARIES_DCI_P3 = 8 | |
| 116 | + | ||
| 117 | + | // PRIMARIES_DISPLAY_P3 is the primaries display_p3 value. | |
| 118 | + | const PRIMARIES_DISPLAY_P3 = 9 | |
| 119 | + | ||
| 120 | + | // PRIMARIES_ADOBE_RGB is the primaries adobe_rgb value. | |
| 121 | + | const PRIMARIES_ADOBE_RGB = 10 | |
| 122 | + | ||
| 123 | + | // TRANSFER_FUNCTION_BT1886 is the transfer_function bt1886 value. | |
| 124 | + | const TRANSFER_FUNCTION_BT1886 = 1 | |
| 125 | + | ||
| 126 | + | // TRANSFER_FUNCTION_GAMMA22 is the transfer_function gamma22 value. | |
| 127 | + | const TRANSFER_FUNCTION_GAMMA22 = 2 | |
| 128 | + | ||
| 129 | + | // TRANSFER_FUNCTION_GAMMA28 is the transfer_function gamma28 value. | |
| 130 | + | const TRANSFER_FUNCTION_GAMMA28 = 3 | |
| 131 | + | ||
| 132 | + | // TRANSFER_FUNCTION_ST240 is the transfer_function st240 value. | |
| 133 | + | const TRANSFER_FUNCTION_ST240 = 4 | |
| 134 | + | ||
| 135 | + | // TRANSFER_FUNCTION_EXT_LINEAR is the transfer_function ext_linear value. | |
| 136 | + | const TRANSFER_FUNCTION_EXT_LINEAR = 5 | |
| 137 | + | ||
| 138 | + | // TRANSFER_FUNCTION_LOG_100 is the transfer_function log_100 value. | |
| 139 | + | const TRANSFER_FUNCTION_LOG_100 = 6 | |
| 140 | + | ||
| 141 | + | // TRANSFER_FUNCTION_LOG_316 is the transfer_function log_316 value. | |
| 142 | + | const TRANSFER_FUNCTION_LOG_316 = 7 | |
| 143 | + | ||
| 144 | + | // TRANSFER_FUNCTION_XVYCC is the transfer_function xvycc value. | |
| 145 | + | const TRANSFER_FUNCTION_XVYCC = 8 | |
| 146 | + | ||
| 147 | + | // TRANSFER_FUNCTION_SRGB is the transfer_function srgb value. | |
| 148 | + | const TRANSFER_FUNCTION_SRGB = 9 | |
| 149 | + | ||
| 150 | + | // TRANSFER_FUNCTION_EXT_SRGB is the transfer_function ext_srgb value. | |
| 151 | + | const TRANSFER_FUNCTION_EXT_SRGB = 10 | |
| 152 | + | ||
| 153 | + | // TRANSFER_FUNCTION_ST2084_PQ is the transfer_function st2084_pq value. | |
| 154 | + | const TRANSFER_FUNCTION_ST2084_PQ = 11 | |
| 155 | + | ||
| 156 | + | // TRANSFER_FUNCTION_ST428 is the transfer_function st428 value. | |
| 157 | + | const TRANSFER_FUNCTION_ST428 = 12 | |
| 158 | + | ||
| 159 | + | // TRANSFER_FUNCTION_HLG is the transfer_function hlg value. | |
| 160 | + | const TRANSFER_FUNCTION_HLG = 13 | |
| 161 | + | ||
| 162 | + | // TRANSFER_FUNCTION_COMPOUND_POWER_2_4 is the transfer_function compound_power_2_4 value. | |
| 163 | + | const TRANSFER_FUNCTION_COMPOUND_POWER_2_4 = 14 | |
| 164 | + | ||
| 165 | + | // ERROR_RENDER_INTENT is the error render_intent value. | |
| 166 | + | const ERROR_RENDER_INTENT = 0 | |
| 167 | + | ||
| 168 | + | // ERROR_IMAGE_DESCRIPTION is the error image_description value. | |
| 169 | + | const ERROR_IMAGE_DESCRIPTION = 1 | |
| 170 | + | ||
| 171 | + | // WP_COLOR_MANAGEMENT_SURFACE_V1_ERROR_INERT is the error inert value. | |
| 172 | + | const WP_COLOR_MANAGEMENT_SURFACE_V1_ERROR_INERT = 2 | |
| 173 | + | ||
| 174 | + | // WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_ERROR_INERT is the error inert value. | |
| 175 | + | const WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_ERROR_INERT = 0 | |
| 176 | + | ||
| 177 | + | // WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_ERROR_UNSUPPORTED_FEATURE is the error unsupported_feature value. | |
| 178 | + | const WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_ERROR_UNSUPPORTED_FEATURE = 1 | |
| 179 | + | ||
| 180 | + | // WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_ERROR_INCOMPLETE_SET is the error incomplete_set value. | |
| 181 | + | const WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_ERROR_INCOMPLETE_SET = 0 | |
| 182 | + | ||
| 183 | + | // WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_ERROR_ALREADY_SET is the error already_set value. | |
| 184 | + | const WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_ERROR_ALREADY_SET = 1 | |
| 185 | + | ||
| 186 | + | // ERROR_BAD_FD is the error bad_fd value. | |
| 187 | + | const ERROR_BAD_FD = 2 | |
| 188 | + | ||
| 189 | + | // ERROR_BAD_SIZE is the error bad_size value. | |
| 190 | + | const ERROR_BAD_SIZE = 3 | |
| 191 | + | ||
| 192 | + | // ERROR_OUT_OF_FILE is the error out_of_file value. | |
| 193 | + | const ERROR_OUT_OF_FILE = 4 | |
| 194 | + | ||
| 195 | + | // WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INCOMPLETE_SET is the error incomplete_set value. | |
| 196 | + | const WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INCOMPLETE_SET = 0 | |
| 197 | + | ||
| 198 | + | // WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ALREADY_SET is the error already_set value. | |
| 199 | + | const WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ALREADY_SET = 1 | |
| 200 | + | ||
| 201 | + | // WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_UNSUPPORTED_FEATURE is the error unsupported_feature value. | |
| 202 | + | const WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_UNSUPPORTED_FEATURE = 2 | |
| 203 | + | ||
| 204 | + | // ERROR_INVALID_TF is the error invalid_tf value. | |
| 205 | + | const ERROR_INVALID_TF = 3 | |
| 206 | + | ||
| 207 | + | // ERROR_INVALID_PRIMARIES_NAMED is the error invalid_primaries_named value. | |
| 208 | + | const ERROR_INVALID_PRIMARIES_NAMED = 4 | |
| 209 | + | ||
| 210 | + | // ERROR_INVALID_LUMINANCE is the error invalid_luminance value. | |
| 211 | + | const ERROR_INVALID_LUMINANCE = 5 | |
| 212 | + | ||
| 213 | + | // ERROR_NOT_READY is the error not_ready value. | |
| 214 | + | const ERROR_NOT_READY = 0 | |
| 215 | + | ||
| 216 | + | // ERROR_NO_INFORMATION is the error no_information value. | |
| 217 | + | const ERROR_NO_INFORMATION = 1 | |
| 218 | + | ||
| 219 | + | // CAUSE_LOW_VERSION is the cause low_version value. | |
| 220 | + | const CAUSE_LOW_VERSION = 0 | |
| 221 | + | ||
| 222 | + | // CAUSE_UNSUPPORTED is the cause unsupported value. | |
| 223 | + | const CAUSE_UNSUPPORTED = 1 | |
| 224 | + | ||
| 225 | + | // CAUSE_OPERATING_SYSTEM is the cause operating_system value. | |
| 226 | + | const CAUSE_OPERATING_SYSTEM = 2 | |
| 227 | + | ||
| 228 | + | // CAUSE_NO_OUTPUT is the cause no_output value. | |
| 229 | + | const CAUSE_NO_OUTPUT = 3 | |
| 230 | + | ||
| 231 | + | // WpColorManagerInterface is the protocol interface name. | |
| 232 | + | const WpColorManagerInterface = "wp_color_manager_v1" | |
| 233 | + | ||
| 234 | + | // WpColorManager is the generated binding for wp_color_manager_v1 version 3. | |
| 235 | + | type WpColorManager struct { | |
| 236 | + | wl.BaseProxy | |
| 237 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 238 | + | // handlers while another goroutine dispatches events. | |
| 239 | + | handlersMu sync.Mutex | |
| 240 | + | onSupportedIntent []func(renderIntent uint32) | |
| 241 | + | onSupportedFeature []func(feature uint32) | |
| 242 | + | onSupportedTfNamed []func(tf uint32) | |
| 243 | + | onSupportedPrimariesNamed []func(primaries uint32) | |
| 244 | + | onDone []func() | |
| 245 | + | } | |
| 246 | + | ||
| 247 | + | // NewWpColorManager returns an unbound WpColorManager. | |
| 248 | + | func NewWpColorManager(ctx *wl.Context) *WpColorManager { | |
| 249 | + | obj := &WpColorManager{} | |
| 250 | + | obj.SetContext(ctx) | |
| 251 | + | ctx.Register(obj) | |
| 252 | + | return obj | |
| 253 | + | } | |
| 254 | + | ||
| 255 | + | // Destroy the wp_color_manager_v1 object. This does not affect any other objects in any way. | |
| 256 | + | func (o *WpColorManager) Destroy() error { | |
| 257 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_color_manager_v1.destroy", Destructor: true}); err != nil { | |
| 258 | + | return err | |
| 259 | + | } | |
| 260 | + | return nil | |
| 261 | + | } | |
| 262 | + | ||
| 263 | + | // This creates a new wp_color_management_output_v1 object for the given wl_output. See the wp_color_management_output_v1 interface for more details. | |
| 264 | + | func (o *WpColorManager) GetOutput(output *cross_wl_output.Output) (*WpColorManagementOutput, error) { | |
| 265 | + | var arg1 wl.Object | |
| 266 | + | if output != nil { | |
| 267 | + | arg1 = output | |
| 268 | + | } | |
| 269 | + | child := &WpColorManagementOutput{} | |
| 270 | + | child.SetContext(o.Context()) | |
| 271 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_color_manager_v1.get_output", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 272 | + | return nil, err | |
| 273 | + | } | |
| 274 | + | return child, nil | |
| 275 | + | } | |
| 276 | + | ||
| 277 | + | // If a wp_color_management_surface_v1 object already exists for the given wl_surface, the protocol error surface_exists is raised. This creates a new color wp_color_management_surface_v1 object for the given wl_surface. See the wp_color_management_surface_v1 interface for more details. | |
| 278 | + | func (o *WpColorManager) GetSurface(surface *cross_wl_surface.Surface) (*WpColorManagementSurface, error) { | |
| 279 | + | var arg1 wl.Object | |
| 280 | + | if surface != nil { | |
| 281 | + | arg1 = surface | |
| 282 | + | } | |
| 283 | + | child := &WpColorManagementSurface{} | |
| 284 | + | child.SetContext(o.Context()) | |
| 285 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wp_color_manager_v1.get_surface", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 286 | + | return nil, err | |
| 287 | + | } | |
| 288 | + | return child, nil | |
| 289 | + | } | |
| 290 | + | ||
| 291 | + | // This creates a new color wp_color_management_surface_feedback_v1 object for the given wl_surface. See the wp_color_management_surface_feedback_v1 interface for more details. | |
| 292 | + | func (o *WpColorManager) GetSurfaceFeedback(surface *cross_wl_surface.Surface) (*WpColorManagementSurfaceFeedback, error) { | |
| 293 | + | var arg1 wl.Object | |
| 294 | + | if surface != nil { | |
| 295 | + | arg1 = surface | |
| 296 | + | } | |
| 297 | + | child := &WpColorManagementSurfaceFeedback{} | |
| 298 | + | child.SetContext(o.Context()) | |
| 299 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "wp_color_manager_v1.get_surface_feedback", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 300 | + | return nil, err | |
| 301 | + | } | |
| 302 | + | return child, nil | |
| 303 | + | } | |
| 304 | + | ||
| 305 | + | // Makes a new ICC-based image description creator object with all properties initially unset. The client can then use the object's interface to define all the required properties for an image description and finally create a wp_image_description_v1 object. This request can be used when the compositor advertises wp_color_manager_v1.feature.icc_v2_v4. Otherwise this request raises the protocol error unsupported_feature. | |
| 306 | + | func (o *WpColorManager) CreateIccCreator() (*WpImageDescriptionCreatorIcc, error) { | |
| 307 | + | child := &WpImageDescriptionCreatorIcc{} | |
| 308 | + | child.SetContext(o.Context()) | |
| 309 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 4, Name: "wp_color_manager_v1.create_icc_creator", Child: child}, wl.ArgObject(child)); err != nil { | |
| 310 | + | return nil, err | |
| 311 | + | } | |
| 312 | + | return child, nil | |
| 313 | + | } | |
| 314 | + | ||
| 315 | + | // Makes a new parametric image description creator object with all properties initially unset. The client can then use the object's interface to define all the required properties for an image description and finally create a wp_image_description_v1 object. This request can be used when the compositor advertises wp_color_manager_v1.feature.parametric. Otherwise this request raises the protocol error unsupported_feature. | |
| 316 | + | func (o *WpColorManager) CreateParametricCreator() (*WpImageDescriptionCreatorParams, error) { | |
| 317 | + | child := &WpImageDescriptionCreatorParams{} | |
| 318 | + | child.SetContext(o.Context()) | |
| 319 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 5, Name: "wp_color_manager_v1.create_parametric_creator", Child: child}, wl.ArgObject(child)); err != nil { | |
| 320 | + | return nil, err | |
| 321 | + | } | |
| 322 | + | return child, nil | |
| 323 | + | } | |
| 324 | + | ||
| 325 | + | // This creates a pre-defined image description for the so-called Windows-scRGB stimulus encoding. This comes from the Windows 10 handling of its own definition of an scRGB color space for an HDR screen driven in BT.2100/PQ signalling mode. Windows-scRGB uses sRGB (BT.709) color primaries and white point. The transfer characteristic is extended linear. The nominal color channel value range is extended, meaning it includes negative and greater than 1.0 values. Negative values are used to escape the sRGB color gamut boundaries. To make use of the extended range, the client needs to use a pixel format that can represent those values, e.g. floating-point 16 bits per channel. Nominal color value R=G=B=0.0 corresponds to BT.2100/PQ system 0 cd/m², and R=G=B=1.0 corresponds to BT.2100/PQ system 80 cd/m². The maximum is R=G=B=125.0 corresponding to 10k cd/m². Windows-scRGB is displayed by Windows 10 by converting it to BT.2100/PQ, maintaining the CIE 1931 chromaticity and mapping the luminance as above. No adjustment is made to the signal to account for the viewing conditions. The reference white level of Windows-scRGB is unknown. If a reference white level must be assumed for compositor processing, it should be R=G=B=2.5375 corresponding to 203 cd/m² of Report ITU-R BT.2408-7. The target color volume of Windows-scRGB is unknown. The color gamut may be anything between sRGB and BT.2100. Note: EGL_EXT_gl_colorspace_scrgb_linear definition differs from Windows-scRGB by using R=G=B=1.0 as the reference white level, while Windows-scRGB reference white level is unknown or varies. However, it seems probable that Windows implements both EGL_EXT_gl_colorspace_scrgb_linear and Vulkan VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT as Windows-scRGB. This request can be used when the compositor advertises wp_color_manager_v1.feature.windows_scrgb. Otherwise this request raises the protocol error unsupported_feature. The resulting image description object does not allow get_information request. The wp_image_description_v1.ready event shall be sent. | |
| 326 | + | func (o *WpColorManager) CreateWindowsScrgb() (*WpImageDescription, error) { | |
| 327 | + | child := &WpImageDescription{} | |
| 328 | + | child.SetContext(o.Context()) | |
| 329 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 6, Name: "wp_color_manager_v1.create_windows_scrgb", Child: child}, wl.ArgObject(child)); err != nil { | |
| 330 | + | return nil, err | |
| 331 | + | } | |
| 332 | + | return child, nil | |
| 333 | + | } | |
| 334 | + | ||
| 335 | + | // This request retrieves the image description backing a reference. The get_information request can be used if and only if the request that creates the reference allows it. | |
| 336 | + | func (o *WpColorManager) GetImageDescription(reference *WpImageDescriptionReference) (*WpImageDescription, error) { | |
| 337 | + | var arg1 wl.Object | |
| 338 | + | if reference != nil { | |
| 339 | + | arg1 = reference | |
| 340 | + | } | |
| 341 | + | child := &WpImageDescription{} | |
| 342 | + | child.SetContext(o.Context()) | |
| 343 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 7, Name: "wp_color_manager_v1.get_image_description", Since: 2, Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 344 | + | return nil, err | |
| 345 | + | } | |
| 346 | + | return child, nil | |
| 347 | + | } | |
| 348 | + | ||
| 349 | + | // This creates a pre-defined image description for the so-called Windows-BT.2100 stimulus encoding. This comes from the Windows 10 handling of its own definition of a BT.2100 color space for an HDR screen driven in BT.2100/PQ signalling mode. Windows-BT.2100 uses BT.2020 color primaries and white point. The transfer characteristic is st2084_pq. Windows-BT.2100 is generally displayed by Windows 10 without any adjustments to the signal to account for viewing conditions. The reference white level of Windows-BT.2100 is unknown. If a reference white level must be assumed for compositor processing, it should be 203 cd/m² of Report ITU-R BT.2408-7. The target color volume of Windows-BT.2100 is unknown. The color gamut may be anything up to BT.2100. This request can be used when the compositor advertises wp_color_manager_v1.feature.windows_bt2100. Otherwise this request raises the protocol error unsupported_feature. The resulting image description object does not allow get_information request. The wp_image_description_v1.ready event shall be sent. | |
| 350 | + | func (o *WpColorManager) CreateWindowsBt2100() (*WpImageDescription, error) { | |
| 351 | + | child := &WpImageDescription{} | |
| 352 | + | child.SetContext(o.Context()) | |
| 353 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 8, Name: "wp_color_manager_v1.create_windows_bt2100", Since: 3, Child: child}, wl.ArgObject(child)); err != nil { | |
| 354 | + | return nil, err | |
| 355 | + | } | |
| 356 | + | return child, nil | |
| 357 | + | } | |
| 358 | + | ||
| 359 | + | // OnSupportedIntent registers a handler for the supported_intent event. | |
| 360 | + | // | |
| 361 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 362 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 363 | + | func (o *WpColorManager) OnSupportedIntent(handler func(renderIntent uint32)) { | |
| 364 | + | if handler == nil { | |
| 365 | + | return | |
| 366 | + | } | |
| 367 | + | o.handlersMu.Lock() | |
| 368 | + | defer o.handlersMu.Unlock() | |
| 369 | + | o.onSupportedIntent = append(o.onSupportedIntent, handler) | |
| 370 | + | } | |
| 371 | + | ||
| 372 | + | // handlersForSupportedIntent returns the handlers registered for supported_intent, taken | |
| 373 | + | // under the lock so a handler may register another handler while events are | |
| 374 | + | // being dispatched. | |
| 375 | + | func (o *WpColorManager) handlersForSupportedIntent() []func(renderIntent uint32) { | |
| 376 | + | o.handlersMu.Lock() | |
| 377 | + | defer o.handlersMu.Unlock() | |
| 378 | + | return o.onSupportedIntent | |
| 379 | + | } | |
| 380 | + | ||
| 381 | + | // OnSupportedFeature registers a handler for the supported_feature event. | |
| 382 | + | // | |
| 383 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 384 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 385 | + | func (o *WpColorManager) OnSupportedFeature(handler func(feature uint32)) { | |
| 386 | + | if handler == nil { | |
| 387 | + | return | |
| 388 | + | } | |
| 389 | + | o.handlersMu.Lock() | |
| 390 | + | defer o.handlersMu.Unlock() | |
| 391 | + | o.onSupportedFeature = append(o.onSupportedFeature, handler) | |
| 392 | + | } | |
| 393 | + | ||
| 394 | + | // handlersForSupportedFeature returns the handlers registered for supported_feature, taken | |
| 395 | + | // under the lock so a handler may register another handler while events are | |
| 396 | + | // being dispatched. | |
| 397 | + | func (o *WpColorManager) handlersForSupportedFeature() []func(feature uint32) { | |
| 398 | + | o.handlersMu.Lock() | |
| 399 | + | defer o.handlersMu.Unlock() | |
| 400 | + | return o.onSupportedFeature | |
| 401 | + | } | |
| 402 | + | ||
| 403 | + | // OnSupportedTfNamed registers a handler for the supported_tf_named event. | |
| 404 | + | // | |
| 405 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 406 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 407 | + | func (o *WpColorManager) OnSupportedTfNamed(handler func(tf uint32)) { | |
| 408 | + | if handler == nil { | |
| 409 | + | return | |
| 410 | + | } | |
| 411 | + | o.handlersMu.Lock() | |
| 412 | + | defer o.handlersMu.Unlock() | |
| 413 | + | o.onSupportedTfNamed = append(o.onSupportedTfNamed, handler) | |
| 414 | + | } | |
| 415 | + | ||
| 416 | + | // handlersForSupportedTfNamed returns the handlers registered for supported_tf_named, taken | |
| 417 | + | // under the lock so a handler may register another handler while events are | |
| 418 | + | // being dispatched. | |
| 419 | + | func (o *WpColorManager) handlersForSupportedTfNamed() []func(tf uint32) { | |
| 420 | + | o.handlersMu.Lock() | |
| 421 | + | defer o.handlersMu.Unlock() | |
| 422 | + | return o.onSupportedTfNamed | |
| 423 | + | } | |
| 424 | + | ||
| 425 | + | // OnSupportedPrimariesNamed registers a handler for the supported_primaries_named event. | |
| 426 | + | // | |
| 427 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 428 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 429 | + | func (o *WpColorManager) OnSupportedPrimariesNamed(handler func(primaries uint32)) { | |
| 430 | + | if handler == nil { | |
| 431 | + | return | |
| 432 | + | } | |
| 433 | + | o.handlersMu.Lock() | |
| 434 | + | defer o.handlersMu.Unlock() | |
| 435 | + | o.onSupportedPrimariesNamed = append(o.onSupportedPrimariesNamed, handler) | |
| 436 | + | } | |
| 437 | + | ||
| 438 | + | // handlersForSupportedPrimariesNamed returns the handlers registered for supported_primaries_named, taken | |
| 439 | + | // under the lock so a handler may register another handler while events are | |
| 440 | + | // being dispatched. | |
| 441 | + | func (o *WpColorManager) handlersForSupportedPrimariesNamed() []func(primaries uint32) { | |
| 442 | + | o.handlersMu.Lock() | |
| 443 | + | defer o.handlersMu.Unlock() | |
| 444 | + | return o.onSupportedPrimariesNamed | |
| 445 | + | } | |
| 446 | + | ||
| 447 | + | // OnDone registers a handler for the done event. | |
| 448 | + | // | |
| 449 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 450 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 451 | + | func (o *WpColorManager) OnDone(handler func()) { | |
| 452 | + | if handler == nil { | |
| 453 | + | return | |
| 454 | + | } | |
| 455 | + | o.handlersMu.Lock() | |
| 456 | + | defer o.handlersMu.Unlock() | |
| 457 | + | o.onDone = append(o.onDone, handler) | |
| 458 | + | } | |
| 459 | + | ||
| 460 | + | // handlersForDone returns the handlers registered for done, taken | |
| 461 | + | // under the lock so a handler may register another handler while events are | |
| 462 | + | // being dispatched. | |
| 463 | + | func (o *WpColorManager) handlersForDone() []func() { | |
| 464 | + | o.handlersMu.Lock() | |
| 465 | + | defer o.handlersMu.Unlock() | |
| 466 | + | return o.onDone | |
| 467 | + | } | |
| 468 | + | ||
| 469 | + | // EventSignature returns the declared event argument types in wire order. | |
| 470 | + | func (o *WpColorManager) EventSignature(opcode uint16) (string, bool) { | |
| 471 | + | switch opcode { | |
| 472 | + | case 0: | |
| 473 | + | return "uint,", true | |
| 474 | + | case 1: | |
| 475 | + | return "uint,", true | |
| 476 | + | case 2: | |
| 477 | + | return "uint,", true | |
| 478 | + | case 3: | |
| 479 | + | return "uint,", true | |
| 480 | + | case 4: | |
| 481 | + | return "", true | |
| 482 | + | default: | |
| 483 | + | return "", false | |
| 484 | + | } | |
| 485 | + | } | |
| 486 | + | ||
| 487 | + | // Dispatch decodes one event on wp_color_manager_v1 and calls the registered handlers. | |
| 488 | + | func (o *WpColorManager) Dispatch(event *wl.Event) { | |
| 489 | + | switch event.Opcode { | |
| 490 | + | case 0: // supported_intent | |
| 491 | + | renderIntent := event.Uint32() | |
| 492 | + | ||
| 493 | + | for i, handler := range o.handlersForSupportedIntent() { | |
| 494 | + | _ = i | |
| 495 | + | handler(renderIntent) | |
| 496 | + | } | |
| 497 | + | case 1: // supported_feature | |
| 498 | + | feature := event.Uint32() | |
| 499 | + | ||
| 500 | + | for i, handler := range o.handlersForSupportedFeature() { | |
| 501 | + | _ = i | |
| 502 | + | handler(feature) | |
| 503 | + | } | |
| 504 | + | case 2: // supported_tf_named | |
| 505 | + | tf := event.Uint32() | |
| 506 | + | ||
| 507 | + | for i, handler := range o.handlersForSupportedTfNamed() { | |
| 508 | + | _ = i | |
| 509 | + | handler(tf) | |
| 510 | + | } | |
| 511 | + | case 3: // supported_primaries_named | |
| 512 | + | primaries := event.Uint32() | |
| 513 | + | ||
| 514 | + | for i, handler := range o.handlersForSupportedPrimariesNamed() { | |
| 515 | + | _ = i | |
| 516 | + | handler(primaries) | |
| 517 | + | } | |
| 518 | + | case 4: // done | |
| 519 | + | ||
| 520 | + | for i, handler := range o.handlersForDone() { | |
| 521 | + | _ = i | |
| 522 | + | handler() | |
| 523 | + | } | |
| 524 | + | default: | |
| 525 | + | } | |
| 526 | + | } | |
| 527 | + | ||
| 528 | + | // WpColorManagementOutputInterface is the protocol interface name. | |
| 529 | + | const WpColorManagementOutputInterface = "wp_color_management_output_v1" | |
| 530 | + | ||
| 531 | + | // WpColorManagementOutput is the generated binding for wp_color_management_output_v1 version 3. | |
| 532 | + | type WpColorManagementOutput struct { | |
| 533 | + | wl.BaseProxy | |
| 534 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 535 | + | // handlers while another goroutine dispatches events. | |
| 536 | + | handlersMu sync.Mutex | |
| 537 | + | onImageDescriptionChanged []func() | |
| 538 | + | } | |
| 539 | + | ||
| 540 | + | // NewWpColorManagementOutput returns an unbound WpColorManagementOutput. | |
| 541 | + | func NewWpColorManagementOutput(ctx *wl.Context) *WpColorManagementOutput { | |
| 542 | + | obj := &WpColorManagementOutput{} | |
| 543 | + | obj.SetContext(ctx) | |
| 544 | + | ctx.Register(obj) | |
| 545 | + | return obj | |
| 546 | + | } | |
| 547 | + | ||
| 548 | + | // Destroy the color wp_color_management_output_v1 object. This does not affect any remaining protocol objects. | |
| 549 | + | func (o *WpColorManagementOutput) Destroy() error { | |
| 550 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_color_management_output_v1.destroy", Destructor: true}); err != nil { | |
| 551 | + | return err | |
| 552 | + | } | |
| 553 | + | return nil | |
| 554 | + | } | |
| 555 | + | ||
| 556 | + | // This creates a new wp_image_description_v1 object for the current image description of the output. There always is exactly one image description active for an output so the client should destroy the image description created by earlier invocations of this request. This request is usually sent as a reaction to the image_description_changed event or when creating a wp_color_management_output_v1 object. The image description of an output represents the color encoding the output expects. There might be performance and power advantages, as well as improved color reproduction, if a content update matches the image description of the output it is being shown on. If a content update is shown on any other output than the one it matches the image description of, then the color reproduction on those outputs might be considerably worse. The created wp_image_description_v1 object preserves the image description of the output from the time the object was created. The resulting image description object allows get_information request. If this protocol object is inert, the resulting image description object shall immediately deliver the wp_image_description_v1.failed event with the no_output cause. If the interface version is inadequate for the output's image description, meaning that the client does not support all the events needed to deliver the crucial information, the resulting image description object shall immediately deliver the wp_image_description_v1.failed event with the low_version cause. Otherwise the object shall immediately deliver the ready event. | |
| 557 | + | func (o *WpColorManagementOutput) GetImageDescription() (*WpImageDescription, error) { | |
| 558 | + | child := &WpImageDescription{} | |
| 559 | + | child.SetContext(o.Context()) | |
| 560 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_color_management_output_v1.get_image_description", Child: child}, wl.ArgObject(child)); err != nil { | |
| 561 | + | return nil, err | |
| 562 | + | } | |
| 563 | + | return child, nil | |
| 564 | + | } | |
| 565 | + | ||
| 566 | + | // OnImageDescriptionChanged registers a handler for the image_description_changed event. | |
| 567 | + | // | |
| 568 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 569 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 570 | + | func (o *WpColorManagementOutput) OnImageDescriptionChanged(handler func()) { | |
| 571 | + | if handler == nil { | |
| 572 | + | return | |
| 573 | + | } | |
| 574 | + | o.handlersMu.Lock() | |
| 575 | + | defer o.handlersMu.Unlock() | |
| 576 | + | o.onImageDescriptionChanged = append(o.onImageDescriptionChanged, handler) | |
| 577 | + | } | |
| 578 | + | ||
| 579 | + | // handlersForImageDescriptionChanged returns the handlers registered for image_description_changed, taken | |
| 580 | + | // under the lock so a handler may register another handler while events are | |
| 581 | + | // being dispatched. | |
| 582 | + | func (o *WpColorManagementOutput) handlersForImageDescriptionChanged() []func() { | |
| 583 | + | o.handlersMu.Lock() | |
| 584 | + | defer o.handlersMu.Unlock() | |
| 585 | + | return o.onImageDescriptionChanged | |
| 586 | + | } | |
| 587 | + | ||
| 588 | + | // EventSignature returns the declared event argument types in wire order. | |
| 589 | + | func (o *WpColorManagementOutput) EventSignature(opcode uint16) (string, bool) { | |
| 590 | + | switch opcode { | |
| 591 | + | case 0: | |
| 592 | + | return "", true | |
| 593 | + | default: | |
| 594 | + | return "", false | |
| 595 | + | } | |
| 596 | + | } | |
| 597 | + | ||
| 598 | + | // Dispatch decodes one event on wp_color_management_output_v1 and calls the registered handlers. | |
| 599 | + | func (o *WpColorManagementOutput) Dispatch(event *wl.Event) { | |
| 600 | + | switch event.Opcode { | |
| 601 | + | case 0: // image_description_changed | |
| 602 | + | ||
| 603 | + | for i, handler := range o.handlersForImageDescriptionChanged() { | |
| 604 | + | _ = i | |
| 605 | + | handler() | |
| 606 | + | } | |
| 607 | + | default: | |
| 608 | + | } | |
| 609 | + | } | |
| 610 | + | ||
| 611 | + | // WpColorManagementSurfaceInterface is the protocol interface name. | |
| 612 | + | const WpColorManagementSurfaceInterface = "wp_color_management_surface_v1" | |
| 613 | + | ||
| 614 | + | // WpColorManagementSurface is the generated binding for wp_color_management_surface_v1 version 3. | |
| 615 | + | type WpColorManagementSurface struct { | |
| 616 | + | wl.BaseProxy | |
| 617 | + | } | |
| 618 | + | ||
| 619 | + | // NewWpColorManagementSurface returns an unbound WpColorManagementSurface. | |
| 620 | + | func NewWpColorManagementSurface(ctx *wl.Context) *WpColorManagementSurface { | |
| 621 | + | obj := &WpColorManagementSurface{} | |
| 622 | + | obj.SetContext(ctx) | |
| 623 | + | ctx.Register(obj) | |
| 624 | + | return obj | |
| 625 | + | } | |
| 626 | + | ||
| 627 | + | // Destroy the wp_color_management_surface_v1 object and do the same as unset_image_description. | |
| 628 | + | func (o *WpColorManagementSurface) Destroy() error { | |
| 629 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_color_management_surface_v1.destroy", Destructor: true}); err != nil { | |
| 630 | + | return err | |
| 631 | + | } | |
| 632 | + | return nil | |
| 633 | + | } | |
| 634 | + | ||
| 635 | + | // If this protocol object is inert, the protocol error inert is raised. Set the image description of the underlying surface. The image description and rendering intent are double-buffered state, see wl_surface.commit. It is the client's responsibility to understand the image description it sets on a surface, and to provide content that matches that image description. Compositors might convert images to match their own or any other image descriptions. Image descriptions which are not ready (see wp_image_description_v1) are forbidden in this request, and in such case the protocol error image_description is raised. All image descriptions which are ready (see wp_image_description_v1) are allowed and must always be accepted by the compositor. When an image description is set on a surface, it establishes an explicit link between surface pixel values and surface colorimetry. This link may be undefined for some pixel values, see the image description creator interfaces for the conditions. Non-finite floating-point values (NaN, Inf) always have an undefined colorimetry. A rendering intent provides the client's preference on how surface colorimetry should be mapped to each output. The render_intent value must be one advertised by the compositor with wp_color_manager_v1.render_intent event, otherwise the protocol error render_intent is raised. By default, a surface does not have an associated image description nor a rendering intent. The handling of color on such surfaces is compositor implementation defined. Compositors should handle such surfaces as sRGB, but may handle them differently if they have specific requirements. Setting the image description has copy semantics; after this request, the image description can be immediately destroyed without affecting the pending state of the surface. | |
| 636 | + | func (o *WpColorManagementSurface) SetImageDescription(imageDescription *WpImageDescription, renderIntent uint32) error { | |
| 637 | + | var arg0 wl.Object | |
| 638 | + | if imageDescription != nil { | |
| 639 | + | arg0 = imageDescription | |
| 640 | + | } | |
| 641 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_color_management_surface_v1.set_image_description"}, wl.ArgObject(arg0), wl.ArgUint(renderIntent)); err != nil { | |
| 642 | + | return err | |
| 643 | + | } | |
| 644 | + | return nil | |
| 645 | + | } | |
| 646 | + | ||
| 647 | + | // If this protocol object is inert, the protocol error inert is raised. This request removes any image description from the surface. See set_image_description for how a compositor handles a surface without an image description. This is double-buffered state, see wl_surface.commit. | |
| 648 | + | func (o *WpColorManagementSurface) UnsetImageDescription() error { | |
| 649 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wp_color_management_surface_v1.unset_image_description"}); err != nil { | |
| 650 | + | return err | |
| 651 | + | } | |
| 652 | + | return nil | |
| 653 | + | } | |
| 654 | + | ||
| 655 | + | // EventSignature returns the declared event argument types in wire order. | |
| 656 | + | func (o *WpColorManagementSurface) EventSignature(opcode uint16) (string, bool) { | |
| 657 | + | switch opcode { | |
| 658 | + | default: | |
| 659 | + | return "", false | |
| 660 | + | } | |
| 661 | + | } | |
| 662 | + | ||
| 663 | + | // Dispatch decodes one event on wp_color_management_surface_v1 and calls the registered handlers. | |
| 664 | + | func (o *WpColorManagementSurface) Dispatch(event *wl.Event) { | |
| 665 | + | switch event.Opcode { | |
| 666 | + | default: | |
| 667 | + | } | |
| 668 | + | } | |
| 669 | + | ||
| 670 | + | // WpColorManagementSurfaceFeedbackInterface is the protocol interface name. | |
| 671 | + | const WpColorManagementSurfaceFeedbackInterface = "wp_color_management_surface_feedback_v1" | |
| 672 | + | ||
| 673 | + | // WpColorManagementSurfaceFeedback is the generated binding for wp_color_management_surface_feedback_v1 version 3. | |
| 674 | + | type WpColorManagementSurfaceFeedback struct { | |
| 675 | + | wl.BaseProxy | |
| 676 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 677 | + | // handlers while another goroutine dispatches events. | |
| 678 | + | handlersMu sync.Mutex | |
| 679 | + | onPreferredChanged []func(identity uint32) | |
| 680 | + | onPreferredChanged2 []func(identityHi uint32, identityLo uint32) | |
| 681 | + | } | |
| 682 | + | ||
| 683 | + | // NewWpColorManagementSurfaceFeedback returns an unbound WpColorManagementSurfaceFeedback. | |
| 684 | + | func NewWpColorManagementSurfaceFeedback(ctx *wl.Context) *WpColorManagementSurfaceFeedback { | |
| 685 | + | obj := &WpColorManagementSurfaceFeedback{} | |
| 686 | + | obj.SetContext(ctx) | |
| 687 | + | ctx.Register(obj) | |
| 688 | + | return obj | |
| 689 | + | } | |
| 690 | + | ||
| 691 | + | // Destroy the wp_color_management_surface_feedback_v1 object. | |
| 692 | + | func (o *WpColorManagementSurfaceFeedback) Destroy() error { | |
| 693 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_color_management_surface_feedback_v1.destroy", Destructor: true}); err != nil { | |
| 694 | + | return err | |
| 695 | + | } | |
| 696 | + | return nil | |
| 697 | + | } | |
| 698 | + | ||
| 699 | + | // If this protocol object is inert, the protocol error inert is raised. The preferred image description represents the compositor's preferred color encoding for this wl_surface at the current time. There might be performance and power advantages, as well as improved color reproduction, if the image description of a content update matches the preferred image description. This creates a new wp_image_description_v1 object for the currently preferred image description for the wl_surface. The client should stop using and destroy the image descriptions created by earlier invocations of this request for the associated wl_surface. This request is usually sent as a reaction to the preferred_changed event or when creating a wp_color_management_surface_feedback_v1 object if the client is capable of adapting to image descriptions. The created wp_image_description_v1 object preserves the preferred image description of the wl_surface from the time the object was created. The resulting image description object allows get_information request. If the image description is parametric, the client should set it on its wl_surface only if the image description is an exact match with the client content. Particularly if everything else matches, but the target color volume is greater than what the client needs, the client should create its own parameric image description with its exact parameters. If the interface version is inadequate for the preferred image description, meaning that the client does not support all the events needed to deliver the crucial information, the resulting image description object shall immediately deliver the wp_image_description_v1.failed event with the low_version cause, otherwise the object shall immediately deliver the ready event. | |
| 700 | + | func (o *WpColorManagementSurfaceFeedback) GetPreferred() (*WpImageDescription, error) { | |
| 701 | + | child := &WpImageDescription{} | |
| 702 | + | child.SetContext(o.Context()) | |
| 703 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_color_management_surface_feedback_v1.get_preferred", Child: child}, wl.ArgObject(child)); err != nil { | |
| 704 | + | return nil, err | |
| 705 | + | } | |
| 706 | + | return child, nil | |
| 707 | + | } | |
| 708 | + | ||
| 709 | + | // The same description as for get_preferred applies, except the returned image description is guaranteed to be parametric. This is meant for clients that can only deal with parametric image descriptions. If the compositor doesn't support parametric image descriptions, the unsupported_feature error is emitted. | |
| 710 | + | func (o *WpColorManagementSurfaceFeedback) GetPreferredParametric() (*WpImageDescription, error) { | |
| 711 | + | child := &WpImageDescription{} | |
| 712 | + | child.SetContext(o.Context()) | |
| 713 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wp_color_management_surface_feedback_v1.get_preferred_parametric", Child: child}, wl.ArgObject(child)); err != nil { | |
| 714 | + | return nil, err | |
| 715 | + | } | |
| 716 | + | return child, nil | |
| 717 | + | } | |
| 718 | + | ||
| 719 | + | // OnPreferredChanged registers a handler for the preferred_changed event. | |
| 720 | + | // | |
| 721 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 722 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 723 | + | func (o *WpColorManagementSurfaceFeedback) OnPreferredChanged(handler func(identity uint32)) { | |
| 724 | + | if handler == nil { | |
| 725 | + | return | |
| 726 | + | } | |
| 727 | + | o.handlersMu.Lock() | |
| 728 | + | defer o.handlersMu.Unlock() | |
| 729 | + | o.onPreferredChanged = append(o.onPreferredChanged, handler) | |
| 730 | + | } | |
| 731 | + | ||
| 732 | + | // handlersForPreferredChanged returns the handlers registered for preferred_changed, taken | |
| 733 | + | // under the lock so a handler may register another handler while events are | |
| 734 | + | // being dispatched. | |
| 735 | + | func (o *WpColorManagementSurfaceFeedback) handlersForPreferredChanged() []func(identity uint32) { | |
| 736 | + | o.handlersMu.Lock() | |
| 737 | + | defer o.handlersMu.Unlock() | |
| 738 | + | return o.onPreferredChanged | |
| 739 | + | } | |
| 740 | + | ||
| 741 | + | // OnPreferredChanged2 registers a handler for the preferred_changed2 event. | |
| 742 | + | // | |
| 743 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 744 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 745 | + | func (o *WpColorManagementSurfaceFeedback) OnPreferredChanged2(handler func(identityHi uint32, identityLo uint32)) { | |
| 746 | + | if handler == nil { | |
| 747 | + | return | |
| 748 | + | } | |
| 749 | + | o.handlersMu.Lock() | |
| 750 | + | defer o.handlersMu.Unlock() | |
| 751 | + | o.onPreferredChanged2 = append(o.onPreferredChanged2, handler) | |
| 752 | + | } | |
| 753 | + | ||
| 754 | + | // handlersForPreferredChanged2 returns the handlers registered for preferred_changed2, taken | |
| 755 | + | // under the lock so a handler may register another handler while events are | |
| 756 | + | // being dispatched. | |
| 757 | + | func (o *WpColorManagementSurfaceFeedback) handlersForPreferredChanged2() []func(identityHi uint32, identityLo uint32) { | |
| 758 | + | o.handlersMu.Lock() | |
| 759 | + | defer o.handlersMu.Unlock() | |
| 760 | + | return o.onPreferredChanged2 | |
| 761 | + | } | |
| 762 | + | ||
| 763 | + | // EventSignature returns the declared event argument types in wire order. | |
| 764 | + | func (o *WpColorManagementSurfaceFeedback) EventSignature(opcode uint16) (string, bool) { | |
| 765 | + | switch opcode { | |
| 766 | + | case 0: | |
| 767 | + | return "uint,", true | |
| 768 | + | case 1: | |
| 769 | + | return "uint,uint,", true | |
| 770 | + | default: | |
| 771 | + | return "", false | |
| 772 | + | } | |
| 773 | + | } | |
| 774 | + | ||
| 775 | + | // Dispatch decodes one event on wp_color_management_surface_feedback_v1 and calls the registered handlers. | |
| 776 | + | func (o *WpColorManagementSurfaceFeedback) Dispatch(event *wl.Event) { | |
| 777 | + | switch event.Opcode { | |
| 778 | + | case 0: // preferred_changed | |
| 779 | + | identity := event.Uint32() | |
| 780 | + | ||
| 781 | + | for i, handler := range o.handlersForPreferredChanged() { | |
| 782 | + | _ = i | |
| 783 | + | handler(identity) | |
| 784 | + | } | |
| 785 | + | case 1: // preferred_changed2 | |
| 786 | + | identityHi := event.Uint32() | |
| 787 | + | identityLo := event.Uint32() | |
| 788 | + | ||
| 789 | + | for i, handler := range o.handlersForPreferredChanged2() { | |
| 790 | + | _ = i | |
| 791 | + | handler(identityHi, identityLo) | |
| 792 | + | } | |
| 793 | + | default: | |
| 794 | + | } | |
| 795 | + | } | |
| 796 | + | ||
| 797 | + | // WpImageDescriptionCreatorIccInterface is the protocol interface name. | |
| 798 | + | const WpImageDescriptionCreatorIccInterface = "wp_image_description_creator_icc_v1" | |
| 799 | + | ||
| 800 | + | // WpImageDescriptionCreatorIcc is the generated binding for wp_image_description_creator_icc_v1 version 3. | |
| 801 | + | type WpImageDescriptionCreatorIcc struct { | |
| 802 | + | wl.BaseProxy | |
| 803 | + | } | |
| 804 | + | ||
| 805 | + | // NewWpImageDescriptionCreatorIcc returns an unbound WpImageDescriptionCreatorIcc. | |
| 806 | + | func NewWpImageDescriptionCreatorIcc(ctx *wl.Context) *WpImageDescriptionCreatorIcc { | |
| 807 | + | obj := &WpImageDescriptionCreatorIcc{} | |
| 808 | + | obj.SetContext(ctx) | |
| 809 | + | ctx.Register(obj) | |
| 810 | + | return obj | |
| 811 | + | } | |
| 812 | + | ||
| 813 | + | // Create an image description object based on the ICC information previously set on this object. A compositor must parse the ICC data in some undefined but finite amount of time. The completeness of the parameter set is verified. If the set is not complete, the protocol error incomplete_set is raised. For the definition of a complete set, see the description of this interface. If the particular combination of the information is not supported by the compositor, the resulting image description object shall immediately deliver the wp_image_description_v1.failed event with the 'unsupported' cause. If a valid image description was created from the information, the wp_image_description_v1.ready event will eventually be sent instead. This request destroys the wp_image_description_creator_icc_v1 object. The resulting image description object does not allow get_information request. | |
| 814 | + | func (o *WpImageDescriptionCreatorIcc) Create() (*WpImageDescription, error) { | |
| 815 | + | child := &WpImageDescription{} | |
| 816 | + | child.SetContext(o.Context()) | |
| 817 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_image_description_creator_icc_v1.create", Destructor: true, Child: child}, wl.ArgObject(child)); err != nil { | |
| 818 | + | return nil, err | |
| 819 | + | } | |
| 820 | + | return child, nil | |
| 821 | + | } | |
| 822 | + | ||
| 823 | + | // Sets the ICC profile file to be used as the basis of the image description. The data shall be found through the given fd at the given offset, having the given length. The fd must be seekable and readable. Violating these requirements raises the bad_fd protocol error. If reading the data fails due to an error independent of the client, the compositor shall send the wp_image_description_v1.failed event on the created wp_image_description_v1 with the 'operating_system' cause. The maximum size of the ICC profile is 32 MB. If length is greater than that or zero, the protocol error bad_size is raised. If offset + length exceeds the file size, the protocol error out_of_file is raised. A compositor may read the file at any time starting from this request and only until whichever happens first: - If create request was issued, the wp_image_description_v1 object delivers either failed or ready event; or - if create request was not issued, this wp_image_description_creator_icc_v1 object is destroyed. A compositor shall not modify the contents of the file, and the fd may be sealed for writes and size changes. The client must ensure to its best ability that the data does not change while the compositor is reading it. The data must represent a valid ICC profile. The ICC profile version must be 2 or 4, it must be a 3 channel profile and the class must be Display or ColorSpace. Violating these requirements will not result in a protocol error, but will eventually send the wp_image_description_v1.failed event on the created wp_image_description_v1 with the 'unsupported' cause. See the International Color Consortium specification ICC.1:2022 for more details about ICC profiles. If ICC file has already been set on this object, the protocol error already_set is raised. | |
| 824 | + | func (o *WpImageDescriptionCreatorIcc) SetIccFile(iccProfile int, offset uint32, length uint32) error { | |
| 825 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_image_description_creator_icc_v1.set_icc_file", FDs: []int{iccProfile}}, wl.ArgFD(), wl.ArgUint(offset), wl.ArgUint(length)); err != nil { | |
| 826 | + | return err | |
| 827 | + | } | |
| 828 | + | return nil | |
| 829 | + | } | |
| 830 | + | ||
| 831 | + | // EventSignature returns the declared event argument types in wire order. | |
| 832 | + | func (o *WpImageDescriptionCreatorIcc) EventSignature(opcode uint16) (string, bool) { | |
| 833 | + | switch opcode { | |
| 834 | + | default: | |
| 835 | + | return "", false | |
| 836 | + | } | |
| 837 | + | } | |
| 838 | + | ||
| 839 | + | // Dispatch decodes one event on wp_image_description_creator_icc_v1 and calls the registered handlers. | |
| 840 | + | func (o *WpImageDescriptionCreatorIcc) Dispatch(event *wl.Event) { | |
| 841 | + | switch event.Opcode { | |
| 842 | + | default: | |
| 843 | + | } | |
| 844 | + | } | |
| 845 | + | ||
| 846 | + | // WpImageDescriptionCreatorParamsInterface is the protocol interface name. | |
| 847 | + | const WpImageDescriptionCreatorParamsInterface = "wp_image_description_creator_params_v1" | |
| 848 | + | ||
| 849 | + | // WpImageDescriptionCreatorParams is the generated binding for wp_image_description_creator_params_v1 version 3. | |
| 850 | + | type WpImageDescriptionCreatorParams struct { | |
| 851 | + | wl.BaseProxy | |
| 852 | + | } | |
| 853 | + | ||
| 854 | + | // NewWpImageDescriptionCreatorParams returns an unbound WpImageDescriptionCreatorParams. | |
| 855 | + | func NewWpImageDescriptionCreatorParams(ctx *wl.Context) *WpImageDescriptionCreatorParams { | |
| 856 | + | obj := &WpImageDescriptionCreatorParams{} | |
| 857 | + | obj.SetContext(ctx) | |
| 858 | + | ctx.Register(obj) | |
| 859 | + | return obj | |
| 860 | + | } | |
| 861 | + | ||
| 862 | + | // Create an image description object based on the parameters previously set on this object. The completeness of the parameter set is verified. If the set is not complete, the protocol error incomplete_set is raised. For the definition of a complete set, see the description of this interface. When both max_cll and max_fall are set, max_fall must be less or equal to max_cll otherwise the invalid_luminance protocol error is raised. In version 1, these following conditions also result in the invalid_luminance protocol error. Version 2 and later do not have this requirement. - When max_cll is set, it must be greater than min L and less or equal to max L of the mastering luminance range. - When max_fall is set, it must be greater than min L and less or equal to max L of the mastering luminance range. If the particular combination of the parameter set is not supported by the compositor, the resulting image description object shall immediately deliver the wp_image_description_v1.failed event with the 'unsupported' cause. If a valid image description was created from the parameter set, the wp_image_description_v1.ready event will eventually be sent instead. This request destroys the wp_image_description_creator_params_v1 object. The resulting image description object does not allow get_information request. | |
| 863 | + | func (o *WpImageDescriptionCreatorParams) Create() (*WpImageDescription, error) { | |
| 864 | + | child := &WpImageDescription{} | |
| 865 | + | child.SetContext(o.Context()) | |
| 866 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_image_description_creator_params_v1.create", Destructor: true, Child: child}, wl.ArgObject(child)); err != nil { | |
| 867 | + | return nil, err | |
| 868 | + | } | |
| 869 | + | return child, nil | |
| 870 | + | } | |
| 871 | + | ||
| 872 | + | // Sets the transfer characteristic using explicitly enumerated named functions. When the resulting image description is attached to an image, the content should be decoded according to the industry standard practices for the transfer characteristic. Only names advertised with wp_color_manager_v1 event supported_tf_named are allowed. Other values shall raise the protocol error invalid_tf. If transfer characteristic has already been set on this object, the protocol error already_set is raised. | |
| 873 | + | func (o *WpImageDescriptionCreatorParams) SetTfNamed(tf uint32) error { | |
| 874 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_image_description_creator_params_v1.set_tf_named"}, wl.ArgUint(tf)); err != nil { | |
| 875 | + | return err | |
| 876 | + | } | |
| 877 | + | return nil | |
| 878 | + | } | |
| 879 | + | ||
| 880 | + | // Sets the color component transfer characteristic to a power curve with the given exponent. Negative values are handled by mirroring the positive half of the curve through the origin. The valid domain and range of the curve are all finite real numbers. This curve represents the conversion from electrical to optical color channel values. The curve exponent shall be multiplied by 10000 to get the argument eexp value to carry the precision of 4 decimals. The curve exponent must be at least 1.0 and at most 10.0. Otherwise the protocol error invalid_tf is raised. If transfer characteristic has already been set on this object, the protocol error already_set is raised. This request can be used when the compositor advertises wp_color_manager_v1.feature.set_tf_power. Otherwise this request raises the protocol error unsupported_feature. | |
| 881 | + | func (o *WpImageDescriptionCreatorParams) SetTfPower(eexp uint32) error { | |
| 882 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wp_image_description_creator_params_v1.set_tf_power"}, wl.ArgUint(eexp)); err != nil { | |
| 883 | + | return err | |
| 884 | + | } | |
| 885 | + | return nil | |
| 886 | + | } | |
| 887 | + | ||
| 888 | + | // Sets the color primaries and white point using explicitly named sets. This describes the primary color volume which is the basis for color value encoding. Only names advertised with wp_color_manager_v1 event supported_primaries_named are allowed. Other values shall raise the protocol error invalid_primaries_named. If primaries have already been set on this object, the protocol error already_set is raised. | |
| 889 | + | func (o *WpImageDescriptionCreatorParams) SetPrimariesNamed(primaries uint32) error { | |
| 890 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "wp_image_description_creator_params_v1.set_primaries_named"}, wl.ArgUint(primaries)); err != nil { | |
| 891 | + | return err | |
| 892 | + | } | |
| 893 | + | return nil | |
| 894 | + | } | |
| 895 | + | ||
| 896 | + | // Sets the color primaries and white point using CIE 1931 xy chromaticity coordinates. This describes the primary color volume which is the basis for color value encoding. Each coordinate value is multiplied by 1 million to get the argument value to carry precision of 6 decimals. If primaries have already been set on this object, the protocol error already_set is raised. This request can be used if the compositor advertises wp_color_manager_v1.feature.set_primaries. Otherwise this request raises the protocol error unsupported_feature. | |
| 897 | + | func (o *WpImageDescriptionCreatorParams) SetPrimaries(rX int32, rY int32, gX int32, gY int32, bX int32, bY int32, wX int32, wY int32) error { | |
| 898 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 4, Name: "wp_image_description_creator_params_v1.set_primaries"}, wl.ArgInt(rX), wl.ArgInt(rY), wl.ArgInt(gX), wl.ArgInt(gY), wl.ArgInt(bX), wl.ArgInt(bY), wl.ArgInt(wX), wl.ArgInt(wY)); err != nil { | |
| 899 | + | return err | |
| 900 | + | } | |
| 901 | + | return nil | |
| 902 | + | } | |
| 903 | + | ||
| 904 | + | // Sets the primary color volume luminance range and the reference white luminance level. These values include the minimum display emission, but not external flare. The minimum display emission is assumed to have the chromaticity of the primary color volume white point. The default luminances from https://www.color.org/chardata/rgb/srgb.xalter are - primary color volume minimum: 0.2 cd/m² - primary color volume maximum: 80 cd/m² - reference white: 80 cd/m² Setting a named transfer characteristic can imply other default luminances. The default luminances get overwritten when this request is used. With transfer_function.st2084_pq the given 'max_lum' value is ignored, and 'max_lum' is taken as 'min_lum' + 10000 cd/m². 'min_lum' and 'max_lum' specify the minimum and maximum luminances of the primary color volume as reproduced by the targeted display. 'reference_lum' specifies the luminance of the reference white as reproduced by the targeted display, and reflects the targeted viewing environment. Compositors should make sure that all content is anchored, meaning that an input signal level of 'reference_lum' on one image description and another input signal level of 'reference_lum' on another image description should produce the same output level, even though the 'reference_lum' on both image representations can be different. 'reference_lum' may be higher than 'max_lum'. In that case reaching the reference white output level in image content requires the 'extended_target_volume' feature support. If 'max_lum' or 'reference_lum' are less than or equal to 'min_lum', the protocol error invalid_luminance is raised. The minimum luminance is multiplied by 10000 to get the argument 'min_lum' value and carries precision of 4 decimals. The maximum luminance and reference white luminance values are unscaled. If the primary color volume luminance range and the reference white luminance level have already been set on this object, the protocol error already_set is raised. This request can be used if the compositor advertises wp_color_manager_v1.feature.set_luminances. Otherwise this request raises the protocol error unsupported_feature. | |
| 905 | + | func (o *WpImageDescriptionCreatorParams) SetLuminances(minLum uint32, maxLum uint32, referenceLum uint32) error { | |
| 906 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 5, Name: "wp_image_description_creator_params_v1.set_luminances"}, wl.ArgUint(minLum), wl.ArgUint(maxLum), wl.ArgUint(referenceLum)); err != nil { | |
| 907 | + | return err | |
| 908 | + | } | |
| 909 | + | return nil | |
| 910 | + | } | |
| 911 | + | ||
| 912 | + | // Provides the color primaries and white point of the mastering display using CIE 1931 xy chromaticity coordinates. This is compatible with the SMPTE ST 2086 definition of HDR static metadata. The mastering display primaries and mastering display luminances define the target color volume. If mastering display primaries are not explicitly set, the target color volume is assumed to have the same primaries as the primary color volume. The target color volume is defined by all tristimulus values between 0.0 and 1.0 (inclusive) of the color space defined by the given mastering display primaries and white point. The colorimetry is identical between the container color space and the mastering display color space, including that no chromatic adaptation is applied even if the white points differ. The target color volume can exceed the primary color volume to allow for a greater color volume with an existing color space definition (for example scRGB). It can be smaller than the primary color volume to minimize gamut and tone mapping distances for big color spaces (HDR metadata). To make use of the entire target color volume a suitable pixel format has to be chosen (e.g. floating point to exceed the primary color volume, or abusing limited quantization range as with xvYCC). Each coordinate value is multiplied by 1 million to get the argument value to carry precision of 6 decimals. If mastering display primaries have already been set on this object, the protocol error already_set is raised. This request can be used if the compositor advertises wp_color_manager_v1.feature.set_mastering_display_primaries. Otherwise this request raises the protocol error unsupported_feature. The advertisement implies support only for target color volumes fully contained within the primary color volume. If a compositor additionally supports target color volume exceeding the primary color volume, it must advertise wp_color_manager_v1.feature.extended_target_volume. If a client uses target color volume exceeding the primary color volume and the compositor does not support it, the result is implementation defined. Compositors are recommended to detect this case and fail the image description gracefully, but it may as well result in color artifacts. | |
| 913 | + | func (o *WpImageDescriptionCreatorParams) SetMasteringDisplayPrimaries(rX int32, rY int32, gX int32, gY int32, bX int32, bY int32, wX int32, wY int32) error { | |
| 914 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 6, Name: "wp_image_description_creator_params_v1.set_mastering_display_primaries"}, wl.ArgInt(rX), wl.ArgInt(rY), wl.ArgInt(gX), wl.ArgInt(gY), wl.ArgInt(bX), wl.ArgInt(bY), wl.ArgInt(wX), wl.ArgInt(wY)); err != nil { | |
| 915 | + | return err | |
| 916 | + | } | |
| 917 | + | return nil | |
| 918 | + | } | |
| 919 | + | ||
| 920 | + | // Sets the luminance range that was used during the content mastering process as the minimum and maximum absolute luminance L. These values include the minimum display emission and ambient flare luminances, assumed to be optically additive and have the chromaticity of the primary color volume white point. This should be compatible with the SMPTE ST 2086 definition of HDR static metadata. The mastering display primaries and mastering display luminances define the target color volume. If mastering luminances are not explicitly set, the target color volume is assumed to have the same min and max luminances as the primary color volume. If max L is less than or equal to min L, the protocol error invalid_luminance is raised. Min L value is multiplied by 10000 to get the argument min_lum value and carry precision of 4 decimals. Max L value is unscaled for max_lum. This request can be used if the compositor advertises wp_color_manager_v1.feature.set_mastering_display_primaries. Otherwise this request raises the protocol error unsupported_feature. The advertisement implies support only for target color volumes fully contained within the primary color volume. If a compositor additionally supports target color volume exceeding the primary color volume, it must advertise wp_color_manager_v1.feature.extended_target_volume. If a client uses target color volume exceeding the primary color volume and the compositor does not support it, the result is implementation defined. Compositors are recommended to detect this case and fail the image description gracefully, but it may as well result in color artifacts. | |
| 921 | + | func (o *WpImageDescriptionCreatorParams) SetMasteringLuminance(minLum uint32, maxLum uint32) error { | |
| 922 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 7, Name: "wp_image_description_creator_params_v1.set_mastering_luminance"}, wl.ArgUint(minLum), wl.ArgUint(maxLum)); err != nil { | |
| 923 | + | return err | |
| 924 | + | } | |
| 925 | + | return nil | |
| 926 | + | } | |
| 927 | + | ||
| 928 | + | // Sets the maximum content light level (max_cll) as defined by CTA-861-H. max_cll is undefined by default. | |
| 929 | + | func (o *WpImageDescriptionCreatorParams) SetMaxCll(maxCll uint32) error { | |
| 930 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 8, Name: "wp_image_description_creator_params_v1.set_max_cll"}, wl.ArgUint(maxCll)); err != nil { | |
| 931 | + | return err | |
| 932 | + | } | |
| 933 | + | return nil | |
| 934 | + | } | |
| 935 | + | ||
| 936 | + | // Sets the maximum frame-average light level (max_fall) as defined by CTA-861-H. max_fall is undefined by default. | |
| 937 | + | func (o *WpImageDescriptionCreatorParams) SetMaxFall(maxFall uint32) error { | |
| 938 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 9, Name: "wp_image_description_creator_params_v1.set_max_fall"}, wl.ArgUint(maxFall)); err != nil { | |
| 939 | + | return err | |
| 940 | + | } | |
| 941 | + | return nil | |
| 942 | + | } | |
| 943 | + | ||
| 944 | + | // EventSignature returns the declared event argument types in wire order. | |
| 945 | + | func (o *WpImageDescriptionCreatorParams) EventSignature(opcode uint16) (string, bool) { | |
| 946 | + | switch opcode { | |
| 947 | + | default: | |
| 948 | + | return "", false | |
| 949 | + | } | |
| 950 | + | } | |
| 951 | + | ||
| 952 | + | // Dispatch decodes one event on wp_image_description_creator_params_v1 and calls the registered handlers. | |
| 953 | + | func (o *WpImageDescriptionCreatorParams) Dispatch(event *wl.Event) { | |
| 954 | + | switch event.Opcode { | |
| 955 | + | default: | |
| 956 | + | } | |
| 957 | + | } | |
| 958 | + | ||
| 959 | + | // WpImageDescriptionInterface is the protocol interface name. | |
| 960 | + | const WpImageDescriptionInterface = "wp_image_description_v1" | |
| 961 | + | ||
| 962 | + | // WpImageDescription is the generated binding for wp_image_description_v1 version 3. | |
| 963 | + | type WpImageDescription struct { | |
| 964 | + | wl.BaseProxy | |
| 965 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 966 | + | // handlers while another goroutine dispatches events. | |
| 967 | + | handlersMu sync.Mutex | |
| 968 | + | onFailed []func(cause uint32, msg string) | |
| 969 | + | onReady []func(identity uint32) | |
| 970 | + | onReady2 []func(identityHi uint32, identityLo uint32) | |
| 971 | + | } | |
| 972 | + | ||
| 973 | + | // NewWpImageDescription returns an unbound WpImageDescription. | |
| 974 | + | func NewWpImageDescription(ctx *wl.Context) *WpImageDescription { | |
| 975 | + | obj := &WpImageDescription{} | |
| 976 | + | obj.SetContext(ctx) | |
| 977 | + | ctx.Register(obj) | |
| 978 | + | return obj | |
| 979 | + | } | |
| 980 | + | ||
| 981 | + | // Destroy this object. It is safe to destroy an object which is not ready. Destroying a wp_image_description_v1 object has no side-effects, not even if a wp_color_management_surface_v1.set_image_description has not yet been followed by a wl_surface.commit. | |
| 982 | + | func (o *WpImageDescription) Destroy() error { | |
| 983 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_image_description_v1.destroy", Destructor: true}); err != nil { | |
| 984 | + | return err | |
| 985 | + | } | |
| 986 | + | return nil | |
| 987 | + | } | |
| 988 | + | ||
| 989 | + | // Creates a wp_image_description_info_v1 object which delivers the information that makes up the image description. Not all image description protocol objects allow get_information request. Whether it is allowed or not is defined by the request that created the object. If get_information is not allowed, the protocol error no_information is raised. | |
| 990 | + | func (o *WpImageDescription) GetInformation() (*WpImageDescriptionInfo, error) { | |
| 991 | + | child := &WpImageDescriptionInfo{} | |
| 992 | + | child.SetContext(o.Context()) | |
| 993 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_image_description_v1.get_information", Child: child}, wl.ArgObject(child)); err != nil { | |
| 994 | + | return nil, err | |
| 995 | + | } | |
| 996 | + | return child, nil | |
| 997 | + | } | |
| 998 | + | ||
| 999 | + | // OnFailed registers a handler for the failed event. | |
| 1000 | + | // | |
| 1001 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1002 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1003 | + | func (o *WpImageDescription) OnFailed(handler func(cause uint32, msg string)) { | |
| 1004 | + | if handler == nil { | |
| 1005 | + | return | |
| 1006 | + | } | |
| 1007 | + | o.handlersMu.Lock() | |
| 1008 | + | defer o.handlersMu.Unlock() | |
| 1009 | + | o.onFailed = append(o.onFailed, handler) | |
| 1010 | + | } | |
| 1011 | + | ||
| 1012 | + | // handlersForFailed returns the handlers registered for failed, taken | |
| 1013 | + | // under the lock so a handler may register another handler while events are | |
| 1014 | + | // being dispatched. | |
| 1015 | + | func (o *WpImageDescription) handlersForFailed() []func(cause uint32, msg string) { | |
| 1016 | + | o.handlersMu.Lock() | |
| 1017 | + | defer o.handlersMu.Unlock() | |
| 1018 | + | return o.onFailed | |
| 1019 | + | } | |
| 1020 | + | ||
| 1021 | + | // OnReady registers a handler for the ready event. | |
| 1022 | + | // | |
| 1023 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1024 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1025 | + | func (o *WpImageDescription) OnReady(handler func(identity uint32)) { | |
| 1026 | + | if handler == nil { | |
| 1027 | + | return | |
| 1028 | + | } | |
| 1029 | + | o.handlersMu.Lock() | |
| 1030 | + | defer o.handlersMu.Unlock() | |
| 1031 | + | o.onReady = append(o.onReady, handler) | |
| 1032 | + | } | |
| 1033 | + | ||
| 1034 | + | // handlersForReady returns the handlers registered for ready, taken | |
| 1035 | + | // under the lock so a handler may register another handler while events are | |
| 1036 | + | // being dispatched. | |
| 1037 | + | func (o *WpImageDescription) handlersForReady() []func(identity uint32) { | |
| 1038 | + | o.handlersMu.Lock() | |
| 1039 | + | defer o.handlersMu.Unlock() | |
| 1040 | + | return o.onReady | |
| 1041 | + | } | |
| 1042 | + | ||
| 1043 | + | // OnReady2 registers a handler for the ready2 event. | |
| 1044 | + | // | |
| 1045 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1046 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1047 | + | func (o *WpImageDescription) OnReady2(handler func(identityHi uint32, identityLo uint32)) { | |
| 1048 | + | if handler == nil { | |
| 1049 | + | return | |
| 1050 | + | } | |
| 1051 | + | o.handlersMu.Lock() | |
| 1052 | + | defer o.handlersMu.Unlock() | |
| 1053 | + | o.onReady2 = append(o.onReady2, handler) | |
| 1054 | + | } | |
| 1055 | + | ||
| 1056 | + | // handlersForReady2 returns the handlers registered for ready2, taken | |
| 1057 | + | // under the lock so a handler may register another handler while events are | |
| 1058 | + | // being dispatched. | |
| 1059 | + | func (o *WpImageDescription) handlersForReady2() []func(identityHi uint32, identityLo uint32) { | |
| 1060 | + | o.handlersMu.Lock() | |
| 1061 | + | defer o.handlersMu.Unlock() | |
| 1062 | + | return o.onReady2 | |
| 1063 | + | } | |
| 1064 | + | ||
| 1065 | + | // EventSignature returns the declared event argument types in wire order. | |
| 1066 | + | func (o *WpImageDescription) EventSignature(opcode uint16) (string, bool) { | |
| 1067 | + | switch opcode { | |
| 1068 | + | case 0: | |
| 1069 | + | return "uint,string,", true | |
| 1070 | + | case 1: | |
| 1071 | + | return "uint,", true | |
| 1072 | + | case 2: | |
| 1073 | + | return "uint,uint,", true | |
| 1074 | + | default: | |
| 1075 | + | return "", false | |
| 1076 | + | } | |
| 1077 | + | } | |
| 1078 | + | ||
| 1079 | + | // Dispatch decodes one event on wp_image_description_v1 and calls the registered handlers. | |
| 1080 | + | func (o *WpImageDescription) Dispatch(event *wl.Event) { | |
| 1081 | + | switch event.Opcode { | |
| 1082 | + | case 0: // failed | |
| 1083 | + | cause := event.Uint32() | |
| 1084 | + | msg := event.String() | |
| 1085 | + | ||
| 1086 | + | for i, handler := range o.handlersForFailed() { | |
| 1087 | + | _ = i | |
| 1088 | + | handler(cause, msg) | |
| 1089 | + | } | |
| 1090 | + | case 1: // ready | |
| 1091 | + | identity := event.Uint32() | |
| 1092 | + | ||
| 1093 | + | for i, handler := range o.handlersForReady() { | |
| 1094 | + | _ = i | |
| 1095 | + | handler(identity) | |
| 1096 | + | } | |
| 1097 | + | case 2: // ready2 | |
| 1098 | + | identityHi := event.Uint32() | |
| 1099 | + | identityLo := event.Uint32() | |
| 1100 | + | ||
| 1101 | + | for i, handler := range o.handlersForReady2() { | |
| 1102 | + | _ = i | |
| 1103 | + | handler(identityHi, identityLo) | |
| 1104 | + | } | |
| 1105 | + | default: | |
| 1106 | + | } | |
| 1107 | + | } | |
| 1108 | + | ||
| 1109 | + | // WpImageDescriptionInfoInterface is the protocol interface name. | |
| 1110 | + | const WpImageDescriptionInfoInterface = "wp_image_description_info_v1" | |
| 1111 | + | ||
| 1112 | + | // WpImageDescriptionInfo is the generated binding for wp_image_description_info_v1 version 3. | |
| 1113 | + | type WpImageDescriptionInfo struct { | |
| 1114 | + | wl.BaseProxy | |
| 1115 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 1116 | + | // handlers while another goroutine dispatches events. | |
| 1117 | + | handlersMu sync.Mutex | |
| 1118 | + | onDone []func() | |
| 1119 | + | onIccFile []func(icc *wl.OwnedFD, iccSize uint32) | |
| 1120 | + | onPrimaries []func(rX int32, rY int32, gX int32, gY int32, bX int32, bY int32, wX int32, wY int32) | |
| 1121 | + | onPrimariesNamed []func(primaries uint32) | |
| 1122 | + | onTfPower []func(eexp uint32) | |
| 1123 | + | onTfNamed []func(tf uint32) | |
| 1124 | + | onLuminances []func(minLum uint32, maxLum uint32, referenceLum uint32) | |
| 1125 | + | onTargetPrimaries []func(rX int32, rY int32, gX int32, gY int32, bX int32, bY int32, wX int32, wY int32) | |
| 1126 | + | onTargetLuminance []func(minLum uint32, maxLum uint32) | |
| 1127 | + | onTargetMaxCll []func(maxCll uint32) | |
| 1128 | + | onTargetMaxFall []func(maxFall uint32) | |
| 1129 | + | } | |
| 1130 | + | ||
| 1131 | + | // NewWpImageDescriptionInfo returns an unbound WpImageDescriptionInfo. | |
| 1132 | + | func NewWpImageDescriptionInfo(ctx *wl.Context) *WpImageDescriptionInfo { | |
| 1133 | + | obj := &WpImageDescriptionInfo{} | |
| 1134 | + | obj.SetContext(ctx) | |
| 1135 | + | ctx.Register(obj) | |
| 1136 | + | return obj | |
| 1137 | + | } | |
| 1138 | + | ||
| 1139 | + | // OnDone registers a handler for the done event. | |
| 1140 | + | // | |
| 1141 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1142 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1143 | + | func (o *WpImageDescriptionInfo) OnDone(handler func()) { | |
| 1144 | + | if handler == nil { | |
| 1145 | + | return | |
| 1146 | + | } | |
| 1147 | + | o.handlersMu.Lock() | |
| 1148 | + | defer o.handlersMu.Unlock() | |
| 1149 | + | o.onDone = append(o.onDone, handler) | |
| 1150 | + | } | |
| 1151 | + | ||
| 1152 | + | // handlersForDone returns the handlers registered for done, taken | |
| 1153 | + | // under the lock so a handler may register another handler while events are | |
| 1154 | + | // being dispatched. | |
| 1155 | + | func (o *WpImageDescriptionInfo) handlersForDone() []func() { | |
| 1156 | + | o.handlersMu.Lock() | |
| 1157 | + | defer o.handlersMu.Unlock() | |
| 1158 | + | return o.onDone | |
| 1159 | + | } | |
| 1160 | + | ||
| 1161 | + | // OnIccFile registers a handler for the icc_file event. | |
| 1162 | + | // | |
| 1163 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1164 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1165 | + | func (o *WpImageDescriptionInfo) OnIccFile(handler func(icc *wl.OwnedFD, iccSize uint32)) { | |
| 1166 | + | if handler == nil { | |
| 1167 | + | return | |
| 1168 | + | } | |
| 1169 | + | o.handlersMu.Lock() | |
| 1170 | + | defer o.handlersMu.Unlock() | |
| 1171 | + | o.onIccFile = append(o.onIccFile, handler) | |
| 1172 | + | } | |
| 1173 | + | ||
| 1174 | + | // handlersForIccFile returns the handlers registered for icc_file, taken | |
| 1175 | + | // under the lock so a handler may register another handler while events are | |
| 1176 | + | // being dispatched. | |
| 1177 | + | func (o *WpImageDescriptionInfo) handlersForIccFile() []func(icc *wl.OwnedFD, iccSize uint32) { | |
| 1178 | + | o.handlersMu.Lock() | |
| 1179 | + | defer o.handlersMu.Unlock() | |
| 1180 | + | return o.onIccFile | |
| 1181 | + | } | |
| 1182 | + | ||
| 1183 | + | // OnPrimaries registers a handler for the primaries event. | |
| 1184 | + | // | |
| 1185 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1186 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1187 | + | func (o *WpImageDescriptionInfo) OnPrimaries(handler func(rX int32, rY int32, gX int32, gY int32, bX int32, bY int32, wX int32, wY int32)) { | |
| 1188 | + | if handler == nil { | |
| 1189 | + | return | |
| 1190 | + | } | |
| 1191 | + | o.handlersMu.Lock() | |
| 1192 | + | defer o.handlersMu.Unlock() | |
| 1193 | + | o.onPrimaries = append(o.onPrimaries, handler) | |
| 1194 | + | } | |
| 1195 | + | ||
| 1196 | + | // handlersForPrimaries returns the handlers registered for primaries, taken | |
| 1197 | + | // under the lock so a handler may register another handler while events are | |
| 1198 | + | // being dispatched. | |
| 1199 | + | func (o *WpImageDescriptionInfo) handlersForPrimaries() []func(rX int32, rY int32, gX int32, gY int32, bX int32, bY int32, wX int32, wY int32) { | |
| 1200 | + | o.handlersMu.Lock() | |
| 1201 | + | defer o.handlersMu.Unlock() | |
| 1202 | + | return o.onPrimaries | |
| 1203 | + | } | |
| 1204 | + | ||
| 1205 | + | // OnPrimariesNamed registers a handler for the primaries_named event. | |
| 1206 | + | // | |
| 1207 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1208 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1209 | + | func (o *WpImageDescriptionInfo) OnPrimariesNamed(handler func(primaries uint32)) { | |
| 1210 | + | if handler == nil { | |
| 1211 | + | return | |
| 1212 | + | } | |
| 1213 | + | o.handlersMu.Lock() | |
| 1214 | + | defer o.handlersMu.Unlock() | |
| 1215 | + | o.onPrimariesNamed = append(o.onPrimariesNamed, handler) | |
| 1216 | + | } | |
| 1217 | + | ||
| 1218 | + | // handlersForPrimariesNamed returns the handlers registered for primaries_named, taken | |
| 1219 | + | // under the lock so a handler may register another handler while events are | |
| 1220 | + | // being dispatched. | |
| 1221 | + | func (o *WpImageDescriptionInfo) handlersForPrimariesNamed() []func(primaries uint32) { | |
| 1222 | + | o.handlersMu.Lock() | |
| 1223 | + | defer o.handlersMu.Unlock() | |
| 1224 | + | return o.onPrimariesNamed | |
| 1225 | + | } | |
| 1226 | + | ||
| 1227 | + | // OnTfPower registers a handler for the tf_power event. | |
| 1228 | + | // | |
| 1229 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1230 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1231 | + | func (o *WpImageDescriptionInfo) OnTfPower(handler func(eexp uint32)) { | |
| 1232 | + | if handler == nil { | |
| 1233 | + | return | |
| 1234 | + | } | |
| 1235 | + | o.handlersMu.Lock() | |
| 1236 | + | defer o.handlersMu.Unlock() | |
| 1237 | + | o.onTfPower = append(o.onTfPower, handler) | |
| 1238 | + | } | |
| 1239 | + | ||
| 1240 | + | // handlersForTfPower returns the handlers registered for tf_power, taken | |
| 1241 | + | // under the lock so a handler may register another handler while events are | |
| 1242 | + | // being dispatched. | |
| 1243 | + | func (o *WpImageDescriptionInfo) handlersForTfPower() []func(eexp uint32) { | |
| 1244 | + | o.handlersMu.Lock() | |
| 1245 | + | defer o.handlersMu.Unlock() | |
| 1246 | + | return o.onTfPower | |
| 1247 | + | } | |
| 1248 | + | ||
| 1249 | + | // OnTfNamed registers a handler for the tf_named event. | |
| 1250 | + | // | |
| 1251 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1252 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1253 | + | func (o *WpImageDescriptionInfo) OnTfNamed(handler func(tf uint32)) { | |
| 1254 | + | if handler == nil { | |
| 1255 | + | return | |
| 1256 | + | } | |
| 1257 | + | o.handlersMu.Lock() | |
| 1258 | + | defer o.handlersMu.Unlock() | |
| 1259 | + | o.onTfNamed = append(o.onTfNamed, handler) | |
| 1260 | + | } | |
| 1261 | + | ||
| 1262 | + | // handlersForTfNamed returns the handlers registered for tf_named, taken | |
| 1263 | + | // under the lock so a handler may register another handler while events are | |
| 1264 | + | // being dispatched. | |
| 1265 | + | func (o *WpImageDescriptionInfo) handlersForTfNamed() []func(tf uint32) { | |
| 1266 | + | o.handlersMu.Lock() | |
| 1267 | + | defer o.handlersMu.Unlock() | |
| 1268 | + | return o.onTfNamed | |
| 1269 | + | } | |
| 1270 | + | ||
| 1271 | + | // OnLuminances registers a handler for the luminances event. | |
| 1272 | + | // | |
| 1273 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1274 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1275 | + | func (o *WpImageDescriptionInfo) OnLuminances(handler func(minLum uint32, maxLum uint32, referenceLum uint32)) { | |
| 1276 | + | if handler == nil { | |
| 1277 | + | return | |
| 1278 | + | } | |
| 1279 | + | o.handlersMu.Lock() | |
| 1280 | + | defer o.handlersMu.Unlock() | |
| 1281 | + | o.onLuminances = append(o.onLuminances, handler) | |
| 1282 | + | } | |
| 1283 | + | ||
| 1284 | + | // handlersForLuminances returns the handlers registered for luminances, taken | |
| 1285 | + | // under the lock so a handler may register another handler while events are | |
| 1286 | + | // being dispatched. | |
| 1287 | + | func (o *WpImageDescriptionInfo) handlersForLuminances() []func(minLum uint32, maxLum uint32, referenceLum uint32) { | |
| 1288 | + | o.handlersMu.Lock() | |
| 1289 | + | defer o.handlersMu.Unlock() | |
| 1290 | + | return o.onLuminances | |
| 1291 | + | } | |
| 1292 | + | ||
| 1293 | + | // OnTargetPrimaries registers a handler for the target_primaries event. | |
| 1294 | + | // | |
| 1295 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1296 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1297 | + | func (o *WpImageDescriptionInfo) OnTargetPrimaries(handler func(rX int32, rY int32, gX int32, gY int32, bX int32, bY int32, wX int32, wY int32)) { | |
| 1298 | + | if handler == nil { | |
| 1299 | + | return | |
| 1300 | + | } | |
| 1301 | + | o.handlersMu.Lock() | |
| 1302 | + | defer o.handlersMu.Unlock() | |
| 1303 | + | o.onTargetPrimaries = append(o.onTargetPrimaries, handler) | |
| 1304 | + | } | |
| 1305 | + | ||
| 1306 | + | // handlersForTargetPrimaries returns the handlers registered for target_primaries, taken | |
| 1307 | + | // under the lock so a handler may register another handler while events are | |
| 1308 | + | // being dispatched. | |
| 1309 | + | func (o *WpImageDescriptionInfo) handlersForTargetPrimaries() []func(rX int32, rY int32, gX int32, gY int32, bX int32, bY int32, wX int32, wY int32) { | |
| 1310 | + | o.handlersMu.Lock() | |
| 1311 | + | defer o.handlersMu.Unlock() | |
| 1312 | + | return o.onTargetPrimaries | |
| 1313 | + | } | |
| 1314 | + | ||
| 1315 | + | // OnTargetLuminance registers a handler for the target_luminance event. | |
| 1316 | + | // | |
| 1317 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1318 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1319 | + | func (o *WpImageDescriptionInfo) OnTargetLuminance(handler func(minLum uint32, maxLum uint32)) { | |
| 1320 | + | if handler == nil { | |
| 1321 | + | return | |
| 1322 | + | } | |
| 1323 | + | o.handlersMu.Lock() | |
| 1324 | + | defer o.handlersMu.Unlock() | |
| 1325 | + | o.onTargetLuminance = append(o.onTargetLuminance, handler) | |
| 1326 | + | } | |
| 1327 | + | ||
| 1328 | + | // handlersForTargetLuminance returns the handlers registered for target_luminance, taken | |
| 1329 | + | // under the lock so a handler may register another handler while events are | |
| 1330 | + | // being dispatched. | |
| 1331 | + | func (o *WpImageDescriptionInfo) handlersForTargetLuminance() []func(minLum uint32, maxLum uint32) { | |
| 1332 | + | o.handlersMu.Lock() | |
| 1333 | + | defer o.handlersMu.Unlock() | |
| 1334 | + | return o.onTargetLuminance | |
| 1335 | + | } | |
| 1336 | + | ||
| 1337 | + | // OnTargetMaxCll registers a handler for the target_max_cll event. | |
| 1338 | + | // | |
| 1339 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1340 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1341 | + | func (o *WpImageDescriptionInfo) OnTargetMaxCll(handler func(maxCll uint32)) { | |
| 1342 | + | if handler == nil { | |
| 1343 | + | return | |
| 1344 | + | } | |
| 1345 | + | o.handlersMu.Lock() | |
| 1346 | + | defer o.handlersMu.Unlock() | |
| 1347 | + | o.onTargetMaxCll = append(o.onTargetMaxCll, handler) | |
| 1348 | + | } | |
| 1349 | + | ||
| 1350 | + | // handlersForTargetMaxCll returns the handlers registered for target_max_cll, taken | |
| 1351 | + | // under the lock so a handler may register another handler while events are | |
| 1352 | + | // being dispatched. | |
| 1353 | + | func (o *WpImageDescriptionInfo) handlersForTargetMaxCll() []func(maxCll uint32) { | |
| 1354 | + | o.handlersMu.Lock() | |
| 1355 | + | defer o.handlersMu.Unlock() | |
| 1356 | + | return o.onTargetMaxCll | |
| 1357 | + | } | |
| 1358 | + | ||
| 1359 | + | // OnTargetMaxFall registers a handler for the target_max_fall event. | |
| 1360 | + | // | |
| 1361 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1362 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1363 | + | func (o *WpImageDescriptionInfo) OnTargetMaxFall(handler func(maxFall uint32)) { | |
| 1364 | + | if handler == nil { | |
| 1365 | + | return | |
| 1366 | + | } | |
| 1367 | + | o.handlersMu.Lock() | |
| 1368 | + | defer o.handlersMu.Unlock() | |
| 1369 | + | o.onTargetMaxFall = append(o.onTargetMaxFall, handler) | |
| 1370 | + | } | |
| 1371 | + | ||
| 1372 | + | // handlersForTargetMaxFall returns the handlers registered for target_max_fall, taken | |
| 1373 | + | // under the lock so a handler may register another handler while events are | |
| 1374 | + | // being dispatched. | |
| 1375 | + | func (o *WpImageDescriptionInfo) handlersForTargetMaxFall() []func(maxFall uint32) { | |
| 1376 | + | o.handlersMu.Lock() | |
| 1377 | + | defer o.handlersMu.Unlock() | |
| 1378 | + | return o.onTargetMaxFall | |
| 1379 | + | } | |
| 1380 | + | ||
| 1381 | + | // EventSignature returns the declared event argument types in wire order. | |
| 1382 | + | func (o *WpImageDescriptionInfo) EventSignature(opcode uint16) (string, bool) { | |
| 1383 | + | switch opcode { | |
| 1384 | + | case 0: | |
| 1385 | + | return "", true | |
| 1386 | + | case 1: | |
| 1387 | + | return "fd,uint,", true | |
| 1388 | + | case 2: | |
| 1389 | + | return "int,int,int,int,int,int,int,int,", true | |
| 1390 | + | case 3: | |
| 1391 | + | return "uint,", true | |
| 1392 | + | case 4: | |
| 1393 | + | return "uint,", true | |
| 1394 | + | case 5: | |
| 1395 | + | return "uint,", true | |
| 1396 | + | case 6: | |
| 1397 | + | return "uint,uint,uint,", true | |
| 1398 | + | case 7: | |
| 1399 | + | return "int,int,int,int,int,int,int,int,", true | |
| 1400 | + | case 8: | |
| 1401 | + | return "uint,uint,", true | |
| 1402 | + | case 9: | |
| 1403 | + | return "uint,", true | |
| 1404 | + | case 10: | |
| 1405 | + | return "uint,", true | |
| 1406 | + | default: | |
| 1407 | + | return "", false | |
| 1408 | + | } | |
| 1409 | + | } | |
| 1410 | + | ||
| 1411 | + | // Dispatch decodes one event on wp_image_description_info_v1 and calls the registered handlers. | |
| 1412 | + | func (o *WpImageDescriptionInfo) Dispatch(event *wl.Event) { | |
| 1413 | + | switch event.Opcode { | |
| 1414 | + | case 0: // done | |
| 1415 | + | ||
| 1416 | + | for i, handler := range o.handlersForDone() { | |
| 1417 | + | _ = i | |
| 1418 | + | handler() | |
| 1419 | + | } | |
| 1420 | + | o.Context().Unregister(o) | |
| 1421 | + | case 1: // icc_file | |
| 1422 | + | icc := event.FD() | |
| 1423 | + | iccSize := event.Uint32() | |
| 1424 | + | ownedicc := icc | |
| 1425 | + | defer ownedicc.Close() | |
| 1426 | + | ||
| 1427 | + | for i, handler := range o.handlersForIccFile() { | |
| 1428 | + | if i > 0 { | |
| 1429 | + | icc = nil | |
| 1430 | + | } | |
| 1431 | + | handler(icc, iccSize) | |
| 1432 | + | } | |
| 1433 | + | case 2: // primaries | |
| 1434 | + | rX := event.Int32() | |
| 1435 | + | rY := event.Int32() | |
| 1436 | + | gX := event.Int32() | |
| 1437 | + | gY := event.Int32() | |
| 1438 | + | bX := event.Int32() | |
| 1439 | + | bY := event.Int32() | |
| 1440 | + | wX := event.Int32() | |
| 1441 | + | wY := event.Int32() | |
| 1442 | + | ||
| 1443 | + | for i, handler := range o.handlersForPrimaries() { | |
| 1444 | + | _ = i | |
| 1445 | + | handler(rX, rY, gX, gY, bX, bY, wX, wY) | |
| 1446 | + | } | |
| 1447 | + | case 3: // primaries_named | |
| 1448 | + | primaries := event.Uint32() | |
| 1449 | + | ||
| 1450 | + | for i, handler := range o.handlersForPrimariesNamed() { | |
| 1451 | + | _ = i | |
| 1452 | + | handler(primaries) | |
| 1453 | + | } | |
| 1454 | + | case 4: // tf_power | |
| 1455 | + | eexp := event.Uint32() | |
| 1456 | + | ||
| 1457 | + | for i, handler := range o.handlersForTfPower() { | |
| 1458 | + | _ = i | |
| 1459 | + | handler(eexp) | |
| 1460 | + | } | |
| 1461 | + | case 5: // tf_named | |
| 1462 | + | tf := event.Uint32() | |
| 1463 | + | ||
| 1464 | + | for i, handler := range o.handlersForTfNamed() { | |
| 1465 | + | _ = i | |
| 1466 | + | handler(tf) | |
| 1467 | + | } | |
| 1468 | + | case 6: // luminances | |
| 1469 | + | minLum := event.Uint32() | |
| 1470 | + | maxLum := event.Uint32() | |
| 1471 | + | referenceLum := event.Uint32() | |
| 1472 | + | ||
| 1473 | + | for i, handler := range o.handlersForLuminances() { | |
| 1474 | + | _ = i | |
| 1475 | + | handler(minLum, maxLum, referenceLum) | |
| 1476 | + | } | |
| 1477 | + | case 7: // target_primaries | |
| 1478 | + | rX := event.Int32() | |
| 1479 | + | rY := event.Int32() | |
| 1480 | + | gX := event.Int32() | |
| 1481 | + | gY := event.Int32() | |
| 1482 | + | bX := event.Int32() | |
| 1483 | + | bY := event.Int32() | |
| 1484 | + | wX := event.Int32() | |
| 1485 | + | wY := event.Int32() | |
| 1486 | + | ||
| 1487 | + | for i, handler := range o.handlersForTargetPrimaries() { | |
| 1488 | + | _ = i | |
| 1489 | + | handler(rX, rY, gX, gY, bX, bY, wX, wY) | |
| 1490 | + | } | |
| 1491 | + | case 8: // target_luminance | |
| 1492 | + | minLum := event.Uint32() | |
| 1493 | + | maxLum := event.Uint32() | |
| 1494 | + | ||
| 1495 | + | for i, handler := range o.handlersForTargetLuminance() { | |
| 1496 | + | _ = i | |
| 1497 | + | handler(minLum, maxLum) | |
| 1498 | + | } | |
| 1499 | + | case 9: // target_max_cll | |
| 1500 | + | maxCll := event.Uint32() | |
| 1501 | + | ||
| 1502 | + | for i, handler := range o.handlersForTargetMaxCll() { | |
| 1503 | + | _ = i | |
| 1504 | + | handler(maxCll) | |
| 1505 | + | } | |
| 1506 | + | case 10: // target_max_fall | |
| 1507 | + | maxFall := event.Uint32() | |
| 1508 | + | ||
| 1509 | + | for i, handler := range o.handlersForTargetMaxFall() { | |
| 1510 | + | _ = i | |
| 1511 | + | handler(maxFall) | |
| 1512 | + | } | |
| 1513 | + | default: | |
| 1514 | + | } | |
| 1515 | + | } | |
| 1516 | + | ||
| 1517 | + | // WpImageDescriptionReferenceInterface is the protocol interface name. | |
| 1518 | + | const WpImageDescriptionReferenceInterface = "wp_image_description_reference_v1" | |
| 1519 | + | ||
| 1520 | + | // WpImageDescriptionReference is the generated binding for wp_image_description_reference_v1 version 1. | |
| 1521 | + | type WpImageDescriptionReference struct { | |
| 1522 | + | wl.BaseProxy | |
| 1523 | + | } | |
| 1524 | + | ||
| 1525 | + | // NewWpImageDescriptionReference returns an unbound WpImageDescriptionReference. | |
| 1526 | + | func NewWpImageDescriptionReference(ctx *wl.Context) *WpImageDescriptionReference { | |
| 1527 | + | obj := &WpImageDescriptionReference{} | |
| 1528 | + | obj.SetContext(ctx) | |
| 1529 | + | ctx.Register(obj) | |
| 1530 | + | return obj | |
| 1531 | + | } | |
| 1532 | + | ||
| 1533 | + | // Destroy this object. This has no effect on the referenced image description. | |
| 1534 | + | func (o *WpImageDescriptionReference) Destroy() error { | |
| 1535 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_image_description_reference_v1.destroy", Destructor: true}); err != nil { | |
| 1536 | + | return err | |
| 1537 | + | } | |
| 1538 | + | return nil | |
| 1539 | + | } | |
| 1540 | + | ||
| 1541 | + | // EventSignature returns the declared event argument types in wire order. | |
| 1542 | + | func (o *WpImageDescriptionReference) EventSignature(opcode uint16) (string, bool) { | |
| 1543 | + | switch opcode { | |
| 1544 | + | default: | |
| 1545 | + | return "", false | |
| 1546 | + | } | |
| 1547 | + | } | |
| 1548 | + | ||
| 1549 | + | // Dispatch decodes one event on wp_image_description_reference_v1 and calls the registered handlers. | |
| 1550 | + | func (o *WpImageDescriptionReference) Dispatch(event *wl.Event) { | |
| 1551 | + | switch event.Opcode { | |
| 1552 | + | default: | |
| 1553 | + | } | |
| 1554 | + | } | |
A protocol/colormanagement/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package colormanagement | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p colormanagement -o color-management-v1_generated.go -import wl_surface=github.com/bnema/wlturbo/protocol/core -import wl_output=github.com/bnema/wlturbo/protocol/core color-management-v1.xml | |
A protocol/colorrepresentation/color-representation-v1.xml +433 -0
| @@ -0,0 +1,433 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="color_representation_v1"> | |
| 3 | + | <copyright> | |
| 4 | + | Copyright 2022 Simon Ser | |
| 5 | + | Copyright 2022 Red Hat, Inc. | |
| 6 | + | Copyright 2022 Collabora, Ltd. | |
| 7 | + | Copyright 2022-2025 Red Hat, Inc. | |
| 8 | + | ||
| 9 | + | Permission is hereby granted, free of charge, to any person obtaining a | |
| 10 | + | copy of this software and associated documentation files (the "Software"), | |
| 11 | + | to deal in the Software without restriction, including without limitation | |
| 12 | + | the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 13 | + | and/or sell copies of the Software, and to permit persons to whom the | |
| 14 | + | Software is furnished to do so, subject to the following conditions: | |
| 15 | + | ||
| 16 | + | The above copyright notice and this permission notice (including the next | |
| 17 | + | paragraph) shall be included in all copies or substantial portions of the | |
| 18 | + | Software. | |
| 19 | + | ||
| 20 | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 21 | + | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 22 | + | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 23 | + | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 24 | + | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 25 | + | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 26 | + | DEALINGS IN THE SOFTWARE. | |
| 27 | + | </copyright> | |
| 28 | + | ||
| 29 | + | <description summary="color representation protocol extension"> | |
| 30 | + | This protocol extension delivers the metadata required to define alpha mode, | |
| 31 | + | the color model, sub-sampling and quantization range used when interpreting | |
| 32 | + | buffer contents. The main use case is defining how the YCbCr family of pixel | |
| 33 | + | formats convert to RGB. | |
| 34 | + | ||
| 35 | + | Note that this protocol does not define the colorimetry of the resulting RGB | |
| 36 | + | channels / tristimulus values. Without the help of other extensions the | |
| 37 | + | resulting colorimetry is therefore implementation defined. | |
| 38 | + | ||
| 39 | + | If this extension is not used, the color representation used is compositor | |
| 40 | + | implementation defined. | |
| 41 | + | ||
| 42 | + | Recommendation ITU-T H.273 | |
| 43 | + | "Coding-independent code points for video signal type identification" | |
| 44 | + | shall be referred to as simply H.273 here. | |
| 45 | + | </description> | |
| 46 | + | ||
| 47 | + | <interface name="wp_color_representation_manager_v1" version="1"> | |
| 48 | + | <description summary="color representation manager singleton"> | |
| 49 | + | A singleton global interface used for getting color representation | |
| 50 | + | extensions for wl_surface. The extension interfaces allow setting the | |
| 51 | + | color representation of surfaces. | |
| 52 | + | ||
| 53 | + | Compositors should never remove this global. | |
| 54 | + | </description> | |
| 55 | + | ||
| 56 | + | <enum name="error"> | |
| 57 | + | <description summary="protocol errors"/> | |
| 58 | + | <entry name="surface_exists" value="1" | |
| 59 | + | summary="color representation surface exists already"/> | |
| 60 | + | </enum> | |
| 61 | + | ||
| 62 | + | <request name="destroy" type="destructor"> | |
| 63 | + | <description summary="destroy the manager"> | |
| 64 | + | Destroy the wp_color_representation_manager_v1 object. This does not | |
| 65 | + | affect any other objects in any way. | |
| 66 | + | </description> | |
| 67 | + | ||
| 68 | + | </request> | |
| 69 | + | ||
| 70 | + | <request name="get_surface"> | |
| 71 | + | <description summary="create a color representation interface for a wl_surface"> | |
| 72 | + | If a wp_color_representation_surface_v1 object already exists for the | |
| 73 | + | given wl_surface, the protocol error surface_exists is raised. | |
| 74 | + | ||
| 75 | + | This creates a new color wp_color_representation_surface_v1 object for | |
| 76 | + | the given wl_surface. | |
| 77 | + | ||
| 78 | + | See the wp_color_representation_surface_v1 interface for more details. | |
| 79 | + | </description> | |
| 80 | + | <arg name="id" | |
| 81 | + | type="new_id" interface="wp_color_representation_surface_v1"/> | |
| 82 | + | <arg name="surface" | |
| 83 | + | type="object" interface="wl_surface"/> | |
| 84 | + | </request> | |
| 85 | + | ||
| 86 | + | <event name="supported_alpha_mode"> | |
| 87 | + | <description summary="supported alpha modes"> | |
| 88 | + | When this object is created, it shall immediately send this event once | |
| 89 | + | for each alpha mode the compositor supports. | |
| 90 | + | ||
| 91 | + | For the definition of the supported values, see the | |
| 92 | + | wp_color_representation_surface_v1::alpha_mode enum. | |
| 93 | + | </description> | |
| 94 | + | <arg name="alpha_mode" | |
| 95 | + | type="uint" enum="wp_color_representation_surface_v1.alpha_mode" | |
| 96 | + | summary="supported alpha mode"/> | |
| 97 | + | </event> | |
| 98 | + | ||
| 99 | + | <event name="supported_coefficients_and_ranges"> | |
| 100 | + | <description summary="supported matrix coefficients and ranges"> | |
| 101 | + | When this object is created, it shall immediately send this event once | |
| 102 | + | for each matrix coefficient and color range combination the compositor | |
| 103 | + | supports. | |
| 104 | + | ||
| 105 | + | For the definition of the supported values, see the | |
| 106 | + | wp_color_representation_surface_v1::coefficients and | |
| 107 | + | wp_color_representation_surface_v1::range enums. | |
| 108 | + | </description> | |
| 109 | + | <arg name="coefficients" | |
| 110 | + | type="uint" enum="wp_color_representation_surface_v1.coefficients" | |
| 111 | + | summary="supported matrix coefficients"/> | |
| 112 | + | <arg name="range" | |
| 113 | + | type="uint" enum="wp_color_representation_surface_v1.range" | |
| 114 | + | summary="full range flag"/> | |
| 115 | + | </event> | |
| 116 | + | ||
| 117 | + | <event name="done"> | |
| 118 | + | <description summary="all features have been sent"> | |
| 119 | + | This event is sent when all supported features have been sent. | |
| 120 | + | </description> | |
| 121 | + | </event> | |
| 122 | + | </interface> | |
| 123 | + | ||
| 124 | + | <interface name="wp_color_representation_surface_v1" version="1"> | |
| 125 | + | <description summary="color representation extension to a surface"> | |
| 126 | + | A wp_color_representation_surface_v1 allows the client to set the color | |
| 127 | + | representation metadata of a surface. | |
| 128 | + | ||
| 129 | + | By default, a surface does not have any color representation metadata set. | |
| 130 | + | The reconstruction of R, G, B signals on such surfaces is compositor | |
| 131 | + | implementation defined. The alpha mode is assumed to be | |
| 132 | + | premultiplied_electrical when the alpha mode is unset. | |
| 133 | + | ||
| 134 | + | If the wl_surface associated with the wp_color_representation_surface_v1 | |
| 135 | + | is destroyed, the wp_color_representation_surface_v1 object becomes inert. | |
| 136 | + | </description> | |
| 137 | + | ||
| 138 | + | <enum name="error"> | |
| 139 | + | <description summary="protocol errors"/> | |
| 140 | + | <entry name="alpha_mode" value="1" | |
| 141 | + | summary="unsupported alpha mode"/> | |
| 142 | + | <entry name="coefficients" value="2" | |
| 143 | + | summary="unsupported coefficients"/> | |
| 144 | + | <entry name="pixel_format" value="3" | |
| 145 | + | summary="the pixel format and a set value are incompatible"/> | |
| 146 | + | <entry name="inert" value="4" | |
| 147 | + | summary="forbidden request on inert object"/> | |
| 148 | + | <entry name="chroma_location" value="5" | |
| 149 | + | summary="invalid chroma location"/> | |
| 150 | + | </enum> | |
| 151 | + | ||
| 152 | + | <request name="destroy" type="destructor"> | |
| 153 | + | <description summary="destroy the color representation"> | |
| 154 | + | Destroy the wp_color_representation_surface_v1 object. | |
| 155 | + | ||
| 156 | + | Destroying this object unsets all the color representation metadata from | |
| 157 | + | the surface. See the wp_color_representation_surface_v1 interface | |
| 158 | + | description for how a compositor handles a surface without color | |
| 159 | + | representation metadata. Unsetting is double-buffered state, see | |
| 160 | + | wl_surface.commit. | |
| 161 | + | </description> | |
| 162 | + | </request> | |
| 163 | + | ||
| 164 | + | <enum name="alpha_mode"> | |
| 165 | + | <description summary="alpha mode"> | |
| 166 | + | Specifies how the alpha channel affects the color channels. | |
| 167 | + | </description> | |
| 168 | + | <entry name="premultiplied_electrical" value="0"> | |
| 169 | + | <description summary="premultiplied alpha in electrical values"> | |
| 170 | + | Electrical color channel values (after transfer function encoding) | |
| 171 | + | are already multiplied with the alpha channel value. | |
| 172 | + | </description> | |
| 173 | + | </entry> | |
| 174 | + | <entry name="premultiplied_optical" value="1"> | |
| 175 | + | <description summary="premultiplied alpha in optical values"> | |
| 176 | + | Optical color channel values (before transfer function encoding) | |
| 177 | + | are already multiplied with the alpha channel value. | |
| 178 | + | </description> | |
| 179 | + | </entry> | |
| 180 | + | <entry name="straight" value="2"> | |
| 181 | + | <description summary="straight alpha"> | |
| 182 | + | Alpha channel has not been pre-multiplied into color channels. | |
| 183 | + | </description> | |
| 184 | + | </entry> | |
| 185 | + | </enum> | |
| 186 | + | ||
| 187 | + | <enum name="coefficients"> | |
| 188 | + | <description summary="named coefficients"> | |
| 189 | + | Named matrix coefficients used to encode well-known sets of | |
| 190 | + | coefficients. H.273 is the authority, when it comes to the exact values | |
| 191 | + | of coefficients and authoritative specifications, where an equivalent | |
| 192 | + | code point exists. | |
| 193 | + | ||
| 194 | + | A value of 0 is invalid and will never be present in the list of enums. | |
| 195 | + | ||
| 196 | + | Descriptions do list the specifications for convenience. | |
| 197 | + | </description> | |
| 198 | + | <entry name="identity" value="1"> | |
| 199 | + | <description summary="The identity matrix"> | |
| 200 | + | Coefficients as defined by | |
| 201 | + | - IEC 61966-2-1 sRGB | |
| 202 | + | - SMPTE ST 428-1 (2019) | |
| 203 | + | ||
| 204 | + | Equivalent to H.273 MatrixCoefficients code point 0. | |
| 205 | + | Compatible with pixel formats of the RGB family. | |
| 206 | + | </description> | |
| 207 | + | </entry> | |
| 208 | + | <entry name="bt709" value="2"> | |
| 209 | + | <description summary="BT.709 matrix coefficients"> | |
| 210 | + | Coefficients as defined by | |
| 211 | + | - Rec. ITU-R BT.709-6 | |
| 212 | + | - Rec. ITU-R BT.1361-0 conventional colour gamut system (historical) | |
| 213 | + | - Rec. ITU-R BT.1361-0 conventional colour gamut system and extended | |
| 214 | + | colour gamut system (historical) | |
| 215 | + | - IEC 61966-2-4 xvYCC709 | |
| 216 | + | - SMPTE RP 177 (1993) Annex B | |
| 217 | + | ||
| 218 | + | Equivalent to H.273 MatrixCoefficients code point 1. | |
| 219 | + | Compatible with pixel formats of the YCbCr family. | |
| 220 | + | </description> | |
| 221 | + | </entry> | |
| 222 | + | <entry name="fcc" value="3"> | |
| 223 | + | <description summary="FCC matrix coefficients"> | |
| 224 | + | Coefficients as defined by | |
| 225 | + | - United States Federal Communications Commission (2003) Title 47 | |
| 226 | + | Code of Federal Regulations 73.682 (a) (20) | |
| 227 | + | ||
| 228 | + | Equivalent to H.273 MatrixCoefficients code point 4. | |
| 229 | + | Compatible with pixel formats of the YCbCr family. | |
| 230 | + | </description> | |
| 231 | + | </entry> | |
| 232 | + | <entry name="bt601" value="4"> | |
| 233 | + | <description summary="BT.601-7 matrix coefficients"> | |
| 234 | + | Coefficients as defined by | |
| 235 | + | - Rec. ITU-R BT.470-6 System B, G (historical) | |
| 236 | + | - Rec. ITU-R BT.601-7 625 | |
| 237 | + | - Rec. ITU-R BT.601-7 525 | |
| 238 | + | - Rec. ITU-R BT.1358-0 625 (historical) | |
| 239 | + | - Rec. ITU-R BT.1358-1 525 or 625 (historical) | |
| 240 | + | - Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM | |
| 241 | + | - Rec. ITU-R BT.1700-0 NTSC | |
| 242 | + | - IEC 61966-2-1 sYCC | |
| 243 | + | - IEC 61966-2-4 xvYCC601 | |
| 244 | + | - SMPTE ST 170 (2004) | |
| 245 | + | ||
| 246 | + | Equivalent to H.273 MatrixCoefficients code point 5, 6. | |
| 247 | + | Compatible with pixel formats of the YCbCr family. | |
| 248 | + | </description> | |
| 249 | + | </entry> | |
| 250 | + | <entry name="smpte240" value="5"> | |
| 251 | + | <description summary="SMPTE ST 240 matrix coefficients"> | |
| 252 | + | Coefficients as defined by | |
| 253 | + | - SMPTE ST 240 (1999) | |
| 254 | + | ||
| 255 | + | Equivalent to H.273 MatrixCoefficients code point 7. | |
| 256 | + | Compatible with pixel formats of the YCbCr family. | |
| 257 | + | </description> | |
| 258 | + | </entry> | |
| 259 | + | <entry name="bt2020" value="6"> | |
| 260 | + | <description summary="BT.2020 and BT.2100 YCbCr matrix coefficients"> | |
| 261 | + | Coefficients as defined by | |
| 262 | + | - Rec. ITU-R BT.2020-2 (non-constant luminance) | |
| 263 | + | - Rec. ITU-R BT.2100-2 Y′CbCr | |
| 264 | + | ||
| 265 | + | Equivalent to H.273 MatrixCoefficients code point 9. | |
| 266 | + | Compatible with pixel formats of the YCbCr family. | |
| 267 | + | </description> | |
| 268 | + | </entry> | |
| 269 | + | <entry name="bt2020_cl" value="7"> | |
| 270 | + | <description summary="BT.2020 matrix coefficients for constant luminance"> | |
| 271 | + | Coefficients as defined by | |
| 272 | + | - Rec. ITU-R BT.2020-2 (constant luminance) | |
| 273 | + | ||
| 274 | + | Equivalent to H.273 MatrixCoefficients code point 10. | |
| 275 | + | Compatible with pixel formats of the YCbCr family. | |
| 276 | + | </description> | |
| 277 | + | </entry> | |
| 278 | + | <entry name="ictcp" value="8"> | |
| 279 | + | <description summary="BT.2100 ICtCp matrix coefficients"> | |
| 280 | + | Coefficients as defined by | |
| 281 | + | - Rec. ITU-R BT.2100-2 ICTCP | |
| 282 | + | ||
| 283 | + | Equivalent to H.273 MatrixCoefficients code point 14. | |
| 284 | + | Compatible with pixel formats of the YCbCr family. | |
| 285 | + | </description> | |
| 286 | + | </entry> | |
| 287 | + | </enum> | |
| 288 | + | ||
| 289 | + | <enum name="range"> | |
| 290 | + | <description summary="Color range values"> | |
| 291 | + | Possible color range values. | |
| 292 | + | ||
| 293 | + | A value of 0 is invalid and will never be present in the list of enums. | |
| 294 | + | </description> | |
| 295 | + | <entry name="full" value="1" summary="Full color range"/> | |
| 296 | + | <entry name="limited" value="2" summary="Limited color range"/> | |
| 297 | + | </enum> | |
| 298 | + | ||
| 299 | + | <enum name="chroma_location"> | |
| 300 | + | <description summary="Chroma sample location for 4:2:0 YCbCr"> | |
| 301 | + | Chroma sample location as defined by H.273 Chroma420SampleLocType. | |
| 302 | + | ||
| 303 | + | A value of 0 is invalid and will never be present in the list of enums. | |
| 304 | + | ||
| 305 | + | The descriptions list the matching Vulkan VkChromaLocation combinations | |
| 306 | + | for convenience. | |
| 307 | + | </description> | |
| 308 | + | <entry name="type_0" value="1"> | |
| 309 | + | <description summary="Horizontal offset of 0, vertical offset of 0.5"> | |
| 310 | + | Corresponding to VkChromaLocations: | |
| 311 | + | - xChromaOffset: VK_CHROMA_LOCATION_COSITED_EVEN | |
| 312 | + | - yChromaOffset: VK_CHROMA_LOCATION_MIDPOINT | |
| 313 | + | ||
| 314 | + | Equivalent to H.273 Chroma420SampleLocType 0. | |
| 315 | + | </description> | |
| 316 | + | </entry> | |
| 317 | + | <entry name="type_1" value="2"> | |
| 318 | + | <description summary="Horizontal offset of 0.5, vertical offset of 0.5"> | |
| 319 | + | Corresponding to VkChromaLocations: | |
| 320 | + | - xChromaOffset: VK_CHROMA_LOCATION_MIDPOINT | |
| 321 | + | - yChromaOffset: VK_CHROMA_LOCATION_MIDPOINT | |
| 322 | + | ||
| 323 | + | Equivalent to H.273 Chroma420SampleLocType 1. | |
| 324 | + | </description> | |
| 325 | + | </entry> | |
| 326 | + | <entry name="type_2" value="3"> | |
| 327 | + | <description summary="Horizontal offset of 0, vertical offset of 0"> | |
| 328 | + | Corresponding to VkChromaLocations: | |
| 329 | + | - xChromaOffset: VK_CHROMA_LOCATION_COSITED_EVEN | |
| 330 | + | - yChromaOffset: VK_CHROMA_LOCATION_COSITED_EVEN | |
| 331 | + | ||
| 332 | + | Equivalent to H.273 Chroma420SampleLocType 2. | |
| 333 | + | </description> | |
| 334 | + | </entry> | |
| 335 | + | <entry name="type_3" value="4"> | |
| 336 | + | <description summary="Horizontal offset of 0.5, vertical offset of 0"> | |
| 337 | + | Corresponding to VkChromaLocations: | |
| 338 | + | - xChromaOffset: VK_CHROMA_LOCATION_MIDPOINT | |
| 339 | + | - yChromaOffset: VK_CHROMA_LOCATION_COSITED_EVEN | |
| 340 | + | ||
| 341 | + | Equivalent to H.273 Chroma420SampleLocType 3. | |
| 342 | + | </description> | |
| 343 | + | </entry> | |
| 344 | + | <entry name="type_4" value="5"> | |
| 345 | + | <description summary="Horizontal offset of 0, vertical offset of 1"> | |
| 346 | + | Equivalent to H.273 Chroma420SampleLocType 4. | |
| 347 | + | </description> | |
| 348 | + | </entry> | |
| 349 | + | <entry name="type_5" value="6"> | |
| 350 | + | <description summary="Horizontal offset of 0.5, vertical offset of 1"> | |
| 351 | + | Equivalent to H.273 Chroma420SampleLocType 5. | |
| 352 | + | </description> | |
| 353 | + | </entry> | |
| 354 | + | </enum> | |
| 355 | + | ||
| 356 | + | <request name="set_alpha_mode"> | |
| 357 | + | <description summary="set the surface alpha mode"> | |
| 358 | + | If this protocol object is inert, the protocol error inert is raised. | |
| 359 | + | ||
| 360 | + | Assuming an alpha channel exists, it is always linear. The alpha mode | |
| 361 | + | determines whether and how the color channels include pre-multiplied | |
| 362 | + | alpha. Using straight alpha might have performance benefits. | |
| 363 | + | ||
| 364 | + | Only alpha modes advertised by the compositor are allowed to be used as | |
| 365 | + | argument for this request. The "alpha_mode" protocol error is raised | |
| 366 | + | otherwise. | |
| 367 | + | ||
| 368 | + | Alpha mode is double buffered, see wl_surface.commit. | |
| 369 | + | </description> | |
| 370 | + | <arg name="alpha_mode" type="uint" enum="alpha_mode" | |
| 371 | + | summary="alpha mode"/> | |
| 372 | + | </request> | |
| 373 | + | ||
| 374 | + | <request name="set_coefficients_and_range"> | |
| 375 | + | <description summary="set the matrix coefficients and range"> | |
| 376 | + | If this protocol object is inert, the protocol error inert is raised. | |
| 377 | + | ||
| 378 | + | Set the matrix coefficients and video range which defines the formula | |
| 379 | + | and the related constants used to derive red, green and blue signals. | |
| 380 | + | Usually coefficients correspond to MatrixCoefficients code points in | |
| 381 | + | H.273. | |
| 382 | + | ||
| 383 | + | Only combinations advertised by the compositor are allowed to be used as | |
| 384 | + | argument for this request. The "coefficients" protocol error is raised | |
| 385 | + | otherwise. | |
| 386 | + | ||
| 387 | + | A call to wl_surface.commit verifies that the pixel format and the | |
| 388 | + | coefficients-range combination in the committed surface contents are | |
| 389 | + | compatible, if contents exist. The "pixel_format" protocol error is | |
| 390 | + | raised otherwise. | |
| 391 | + | ||
| 392 | + | A pixel format is compatible with the coefficients-range combination if | |
| 393 | + | the related equations and conventions as defined in H.273 can produce | |
| 394 | + | the color channels (RGB or YCbCr) of the pixel format. | |
| 395 | + | ||
| 396 | + | For the definition of the supported combination, see the | |
| 397 | + | wp_color_representation_surface_v1::coefficients and | |
| 398 | + | wp_color_representation_surface_v1::range enums. | |
| 399 | + | ||
| 400 | + | The coefficients-range combination is double-buffered, see | |
| 401 | + | wl_surface.commit. | |
| 402 | + | </description> | |
| 403 | + | <arg name="coefficients" type="uint" enum="coefficients" | |
| 404 | + | summary="matrix coefficients"/> | |
| 405 | + | <arg name="range" type="uint" enum="range" | |
| 406 | + | summary="range"/> | |
| 407 | + | </request> | |
| 408 | + | ||
| 409 | + | <request name="set_chroma_location"> | |
| 410 | + | <description summary="set the chroma location"> | |
| 411 | + | If this protocol object is inert, the protocol error inert is raised. | |
| 412 | + | ||
| 413 | + | Set the chroma location type which defines the position of downsampled | |
| 414 | + | chroma samples, corresponding to Chroma420SampleLocType code points in | |
| 415 | + | H.273. | |
| 416 | + | ||
| 417 | + | An invalid chroma location enum value raises the "chroma_location" | |
| 418 | + | protocol error. | |
| 419 | + | ||
| 420 | + | A call to wl_surface.commit verifies that the pixel format and chroma | |
| 421 | + | location type in the committed surface contents are compatible, if | |
| 422 | + | contents exist. The "pixel_format" protocol error is raised otherwise. | |
| 423 | + | ||
| 424 | + | For the definition of the supported chroma location types, see the | |
| 425 | + | wp_color_representation_surface_v1::chroma_location enum. | |
| 426 | + | ||
| 427 | + | The chroma location type is double-buffered, see wl_surface.commit. | |
| 428 | + | </description> | |
| 429 | + | <arg name="chroma_location" type="uint" enum="chroma_location" | |
| 430 | + | summary="chroma sample location"/> | |
| 431 | + | </request> | |
| 432 | + | </interface> | |
| 433 | + | </protocol> | |
A protocol/colorrepresentation/color-representation-v1_generated.go +327 -0
| @@ -0,0 +1,327 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: color_representation_v1 | |
| 3 | + | // Source: color-representation-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright 2022 Simon Ser | |
| 7 | + | // Copyright 2022 Red Hat, Inc. | |
| 8 | + | // Copyright 2022 Collabora, Ltd. | |
| 9 | + | // Copyright 2022-2025 Red Hat, Inc. | |
| 10 | + | // | |
| 11 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 12 | + | // copy of this software and associated documentation files (the "Software"), | |
| 13 | + | // to deal in the Software without restriction, including without limitation | |
| 14 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 15 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 16 | + | // Software is furnished to do so, subject to the following conditions: | |
| 17 | + | // | |
| 18 | + | // The above copyright notice and this permission notice (including the next | |
| 19 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 20 | + | // Software. | |
| 21 | + | // | |
| 22 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 23 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 24 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 25 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 26 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 27 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 28 | + | // DEALINGS IN THE SOFTWARE. | |
| 29 | + | ||
| 30 | + | package colorrepresentation | |
| 31 | + | ||
| 32 | + | import ( | |
| 33 | + | "sync" | |
| 34 | + | ||
| 35 | + | cross_wl_surface "github.com/bnema/wlturbo/protocol/core" | |
| 36 | + | "github.com/bnema/wlturbo/wl" | |
| 37 | + | ) | |
| 38 | + | ||
| 39 | + | // ERROR_SURFACE_EXISTS is the error surface_exists value. | |
| 40 | + | const ERROR_SURFACE_EXISTS = 1 | |
| 41 | + | ||
| 42 | + | // ERROR_ALPHA_MODE is the error alpha_mode value. | |
| 43 | + | const ERROR_ALPHA_MODE = 1 | |
| 44 | + | ||
| 45 | + | // ERROR_COEFFICIENTS is the error coefficients value. | |
| 46 | + | const ERROR_COEFFICIENTS = 2 | |
| 47 | + | ||
| 48 | + | // ERROR_PIXEL_FORMAT is the error pixel_format value. | |
| 49 | + | const ERROR_PIXEL_FORMAT = 3 | |
| 50 | + | ||
| 51 | + | // ERROR_INERT is the error inert value. | |
| 52 | + | const ERROR_INERT = 4 | |
| 53 | + | ||
| 54 | + | // ERROR_CHROMA_LOCATION is the error chroma_location value. | |
| 55 | + | const ERROR_CHROMA_LOCATION = 5 | |
| 56 | + | ||
| 57 | + | // ALPHA_MODE_PREMULTIPLIED_ELECTRICAL is the alpha_mode premultiplied_electrical value. | |
| 58 | + | const ALPHA_MODE_PREMULTIPLIED_ELECTRICAL = 0 | |
| 59 | + | ||
| 60 | + | // ALPHA_MODE_PREMULTIPLIED_OPTICAL is the alpha_mode premultiplied_optical value. | |
| 61 | + | const ALPHA_MODE_PREMULTIPLIED_OPTICAL = 1 | |
| 62 | + | ||
| 63 | + | // ALPHA_MODE_STRAIGHT is the alpha_mode straight value. | |
| 64 | + | const ALPHA_MODE_STRAIGHT = 2 | |
| 65 | + | ||
| 66 | + | // COEFFICIENTS_IDENTITY is the coefficients identity value. | |
| 67 | + | const COEFFICIENTS_IDENTITY = 1 | |
| 68 | + | ||
| 69 | + | // COEFFICIENTS_BT709 is the coefficients bt709 value. | |
| 70 | + | const COEFFICIENTS_BT709 = 2 | |
| 71 | + | ||
| 72 | + | // COEFFICIENTS_FCC is the coefficients fcc value. | |
| 73 | + | const COEFFICIENTS_FCC = 3 | |
| 74 | + | ||
| 75 | + | // COEFFICIENTS_BT601 is the coefficients bt601 value. | |
| 76 | + | const COEFFICIENTS_BT601 = 4 | |
| 77 | + | ||
| 78 | + | // COEFFICIENTS_SMPTE240 is the coefficients smpte240 value. | |
| 79 | + | const COEFFICIENTS_SMPTE240 = 5 | |
| 80 | + | ||
| 81 | + | // COEFFICIENTS_BT2020 is the coefficients bt2020 value. | |
| 82 | + | const COEFFICIENTS_BT2020 = 6 | |
| 83 | + | ||
| 84 | + | // COEFFICIENTS_BT2020_CL is the coefficients bt2020_cl value. | |
| 85 | + | const COEFFICIENTS_BT2020_CL = 7 | |
| 86 | + | ||
| 87 | + | // COEFFICIENTS_ICTCP is the coefficients ictcp value. | |
| 88 | + | const COEFFICIENTS_ICTCP = 8 | |
| 89 | + | ||
| 90 | + | // RANGE_FULL is the range full value. | |
| 91 | + | const RANGE_FULL = 1 | |
| 92 | + | ||
| 93 | + | // RANGE_LIMITED is the range limited value. | |
| 94 | + | const RANGE_LIMITED = 2 | |
| 95 | + | ||
| 96 | + | // CHROMA_LOCATION_TYPE_0 is the chroma_location type_0 value. | |
| 97 | + | const CHROMA_LOCATION_TYPE_0 = 1 | |
| 98 | + | ||
| 99 | + | // CHROMA_LOCATION_TYPE_1 is the chroma_location type_1 value. | |
| 100 | + | const CHROMA_LOCATION_TYPE_1 = 2 | |
| 101 | + | ||
| 102 | + | // CHROMA_LOCATION_TYPE_2 is the chroma_location type_2 value. | |
| 103 | + | const CHROMA_LOCATION_TYPE_2 = 3 | |
| 104 | + | ||
| 105 | + | // CHROMA_LOCATION_TYPE_3 is the chroma_location type_3 value. | |
| 106 | + | const CHROMA_LOCATION_TYPE_3 = 4 | |
| 107 | + | ||
| 108 | + | // CHROMA_LOCATION_TYPE_4 is the chroma_location type_4 value. | |
| 109 | + | const CHROMA_LOCATION_TYPE_4 = 5 | |
| 110 | + | ||
| 111 | + | // CHROMA_LOCATION_TYPE_5 is the chroma_location type_5 value. | |
| 112 | + | const CHROMA_LOCATION_TYPE_5 = 6 | |
| 113 | + | ||
| 114 | + | // WpColorRepresentationManagerInterface is the protocol interface name. | |
| 115 | + | const WpColorRepresentationManagerInterface = "wp_color_representation_manager_v1" | |
| 116 | + | ||
| 117 | + | // WpColorRepresentationManager is the generated binding for wp_color_representation_manager_v1 version 1. | |
| 118 | + | type WpColorRepresentationManager struct { | |
| 119 | + | wl.BaseProxy | |
| 120 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 121 | + | // handlers while another goroutine dispatches events. | |
| 122 | + | handlersMu sync.Mutex | |
| 123 | + | onSupportedAlphaMode []func(alphaMode uint32) | |
| 124 | + | onSupportedCoefficientsAndRanges []func(coefficients uint32, rangeArg uint32) | |
| 125 | + | onDone []func() | |
| 126 | + | } | |
| 127 | + | ||
| 128 | + | // NewWpColorRepresentationManager returns an unbound WpColorRepresentationManager. | |
| 129 | + | func NewWpColorRepresentationManager(ctx *wl.Context) *WpColorRepresentationManager { | |
| 130 | + | obj := &WpColorRepresentationManager{} | |
| 131 | + | obj.SetContext(ctx) | |
| 132 | + | ctx.Register(obj) | |
| 133 | + | return obj | |
| 134 | + | } | |
| 135 | + | ||
| 136 | + | // Destroy the wp_color_representation_manager_v1 object. This does not affect any other objects in any way. | |
| 137 | + | func (o *WpColorRepresentationManager) Destroy() error { | |
| 138 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_color_representation_manager_v1.destroy", Destructor: true}); err != nil { | |
| 139 | + | return err | |
| 140 | + | } | |
| 141 | + | return nil | |
| 142 | + | } | |
| 143 | + | ||
| 144 | + | // If a wp_color_representation_surface_v1 object already exists for the given wl_surface, the protocol error surface_exists is raised. This creates a new color wp_color_representation_surface_v1 object for the given wl_surface. See the wp_color_representation_surface_v1 interface for more details. | |
| 145 | + | func (o *WpColorRepresentationManager) GetSurface(surface *cross_wl_surface.Surface) (*WpColorRepresentationSurface, error) { | |
| 146 | + | var arg1 wl.Object | |
| 147 | + | if surface != nil { | |
| 148 | + | arg1 = surface | |
| 149 | + | } | |
| 150 | + | child := &WpColorRepresentationSurface{} | |
| 151 | + | child.SetContext(o.Context()) | |
| 152 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_color_representation_manager_v1.get_surface", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 153 | + | return nil, err | |
| 154 | + | } | |
| 155 | + | return child, nil | |
| 156 | + | } | |
| 157 | + | ||
| 158 | + | // OnSupportedAlphaMode registers a handler for the supported_alpha_mode event. | |
| 159 | + | // | |
| 160 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 161 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 162 | + | func (o *WpColorRepresentationManager) OnSupportedAlphaMode(handler func(alphaMode uint32)) { | |
| 163 | + | if handler == nil { | |
| 164 | + | return | |
| 165 | + | } | |
| 166 | + | o.handlersMu.Lock() | |
| 167 | + | defer o.handlersMu.Unlock() | |
| 168 | + | o.onSupportedAlphaMode = append(o.onSupportedAlphaMode, handler) | |
| 169 | + | } | |
| 170 | + | ||
| 171 | + | // handlersForSupportedAlphaMode returns the handlers registered for supported_alpha_mode, taken | |
| 172 | + | // under the lock so a handler may register another handler while events are | |
| 173 | + | // being dispatched. | |
| 174 | + | func (o *WpColorRepresentationManager) handlersForSupportedAlphaMode() []func(alphaMode uint32) { | |
| 175 | + | o.handlersMu.Lock() | |
| 176 | + | defer o.handlersMu.Unlock() | |
| 177 | + | return o.onSupportedAlphaMode | |
| 178 | + | } | |
| 179 | + | ||
| 180 | + | // OnSupportedCoefficientsAndRanges registers a handler for the supported_coefficients_and_ranges event. | |
| 181 | + | // | |
| 182 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 183 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 184 | + | func (o *WpColorRepresentationManager) OnSupportedCoefficientsAndRanges(handler func(coefficients uint32, rangeArg uint32)) { | |
| 185 | + | if handler == nil { | |
| 186 | + | return | |
| 187 | + | } | |
| 188 | + | o.handlersMu.Lock() | |
| 189 | + | defer o.handlersMu.Unlock() | |
| 190 | + | o.onSupportedCoefficientsAndRanges = append(o.onSupportedCoefficientsAndRanges, handler) | |
| 191 | + | } | |
| 192 | + | ||
| 193 | + | // handlersForSupportedCoefficientsAndRanges returns the handlers registered for supported_coefficients_and_ranges, taken | |
| 194 | + | // under the lock so a handler may register another handler while events are | |
| 195 | + | // being dispatched. | |
| 196 | + | func (o *WpColorRepresentationManager) handlersForSupportedCoefficientsAndRanges() []func(coefficients uint32, rangeArg uint32) { | |
| 197 | + | o.handlersMu.Lock() | |
| 198 | + | defer o.handlersMu.Unlock() | |
| 199 | + | return o.onSupportedCoefficientsAndRanges | |
| 200 | + | } | |
| 201 | + | ||
| 202 | + | // OnDone registers a handler for the done event. | |
| 203 | + | // | |
| 204 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 205 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 206 | + | func (o *WpColorRepresentationManager) OnDone(handler func()) { | |
| 207 | + | if handler == nil { | |
| 208 | + | return | |
| 209 | + | } | |
| 210 | + | o.handlersMu.Lock() | |
| 211 | + | defer o.handlersMu.Unlock() | |
| 212 | + | o.onDone = append(o.onDone, handler) | |
| 213 | + | } | |
| 214 | + | ||
| 215 | + | // handlersForDone returns the handlers registered for done, taken | |
| 216 | + | // under the lock so a handler may register another handler while events are | |
| 217 | + | // being dispatched. | |
| 218 | + | func (o *WpColorRepresentationManager) handlersForDone() []func() { | |
| 219 | + | o.handlersMu.Lock() | |
| 220 | + | defer o.handlersMu.Unlock() | |
| 221 | + | return o.onDone | |
| 222 | + | } | |
| 223 | + | ||
| 224 | + | // EventSignature returns the declared event argument types in wire order. | |
| 225 | + | func (o *WpColorRepresentationManager) EventSignature(opcode uint16) (string, bool) { | |
| 226 | + | switch opcode { | |
| 227 | + | case 0: | |
| 228 | + | return "uint,", true | |
| 229 | + | case 1: | |
| 230 | + | return "uint,uint,", true | |
| 231 | + | case 2: | |
| 232 | + | return "", true | |
| 233 | + | default: | |
| 234 | + | return "", false | |
| 235 | + | } | |
| 236 | + | } | |
| 237 | + | ||
| 238 | + | // Dispatch decodes one event on wp_color_representation_manager_v1 and calls the registered handlers. | |
| 239 | + | func (o *WpColorRepresentationManager) Dispatch(event *wl.Event) { | |
| 240 | + | switch event.Opcode { | |
| 241 | + | case 0: // supported_alpha_mode | |
| 242 | + | alphaMode := event.Uint32() | |
| 243 | + | ||
| 244 | + | for i, handler := range o.handlersForSupportedAlphaMode() { | |
| 245 | + | _ = i | |
| 246 | + | handler(alphaMode) | |
| 247 | + | } | |
| 248 | + | case 1: // supported_coefficients_and_ranges | |
| 249 | + | coefficients := event.Uint32() | |
| 250 | + | rangeArg := event.Uint32() | |
| 251 | + | ||
| 252 | + | for i, handler := range o.handlersForSupportedCoefficientsAndRanges() { | |
| 253 | + | _ = i | |
| 254 | + | handler(coefficients, rangeArg) | |
| 255 | + | } | |
| 256 | + | case 2: // done | |
| 257 | + | ||
| 258 | + | for i, handler := range o.handlersForDone() { | |
| 259 | + | _ = i | |
| 260 | + | handler() | |
| 261 | + | } | |
| 262 | + | default: | |
| 263 | + | } | |
| 264 | + | } | |
| 265 | + | ||
| 266 | + | // WpColorRepresentationSurfaceInterface is the protocol interface name. | |
| 267 | + | const WpColorRepresentationSurfaceInterface = "wp_color_representation_surface_v1" | |
| 268 | + | ||
| 269 | + | // WpColorRepresentationSurface is the generated binding for wp_color_representation_surface_v1 version 1. | |
| 270 | + | type WpColorRepresentationSurface struct { | |
| 271 | + | wl.BaseProxy | |
| 272 | + | } | |
| 273 | + | ||
| 274 | + | // NewWpColorRepresentationSurface returns an unbound WpColorRepresentationSurface. | |
| 275 | + | func NewWpColorRepresentationSurface(ctx *wl.Context) *WpColorRepresentationSurface { | |
| 276 | + | obj := &WpColorRepresentationSurface{} | |
| 277 | + | obj.SetContext(ctx) | |
| 278 | + | ctx.Register(obj) | |
| 279 | + | return obj | |
| 280 | + | } | |
| 281 | + | ||
| 282 | + | // Destroy the wp_color_representation_surface_v1 object. Destroying this object unsets all the color representation metadata from the surface. See the wp_color_representation_surface_v1 interface description for how a compositor handles a surface without color representation metadata. Unsetting is double-buffered state, see wl_surface.commit. | |
| 283 | + | func (o *WpColorRepresentationSurface) Destroy() error { | |
| 284 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_color_representation_surface_v1.destroy", Destructor: true}); err != nil { | |
| 285 | + | return err | |
| 286 | + | } | |
| 287 | + | return nil | |
| 288 | + | } | |
| 289 | + | ||
| 290 | + | // If this protocol object is inert, the protocol error inert is raised. Assuming an alpha channel exists, it is always linear. The alpha mode determines whether and how the color channels include pre-multiplied alpha. Using straight alpha might have performance benefits. Only alpha modes advertised by the compositor are allowed to be used as argument for this request. The "alpha_mode" protocol error is raised otherwise. Alpha mode is double buffered, see wl_surface.commit. | |
| 291 | + | func (o *WpColorRepresentationSurface) SetAlphaMode(alphaMode uint32) error { | |
| 292 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_color_representation_surface_v1.set_alpha_mode"}, wl.ArgUint(alphaMode)); err != nil { | |
| 293 | + | return err | |
| 294 | + | } | |
| 295 | + | return nil | |
| 296 | + | } | |
| 297 | + | ||
| 298 | + | // If this protocol object is inert, the protocol error inert is raised. Set the matrix coefficients and video range which defines the formula and the related constants used to derive red, green and blue signals. Usually coefficients correspond to MatrixCoefficients code points in H.273. Only combinations advertised by the compositor are allowed to be used as argument for this request. The "coefficients" protocol error is raised otherwise. A call to wl_surface.commit verifies that the pixel format and the coefficients-range combination in the committed surface contents are compatible, if contents exist. The "pixel_format" protocol error is raised otherwise. A pixel format is compatible with the coefficients-range combination if the related equations and conventions as defined in H.273 can produce the color channels (RGB or YCbCr) of the pixel format. For the definition of the supported combination, see the wp_color_representation_surface_v1::coefficients and wp_color_representation_surface_v1::range enums. The coefficients-range combination is double-buffered, see wl_surface.commit. | |
| 299 | + | func (o *WpColorRepresentationSurface) SetCoefficientsAndRange(coefficients uint32, rangeArg uint32) error { | |
| 300 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wp_color_representation_surface_v1.set_coefficients_and_range"}, wl.ArgUint(coefficients), wl.ArgUint(rangeArg)); err != nil { | |
| 301 | + | return err | |
| 302 | + | } | |
| 303 | + | return nil | |
| 304 | + | } | |
| 305 | + | ||
| 306 | + | // If this protocol object is inert, the protocol error inert is raised. Set the chroma location type which defines the position of downsampled chroma samples, corresponding to Chroma420SampleLocType code points in H.273. An invalid chroma location enum value raises the "chroma_location" protocol error. A call to wl_surface.commit verifies that the pixel format and chroma location type in the committed surface contents are compatible, if contents exist. The "pixel_format" protocol error is raised otherwise. For the definition of the supported chroma location types, see the wp_color_representation_surface_v1::chroma_location enum. The chroma location type is double-buffered, see wl_surface.commit. | |
| 307 | + | func (o *WpColorRepresentationSurface) SetChromaLocation(chromaLocation uint32) error { | |
| 308 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "wp_color_representation_surface_v1.set_chroma_location"}, wl.ArgUint(chromaLocation)); err != nil { | |
| 309 | + | return err | |
| 310 | + | } | |
| 311 | + | return nil | |
| 312 | + | } | |
| 313 | + | ||
| 314 | + | // EventSignature returns the declared event argument types in wire order. | |
| 315 | + | func (o *WpColorRepresentationSurface) EventSignature(opcode uint16) (string, bool) { | |
| 316 | + | switch opcode { | |
| 317 | + | default: | |
| 318 | + | return "", false | |
| 319 | + | } | |
| 320 | + | } | |
| 321 | + | ||
| 322 | + | // Dispatch decodes one event on wp_color_representation_surface_v1 and calls the registered handlers. | |
| 323 | + | func (o *WpColorRepresentationSurface) Dispatch(event *wl.Event) { | |
| 324 | + | switch event.Opcode { | |
| 325 | + | default: | |
| 326 | + | } | |
| 327 | + | } | |
A protocol/colorrepresentation/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package colorrepresentation | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p colorrepresentation -o color-representation-v1_generated.go -import wl_surface=github.com/bnema/wlturbo/protocol/core color-representation-v1.xml | |
A protocol/committiming/commit-timing-v1.xml +124 -0
| @@ -0,0 +1,124 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="commit_timing_v1"> | |
| 3 | + | ||
| 4 | + | <copyright> | |
| 5 | + | Copyright © 2023 Valve Corporation | |
| 6 | + | ||
| 7 | + | Permission is hereby granted, free of charge, to any person obtaining a | |
| 8 | + | copy of this software and associated documentation files (the "Software"), | |
| 9 | + | to deal in the Software without restriction, including without limitation | |
| 10 | + | the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 11 | + | and/or sell copies of the Software, and to permit persons to whom the | |
| 12 | + | Software is furnished to do so, subject to the following conditions: | |
| 13 | + | ||
| 14 | + | The above copyright notice and this permission notice (including the next | |
| 15 | + | paragraph) shall be included in all copies or substantial portions of the | |
| 16 | + | Software. | |
| 17 | + | ||
| 18 | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | + | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | + | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 21 | + | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | + | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 23 | + | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 24 | + | DEALINGS IN THE SOFTWARE. | |
| 25 | + | </copyright> | |
| 26 | + | ||
| 27 | + | <interface name="wp_commit_timing_manager_v1" version="1"> | |
| 28 | + | <description summary="commit timing"> | |
| 29 | + | When a compositor latches on to new content updates it will check for | |
| 30 | + | any number of requirements of the available content updates (such as | |
| 31 | + | fences of all buffers being signalled) to consider the update ready. | |
| 32 | + | ||
| 33 | + | This protocol provides a method for adding a time constraint to surface | |
| 34 | + | content. This constraint indicates to the compositor that a content | |
| 35 | + | update should be presented as closely as possible to, but not before, | |
| 36 | + | a specified time. | |
| 37 | + | ||
| 38 | + | This protocol does not change the Wayland property that content | |
| 39 | + | updates are applied in the order they are received, even when some | |
| 40 | + | content updates contain timestamps and others do not. | |
| 41 | + | ||
| 42 | + | To provide timestamps, this global factory interface must be used to | |
| 43 | + | acquire a wp_commit_timing_v1 object for a surface, which may then be | |
| 44 | + | used to provide timestamp information for commits. | |
| 45 | + | ||
| 46 | + | Warning! The protocol described in this file is currently in the testing | |
| 47 | + | phase. Backward compatible changes may be added together with the | |
| 48 | + | corresponding interface version bump. Backward incompatible changes can | |
| 49 | + | only be done by creating a new major version of the extension. | |
| 50 | + | </description> | |
| 51 | + | <enum name="error"> | |
| 52 | + | <entry name="commit_timer_exists" value="0" | |
| 53 | + | summary="commit timer already exists for surface"/> | |
| 54 | + | </enum> | |
| 55 | + | ||
| 56 | + | <request name="destroy" type="destructor"> | |
| 57 | + | <description summary="unbind from the commit timing interface"> | |
| 58 | + | Informs the server that the client will no longer be using | |
| 59 | + | this protocol object. Existing objects created by this object | |
| 60 | + | are not affected. | |
| 61 | + | </description> | |
| 62 | + | </request> | |
| 63 | + | ||
| 64 | + | <request name="get_timer"> | |
| 65 | + | <description summary="request commit timer interface for surface"> | |
| 66 | + | Establish a timing controller for a surface. | |
| 67 | + | ||
| 68 | + | Only one commit timer can be created for a surface, or a | |
| 69 | + | commit_timer_exists protocol error will be generated. | |
| 70 | + | </description> | |
| 71 | + | <arg name="id" type="new_id" interface="wp_commit_timer_v1"/> | |
| 72 | + | <arg name="surface" type="object" interface="wl_surface"/> | |
| 73 | + | </request> | |
| 74 | + | </interface> | |
| 75 | + | ||
| 76 | + | <interface name="wp_commit_timer_v1" version="1"> | |
| 77 | + | <description summary="Surface commit timer"> | |
| 78 | + | An object to set a time constraint for a content update on a surface. | |
| 79 | + | </description> | |
| 80 | + | ||
| 81 | + | <enum name="error"> | |
| 82 | + | <entry name="invalid_timestamp" value="0" | |
| 83 | + | summary="timestamp contains an invalid value"/> | |
| 84 | + | <entry name="timestamp_exists" value="1" | |
| 85 | + | summary="timestamp exists"/> | |
| 86 | + | <entry name="surface_destroyed" value="2" | |
| 87 | + | summary="the associated surface no longer exists"/> | |
| 88 | + | </enum> | |
| 89 | + | ||
| 90 | + | <request name="set_timestamp"> | |
| 91 | + | <description summary="Specify time the following commit takes effect"> | |
| 92 | + | Provide a timing constraint for a surface content update. | |
| 93 | + | ||
| 94 | + | A set_timestamp request may be made before a wl_surface.commit to | |
| 95 | + | tell the compositor that the content is intended to be presented | |
| 96 | + | as closely as possible to, but not before, the specified time. | |
| 97 | + | The time is in the domain of the compositor's presentation clock. | |
| 98 | + | ||
| 99 | + | An invalid_timestamp error will be generated for invalid tv_nsec. | |
| 100 | + | ||
| 101 | + | If a timestamp already exists on the surface, a timestamp_exists | |
| 102 | + | error is generated. | |
| 103 | + | ||
| 104 | + | Requesting set_timestamp after the commit_timer object's surface is | |
| 105 | + | destroyed will generate a "surface_destroyed" error. | |
| 106 | + | </description> | |
| 107 | + | <arg name="tv_sec_hi" type="uint" | |
| 108 | + | summary="high 32 bits of the seconds part of target time"/> | |
| 109 | + | <arg name="tv_sec_lo" type="uint" | |
| 110 | + | summary="low 32 bits of the seconds part of target time"/> | |
| 111 | + | <arg name="tv_nsec" type="uint" | |
| 112 | + | summary="nanoseconds part of target time"/> | |
| 113 | + | </request> | |
| 114 | + | ||
| 115 | + | <request name="destroy" type="destructor"> | |
| 116 | + | <description summary="Destroy the timer"> | |
| 117 | + | Informs the server that the client will no longer be using | |
| 118 | + | this protocol object. | |
| 119 | + | ||
| 120 | + | Existing timing constraints are not affected by the destruction. | |
| 121 | + | </description> | |
| 122 | + | </request> | |
| 123 | + | </interface> | |
| 124 | + | </protocol> | |
A protocol/committiming/commit-timing-v1_generated.go +144 -0
| @@ -0,0 +1,144 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: commit_timing_v1 | |
| 3 | + | // Source: commit-timing-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2023 Valve Corporation | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package committiming | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | cross_wl_surface "github.com/bnema/wlturbo/protocol/core" | |
| 31 | + | "github.com/bnema/wlturbo/wl" | |
| 32 | + | ) | |
| 33 | + | ||
| 34 | + | // ERROR_COMMIT_TIMER_EXISTS is the error commit_timer_exists value. | |
| 35 | + | const ERROR_COMMIT_TIMER_EXISTS = 0 | |
| 36 | + | ||
| 37 | + | // ERROR_INVALID_TIMESTAMP is the error invalid_timestamp value. | |
| 38 | + | const ERROR_INVALID_TIMESTAMP = 0 | |
| 39 | + | ||
| 40 | + | // ERROR_TIMESTAMP_EXISTS is the error timestamp_exists value. | |
| 41 | + | const ERROR_TIMESTAMP_EXISTS = 1 | |
| 42 | + | ||
| 43 | + | // ERROR_SURFACE_DESTROYED is the error surface_destroyed value. | |
| 44 | + | const ERROR_SURFACE_DESTROYED = 2 | |
| 45 | + | ||
| 46 | + | // WpCommitTimingManagerInterface is the protocol interface name. | |
| 47 | + | const WpCommitTimingManagerInterface = "wp_commit_timing_manager_v1" | |
| 48 | + | ||
| 49 | + | // WpCommitTimingManager is the generated binding for wp_commit_timing_manager_v1 version 1. | |
| 50 | + | type WpCommitTimingManager struct { | |
| 51 | + | wl.BaseProxy | |
| 52 | + | } | |
| 53 | + | ||
| 54 | + | // NewWpCommitTimingManager returns an unbound WpCommitTimingManager. | |
| 55 | + | func NewWpCommitTimingManager(ctx *wl.Context) *WpCommitTimingManager { | |
| 56 | + | obj := &WpCommitTimingManager{} | |
| 57 | + | obj.SetContext(ctx) | |
| 58 | + | ctx.Register(obj) | |
| 59 | + | return obj | |
| 60 | + | } | |
| 61 | + | ||
| 62 | + | // Informs the server that the client will no longer be using this protocol object. Existing objects created by this object are not affected. | |
| 63 | + | func (o *WpCommitTimingManager) Destroy() error { | |
| 64 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_commit_timing_manager_v1.destroy", Destructor: true}); err != nil { | |
| 65 | + | return err | |
| 66 | + | } | |
| 67 | + | return nil | |
| 68 | + | } | |
| 69 | + | ||
| 70 | + | // Establish a timing controller for a surface. Only one commit timer can be created for a surface, or a commit_timer_exists protocol error will be generated. | |
| 71 | + | func (o *WpCommitTimingManager) GetTimer(surface *cross_wl_surface.Surface) (*WpCommitTimer, error) { | |
| 72 | + | var arg1 wl.Object | |
| 73 | + | if surface != nil { | |
| 74 | + | arg1 = surface | |
| 75 | + | } | |
| 76 | + | child := &WpCommitTimer{} | |
| 77 | + | child.SetContext(o.Context()) | |
| 78 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_commit_timing_manager_v1.get_timer", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 79 | + | return nil, err | |
| 80 | + | } | |
| 81 | + | return child, nil | |
| 82 | + | } | |
| 83 | + | ||
| 84 | + | // EventSignature returns the declared event argument types in wire order. | |
| 85 | + | func (o *WpCommitTimingManager) EventSignature(opcode uint16) (string, bool) { | |
| 86 | + | switch opcode { | |
| 87 | + | default: | |
| 88 | + | return "", false | |
| 89 | + | } | |
| 90 | + | } | |
| 91 | + | ||
| 92 | + | // Dispatch decodes one event on wp_commit_timing_manager_v1 and calls the registered handlers. | |
| 93 | + | func (o *WpCommitTimingManager) Dispatch(event *wl.Event) { | |
| 94 | + | switch event.Opcode { | |
| 95 | + | default: | |
| 96 | + | } | |
| 97 | + | } | |
| 98 | + | ||
| 99 | + | // WpCommitTimerInterface is the protocol interface name. | |
| 100 | + | const WpCommitTimerInterface = "wp_commit_timer_v1" | |
| 101 | + | ||
| 102 | + | // WpCommitTimer is the generated binding for wp_commit_timer_v1 version 1. | |
| 103 | + | type WpCommitTimer struct { | |
| 104 | + | wl.BaseProxy | |
| 105 | + | } | |
| 106 | + | ||
| 107 | + | // NewWpCommitTimer returns an unbound WpCommitTimer. | |
| 108 | + | func NewWpCommitTimer(ctx *wl.Context) *WpCommitTimer { | |
| 109 | + | obj := &WpCommitTimer{} | |
| 110 | + | obj.SetContext(ctx) | |
| 111 | + | ctx.Register(obj) | |
| 112 | + | return obj | |
| 113 | + | } | |
| 114 | + | ||
| 115 | + | // Provide a timing constraint for a surface content update. A set_timestamp request may be made before a wl_surface.commit to tell the compositor that the content is intended to be presented as closely as possible to, but not before, the specified time. The time is in the domain of the compositor's presentation clock. An invalid_timestamp error will be generated for invalid tv_nsec. If a timestamp already exists on the surface, a timestamp_exists error is generated. Requesting set_timestamp after the commit_timer object's surface is destroyed will generate a "surface_destroyed" error. | |
| 116 | + | func (o *WpCommitTimer) SetTimestamp(tvSecHi uint32, tvSecLo uint32, tvNsec uint32) error { | |
| 117 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_commit_timer_v1.set_timestamp"}, wl.ArgUint(tvSecHi), wl.ArgUint(tvSecLo), wl.ArgUint(tvNsec)); err != nil { | |
| 118 | + | return err | |
| 119 | + | } | |
| 120 | + | return nil | |
| 121 | + | } | |
| 122 | + | ||
| 123 | + | // Informs the server that the client will no longer be using this protocol object. Existing timing constraints are not affected by the destruction. | |
| 124 | + | func (o *WpCommitTimer) Destroy() error { | |
| 125 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_commit_timer_v1.destroy", Destructor: true}); err != nil { | |
| 126 | + | return err | |
| 127 | + | } | |
| 128 | + | return nil | |
| 129 | + | } | |
| 130 | + | ||
| 131 | + | // EventSignature returns the declared event argument types in wire order. | |
| 132 | + | func (o *WpCommitTimer) EventSignature(opcode uint16) (string, bool) { | |
| 133 | + | switch opcode { | |
| 134 | + | default: | |
| 135 | + | return "", false | |
| 136 | + | } | |
| 137 | + | } | |
| 138 | + | ||
| 139 | + | // Dispatch decodes one event on wp_commit_timer_v1 and calls the registered handlers. | |
| 140 | + | func (o *WpCommitTimer) Dispatch(event *wl.Event) { | |
| 141 | + | switch event.Opcode { | |
| 142 | + | default: | |
| 143 | + | } | |
| 144 | + | } | |
A protocol/committiming/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package committiming | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p committiming -o commit-timing-v1_generated.go -import wl_surface=github.com/bnema/wlturbo/protocol/core commit-timing-v1.xml | |
A protocol/contenttype/content-type-v1.xml +128 -0
| @@ -0,0 +1,128 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="content_type_v1"> | |
| 3 | + | <copyright> | |
| 4 | + | Copyright © 2021 Emmanuel Gil Peyrot | |
| 5 | + | Copyright © 2022 Xaver Hugl | |
| 6 | + | ||
| 7 | + | Permission is hereby granted, free of charge, to any person obtaining a | |
| 8 | + | copy of this software and associated documentation files (the "Software"), | |
| 9 | + | to deal in the Software without restriction, including without limitation | |
| 10 | + | the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 11 | + | and/or sell copies of the Software, and to permit persons to whom the | |
| 12 | + | Software is furnished to do so, subject to the following conditions: | |
| 13 | + | ||
| 14 | + | The above copyright notice and this permission notice (including the next | |
| 15 | + | paragraph) shall be included in all copies or substantial portions of the | |
| 16 | + | Software. | |
| 17 | + | ||
| 18 | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | + | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | + | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 21 | + | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | + | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 23 | + | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 24 | + | DEALINGS IN THE SOFTWARE. | |
| 25 | + | </copyright> | |
| 26 | + | ||
| 27 | + | <interface name="wp_content_type_manager_v1" version="1"> | |
| 28 | + | <description summary="surface content type manager"> | |
| 29 | + | This interface allows a client to describe the kind of content a surface | |
| 30 | + | will display, to allow the compositor to optimize its behavior for it. | |
| 31 | + | ||
| 32 | + | Warning! The protocol described in this file is currently in the testing | |
| 33 | + | phase. Backward compatible changes may be added together with the | |
| 34 | + | corresponding interface version bump. Backward incompatible changes can | |
| 35 | + | only be done by creating a new major version of the extension. | |
| 36 | + | </description> | |
| 37 | + | ||
| 38 | + | <request name="destroy" type="destructor"> | |
| 39 | + | <description summary="destroy the content type manager object"> | |
| 40 | + | Destroy the content type manager. This doesn't destroy objects created | |
| 41 | + | with the manager. | |
| 42 | + | </description> | |
| 43 | + | </request> | |
| 44 | + | ||
| 45 | + | <enum name="error"> | |
| 46 | + | <entry name="already_constructed" value="0" | |
| 47 | + | summary="wl_surface already has a content type object"/> | |
| 48 | + | </enum> | |
| 49 | + | ||
| 50 | + | <request name="get_surface_content_type"> | |
| 51 | + | <description summary="create a new content type object"> | |
| 52 | + | Create a new content type object associated with the given surface. | |
| 53 | + | ||
| 54 | + | Creating a wp_content_type_v1 from a wl_surface which already has one | |
| 55 | + | attached is a client error: already_constructed. | |
| 56 | + | </description> | |
| 57 | + | <arg name="id" type="new_id" interface="wp_content_type_v1"/> | |
| 58 | + | <arg name="surface" type="object" interface="wl_surface"/> | |
| 59 | + | </request> | |
| 60 | + | </interface> | |
| 61 | + | ||
| 62 | + | <interface name="wp_content_type_v1" version="1"> | |
| 63 | + | <description summary="content type object for a surface"> | |
| 64 | + | The content type object allows the compositor to optimize for the kind | |
| 65 | + | of content shown on the surface. A compositor may for example use it to | |
| 66 | + | set relevant drm properties like "content type". | |
| 67 | + | ||
| 68 | + | The client may request to switch to another content type at any time. | |
| 69 | + | When the associated surface gets destroyed, this object becomes inert and | |
| 70 | + | the client should destroy it. | |
| 71 | + | </description> | |
| 72 | + | ||
| 73 | + | <request name="destroy" type="destructor"> | |
| 74 | + | <description summary="destroy the content type object"> | |
| 75 | + | Switch back to not specifying the content type of this surface. This is | |
| 76 | + | equivalent to setting the content type to none, including double | |
| 77 | + | buffering semantics. See set_content_type for details. | |
| 78 | + | </description> | |
| 79 | + | </request> | |
| 80 | + | ||
| 81 | + | <enum name="type"> | |
| 82 | + | <description summary="possible content types"> | |
| 83 | + | These values describe the available content types for a surface. | |
| 84 | + | </description> | |
| 85 | + | <entry name="none" value="0"> | |
| 86 | + | <description summary="no content type applies"> | |
| 87 | + | The content type none means that either the application has no data | |
| 88 | + | about the content type, or that the content doesn't fit into one of | |
| 89 | + | the other categories. | |
| 90 | + | </description> | |
| 91 | + | </entry> | |
| 92 | + | <entry name="photo" value="1"> | |
| 93 | + | <description summary="photo content type"> | |
| 94 | + | The content type photo describes content derived from digital still | |
| 95 | + | pictures and may be presented with minimal processing. | |
| 96 | + | </description> | |
| 97 | + | </entry> | |
| 98 | + | <entry name="video" value="2"> | |
| 99 | + | <description summary="video content type"> | |
| 100 | + | The content type video describes a video or animation and may be | |
| 101 | + | presented with more accurate timing to avoid stutter. Where scaling | |
| 102 | + | is needed, scaling methods more appropriate for video may be used. | |
| 103 | + | </description> | |
| 104 | + | </entry> | |
| 105 | + | <entry name="game" value="3"> | |
| 106 | + | <description summary="game content type"> | |
| 107 | + | The content type game describes a running game. Its content may be | |
| 108 | + | presented with reduced latency. | |
| 109 | + | </description> | |
| 110 | + | </entry> | |
| 111 | + | </enum> | |
| 112 | + | ||
| 113 | + | <request name="set_content_type"> | |
| 114 | + | <description summary="specify the content type"> | |
| 115 | + | Set the surface content type. This informs the compositor that the | |
| 116 | + | client believes it is displaying buffers matching this content type. | |
| 117 | + | ||
| 118 | + | This is purely a hint for the compositor, which can be used to adjust | |
| 119 | + | its behavior or hardware settings to fit the presented content best. | |
| 120 | + | ||
| 121 | + | The content type is double-buffered state, see wl_surface.commit for | |
| 122 | + | details. | |
| 123 | + | </description> | |
| 124 | + | <arg name="content_type" type="uint" enum="type" | |
| 125 | + | summary="the content type"/> | |
| 126 | + | </request> | |
| 127 | + | </interface> | |
| 128 | + | </protocol> | |
A protocol/contenttype/content-type-v1_generated.go +148 -0
| @@ -0,0 +1,148 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: content_type_v1 | |
| 3 | + | // Source: content-type-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2021 Emmanuel Gil Peyrot | |
| 7 | + | // Copyright © 2022 Xaver Hugl | |
| 8 | + | // | |
| 9 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 10 | + | // copy of this software and associated documentation files (the "Software"), | |
| 11 | + | // to deal in the Software without restriction, including without limitation | |
| 12 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 13 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 14 | + | // Software is furnished to do so, subject to the following conditions: | |
| 15 | + | // | |
| 16 | + | // The above copyright notice and this permission notice (including the next | |
| 17 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 18 | + | // Software. | |
| 19 | + | // | |
| 20 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 21 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 22 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 23 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 24 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 25 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 26 | + | // DEALINGS IN THE SOFTWARE. | |
| 27 | + | ||
| 28 | + | package contenttype | |
| 29 | + | ||
| 30 | + | import ( | |
| 31 | + | cross_wl_surface "github.com/bnema/wlturbo/protocol/core" | |
| 32 | + | "github.com/bnema/wlturbo/wl" | |
| 33 | + | ) | |
| 34 | + | ||
| 35 | + | // ERROR_ALREADY_CONSTRUCTED is the error already_constructed value. | |
| 36 | + | const ERROR_ALREADY_CONSTRUCTED = 0 | |
| 37 | + | ||
| 38 | + | // TYPE_NONE is the type none value. | |
| 39 | + | const TYPE_NONE = 0 | |
| 40 | + | ||
| 41 | + | // TYPE_PHOTO is the type photo value. | |
| 42 | + | const TYPE_PHOTO = 1 | |
| 43 | + | ||
| 44 | + | // TYPE_VIDEO is the type video value. | |
| 45 | + | const TYPE_VIDEO = 2 | |
| 46 | + | ||
| 47 | + | // TYPE_GAME is the type game value. | |
| 48 | + | const TYPE_GAME = 3 | |
| 49 | + | ||
| 50 | + | // WpContentTypeManagerInterface is the protocol interface name. | |
| 51 | + | const WpContentTypeManagerInterface = "wp_content_type_manager_v1" | |
| 52 | + | ||
| 53 | + | // WpContentTypeManager is the generated binding for wp_content_type_manager_v1 version 1. | |
| 54 | + | type WpContentTypeManager struct { | |
| 55 | + | wl.BaseProxy | |
| 56 | + | } | |
| 57 | + | ||
| 58 | + | // NewWpContentTypeManager returns an unbound WpContentTypeManager. | |
| 59 | + | func NewWpContentTypeManager(ctx *wl.Context) *WpContentTypeManager { | |
| 60 | + | obj := &WpContentTypeManager{} | |
| 61 | + | obj.SetContext(ctx) | |
| 62 | + | ctx.Register(obj) | |
| 63 | + | return obj | |
| 64 | + | } | |
| 65 | + | ||
| 66 | + | // Destroy the content type manager. This doesn't destroy objects created with the manager. | |
| 67 | + | func (o *WpContentTypeManager) Destroy() error { | |
| 68 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_content_type_manager_v1.destroy", Destructor: true}); err != nil { | |
| 69 | + | return err | |
| 70 | + | } | |
| 71 | + | return nil | |
| 72 | + | } | |
| 73 | + | ||
| 74 | + | // Create a new content type object associated with the given surface. Creating a wp_content_type_v1 from a wl_surface which already has one attached is a client error: already_constructed. | |
| 75 | + | func (o *WpContentTypeManager) GetSurfaceContentType(surface *cross_wl_surface.Surface) (*WpContentType, error) { | |
| 76 | + | var arg1 wl.Object | |
| 77 | + | if surface != nil { | |
| 78 | + | arg1 = surface | |
| 79 | + | } | |
| 80 | + | child := &WpContentType{} | |
| 81 | + | child.SetContext(o.Context()) | |
| 82 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_content_type_manager_v1.get_surface_content_type", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 83 | + | return nil, err | |
| 84 | + | } | |
| 85 | + | return child, nil | |
| 86 | + | } | |
| 87 | + | ||
| 88 | + | // EventSignature returns the declared event argument types in wire order. | |
| 89 | + | func (o *WpContentTypeManager) EventSignature(opcode uint16) (string, bool) { | |
| 90 | + | switch opcode { | |
| 91 | + | default: | |
| 92 | + | return "", false | |
| 93 | + | } | |
| 94 | + | } | |
| 95 | + | ||
| 96 | + | // Dispatch decodes one event on wp_content_type_manager_v1 and calls the registered handlers. | |
| 97 | + | func (o *WpContentTypeManager) Dispatch(event *wl.Event) { | |
| 98 | + | switch event.Opcode { | |
| 99 | + | default: | |
| 100 | + | } | |
| 101 | + | } | |
| 102 | + | ||
| 103 | + | // WpContentTypeInterface is the protocol interface name. | |
| 104 | + | const WpContentTypeInterface = "wp_content_type_v1" | |
| 105 | + | ||
| 106 | + | // WpContentType is the generated binding for wp_content_type_v1 version 1. | |
| 107 | + | type WpContentType struct { | |
| 108 | + | wl.BaseProxy | |
| 109 | + | } | |
| 110 | + | ||
| 111 | + | // NewWpContentType returns an unbound WpContentType. | |
| 112 | + | func NewWpContentType(ctx *wl.Context) *WpContentType { | |
| 113 | + | obj := &WpContentType{} | |
| 114 | + | obj.SetContext(ctx) | |
| 115 | + | ctx.Register(obj) | |
| 116 | + | return obj | |
| 117 | + | } | |
| 118 | + | ||
| 119 | + | // Switch back to not specifying the content type of this surface. This is equivalent to setting the content type to none, including double buffering semantics. See set_content_type for details. | |
| 120 | + | func (o *WpContentType) Destroy() error { | |
| 121 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_content_type_v1.destroy", Destructor: true}); err != nil { | |
| 122 | + | return err | |
| 123 | + | } | |
| 124 | + | return nil | |
| 125 | + | } | |
| 126 | + | ||
| 127 | + | // Set the surface content type. This informs the compositor that the client believes it is displaying buffers matching this content type. This is purely a hint for the compositor, which can be used to adjust its behavior or hardware settings to fit the presented content best. The content type is double-buffered state, see wl_surface.commit for details. | |
| 128 | + | func (o *WpContentType) SetContentType(contentType uint32) error { | |
| 129 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_content_type_v1.set_content_type"}, wl.ArgUint(contentType)); err != nil { | |
| 130 | + | return err | |
| 131 | + | } | |
| 132 | + | return nil | |
| 133 | + | } | |
| 134 | + | ||
| 135 | + | // EventSignature returns the declared event argument types in wire order. | |
| 136 | + | func (o *WpContentType) EventSignature(opcode uint16) (string, bool) { | |
| 137 | + | switch opcode { | |
| 138 | + | default: | |
| 139 | + | return "", false | |
| 140 | + | } | |
| 141 | + | } | |
| 142 | + | ||
| 143 | + | // Dispatch decodes one event on wp_content_type_v1 and calls the registered handlers. | |
| 144 | + | func (o *WpContentType) Dispatch(event *wl.Event) { | |
| 145 | + | switch event.Opcode { | |
| 146 | + | default: | |
| 147 | + | } | |
| 148 | + | } | |
A protocol/contenttype/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package contenttype | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p contenttype -o content-type-v1_generated.go -import wl_surface=github.com/bnema/wlturbo/protocol/core content-type-v1.xml | |
M protocol/core/wayland_generated.go +95 -69
| @@ -2,6 +2,32 @@ | |||
| 2 | 2 | // Protocol: wayland | |
| 3 | 3 | // Source: wayland.xml | |
| 4 | 4 | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2008-2011 Kristian Høgsberg | |
| 7 | + | // Copyright © 2010-2011 Intel Corporation | |
| 8 | + | // Copyright © 2012-2013 Collabora, Ltd. | |
| 9 | + | // | |
| 10 | + | // Permission is hereby granted, free of charge, to any person | |
| 11 | + | // obtaining a copy of this software and associated documentation files | |
| 12 | + | // (the "Software"), to deal in the Software without restriction, | |
| 13 | + | // including without limitation the rights to use, copy, modify, merge, | |
| 14 | + | // publish, distribute, sublicense, and/or sell copies of the Software, | |
| 15 | + | // and to permit persons to whom the Software is furnished to do so, | |
| 16 | + | // subject to the following conditions: | |
| 17 | + | // | |
| 18 | + | // The above copyright notice and this permission notice (including the | |
| 19 | + | // next paragraph) shall be included in all copies or substantial | |
| 20 | + | // portions of the Software. | |
| 21 | + | // | |
| 22 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
| 23 | + | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
| 24 | + | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
| 25 | + | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
| 26 | + | // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
| 27 | + | // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
| 28 | + | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 29 | + | // SOFTWARE. | |
| 30 | + | ||
| 5 | 31 | package core | |
| 6 | 32 | ||
| 7 | 33 | import ( | |
| @@ -775,7 +801,7 @@ func NewCompositor(ctx *wl.Context) *Compositor { | |||
| 775 | 801 | func (o *Compositor) CreateSurface() (*Surface, error) { | |
| 776 | 802 | child := &Surface{} | |
| 777 | 803 | child.SetContext(o.Context()) | |
| 778 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_compositor.create_surface", Child: child}, child); err != nil { | |
| 804 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wl_compositor.create_surface", Child: child}, wl.ArgObject(child)); err != nil { | |
| 779 | 805 | return nil, err | |
| 780 | 806 | } | |
| 781 | 807 | return child, nil | |
| @@ -785,7 +811,7 @@ func (o *Compositor) CreateSurface() (*Surface, error) { | |||
| 785 | 811 | func (o *Compositor) CreateRegion() (*Region, error) { | |
| 786 | 812 | child := &Region{} | |
| 787 | 813 | child.SetContext(o.Context()) | |
| 788 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_compositor.create_region", Child: child}, child); err != nil { | |
| 814 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wl_compositor.create_region", Child: child}, wl.ArgObject(child)); err != nil { | |
| 789 | 815 | return nil, err | |
| 790 | 816 | } | |
| 791 | 817 | return child, nil | |
| @@ -793,7 +819,7 @@ func (o *Compositor) CreateRegion() (*Region, error) { | |||
| 793 | 819 | ||
| 794 | 820 | // This request destroys the wl_compositor. This has no effect on any other objects. | |
| 795 | 821 | func (o *Compositor) Release() error { | |
| 796 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_compositor.release", Since: 7, Destructor: true}); err != nil { | |
| 822 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wl_compositor.release", Since: 7, Destructor: true}); err != nil { | |
| 797 | 823 | return err | |
| 798 | 824 | } | |
| 799 | 825 | return nil | |
| @@ -834,7 +860,7 @@ func NewShmPool(ctx *wl.Context) *ShmPool { | |||
| 834 | 860 | func (o *ShmPool) CreateBuffer(offset int32, width int32, height int32, stride int32, format uint32) (*Buffer, error) { | |
| 835 | 861 | child := &Buffer{} | |
| 836 | 862 | child.SetContext(o.Context()) | |
| 837 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_shm_pool.create_buffer", Child: child}, child, offset, width, height, stride, format); err != nil { | |
| 863 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wl_shm_pool.create_buffer", Child: child}, wl.ArgObject(child), wl.ArgInt(offset), wl.ArgInt(width), wl.ArgInt(height), wl.ArgInt(stride), wl.ArgUint(format)); err != nil { | |
| 838 | 864 | return nil, err | |
| 839 | 865 | } | |
| 840 | 866 | return child, nil | |
| @@ -842,7 +868,7 @@ func (o *ShmPool) CreateBuffer(offset int32, width int32, height int32, stride i | |||
| 842 | 868 | ||
| 843 | 869 | // Destroy the shared memory pool. The mmapped memory will be released when all buffers that have been created from this pool are gone. | |
| 844 | 870 | func (o *ShmPool) Destroy() error { | |
| 845 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_shm_pool.destroy", Destructor: true}); err != nil { | |
| 871 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wl_shm_pool.destroy", Destructor: true}); err != nil { | |
| 846 | 872 | return err | |
| 847 | 873 | } | |
| 848 | 874 | return nil | |
| @@ -850,7 +876,7 @@ func (o *ShmPool) Destroy() error { | |||
| 850 | 876 | ||
| 851 | 877 | // This request will cause the server to remap the backing memory for the pool from the file descriptor passed when the pool was created, but using the new size. This request can only be used to make the pool bigger. This request only changes the amount of bytes that are mmapped by the server and does not touch the file corresponding to the file descriptor passed at creation time. It is the client's responsibility to ensure that the file is at least as big as the new pool size. | |
| 852 | 878 | func (o *ShmPool) Resize(size int32) error { | |
| 853 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_shm_pool.resize"}, size); err != nil { | |
| 879 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wl_shm_pool.resize"}, wl.ArgInt(size)); err != nil { | |
| 854 | 880 | return err | |
| 855 | 881 | } | |
| 856 | 882 | return nil | |
| @@ -895,7 +921,7 @@ func NewShm(ctx *wl.Context) *Shm { | |||
| 895 | 921 | func (o *Shm) CreatePool(fd int, size int32) (*ShmPool, error) { | |
| 896 | 922 | child := &ShmPool{} | |
| 897 | 923 | child.SetContext(o.Context()) | |
| 898 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_shm.create_pool", Child: child, FDs: []int{fd}}, child, uintptr(fd), size); err != nil { | |
| 924 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wl_shm.create_pool", Child: child, FDs: []int{fd}}, wl.ArgObject(child), wl.ArgFD(), wl.ArgInt(size)); err != nil { | |
| 899 | 925 | return nil, err | |
| 900 | 926 | } | |
| 901 | 927 | return child, nil | |
| @@ -903,7 +929,7 @@ func (o *Shm) CreatePool(fd int, size int32) (*ShmPool, error) { | |||
| 903 | 929 | ||
| 904 | 930 | // Using this request a client can tell the server that it is not going to use the shm object anymore. Objects created via this interface remain unaffected. | |
| 905 | 931 | func (o *Shm) Release() error { | |
| 906 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_shm.release", Since: 2, Destructor: true}); err != nil { | |
| 932 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wl_shm.release", Since: 2, Destructor: true}); err != nil { | |
| 907 | 933 | return err | |
| 908 | 934 | } | |
| 909 | 935 | return nil | |
| @@ -977,7 +1003,7 @@ func NewBuffer(ctx *wl.Context) *Buffer { | |||
| 977 | 1003 | ||
| 978 | 1004 | // Destroy a buffer. If and how you need to release the backing storage is defined by the buffer factory interface. For possible side-effects to a surface, see wl_surface.attach. | |
| 979 | 1005 | func (o *Buffer) Destroy() error { | |
| 980 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_buffer.destroy", Destructor: true}); err != nil { | |
| 1006 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wl_buffer.destroy", Destructor: true}); err != nil { | |
| 981 | 1007 | return err | |
| 982 | 1008 | } | |
| 983 | 1009 | return nil | |
| @@ -1052,7 +1078,7 @@ func NewDataOffer(ctx *wl.Context) *DataOffer { | |||
| 1052 | 1078 | ||
| 1053 | 1079 | // Indicate that the client can accept the given mime type, or NULL for not accepted. For objects of version 2 or older, this request is used by the client to give feedback whether the client can receive the given mime type, or NULL if none is accepted; the feedback does not determine whether the drag-and-drop operation succeeds or not. For objects of version 3 or newer, this request determines the final result of the drag-and-drop operation. If the end result is that no mime types were accepted, the drag-and-drop operation will be cancelled and the corresponding drag source will receive wl_data_source.cancelled. Clients may still use this event in conjunction with wl_data_source.action for feedback. | |
| 1054 | 1080 | func (o *DataOffer) Accept(serial uint32, mimeType string) error { | |
| 1055 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_data_offer.accept"}, serial, mimeType); err != nil { | |
| 1081 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wl_data_offer.accept"}, wl.ArgUint(serial), wl.ArgString(mimeType)); err != nil { | |
| 1056 | 1082 | return err | |
| 1057 | 1083 | } | |
| 1058 | 1084 | return nil | |
| @@ -1060,7 +1086,7 @@ func (o *DataOffer) Accept(serial uint32, mimeType string) error { | |||
| 1060 | 1086 | ||
| 1061 | 1087 | // To transfer the offered data, the client issues this request and indicates the mime type it wants to receive. The transfer happens through the passed file descriptor (typically created with the pipe system call). The source client writes the data in the mime type representation requested and then closes the file descriptor. The receiving client reads from the read end of the pipe until EOF and then closes its end, at which point the transfer is complete. This request may happen multiple times for different mime types, both before and after wl_data_device.drop. Drag-and-drop destination clients may preemptively fetch data or examine it more closely to determine acceptance. | |
| 1062 | 1088 | func (o *DataOffer) Receive(mimeType string, fd int) error { | |
| 1063 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_data_offer.receive", FDs: []int{fd}}, mimeType, uintptr(fd)); err != nil { | |
| 1089 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wl_data_offer.receive", FDs: []int{fd}}, wl.ArgString(mimeType), wl.ArgFD()); err != nil { | |
| 1064 | 1090 | return err | |
| 1065 | 1091 | } | |
| 1066 | 1092 | return nil | |
| @@ -1068,7 +1094,7 @@ func (o *DataOffer) Receive(mimeType string, fd int) error { | |||
| 1068 | 1094 | ||
| 1069 | 1095 | // Destroy the data offer. | |
| 1070 | 1096 | func (o *DataOffer) Destroy() error { | |
| 1071 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_data_offer.destroy", Destructor: true}); err != nil { | |
| 1097 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wl_data_offer.destroy", Destructor: true}); err != nil { | |
| 1072 | 1098 | return err | |
| 1073 | 1099 | } | |
| 1074 | 1100 | return nil | |
| @@ -1076,7 +1102,7 @@ func (o *DataOffer) Destroy() error { | |||
| 1076 | 1102 | ||
| 1077 | 1103 | // Notifies the compositor that the drag destination successfully finished the drag-and-drop operation. Upon receiving this request, the compositor will emit wl_data_source.dnd_finished on the drag source client. It is a client error to perform other requests than wl_data_offer.destroy after this one. It is also an error to perform this request after a NULL mime type has been set in wl_data_offer.accept or no action was received through wl_data_offer.action. If wl_data_offer.finish request is received for a non drag and drop operation, the invalid_finish protocol error is raised. | |
| 1078 | 1104 | func (o *DataOffer) Finish() error { | |
| 1079 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "wl_data_offer.finish", Since: 3}); err != nil { | |
| 1105 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "wl_data_offer.finish", Since: 3}); err != nil { | |
| 1080 | 1106 | return err | |
| 1081 | 1107 | } | |
| 1082 | 1108 | return nil | |
| @@ -1084,7 +1110,7 @@ func (o *DataOffer) Finish() error { | |||
| 1084 | 1110 | ||
| 1085 | 1111 | // Sets the actions that the destination side client supports for this operation. This request may trigger the emission of wl_data_source.action and wl_data_offer.action events if the compositor needs to change the selected action. This request can be called multiple times throughout the drag-and-drop operation, typically in response to wl_data_device.enter or wl_data_device.motion events. This request determines the final result of the drag-and-drop operation. If the end result is that no action is accepted, the drag source will receive wl_data_source.cancelled. The dnd_actions argument must contain only values expressed in the wl_data_device_manager.dnd_actions enum, and the preferred_action argument must only contain one of those values set, otherwise it will result in a protocol error. While managing an "ask" action, the destination drag-and-drop client may perform further wl_data_offer.receive requests, and is expected to perform one last wl_data_offer.set_actions request with a preferred action other than "ask" (and optionally wl_data_offer.accept) before requesting wl_data_offer.finish, in order to convey the action selected by the user. If the preferred action is not in the wl_data_offer.source_actions mask, an error will be raised. If the "ask" action is dismissed (e.g. user cancellation), the client is expected to perform wl_data_offer.destroy right away. This request can only be made on drag-and-drop offers, a protocol error will be raised otherwise. | |
| 1086 | 1112 | func (o *DataOffer) SetActions(dndActions uint32, preferredAction uint32) error { | |
| 1087 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "wl_data_offer.set_actions", Since: 3}, dndActions, preferredAction); err != nil { | |
| 1113 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 4, Name: "wl_data_offer.set_actions", Since: 3}, wl.ArgUint(dndActions), wl.ArgUint(preferredAction)); err != nil { | |
| 1088 | 1114 | return err | |
| 1089 | 1115 | } | |
| 1090 | 1116 | return nil | |
| @@ -1225,7 +1251,7 @@ func NewDataSource(ctx *wl.Context) *DataSource { | |||
| 1225 | 1251 | ||
| 1226 | 1252 | // This request adds a mime type to the set of mime types advertised to targets. Can be called several times to offer multiple types. | |
| 1227 | 1253 | func (o *DataSource) Offer(mimeType string) error { | |
| 1228 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_data_source.offer"}, mimeType); err != nil { | |
| 1254 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wl_data_source.offer"}, wl.ArgString(mimeType)); err != nil { | |
| 1229 | 1255 | return err | |
| 1230 | 1256 | } | |
| 1231 | 1257 | return nil | |
| @@ -1233,7 +1259,7 @@ func (o *DataSource) Offer(mimeType string) error { | |||
| 1233 | 1259 | ||
| 1234 | 1260 | // Destroy the data source. | |
| 1235 | 1261 | func (o *DataSource) Destroy() error { | |
| 1236 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_data_source.destroy", Destructor: true}); err != nil { | |
| 1262 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wl_data_source.destroy", Destructor: true}); err != nil { | |
| 1237 | 1263 | return err | |
| 1238 | 1264 | } | |
| 1239 | 1265 | return nil | |
| @@ -1241,7 +1267,7 @@ func (o *DataSource) Destroy() error { | |||
| 1241 | 1267 | ||
| 1242 | 1268 | // Sets the actions that the source side client supports for this operation. This request may trigger wl_data_source.action and wl_data_offer.action events if the compositor needs to change the selected action. The dnd_actions argument must contain only values expressed in the wl_data_device_manager.dnd_actions enum, otherwise it will result in a protocol error. This request must be made once only, and can only be made on sources used in drag-and-drop, so it must be performed before wl_data_device.start_drag. Attempting to use the source other than for drag-and-drop will raise a protocol error. | |
| 1243 | 1269 | func (o *DataSource) SetActions(dndActions uint32) error { | |
| 1244 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_data_source.set_actions", Since: 3}, dndActions); err != nil { | |
| 1270 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wl_data_source.set_actions", Since: 3}, wl.ArgUint(dndActions)); err != nil { | |
| 1245 | 1271 | return err | |
| 1246 | 1272 | } | |
| 1247 | 1273 | return nil | |
| @@ -1489,7 +1515,7 @@ func (o *DataDevice) StartDrag(source *DataSource, origin *Surface, icon *Surfac | |||
| 1489 | 1515 | if icon != nil { | |
| 1490 | 1516 | arg2 = icon | |
| 1491 | 1517 | } | |
| 1492 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_data_device.start_drag"}, arg0, arg1, arg2, serial); err != nil { | |
| 1518 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wl_data_device.start_drag"}, wl.ArgObject(arg0), wl.ArgObject(arg1), wl.ArgObject(arg2), wl.ArgUint(serial)); err != nil { | |
| 1493 | 1519 | return err | |
| 1494 | 1520 | } | |
| 1495 | 1521 | return nil | |
| @@ -1501,7 +1527,7 @@ func (o *DataDevice) SetSelection(source *DataSource, serial uint32) error { | |||
| 1501 | 1527 | if source != nil { | |
| 1502 | 1528 | arg0 = source | |
| 1503 | 1529 | } | |
| 1504 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_data_device.set_selection"}, arg0, serial); err != nil { | |
| 1530 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wl_data_device.set_selection"}, wl.ArgObject(arg0), wl.ArgUint(serial)); err != nil { | |
| 1505 | 1531 | return err | |
| 1506 | 1532 | } | |
| 1507 | 1533 | return nil | |
| @@ -1509,7 +1535,7 @@ func (o *DataDevice) SetSelection(source *DataSource, serial uint32) error { | |||
| 1509 | 1535 | ||
| 1510 | 1536 | // This request destroys the data device. | |
| 1511 | 1537 | func (o *DataDevice) Release() error { | |
| 1512 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_data_device.release", Since: 2, Destructor: true}); err != nil { | |
| 1538 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wl_data_device.release", Since: 2, Destructor: true}); err != nil { | |
| 1513 | 1539 | return err | |
| 1514 | 1540 | } | |
| 1515 | 1541 | return nil | |
| @@ -1745,7 +1771,7 @@ func NewDataDeviceManager(ctx *wl.Context) *DataDeviceManager { | |||
| 1745 | 1771 | func (o *DataDeviceManager) CreateDataSource() (*DataSource, error) { | |
| 1746 | 1772 | child := &DataSource{} | |
| 1747 | 1773 | child.SetContext(o.Context()) | |
| 1748 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_data_device_manager.create_data_source", Child: child}, child); err != nil { | |
| 1774 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wl_data_device_manager.create_data_source", Child: child}, wl.ArgObject(child)); err != nil { | |
| 1749 | 1775 | return nil, err | |
| 1750 | 1776 | } | |
| 1751 | 1777 | return child, nil | |
| @@ -1759,7 +1785,7 @@ func (o *DataDeviceManager) GetDataDevice(seat *Seat) (*DataDevice, error) { | |||
| 1759 | 1785 | } | |
| 1760 | 1786 | child := &DataDevice{} | |
| 1761 | 1787 | child.SetContext(o.Context()) | |
| 1762 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_data_device_manager.get_data_device", Child: child}, child, arg1); err != nil { | |
| 1788 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wl_data_device_manager.get_data_device", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 1763 | 1789 | return nil, err | |
| 1764 | 1790 | } | |
| 1765 | 1791 | return child, nil | |
| @@ -1767,7 +1793,7 @@ func (o *DataDeviceManager) GetDataDevice(seat *Seat) (*DataDevice, error) { | |||
| 1767 | 1793 | ||
| 1768 | 1794 | // This request destroys the wl_data_device_manager. This has no effect on any other objects. | |
| 1769 | 1795 | func (o *DataDeviceManager) Release() error { | |
| 1770 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_data_device_manager.release", Since: 4, Destructor: true}); err != nil { | |
| 1796 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wl_data_device_manager.release", Since: 4, Destructor: true}); err != nil { | |
| 1771 | 1797 | return err | |
| 1772 | 1798 | } | |
| 1773 | 1799 | return nil | |
| @@ -1812,7 +1838,7 @@ func (o *Shell) GetShellSurface(surface *Surface) (*ShellSurface, error) { | |||
| 1812 | 1838 | } | |
| 1813 | 1839 | child := &ShellSurface{} | |
| 1814 | 1840 | child.SetContext(o.Context()) | |
| 1815 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_shell.get_shell_surface", Child: child}, child, arg1); err != nil { | |
| 1841 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wl_shell.get_shell_surface", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 1816 | 1842 | return nil, err | |
| 1817 | 1843 | } | |
| 1818 | 1844 | return child, nil | |
| @@ -1857,7 +1883,7 @@ func NewShellSurface(ctx *wl.Context) *ShellSurface { | |||
| 1857 | 1883 | ||
| 1858 | 1884 | // A client must respond to a ping event with a pong request or the client may be deemed unresponsive. | |
| 1859 | 1885 | func (o *ShellSurface) Pong(serial uint32) error { | |
| 1860 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_shell_surface.pong"}, serial); err != nil { | |
| 1886 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wl_shell_surface.pong"}, wl.ArgUint(serial)); err != nil { | |
| 1861 | 1887 | return err | |
| 1862 | 1888 | } | |
| 1863 | 1889 | return nil | |
| @@ -1869,7 +1895,7 @@ func (o *ShellSurface) Move(seat *Seat, serial uint32) error { | |||
| 1869 | 1895 | if seat != nil { | |
| 1870 | 1896 | arg0 = seat | |
| 1871 | 1897 | } | |
| 1872 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_shell_surface.move"}, arg0, serial); err != nil { | |
| 1898 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wl_shell_surface.move"}, wl.ArgObject(arg0), wl.ArgUint(serial)); err != nil { | |
| 1873 | 1899 | return err | |
| 1874 | 1900 | } | |
| 1875 | 1901 | return nil | |
| @@ -1881,7 +1907,7 @@ func (o *ShellSurface) Resize(seat *Seat, serial uint32, edges uint32) error { | |||
| 1881 | 1907 | if seat != nil { | |
| 1882 | 1908 | arg0 = seat | |
| 1883 | 1909 | } | |
| 1884 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_shell_surface.resize"}, arg0, serial, edges); err != nil { | |
| 1910 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wl_shell_surface.resize"}, wl.ArgObject(arg0), wl.ArgUint(serial), wl.ArgUint(edges)); err != nil { | |
| 1885 | 1911 | return err | |
| 1886 | 1912 | } | |
| 1887 | 1913 | return nil | |
| @@ -1889,7 +1915,7 @@ func (o *ShellSurface) Resize(seat *Seat, serial uint32, edges uint32) error { | |||
| 1889 | 1915 | ||
| 1890 | 1916 | // Map the surface as a toplevel surface. A toplevel surface is not fullscreen, maximized or transient. | |
| 1891 | 1917 | func (o *ShellSurface) SetToplevel() error { | |
| 1892 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "wl_shell_surface.set_toplevel"}); err != nil { | |
| 1918 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "wl_shell_surface.set_toplevel"}); err != nil { | |
| 1893 | 1919 | return err | |
| 1894 | 1920 | } | |
| 1895 | 1921 | return nil | |
| @@ -1901,7 +1927,7 @@ func (o *ShellSurface) SetTransient(parent *Surface, x int32, y int32, flags uin | |||
| 1901 | 1927 | if parent != nil { | |
| 1902 | 1928 | arg0 = parent | |
| 1903 | 1929 | } | |
| 1904 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "wl_shell_surface.set_transient"}, arg0, x, y, flags); err != nil { | |
| 1930 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 4, Name: "wl_shell_surface.set_transient"}, wl.ArgObject(arg0), wl.ArgInt(x), wl.ArgInt(y), wl.ArgUint(flags)); err != nil { | |
| 1905 | 1931 | return err | |
| 1906 | 1932 | } | |
| 1907 | 1933 | return nil | |
| @@ -1913,7 +1939,7 @@ func (o *ShellSurface) SetFullscreen(method uint32, framerate uint32, output *Ou | |||
| 1913 | 1939 | if output != nil { | |
| 1914 | 1940 | arg2 = output | |
| 1915 | 1941 | } | |
| 1916 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 5, Name: "wl_shell_surface.set_fullscreen"}, method, framerate, arg2); err != nil { | |
| 1942 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 5, Name: "wl_shell_surface.set_fullscreen"}, wl.ArgUint(method), wl.ArgUint(framerate), wl.ArgObject(arg2)); err != nil { | |
| 1917 | 1943 | return err | |
| 1918 | 1944 | } | |
| 1919 | 1945 | return nil | |
| @@ -1929,7 +1955,7 @@ func (o *ShellSurface) SetPopup(seat *Seat, serial uint32, parent *Surface, x in | |||
| 1929 | 1955 | if parent != nil { | |
| 1930 | 1956 | arg2 = parent | |
| 1931 | 1957 | } | |
| 1932 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 6, Name: "wl_shell_surface.set_popup"}, arg0, serial, arg2, x, y, flags); err != nil { | |
| 1958 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 6, Name: "wl_shell_surface.set_popup"}, wl.ArgObject(arg0), wl.ArgUint(serial), wl.ArgObject(arg2), wl.ArgInt(x), wl.ArgInt(y), wl.ArgUint(flags)); err != nil { | |
| 1933 | 1959 | return err | |
| 1934 | 1960 | } | |
| 1935 | 1961 | return nil | |
| @@ -1941,7 +1967,7 @@ func (o *ShellSurface) SetMaximized(output *Output) error { | |||
| 1941 | 1967 | if output != nil { | |
| 1942 | 1968 | arg0 = output | |
| 1943 | 1969 | } | |
| 1944 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 7, Name: "wl_shell_surface.set_maximized"}, arg0); err != nil { | |
| 1970 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 7, Name: "wl_shell_surface.set_maximized"}, wl.ArgObject(arg0)); err != nil { | |
| 1945 | 1971 | return err | |
| 1946 | 1972 | } | |
| 1947 | 1973 | return nil | |
| @@ -1949,7 +1975,7 @@ func (o *ShellSurface) SetMaximized(output *Output) error { | |||
| 1949 | 1975 | ||
| 1950 | 1976 | // Set a short title for the surface. This string may be used to identify the surface in a task bar, window list, or other user interface elements provided by the compositor. The string must be encoded in UTF-8. | |
| 1951 | 1977 | func (o *ShellSurface) SetTitle(title string) error { | |
| 1952 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 8, Name: "wl_shell_surface.set_title"}, title); err != nil { | |
| 1978 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 8, Name: "wl_shell_surface.set_title"}, wl.ArgString(title)); err != nil { | |
| 1953 | 1979 | return err | |
| 1954 | 1980 | } | |
| 1955 | 1981 | return nil | |
| @@ -1957,7 +1983,7 @@ func (o *ShellSurface) SetTitle(title string) error { | |||
| 1957 | 1983 | ||
| 1958 | 1984 | // Set a class for the surface. The surface class identifies the general class of applications to which the surface belongs. A common convention is to use the file name (or the full path if it is a non-standard location) of the application's .desktop file as the class. | |
| 1959 | 1985 | func (o *ShellSurface) SetClass(class string) error { | |
| 1960 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 9, Name: "wl_shell_surface.set_class"}, class); err != nil { | |
| 1986 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 9, Name: "wl_shell_surface.set_class"}, wl.ArgString(class)); err != nil { | |
| 1961 | 1987 | return err | |
| 1962 | 1988 | } | |
| 1963 | 1989 | return nil | |
| @@ -2097,7 +2123,7 @@ func NewSurface(ctx *wl.Context) *Surface { | |||
| 2097 | 2123 | ||
| 2098 | 2124 | // Deletes the surface and invalidates its object ID. | |
| 2099 | 2125 | func (o *Surface) Destroy() error { | |
| 2100 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_surface.destroy", Destructor: true}); err != nil { | |
| 2126 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wl_surface.destroy", Destructor: true}); err != nil { | |
| 2101 | 2127 | return err | |
| 2102 | 2128 | } | |
| 2103 | 2129 | return nil | |
| @@ -2109,7 +2135,7 @@ func (o *Surface) Attach(buffer *Buffer, x int32, y int32) error { | |||
| 2109 | 2135 | if buffer != nil { | |
| 2110 | 2136 | arg0 = buffer | |
| 2111 | 2137 | } | |
| 2112 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_surface.attach"}, arg0, x, y); err != nil { | |
| 2138 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wl_surface.attach"}, wl.ArgObject(arg0), wl.ArgInt(x), wl.ArgInt(y)); err != nil { | |
| 2113 | 2139 | return err | |
| 2114 | 2140 | } | |
| 2115 | 2141 | return nil | |
| @@ -2117,7 +2143,7 @@ func (o *Surface) Attach(buffer *Buffer, x int32, y int32) error { | |||
| 2117 | 2143 | ||
| 2118 | 2144 | // This request is used to describe the regions where the pending buffer is different from the current surface contents, and where the surface therefore needs to be repainted. The compositor ignores the parts of the damage that fall outside of the surface. Damage is double-buffered state, see wl_surface.commit. The damage rectangle is specified in surface-local coordinates, where x and y specify the upper left corner of the damage rectangle. The initial value for pending damage is empty: no damage. wl_surface.damage adds pending damage: the new pending damage is the union of old pending damage and the given rectangle. wl_surface.commit assigns pending damage as the current damage, and clears pending damage. The server will clear the current damage as it repaints the surface. Note! New clients should not use this request. Instead damage can be posted with wl_surface.damage_buffer which uses buffer coordinates instead of surface coordinates. | |
| 2119 | 2145 | func (o *Surface) Damage(x int32, y int32, width int32, height int32) error { | |
| 2120 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_surface.damage"}, x, y, width, height); err != nil { | |
| 2146 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wl_surface.damage"}, wl.ArgInt(x), wl.ArgInt(y), wl.ArgInt(width), wl.ArgInt(height)); err != nil { | |
| 2121 | 2147 | return err | |
| 2122 | 2148 | } | |
| 2123 | 2149 | return nil | |
| @@ -2127,7 +2153,7 @@ func (o *Surface) Damage(x int32, y int32, width int32, height int32) error { | |||
| 2127 | 2153 | func (o *Surface) Frame() (*Callback, error) { | |
| 2128 | 2154 | child := &Callback{} | |
| 2129 | 2155 | child.SetContext(o.Context()) | |
| 2130 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "wl_surface.frame", Child: child}, child); err != nil { | |
| 2156 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "wl_surface.frame", Child: child}, wl.ArgObject(child)); err != nil { | |
| 2131 | 2157 | return nil, err | |
| 2132 | 2158 | } | |
| 2133 | 2159 | return child, nil | |
| @@ -2139,7 +2165,7 @@ func (o *Surface) SetOpaqueRegion(region *Region) error { | |||
| 2139 | 2165 | if region != nil { | |
| 2140 | 2166 | arg0 = region | |
| 2141 | 2167 | } | |
| 2142 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "wl_surface.set_opaque_region"}, arg0); err != nil { | |
| 2168 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 4, Name: "wl_surface.set_opaque_region"}, wl.ArgObject(arg0)); err != nil { | |
| 2143 | 2169 | return err | |
| 2144 | 2170 | } | |
| 2145 | 2171 | return nil | |
| @@ -2151,7 +2177,7 @@ func (o *Surface) SetInputRegion(region *Region) error { | |||
| 2151 | 2177 | if region != nil { | |
| 2152 | 2178 | arg0 = region | |
| 2153 | 2179 | } | |
| 2154 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 5, Name: "wl_surface.set_input_region"}, arg0); err != nil { | |
| 2180 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 5, Name: "wl_surface.set_input_region"}, wl.ArgObject(arg0)); err != nil { | |
| 2155 | 2181 | return err | |
| 2156 | 2182 | } | |
| 2157 | 2183 | return nil | |
| @@ -2159,7 +2185,7 @@ func (o *Surface) SetInputRegion(region *Region) error { | |||
| 2159 | 2185 | ||
| 2160 | 2186 | // Surface state (input, opaque, and damage regions, attached buffers, etc.) is double-buffered. Protocol requests modify the pending state, as opposed to the active state in use by the compositor. All requests that need a commit to become effective are documented to affect double-buffered state. Other interfaces may add further double-buffered surface state. A commit request atomically creates a Content Update (CU) from the pending state, even if the pending state has not been touched. The content update is placed at the end of a per-surface queue until it becomes active. After commit, the new pending state is as documented for each related request. A CU is either a Desync Content Update (DCU) or a Sync Content Update (SCU). If the surface is effectively synchronized at the commit request, it is a SCU, otherwise a DCU. When a surface transitions from effectively synchronized to effectively desynchronized, all SCUs in its queue which are not reachable by any DCU become DCUs and dependency edges from outside the queue to these CUs are removed. See wl_subsurface for the definition of 'effectively synchronized' and 'effectively desynchronized'. When a CU is placed in the queue, the CU has a dependency on the CU in front of it and to the SCU at end of the queue of every direct child surface if that SCU exists and does not have another dependent. This can form a directed acyclic graph of CUs with dependencies as edges. In addition to surface state, the CU can have constraints that must be satisfied before it can be applied. Other interfaces may add CU constraints. All DCUs which do not have a SCU in front of themselves in their queue, are candidates. If the graph that's reachable by a candidate does not have any unsatisfied constraints, the entire graph must be applied atomically. When a CU is applied, the wl_buffer is applied before all other state. This means that all coordinates in double-buffered state are relative to the newly attached wl_buffers, except for wl_surface.attach itself. If there is no newly attached wl_buffer, the coordinates are relative to the previous content update. | |
| 2161 | 2187 | func (o *Surface) Commit() error { | |
| 2162 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 6, Name: "wl_surface.commit"}); err != nil { | |
| 2188 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 6, Name: "wl_surface.commit"}); err != nil { | |
| 2163 | 2189 | return err | |
| 2164 | 2190 | } | |
| 2165 | 2191 | return nil | |
| @@ -2167,7 +2193,7 @@ func (o *Surface) Commit() error { | |||
| 2167 | 2193 | ||
| 2168 | 2194 | // This request sets the transformation that the client has already applied to the content of the buffer. The accepted values for the transform parameter are the values for wl_output.transform. The compositor applies the inverse of this transformation whenever it uses the buffer contents. Buffer transform is double-buffered state, see wl_surface.commit. A newly created surface has its buffer transformation set to normal. wl_surface.set_buffer_transform changes the pending buffer transformation. wl_surface.commit copies the pending buffer transformation to the current one. Otherwise, the pending and current values are never changed. The purpose of this request is to allow clients to render content according to the output transform, thus permitting the compositor to use certain optimizations even if the display is rotated. Using hardware overlays and scanning out a client buffer for fullscreen surfaces are examples of such optimizations. Those optimizations are highly dependent on the compositor implementation, so the use of this request should be considered on a case-by-case basis. Note that if the transform value includes 90 or 270 degree rotation, the width of the buffer will become the surface height and the height of the buffer will become the surface width. If transform is not one of the values from the wl_output.transform enum the invalid_transform protocol error is raised. | |
| 2169 | 2195 | func (o *Surface) SetBufferTransform(transform int32) error { | |
| 2170 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 7, Name: "wl_surface.set_buffer_transform", Since: 2}, transform); err != nil { | |
| 2196 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 7, Name: "wl_surface.set_buffer_transform", Since: 2}, wl.ArgInt(transform)); err != nil { | |
| 2171 | 2197 | return err | |
| 2172 | 2198 | } | |
| 2173 | 2199 | return nil | |
| @@ -2175,7 +2201,7 @@ func (o *Surface) SetBufferTransform(transform int32) error { | |||
| 2175 | 2201 | ||
| 2176 | 2202 | // This request sets an optional scaling factor on how the compositor interprets the contents of the buffer attached to the window. Buffer scale is double-buffered state, see wl_surface.commit. A newly created surface has its buffer scale set to 1. wl_surface.set_buffer_scale changes the pending buffer scale. wl_surface.commit copies the pending buffer scale to the current one. Otherwise, the pending and current values are never changed. The purpose of this request is to allow clients to supply higher resolution buffer data for use on high resolution outputs. It is intended that you pick the same buffer scale as the scale of the output that the surface is displayed on. This means the compositor can avoid scaling when rendering the surface on that output. Note that if the scale is larger than 1, then you have to attach a buffer that is larger (by a factor of scale in each dimension) than the desired surface size. If scale is not greater than 0 the invalid_scale protocol error is raised. | |
| 2177 | 2203 | func (o *Surface) SetBufferScale(scale int32) error { | |
| 2178 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 8, Name: "wl_surface.set_buffer_scale", Since: 3}, scale); err != nil { | |
| 2204 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 8, Name: "wl_surface.set_buffer_scale", Since: 3}, wl.ArgInt(scale)); err != nil { | |
| 2179 | 2205 | return err | |
| 2180 | 2206 | } | |
| 2181 | 2207 | return nil | |
| @@ -2183,7 +2209,7 @@ func (o *Surface) SetBufferScale(scale int32) error { | |||
| 2183 | 2209 | ||
| 2184 | 2210 | // This request is used to describe the regions where the pending buffer is different from the current surface contents, and where the surface therefore needs to be repainted. The compositor ignores the parts of the damage that fall outside of the surface. Damage is double-buffered state, see wl_surface.commit. The damage rectangle is specified in buffer coordinates, where x and y specify the upper left corner of the damage rectangle. The initial value for pending damage is empty: no damage. wl_surface.damage_buffer adds pending damage: the new pending damage is the union of old pending damage and the given rectangle. wl_surface.commit assigns pending damage as the current damage, and clears pending damage. The server will clear the current damage as it repaints the surface. This request differs from wl_surface.damage in only one way - it takes damage in buffer coordinates instead of surface-local coordinates. While this generally is more intuitive than surface coordinates, it is especially desirable when using wp_viewport or when a drawing library (like EGL) is unaware of buffer scale and buffer transform. Note: Because buffer transformation changes and damage requests may be interleaved in the protocol stream, it is impossible to determine the actual mapping between surface and buffer damage until wl_surface.commit time. Therefore, compositors wishing to take both kinds of damage into account will have to accumulate damage from the two requests separately and only transform from one to the other after receiving the wl_surface.commit. | |
| 2185 | 2211 | func (o *Surface) DamageBuffer(x int32, y int32, width int32, height int32) error { | |
| 2186 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 9, Name: "wl_surface.damage_buffer", Since: 4}, x, y, width, height); err != nil { | |
| 2212 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 9, Name: "wl_surface.damage_buffer", Since: 4}, wl.ArgInt(x), wl.ArgInt(y), wl.ArgInt(width), wl.ArgInt(height)); err != nil { | |
| 2187 | 2213 | return err | |
| 2188 | 2214 | } | |
| 2189 | 2215 | return nil | |
| @@ -2191,7 +2217,7 @@ func (o *Surface) DamageBuffer(x int32, y int32, width int32, height int32) erro | |||
| 2191 | 2217 | ||
| 2192 | 2218 | // The x and y arguments specify the location of the new pending buffer's upper left corner, relative to the current buffer's upper left corner, in surface-local coordinates. In other words, the x and y, combined with the new surface size define in which directions the surface's size changes. The exact semantics of wl_surface.offset are role-specific. Refer to the documentation of specific roles for more information. Surface location offset is double-buffered state, see wl_surface.commit. This request is semantically equivalent to and the replaces the x and y arguments in the wl_surface.attach request in wl_surface versions prior to 5. See wl_surface.attach for details. | |
| 2193 | 2219 | func (o *Surface) Offset(x int32, y int32) error { | |
| 2194 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 10, Name: "wl_surface.offset", Since: 5}, x, y); err != nil { | |
| 2220 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 10, Name: "wl_surface.offset", Since: 5}, wl.ArgInt(x), wl.ArgInt(y)); err != nil { | |
| 2195 | 2221 | return err | |
| 2196 | 2222 | } | |
| 2197 | 2223 | return nil | |
| @@ -2201,7 +2227,7 @@ func (o *Surface) Offset(x int32, y int32) error { | |||
| 2201 | 2227 | func (o *Surface) GetRelease() (*Callback, error) { | |
| 2202 | 2228 | child := &Callback{} | |
| 2203 | 2229 | child.SetContext(o.Context()) | |
| 2204 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 11, Name: "wl_surface.get_release", Since: 7, Child: child}, child); err != nil { | |
| 2230 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 11, Name: "wl_surface.get_release", Since: 7, Child: child}, wl.ArgObject(child)); err != nil { | |
| 2205 | 2231 | return nil, err | |
| 2206 | 2232 | } | |
| 2207 | 2233 | return child, nil | |
| @@ -2371,7 +2397,7 @@ func NewSeat(ctx *wl.Context) *Seat { | |||
| 2371 | 2397 | func (o *Seat) GetPointer() (*Pointer, error) { | |
| 2372 | 2398 | child := &Pointer{} | |
| 2373 | 2399 | child.SetContext(o.Context()) | |
| 2374 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_seat.get_pointer", Child: child}, child); err != nil { | |
| 2400 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wl_seat.get_pointer", Child: child}, wl.ArgObject(child)); err != nil { | |
| 2375 | 2401 | return nil, err | |
| 2376 | 2402 | } | |
| 2377 | 2403 | return child, nil | |
| @@ -2381,7 +2407,7 @@ func (o *Seat) GetPointer() (*Pointer, error) { | |||
| 2381 | 2407 | func (o *Seat) GetKeyboard() (*Keyboard, error) { | |
| 2382 | 2408 | child := &Keyboard{} | |
| 2383 | 2409 | child.SetContext(o.Context()) | |
| 2384 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_seat.get_keyboard", Child: child}, child); err != nil { | |
| 2410 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wl_seat.get_keyboard", Child: child}, wl.ArgObject(child)); err != nil { | |
| 2385 | 2411 | return nil, err | |
| 2386 | 2412 | } | |
| 2387 | 2413 | return child, nil | |
| @@ -2391,7 +2417,7 @@ func (o *Seat) GetKeyboard() (*Keyboard, error) { | |||
| 2391 | 2417 | func (o *Seat) GetTouch() (*Touch, error) { | |
| 2392 | 2418 | child := &Touch{} | |
| 2393 | 2419 | child.SetContext(o.Context()) | |
| 2394 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_seat.get_touch", Child: child}, child); err != nil { | |
| 2420 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wl_seat.get_touch", Child: child}, wl.ArgObject(child)); err != nil { | |
| 2395 | 2421 | return nil, err | |
| 2396 | 2422 | } | |
| 2397 | 2423 | return child, nil | |
| @@ -2399,7 +2425,7 @@ func (o *Seat) GetTouch() (*Touch, error) { | |||
| 2399 | 2425 | ||
| 2400 | 2426 | // Using this request a client can tell the server that it is not going to use the seat object anymore. | |
| 2401 | 2427 | func (o *Seat) Release() error { | |
| 2402 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "wl_seat.release", Since: 5, Destructor: true}); err != nil { | |
| 2428 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "wl_seat.release", Since: 5, Destructor: true}); err != nil { | |
| 2403 | 2429 | return err | |
| 2404 | 2430 | } | |
| 2405 | 2431 | return nil | |
| @@ -2519,7 +2545,7 @@ func (o *Pointer) SetCursor(serial uint32, surface *Surface, hotspotX int32, hot | |||
| 2519 | 2545 | if surface != nil { | |
| 2520 | 2546 | arg1 = surface | |
| 2521 | 2547 | } | |
| 2522 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_pointer.set_cursor"}, serial, arg1, hotspotX, hotspotY); err != nil { | |
| 2548 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wl_pointer.set_cursor"}, wl.ArgUint(serial), wl.ArgObject(arg1), wl.ArgInt(hotspotX), wl.ArgInt(hotspotY)); err != nil { | |
| 2523 | 2549 | return err | |
| 2524 | 2550 | } | |
| 2525 | 2551 | return nil | |
| @@ -2527,7 +2553,7 @@ func (o *Pointer) SetCursor(serial uint32, surface *Surface, hotspotX int32, hot | |||
| 2527 | 2553 | ||
| 2528 | 2554 | // Using this request a client can tell the server that it is not going to use the pointer object anymore. This request destroys the pointer proxy object, so clients must not call wl_pointer_destroy() after using this request. | |
| 2529 | 2555 | func (o *Pointer) Release() error { | |
| 2530 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_pointer.release", Since: 3, Destructor: true}); err != nil { | |
| 2556 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wl_pointer.release", Since: 3, Destructor: true}); err != nil { | |
| 2531 | 2557 | return err | |
| 2532 | 2558 | } | |
| 2533 | 2559 | return nil | |
| @@ -2962,7 +2988,7 @@ func NewKeyboard(ctx *wl.Context) *Keyboard { | |||
| 2962 | 2988 | ||
| 2963 | 2989 | // release the keyboard object | |
| 2964 | 2990 | func (o *Keyboard) Release() error { | |
| 2965 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_keyboard.release", Since: 3, Destructor: true}); err != nil { | |
| 2991 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wl_keyboard.release", Since: 3, Destructor: true}); err != nil { | |
| 2966 | 2992 | return err | |
| 2967 | 2993 | } | |
| 2968 | 2994 | return nil | |
| @@ -3214,7 +3240,7 @@ func NewTouch(ctx *wl.Context) *Touch { | |||
| 3214 | 3240 | ||
| 3215 | 3241 | // release the touch object | |
| 3216 | 3242 | func (o *Touch) Release() error { | |
| 3217 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_touch.release", Since: 3, Destructor: true}); err != nil { | |
| 3243 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wl_touch.release", Since: 3, Destructor: true}); err != nil { | |
| 3218 | 3244 | return err | |
| 3219 | 3245 | } | |
| 3220 | 3246 | return nil | |
| @@ -3490,7 +3516,7 @@ func NewOutput(ctx *wl.Context) *Output { | |||
| 3490 | 3516 | ||
| 3491 | 3517 | // Using this request a client can tell the server that it is not going to use the output object anymore. | |
| 3492 | 3518 | func (o *Output) Release() error { | |
| 3493 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_output.release", Since: 3, Destructor: true}); err != nil { | |
| 3519 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wl_output.release", Since: 3, Destructor: true}); err != nil { | |
| 3494 | 3520 | return err | |
| 3495 | 3521 | } | |
| 3496 | 3522 | return nil | |
| @@ -3724,7 +3750,7 @@ func NewRegion(ctx *wl.Context) *Region { | |||
| 3724 | 3750 | ||
| 3725 | 3751 | // Destroy the region. This will invalidate the object ID. | |
| 3726 | 3752 | func (o *Region) Destroy() error { | |
| 3727 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_region.destroy", Destructor: true}); err != nil { | |
| 3753 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wl_region.destroy", Destructor: true}); err != nil { | |
| 3728 | 3754 | return err | |
| 3729 | 3755 | } | |
| 3730 | 3756 | return nil | |
| @@ -3732,7 +3758,7 @@ func (o *Region) Destroy() error { | |||
| 3732 | 3758 | ||
| 3733 | 3759 | // Add the specified rectangle to the region. | |
| 3734 | 3760 | func (o *Region) Add(x int32, y int32, width int32, height int32) error { | |
| 3735 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_region.add"}, x, y, width, height); err != nil { | |
| 3761 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wl_region.add"}, wl.ArgInt(x), wl.ArgInt(y), wl.ArgInt(width), wl.ArgInt(height)); err != nil { | |
| 3736 | 3762 | return err | |
| 3737 | 3763 | } | |
| 3738 | 3764 | return nil | |
| @@ -3740,7 +3766,7 @@ func (o *Region) Add(x int32, y int32, width int32, height int32) error { | |||
| 3740 | 3766 | ||
| 3741 | 3767 | // Subtract the specified rectangle from the region. | |
| 3742 | 3768 | func (o *Region) Subtract(x int32, y int32, width int32, height int32) error { | |
| 3743 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_region.subtract"}, x, y, width, height); err != nil { | |
| 3769 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wl_region.subtract"}, wl.ArgInt(x), wl.ArgInt(y), wl.ArgInt(width), wl.ArgInt(height)); err != nil { | |
| 3744 | 3770 | return err | |
| 3745 | 3771 | } | |
| 3746 | 3772 | return nil | |
| @@ -3779,7 +3805,7 @@ func NewSubcompositor(ctx *wl.Context) *Subcompositor { | |||
| 3779 | 3805 | ||
| 3780 | 3806 | // Informs the server that the client will not be using this protocol object anymore. This does not affect any other objects, wl_subsurface objects included. | |
| 3781 | 3807 | func (o *Subcompositor) Destroy() error { | |
| 3782 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_subcompositor.destroy", Destructor: true}); err != nil { | |
| 3808 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wl_subcompositor.destroy", Destructor: true}); err != nil { | |
| 3783 | 3809 | return err | |
| 3784 | 3810 | } | |
| 3785 | 3811 | return nil | |
| @@ -3797,7 +3823,7 @@ func (o *Subcompositor) GetSubsurface(surface *Surface, parent *Surface) (*Subsu | |||
| 3797 | 3823 | } | |
| 3798 | 3824 | child := &Subsurface{} | |
| 3799 | 3825 | child.SetContext(o.Context()) | |
| 3800 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_subcompositor.get_subsurface", Child: child}, child, arg1, arg2); err != nil { | |
| 3826 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wl_subcompositor.get_subsurface", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1), wl.ArgObject(arg2)); err != nil { | |
| 3801 | 3827 | return nil, err | |
| 3802 | 3828 | } | |
| 3803 | 3829 | return child, nil | |
| @@ -3836,7 +3862,7 @@ func NewSubsurface(ctx *wl.Context) *Subsurface { | |||
| 3836 | 3862 | ||
| 3837 | 3863 | // The sub-surface interface is removed from the wl_surface object that was turned into a sub-surface with a wl_subcompositor.get_subsurface request. The wl_surface's association to the parent is deleted. The wl_surface is unmapped immediately. | |
| 3838 | 3864 | func (o *Subsurface) Destroy() error { | |
| 3839 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_subsurface.destroy", Destructor: true}); err != nil { | |
| 3865 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wl_subsurface.destroy", Destructor: true}); err != nil { | |
| 3840 | 3866 | return err | |
| 3841 | 3867 | } | |
| 3842 | 3868 | return nil | |
| @@ -3844,7 +3870,7 @@ func (o *Subsurface) Destroy() error { | |||
| 3844 | 3870 | ||
| 3845 | 3871 | // This sets the position of the sub-surface, relative to the parent surface. The sub-surface will be moved so that its origin (top left corner pixel) will be at the location x, y of the parent surface coordinate system. The coordinates are not restricted to the parent surface area. Negative values are allowed. The initial position is 0, 0. Position is double-buffered state on the parent surface, see wl_subsurface and wl_surface.commit for more information. | |
| 3846 | 3872 | func (o *Subsurface) SetPosition(x int32, y int32) error { | |
| 3847 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_subsurface.set_position"}, x, y); err != nil { | |
| 3873 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wl_subsurface.set_position"}, wl.ArgInt(x), wl.ArgInt(y)); err != nil { | |
| 3848 | 3874 | return err | |
| 3849 | 3875 | } | |
| 3850 | 3876 | return nil | |
| @@ -3856,7 +3882,7 @@ func (o *Subsurface) PlaceAbove(sibling *Surface) error { | |||
| 3856 | 3882 | if sibling != nil { | |
| 3857 | 3883 | arg0 = sibling | |
| 3858 | 3884 | } | |
| 3859 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_subsurface.place_above"}, arg0); err != nil { | |
| 3885 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wl_subsurface.place_above"}, wl.ArgObject(arg0)); err != nil { | |
| 3860 | 3886 | return err | |
| 3861 | 3887 | } | |
| 3862 | 3888 | return nil | |
| @@ -3868,7 +3894,7 @@ func (o *Subsurface) PlaceBelow(sibling *Surface) error { | |||
| 3868 | 3894 | if sibling != nil { | |
| 3869 | 3895 | arg0 = sibling | |
| 3870 | 3896 | } | |
| 3871 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "wl_subsurface.place_below"}, arg0); err != nil { | |
| 3897 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "wl_subsurface.place_below"}, wl.ArgObject(arg0)); err != nil { | |
| 3872 | 3898 | return err | |
| 3873 | 3899 | } | |
| 3874 | 3900 | return nil | |
| @@ -3876,7 +3902,7 @@ func (o *Subsurface) PlaceBelow(sibling *Surface) error { | |||
| 3876 | 3902 | ||
| 3877 | 3903 | // Change the commit behaviour of the sub-surface to synchronized mode. See wl_subsurface and wl_surface.commit for more information. | |
| 3878 | 3904 | func (o *Subsurface) SetSync() error { | |
| 3879 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "wl_subsurface.set_sync"}); err != nil { | |
| 3905 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 4, Name: "wl_subsurface.set_sync"}); err != nil { | |
| 3880 | 3906 | return err | |
| 3881 | 3907 | } | |
| 3882 | 3908 | return nil | |
| @@ -3884,7 +3910,7 @@ func (o *Subsurface) SetSync() error { | |||
| 3884 | 3910 | ||
| 3885 | 3911 | // Change the commit behaviour of the sub-surface to desynchronized mode. See wl_subsurface and wl_surface.commit for more information. | |
| 3886 | 3912 | func (o *Subsurface) SetDesync() error { | |
| 3887 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 5, Name: "wl_subsurface.set_desync"}); err != nil { | |
| 3913 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 5, Name: "wl_subsurface.set_desync"}); err != nil { | |
| 3888 | 3914 | return err | |
| 3889 | 3915 | } | |
| 3890 | 3916 | return nil | |
| @@ -3923,7 +3949,7 @@ func NewFixes(ctx *wl.Context) *Fixes { | |||
| 3923 | 3949 | ||
| 3924 | 3950 | // destroys this object | |
| 3925 | 3951 | func (o *Fixes) Destroy() error { | |
| 3926 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_fixes.destroy", Destructor: true}); err != nil { | |
| 3952 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wl_fixes.destroy", Destructor: true}); err != nil { | |
| 3927 | 3953 | return err | |
| 3928 | 3954 | } | |
| 3929 | 3955 | return nil | |
| @@ -3935,7 +3961,7 @@ func (o *Fixes) DestroyRegistry(registry *wl.Registry) error { | |||
| 3935 | 3961 | if registry != nil { | |
| 3936 | 3962 | arg0 = registry | |
| 3937 | 3963 | } | |
| 3938 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_fixes.destroy_registry"}, arg0); err != nil { | |
| 3964 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wl_fixes.destroy_registry"}, wl.ArgObject(arg0)); err != nil { | |
| 3939 | 3965 | return err | |
| 3940 | 3966 | } | |
| 3941 | 3967 | return nil | |
| @@ -3947,7 +3973,7 @@ func (o *Fixes) AckGlobalRemove(registry *wl.Registry, name uint32) error { | |||
| 3947 | 3973 | if registry != nil { | |
| 3948 | 3974 | arg0 = registry | |
| 3949 | 3975 | } | |
| 3950 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_fixes.ack_global_remove", Since: 2}, arg0, name); err != nil { | |
| 3976 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wl_fixes.ack_global_remove", Since: 2}, wl.ArgObject(arg0), wl.ArgUint(name)); err != nil { | |
| 3951 | 3977 | return err | |
| 3952 | 3978 | } | |
| 3953 | 3979 | return nil | |
M protocol/cursorshape/cursor-shape-v1_generated.go +26 -5
| @@ -2,6 +2,27 @@ | |||
| 2 | 2 | // Protocol: cursor_shape_v1 | |
| 3 | 3 | // Source: cursor-shape-v1.xml | |
| 4 | 4 | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright 2018 The Chromium Authors | |
| 7 | + | // Copyright 2023 Simon Ser | |
| 8 | + | // | |
| 9 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 10 | + | // copy of this software and associated documentation files (the "Software"), | |
| 11 | + | // to deal in the Software without restriction, including without limitation | |
| 12 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 13 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 14 | + | // Software is furnished to do so, subject to the following conditions: | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 21 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 23 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 24 | + | // DEALINGS IN THE SOFTWARE. | |
| 25 | + | ||
| 5 | 26 | package cursorshape | |
| 6 | 27 | ||
| 7 | 28 | import ( | |
| @@ -139,7 +160,7 @@ func NewWpCursorShapeManager(ctx *wl.Context) *WpCursorShapeManager { | |||
| 139 | 160 | ||
| 140 | 161 | // Destroy the cursor shape manager. | |
| 141 | 162 | func (o *WpCursorShapeManager) Destroy() error { | |
| 142 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_cursor_shape_manager_v1.destroy", Destructor: true}); err != nil { | |
| 163 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_cursor_shape_manager_v1.destroy", Destructor: true}); err != nil { | |
| 143 | 164 | return err | |
| 144 | 165 | } | |
| 145 | 166 | return nil | |
| @@ -153,7 +174,7 @@ func (o *WpCursorShapeManager) GetPointer(pointer *cross_wl_pointer.Pointer) (*W | |||
| 153 | 174 | } | |
| 154 | 175 | child := &WpCursorShapeDevice{} | |
| 155 | 176 | child.SetContext(o.Context()) | |
| 156 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wp_cursor_shape_manager_v1.get_pointer", Child: child}, child, arg1); err != nil { | |
| 177 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_cursor_shape_manager_v1.get_pointer", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 157 | 178 | return nil, err | |
| 158 | 179 | } | |
| 159 | 180 | return child, nil | |
| @@ -167,7 +188,7 @@ func (o *WpCursorShapeManager) GetTabletTool(tabletTool *cross_zwp_tablet_tool_v | |||
| 167 | 188 | } | |
| 168 | 189 | child := &WpCursorShapeDevice{} | |
| 169 | 190 | child.SetContext(o.Context()) | |
| 170 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wp_cursor_shape_manager_v1.get_tablet_tool_v2", Child: child}, child, arg1); err != nil { | |
| 191 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wp_cursor_shape_manager_v1.get_tablet_tool_v2", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 171 | 192 | return nil, err | |
| 172 | 193 | } | |
| 173 | 194 | return child, nil | |
| @@ -206,7 +227,7 @@ func NewWpCursorShapeDevice(ctx *wl.Context) *WpCursorShapeDevice { | |||
| 206 | 227 | ||
| 207 | 228 | // Destroy the cursor shape device. The device cursor shape remains unchanged. | |
| 208 | 229 | func (o *WpCursorShapeDevice) Destroy() error { | |
| 209 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_cursor_shape_device_v1.destroy", Destructor: true}); err != nil { | |
| 230 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_cursor_shape_device_v1.destroy", Destructor: true}); err != nil { | |
| 210 | 231 | return err | |
| 211 | 232 | } | |
| 212 | 233 | return nil | |
| @@ -214,7 +235,7 @@ func (o *WpCursorShapeDevice) Destroy() error { | |||
| 214 | 235 | ||
| 215 | 236 | // Sets the device cursor to the specified shape. The compositor will change the cursor image based on the specified shape. The cursor actually changes only if the input device focus is one of the requesting client's surfaces. If any, the previous cursor image (surface or shape) is replaced. The "shape" argument must be a valid enum entry, otherwise the invalid_shape protocol error is raised. This is similar to the wl_pointer.set_cursor and zwp_tablet_tool_v2.set_cursor requests, but this request accepts a shape instead of contents in the form of a surface. Clients can mix set_cursor and set_shape requests. The serial parameter must match the latest wl_pointer.enter or zwp_tablet_tool_v2.proximity_in serial number sent to the client. Otherwise the request will be ignored. | |
| 216 | 237 | func (o *WpCursorShapeDevice) SetShape(serial uint32, shape uint32) error { | |
| 217 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wp_cursor_shape_device_v1.set_shape"}, serial, shape); err != nil { | |
| 238 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_cursor_shape_device_v1.set_shape"}, wl.ArgUint(serial), wl.ArgUint(shape)); err != nil { | |
| 218 | 239 | return err | |
| 219 | 240 | } | |
| 220 | 241 | return nil | |
A protocol/datacontrol/ext-data-control-v1.xml +276 -0
| @@ -0,0 +1,276 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="ext_data_control_v1"> | |
| 3 | + | <copyright> | |
| 4 | + | Copyright © 2018 Simon Ser | |
| 5 | + | Copyright © 2019 Ivan Molodetskikh | |
| 6 | + | Copyright © 2024 Neal Gompa | |
| 7 | + | ||
| 8 | + | Permission to use, copy, modify, distribute, and sell this | |
| 9 | + | software and its documentation for any purpose is hereby granted | |
| 10 | + | without fee, provided that the above copyright notice appear in | |
| 11 | + | all copies and that both that copyright notice and this permission | |
| 12 | + | notice appear in supporting documentation, and that the name of | |
| 13 | + | the copyright holders not be used in advertising or publicity | |
| 14 | + | pertaining to distribution of the software without specific, | |
| 15 | + | written prior permission. The copyright holders make no | |
| 16 | + | representations about the suitability of this software for any | |
| 17 | + | purpose. It is provided "as is" without express or implied | |
| 18 | + | warranty. | |
| 19 | + | ||
| 20 | + | THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
| 21 | + | SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| 22 | + | FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| 23 | + | SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 24 | + | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
| 25 | + | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
| 26 | + | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| 27 | + | THIS SOFTWARE. | |
| 28 | + | </copyright> | |
| 29 | + | ||
| 30 | + | <description summary="control data devices"> | |
| 31 | + | This protocol allows a privileged client to control data devices. In | |
| 32 | + | particular, the client will be able to manage the current selection and take | |
| 33 | + | the role of a clipboard manager. | |
| 34 | + | ||
| 35 | + | Warning! The protocol described in this file is currently in the testing | |
| 36 | + | phase. Backward compatible changes may be added together with the | |
| 37 | + | corresponding interface version bump. Backward incompatible changes can | |
| 38 | + | only be done by creating a new major version of the extension. | |
| 39 | + | </description> | |
| 40 | + | ||
| 41 | + | <interface name="ext_data_control_manager_v1" version="1"> | |
| 42 | + | <description summary="manager to control data devices"> | |
| 43 | + | This interface is a manager that allows creating per-seat data device | |
| 44 | + | controls. | |
| 45 | + | </description> | |
| 46 | + | ||
| 47 | + | <request name="create_data_source"> | |
| 48 | + | <description summary="create a new data source"> | |
| 49 | + | Create a new data source. | |
| 50 | + | </description> | |
| 51 | + | <arg name="id" type="new_id" interface="ext_data_control_source_v1" | |
| 52 | + | summary="data source to create"/> | |
| 53 | + | </request> | |
| 54 | + | ||
| 55 | + | <request name="get_data_device"> | |
| 56 | + | <description summary="get a data device for a seat"> | |
| 57 | + | Create a data device that can be used to manage a seat's selection. | |
| 58 | + | </description> | |
| 59 | + | <arg name="id" type="new_id" interface="ext_data_control_device_v1"/> | |
| 60 | + | <arg name="seat" type="object" interface="wl_seat"/> | |
| 61 | + | </request> | |
| 62 | + | ||
| 63 | + | <request name="destroy" type="destructor"> | |
| 64 | + | <description summary="destroy the manager"> | |
| 65 | + | All objects created by the manager will still remain valid, until their | |
| 66 | + | appropriate destroy request has been called. | |
| 67 | + | </description> | |
| 68 | + | </request> | |
| 69 | + | </interface> | |
| 70 | + | ||
| 71 | + | <interface name="ext_data_control_device_v1" version="1"> | |
| 72 | + | <description summary="manage a data device for a seat"> | |
| 73 | + | This interface allows a client to manage a seat's selection. | |
| 74 | + | ||
| 75 | + | When the seat is destroyed, this object becomes inert. | |
| 76 | + | </description> | |
| 77 | + | ||
| 78 | + | <request name="set_selection"> | |
| 79 | + | <description summary="copy data to the selection"> | |
| 80 | + | This request asks the compositor to set the selection to the data from | |
| 81 | + | the source on behalf of the client. | |
| 82 | + | ||
| 83 | + | The given source may not be used in any further set_selection or | |
| 84 | + | set_primary_selection requests. Attempting to use a previously used | |
| 85 | + | source triggers the used_source protocol error. | |
| 86 | + | ||
| 87 | + | To unset the selection, set the source to NULL. | |
| 88 | + | </description> | |
| 89 | + | <arg name="source" type="object" interface="ext_data_control_source_v1" | |
| 90 | + | allow-null="true"/> | |
| 91 | + | </request> | |
| 92 | + | ||
| 93 | + | <request name="destroy" type="destructor"> | |
| 94 | + | <description summary="destroy this data device"> | |
| 95 | + | Destroys the data device object. | |
| 96 | + | </description> | |
| 97 | + | </request> | |
| 98 | + | ||
| 99 | + | <event name="data_offer"> | |
| 100 | + | <description summary="introduce a new ext_data_control_offer"> | |
| 101 | + | The data_offer event introduces a new ext_data_control_offer object, | |
| 102 | + | which will subsequently be used in either the | |
| 103 | + | ext_data_control_device.selection event (for the regular clipboard | |
| 104 | + | selections) or the ext_data_control_device.primary_selection event (for | |
| 105 | + | the primary clipboard selections). Immediately following the | |
| 106 | + | ext_data_control_device.data_offer event, the new data_offer object | |
| 107 | + | will send out ext_data_control_offer.offer events to describe the MIME | |
| 108 | + | types it offers. | |
| 109 | + | </description> | |
| 110 | + | <arg name="id" type="new_id" interface="ext_data_control_offer_v1"/> | |
| 111 | + | </event> | |
| 112 | + | ||
| 113 | + | <event name="selection"> | |
| 114 | + | <description summary="advertise new selection"> | |
| 115 | + | The selection event is sent out to notify the client of a new | |
| 116 | + | ext_data_control_offer for the selection for this device. The | |
| 117 | + | ext_data_control_device.data_offer and the ext_data_control_offer.offer | |
| 118 | + | events are sent out immediately before this event to introduce the data | |
| 119 | + | offer object. The selection event is sent to a client when a new | |
| 120 | + | selection is set. The ext_data_control_offer is valid until a new | |
| 121 | + | ext_data_control_offer or NULL is received. The client must destroy the | |
| 122 | + | previous selection ext_data_control_offer, if any, upon receiving this | |
| 123 | + | event. Regardless, the previous selection will be ignored once a new | |
| 124 | + | selection ext_data_control_offer is received. | |
| 125 | + | ||
| 126 | + | The first selection event is sent upon binding the | |
| 127 | + | ext_data_control_device object. | |
| 128 | + | </description> | |
| 129 | + | <arg name="id" type="object" interface="ext_data_control_offer_v1" | |
| 130 | + | allow-null="true"/> | |
| 131 | + | </event> | |
| 132 | + | ||
| 133 | + | <event name="finished"> | |
| 134 | + | <description summary="this data control is no longer valid"> | |
| 135 | + | This data control object is no longer valid and should be destroyed by | |
| 136 | + | the client. | |
| 137 | + | </description> | |
| 138 | + | </event> | |
| 139 | + | ||
| 140 | + | <event name="primary_selection"> | |
| 141 | + | <description summary="advertise new primary selection"> | |
| 142 | + | The primary_selection event is sent out to notify the client of a new | |
| 143 | + | ext_data_control_offer for the primary selection for this device. The | |
| 144 | + | ext_data_control_device.data_offer and the ext_data_control_offer.offer | |
| 145 | + | events are sent out immediately before this event to introduce the data | |
| 146 | + | offer object. The primary_selection event is sent to a client when a | |
| 147 | + | new primary selection is set. The ext_data_control_offer is valid until | |
| 148 | + | a new ext_data_control_offer or NULL is received. The client must | |
| 149 | + | destroy the previous primary selection ext_data_control_offer, if any, | |
| 150 | + | upon receiving this event. Regardless, the previous primary selection | |
| 151 | + | will be ignored once a new primary selection ext_data_control_offer is | |
| 152 | + | received. | |
| 153 | + | ||
| 154 | + | If the compositor supports primary selection, the first | |
| 155 | + | primary_selection event is sent upon binding the | |
| 156 | + | ext_data_control_device object. | |
| 157 | + | </description> | |
| 158 | + | <arg name="id" type="object" interface="ext_data_control_offer_v1" | |
| 159 | + | allow-null="true"/> | |
| 160 | + | </event> | |
| 161 | + | ||
| 162 | + | <request name="set_primary_selection"> | |
| 163 | + | <description summary="copy data to the primary selection"> | |
| 164 | + | This request asks the compositor to set the primary selection to the | |
| 165 | + | data from the source on behalf of the client. | |
| 166 | + | ||
| 167 | + | The given source may not be used in any further set_selection or | |
| 168 | + | set_primary_selection requests. Attempting to use a previously used | |
| 169 | + | source triggers the used_source protocol error. | |
| 170 | + | ||
| 171 | + | To unset the primary selection, set the source to NULL. | |
| 172 | + | ||
| 173 | + | The compositor will ignore this request if it does not support primary | |
| 174 | + | selection. | |
| 175 | + | </description> | |
| 176 | + | <arg name="source" type="object" interface="ext_data_control_source_v1" | |
| 177 | + | allow-null="true"/> | |
| 178 | + | </request> | |
| 179 | + | ||
| 180 | + | <enum name="error"> | |
| 181 | + | <entry name="used_source" value="1" | |
| 182 | + | summary="source given to set_selection or set_primary_selection was already used before"/> | |
| 183 | + | </enum> | |
| 184 | + | </interface> | |
| 185 | + | ||
| 186 | + | <interface name="ext_data_control_source_v1" version="1"> | |
| 187 | + | <description summary="offer to transfer data"> | |
| 188 | + | The ext_data_control_source object is the source side of a | |
| 189 | + | ext_data_control_offer. It is created by the source client in a data | |
| 190 | + | transfer and provides a way to describe the offered data and a way to | |
| 191 | + | respond to requests to transfer the data. | |
| 192 | + | </description> | |
| 193 | + | ||
| 194 | + | <enum name="error"> | |
| 195 | + | <entry name="invalid_offer" value="1" | |
| 196 | + | summary="offer sent after ext_data_control_device.set_selection"/> | |
| 197 | + | </enum> | |
| 198 | + | ||
| 199 | + | <request name="offer"> | |
| 200 | + | <description summary="add an offered MIME type"> | |
| 201 | + | This request adds a MIME type to the set of MIME types advertised to | |
| 202 | + | targets. Can be called several times to offer multiple types. | |
| 203 | + | ||
| 204 | + | Calling this after ext_data_control_device.set_selection is a protocol | |
| 205 | + | error. | |
| 206 | + | </description> | |
| 207 | + | <arg name="mime_type" type="string" | |
| 208 | + | summary="MIME type offered by the data source"/> | |
| 209 | + | </request> | |
| 210 | + | ||
| 211 | + | <request name="destroy" type="destructor"> | |
| 212 | + | <description summary="destroy this source"> | |
| 213 | + | Destroys the data source object. | |
| 214 | + | </description> | |
| 215 | + | </request> | |
| 216 | + | ||
| 217 | + | <event name="send"> | |
| 218 | + | <description summary="send the data"> | |
| 219 | + | Request for data from the client. Send the data as the specified MIME | |
| 220 | + | type over the passed file descriptor, then close it. | |
| 221 | + | </description> | |
| 222 | + | <arg name="mime_type" type="string" summary="MIME type for the data"/> | |
| 223 | + | <arg name="fd" type="fd" summary="file descriptor for the data"/> | |
| 224 | + | </event> | |
| 225 | + | ||
| 226 | + | <event name="cancelled"> | |
| 227 | + | <description summary="selection was cancelled"> | |
| 228 | + | This data source is no longer valid. The data source has been replaced | |
| 229 | + | by another data source. | |
| 230 | + | ||
| 231 | + | The client should clean up and destroy this data source. | |
| 232 | + | </description> | |
| 233 | + | </event> | |
| 234 | + | </interface> | |
| 235 | + | ||
| 236 | + | <interface name="ext_data_control_offer_v1" version="1"> | |
| 237 | + | <description summary="offer to transfer data"> | |
| 238 | + | A ext_data_control_offer represents a piece of data offered for transfer | |
| 239 | + | by another client (the source client). The offer describes the different | |
| 240 | + | MIME types that the data can be converted to and provides the mechanism | |
| 241 | + | for transferring the data directly from the source client. | |
| 242 | + | </description> | |
| 243 | + | ||
| 244 | + | <request name="receive"> | |
| 245 | + | <description summary="request that the data is transferred"> | |
| 246 | + | To transfer the offered data, the client issues this request and | |
| 247 | + | indicates the MIME type it wants to receive. The transfer happens | |
| 248 | + | through the passed file descriptor (typically created with the pipe | |
| 249 | + | system call). The source client writes the data in the MIME type | |
| 250 | + | representation requested and then closes the file descriptor. | |
| 251 | + | ||
| 252 | + | The receiving client reads from the read end of the pipe until EOF and | |
| 253 | + | then closes its end, at which point the transfer is complete. | |
| 254 | + | ||
| 255 | + | This request may happen multiple times for different MIME types. | |
| 256 | + | </description> | |
| 257 | + | <arg name="mime_type" type="string" | |
| 258 | + | summary="MIME type desired by receiver"/> | |
| 259 | + | <arg name="fd" type="fd" summary="file descriptor for data transfer"/> | |
| 260 | + | </request> | |
| 261 | + | ||
| 262 | + | <request name="destroy" type="destructor"> | |
| 263 | + | <description summary="destroy this offer"> | |
| 264 | + | Destroys the data offer object. | |
| 265 | + | </description> | |
| 266 | + | </request> | |
| 267 | + | ||
| 268 | + | <event name="offer"> | |
| 269 | + | <description summary="advertise offered MIME type"> | |
| 270 | + | Sent immediately after creating the ext_data_control_offer object. | |
| 271 | + | One event per offered MIME type. | |
| 272 | + | </description> | |
| 273 | + | <arg name="mime_type" type="string" summary="offered MIME type"/> | |
| 274 | + | </event> | |
| 275 | + | </interface> | |
| 276 | + | </protocol> | |
A protocol/datacontrol/ext-data-control-v1_generated.go +505 -0
| @@ -0,0 +1,505 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: ext_data_control_v1 | |
| 3 | + | // Source: ext-data-control-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2018 Simon Ser | |
| 7 | + | // Copyright © 2019 Ivan Molodetskikh | |
| 8 | + | // Copyright © 2024 Neal Gompa | |
| 9 | + | // | |
| 10 | + | // Permission to use, copy, modify, distribute, and sell this | |
| 11 | + | // software and its documentation for any purpose is hereby granted | |
| 12 | + | // without fee, provided that the above copyright notice appear in | |
| 13 | + | // all copies and that both that copyright notice and this permission | |
| 14 | + | // notice appear in supporting documentation, and that the name of | |
| 15 | + | // the copyright holders not be used in advertising or publicity | |
| 16 | + | // pertaining to distribution of the software without specific, | |
| 17 | + | // written prior permission. The copyright holders make no | |
| 18 | + | // representations about the suitability of this software for any | |
| 19 | + | // purpose. It is provided "as is" without express or implied | |
| 20 | + | // warranty. | |
| 21 | + | // | |
| 22 | + | // THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
| 23 | + | // SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| 24 | + | // FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| 25 | + | // SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 26 | + | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
| 27 | + | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
| 28 | + | // ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| 29 | + | // THIS SOFTWARE. | |
| 30 | + | ||
| 31 | + | package datacontrol | |
| 32 | + | ||
| 33 | + | import ( | |
| 34 | + | "sync" | |
| 35 | + | ||
| 36 | + | cross_wl_seat "github.com/bnema/wlturbo/protocol/core" | |
| 37 | + | "github.com/bnema/wlturbo/wl" | |
| 38 | + | ) | |
| 39 | + | ||
| 40 | + | // ERROR_USED_SOURCE is the error used_source value. | |
| 41 | + | const ERROR_USED_SOURCE = 1 | |
| 42 | + | ||
| 43 | + | // ERROR_INVALID_OFFER is the error invalid_offer value. | |
| 44 | + | const ERROR_INVALID_OFFER = 1 | |
| 45 | + | ||
| 46 | + | // ExtDataControlManagerInterface is the protocol interface name. | |
| 47 | + | const ExtDataControlManagerInterface = "ext_data_control_manager_v1" | |
| 48 | + | ||
| 49 | + | // ExtDataControlManager is the generated binding for ext_data_control_manager_v1 version 1. | |
| 50 | + | type ExtDataControlManager struct { | |
| 51 | + | wl.BaseProxy | |
| 52 | + | } | |
| 53 | + | ||
| 54 | + | // NewExtDataControlManager returns an unbound ExtDataControlManager. | |
| 55 | + | func NewExtDataControlManager(ctx *wl.Context) *ExtDataControlManager { | |
| 56 | + | obj := &ExtDataControlManager{} | |
| 57 | + | obj.SetContext(ctx) | |
| 58 | + | ctx.Register(obj) | |
| 59 | + | return obj | |
| 60 | + | } | |
| 61 | + | ||
| 62 | + | // Create a new data source. | |
| 63 | + | func (o *ExtDataControlManager) CreateDataSource() (*ExtDataControlSource, error) { | |
| 64 | + | child := &ExtDataControlSource{} | |
| 65 | + | child.SetContext(o.Context()) | |
| 66 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_data_control_manager_v1.create_data_source", Child: child}, wl.ArgObject(child)); err != nil { | |
| 67 | + | return nil, err | |
| 68 | + | } | |
| 69 | + | return child, nil | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | // Create a data device that can be used to manage a seat's selection. | |
| 73 | + | func (o *ExtDataControlManager) GetDataDevice(seat *cross_wl_seat.Seat) (*ExtDataControlDevice, error) { | |
| 74 | + | var arg1 wl.Object | |
| 75 | + | if seat != nil { | |
| 76 | + | arg1 = seat | |
| 77 | + | } | |
| 78 | + | child := &ExtDataControlDevice{} | |
| 79 | + | child.SetContext(o.Context()) | |
| 80 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_data_control_manager_v1.get_data_device", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 81 | + | return nil, err | |
| 82 | + | } | |
| 83 | + | return child, nil | |
| 84 | + | } | |
| 85 | + | ||
| 86 | + | // All objects created by the manager will still remain valid, until their appropriate destroy request has been called. | |
| 87 | + | func (o *ExtDataControlManager) Destroy() error { | |
| 88 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "ext_data_control_manager_v1.destroy", Destructor: true}); err != nil { | |
| 89 | + | return err | |
| 90 | + | } | |
| 91 | + | return nil | |
| 92 | + | } | |
| 93 | + | ||
| 94 | + | // EventSignature returns the declared event argument types in wire order. | |
| 95 | + | func (o *ExtDataControlManager) EventSignature(opcode uint16) (string, bool) { | |
| 96 | + | switch opcode { | |
| 97 | + | default: | |
| 98 | + | return "", false | |
| 99 | + | } | |
| 100 | + | } | |
| 101 | + | ||
| 102 | + | // Dispatch decodes one event on ext_data_control_manager_v1 and calls the registered handlers. | |
| 103 | + | func (o *ExtDataControlManager) Dispatch(event *wl.Event) { | |
| 104 | + | switch event.Opcode { | |
| 105 | + | default: | |
| 106 | + | } | |
| 107 | + | } | |
| 108 | + | ||
| 109 | + | // ExtDataControlDeviceInterface is the protocol interface name. | |
| 110 | + | const ExtDataControlDeviceInterface = "ext_data_control_device_v1" | |
| 111 | + | ||
| 112 | + | // ExtDataControlDevice is the generated binding for ext_data_control_device_v1 version 1. | |
| 113 | + | type ExtDataControlDevice struct { | |
| 114 | + | wl.BaseProxy | |
| 115 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 116 | + | // handlers while another goroutine dispatches events. | |
| 117 | + | handlersMu sync.Mutex | |
| 118 | + | onDataOffer []func(idObject *ExtDataControlOffer) | |
| 119 | + | onSelection []func(idID uint32) | |
| 120 | + | onFinished []func() | |
| 121 | + | onPrimarySelection []func(idID uint32) | |
| 122 | + | } | |
| 123 | + | ||
| 124 | + | // NewExtDataControlDevice returns an unbound ExtDataControlDevice. | |
| 125 | + | func NewExtDataControlDevice(ctx *wl.Context) *ExtDataControlDevice { | |
| 126 | + | obj := &ExtDataControlDevice{} | |
| 127 | + | obj.SetContext(ctx) | |
| 128 | + | ctx.Register(obj) | |
| 129 | + | return obj | |
| 130 | + | } | |
| 131 | + | ||
| 132 | + | // This request asks the compositor to set the selection to the data from the source on behalf of the client. The given source may not be used in any further set_selection or set_primary_selection requests. Attempting to use a previously used source triggers the used_source protocol error. To unset the selection, set the source to NULL. | |
| 133 | + | func (o *ExtDataControlDevice) SetSelection(source *ExtDataControlSource) error { | |
| 134 | + | var arg0 wl.Object | |
| 135 | + | if source != nil { | |
| 136 | + | arg0 = source | |
| 137 | + | } | |
| 138 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_data_control_device_v1.set_selection"}, wl.ArgObject(arg0)); err != nil { | |
| 139 | + | return err | |
| 140 | + | } | |
| 141 | + | return nil | |
| 142 | + | } | |
| 143 | + | ||
| 144 | + | // Destroys the data device object. | |
| 145 | + | func (o *ExtDataControlDevice) Destroy() error { | |
| 146 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_data_control_device_v1.destroy", Destructor: true}); err != nil { | |
| 147 | + | return err | |
| 148 | + | } | |
| 149 | + | return nil | |
| 150 | + | } | |
| 151 | + | ||
| 152 | + | // This request asks the compositor to set the primary selection to the data from the source on behalf of the client. The given source may not be used in any further set_selection or set_primary_selection requests. Attempting to use a previously used source triggers the used_source protocol error. To unset the primary selection, set the source to NULL. The compositor will ignore this request if it does not support primary selection. | |
| 153 | + | func (o *ExtDataControlDevice) SetPrimarySelection(source *ExtDataControlSource) error { | |
| 154 | + | var arg0 wl.Object | |
| 155 | + | if source != nil { | |
| 156 | + | arg0 = source | |
| 157 | + | } | |
| 158 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "ext_data_control_device_v1.set_primary_selection"}, wl.ArgObject(arg0)); err != nil { | |
| 159 | + | return err | |
| 160 | + | } | |
| 161 | + | return nil | |
| 162 | + | } | |
| 163 | + | ||
| 164 | + | // OnDataOffer registers a handler for the data_offer event. | |
| 165 | + | // | |
| 166 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 167 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 168 | + | func (o *ExtDataControlDevice) OnDataOffer(handler func(idObject *ExtDataControlOffer)) { | |
| 169 | + | if handler == nil { | |
| 170 | + | return | |
| 171 | + | } | |
| 172 | + | o.handlersMu.Lock() | |
| 173 | + | defer o.handlersMu.Unlock() | |
| 174 | + | o.onDataOffer = append(o.onDataOffer, handler) | |
| 175 | + | } | |
| 176 | + | ||
| 177 | + | // handlersForDataOffer returns the handlers registered for data_offer, taken | |
| 178 | + | // under the lock so a handler may register another handler while events are | |
| 179 | + | // being dispatched. | |
| 180 | + | func (o *ExtDataControlDevice) handlersForDataOffer() []func(idObject *ExtDataControlOffer) { | |
| 181 | + | o.handlersMu.Lock() | |
| 182 | + | defer o.handlersMu.Unlock() | |
| 183 | + | return o.onDataOffer | |
| 184 | + | } | |
| 185 | + | ||
| 186 | + | // OnSelection registers a handler for the selection event. | |
| 187 | + | // | |
| 188 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 189 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 190 | + | func (o *ExtDataControlDevice) OnSelection(handler func(idID uint32)) { | |
| 191 | + | if handler == nil { | |
| 192 | + | return | |
| 193 | + | } | |
| 194 | + | o.handlersMu.Lock() | |
| 195 | + | defer o.handlersMu.Unlock() | |
| 196 | + | o.onSelection = append(o.onSelection, handler) | |
| 197 | + | } | |
| 198 | + | ||
| 199 | + | // handlersForSelection returns the handlers registered for selection, taken | |
| 200 | + | // under the lock so a handler may register another handler while events are | |
| 201 | + | // being dispatched. | |
| 202 | + | func (o *ExtDataControlDevice) handlersForSelection() []func(idID uint32) { | |
| 203 | + | o.handlersMu.Lock() | |
| 204 | + | defer o.handlersMu.Unlock() | |
| 205 | + | return o.onSelection | |
| 206 | + | } | |
| 207 | + | ||
| 208 | + | // OnFinished registers a handler for the finished event. | |
| 209 | + | // | |
| 210 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 211 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 212 | + | func (o *ExtDataControlDevice) OnFinished(handler func()) { | |
| 213 | + | if handler == nil { | |
| 214 | + | return | |
| 215 | + | } | |
| 216 | + | o.handlersMu.Lock() | |
| 217 | + | defer o.handlersMu.Unlock() | |
| 218 | + | o.onFinished = append(o.onFinished, handler) | |
| 219 | + | } | |
| 220 | + | ||
| 221 | + | // handlersForFinished returns the handlers registered for finished, taken | |
| 222 | + | // under the lock so a handler may register another handler while events are | |
| 223 | + | // being dispatched. | |
| 224 | + | func (o *ExtDataControlDevice) handlersForFinished() []func() { | |
| 225 | + | o.handlersMu.Lock() | |
| 226 | + | defer o.handlersMu.Unlock() | |
| 227 | + | return o.onFinished | |
| 228 | + | } | |
| 229 | + | ||
| 230 | + | // OnPrimarySelection registers a handler for the primary_selection event. | |
| 231 | + | // | |
| 232 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 233 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 234 | + | func (o *ExtDataControlDevice) OnPrimarySelection(handler func(idID uint32)) { | |
| 235 | + | if handler == nil { | |
| 236 | + | return | |
| 237 | + | } | |
| 238 | + | o.handlersMu.Lock() | |
| 239 | + | defer o.handlersMu.Unlock() | |
| 240 | + | o.onPrimarySelection = append(o.onPrimarySelection, handler) | |
| 241 | + | } | |
| 242 | + | ||
| 243 | + | // handlersForPrimarySelection returns the handlers registered for primary_selection, taken | |
| 244 | + | // under the lock so a handler may register another handler while events are | |
| 245 | + | // being dispatched. | |
| 246 | + | func (o *ExtDataControlDevice) handlersForPrimarySelection() []func(idID uint32) { | |
| 247 | + | o.handlersMu.Lock() | |
| 248 | + | defer o.handlersMu.Unlock() | |
| 249 | + | return o.onPrimarySelection | |
| 250 | + | } | |
| 251 | + | ||
| 252 | + | // EventSignature returns the declared event argument types in wire order. | |
| 253 | + | func (o *ExtDataControlDevice) EventSignature(opcode uint16) (string, bool) { | |
| 254 | + | switch opcode { | |
| 255 | + | case 0: | |
| 256 | + | return "new_id,", true | |
| 257 | + | case 1: | |
| 258 | + | return "object,", true | |
| 259 | + | case 2: | |
| 260 | + | return "", true | |
| 261 | + | case 3: | |
| 262 | + | return "object,", true | |
| 263 | + | default: | |
| 264 | + | return "", false | |
| 265 | + | } | |
| 266 | + | } | |
| 267 | + | ||
| 268 | + | // Dispatch decodes one event on ext_data_control_device_v1 and calls the registered handlers. | |
| 269 | + | func (o *ExtDataControlDevice) Dispatch(event *wl.Event) { | |
| 270 | + | switch event.Opcode { | |
| 271 | + | case 0: // data_offer | |
| 272 | + | idID := event.Uint32() | |
| 273 | + | idObject := &ExtDataControlOffer{} | |
| 274 | + | idObject.SetContext(o.Context()) | |
| 275 | + | idObject.SetID(idID) | |
| 276 | + | idObject.SetVersion(o.Version()) | |
| 277 | + | o.Context().Register(idObject) | |
| 278 | + | ||
| 279 | + | for i, handler := range o.handlersForDataOffer() { | |
| 280 | + | _ = i | |
| 281 | + | handler(idObject) | |
| 282 | + | } | |
| 283 | + | case 1: // selection | |
| 284 | + | idID := event.Uint32() | |
| 285 | + | ||
| 286 | + | for i, handler := range o.handlersForSelection() { | |
| 287 | + | _ = i | |
| 288 | + | handler(idID) | |
| 289 | + | } | |
| 290 | + | case 2: // finished | |
| 291 | + | ||
| 292 | + | for i, handler := range o.handlersForFinished() { | |
| 293 | + | _ = i | |
| 294 | + | handler() | |
| 295 | + | } | |
| 296 | + | case 3: // primary_selection | |
| 297 | + | idID := event.Uint32() | |
| 298 | + | ||
| 299 | + | for i, handler := range o.handlersForPrimarySelection() { | |
| 300 | + | _ = i | |
| 301 | + | handler(idID) | |
| 302 | + | } | |
| 303 | + | default: | |
| 304 | + | } | |
| 305 | + | } | |
| 306 | + | ||
| 307 | + | // ExtDataControlSourceInterface is the protocol interface name. | |
| 308 | + | const ExtDataControlSourceInterface = "ext_data_control_source_v1" | |
| 309 | + | ||
| 310 | + | // ExtDataControlSource is the generated binding for ext_data_control_source_v1 version 1. | |
| 311 | + | type ExtDataControlSource struct { | |
| 312 | + | wl.BaseProxy | |
| 313 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 314 | + | // handlers while another goroutine dispatches events. | |
| 315 | + | handlersMu sync.Mutex | |
| 316 | + | onSend []func(mimeType string, fd *wl.OwnedFD) | |
| 317 | + | onCancelled []func() | |
| 318 | + | } | |
| 319 | + | ||
| 320 | + | // NewExtDataControlSource returns an unbound ExtDataControlSource. | |
| 321 | + | func NewExtDataControlSource(ctx *wl.Context) *ExtDataControlSource { | |
| 322 | + | obj := &ExtDataControlSource{} | |
| 323 | + | obj.SetContext(ctx) | |
| 324 | + | ctx.Register(obj) | |
| 325 | + | return obj | |
| 326 | + | } | |
| 327 | + | ||
| 328 | + | // This request adds a MIME type to the set of MIME types advertised to targets. Can be called several times to offer multiple types. Calling this after ext_data_control_device.set_selection is a protocol error. | |
| 329 | + | func (o *ExtDataControlSource) Offer(mimeType string) error { | |
| 330 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_data_control_source_v1.offer"}, wl.ArgString(mimeType)); err != nil { | |
| 331 | + | return err | |
| 332 | + | } | |
| 333 | + | return nil | |
| 334 | + | } | |
| 335 | + | ||
| 336 | + | // Destroys the data source object. | |
| 337 | + | func (o *ExtDataControlSource) Destroy() error { | |
| 338 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_data_control_source_v1.destroy", Destructor: true}); err != nil { | |
| 339 | + | return err | |
| 340 | + | } | |
| 341 | + | return nil | |
| 342 | + | } | |
| 343 | + | ||
| 344 | + | // OnSend registers a handler for the send event. | |
| 345 | + | // | |
| 346 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 347 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 348 | + | func (o *ExtDataControlSource) OnSend(handler func(mimeType string, fd *wl.OwnedFD)) { | |
| 349 | + | if handler == nil { | |
| 350 | + | return | |
| 351 | + | } | |
| 352 | + | o.handlersMu.Lock() | |
| 353 | + | defer o.handlersMu.Unlock() | |
| 354 | + | o.onSend = append(o.onSend, handler) | |
| 355 | + | } | |
| 356 | + | ||
| 357 | + | // handlersForSend returns the handlers registered for send, taken | |
| 358 | + | // under the lock so a handler may register another handler while events are | |
| 359 | + | // being dispatched. | |
| 360 | + | func (o *ExtDataControlSource) handlersForSend() []func(mimeType string, fd *wl.OwnedFD) { | |
| 361 | + | o.handlersMu.Lock() | |
| 362 | + | defer o.handlersMu.Unlock() | |
| 363 | + | return o.onSend | |
| 364 | + | } | |
| 365 | + | ||
| 366 | + | // OnCancelled registers a handler for the cancelled event. | |
| 367 | + | // | |
| 368 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 369 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 370 | + | func (o *ExtDataControlSource) OnCancelled(handler func()) { | |
| 371 | + | if handler == nil { | |
| 372 | + | return | |
| 373 | + | } | |
| 374 | + | o.handlersMu.Lock() | |
| 375 | + | defer o.handlersMu.Unlock() | |
| 376 | + | o.onCancelled = append(o.onCancelled, handler) | |
| 377 | + | } | |
| 378 | + | ||
| 379 | + | // handlersForCancelled returns the handlers registered for cancelled, taken | |
| 380 | + | // under the lock so a handler may register another handler while events are | |
| 381 | + | // being dispatched. | |
| 382 | + | func (o *ExtDataControlSource) handlersForCancelled() []func() { | |
| 383 | + | o.handlersMu.Lock() | |
| 384 | + | defer o.handlersMu.Unlock() | |
| 385 | + | return o.onCancelled | |
| 386 | + | } | |
| 387 | + | ||
| 388 | + | // EventSignature returns the declared event argument types in wire order. | |
| 389 | + | func (o *ExtDataControlSource) EventSignature(opcode uint16) (string, bool) { | |
| 390 | + | switch opcode { | |
| 391 | + | case 0: | |
| 392 | + | return "string,fd,", true | |
| 393 | + | case 1: | |
| 394 | + | return "", true | |
| 395 | + | default: | |
| 396 | + | return "", false | |
| 397 | + | } | |
| 398 | + | } | |
| 399 | + | ||
| 400 | + | // Dispatch decodes one event on ext_data_control_source_v1 and calls the registered handlers. | |
| 401 | + | func (o *ExtDataControlSource) Dispatch(event *wl.Event) { | |
| 402 | + | switch event.Opcode { | |
| 403 | + | case 0: // send | |
| 404 | + | mimeType := event.String() | |
| 405 | + | fd := event.FD() | |
| 406 | + | ownedfd := fd | |
| 407 | + | defer ownedfd.Close() | |
| 408 | + | ||
| 409 | + | for i, handler := range o.handlersForSend() { | |
| 410 | + | if i > 0 { | |
| 411 | + | fd = nil | |
| 412 | + | } | |
| 413 | + | handler(mimeType, fd) | |
| 414 | + | } | |
| 415 | + | case 1: // cancelled | |
| 416 | + | ||
| 417 | + | for i, handler := range o.handlersForCancelled() { | |
| 418 | + | _ = i | |
| 419 | + | handler() | |
| 420 | + | } | |
| 421 | + | default: | |
| 422 | + | } | |
| 423 | + | } | |
| 424 | + | ||
| 425 | + | // ExtDataControlOfferInterface is the protocol interface name. | |
| 426 | + | const ExtDataControlOfferInterface = "ext_data_control_offer_v1" | |
| 427 | + | ||
| 428 | + | // ExtDataControlOffer is the generated binding for ext_data_control_offer_v1 version 1. | |
| 429 | + | type ExtDataControlOffer struct { | |
| 430 | + | wl.BaseProxy | |
| 431 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 432 | + | // handlers while another goroutine dispatches events. | |
| 433 | + | handlersMu sync.Mutex | |
| 434 | + | onOffer []func(mimeType string) | |
| 435 | + | } | |
| 436 | + | ||
| 437 | + | // NewExtDataControlOffer returns an unbound ExtDataControlOffer. | |
| 438 | + | func NewExtDataControlOffer(ctx *wl.Context) *ExtDataControlOffer { | |
| 439 | + | obj := &ExtDataControlOffer{} | |
| 440 | + | obj.SetContext(ctx) | |
| 441 | + | ctx.Register(obj) | |
| 442 | + | return obj | |
| 443 | + | } | |
| 444 | + | ||
| 445 | + | // To transfer the offered data, the client issues this request and indicates the MIME type it wants to receive. The transfer happens through the passed file descriptor (typically created with the pipe system call). The source client writes the data in the MIME type representation requested and then closes the file descriptor. The receiving client reads from the read end of the pipe until EOF and then closes its end, at which point the transfer is complete. This request may happen multiple times for different MIME types. | |
| 446 | + | func (o *ExtDataControlOffer) Receive(mimeType string, fd int) error { | |
| 447 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_data_control_offer_v1.receive", FDs: []int{fd}}, wl.ArgString(mimeType), wl.ArgFD()); err != nil { | |
| 448 | + | return err | |
| 449 | + | } | |
| 450 | + | return nil | |
| 451 | + | } | |
| 452 | + | ||
| 453 | + | // Destroys the data offer object. | |
| 454 | + | func (o *ExtDataControlOffer) Destroy() error { | |
| 455 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_data_control_offer_v1.destroy", Destructor: true}); err != nil { | |
| 456 | + | return err | |
| 457 | + | } | |
| 458 | + | return nil | |
| 459 | + | } | |
| 460 | + | ||
| 461 | + | // OnOffer registers a handler for the offer event. | |
| 462 | + | // | |
| 463 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 464 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 465 | + | func (o *ExtDataControlOffer) OnOffer(handler func(mimeType string)) { | |
| 466 | + | if handler == nil { | |
| 467 | + | return | |
| 468 | + | } | |
| 469 | + | o.handlersMu.Lock() | |
| 470 | + | defer o.handlersMu.Unlock() | |
| 471 | + | o.onOffer = append(o.onOffer, handler) | |
| 472 | + | } | |
| 473 | + | ||
| 474 | + | // handlersForOffer returns the handlers registered for offer, taken | |
| 475 | + | // under the lock so a handler may register another handler while events are | |
| 476 | + | // being dispatched. | |
| 477 | + | func (o *ExtDataControlOffer) handlersForOffer() []func(mimeType string) { | |
| 478 | + | o.handlersMu.Lock() | |
| 479 | + | defer o.handlersMu.Unlock() | |
| 480 | + | return o.onOffer | |
| 481 | + | } | |
| 482 | + | ||
| 483 | + | // EventSignature returns the declared event argument types in wire order. | |
| 484 | + | func (o *ExtDataControlOffer) EventSignature(opcode uint16) (string, bool) { | |
| 485 | + | switch opcode { | |
| 486 | + | case 0: | |
| 487 | + | return "string,", true | |
| 488 | + | default: | |
| 489 | + | return "", false | |
| 490 | + | } | |
| 491 | + | } | |
| 492 | + | ||
| 493 | + | // Dispatch decodes one event on ext_data_control_offer_v1 and calls the registered handlers. | |
| 494 | + | func (o *ExtDataControlOffer) Dispatch(event *wl.Event) { | |
| 495 | + | switch event.Opcode { | |
| 496 | + | case 0: // offer | |
| 497 | + | mimeType := event.String() | |
| 498 | + | ||
| 499 | + | for i, handler := range o.handlersForOffer() { | |
| 500 | + | _ = i | |
| 501 | + | handler(mimeType) | |
| 502 | + | } | |
| 503 | + | default: | |
| 504 | + | } | |
| 505 | + | } | |
A protocol/datacontrol/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package datacontrol | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p datacontrol -o ext-data-control-v1_generated.go -import wl_seat=github.com/bnema/wlturbo/protocol/core ext-data-control-v1.xml | |
A protocol/drmlease/drm-lease-v1.xml +317 -0
| @@ -0,0 +1,317 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="drm_lease_v1"> | |
| 3 | + | <copyright> | |
| 4 | + | Copyright © 2018 NXP | |
| 5 | + | Copyright © 2019 Status Research & Development GmbH. | |
| 6 | + | Copyright © 2021 Xaver Hugl | |
| 7 | + | ||
| 8 | + | Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | copy of this software and associated documentation files (the "Software"), | |
| 10 | + | to deal in the Software without restriction, including without limitation | |
| 11 | + | the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | Software is furnished to do so, subject to the following conditions: | |
| 14 | + | ||
| 15 | + | The above copyright notice and this permission notice (including the next | |
| 16 | + | paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | Software. | |
| 18 | + | ||
| 19 | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | DEALINGS IN THE SOFTWARE. | |
| 26 | + | </copyright> | |
| 27 | + | ||
| 28 | + | <interface name="wp_drm_lease_device_v1" version="1"> | |
| 29 | + | <description summary="lease device"> | |
| 30 | + | This protocol is used by Wayland compositors which act as Direct | |
| 31 | + | Rendering Manager (DRM) masters to lease DRM resources to Wayland | |
| 32 | + | clients. | |
| 33 | + | ||
| 34 | + | The compositor will advertise one wp_drm_lease_device_v1 global for each | |
| 35 | + | DRM node. Some time after a client binds to the wp_drm_lease_device_v1 | |
| 36 | + | global, the compositor will send a drm_fd event followed by zero, one or | |
| 37 | + | more connector events. After all currently available connectors have been | |
| 38 | + | sent, the compositor will send a wp_drm_lease_device_v1.done event. | |
| 39 | + | ||
| 40 | + | When the list of connectors available for lease changes the compositor | |
| 41 | + | will send wp_drm_lease_device_v1.connector events for added connectors and | |
| 42 | + | wp_drm_lease_connector_v1.withdrawn events for removed connectors, | |
| 43 | + | followed by a wp_drm_lease_device_v1.done event. | |
| 44 | + | ||
| 45 | + | The compositor will indicate when a device is gone by removing the global | |
| 46 | + | via a wl_registry.global_remove event. Upon receiving this event, the | |
| 47 | + | client should destroy any matching wp_drm_lease_device_v1 object. | |
| 48 | + | ||
| 49 | + | To destroy a wp_drm_lease_device_v1 object, the client must first issue | |
| 50 | + | a release request. Upon receiving this request, the compositor will | |
| 51 | + | immediately send a released event and destroy the object. The client must | |
| 52 | + | continue to process and discard drm_fd and connector events until it | |
| 53 | + | receives the released event. Upon receiving the released event, the | |
| 54 | + | client can safely cleanup any client-side resources. | |
| 55 | + | ||
| 56 | + | Warning! The protocol described in this file is currently in the testing | |
| 57 | + | phase. Backward compatible changes may be added together with the | |
| 58 | + | corresponding interface version bump. Backward incompatible changes can | |
| 59 | + | only be done by creating a new major version of the extension. | |
| 60 | + | </description> | |
| 61 | + | ||
| 62 | + | <request name="create_lease_request"> | |
| 63 | + | <description summary="create a lease request object"> | |
| 64 | + | Creates a lease request object. | |
| 65 | + | ||
| 66 | + | See the documentation for wp_drm_lease_request_v1 for details. | |
| 67 | + | </description> | |
| 68 | + | <arg name="id" type="new_id" interface="wp_drm_lease_request_v1" /> | |
| 69 | + | </request> | |
| 70 | + | ||
| 71 | + | <request name="release"> | |
| 72 | + | <description summary="release this object"> | |
| 73 | + | Indicates the client no longer wishes to use this object. In response | |
| 74 | + | the compositor will immediately send the released event and destroy | |
| 75 | + | this object. It can however not guarantee that the client won't receive | |
| 76 | + | connector events before the released event. The client must not send any | |
| 77 | + | requests after this one, doing so will raise a wl_display error. | |
| 78 | + | Existing connectors, lease request and leases will not be affected. | |
| 79 | + | </description> | |
| 80 | + | </request> | |
| 81 | + | ||
| 82 | + | <event name="drm_fd"> | |
| 83 | + | <description summary="open a non-master fd for this DRM node"> | |
| 84 | + | The compositor will send this event when the wp_drm_lease_device_v1 | |
| 85 | + | global is bound, although there are no guarantees as to how long this | |
| 86 | + | takes - the compositor might need to wait until regaining DRM master. | |
| 87 | + | The included fd is a non-master DRM file descriptor opened for this | |
| 88 | + | device and the compositor must not authenticate it. | |
| 89 | + | The purpose of this event is to give the client the ability to | |
| 90 | + | query DRM and discover information which may help them pick the | |
| 91 | + | appropriate DRM device or select the appropriate connectors therein. | |
| 92 | + | </description> | |
| 93 | + | <arg name="fd" type="fd" summary="DRM file descriptor" /> | |
| 94 | + | </event> | |
| 95 | + | ||
| 96 | + | <event name="connector"> | |
| 97 | + | <description summary="advertise connectors available for leases"> | |
| 98 | + | The compositor will use this event to advertise connectors available for | |
| 99 | + | lease by clients. This object may be passed into a lease request to | |
| 100 | + | indicate the client would like to lease that connector, see | |
| 101 | + | wp_drm_lease_request_v1.request_connector for details. While the | |
| 102 | + | compositor will make a best effort to not send disconnected connectors, | |
| 103 | + | no guarantees can be made. | |
| 104 | + | ||
| 105 | + | The compositor must send the drm_fd event before sending connectors. | |
| 106 | + | After the drm_fd event it will send all available connectors but may | |
| 107 | + | send additional connectors at any time. | |
| 108 | + | </description> | |
| 109 | + | <arg name="id" type="new_id" interface="wp_drm_lease_connector_v1" /> | |
| 110 | + | </event> | |
| 111 | + | ||
| 112 | + | <event name="done"> | |
| 113 | + | <description summary="signals grouping of connectors"> | |
| 114 | + | The compositor will send this event to indicate that it has sent all | |
| 115 | + | currently available connectors after the client binds to the global or | |
| 116 | + | when it updates the connector list, for example on hotplug, drm master | |
| 117 | + | change or when a leased connector becomes available again. It will | |
| 118 | + | similarly send this event to group wp_drm_lease_connector_v1.withdrawn | |
| 119 | + | events of connectors of this device. | |
| 120 | + | </description> | |
| 121 | + | </event> | |
| 122 | + | ||
| 123 | + | <event name="released" type="destructor"> | |
| 124 | + | <description summary="the compositor has finished using the device"> | |
| 125 | + | This event is sent in response to the release request and indicates | |
| 126 | + | that the compositor is done sending connector events. | |
| 127 | + | The compositor will destroy this object immediately after sending the | |
| 128 | + | event and it will become invalid. The client should release any | |
| 129 | + | resources associated with this device after receiving this event. | |
| 130 | + | </description> | |
| 131 | + | </event> | |
| 132 | + | </interface> | |
| 133 | + | ||
| 134 | + | <interface name="wp_drm_lease_connector_v1" version="1"> | |
| 135 | + | <description summary="a leasable DRM connector"> | |
| 136 | + | Represents a DRM connector which is available for lease. These objects are | |
| 137 | + | created via wp_drm_lease_device_v1.connector events, and should be passed | |
| 138 | + | to lease requests via wp_drm_lease_request_v1.request_connector. | |
| 139 | + | Immediately after the wp_drm_lease_connector_v1 object is created the | |
| 140 | + | compositor will send a name, a description, a connector_id and a done | |
| 141 | + | event. When the description is updated the compositor will send a | |
| 142 | + | description event followed by a done event. | |
| 143 | + | </description> | |
| 144 | + | ||
| 145 | + | <event name="name"> | |
| 146 | + | <description summary="name"> | |
| 147 | + | The compositor sends this event once the connector is created to | |
| 148 | + | indicate the name of this connector. This will not change for the | |
| 149 | + | duration of the Wayland session, but is not guaranteed to be consistent | |
| 150 | + | between sessions. | |
| 151 | + | ||
| 152 | + | If the compositor supports wl_output version 4 and this connector | |
| 153 | + | corresponds to a wl_output, the compositor should use the same name as | |
| 154 | + | for the wl_output. | |
| 155 | + | </description> | |
| 156 | + | <arg name="name" type="string" summary="connector name" /> | |
| 157 | + | </event> | |
| 158 | + | ||
| 159 | + | <event name="description"> | |
| 160 | + | <description summary="description"> | |
| 161 | + | The compositor sends this event once the connector is created to provide | |
| 162 | + | a human-readable description for this connector, which may be presented | |
| 163 | + | to the user. The compositor may send this event multiple times over the | |
| 164 | + | lifetime of this object to reflect changes in the description. | |
| 165 | + | </description> | |
| 166 | + | <arg name="description" type="string" summary="connector description" /> | |
| 167 | + | </event> | |
| 168 | + | ||
| 169 | + | <event name="connector_id"> | |
| 170 | + | <description summary="connector_id"> | |
| 171 | + | The compositor sends this event once the connector is created to | |
| 172 | + | indicate the DRM object ID which represents the underlying connector | |
| 173 | + | that is being offered. Note that the final lease may include additional | |
| 174 | + | object IDs, such as CRTCs and planes. | |
| 175 | + | </description> | |
| 176 | + | <arg name="connector_id" type="uint" summary="DRM connector ID" /> | |
| 177 | + | </event> | |
| 178 | + | ||
| 179 | + | <event name="done"> | |
| 180 | + | <description summary="all properties have been sent"> | |
| 181 | + | This event is sent after all properties of a connector have been sent. | |
| 182 | + | This allows changes to the properties to be seen as atomic even if they | |
| 183 | + | happen via multiple events. | |
| 184 | + | </description> | |
| 185 | + | </event> | |
| 186 | + | ||
| 187 | + | <event name="withdrawn"> | |
| 188 | + | <description summary="lease offer withdrawn"> | |
| 189 | + | Sent to indicate that the compositor will no longer honor requests for | |
| 190 | + | DRM leases which include this connector. The client may still issue a | |
| 191 | + | lease request including this connector, but the compositor will send | |
| 192 | + | wp_drm_lease_v1.finished without issuing a lease fd. Compositors are | |
| 193 | + | encouraged to send this event when they lose access to connector, for | |
| 194 | + | example when the connector is hot-unplugged, when the connector gets | |
| 195 | + | leased to a client or when the compositor loses DRM master. | |
| 196 | + | ||
| 197 | + | If a client holds a lease for the connector, the status of the lease | |
| 198 | + | remains the same. The client should destroy the object after receiving | |
| 199 | + | this event. | |
| 200 | + | </description> | |
| 201 | + | </event> | |
| 202 | + | ||
| 203 | + | <request name="destroy" type="destructor"> | |
| 204 | + | <description summary="destroy connector"> | |
| 205 | + | The client may send this request to indicate that it will not use this | |
| 206 | + | connector. Clients are encouraged to send this after receiving the | |
| 207 | + | "withdrawn" event so that the server can release the resources | |
| 208 | + | associated with this connector offer. Neither existing lease requests | |
| 209 | + | nor leases will be affected. | |
| 210 | + | </description> | |
| 211 | + | </request> | |
| 212 | + | </interface> | |
| 213 | + | ||
| 214 | + | <interface name="wp_drm_lease_request_v1" version="1"> | |
| 215 | + | <description summary="DRM lease request"> | |
| 216 | + | A client that wishes to lease DRM resources will attach the list of | |
| 217 | + | connectors advertised with wp_drm_lease_device_v1.connector that they | |
| 218 | + | wish to lease, then use wp_drm_lease_request_v1.submit to submit the | |
| 219 | + | request. | |
| 220 | + | </description> | |
| 221 | + | ||
| 222 | + | <enum name="error"> | |
| 223 | + | <entry name="wrong_device" value="0" | |
| 224 | + | summary="requested a connector from a different lease device"/> | |
| 225 | + | <entry name="duplicate_connector" value="1" | |
| 226 | + | summary="requested a connector twice"/> | |
| 227 | + | <entry name="empty_lease" value="2" | |
| 228 | + | summary="requested a lease without requesting a connector"/> | |
| 229 | + | </enum> | |
| 230 | + | ||
| 231 | + | <request name="request_connector"> | |
| 232 | + | <description summary="request a connector for this lease"> | |
| 233 | + | Indicates that the client would like to lease the given connector. | |
| 234 | + | This is only used as a suggestion, the compositor may choose to | |
| 235 | + | include any resources in the lease it issues, or change the set of | |
| 236 | + | leased resources at any time. Compositors are however encouraged to | |
| 237 | + | include the requested connector and other resources necessary | |
| 238 | + | to drive the connected output in the lease. | |
| 239 | + | ||
| 240 | + | Requesting a connector that was created from a different lease device | |
| 241 | + | than this lease request raises the wrong_device error. Requesting a | |
| 242 | + | connector twice will raise the duplicate_connector error. | |
| 243 | + | </description> | |
| 244 | + | <arg name="connector" type="object" | |
| 245 | + | interface="wp_drm_lease_connector_v1" /> | |
| 246 | + | </request> | |
| 247 | + | ||
| 248 | + | <request name="submit" type="destructor"> | |
| 249 | + | <description summary="submit the lease request"> | |
| 250 | + | Submits the lease request and creates a new wp_drm_lease_v1 object. | |
| 251 | + | After calling submit the compositor will immediately destroy this | |
| 252 | + | object, issuing any more requests will cause a wl_display error. | |
| 253 | + | The compositor doesn't make any guarantees about the events of the | |
| 254 | + | lease object, clients cannot expect an immediate response. | |
| 255 | + | Not requesting any connectors before submitting the lease request | |
| 256 | + | will raise the empty_lease error. | |
| 257 | + | </description> | |
| 258 | + | <arg name="id" type="new_id" interface="wp_drm_lease_v1" /> | |
| 259 | + | </request> | |
| 260 | + | </interface> | |
| 261 | + | ||
| 262 | + | <interface name="wp_drm_lease_v1" version="1"> | |
| 263 | + | <description summary="a DRM lease"> | |
| 264 | + | A DRM lease object is used to transfer the DRM file descriptor to the | |
| 265 | + | client and manage the lifetime of the lease. | |
| 266 | + | ||
| 267 | + | Some time after the wp_drm_lease_v1 object is created, the compositor | |
| 268 | + | will reply with the lease request's result. If the lease request is | |
| 269 | + | granted, the compositor will send a lease_fd event. If the lease request | |
| 270 | + | is denied, the compositor will send a finished event without a lease_fd | |
| 271 | + | event. | |
| 272 | + | </description> | |
| 273 | + | ||
| 274 | + | <event name="lease_fd"> | |
| 275 | + | <description summary="shares the DRM file descriptor"> | |
| 276 | + | This event returns a file descriptor suitable for use with DRM-related | |
| 277 | + | ioctls. The client should use drmModeGetLease to enumerate the DRM | |
| 278 | + | objects which have been leased to them. The compositor guarantees it | |
| 279 | + | will not use the leased DRM objects itself until it sends the finished | |
| 280 | + | event. If the compositor cannot or will not grant a lease for the | |
| 281 | + | requested connectors, it will not send this event, instead sending the | |
| 282 | + | finished event. | |
| 283 | + | ||
| 284 | + | The compositor will send this event at most once during this objects | |
| 285 | + | lifetime. | |
| 286 | + | </description> | |
| 287 | + | <arg name="leased_fd" type="fd" summary="leased DRM file descriptor" /> | |
| 288 | + | </event> | |
| 289 | + | ||
| 290 | + | <event name="finished"> | |
| 291 | + | <description summary="sent when the lease has been revoked"> | |
| 292 | + | The compositor uses this event to either reject a lease request, or if | |
| 293 | + | it previously sent a lease_fd, to notify the client that the lease has | |
| 294 | + | been revoked. If the client requires a new lease, they should destroy | |
| 295 | + | this object and submit a new lease request. The compositor will send | |
| 296 | + | no further events for this object after sending the finish event. | |
| 297 | + | Compositors should revoke the lease when any of the leased resources | |
| 298 | + | become unavailable, namely when a hot-unplug occurs or when the | |
| 299 | + | compositor loses DRM master. Compositors may advertise the connector | |
| 300 | + | for leasing again, if the resource is available, by sending the | |
| 301 | + | connector event through the wp_drm_lease_device_v1 interface. | |
| 302 | + | </description> | |
| 303 | + | </event> | |
| 304 | + | ||
| 305 | + | <request name="destroy" type="destructor"> | |
| 306 | + | <description summary="destroys the lease object"> | |
| 307 | + | The client should send this to indicate that it no longer wishes to use | |
| 308 | + | this lease. The compositor should use drmModeRevokeLease on the | |
| 309 | + | appropriate file descriptor, if necessary. | |
| 310 | + | ||
| 311 | + | Upon destruction, the compositor should advertise the connector for | |
| 312 | + | leasing again by sending the connector event through the | |
| 313 | + | wp_drm_lease_device_v1 interface. | |
| 314 | + | </description> | |
| 315 | + | </request> | |
| 316 | + | </interface> | |
| 317 | + | </protocol> | |
A protocol/drmlease/drm-lease-v1_generated.go +594 -0
| @@ -0,0 +1,594 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: drm_lease_v1 | |
| 3 | + | // Source: drm-lease-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2018 NXP | |
| 7 | + | // Copyright © 2019 Status Research & Development GmbH. | |
| 8 | + | // Copyright © 2021 Xaver Hugl | |
| 9 | + | // | |
| 10 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 11 | + | // copy of this software and associated documentation files (the "Software"), | |
| 12 | + | // to deal in the Software without restriction, including without limitation | |
| 13 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 14 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 15 | + | // Software is furnished to do so, subject to the following conditions: | |
| 16 | + | // | |
| 17 | + | // The above copyright notice and this permission notice (including the next | |
| 18 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 19 | + | // Software. | |
| 20 | + | // | |
| 21 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 22 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 23 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 24 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 25 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 26 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 27 | + | // DEALINGS IN THE SOFTWARE. | |
| 28 | + | ||
| 29 | + | package drmlease | |
| 30 | + | ||
| 31 | + | import ( | |
| 32 | + | "sync" | |
| 33 | + | ||
| 34 | + | "github.com/bnema/wlturbo/wl" | |
| 35 | + | ) | |
| 36 | + | ||
| 37 | + | // ERROR_WRONG_DEVICE is the error wrong_device value. | |
| 38 | + | const ERROR_WRONG_DEVICE = 0 | |
| 39 | + | ||
| 40 | + | // ERROR_DUPLICATE_CONNECTOR is the error duplicate_connector value. | |
| 41 | + | const ERROR_DUPLICATE_CONNECTOR = 1 | |
| 42 | + | ||
| 43 | + | // ERROR_EMPTY_LEASE is the error empty_lease value. | |
| 44 | + | const ERROR_EMPTY_LEASE = 2 | |
| 45 | + | ||
| 46 | + | // WpDrmLeaseDeviceInterface is the protocol interface name. | |
| 47 | + | const WpDrmLeaseDeviceInterface = "wp_drm_lease_device_v1" | |
| 48 | + | ||
| 49 | + | // WpDrmLeaseDevice is the generated binding for wp_drm_lease_device_v1 version 1. | |
| 50 | + | type WpDrmLeaseDevice struct { | |
| 51 | + | wl.BaseProxy | |
| 52 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 53 | + | // handlers while another goroutine dispatches events. | |
| 54 | + | handlersMu sync.Mutex | |
| 55 | + | onDrmFd []func(fd *wl.OwnedFD) | |
| 56 | + | onConnector []func(idObject *WpDrmLeaseConnector) | |
| 57 | + | onDone []func() | |
| 58 | + | onReleased []func() | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | // NewWpDrmLeaseDevice returns an unbound WpDrmLeaseDevice. | |
| 62 | + | func NewWpDrmLeaseDevice(ctx *wl.Context) *WpDrmLeaseDevice { | |
| 63 | + | obj := &WpDrmLeaseDevice{} | |
| 64 | + | obj.SetContext(ctx) | |
| 65 | + | ctx.Register(obj) | |
| 66 | + | return obj | |
| 67 | + | } | |
| 68 | + | ||
| 69 | + | // Creates a lease request object. See the documentation for wp_drm_lease_request_v1 for details. | |
| 70 | + | func (o *WpDrmLeaseDevice) CreateLeaseRequest() (*WpDrmLeaseRequest, error) { | |
| 71 | + | child := &WpDrmLeaseRequest{} | |
| 72 | + | child.SetContext(o.Context()) | |
| 73 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_drm_lease_device_v1.create_lease_request", Child: child}, wl.ArgObject(child)); err != nil { | |
| 74 | + | return nil, err | |
| 75 | + | } | |
| 76 | + | return child, nil | |
| 77 | + | } | |
| 78 | + | ||
| 79 | + | // Indicates the client no longer wishes to use this object. In response the compositor will immediately send the released event and destroy this object. It can however not guarantee that the client won't receive connector events before the released event. The client must not send any requests after this one, doing so will raise a wl_display error. Existing connectors, lease request and leases will not be affected. | |
| 80 | + | func (o *WpDrmLeaseDevice) Release() error { | |
| 81 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_drm_lease_device_v1.release"}); err != nil { | |
| 82 | + | return err | |
| 83 | + | } | |
| 84 | + | return nil | |
| 85 | + | } | |
| 86 | + | ||
| 87 | + | // OnDrmFd registers a handler for the drm_fd event. | |
| 88 | + | // | |
| 89 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 90 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 91 | + | func (o *WpDrmLeaseDevice) OnDrmFd(handler func(fd *wl.OwnedFD)) { | |
| 92 | + | if handler == nil { | |
| 93 | + | return | |
| 94 | + | } | |
| 95 | + | o.handlersMu.Lock() | |
| 96 | + | defer o.handlersMu.Unlock() | |
| 97 | + | o.onDrmFd = append(o.onDrmFd, handler) | |
| 98 | + | } | |
| 99 | + | ||
| 100 | + | // handlersForDrmFd returns the handlers registered for drm_fd, taken | |
| 101 | + | // under the lock so a handler may register another handler while events are | |
| 102 | + | // being dispatched. | |
| 103 | + | func (o *WpDrmLeaseDevice) handlersForDrmFd() []func(fd *wl.OwnedFD) { | |
| 104 | + | o.handlersMu.Lock() | |
| 105 | + | defer o.handlersMu.Unlock() | |
| 106 | + | return o.onDrmFd | |
| 107 | + | } | |
| 108 | + | ||
| 109 | + | // OnConnector registers a handler for the connector event. | |
| 110 | + | // | |
| 111 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 112 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 113 | + | func (o *WpDrmLeaseDevice) OnConnector(handler func(idObject *WpDrmLeaseConnector)) { | |
| 114 | + | if handler == nil { | |
| 115 | + | return | |
| 116 | + | } | |
| 117 | + | o.handlersMu.Lock() | |
| 118 | + | defer o.handlersMu.Unlock() | |
| 119 | + | o.onConnector = append(o.onConnector, handler) | |
| 120 | + | } | |
| 121 | + | ||
| 122 | + | // handlersForConnector returns the handlers registered for connector, taken | |
| 123 | + | // under the lock so a handler may register another handler while events are | |
| 124 | + | // being dispatched. | |
| 125 | + | func (o *WpDrmLeaseDevice) handlersForConnector() []func(idObject *WpDrmLeaseConnector) { | |
| 126 | + | o.handlersMu.Lock() | |
| 127 | + | defer o.handlersMu.Unlock() | |
| 128 | + | return o.onConnector | |
| 129 | + | } | |
| 130 | + | ||
| 131 | + | // OnDone registers a handler for the done event. | |
| 132 | + | // | |
| 133 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 134 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 135 | + | func (o *WpDrmLeaseDevice) OnDone(handler func()) { | |
| 136 | + | if handler == nil { | |
| 137 | + | return | |
| 138 | + | } | |
| 139 | + | o.handlersMu.Lock() | |
| 140 | + | defer o.handlersMu.Unlock() | |
| 141 | + | o.onDone = append(o.onDone, handler) | |
| 142 | + | } | |
| 143 | + | ||
| 144 | + | // handlersForDone returns the handlers registered for done, taken | |
| 145 | + | // under the lock so a handler may register another handler while events are | |
| 146 | + | // being dispatched. | |
| 147 | + | func (o *WpDrmLeaseDevice) handlersForDone() []func() { | |
| 148 | + | o.handlersMu.Lock() | |
| 149 | + | defer o.handlersMu.Unlock() | |
| 150 | + | return o.onDone | |
| 151 | + | } | |
| 152 | + | ||
| 153 | + | // OnReleased registers a handler for the released event. | |
| 154 | + | // | |
| 155 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 156 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 157 | + | func (o *WpDrmLeaseDevice) OnReleased(handler func()) { | |
| 158 | + | if handler == nil { | |
| 159 | + | return | |
| 160 | + | } | |
| 161 | + | o.handlersMu.Lock() | |
| 162 | + | defer o.handlersMu.Unlock() | |
| 163 | + | o.onReleased = append(o.onReleased, handler) | |
| 164 | + | } | |
| 165 | + | ||
| 166 | + | // handlersForReleased returns the handlers registered for released, taken | |
| 167 | + | // under the lock so a handler may register another handler while events are | |
| 168 | + | // being dispatched. | |
| 169 | + | func (o *WpDrmLeaseDevice) handlersForReleased() []func() { | |
| 170 | + | o.handlersMu.Lock() | |
| 171 | + | defer o.handlersMu.Unlock() | |
| 172 | + | return o.onReleased | |
| 173 | + | } | |
| 174 | + | ||
| 175 | + | // EventSignature returns the declared event argument types in wire order. | |
| 176 | + | func (o *WpDrmLeaseDevice) EventSignature(opcode uint16) (string, bool) { | |
| 177 | + | switch opcode { | |
| 178 | + | case 0: | |
| 179 | + | return "fd,", true | |
| 180 | + | case 1: | |
| 181 | + | return "new_id,", true | |
| 182 | + | case 2: | |
| 183 | + | return "", true | |
| 184 | + | case 3: | |
| 185 | + | return "", true | |
| 186 | + | default: | |
| 187 | + | return "", false | |
| 188 | + | } | |
| 189 | + | } | |
| 190 | + | ||
| 191 | + | // Dispatch decodes one event on wp_drm_lease_device_v1 and calls the registered handlers. | |
| 192 | + | func (o *WpDrmLeaseDevice) Dispatch(event *wl.Event) { | |
| 193 | + | switch event.Opcode { | |
| 194 | + | case 0: // drm_fd | |
| 195 | + | fd := event.FD() | |
| 196 | + | ownedfd := fd | |
| 197 | + | defer ownedfd.Close() | |
| 198 | + | ||
| 199 | + | for i, handler := range o.handlersForDrmFd() { | |
| 200 | + | if i > 0 { | |
| 201 | + | fd = nil | |
| 202 | + | } | |
| 203 | + | handler(fd) | |
| 204 | + | } | |
| 205 | + | case 1: // connector | |
| 206 | + | idID := event.Uint32() | |
| 207 | + | idObject := &WpDrmLeaseConnector{} | |
| 208 | + | idObject.SetContext(o.Context()) | |
| 209 | + | idObject.SetID(idID) | |
| 210 | + | idObject.SetVersion(o.Version()) | |
| 211 | + | o.Context().Register(idObject) | |
| 212 | + | ||
| 213 | + | for i, handler := range o.handlersForConnector() { | |
| 214 | + | _ = i | |
| 215 | + | handler(idObject) | |
| 216 | + | } | |
| 217 | + | case 2: // done | |
| 218 | + | ||
| 219 | + | for i, handler := range o.handlersForDone() { | |
| 220 | + | _ = i | |
| 221 | + | handler() | |
| 222 | + | } | |
| 223 | + | case 3: // released | |
| 224 | + | ||
| 225 | + | for i, handler := range o.handlersForReleased() { | |
| 226 | + | _ = i | |
| 227 | + | handler() | |
| 228 | + | } | |
| 229 | + | o.Context().Unregister(o) | |
| 230 | + | default: | |
| 231 | + | } | |
| 232 | + | } | |
| 233 | + | ||
| 234 | + | // WpDrmLeaseConnectorInterface is the protocol interface name. | |
| 235 | + | const WpDrmLeaseConnectorInterface = "wp_drm_lease_connector_v1" | |
| 236 | + | ||
| 237 | + | // WpDrmLeaseConnector is the generated binding for wp_drm_lease_connector_v1 version 1. | |
| 238 | + | type WpDrmLeaseConnector struct { | |
| 239 | + | wl.BaseProxy | |
| 240 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 241 | + | // handlers while another goroutine dispatches events. | |
| 242 | + | handlersMu sync.Mutex | |
| 243 | + | onName []func(name string) | |
| 244 | + | onDescription []func(description string) | |
| 245 | + | onConnectorId []func(connectorId uint32) | |
| 246 | + | onDone []func() | |
| 247 | + | onWithdrawn []func() | |
| 248 | + | } | |
| 249 | + | ||
| 250 | + | // NewWpDrmLeaseConnector returns an unbound WpDrmLeaseConnector. | |
| 251 | + | func NewWpDrmLeaseConnector(ctx *wl.Context) *WpDrmLeaseConnector { | |
| 252 | + | obj := &WpDrmLeaseConnector{} | |
| 253 | + | obj.SetContext(ctx) | |
| 254 | + | ctx.Register(obj) | |
| 255 | + | return obj | |
| 256 | + | } | |
| 257 | + | ||
| 258 | + | // The client may send this request to indicate that it will not use this connector. Clients are encouraged to send this after receiving the "withdrawn" event so that the server can release the resources associated with this connector offer. Neither existing lease requests nor leases will be affected. | |
| 259 | + | func (o *WpDrmLeaseConnector) Destroy() error { | |
| 260 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_drm_lease_connector_v1.destroy", Destructor: true}); err != nil { | |
| 261 | + | return err | |
| 262 | + | } | |
| 263 | + | return nil | |
| 264 | + | } | |
| 265 | + | ||
| 266 | + | // OnName registers a handler for the name event. | |
| 267 | + | // | |
| 268 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 269 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 270 | + | func (o *WpDrmLeaseConnector) OnName(handler func(name string)) { | |
| 271 | + | if handler == nil { | |
| 272 | + | return | |
| 273 | + | } | |
| 274 | + | o.handlersMu.Lock() | |
| 275 | + | defer o.handlersMu.Unlock() | |
| 276 | + | o.onName = append(o.onName, handler) | |
| 277 | + | } | |
| 278 | + | ||
| 279 | + | // handlersForName returns the handlers registered for name, taken | |
| 280 | + | // under the lock so a handler may register another handler while events are | |
| 281 | + | // being dispatched. | |
| 282 | + | func (o *WpDrmLeaseConnector) handlersForName() []func(name string) { | |
| 283 | + | o.handlersMu.Lock() | |
| 284 | + | defer o.handlersMu.Unlock() | |
| 285 | + | return o.onName | |
| 286 | + | } | |
| 287 | + | ||
| 288 | + | // OnDescription registers a handler for the description event. | |
| 289 | + | // | |
| 290 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 291 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 292 | + | func (o *WpDrmLeaseConnector) OnDescription(handler func(description string)) { | |
| 293 | + | if handler == nil { | |
| 294 | + | return | |
| 295 | + | } | |
| 296 | + | o.handlersMu.Lock() | |
| 297 | + | defer o.handlersMu.Unlock() | |
| 298 | + | o.onDescription = append(o.onDescription, handler) | |
| 299 | + | } | |
| 300 | + | ||
| 301 | + | // handlersForDescription returns the handlers registered for description, taken | |
| 302 | + | // under the lock so a handler may register another handler while events are | |
| 303 | + | // being dispatched. | |
| 304 | + | func (o *WpDrmLeaseConnector) handlersForDescription() []func(description string) { | |
| 305 | + | o.handlersMu.Lock() | |
| 306 | + | defer o.handlersMu.Unlock() | |
| 307 | + | return o.onDescription | |
| 308 | + | } | |
| 309 | + | ||
| 310 | + | // OnConnectorId registers a handler for the connector_id event. | |
| 311 | + | // | |
| 312 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 313 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 314 | + | func (o *WpDrmLeaseConnector) OnConnectorId(handler func(connectorId uint32)) { | |
| 315 | + | if handler == nil { | |
| 316 | + | return | |
| 317 | + | } | |
| 318 | + | o.handlersMu.Lock() | |
| 319 | + | defer o.handlersMu.Unlock() | |
| 320 | + | o.onConnectorId = append(o.onConnectorId, handler) | |
| 321 | + | } | |
| 322 | + | ||
| 323 | + | // handlersForConnectorId returns the handlers registered for connector_id, taken | |
| 324 | + | // under the lock so a handler may register another handler while events are | |
| 325 | + | // being dispatched. | |
| 326 | + | func (o *WpDrmLeaseConnector) handlersForConnectorId() []func(connectorId uint32) { | |
| 327 | + | o.handlersMu.Lock() | |
| 328 | + | defer o.handlersMu.Unlock() | |
| 329 | + | return o.onConnectorId | |
| 330 | + | } | |
| 331 | + | ||
| 332 | + | // OnDone registers a handler for the done event. | |
| 333 | + | // | |
| 334 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 335 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 336 | + | func (o *WpDrmLeaseConnector) OnDone(handler func()) { | |
| 337 | + | if handler == nil { | |
| 338 | + | return | |
| 339 | + | } | |
| 340 | + | o.handlersMu.Lock() | |
| 341 | + | defer o.handlersMu.Unlock() | |
| 342 | + | o.onDone = append(o.onDone, handler) | |
| 343 | + | } | |
| 344 | + | ||
| 345 | + | // handlersForDone returns the handlers registered for done, taken | |
| 346 | + | // under the lock so a handler may register another handler while events are | |
| 347 | + | // being dispatched. | |
| 348 | + | func (o *WpDrmLeaseConnector) handlersForDone() []func() { | |
| 349 | + | o.handlersMu.Lock() | |
| 350 | + | defer o.handlersMu.Unlock() | |
| 351 | + | return o.onDone | |
| 352 | + | } | |
| 353 | + | ||
| 354 | + | // OnWithdrawn registers a handler for the withdrawn event. | |
| 355 | + | // | |
| 356 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 357 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 358 | + | func (o *WpDrmLeaseConnector) OnWithdrawn(handler func()) { | |
| 359 | + | if handler == nil { | |
| 360 | + | return | |
| 361 | + | } | |
| 362 | + | o.handlersMu.Lock() | |
| 363 | + | defer o.handlersMu.Unlock() | |
| 364 | + | o.onWithdrawn = append(o.onWithdrawn, handler) | |
| 365 | + | } | |
| 366 | + | ||
| 367 | + | // handlersForWithdrawn returns the handlers registered for withdrawn, taken | |
| 368 | + | // under the lock so a handler may register another handler while events are | |
| 369 | + | // being dispatched. | |
| 370 | + | func (o *WpDrmLeaseConnector) handlersForWithdrawn() []func() { | |
| 371 | + | o.handlersMu.Lock() | |
| 372 | + | defer o.handlersMu.Unlock() | |
| 373 | + | return o.onWithdrawn | |
| 374 | + | } | |
| 375 | + | ||
| 376 | + | // EventSignature returns the declared event argument types in wire order. | |
| 377 | + | func (o *WpDrmLeaseConnector) EventSignature(opcode uint16) (string, bool) { | |
| 378 | + | switch opcode { | |
| 379 | + | case 0: | |
| 380 | + | return "string,", true | |
| 381 | + | case 1: | |
| 382 | + | return "string,", true | |
| 383 | + | case 2: | |
| 384 | + | return "uint,", true | |
| 385 | + | case 3: | |
| 386 | + | return "", true | |
| 387 | + | case 4: | |
| 388 | + | return "", true | |
| 389 | + | default: | |
| 390 | + | return "", false | |
| 391 | + | } | |
| 392 | + | } | |
| 393 | + | ||
| 394 | + | // Dispatch decodes one event on wp_drm_lease_connector_v1 and calls the registered handlers. | |
| 395 | + | func (o *WpDrmLeaseConnector) Dispatch(event *wl.Event) { | |
| 396 | + | switch event.Opcode { | |
| 397 | + | case 0: // name | |
| 398 | + | name := event.String() | |
| 399 | + | ||
| 400 | + | for i, handler := range o.handlersForName() { | |
| 401 | + | _ = i | |
| 402 | + | handler(name) | |
| 403 | + | } | |
| 404 | + | case 1: // description | |
| 405 | + | description := event.String() | |
| 406 | + | ||
| 407 | + | for i, handler := range o.handlersForDescription() { | |
| 408 | + | _ = i | |
| 409 | + | handler(description) | |
| 410 | + | } | |
| 411 | + | case 2: // connector_id | |
| 412 | + | connectorId := event.Uint32() | |
| 413 | + | ||
| 414 | + | for i, handler := range o.handlersForConnectorId() { | |
| 415 | + | _ = i | |
| 416 | + | handler(connectorId) | |
| 417 | + | } | |
| 418 | + | case 3: // done | |
| 419 | + | ||
| 420 | + | for i, handler := range o.handlersForDone() { | |
| 421 | + | _ = i | |
| 422 | + | handler() | |
| 423 | + | } | |
| 424 | + | case 4: // withdrawn | |
| 425 | + | ||
| 426 | + | for i, handler := range o.handlersForWithdrawn() { | |
| 427 | + | _ = i | |
| 428 | + | handler() | |
| 429 | + | } | |
| 430 | + | default: | |
| 431 | + | } | |
| 432 | + | } | |
| 433 | + | ||
| 434 | + | // WpDrmLeaseRequestInterface is the protocol interface name. | |
| 435 | + | const WpDrmLeaseRequestInterface = "wp_drm_lease_request_v1" | |
| 436 | + | ||
| 437 | + | // WpDrmLeaseRequest is the generated binding for wp_drm_lease_request_v1 version 1. | |
| 438 | + | type WpDrmLeaseRequest struct { | |
| 439 | + | wl.BaseProxy | |
| 440 | + | } | |
| 441 | + | ||
| 442 | + | // NewWpDrmLeaseRequest returns an unbound WpDrmLeaseRequest. | |
| 443 | + | func NewWpDrmLeaseRequest(ctx *wl.Context) *WpDrmLeaseRequest { | |
| 444 | + | obj := &WpDrmLeaseRequest{} | |
| 445 | + | obj.SetContext(ctx) | |
| 446 | + | ctx.Register(obj) | |
| 447 | + | return obj | |
| 448 | + | } | |
| 449 | + | ||
| 450 | + | // Indicates that the client would like to lease the given connector. This is only used as a suggestion, the compositor may choose to include any resources in the lease it issues, or change the set of leased resources at any time. Compositors are however encouraged to include the requested connector and other resources necessary to drive the connected output in the lease. Requesting a connector that was created from a different lease device than this lease request raises the wrong_device error. Requesting a connector twice will raise the duplicate_connector error. | |
| 451 | + | func (o *WpDrmLeaseRequest) RequestConnector(connector *WpDrmLeaseConnector) error { | |
| 452 | + | var arg0 wl.Object | |
| 453 | + | if connector != nil { | |
| 454 | + | arg0 = connector | |
| 455 | + | } | |
| 456 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_drm_lease_request_v1.request_connector"}, wl.ArgObject(arg0)); err != nil { | |
| 457 | + | return err | |
| 458 | + | } | |
| 459 | + | return nil | |
| 460 | + | } | |
| 461 | + | ||
| 462 | + | // Submits the lease request and creates a new wp_drm_lease_v1 object. After calling submit the compositor will immediately destroy this object, issuing any more requests will cause a wl_display error. The compositor doesn't make any guarantees about the events of the lease object, clients cannot expect an immediate response. Not requesting any connectors before submitting the lease request will raise the empty_lease error. | |
| 463 | + | func (o *WpDrmLeaseRequest) Submit() (*WpDrmLease, error) { | |
| 464 | + | child := &WpDrmLease{} | |
| 465 | + | child.SetContext(o.Context()) | |
| 466 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_drm_lease_request_v1.submit", Destructor: true, Child: child}, wl.ArgObject(child)); err != nil { | |
| 467 | + | return nil, err | |
| 468 | + | } | |
| 469 | + | return child, nil | |
| 470 | + | } | |
| 471 | + | ||
| 472 | + | // EventSignature returns the declared event argument types in wire order. | |
| 473 | + | func (o *WpDrmLeaseRequest) EventSignature(opcode uint16) (string, bool) { | |
| 474 | + | switch opcode { | |
| 475 | + | default: | |
| 476 | + | return "", false | |
| 477 | + | } | |
| 478 | + | } | |
| 479 | + | ||
| 480 | + | // Dispatch decodes one event on wp_drm_lease_request_v1 and calls the registered handlers. | |
| 481 | + | func (o *WpDrmLeaseRequest) Dispatch(event *wl.Event) { | |
| 482 | + | switch event.Opcode { | |
| 483 | + | default: | |
| 484 | + | } | |
| 485 | + | } | |
| 486 | + | ||
| 487 | + | // WpDrmLeaseInterface is the protocol interface name. | |
| 488 | + | const WpDrmLeaseInterface = "wp_drm_lease_v1" | |
| 489 | + | ||
| 490 | + | // WpDrmLease is the generated binding for wp_drm_lease_v1 version 1. | |
| 491 | + | type WpDrmLease struct { | |
| 492 | + | wl.BaseProxy | |
| 493 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 494 | + | // handlers while another goroutine dispatches events. | |
| 495 | + | handlersMu sync.Mutex | |
| 496 | + | onLeaseFd []func(leasedFd *wl.OwnedFD) | |
| 497 | + | onFinished []func() | |
| 498 | + | } | |
| 499 | + | ||
| 500 | + | // NewWpDrmLease returns an unbound WpDrmLease. | |
| 501 | + | func NewWpDrmLease(ctx *wl.Context) *WpDrmLease { | |
| 502 | + | obj := &WpDrmLease{} | |
| 503 | + | obj.SetContext(ctx) | |
| 504 | + | ctx.Register(obj) | |
| 505 | + | return obj | |
| 506 | + | } | |
| 507 | + | ||
| 508 | + | // The client should send this to indicate that it no longer wishes to use this lease. The compositor should use drmModeRevokeLease on the appropriate file descriptor, if necessary. Upon destruction, the compositor should advertise the connector for leasing again by sending the connector event through the wp_drm_lease_device_v1 interface. | |
| 509 | + | func (o *WpDrmLease) Destroy() error { | |
| 510 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_drm_lease_v1.destroy", Destructor: true}); err != nil { | |
| 511 | + | return err | |
| 512 | + | } | |
| 513 | + | return nil | |
| 514 | + | } | |
| 515 | + | ||
| 516 | + | // OnLeaseFd registers a handler for the lease_fd event. | |
| 517 | + | // | |
| 518 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 519 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 520 | + | func (o *WpDrmLease) OnLeaseFd(handler func(leasedFd *wl.OwnedFD)) { | |
| 521 | + | if handler == nil { | |
| 522 | + | return | |
| 523 | + | } | |
| 524 | + | o.handlersMu.Lock() | |
| 525 | + | defer o.handlersMu.Unlock() | |
| 526 | + | o.onLeaseFd = append(o.onLeaseFd, handler) | |
| 527 | + | } | |
| 528 | + | ||
| 529 | + | // handlersForLeaseFd returns the handlers registered for lease_fd, taken | |
| 530 | + | // under the lock so a handler may register another handler while events are | |
| 531 | + | // being dispatched. | |
| 532 | + | func (o *WpDrmLease) handlersForLeaseFd() []func(leasedFd *wl.OwnedFD) { | |
| 533 | + | o.handlersMu.Lock() | |
| 534 | + | defer o.handlersMu.Unlock() | |
| 535 | + | return o.onLeaseFd | |
| 536 | + | } | |
| 537 | + | ||
| 538 | + | // OnFinished registers a handler for the finished event. | |
| 539 | + | // | |
| 540 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 541 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 542 | + | func (o *WpDrmLease) OnFinished(handler func()) { | |
| 543 | + | if handler == nil { | |
| 544 | + | return | |
| 545 | + | } | |
| 546 | + | o.handlersMu.Lock() | |
| 547 | + | defer o.handlersMu.Unlock() | |
| 548 | + | o.onFinished = append(o.onFinished, handler) | |
| 549 | + | } | |
| 550 | + | ||
| 551 | + | // handlersForFinished returns the handlers registered for finished, taken | |
| 552 | + | // under the lock so a handler may register another handler while events are | |
| 553 | + | // being dispatched. | |
| 554 | + | func (o *WpDrmLease) handlersForFinished() []func() { | |
| 555 | + | o.handlersMu.Lock() | |
| 556 | + | defer o.handlersMu.Unlock() | |
| 557 | + | return o.onFinished | |
| 558 | + | } | |
| 559 | + | ||
| 560 | + | // EventSignature returns the declared event argument types in wire order. | |
| 561 | + | func (o *WpDrmLease) EventSignature(opcode uint16) (string, bool) { | |
| 562 | + | switch opcode { | |
| 563 | + | case 0: | |
| 564 | + | return "fd,", true | |
| 565 | + | case 1: | |
| 566 | + | return "", true | |
| 567 | + | default: | |
| 568 | + | return "", false | |
| 569 | + | } | |
| 570 | + | } | |
| 571 | + | ||
| 572 | + | // Dispatch decodes one event on wp_drm_lease_v1 and calls the registered handlers. | |
| 573 | + | func (o *WpDrmLease) Dispatch(event *wl.Event) { | |
| 574 | + | switch event.Opcode { | |
| 575 | + | case 0: // lease_fd | |
| 576 | + | leasedFd := event.FD() | |
| 577 | + | ownedleasedFd := leasedFd | |
| 578 | + | defer ownedleasedFd.Close() | |
| 579 | + | ||
| 580 | + | for i, handler := range o.handlersForLeaseFd() { | |
| 581 | + | if i > 0 { | |
| 582 | + | leasedFd = nil | |
| 583 | + | } | |
| 584 | + | handler(leasedFd) | |
| 585 | + | } | |
| 586 | + | case 1: // finished | |
| 587 | + | ||
| 588 | + | for i, handler := range o.handlersForFinished() { | |
| 589 | + | _ = i | |
| 590 | + | handler() | |
| 591 | + | } | |
| 592 | + | default: | |
| 593 | + | } | |
| 594 | + | } | |
A protocol/drmlease/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package drmlease | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p drmlease -o drm-lease-v1_generated.go drm-lease-v1.xml | |
M protocol/drmsyncobj/linux-drm-syncobj-v1_generated.go +32 -7
| @@ -2,6 +2,31 @@ | |||
| 2 | 2 | // Protocol: linux_drm_syncobj_v1 | |
| 3 | 3 | // Source: linux-drm-syncobj-v1.xml | |
| 4 | 4 | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright 2016 The Chromium Authors. | |
| 7 | + | // Copyright 2017 Intel Corporation | |
| 8 | + | // Copyright 2018 Collabora, Ltd | |
| 9 | + | // Copyright 2021 Simon Ser | |
| 10 | + | // | |
| 11 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 12 | + | // copy of this software and associated documentation files (the "Software"), | |
| 13 | + | // to deal in the Software without restriction, including without limitation | |
| 14 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 15 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 16 | + | // Software is furnished to do so, subject to the following conditions: | |
| 17 | + | // | |
| 18 | + | // The above copyright notice and this permission notice (including the next | |
| 19 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 20 | + | // Software. | |
| 21 | + | // | |
| 22 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 23 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 24 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 25 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 26 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 27 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 28 | + | // DEALINGS IN THE SOFTWARE. | |
| 29 | + | ||
| 5 | 30 | package drmsyncobj | |
| 6 | 31 | ||
| 7 | 32 | import ( | |
| @@ -51,7 +76,7 @@ func NewWpLinuxDrmSyncobjManager(ctx *wl.Context) *WpLinuxDrmSyncobjManager { | |||
| 51 | 76 | ||
| 52 | 77 | // Destroy this explicit synchronization factory object. Other objects shall not be affected by this request. | |
| 53 | 78 | func (o *WpLinuxDrmSyncobjManager) Destroy() error { | |
| 54 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_linux_drm_syncobj_manager_v1.destroy", Destructor: true}); err != nil { | |
| 79 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_linux_drm_syncobj_manager_v1.destroy", Destructor: true}); err != nil { | |
| 55 | 80 | return err | |
| 56 | 81 | } | |
| 57 | 82 | return nil | |
| @@ -65,7 +90,7 @@ func (o *WpLinuxDrmSyncobjManager) GetSurface(surface *cross_wl_surface.Surface) | |||
| 65 | 90 | } | |
| 66 | 91 | child := &WpLinuxDrmSyncobjSurface{} | |
| 67 | 92 | child.SetContext(o.Context()) | |
| 68 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wp_linux_drm_syncobj_manager_v1.get_surface", Child: child}, child, arg1); err != nil { | |
| 93 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_linux_drm_syncobj_manager_v1.get_surface", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 69 | 94 | return nil, err | |
| 70 | 95 | } | |
| 71 | 96 | return child, nil | |
| @@ -75,7 +100,7 @@ func (o *WpLinuxDrmSyncobjManager) GetSurface(surface *cross_wl_surface.Surface) | |||
| 75 | 100 | func (o *WpLinuxDrmSyncobjManager) ImportTimeline(fd int) (*WpLinuxDrmSyncobjTimeline, error) { | |
| 76 | 101 | child := &WpLinuxDrmSyncobjTimeline{} | |
| 77 | 102 | child.SetContext(o.Context()) | |
| 78 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wp_linux_drm_syncobj_manager_v1.import_timeline", Child: child, FDs: []int{fd}}, child, uintptr(fd)); err != nil { | |
| 103 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wp_linux_drm_syncobj_manager_v1.import_timeline", Child: child, FDs: []int{fd}}, wl.ArgObject(child), wl.ArgFD()); err != nil { | |
| 79 | 104 | return nil, err | |
| 80 | 105 | } | |
| 81 | 106 | return child, nil | |
| @@ -114,7 +139,7 @@ func NewWpLinuxDrmSyncobjTimeline(ctx *wl.Context) *WpLinuxDrmSyncobjTimeline { | |||
| 114 | 139 | ||
| 115 | 140 | // Destroy the synchronization object timeline. Other objects are not affected by this request, in particular timeline points set by set_acquire_point and set_release_point are not unset. | |
| 116 | 141 | func (o *WpLinuxDrmSyncobjTimeline) Destroy() error { | |
| 117 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_linux_drm_syncobj_timeline_v1.destroy", Destructor: true}); err != nil { | |
| 142 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_linux_drm_syncobj_timeline_v1.destroy", Destructor: true}); err != nil { | |
| 118 | 143 | return err | |
| 119 | 144 | } | |
| 120 | 145 | return nil | |
| @@ -153,7 +178,7 @@ func NewWpLinuxDrmSyncobjSurface(ctx *wl.Context) *WpLinuxDrmSyncobjSurface { | |||
| 153 | 178 | ||
| 154 | 179 | // Destroy this surface synchronization object. Any timeline point set by this object with set_acquire_point or set_release_point since the last commit may be discarded by the compositor. Any timeline point set by this object before the last commit will not be affected. | |
| 155 | 180 | func (o *WpLinuxDrmSyncobjSurface) Destroy() error { | |
| 156 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_linux_drm_syncobj_surface_v1.destroy", Destructor: true}); err != nil { | |
| 181 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_linux_drm_syncobj_surface_v1.destroy", Destructor: true}); err != nil { | |
| 157 | 182 | return err | |
| 158 | 183 | } | |
| 159 | 184 | return nil | |
| @@ -165,7 +190,7 @@ func (o *WpLinuxDrmSyncobjSurface) SetAcquirePoint(timeline *WpLinuxDrmSyncobjTi | |||
| 165 | 190 | if timeline != nil { | |
| 166 | 191 | arg0 = timeline | |
| 167 | 192 | } | |
| 168 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wp_linux_drm_syncobj_surface_v1.set_acquire_point"}, arg0, pointHi, pointLo); err != nil { | |
| 193 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_linux_drm_syncobj_surface_v1.set_acquire_point"}, wl.ArgObject(arg0), wl.ArgUint(pointHi), wl.ArgUint(pointLo)); err != nil { | |
| 169 | 194 | return err | |
| 170 | 195 | } | |
| 171 | 196 | return nil | |
| @@ -177,7 +202,7 @@ func (o *WpLinuxDrmSyncobjSurface) SetReleasePoint(timeline *WpLinuxDrmSyncobjTi | |||
| 177 | 202 | if timeline != nil { | |
| 178 | 203 | arg0 = timeline | |
| 179 | 204 | } | |
| 180 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wp_linux_drm_syncobj_surface_v1.set_release_point"}, arg0, pointHi, pointLo); err != nil { | |
| 205 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wp_linux_drm_syncobj_surface_v1.set_release_point"}, wl.ArgObject(arg0), wl.ArgUint(pointHi), wl.ArgUint(pointLo)); err != nil { | |
| 181 | 206 | return err | |
| 182 | 207 | } | |
| 183 | 208 | return nil | |
M protocol/extensions_test.go +219 -0
| @@ -7,6 +7,7 @@ import ( | |||
| 7 | 7 | "errors" | |
| 8 | 8 | "net" | |
| 9 | 9 | "os" | |
| 10 | + | "slices" | |
| 10 | 11 | "strings" | |
| 11 | 12 | "testing" | |
| 12 | 13 | "time" | |
| @@ -111,6 +112,224 @@ func bind(t *testing.T, d *wlturbo.Display, p *net.UnixConn, name uint32, iface | |||
| 111 | 112 | t.Fatalf("bad bind %s announced=%d supported=%d negotiated=%d wire=%x", iface, announced, supported, v, b) | |
| 112 | 113 | } | |
| 113 | 114 | } | |
| 115 | + | ||
| 116 | + | // serverID is the first server-allocated object ID on the wire. | |
| 117 | + | const serverID = 0xff000000 | |
| 118 | + | ||
| 119 | + | // wordBytes encodes 32-bit words as a message body in native byte order. | |
| 120 | + | func wordBytes(v ...uint32) []byte { return msg(0, 0, v...)[8:] } | |
| 121 | + | ||
| 122 | + | // cat concatenates message body fragments. | |
| 123 | + | func cat(parts ...[]byte) []byte { | |
| 124 | + | var out []byte | |
| 125 | + | for _, p := range parts { | |
| 126 | + | out = append(out, p...) | |
| 127 | + | } | |
| 128 | + | return out | |
| 129 | + | } | |
| 130 | + | ||
| 131 | + | // decodeWords splits a message body into 32-bit words. | |
| 132 | + | func decodeWords(b []byte) []uint32 { | |
| 133 | + | w := make([]uint32, len(b)/4) | |
| 134 | + | for i := range w { | |
| 135 | + | w[i] = binary.NativeEndian.Uint32(b[i*4:]) | |
| 136 | + | } | |
| 137 | + | return w | |
| 138 | + | } | |
| 139 | + | ||
| 140 | + | // wantWords requires a request body to be exactly the given 32-bit words. | |
| 141 | + | func wantWords(t *testing.T, what string, b []byte, want ...uint32) { | |
| 142 | + | t.Helper() | |
| 143 | + | if got := decodeWords(b); !slices.Equal(got, want) { // nil and empty are equal | |
| 144 | + | t.Fatalf("%s wire = %v, want %v", what, got, want) | |
| 145 | + | } | |
| 146 | + | } | |
| 147 | + | ||
| 148 | + | // wantRequestWords reads one request and requires its exact object, opcode and | |
| 149 | + | // 32-bit word arguments. | |
| 150 | + | func wantRequestWords(t *testing.T, p *net.UnixConn, id uint32, op uint16, want ...uint32) { | |
| 151 | + | t.Helper() | |
| 152 | + | gid, gop, body := request(t, p) | |
| 153 | + | if gid != id || gop != op || len(body) != 4*len(want) { | |
| 154 | + | t.Fatalf("request object=%d op=%d body=%x, want object=%d op=%d words=%v", gid, gop, body, id, op, want) | |
| 155 | + | } | |
| 156 | + | wantWords(t, "request", body, want...) | |
| 157 | + | } | |
| 158 | + | ||
| 159 | + | // requireFDClosed fails if fd is still open in this process: the binding must | |
| 160 | + | // close its copy of a descriptor once the kernel took it with a request. Call | |
| 161 | + | // it before reading the request, because the received duplicate may reuse the | |
| 162 | + | // same descriptor number. | |
| 163 | + | func requireFDClosed(t *testing.T, fd int) { | |
| 164 | + | t.Helper() | |
| 165 | + | if _, e := unix.FcntlInt(uintptr(fd), unix.F_GETFD, 0); e == nil { | |
| 166 | + | t.Fatalf("descriptor %d sent by the client was not closed", fd) | |
| 167 | + | } | |
| 168 | + | } | |
| 169 | + | ||
| 170 | + | // requireNoWrite fails unless the client wrote nothing within a short deadline. | |
| 171 | + | func requireNoWrite(t *testing.T, p *net.UnixConn) { | |
| 172 | + | t.Helper() | |
| 173 | + | p.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) | |
| 174 | + | var b [64]byte | |
| 175 | + | n, e := p.Read(b[:]) | |
| 176 | + | if e == nil { | |
| 177 | + | t.Fatalf("unexpected bytes on the wire: %x", b[:n]) | |
| 178 | + | } | |
| 179 | + | if !errors.Is(e, os.ErrDeadlineExceeded) { | |
| 180 | + | t.Fatal(e) | |
| 181 | + | } | |
| 182 | + | } | |
| 183 | + | ||
| 184 | + | // recvRequestFDs reads one client message and the descriptors that came with | |
| 185 | + | // it. Every received descriptor is closed before a fatal failure, so a failed | |
| 186 | + | // check cannot leak them; on success the caller owns fds. | |
| 187 | + | func recvRequestFDs(t *testing.T, p *net.UnixConn) (id uint32, op uint16, body []byte, fds []int) { | |
| 188 | + | t.Helper() | |
| 189 | + | fail := func(format string, args ...any) { | |
| 190 | + | t.Helper() | |
| 191 | + | for _, fd := range fds { | |
| 192 | + | unix.Close(fd) | |
| 193 | + | } | |
| 194 | + | t.Fatalf(format, args...) | |
| 195 | + | } | |
| 196 | + | p.SetReadDeadline(time.Now().Add(2 * time.Second)) | |
| 197 | + | b := make([]byte, 4096) | |
| 198 | + | oob := make([]byte, 256) | |
| 199 | + | n, oobn, _, _, e := p.ReadMsgUnix(b, oob) | |
| 200 | + | if oobn > 0 { | |
| 201 | + | msgs, pe := unix.ParseSocketControlMessage(oob[:oobn]) | |
| 202 | + | for i := range msgs { | |
| 203 | + | r, re := unix.ParseUnixRights(&msgs[i]) | |
| 204 | + | fds = append(fds, r...) | |
| 205 | + | if re != nil && pe == nil { | |
| 206 | + | pe = re | |
| 207 | + | } | |
| 208 | + | } | |
| 209 | + | if pe != nil { | |
| 210 | + | fail("control message: %v", pe) | |
| 211 | + | } | |
| 212 | + | } | |
| 213 | + | if e != nil { | |
| 214 | + | fail("read request: %v", e) | |
| 215 | + | } | |
| 216 | + | if n < 8 { | |
| 217 | + | fail("short request (%d bytes)", n) | |
| 218 | + | } | |
| 219 | + | if size := int(binary.NativeEndian.Uint32(b[4:]) >> 16); size != n { | |
| 220 | + | fail("header size %d != %d bytes read", size, n) | |
| 221 | + | } | |
| 222 | + | return binary.NativeEndian.Uint32(b), uint16(binary.NativeEndian.Uint32(b[4:])), b[8:n], fds | |
| 223 | + | } | |
| 224 | + | ||
| 225 | + | // requestWithFD reads the next request, requires its object and opcode, and | |
| 226 | + | // requires exactly one descriptor, which the caller then owns. | |
| 227 | + | func requestWithFD(t *testing.T, p *net.UnixConn, id uint32, op uint16) ([]byte, int) { | |
| 228 | + | t.Helper() | |
| 229 | + | gid, gop, body, fds := recvRequestFDs(t, p) | |
| 230 | + | if gid != id || gop != op || len(fds) != 1 { | |
| 231 | + | for _, fd := range fds { | |
| 232 | + | unix.Close(fd) | |
| 233 | + | } | |
| 234 | + | t.Fatalf("request object=%d op=%d fds=%d, want object=%d op=%d with 1 descriptor (body %x)", gid, gop, len(fds), id, op, body) | |
| 235 | + | } | |
| 236 | + | return body, fds[0] | |
| 237 | + | } | |
| 238 | + | ||
| 239 | + | // register gives a proxy a client-allocated ID and registers it with d. | |
| 240 | + | func register(d *wlturbo.Display, o wlturbo.Proxy) { | |
| 241 | + | o.SetID(d.AllocateID()) | |
| 242 | + | d.Context().Register(o) | |
| 243 | + | } | |
| 244 | + | ||
| 245 | + | // wireEnv is one client connection against a fake compositor on a socketpair. | |
| 246 | + | type wireEnv struct { | |
| 247 | + | t *testing.T | |
| 248 | + | d *wlturbo.Display | |
| 249 | + | p *net.UnixConn | |
| 250 | + | } | |
| 251 | + | ||
| 252 | + | func newWireEnv(t *testing.T) *wireEnv { | |
| 253 | + | t.Helper() | |
| 254 | + | c, p := pair(t) | |
| 255 | + | d, e := wlturbo.ConnectFromConn(c) | |
| 256 | + | noerr(t, e) | |
| 257 | + | t.Cleanup(func() { d.Close() }) | |
| 258 | + | request(t, p) // wl_display.get_registry | |
| 259 | + | return &wireEnv{t: t, d: d, p: p} | |
| 260 | + | } | |
| 261 | + | ||
| 262 | + | func (s *wireEnv) dispatch() { s.t.Helper(); noerr(s.t, s.d.Dispatch()) } | |
| 263 | + | ||
| 264 | + | // bind advertises and binds a global; see the package-level bind. | |
| 265 | + | func (s *wireEnv) bind(name uint32, iface string, announced, supported uint32, proxy wlturbo.Proxy) { | |
| 266 | + | s.t.Helper() | |
| 267 | + | bind(s.t, s.d, s.p, name, iface, announced, supported, proxy) | |
| 268 | + | } | |
| 269 | + | ||
| 270 | + | // event sends one server event and dispatches it on the client. | |
| 271 | + | func (s *wireEnv) event(id uint32, op uint16, body ...byte) { | |
| 272 | + | s.t.Helper() | |
| 273 | + | s.eventFD(id, op, body) | |
| 274 | + | } | |
| 275 | + | ||
| 276 | + | // eventFD is event for an event that carries descriptors (SCM_RIGHTS). | |
| 277 | + | func (s *wireEnv) eventFD(id uint32, op uint16, body []byte, fd ...int) { | |
| 278 | + | s.t.Helper() | |
| 279 | + | send(s.t, s.p, payload(id, op, body...), fd...) | |
| 280 | + | s.dispatch() | |
| 281 | + | } | |
| 282 | + | ||
| 283 | + | // req reads the next client request and checks its object and opcode. | |
| 284 | + | func (s *wireEnv) req(id uint32, op uint16) []byte { | |
| 285 | + | s.t.Helper() | |
| 286 | + | gid, gop, b := request(s.t, s.p) | |
| 287 | + | if gid != id || gop != op { | |
| 288 | + | s.t.Fatalf("request object=%d op=%d, want object=%d op=%d (body %x)", gid, gop, id, op, b) | |
| 289 | + | } | |
| 290 | + | return b | |
| 291 | + | } | |
| 292 | + | ||
| 293 | + | // reqFD is req for a request that carries exactly one descriptor. | |
| 294 | + | func (s *wireEnv) reqFD(id uint32, op uint16) ([]byte, int) { | |
| 295 | + | s.t.Helper() | |
| 296 | + | return requestWithFD(s.t, s.p, id, op) | |
| 297 | + | } | |
| 298 | + | ||
| 299 | + | // noRequest fails if the client wrote anything. | |
| 300 | + | func (s *wireEnv) noRequest() { s.t.Helper(); requireNoWrite(s.t, s.p) } | |
| 301 | + | ||
| 302 | + | func (s *wireEnv) surface() *core.Surface { | |
| 303 | + | o := core.NewSurface(s.d.Context()) | |
| 304 | + | register(s.d, o) | |
| 305 | + | return o | |
| 306 | + | } | |
| 307 | + | func (s *wireEnv) seat() *core.Seat { | |
| 308 | + | o := core.NewSeat(s.d.Context()) | |
| 309 | + | register(s.d, o) | |
| 310 | + | return o | |
| 311 | + | } | |
| 312 | + | func (s *wireEnv) output() *core.Output { | |
| 313 | + | o := core.NewOutput(s.d.Context()) | |
| 314 | + | register(s.d, o) | |
| 315 | + | return o | |
| 316 | + | } | |
| 317 | + | func (s *wireEnv) pointer() *core.Pointer { | |
| 318 | + | o := core.NewPointer(s.d.Context()) | |
| 319 | + | register(s.d, o) | |
| 320 | + | return o | |
| 321 | + | } | |
| 322 | + | func (s *wireEnv) region() *core.Region { | |
| 323 | + | o := core.NewRegion(s.d.Context()) | |
| 324 | + | register(s.d, o) | |
| 325 | + | return o | |
| 326 | + | } | |
| 327 | + | func (s *wireEnv) buffer() *core.Buffer { | |
| 328 | + | o := core.NewBuffer(s.d.Context()) | |
| 329 | + | register(s.d, o) | |
| 330 | + | return o | |
| 331 | + | } | |
| 332 | + | ||
| 114 | 333 | func TestExtensionsOverSocketpair(t *testing.T) { | |
| 115 | 334 | c, p := pair(t) | |
| 116 | 335 | d, e := wlturbo.ConnectFromConn(c) | |
A protocol/extforeigntoplevel/ext-foreign-toplevel-list-v1.xml +219 -0
| @@ -0,0 +1,219 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="ext_foreign_toplevel_list_v1"> | |
| 3 | + | <copyright> | |
| 4 | + | Copyright © 2018 Ilia Bozhinov | |
| 5 | + | Copyright © 2020 Isaac Freund | |
| 6 | + | Copyright © 2022 wb9688 | |
| 7 | + | Copyright © 2023 i509VCB | |
| 8 | + | ||
| 9 | + | Permission to use, copy, modify, distribute, and sell this | |
| 10 | + | software and its documentation for any purpose is hereby granted | |
| 11 | + | without fee, provided that the above copyright notice appear in | |
| 12 | + | all copies and that both that copyright notice and this permission | |
| 13 | + | notice appear in supporting documentation, and that the name of | |
| 14 | + | the copyright holders not be used in advertising or publicity | |
| 15 | + | pertaining to distribution of the software without specific, | |
| 16 | + | written prior permission. The copyright holders make no | |
| 17 | + | representations about the suitability of this software for any | |
| 18 | + | purpose. It is provided "as is" without express or implied | |
| 19 | + | warranty. | |
| 20 | + | ||
| 21 | + | THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
| 22 | + | SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| 23 | + | FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| 24 | + | SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 25 | + | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
| 26 | + | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
| 27 | + | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| 28 | + | THIS SOFTWARE. | |
| 29 | + | </copyright> | |
| 30 | + | ||
| 31 | + | <description summary="list toplevels"> | |
| 32 | + | The purpose of this protocol is to provide protocol object handles for | |
| 33 | + | toplevels, possibly originating from another client. | |
| 34 | + | ||
| 35 | + | This protocol is intentionally minimalistic and expects additional | |
| 36 | + | functionality (e.g. creating a screencopy source from a toplevel handle, | |
| 37 | + | getting information about the state of the toplevel) to be implemented | |
| 38 | + | in extension protocols. | |
| 39 | + | ||
| 40 | + | The compositor may choose to restrict this protocol to a special client | |
| 41 | + | launched by the compositor itself or expose it to all clients, | |
| 42 | + | this is compositor policy. | |
| 43 | + | ||
| 44 | + | The key words "must", "must not", "required", "shall", "shall not", | |
| 45 | + | "should", "should not", "recommended", "may", and "optional" in this | |
| 46 | + | document are to be interpreted as described in IETF RFC 2119. | |
| 47 | + | ||
| 48 | + | Warning! The protocol described in this file is currently in the testing | |
| 49 | + | phase. Backward compatible changes may be added together with the | |
| 50 | + | corresponding interface version bump. Backward incompatible changes can | |
| 51 | + | only be done by creating a new major version of the extension. | |
| 52 | + | </description> | |
| 53 | + | ||
| 54 | + | <interface name="ext_foreign_toplevel_list_v1" version="1"> | |
| 55 | + | <description summary="list toplevels"> | |
| 56 | + | A toplevel is defined as a surface with a role similar to xdg_toplevel. | |
| 57 | + | XWayland surfaces may be treated like toplevels in this protocol. | |
| 58 | + | ||
| 59 | + | After a client binds the ext_foreign_toplevel_list_v1, each mapped | |
| 60 | + | toplevel window will be sent using the ext_foreign_toplevel_list_v1.toplevel | |
| 61 | + | event. | |
| 62 | + | ||
| 63 | + | Clients which only care about the current state can perform a roundtrip after | |
| 64 | + | binding this global. | |
| 65 | + | ||
| 66 | + | For each instance of ext_foreign_toplevel_list_v1, the compositor must | |
| 67 | + | create a new ext_foreign_toplevel_handle_v1 object for each mapped toplevel. | |
| 68 | + | ||
| 69 | + | If a compositor implementation sends the ext_foreign_toplevel_list_v1.finished | |
| 70 | + | event after the global is bound, the compositor must not send any | |
| 71 | + | ext_foreign_toplevel_list_v1.toplevel events. | |
| 72 | + | </description> | |
| 73 | + | ||
| 74 | + | <event name="toplevel"> | |
| 75 | + | <description summary="a toplevel has been created"> | |
| 76 | + | This event is emitted whenever a new toplevel window is created. It is | |
| 77 | + | emitted for all toplevels, regardless of the app that has created them. | |
| 78 | + | ||
| 79 | + | All initial properties of the toplevel (identifier, title, app_id) will be sent | |
| 80 | + | immediately after this event using the corresponding events for | |
| 81 | + | ext_foreign_toplevel_handle_v1. The compositor will use the | |
| 82 | + | ext_foreign_toplevel_handle_v1.done event to indicate when all data has | |
| 83 | + | been sent. | |
| 84 | + | </description> | |
| 85 | + | <arg name="toplevel" type="new_id" interface="ext_foreign_toplevel_handle_v1"/> | |
| 86 | + | </event> | |
| 87 | + | ||
| 88 | + | <event name="finished"> | |
| 89 | + | <description summary="the compositor has finished with the toplevel manager"> | |
| 90 | + | This event indicates that the compositor is done sending events | |
| 91 | + | to this object. The client should destroy the object. | |
| 92 | + | See ext_foreign_toplevel_list_v1.destroy for more information. | |
| 93 | + | ||
| 94 | + | The compositor must not send any more toplevel events after this event. | |
| 95 | + | </description> | |
| 96 | + | </event> | |
| 97 | + | ||
| 98 | + | <request name="stop"> | |
| 99 | + | <description summary="stop sending events"> | |
| 100 | + | This request indicates that the client no longer wishes to receive | |
| 101 | + | events for new toplevels. | |
| 102 | + | ||
| 103 | + | The Wayland protocol is asynchronous, meaning the compositor may send | |
| 104 | + | further toplevel events until the stop request is processed. | |
| 105 | + | The client should wait for a ext_foreign_toplevel_list_v1.finished | |
| 106 | + | event before destroying this object. | |
| 107 | + | </description> | |
| 108 | + | </request> | |
| 109 | + | ||
| 110 | + | <request name="destroy" type="destructor"> | |
| 111 | + | <description summary="destroy the ext_foreign_toplevel_list_v1 object"> | |
| 112 | + | This request should be called either when the client will no longer | |
| 113 | + | use the ext_foreign_toplevel_list_v1 or after the finished event | |
| 114 | + | has been received to allow destruction of the object. | |
| 115 | + | ||
| 116 | + | If a client wishes to destroy this object it should send a | |
| 117 | + | ext_foreign_toplevel_list_v1.stop request and wait for a ext_foreign_toplevel_list_v1.finished | |
| 118 | + | event, then destroy the handles and then this object. | |
| 119 | + | </description> | |
| 120 | + | </request> | |
| 121 | + | </interface> | |
| 122 | + | ||
| 123 | + | <interface name="ext_foreign_toplevel_handle_v1" version="1"> | |
| 124 | + | <description summary="a mapped toplevel"> | |
| 125 | + | A ext_foreign_toplevel_handle_v1 object represents a mapped toplevel | |
| 126 | + | window. A single app may have multiple mapped toplevels. | |
| 127 | + | </description> | |
| 128 | + | ||
| 129 | + | <request name="destroy" type="destructor"> | |
| 130 | + | <description summary="destroy the ext_foreign_toplevel_handle_v1 object"> | |
| 131 | + | This request should be used when the client will no longer use the handle | |
| 132 | + | or after the closed event has been received to allow destruction of the | |
| 133 | + | object. | |
| 134 | + | ||
| 135 | + | When a handle is destroyed, a new handle may not be created by the server | |
| 136 | + | until the toplevel is unmapped and then remapped. Destroying a toplevel handle | |
| 137 | + | is not recommended unless the client is cleaning up child objects | |
| 138 | + | before destroying the ext_foreign_toplevel_list_v1 object, the toplevel | |
| 139 | + | was closed or the toplevel handle will not be used in the future. | |
| 140 | + | ||
| 141 | + | Other protocols which extend the ext_foreign_toplevel_handle_v1 | |
| 142 | + | interface should require destructors for extension interfaces be | |
| 143 | + | called before allowing the toplevel handle to be destroyed. | |
| 144 | + | </description> | |
| 145 | + | </request> | |
| 146 | + | ||
| 147 | + | <event name="closed"> | |
| 148 | + | <description summary="the toplevel has been closed"> | |
| 149 | + | The server will emit no further events on the ext_foreign_toplevel_handle_v1 | |
| 150 | + | after this event. Any requests received aside from the destroy request must | |
| 151 | + | be ignored. Upon receiving this event, the client should destroy the handle. | |
| 152 | + | ||
| 153 | + | Other protocols which extend the ext_foreign_toplevel_handle_v1 | |
| 154 | + | interface must also ignore requests other than destructors. | |
| 155 | + | </description> | |
| 156 | + | </event> | |
| 157 | + | ||
| 158 | + | <event name="done"> | |
| 159 | + | <description summary="all information about the toplevel has been sent"> | |
| 160 | + | This event is sent after all changes in the toplevel state have | |
| 161 | + | been sent. | |
| 162 | + | ||
| 163 | + | This allows changes to the ext_foreign_toplevel_handle_v1 properties | |
| 164 | + | to be atomically applied. Other protocols which extend the | |
| 165 | + | ext_foreign_toplevel_handle_v1 interface may use this event to also | |
| 166 | + | atomically apply any pending state. | |
| 167 | + | ||
| 168 | + | This event must not be sent after the ext_foreign_toplevel_handle_v1.closed | |
| 169 | + | event. | |
| 170 | + | </description> | |
| 171 | + | </event> | |
| 172 | + | ||
| 173 | + | <event name="title"> | |
| 174 | + | <description summary="title change"> | |
| 175 | + | The title of the toplevel has changed. | |
| 176 | + | ||
| 177 | + | The configured state must not be applied immediately. See | |
| 178 | + | ext_foreign_toplevel_handle_v1.done for details. | |
| 179 | + | </description> | |
| 180 | + | <arg name="title" type="string"/> | |
| 181 | + | </event> | |
| 182 | + | ||
| 183 | + | <event name="app_id"> | |
| 184 | + | <description summary="app_id change"> | |
| 185 | + | The app id of the toplevel has changed. | |
| 186 | + | ||
| 187 | + | The configured state must not be applied immediately. See | |
| 188 | + | ext_foreign_toplevel_handle_v1.done for details. | |
| 189 | + | </description> | |
| 190 | + | <arg name="app_id" type="string"/> | |
| 191 | + | </event> | |
| 192 | + | ||
| 193 | + | <event name="identifier"> | |
| 194 | + | <description summary="a stable identifier for a toplevel"> | |
| 195 | + | This identifier is used to check if two or more toplevel handles belong | |
| 196 | + | to the same toplevel. | |
| 197 | + | ||
| 198 | + | The identifier is useful for command line tools or privileged clients | |
| 199 | + | which may need to reference an exact toplevel across processes or | |
| 200 | + | instances of the ext_foreign_toplevel_list_v1 global. | |
| 201 | + | ||
| 202 | + | The compositor must only send this event when the handle is created. | |
| 203 | + | ||
| 204 | + | The identifier must be unique per toplevel and its handles. Two different | |
| 205 | + | toplevels must not have the same identifier. The identifier is only valid | |
| 206 | + | as long as the toplevel is mapped. If the toplevel is unmapped the identifier | |
| 207 | + | must not be reused. An identifier must not be reused by the compositor to | |
| 208 | + | ensure there are no races when sharing identifiers between processes. | |
| 209 | + | ||
| 210 | + | An identifier is a string that contains up to 32 printable ASCII bytes. | |
| 211 | + | An identifier must not be an empty string. It is recommended that a | |
| 212 | + | compositor includes an opaque generation value in identifiers. How the | |
| 213 | + | generation value is used when generating the identifier is implementation | |
| 214 | + | dependent. | |
| 215 | + | </description> | |
| 216 | + | <arg name="identifier" type="string"/> | |
| 217 | + | </event> | |
| 218 | + | </interface> | |
| 219 | + | </protocol> | |
A protocol/extforeigntoplevel/ext-foreign-toplevel-list-v1_generated.go +356 -0
| @@ -0,0 +1,356 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: ext_foreign_toplevel_list_v1 | |
| 3 | + | // Source: ext-foreign-toplevel-list-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2018 Ilia Bozhinov | |
| 7 | + | // Copyright © 2020 Isaac Freund | |
| 8 | + | // Copyright © 2022 wb9688 | |
| 9 | + | // Copyright © 2023 i509VCB | |
| 10 | + | // | |
| 11 | + | // Permission to use, copy, modify, distribute, and sell this | |
| 12 | + | // software and its documentation for any purpose is hereby granted | |
| 13 | + | // without fee, provided that the above copyright notice appear in | |
| 14 | + | // all copies and that both that copyright notice and this permission | |
| 15 | + | // notice appear in supporting documentation, and that the name of | |
| 16 | + | // the copyright holders not be used in advertising or publicity | |
| 17 | + | // pertaining to distribution of the software without specific, | |
| 18 | + | // written prior permission. The copyright holders make no | |
| 19 | + | // representations about the suitability of this software for any | |
| 20 | + | // purpose. It is provided "as is" without express or implied | |
| 21 | + | // warranty. | |
| 22 | + | // | |
| 23 | + | // THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
| 24 | + | // SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| 25 | + | // FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| 26 | + | // SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 27 | + | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
| 28 | + | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
| 29 | + | // ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| 30 | + | // THIS SOFTWARE. | |
| 31 | + | ||
| 32 | + | package extforeigntoplevel | |
| 33 | + | ||
| 34 | + | import ( | |
| 35 | + | "sync" | |
| 36 | + | ||
| 37 | + | "github.com/bnema/wlturbo/wl" | |
| 38 | + | ) | |
| 39 | + | ||
| 40 | + | // ExtForeignToplevelListInterface is the protocol interface name. | |
| 41 | + | const ExtForeignToplevelListInterface = "ext_foreign_toplevel_list_v1" | |
| 42 | + | ||
| 43 | + | // ExtForeignToplevelList is the generated binding for ext_foreign_toplevel_list_v1 version 1. | |
| 44 | + | type ExtForeignToplevelList struct { | |
| 45 | + | wl.BaseProxy | |
| 46 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 47 | + | // handlers while another goroutine dispatches events. | |
| 48 | + | handlersMu sync.Mutex | |
| 49 | + | onToplevel []func(toplevelObject *ExtForeignToplevelHandle) | |
| 50 | + | onFinished []func() | |
| 51 | + | } | |
| 52 | + | ||
| 53 | + | // NewExtForeignToplevelList returns an unbound ExtForeignToplevelList. | |
| 54 | + | func NewExtForeignToplevelList(ctx *wl.Context) *ExtForeignToplevelList { | |
| 55 | + | obj := &ExtForeignToplevelList{} | |
| 56 | + | obj.SetContext(ctx) | |
| 57 | + | ctx.Register(obj) | |
| 58 | + | return obj | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | // This request indicates that the client no longer wishes to receive events for new toplevels. The Wayland protocol is asynchronous, meaning the compositor may send further toplevel events until the stop request is processed. The client should wait for a ext_foreign_toplevel_list_v1.finished event before destroying this object. | |
| 62 | + | func (o *ExtForeignToplevelList) Stop() error { | |
| 63 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_foreign_toplevel_list_v1.stop"}); err != nil { | |
| 64 | + | return err | |
| 65 | + | } | |
| 66 | + | return nil | |
| 67 | + | } | |
| 68 | + | ||
| 69 | + | // This request should be called either when the client will no longer use the ext_foreign_toplevel_list_v1 or after the finished event has been received to allow destruction of the object. If a client wishes to destroy this object it should send a ext_foreign_toplevel_list_v1.stop request and wait for a ext_foreign_toplevel_list_v1.finished event, then destroy the handles and then this object. | |
| 70 | + | func (o *ExtForeignToplevelList) Destroy() error { | |
| 71 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_foreign_toplevel_list_v1.destroy", Destructor: true}); err != nil { | |
| 72 | + | return err | |
| 73 | + | } | |
| 74 | + | return nil | |
| 75 | + | } | |
| 76 | + | ||
| 77 | + | // OnToplevel registers a handler for the toplevel event. | |
| 78 | + | // | |
| 79 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 80 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 81 | + | func (o *ExtForeignToplevelList) OnToplevel(handler func(toplevelObject *ExtForeignToplevelHandle)) { | |
| 82 | + | if handler == nil { | |
| 83 | + | return | |
| 84 | + | } | |
| 85 | + | o.handlersMu.Lock() | |
| 86 | + | defer o.handlersMu.Unlock() | |
| 87 | + | o.onToplevel = append(o.onToplevel, handler) | |
| 88 | + | } | |
| 89 | + | ||
| 90 | + | // handlersForToplevel returns the handlers registered for toplevel, taken | |
| 91 | + | // under the lock so a handler may register another handler while events are | |
| 92 | + | // being dispatched. | |
| 93 | + | func (o *ExtForeignToplevelList) handlersForToplevel() []func(toplevelObject *ExtForeignToplevelHandle) { | |
| 94 | + | o.handlersMu.Lock() | |
| 95 | + | defer o.handlersMu.Unlock() | |
| 96 | + | return o.onToplevel | |
| 97 | + | } | |
| 98 | + | ||
| 99 | + | // OnFinished registers a handler for the finished event. | |
| 100 | + | // | |
| 101 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 102 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 103 | + | func (o *ExtForeignToplevelList) OnFinished(handler func()) { | |
| 104 | + | if handler == nil { | |
| 105 | + | return | |
| 106 | + | } | |
| 107 | + | o.handlersMu.Lock() | |
| 108 | + | defer o.handlersMu.Unlock() | |
| 109 | + | o.onFinished = append(o.onFinished, handler) | |
| 110 | + | } | |
| 111 | + | ||
| 112 | + | // handlersForFinished returns the handlers registered for finished, taken | |
| 113 | + | // under the lock so a handler may register another handler while events are | |
| 114 | + | // being dispatched. | |
| 115 | + | func (o *ExtForeignToplevelList) handlersForFinished() []func() { | |
| 116 | + | o.handlersMu.Lock() | |
| 117 | + | defer o.handlersMu.Unlock() | |
| 118 | + | return o.onFinished | |
| 119 | + | } | |
| 120 | + | ||
| 121 | + | // EventSignature returns the declared event argument types in wire order. | |
| 122 | + | func (o *ExtForeignToplevelList) EventSignature(opcode uint16) (string, bool) { | |
| 123 | + | switch opcode { | |
| 124 | + | case 0: | |
| 125 | + | return "new_id,", true | |
| 126 | + | case 1: | |
| 127 | + | return "", true | |
| 128 | + | default: | |
| 129 | + | return "", false | |
| 130 | + | } | |
| 131 | + | } | |
| 132 | + | ||
| 133 | + | // Dispatch decodes one event on ext_foreign_toplevel_list_v1 and calls the registered handlers. | |
| 134 | + | func (o *ExtForeignToplevelList) Dispatch(event *wl.Event) { | |
| 135 | + | switch event.Opcode { | |
| 136 | + | case 0: // toplevel | |
| 137 | + | toplevelID := event.Uint32() | |
| 138 | + | toplevelObject := &ExtForeignToplevelHandle{} | |
| 139 | + | toplevelObject.SetContext(o.Context()) | |
| 140 | + | toplevelObject.SetID(toplevelID) | |
| 141 | + | toplevelObject.SetVersion(o.Version()) | |
| 142 | + | o.Context().Register(toplevelObject) | |
| 143 | + | ||
| 144 | + | for i, handler := range o.handlersForToplevel() { | |
| 145 | + | _ = i | |
| 146 | + | handler(toplevelObject) | |
| 147 | + | } | |
| 148 | + | case 1: // finished | |
| 149 | + | ||
| 150 | + | for i, handler := range o.handlersForFinished() { | |
| 151 | + | _ = i | |
| 152 | + | handler() | |
| 153 | + | } | |
| 154 | + | default: | |
| 155 | + | } | |
| 156 | + | } | |
| 157 | + | ||
| 158 | + | // ExtForeignToplevelHandleInterface is the protocol interface name. | |
| 159 | + | const ExtForeignToplevelHandleInterface = "ext_foreign_toplevel_handle_v1" | |
| 160 | + | ||
| 161 | + | // ExtForeignToplevelHandle is the generated binding for ext_foreign_toplevel_handle_v1 version 1. | |
| 162 | + | type ExtForeignToplevelHandle struct { | |
| 163 | + | wl.BaseProxy | |
| 164 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 165 | + | // handlers while another goroutine dispatches events. | |
| 166 | + | handlersMu sync.Mutex | |
| 167 | + | onClosed []func() | |
| 168 | + | onDone []func() | |
| 169 | + | onTitle []func(title string) | |
| 170 | + | onAppId []func(appId string) | |
| 171 | + | onIdentifier []func(identifier string) | |
| 172 | + | } | |
| 173 | + | ||
| 174 | + | // NewExtForeignToplevelHandle returns an unbound ExtForeignToplevelHandle. | |
| 175 | + | func NewExtForeignToplevelHandle(ctx *wl.Context) *ExtForeignToplevelHandle { | |
| 176 | + | obj := &ExtForeignToplevelHandle{} | |
| 177 | + | obj.SetContext(ctx) | |
| 178 | + | ctx.Register(obj) | |
| 179 | + | return obj | |
| 180 | + | } | |
| 181 | + | ||
| 182 | + | // This request should be used when the client will no longer use the handle or after the closed event has been received to allow destruction of the object. When a handle is destroyed, a new handle may not be created by the server until the toplevel is unmapped and then remapped. Destroying a toplevel handle is not recommended unless the client is cleaning up child objects before destroying the ext_foreign_toplevel_list_v1 object, the toplevel was closed or the toplevel handle will not be used in the future. Other protocols which extend the ext_foreign_toplevel_handle_v1 interface should require destructors for extension interfaces be called before allowing the toplevel handle to be destroyed. | |
| 183 | + | func (o *ExtForeignToplevelHandle) Destroy() error { | |
| 184 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_foreign_toplevel_handle_v1.destroy", Destructor: true}); err != nil { | |
| 185 | + | return err | |
| 186 | + | } | |
| 187 | + | return nil | |
| 188 | + | } | |
| 189 | + | ||
| 190 | + | // OnClosed registers a handler for the closed event. | |
| 191 | + | // | |
| 192 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 193 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 194 | + | func (o *ExtForeignToplevelHandle) OnClosed(handler func()) { | |
| 195 | + | if handler == nil { | |
| 196 | + | return | |
| 197 | + | } | |
| 198 | + | o.handlersMu.Lock() | |
| 199 | + | defer o.handlersMu.Unlock() | |
| 200 | + | o.onClosed = append(o.onClosed, handler) | |
| 201 | + | } | |
| 202 | + | ||
| 203 | + | // handlersForClosed returns the handlers registered for closed, taken | |
| 204 | + | // under the lock so a handler may register another handler while events are | |
| 205 | + | // being dispatched. | |
| 206 | + | func (o *ExtForeignToplevelHandle) handlersForClosed() []func() { | |
| 207 | + | o.handlersMu.Lock() | |
| 208 | + | defer o.handlersMu.Unlock() | |
| 209 | + | return o.onClosed | |
| 210 | + | } | |
| 211 | + | ||
| 212 | + | // OnDone registers a handler for the done event. | |
| 213 | + | // | |
| 214 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 215 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 216 | + | func (o *ExtForeignToplevelHandle) OnDone(handler func()) { | |
| 217 | + | if handler == nil { | |
| 218 | + | return | |
| 219 | + | } | |
| 220 | + | o.handlersMu.Lock() | |
| 221 | + | defer o.handlersMu.Unlock() | |
| 222 | + | o.onDone = append(o.onDone, handler) | |
| 223 | + | } | |
| 224 | + | ||
| 225 | + | // handlersForDone returns the handlers registered for done, taken | |
| 226 | + | // under the lock so a handler may register another handler while events are | |
| 227 | + | // being dispatched. | |
| 228 | + | func (o *ExtForeignToplevelHandle) handlersForDone() []func() { | |
| 229 | + | o.handlersMu.Lock() | |
| 230 | + | defer o.handlersMu.Unlock() | |
| 231 | + | return o.onDone | |
| 232 | + | } | |
| 233 | + | ||
| 234 | + | // OnTitle registers a handler for the title event. | |
| 235 | + | // | |
| 236 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 237 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 238 | + | func (o *ExtForeignToplevelHandle) OnTitle(handler func(title string)) { | |
| 239 | + | if handler == nil { | |
| 240 | + | return | |
| 241 | + | } | |
| 242 | + | o.handlersMu.Lock() | |
| 243 | + | defer o.handlersMu.Unlock() | |
| 244 | + | o.onTitle = append(o.onTitle, handler) | |
| 245 | + | } | |
| 246 | + | ||
| 247 | + | // handlersForTitle returns the handlers registered for title, taken | |
| 248 | + | // under the lock so a handler may register another handler while events are | |
| 249 | + | // being dispatched. | |
| 250 | + | func (o *ExtForeignToplevelHandle) handlersForTitle() []func(title string) { | |
| 251 | + | o.handlersMu.Lock() | |
| 252 | + | defer o.handlersMu.Unlock() | |
| 253 | + | return o.onTitle | |
| 254 | + | } | |
| 255 | + | ||
| 256 | + | // OnAppId registers a handler for the app_id event. | |
| 257 | + | // | |
| 258 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 259 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 260 | + | func (o *ExtForeignToplevelHandle) OnAppId(handler func(appId string)) { | |
| 261 | + | if handler == nil { | |
| 262 | + | return | |
| 263 | + | } | |
| 264 | + | o.handlersMu.Lock() | |
| 265 | + | defer o.handlersMu.Unlock() | |
| 266 | + | o.onAppId = append(o.onAppId, handler) | |
| 267 | + | } | |
| 268 | + | ||
| 269 | + | // handlersForAppId returns the handlers registered for app_id, taken | |
| 270 | + | // under the lock so a handler may register another handler while events are | |
| 271 | + | // being dispatched. | |
| 272 | + | func (o *ExtForeignToplevelHandle) handlersForAppId() []func(appId string) { | |
| 273 | + | o.handlersMu.Lock() | |
| 274 | + | defer o.handlersMu.Unlock() | |
| 275 | + | return o.onAppId | |
| 276 | + | } | |
| 277 | + | ||
| 278 | + | // OnIdentifier registers a handler for the identifier event. | |
| 279 | + | // | |
| 280 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 281 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 282 | + | func (o *ExtForeignToplevelHandle) OnIdentifier(handler func(identifier string)) { | |
| 283 | + | if handler == nil { | |
| 284 | + | return | |
| 285 | + | } | |
| 286 | + | o.handlersMu.Lock() | |
| 287 | + | defer o.handlersMu.Unlock() | |
| 288 | + | o.onIdentifier = append(o.onIdentifier, handler) | |
| 289 | + | } | |
| 290 | + | ||
| 291 | + | // handlersForIdentifier returns the handlers registered for identifier, taken | |
| 292 | + | // under the lock so a handler may register another handler while events are | |
| 293 | + | // being dispatched. | |
| 294 | + | func (o *ExtForeignToplevelHandle) handlersForIdentifier() []func(identifier string) { | |
| 295 | + | o.handlersMu.Lock() | |
| 296 | + | defer o.handlersMu.Unlock() | |
| 297 | + | return o.onIdentifier | |
| 298 | + | } | |
| 299 | + | ||
| 300 | + | // EventSignature returns the declared event argument types in wire order. | |
| 301 | + | func (o *ExtForeignToplevelHandle) EventSignature(opcode uint16) (string, bool) { | |
| 302 | + | switch opcode { | |
| 303 | + | case 0: | |
| 304 | + | return "", true | |
| 305 | + | case 1: | |
| 306 | + | return "", true | |
| 307 | + | case 2: | |
| 308 | + | return "string,", true | |
| 309 | + | case 3: | |
| 310 | + | return "string,", true | |
| 311 | + | case 4: | |
| 312 | + | return "string,", true | |
| 313 | + | default: | |
| 314 | + | return "", false | |
| 315 | + | } | |
| 316 | + | } | |
| 317 | + | ||
| 318 | + | // Dispatch decodes one event on ext_foreign_toplevel_handle_v1 and calls the registered handlers. | |
| 319 | + | func (o *ExtForeignToplevelHandle) Dispatch(event *wl.Event) { | |
| 320 | + | switch event.Opcode { | |
| 321 | + | case 0: // closed | |
| 322 | + | ||
| 323 | + | for i, handler := range o.handlersForClosed() { | |
| 324 | + | _ = i | |
| 325 | + | handler() | |
| 326 | + | } | |
| 327 | + | case 1: // done | |
| 328 | + | ||
| 329 | + | for i, handler := range o.handlersForDone() { | |
| 330 | + | _ = i | |
| 331 | + | handler() | |
| 332 | + | } | |
| 333 | + | case 2: // title | |
| 334 | + | title := event.String() | |
| 335 | + | ||
| 336 | + | for i, handler := range o.handlersForTitle() { | |
| 337 | + | _ = i | |
| 338 | + | handler(title) | |
| 339 | + | } | |
| 340 | + | case 3: // app_id | |
| 341 | + | appId := event.String() | |
| 342 | + | ||
| 343 | + | for i, handler := range o.handlersForAppId() { | |
| 344 | + | _ = i | |
| 345 | + | handler(appId) | |
| 346 | + | } | |
| 347 | + | case 4: // identifier | |
| 348 | + | identifier := event.String() | |
| 349 | + | ||
| 350 | + | for i, handler := range o.handlersForIdentifier() { | |
| 351 | + | _ = i | |
| 352 | + | handler(identifier) | |
| 353 | + | } | |
| 354 | + | default: | |
| 355 | + | } | |
| 356 | + | } | |
A protocol/extforeigntoplevel/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package extforeigntoplevel | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p extforeigntoplevel -o ext-foreign-toplevel-list-v1_generated.go ext-foreign-toplevel-list-v1.xml | |
A protocol/fifo/fifo-v1.xml +143 -0
| @@ -0,0 +1,143 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="fifo_v1"> | |
| 3 | + | <copyright> | |
| 4 | + | Copyright © 2023 Valve Corporation | |
| 5 | + | ||
| 6 | + | Permission is hereby granted, free of charge, to any person obtaining a | |
| 7 | + | copy of this software and associated documentation files (the "Software"), | |
| 8 | + | to deal in the Software without restriction, including without limitation | |
| 9 | + | the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 10 | + | and/or sell copies of the Software, and to permit persons to whom the | |
| 11 | + | Software is furnished to do so, subject to the following conditions: | |
| 12 | + | ||
| 13 | + | The above copyright notice and this permission notice (including the next | |
| 14 | + | paragraph) shall be included in all copies or substantial portions of the | |
| 15 | + | Software. | |
| 16 | + | ||
| 17 | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 18 | + | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 19 | + | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 20 | + | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 21 | + | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 22 | + | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 23 | + | DEALINGS IN THE SOFTWARE. | |
| 24 | + | </copyright> | |
| 25 | + | ||
| 26 | + | <interface name="wp_fifo_manager_v1" version="1"> | |
| 27 | + | <description summary="protocol for fifo constraints"> | |
| 28 | + | When a Wayland compositor considers applying a content update, | |
| 29 | + | it must ensure all the update's readiness constraints (fences, etc) | |
| 30 | + | are met. | |
| 31 | + | ||
| 32 | + | This protocol provides a way to use the completion of a display refresh | |
| 33 | + | cycle as an additional readiness constraint. | |
| 34 | + | ||
| 35 | + | Warning! The protocol described in this file is currently in the testing | |
| 36 | + | phase. Backward compatible changes may be added together with the | |
| 37 | + | corresponding interface version bump. Backward incompatible changes can | |
| 38 | + | only be done by creating a new major version of the extension. | |
| 39 | + | </description> | |
| 40 | + | ||
| 41 | + | <enum name="error"> | |
| 42 | + | <description summary="fatal presentation error"> | |
| 43 | + | These fatal protocol errors may be emitted in response to | |
| 44 | + | illegal requests. | |
| 45 | + | </description> | |
| 46 | + | <entry name="already_exists" value="0" | |
| 47 | + | summary="fifo manager already exists for surface"/> | |
| 48 | + | </enum> | |
| 49 | + | ||
| 50 | + | <request name="destroy" type="destructor"> | |
| 51 | + | <description summary="unbind from the manager interface"> | |
| 52 | + | Informs the server that the client will no longer be using | |
| 53 | + | this protocol object. Existing objects created by this object | |
| 54 | + | are not affected. | |
| 55 | + | </description> | |
| 56 | + | </request> | |
| 57 | + | ||
| 58 | + | <request name="get_fifo"> | |
| 59 | + | <description summary="request fifo interface for surface"> | |
| 60 | + | Establish a fifo object for a surface that may be used to add | |
| 61 | + | display refresh constraints to content updates. | |
| 62 | + | ||
| 63 | + | Only one such object may exist for a surface and attempting | |
| 64 | + | to create more than one will result in an already_exists | |
| 65 | + | protocol error. If a surface is acted on by multiple software | |
| 66 | + | components, general best practice is that only the component | |
| 67 | + | performing wl_surface.attach operations should use this protocol. | |
| 68 | + | </description> | |
| 69 | + | <arg name="id" type="new_id" interface="wp_fifo_v1"/> | |
| 70 | + | <arg name="surface" type="object" interface="wl_surface"/> | |
| 71 | + | </request> | |
| 72 | + | </interface> | |
| 73 | + | ||
| 74 | + | <interface name="wp_fifo_v1" version="1"> | |
| 75 | + | <description summary="fifo interface"> | |
| 76 | + | A fifo object for a surface that may be used to add | |
| 77 | + | display refresh constraints to content updates. | |
| 78 | + | </description> | |
| 79 | + | ||
| 80 | + | <enum name="error"> | |
| 81 | + | <description summary="fatal error"> | |
| 82 | + | These fatal protocol errors may be emitted in response to | |
| 83 | + | illegal requests. | |
| 84 | + | </description> | |
| 85 | + | <entry name="surface_destroyed" value="0" | |
| 86 | + | summary="the associated surface no longer exists"/> | |
| 87 | + | </enum> | |
| 88 | + | ||
| 89 | + | <request name="set_barrier"> | |
| 90 | + | <description summary="sets the start point for a fifo constraint"> | |
| 91 | + | When the content update containing the "set_barrier" is applied, | |
| 92 | + | it sets a "fifo_barrier" condition on the surface associated with | |
| 93 | + | the fifo object. The condition is cleared immediately after the | |
| 94 | + | following latching deadline for non-tearing presentation. | |
| 95 | + | ||
| 96 | + | The compositor may clear the condition early if it must do so to | |
| 97 | + | ensure client forward progress assumptions. | |
| 98 | + | ||
| 99 | + | To wait for this condition to clear, use the "wait_barrier" request. | |
| 100 | + | ||
| 101 | + | "set_barrier" is double-buffered state, see wl_surface.commit. | |
| 102 | + | ||
| 103 | + | Requesting set_barrier after the fifo object's surface is | |
| 104 | + | destroyed will generate a "surface_destroyed" error. | |
| 105 | + | </description> | |
| 106 | + | </request> | |
| 107 | + | ||
| 108 | + | <request name="wait_barrier"> | |
| 109 | + | <description summary="adds a fifo constraint to a content update"> | |
| 110 | + | Indicate that this content update is not ready while a | |
| 111 | + | "fifo_barrier" condition is present on the surface. | |
| 112 | + | ||
| 113 | + | This means that when the content update containing "set_barrier" | |
| 114 | + | was made active at a latching deadline, it will be active for | |
| 115 | + | at least one refresh cycle. A content update which is allowed to | |
| 116 | + | tear might become active after a latching deadline if no content | |
| 117 | + | update became active at the deadline. | |
| 118 | + | ||
| 119 | + | The constraint must be ignored if the surface is a subsurface in | |
| 120 | + | synchronized mode. If the surface is not being updated by the | |
| 121 | + | compositor (off-screen, occluded) the compositor may ignore the | |
| 122 | + | constraint. Clients must use an additional mechanism such as | |
| 123 | + | frame callbacks or timestamps to ensure throttling occurs under | |
| 124 | + | all conditions. | |
| 125 | + | ||
| 126 | + | "wait_barrier" is double-buffered state, see wl_surface.commit. | |
| 127 | + | ||
| 128 | + | Requesting "wait_barrier" after the fifo object's surface is | |
| 129 | + | destroyed will generate a "surface_destroyed" error. | |
| 130 | + | </description> | |
| 131 | + | </request> | |
| 132 | + | ||
| 133 | + | <request name="destroy" type="destructor"> | |
| 134 | + | <description summary="destroy the fifo interface"> | |
| 135 | + | Informs the server that the client will no longer be using | |
| 136 | + | this protocol object. | |
| 137 | + | ||
| 138 | + | Surface state changes previously made by this protocol are | |
| 139 | + | unaffected by this object's destruction. | |
| 140 | + | </description> | |
| 141 | + | </request> | |
| 142 | + | </interface> | |
| 143 | + | </protocol> | |
A protocol/fifo/fifo-v1_generated.go +146 -0
| @@ -0,0 +1,146 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: fifo_v1 | |
| 3 | + | // Source: fifo-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2023 Valve Corporation | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package fifo | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | cross_wl_surface "github.com/bnema/wlturbo/protocol/core" | |
| 31 | + | "github.com/bnema/wlturbo/wl" | |
| 32 | + | ) | |
| 33 | + | ||
| 34 | + | // ERROR_ALREADY_EXISTS is the error already_exists value. | |
| 35 | + | const ERROR_ALREADY_EXISTS = 0 | |
| 36 | + | ||
| 37 | + | // ERROR_SURFACE_DESTROYED is the error surface_destroyed value. | |
| 38 | + | const ERROR_SURFACE_DESTROYED = 0 | |
| 39 | + | ||
| 40 | + | // WpFifoManagerInterface is the protocol interface name. | |
| 41 | + | const WpFifoManagerInterface = "wp_fifo_manager_v1" | |
| 42 | + | ||
| 43 | + | // WpFifoManager is the generated binding for wp_fifo_manager_v1 version 1. | |
| 44 | + | type WpFifoManager struct { | |
| 45 | + | wl.BaseProxy | |
| 46 | + | } | |
| 47 | + | ||
| 48 | + | // NewWpFifoManager returns an unbound WpFifoManager. | |
| 49 | + | func NewWpFifoManager(ctx *wl.Context) *WpFifoManager { | |
| 50 | + | obj := &WpFifoManager{} | |
| 51 | + | obj.SetContext(ctx) | |
| 52 | + | ctx.Register(obj) | |
| 53 | + | return obj | |
| 54 | + | } | |
| 55 | + | ||
| 56 | + | // Informs the server that the client will no longer be using this protocol object. Existing objects created by this object are not affected. | |
| 57 | + | func (o *WpFifoManager) Destroy() error { | |
| 58 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_fifo_manager_v1.destroy", Destructor: true}); err != nil { | |
| 59 | + | return err | |
| 60 | + | } | |
| 61 | + | return nil | |
| 62 | + | } | |
| 63 | + | ||
| 64 | + | // Establish a fifo object for a surface that may be used to add display refresh constraints to content updates. Only one such object may exist for a surface and attempting to create more than one will result in an already_exists protocol error. If a surface is acted on by multiple software components, general best practice is that only the component performing wl_surface.attach operations should use this protocol. | |
| 65 | + | func (o *WpFifoManager) GetFifo(surface *cross_wl_surface.Surface) (*WpFifo, error) { | |
| 66 | + | var arg1 wl.Object | |
| 67 | + | if surface != nil { | |
| 68 | + | arg1 = surface | |
| 69 | + | } | |
| 70 | + | child := &WpFifo{} | |
| 71 | + | child.SetContext(o.Context()) | |
| 72 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_fifo_manager_v1.get_fifo", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 73 | + | return nil, err | |
| 74 | + | } | |
| 75 | + | return child, nil | |
| 76 | + | } | |
| 77 | + | ||
| 78 | + | // EventSignature returns the declared event argument types in wire order. | |
| 79 | + | func (o *WpFifoManager) EventSignature(opcode uint16) (string, bool) { | |
| 80 | + | switch opcode { | |
| 81 | + | default: | |
| 82 | + | return "", false | |
| 83 | + | } | |
| 84 | + | } | |
| 85 | + | ||
| 86 | + | // Dispatch decodes one event on wp_fifo_manager_v1 and calls the registered handlers. | |
| 87 | + | func (o *WpFifoManager) Dispatch(event *wl.Event) { | |
| 88 | + | switch event.Opcode { | |
| 89 | + | default: | |
| 90 | + | } | |
| 91 | + | } | |
| 92 | + | ||
| 93 | + | // WpFifoInterface is the protocol interface name. | |
| 94 | + | const WpFifoInterface = "wp_fifo_v1" | |
| 95 | + | ||
| 96 | + | // WpFifo is the generated binding for wp_fifo_v1 version 1. | |
| 97 | + | type WpFifo struct { | |
| 98 | + | wl.BaseProxy | |
| 99 | + | } | |
| 100 | + | ||
| 101 | + | // NewWpFifo returns an unbound WpFifo. | |
| 102 | + | func NewWpFifo(ctx *wl.Context) *WpFifo { | |
| 103 | + | obj := &WpFifo{} | |
| 104 | + | obj.SetContext(ctx) | |
| 105 | + | ctx.Register(obj) | |
| 106 | + | return obj | |
| 107 | + | } | |
| 108 | + | ||
| 109 | + | // When the content update containing the "set_barrier" is applied, it sets a "fifo_barrier" condition on the surface associated with the fifo object. The condition is cleared immediately after the following latching deadline for non-tearing presentation. The compositor may clear the condition early if it must do so to ensure client forward progress assumptions. To wait for this condition to clear, use the "wait_barrier" request. "set_barrier" is double-buffered state, see wl_surface.commit. Requesting set_barrier after the fifo object's surface is destroyed will generate a "surface_destroyed" error. | |
| 110 | + | func (o *WpFifo) SetBarrier() error { | |
| 111 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_fifo_v1.set_barrier"}); err != nil { | |
| 112 | + | return err | |
| 113 | + | } | |
| 114 | + | return nil | |
| 115 | + | } | |
| 116 | + | ||
| 117 | + | // Indicate that this content update is not ready while a "fifo_barrier" condition is present on the surface. This means that when the content update containing "set_barrier" was made active at a latching deadline, it will be active for at least one refresh cycle. A content update which is allowed to tear might become active after a latching deadline if no content update became active at the deadline. The constraint must be ignored if the surface is a subsurface in synchronized mode. If the surface is not being updated by the compositor (off-screen, occluded) the compositor may ignore the constraint. Clients must use an additional mechanism such as frame callbacks or timestamps to ensure throttling occurs under all conditions. "wait_barrier" is double-buffered state, see wl_surface.commit. Requesting "wait_barrier" after the fifo object's surface is destroyed will generate a "surface_destroyed" error. | |
| 118 | + | func (o *WpFifo) WaitBarrier() error { | |
| 119 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_fifo_v1.wait_barrier"}); err != nil { | |
| 120 | + | return err | |
| 121 | + | } | |
| 122 | + | return nil | |
| 123 | + | } | |
| 124 | + | ||
| 125 | + | // Informs the server that the client will no longer be using this protocol object. Surface state changes previously made by this protocol are unaffected by this object's destruction. | |
| 126 | + | func (o *WpFifo) Destroy() error { | |
| 127 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "wp_fifo_v1.destroy", Destructor: true}); err != nil { | |
| 128 | + | return err | |
| 129 | + | } | |
| 130 | + | return nil | |
| 131 | + | } | |
| 132 | + | ||
| 133 | + | // EventSignature returns the declared event argument types in wire order. | |
| 134 | + | func (o *WpFifo) EventSignature(opcode uint16) (string, bool) { | |
| 135 | + | switch opcode { | |
| 136 | + | default: | |
| 137 | + | return "", false | |
| 138 | + | } | |
| 139 | + | } | |
| 140 | + | ||
| 141 | + | // Dispatch decodes one event on wp_fifo_v1 and calls the registered handlers. | |
| 142 | + | func (o *WpFifo) Dispatch(event *wl.Event) { | |
| 143 | + | switch event.Opcode { | |
| 144 | + | default: | |
| 145 | + | } | |
| 146 | + | } | |
A protocol/fifo/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package fifo | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p fifo -o fifo-v1_generated.go -import wl_surface=github.com/bnema/wlturbo/protocol/core fifo-v1.xml | |
A protocol/foreigntoplevel/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package foreigntoplevel | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p foreigntoplevel -o wlr-foreign-toplevel-management-unstable-v1_generated.go -import wl_output=github.com/bnema/wlturbo/protocol/core -import wl_seat=github.com/bnema/wlturbo/protocol/core -import wl_surface=github.com/bnema/wlturbo/protocol/core wlr-foreign-toplevel-management-unstable-v1.xml | |
A protocol/foreigntoplevel/wlr-foreign-toplevel-management-unstable-v1.xml +270 -0
| @@ -0,0 +1,270 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="wlr_foreign_toplevel_management_unstable_v1"> | |
| 3 | + | <copyright> | |
| 4 | + | Copyright © 2018 Ilia Bozhinov | |
| 5 | + | ||
| 6 | + | Permission to use, copy, modify, distribute, and sell this | |
| 7 | + | software and its documentation for any purpose is hereby granted | |
| 8 | + | without fee, provided that the above copyright notice appear in | |
| 9 | + | all copies and that both that copyright notice and this permission | |
| 10 | + | notice appear in supporting documentation, and that the name of | |
| 11 | + | the copyright holders not be used in advertising or publicity | |
| 12 | + | pertaining to distribution of the software without specific, | |
| 13 | + | written prior permission. The copyright holders make no | |
| 14 | + | representations about the suitability of this software for any | |
| 15 | + | purpose. It is provided "as is" without express or implied | |
| 16 | + | warranty. | |
| 17 | + | ||
| 18 | + | THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
| 19 | + | SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| 20 | + | FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| 21 | + | SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 22 | + | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
| 23 | + | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
| 24 | + | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| 25 | + | THIS SOFTWARE. | |
| 26 | + | </copyright> | |
| 27 | + | ||
| 28 | + | <interface name="zwlr_foreign_toplevel_manager_v1" version="3"> | |
| 29 | + | <description summary="list and control opened apps"> | |
| 30 | + | The purpose of this protocol is to enable the creation of taskbars | |
| 31 | + | and docks by providing them with a list of opened applications and | |
| 32 | + | letting them request certain actions on them, like maximizing, etc. | |
| 33 | + | ||
| 34 | + | After a client binds the zwlr_foreign_toplevel_manager_v1, each opened | |
| 35 | + | toplevel window will be sent via the toplevel event | |
| 36 | + | </description> | |
| 37 | + | ||
| 38 | + | <event name="toplevel"> | |
| 39 | + | <description summary="a toplevel has been created"> | |
| 40 | + | This event is emitted whenever a new toplevel window is created. It | |
| 41 | + | is emitted for all toplevels, regardless of the app that has created | |
| 42 | + | them. | |
| 43 | + | ||
| 44 | + | All initial details of the toplevel(title, app_id, states, etc.) will | |
| 45 | + | be sent immediately after this event via the corresponding events in | |
| 46 | + | zwlr_foreign_toplevel_handle_v1. | |
| 47 | + | </description> | |
| 48 | + | <arg name="toplevel" type="new_id" interface="zwlr_foreign_toplevel_handle_v1"/> | |
| 49 | + | </event> | |
| 50 | + | ||
| 51 | + | <request name="stop"> | |
| 52 | + | <description summary="stop sending events"> | |
| 53 | + | Indicates the client no longer wishes to receive events for new toplevels. | |
| 54 | + | However the compositor may emit further toplevel_created events, until | |
| 55 | + | the finished event is emitted. | |
| 56 | + | ||
| 57 | + | The client must not send any more requests after this one. | |
| 58 | + | </description> | |
| 59 | + | </request> | |
| 60 | + | ||
| 61 | + | <event name="finished" type="destructor"> | |
| 62 | + | <description summary="the compositor has finished with the toplevel manager"> | |
| 63 | + | This event indicates that the compositor is done sending events to the | |
| 64 | + | zwlr_foreign_toplevel_manager_v1. The server will destroy the object | |
| 65 | + | immediately after sending this request, so it will become invalid and | |
| 66 | + | the client should free any resources associated with it. | |
| 67 | + | </description> | |
| 68 | + | </event> | |
| 69 | + | </interface> | |
| 70 | + | ||
| 71 | + | <interface name="zwlr_foreign_toplevel_handle_v1" version="3"> | |
| 72 | + | <description summary="an opened toplevel"> | |
| 73 | + | A zwlr_foreign_toplevel_handle_v1 object represents an opened toplevel | |
| 74 | + | window. Each app may have multiple opened toplevels. | |
| 75 | + | ||
| 76 | + | Each toplevel has a list of outputs it is visible on, conveyed to the | |
| 77 | + | client with the output_enter and output_leave events. | |
| 78 | + | </description> | |
| 79 | + | ||
| 80 | + | <event name="title"> | |
| 81 | + | <description summary="title change"> | |
| 82 | + | This event is emitted whenever the title of the toplevel changes. | |
| 83 | + | </description> | |
| 84 | + | <arg name="title" type="string"/> | |
| 85 | + | </event> | |
| 86 | + | ||
| 87 | + | <event name="app_id"> | |
| 88 | + | <description summary="app-id change"> | |
| 89 | + | This event is emitted whenever the app-id of the toplevel changes. | |
| 90 | + | </description> | |
| 91 | + | <arg name="app_id" type="string"/> | |
| 92 | + | </event> | |
| 93 | + | ||
| 94 | + | <event name="output_enter"> | |
| 95 | + | <description summary="toplevel entered an output"> | |
| 96 | + | This event is emitted whenever the toplevel becomes visible on | |
| 97 | + | the given output. A toplevel may be visible on multiple outputs. | |
| 98 | + | </description> | |
| 99 | + | <arg name="output" type="object" interface="wl_output"/> | |
| 100 | + | </event> | |
| 101 | + | ||
| 102 | + | <event name="output_leave"> | |
| 103 | + | <description summary="toplevel left an output"> | |
| 104 | + | This event is emitted whenever the toplevel stops being visible on | |
| 105 | + | the given output. It is guaranteed that an entered-output event | |
| 106 | + | with the same output has been emitted before this event. | |
| 107 | + | </description> | |
| 108 | + | <arg name="output" type="object" interface="wl_output"/> | |
| 109 | + | </event> | |
| 110 | + | ||
| 111 | + | <request name="set_maximized"> | |
| 112 | + | <description summary="requests that the toplevel be maximized"> | |
| 113 | + | Requests that the toplevel be maximized. If the maximized state actually | |
| 114 | + | changes, this will be indicated by the state event. | |
| 115 | + | </description> | |
| 116 | + | </request> | |
| 117 | + | ||
| 118 | + | <request name="unset_maximized"> | |
| 119 | + | <description summary="requests that the toplevel be unmaximized"> | |
| 120 | + | Requests that the toplevel be unmaximized. If the maximized state actually | |
| 121 | + | changes, this will be indicated by the state event. | |
| 122 | + | </description> | |
| 123 | + | </request> | |
| 124 | + | ||
| 125 | + | <request name="set_minimized"> | |
| 126 | + | <description summary="requests that the toplevel be minimized"> | |
| 127 | + | Requests that the toplevel be minimized. If the minimized state actually | |
| 128 | + | changes, this will be indicated by the state event. | |
| 129 | + | </description> | |
| 130 | + | </request> | |
| 131 | + | ||
| 132 | + | <request name="unset_minimized"> | |
| 133 | + | <description summary="requests that the toplevel be unminimized"> | |
| 134 | + | Requests that the toplevel be unminimized. If the minimized state actually | |
| 135 | + | changes, this will be indicated by the state event. | |
| 136 | + | </description> | |
| 137 | + | </request> | |
| 138 | + | ||
| 139 | + | <request name="activate"> | |
| 140 | + | <description summary="activate the toplevel"> | |
| 141 | + | Request that this toplevel be activated on the given seat. | |
| 142 | + | There is no guarantee the toplevel will be actually activated. | |
| 143 | + | </description> | |
| 144 | + | <arg name="seat" type="object" interface="wl_seat"/> | |
| 145 | + | </request> | |
| 146 | + | ||
| 147 | + | <enum name="state"> | |
| 148 | + | <description summary="types of states on the toplevel"> | |
| 149 | + | The different states that a toplevel can have. These have the same meaning | |
| 150 | + | as the states with the same names defined in xdg-toplevel | |
| 151 | + | </description> | |
| 152 | + | ||
| 153 | + | <entry name="maximized" value="0" summary="the toplevel is maximized"/> | |
| 154 | + | <entry name="minimized" value="1" summary="the toplevel is minimized"/> | |
| 155 | + | <entry name="activated" value="2" summary="the toplevel is active"/> | |
| 156 | + | <entry name="fullscreen" value="3" summary="the toplevel is fullscreen" since="2"/> | |
| 157 | + | </enum> | |
| 158 | + | ||
| 159 | + | <event name="state"> | |
| 160 | + | <description summary="the toplevel state changed"> | |
| 161 | + | This event is emitted immediately after the zlw_foreign_toplevel_handle_v1 | |
| 162 | + | is created and each time the toplevel state changes, either because of a | |
| 163 | + | compositor action or because of a request in this protocol. | |
| 164 | + | </description> | |
| 165 | + | ||
| 166 | + | <arg name="state" type="array"/> | |
| 167 | + | </event> | |
| 168 | + | ||
| 169 | + | <event name="done"> | |
| 170 | + | <description summary="all information about the toplevel has been sent"> | |
| 171 | + | This event is sent after all changes in the toplevel state have been | |
| 172 | + | sent. | |
| 173 | + | ||
| 174 | + | This allows changes to the zwlr_foreign_toplevel_handle_v1 properties | |
| 175 | + | to be seen as atomic, even if they happen via multiple events. | |
| 176 | + | </description> | |
| 177 | + | </event> | |
| 178 | + | ||
| 179 | + | <request name="close"> | |
| 180 | + | <description summary="request that the toplevel be closed"> | |
| 181 | + | Send a request to the toplevel to close itself. The compositor would | |
| 182 | + | typically use a shell-specific method to carry out this request, for | |
| 183 | + | example by sending the xdg_toplevel.close event. However, this gives | |
| 184 | + | no guarantees the toplevel will actually be destroyed. If and when | |
| 185 | + | this happens, the zwlr_foreign_toplevel_handle_v1.closed event will | |
| 186 | + | be emitted. | |
| 187 | + | </description> | |
| 188 | + | </request> | |
| 189 | + | ||
| 190 | + | <request name="set_rectangle"> | |
| 191 | + | <description summary="the rectangle which represents the toplevel"> | |
| 192 | + | The rectangle of the surface specified in this request corresponds to | |
| 193 | + | the place where the app using this protocol represents the given toplevel. | |
| 194 | + | It can be used by the compositor as a hint for some operations, e.g | |
| 195 | + | minimizing. The client is however not required to set this, in which | |
| 196 | + | case the compositor is free to decide some default value. | |
| 197 | + | ||
| 198 | + | If the client specifies more than one rectangle, only the last one is | |
| 199 | + | considered. | |
| 200 | + | ||
| 201 | + | The dimensions are given in surface-local coordinates. | |
| 202 | + | Setting width=height=0 removes the already-set rectangle. | |
| 203 | + | </description> | |
| 204 | + | ||
| 205 | + | <arg name="surface" type="object" interface="wl_surface"/> | |
| 206 | + | <arg name="x" type="int"/> | |
| 207 | + | <arg name="y" type="int"/> | |
| 208 | + | <arg name="width" type="int"/> | |
| 209 | + | <arg name="height" type="int"/> | |
| 210 | + | </request> | |
| 211 | + | ||
| 212 | + | <enum name="error"> | |
| 213 | + | <entry name="invalid_rectangle" value="0" | |
| 214 | + | summary="the provided rectangle is invalid"/> | |
| 215 | + | </enum> | |
| 216 | + | ||
| 217 | + | <event name="closed"> | |
| 218 | + | <description summary="this toplevel has been destroyed"> | |
| 219 | + | This event means the toplevel has been destroyed. It is guaranteed there | |
| 220 | + | won't be any more events for this zwlr_foreign_toplevel_handle_v1. The | |
| 221 | + | toplevel itself becomes inert so any requests will be ignored except the | |
| 222 | + | destroy request. | |
| 223 | + | </description> | |
| 224 | + | </event> | |
| 225 | + | ||
| 226 | + | <request name="destroy" type="destructor"> | |
| 227 | + | <description summary="destroy the zwlr_foreign_toplevel_handle_v1 object"> | |
| 228 | + | Destroys the zwlr_foreign_toplevel_handle_v1 object. | |
| 229 | + | ||
| 230 | + | This request should be called either when the client does not want to | |
| 231 | + | use the toplevel anymore or after the closed event to finalize the | |
| 232 | + | destruction of the object. | |
| 233 | + | </description> | |
| 234 | + | </request> | |
| 235 | + | ||
| 236 | + | <!-- Version 2 additions --> | |
| 237 | + | ||
| 238 | + | <request name="set_fullscreen" since="2"> | |
| 239 | + | <description summary="request that the toplevel be fullscreened"> | |
| 240 | + | Requests that the toplevel be fullscreened on the given output. If the | |
| 241 | + | fullscreen state and/or the outputs the toplevel is visible on actually | |
| 242 | + | change, this will be indicated by the state and output_enter/leave | |
| 243 | + | events. | |
| 244 | + | ||
| 245 | + | The output parameter is only a hint to the compositor. Also, if output | |
| 246 | + | is NULL, the compositor should decide which output the toplevel will be | |
| 247 | + | fullscreened on, if at all. | |
| 248 | + | </description> | |
| 249 | + | <arg name="output" type="object" interface="wl_output" allow-null="true"/> | |
| 250 | + | </request> | |
| 251 | + | ||
| 252 | + | <request name="unset_fullscreen" since="2"> | |
| 253 | + | <description summary="request that the toplevel be unfullscreened"> | |
| 254 | + | Requests that the toplevel be unfullscreened. If the fullscreen state | |
| 255 | + | actually changes, this will be indicated by the state event. | |
| 256 | + | </description> | |
| 257 | + | </request> | |
| 258 | + | ||
| 259 | + | <!-- Version 3 additions --> | |
| 260 | + | ||
| 261 | + | <event name="parent" since="3"> | |
| 262 | + | <description summary="parent change"> | |
| 263 | + | This event is emitted whenever the parent of the toplevel changes. | |
| 264 | + | ||
| 265 | + | No event is emitted when the parent handle is destroyed by the client. | |
| 266 | + | </description> | |
| 267 | + | <arg name="parent" type="object" interface="zwlr_foreign_toplevel_handle_v1" allow-null="true"/> | |
| 268 | + | </event> | |
| 269 | + | </interface> | |
| 270 | + | </protocol> | |
A protocol/foreigntoplevel/wlr-foreign-toplevel-management-unstable-v1_generated.go +544 -0
| @@ -0,0 +1,544 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: wlr_foreign_toplevel_management_unstable_v1 | |
| 3 | + | // Source: wlr-foreign-toplevel-management-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2018 Ilia Bozhinov | |
| 7 | + | // | |
| 8 | + | // Permission to use, copy, modify, distribute, and sell this | |
| 9 | + | // software and its documentation for any purpose is hereby granted | |
| 10 | + | // without fee, provided that the above copyright notice appear in | |
| 11 | + | // all copies and that both that copyright notice and this permission | |
| 12 | + | // notice appear in supporting documentation, and that the name of | |
| 13 | + | // the copyright holders not be used in advertising or publicity | |
| 14 | + | // pertaining to distribution of the software without specific, | |
| 15 | + | // written prior permission. The copyright holders make no | |
| 16 | + | // representations about the suitability of this software for any | |
| 17 | + | // purpose. It is provided "as is" without express or implied | |
| 18 | + | // warranty. | |
| 19 | + | // | |
| 20 | + | // THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
| 21 | + | // SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| 22 | + | // FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| 23 | + | // SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 24 | + | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
| 25 | + | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
| 26 | + | // ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| 27 | + | // THIS SOFTWARE. | |
| 28 | + | ||
| 29 | + | package foreigntoplevel | |
| 30 | + | ||
| 31 | + | import ( | |
| 32 | + | "sync" | |
| 33 | + | ||
| 34 | + | cross_wl_output "github.com/bnema/wlturbo/protocol/core" | |
| 35 | + | cross_wl_seat "github.com/bnema/wlturbo/protocol/core" | |
| 36 | + | cross_wl_surface "github.com/bnema/wlturbo/protocol/core" | |
| 37 | + | "github.com/bnema/wlturbo/wl" | |
| 38 | + | ) | |
| 39 | + | ||
| 40 | + | // STATE_MAXIMIZED is the state maximized value. | |
| 41 | + | const STATE_MAXIMIZED = 0 | |
| 42 | + | ||
| 43 | + | // STATE_MINIMIZED is the state minimized value. | |
| 44 | + | const STATE_MINIMIZED = 1 | |
| 45 | + | ||
| 46 | + | // STATE_ACTIVATED is the state activated value. | |
| 47 | + | const STATE_ACTIVATED = 2 | |
| 48 | + | ||
| 49 | + | // STATE_FULLSCREEN is the state fullscreen value. | |
| 50 | + | const STATE_FULLSCREEN = 3 | |
| 51 | + | ||
| 52 | + | // ERROR_INVALID_RECTANGLE is the error invalid_rectangle value. | |
| 53 | + | const ERROR_INVALID_RECTANGLE = 0 | |
| 54 | + | ||
| 55 | + | // ForeignToplevelManagerInterface is the protocol interface name. | |
| 56 | + | const ForeignToplevelManagerInterface = "zwlr_foreign_toplevel_manager_v1" | |
| 57 | + | ||
| 58 | + | // ForeignToplevelManager is the generated binding for zwlr_foreign_toplevel_manager_v1 version 3. | |
| 59 | + | type ForeignToplevelManager struct { | |
| 60 | + | wl.BaseProxy | |
| 61 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 62 | + | // handlers while another goroutine dispatches events. | |
| 63 | + | handlersMu sync.Mutex | |
| 64 | + | onToplevel []func(toplevelObject *ForeignToplevelHandle) | |
| 65 | + | onFinished []func() | |
| 66 | + | } | |
| 67 | + | ||
| 68 | + | // NewForeignToplevelManager returns an unbound ForeignToplevelManager. | |
| 69 | + | func NewForeignToplevelManager(ctx *wl.Context) *ForeignToplevelManager { | |
| 70 | + | obj := &ForeignToplevelManager{} | |
| 71 | + | obj.SetContext(ctx) | |
| 72 | + | ctx.Register(obj) | |
| 73 | + | return obj | |
| 74 | + | } | |
| 75 | + | ||
| 76 | + | // Indicates the client no longer wishes to receive events for new toplevels. However the compositor may emit further toplevel_created events, until the finished event is emitted. The client must not send any more requests after this one. | |
| 77 | + | func (o *ForeignToplevelManager) Stop() error { | |
| 78 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_foreign_toplevel_manager_v1.stop"}); err != nil { | |
| 79 | + | return err | |
| 80 | + | } | |
| 81 | + | return nil | |
| 82 | + | } | |
| 83 | + | ||
| 84 | + | // OnToplevel registers a handler for the toplevel event. | |
| 85 | + | // | |
| 86 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 87 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 88 | + | func (o *ForeignToplevelManager) OnToplevel(handler func(toplevelObject *ForeignToplevelHandle)) { | |
| 89 | + | if handler == nil { | |
| 90 | + | return | |
| 91 | + | } | |
| 92 | + | o.handlersMu.Lock() | |
| 93 | + | defer o.handlersMu.Unlock() | |
| 94 | + | o.onToplevel = append(o.onToplevel, handler) | |
| 95 | + | } | |
| 96 | + | ||
| 97 | + | // handlersForToplevel returns the handlers registered for toplevel, taken | |
| 98 | + | // under the lock so a handler may register another handler while events are | |
| 99 | + | // being dispatched. | |
| 100 | + | func (o *ForeignToplevelManager) handlersForToplevel() []func(toplevelObject *ForeignToplevelHandle) { | |
| 101 | + | o.handlersMu.Lock() | |
| 102 | + | defer o.handlersMu.Unlock() | |
| 103 | + | return o.onToplevel | |
| 104 | + | } | |
| 105 | + | ||
| 106 | + | // OnFinished registers a handler for the finished event. | |
| 107 | + | // | |
| 108 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 109 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 110 | + | func (o *ForeignToplevelManager) OnFinished(handler func()) { | |
| 111 | + | if handler == nil { | |
| 112 | + | return | |
| 113 | + | } | |
| 114 | + | o.handlersMu.Lock() | |
| 115 | + | defer o.handlersMu.Unlock() | |
| 116 | + | o.onFinished = append(o.onFinished, handler) | |
| 117 | + | } | |
| 118 | + | ||
| 119 | + | // handlersForFinished returns the handlers registered for finished, taken | |
| 120 | + | // under the lock so a handler may register another handler while events are | |
| 121 | + | // being dispatched. | |
| 122 | + | func (o *ForeignToplevelManager) handlersForFinished() []func() { | |
| 123 | + | o.handlersMu.Lock() | |
| 124 | + | defer o.handlersMu.Unlock() | |
| 125 | + | return o.onFinished | |
| 126 | + | } | |
| 127 | + | ||
| 128 | + | // EventSignature returns the declared event argument types in wire order. | |
| 129 | + | func (o *ForeignToplevelManager) EventSignature(opcode uint16) (string, bool) { | |
| 130 | + | switch opcode { | |
| 131 | + | case 0: | |
| 132 | + | return "new_id,", true | |
| 133 | + | case 1: | |
| 134 | + | return "", true | |
| 135 | + | default: | |
| 136 | + | return "", false | |
| 137 | + | } | |
| 138 | + | } | |
| 139 | + | ||
| 140 | + | // Dispatch decodes one event on zwlr_foreign_toplevel_manager_v1 and calls the registered handlers. | |
| 141 | + | func (o *ForeignToplevelManager) Dispatch(event *wl.Event) { | |
| 142 | + | switch event.Opcode { | |
| 143 | + | case 0: // toplevel | |
| 144 | + | toplevelID := event.Uint32() | |
| 145 | + | toplevelObject := &ForeignToplevelHandle{} | |
| 146 | + | toplevelObject.SetContext(o.Context()) | |
| 147 | + | toplevelObject.SetID(toplevelID) | |
| 148 | + | toplevelObject.SetVersion(o.Version()) | |
| 149 | + | o.Context().Register(toplevelObject) | |
| 150 | + | ||
| 151 | + | for i, handler := range o.handlersForToplevel() { | |
| 152 | + | _ = i | |
| 153 | + | handler(toplevelObject) | |
| 154 | + | } | |
| 155 | + | case 1: // finished | |
| 156 | + | ||
| 157 | + | for i, handler := range o.handlersForFinished() { | |
| 158 | + | _ = i | |
| 159 | + | handler() | |
| 160 | + | } | |
| 161 | + | o.Context().Unregister(o) | |
| 162 | + | default: | |
| 163 | + | } | |
| 164 | + | } | |
| 165 | + | ||
| 166 | + | // ForeignToplevelHandleInterface is the protocol interface name. | |
| 167 | + | const ForeignToplevelHandleInterface = "zwlr_foreign_toplevel_handle_v1" | |
| 168 | + | ||
| 169 | + | // ForeignToplevelHandle is the generated binding for zwlr_foreign_toplevel_handle_v1 version 3. | |
| 170 | + | type ForeignToplevelHandle struct { | |
| 171 | + | wl.BaseProxy | |
| 172 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 173 | + | // handlers while another goroutine dispatches events. | |
| 174 | + | handlersMu sync.Mutex | |
| 175 | + | onTitle []func(title string) | |
| 176 | + | onAppId []func(appId string) | |
| 177 | + | onOutputEnter []func(outputID uint32) | |
| 178 | + | onOutputLeave []func(outputID uint32) | |
| 179 | + | onState []func(state []byte) | |
| 180 | + | onDone []func() | |
| 181 | + | onClosed []func() | |
| 182 | + | onParent []func(parentID uint32) | |
| 183 | + | } | |
| 184 | + | ||
| 185 | + | // NewForeignToplevelHandle returns an unbound ForeignToplevelHandle. | |
| 186 | + | func NewForeignToplevelHandle(ctx *wl.Context) *ForeignToplevelHandle { | |
| 187 | + | obj := &ForeignToplevelHandle{} | |
| 188 | + | obj.SetContext(ctx) | |
| 189 | + | ctx.Register(obj) | |
| 190 | + | return obj | |
| 191 | + | } | |
| 192 | + | ||
| 193 | + | // Requests that the toplevel be maximized. If the maximized state actually changes, this will be indicated by the state event. | |
| 194 | + | func (o *ForeignToplevelHandle) SetMaximized() error { | |
| 195 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_foreign_toplevel_handle_v1.set_maximized"}); err != nil { | |
| 196 | + | return err | |
| 197 | + | } | |
| 198 | + | return nil | |
| 199 | + | } | |
| 200 | + | ||
| 201 | + | // Requests that the toplevel be unmaximized. If the maximized state actually changes, this will be indicated by the state event. | |
| 202 | + | func (o *ForeignToplevelHandle) UnsetMaximized() error { | |
| 203 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwlr_foreign_toplevel_handle_v1.unset_maximized"}); err != nil { | |
| 204 | + | return err | |
| 205 | + | } | |
| 206 | + | return nil | |
| 207 | + | } | |
| 208 | + | ||
| 209 | + | // Requests that the toplevel be minimized. If the minimized state actually changes, this will be indicated by the state event. | |
| 210 | + | func (o *ForeignToplevelHandle) SetMinimized() error { | |
| 211 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwlr_foreign_toplevel_handle_v1.set_minimized"}); err != nil { | |
| 212 | + | return err | |
| 213 | + | } | |
| 214 | + | return nil | |
| 215 | + | } | |
| 216 | + | ||
| 217 | + | // Requests that the toplevel be unminimized. If the minimized state actually changes, this will be indicated by the state event. | |
| 218 | + | func (o *ForeignToplevelHandle) UnsetMinimized() error { | |
| 219 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "zwlr_foreign_toplevel_handle_v1.unset_minimized"}); err != nil { | |
| 220 | + | return err | |
| 221 | + | } | |
| 222 | + | return nil | |
| 223 | + | } | |
| 224 | + | ||
| 225 | + | // Request that this toplevel be activated on the given seat. There is no guarantee the toplevel will be actually activated. | |
| 226 | + | func (o *ForeignToplevelHandle) Activate(seat *cross_wl_seat.Seat) error { | |
| 227 | + | var arg0 wl.Object | |
| 228 | + | if seat != nil { | |
| 229 | + | arg0 = seat | |
| 230 | + | } | |
| 231 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 4, Name: "zwlr_foreign_toplevel_handle_v1.activate"}, wl.ArgObject(arg0)); err != nil { | |
| 232 | + | return err | |
| 233 | + | } | |
| 234 | + | return nil | |
| 235 | + | } | |
| 236 | + | ||
| 237 | + | // Send a request to the toplevel to close itself. The compositor would typically use a shell-specific method to carry out this request, for example by sending the xdg_toplevel.close event. However, this gives no guarantees the toplevel will actually be destroyed. If and when this happens, the zwlr_foreign_toplevel_handle_v1.closed event will be emitted. | |
| 238 | + | func (o *ForeignToplevelHandle) Close() error { | |
| 239 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 5, Name: "zwlr_foreign_toplevel_handle_v1.close"}); err != nil { | |
| 240 | + | return err | |
| 241 | + | } | |
| 242 | + | return nil | |
| 243 | + | } | |
| 244 | + | ||
| 245 | + | // The rectangle of the surface specified in this request corresponds to the place where the app using this protocol represents the given toplevel. It can be used by the compositor as a hint for some operations, e.g minimizing. The client is however not required to set this, in which case the compositor is free to decide some default value. If the client specifies more than one rectangle, only the last one is considered. The dimensions are given in surface-local coordinates. Setting width=height=0 removes the already-set rectangle. | |
| 246 | + | func (o *ForeignToplevelHandle) SetRectangle(surface *cross_wl_surface.Surface, x int32, y int32, width int32, height int32) error { | |
| 247 | + | var arg0 wl.Object | |
| 248 | + | if surface != nil { | |
| 249 | + | arg0 = surface | |
| 250 | + | } | |
| 251 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 6, Name: "zwlr_foreign_toplevel_handle_v1.set_rectangle"}, wl.ArgObject(arg0), wl.ArgInt(x), wl.ArgInt(y), wl.ArgInt(width), wl.ArgInt(height)); err != nil { | |
| 252 | + | return err | |
| 253 | + | } | |
| 254 | + | return nil | |
| 255 | + | } | |
| 256 | + | ||
| 257 | + | // Destroys the zwlr_foreign_toplevel_handle_v1 object. This request should be called either when the client does not want to use the toplevel anymore or after the closed event to finalize the destruction of the object. | |
| 258 | + | func (o *ForeignToplevelHandle) Destroy() error { | |
| 259 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 7, Name: "zwlr_foreign_toplevel_handle_v1.destroy", Destructor: true}); err != nil { | |
| 260 | + | return err | |
| 261 | + | } | |
| 262 | + | return nil | |
| 263 | + | } | |
| 264 | + | ||
| 265 | + | // Requests that the toplevel be fullscreened on the given output. If the fullscreen state and/or the outputs the toplevel is visible on actually change, this will be indicated by the state and output_enter/leave events. The output parameter is only a hint to the compositor. Also, if output is NULL, the compositor should decide which output the toplevel will be fullscreened on, if at all. | |
| 266 | + | func (o *ForeignToplevelHandle) SetFullscreen(output *cross_wl_output.Output) error { | |
| 267 | + | var arg0 wl.Object | |
| 268 | + | if output != nil { | |
| 269 | + | arg0 = output | |
| 270 | + | } | |
| 271 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 8, Name: "zwlr_foreign_toplevel_handle_v1.set_fullscreen", Since: 2}, wl.ArgObject(arg0)); err != nil { | |
| 272 | + | return err | |
| 273 | + | } | |
| 274 | + | return nil | |
| 275 | + | } | |
| 276 | + | ||
| 277 | + | // Requests that the toplevel be unfullscreened. If the fullscreen state actually changes, this will be indicated by the state event. | |
| 278 | + | func (o *ForeignToplevelHandle) UnsetFullscreen() error { | |
| 279 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 9, Name: "zwlr_foreign_toplevel_handle_v1.unset_fullscreen", Since: 2}); err != nil { | |
| 280 | + | return err | |
| 281 | + | } | |
| 282 | + | return nil | |
| 283 | + | } | |
| 284 | + | ||
| 285 | + | // OnTitle registers a handler for the title event. | |
| 286 | + | // | |
| 287 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 288 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 289 | + | func (o *ForeignToplevelHandle) OnTitle(handler func(title string)) { | |
| 290 | + | if handler == nil { | |
| 291 | + | return | |
| 292 | + | } | |
| 293 | + | o.handlersMu.Lock() | |
| 294 | + | defer o.handlersMu.Unlock() | |
| 295 | + | o.onTitle = append(o.onTitle, handler) | |
| 296 | + | } | |
| 297 | + | ||
| 298 | + | // handlersForTitle returns the handlers registered for title, taken | |
| 299 | + | // under the lock so a handler may register another handler while events are | |
| 300 | + | // being dispatched. | |
| 301 | + | func (o *ForeignToplevelHandle) handlersForTitle() []func(title string) { | |
| 302 | + | o.handlersMu.Lock() | |
| 303 | + | defer o.handlersMu.Unlock() | |
| 304 | + | return o.onTitle | |
| 305 | + | } | |
| 306 | + | ||
| 307 | + | // OnAppId registers a handler for the app_id event. | |
| 308 | + | // | |
| 309 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 310 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 311 | + | func (o *ForeignToplevelHandle) OnAppId(handler func(appId string)) { | |
| 312 | + | if handler == nil { | |
| 313 | + | return | |
| 314 | + | } | |
| 315 | + | o.handlersMu.Lock() | |
| 316 | + | defer o.handlersMu.Unlock() | |
| 317 | + | o.onAppId = append(o.onAppId, handler) | |
| 318 | + | } | |
| 319 | + | ||
| 320 | + | // handlersForAppId returns the handlers registered for app_id, taken | |
| 321 | + | // under the lock so a handler may register another handler while events are | |
| 322 | + | // being dispatched. | |
| 323 | + | func (o *ForeignToplevelHandle) handlersForAppId() []func(appId string) { | |
| 324 | + | o.handlersMu.Lock() | |
| 325 | + | defer o.handlersMu.Unlock() | |
| 326 | + | return o.onAppId | |
| 327 | + | } | |
| 328 | + | ||
| 329 | + | // OnOutputEnter registers a handler for the output_enter event. | |
| 330 | + | // | |
| 331 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 332 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 333 | + | func (o *ForeignToplevelHandle) OnOutputEnter(handler func(outputID uint32)) { | |
| 334 | + | if handler == nil { | |
| 335 | + | return | |
| 336 | + | } | |
| 337 | + | o.handlersMu.Lock() | |
| 338 | + | defer o.handlersMu.Unlock() | |
| 339 | + | o.onOutputEnter = append(o.onOutputEnter, handler) | |
| 340 | + | } | |
| 341 | + | ||
| 342 | + | // handlersForOutputEnter returns the handlers registered for output_enter, taken | |
| 343 | + | // under the lock so a handler may register another handler while events are | |
| 344 | + | // being dispatched. | |
| 345 | + | func (o *ForeignToplevelHandle) handlersForOutputEnter() []func(outputID uint32) { | |
| 346 | + | o.handlersMu.Lock() | |
| 347 | + | defer o.handlersMu.Unlock() | |
| 348 | + | return o.onOutputEnter | |
| 349 | + | } | |
| 350 | + | ||
| 351 | + | // OnOutputLeave registers a handler for the output_leave event. | |
| 352 | + | // | |
| 353 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 354 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 355 | + | func (o *ForeignToplevelHandle) OnOutputLeave(handler func(outputID uint32)) { | |
| 356 | + | if handler == nil { | |
| 357 | + | return | |
| 358 | + | } | |
| 359 | + | o.handlersMu.Lock() | |
| 360 | + | defer o.handlersMu.Unlock() | |
| 361 | + | o.onOutputLeave = append(o.onOutputLeave, handler) | |
| 362 | + | } | |
| 363 | + | ||
| 364 | + | // handlersForOutputLeave returns the handlers registered for output_leave, taken | |
| 365 | + | // under the lock so a handler may register another handler while events are | |
| 366 | + | // being dispatched. | |
| 367 | + | func (o *ForeignToplevelHandle) handlersForOutputLeave() []func(outputID uint32) { | |
| 368 | + | o.handlersMu.Lock() | |
| 369 | + | defer o.handlersMu.Unlock() | |
| 370 | + | return o.onOutputLeave | |
| 371 | + | } | |
| 372 | + | ||
| 373 | + | // OnState registers a handler for the state event. | |
| 374 | + | // | |
| 375 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 376 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 377 | + | func (o *ForeignToplevelHandle) OnState(handler func(state []byte)) { | |
| 378 | + | if handler == nil { | |
| 379 | + | return | |
| 380 | + | } | |
| 381 | + | o.handlersMu.Lock() | |
| 382 | + | defer o.handlersMu.Unlock() | |
| 383 | + | o.onState = append(o.onState, handler) | |
| 384 | + | } | |
| 385 | + | ||
| 386 | + | // handlersForState returns the handlers registered for state, taken | |
| 387 | + | // under the lock so a handler may register another handler while events are | |
| 388 | + | // being dispatched. | |
| 389 | + | func (o *ForeignToplevelHandle) handlersForState() []func(state []byte) { | |
| 390 | + | o.handlersMu.Lock() | |
| 391 | + | defer o.handlersMu.Unlock() | |
| 392 | + | return o.onState | |
| 393 | + | } | |
| 394 | + | ||
| 395 | + | // OnDone registers a handler for the done event. | |
| 396 | + | // | |
| 397 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 398 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 399 | + | func (o *ForeignToplevelHandle) OnDone(handler func()) { | |
| 400 | + | if handler == nil { | |
| 401 | + | return | |
| 402 | + | } | |
| 403 | + | o.handlersMu.Lock() | |
| 404 | + | defer o.handlersMu.Unlock() | |
| 405 | + | o.onDone = append(o.onDone, handler) | |
| 406 | + | } | |
| 407 | + | ||
| 408 | + | // handlersForDone returns the handlers registered for done, taken | |
| 409 | + | // under the lock so a handler may register another handler while events are | |
| 410 | + | // being dispatched. | |
| 411 | + | func (o *ForeignToplevelHandle) handlersForDone() []func() { | |
| 412 | + | o.handlersMu.Lock() | |
| 413 | + | defer o.handlersMu.Unlock() | |
| 414 | + | return o.onDone | |
| 415 | + | } | |
| 416 | + | ||
| 417 | + | // OnClosed registers a handler for the closed event. | |
| 418 | + | // | |
| 419 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 420 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 421 | + | func (o *ForeignToplevelHandle) OnClosed(handler func()) { | |
| 422 | + | if handler == nil { | |
| 423 | + | return | |
| 424 | + | } | |
| 425 | + | o.handlersMu.Lock() | |
| 426 | + | defer o.handlersMu.Unlock() | |
| 427 | + | o.onClosed = append(o.onClosed, handler) | |
| 428 | + | } | |
| 429 | + | ||
| 430 | + | // handlersForClosed returns the handlers registered for closed, taken | |
| 431 | + | // under the lock so a handler may register another handler while events are | |
| 432 | + | // being dispatched. | |
| 433 | + | func (o *ForeignToplevelHandle) handlersForClosed() []func() { | |
| 434 | + | o.handlersMu.Lock() | |
| 435 | + | defer o.handlersMu.Unlock() | |
| 436 | + | return o.onClosed | |
| 437 | + | } | |
| 438 | + | ||
| 439 | + | // OnParent registers a handler for the parent event. | |
| 440 | + | // | |
| 441 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 442 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 443 | + | func (o *ForeignToplevelHandle) OnParent(handler func(parentID uint32)) { | |
| 444 | + | if handler == nil { | |
| 445 | + | return | |
| 446 | + | } | |
| 447 | + | o.handlersMu.Lock() | |
| 448 | + | defer o.handlersMu.Unlock() | |
| 449 | + | o.onParent = append(o.onParent, handler) | |
| 450 | + | } | |
| 451 | + | ||
| 452 | + | // handlersForParent returns the handlers registered for parent, taken | |
| 453 | + | // under the lock so a handler may register another handler while events are | |
| 454 | + | // being dispatched. | |
| 455 | + | func (o *ForeignToplevelHandle) handlersForParent() []func(parentID uint32) { | |
| 456 | + | o.handlersMu.Lock() | |
| 457 | + | defer o.handlersMu.Unlock() | |
| 458 | + | return o.onParent | |
| 459 | + | } | |
| 460 | + | ||
| 461 | + | // EventSignature returns the declared event argument types in wire order. | |
| 462 | + | func (o *ForeignToplevelHandle) EventSignature(opcode uint16) (string, bool) { | |
| 463 | + | switch opcode { | |
| 464 | + | case 0: | |
| 465 | + | return "string,", true | |
| 466 | + | case 1: | |
| 467 | + | return "string,", true | |
| 468 | + | case 2: | |
| 469 | + | return "object,", true | |
| 470 | + | case 3: | |
| 471 | + | return "object,", true | |
| 472 | + | case 4: | |
| 473 | + | return "array,", true | |
| 474 | + | case 5: | |
| 475 | + | return "", true | |
| 476 | + | case 6: | |
| 477 | + | return "", true | |
| 478 | + | case 7: | |
| 479 | + | return "object,", true | |
| 480 | + | default: | |
| 481 | + | return "", false | |
| 482 | + | } | |
| 483 | + | } | |
| 484 | + | ||
| 485 | + | // Dispatch decodes one event on zwlr_foreign_toplevel_handle_v1 and calls the registered handlers. | |
| 486 | + | func (o *ForeignToplevelHandle) Dispatch(event *wl.Event) { | |
| 487 | + | switch event.Opcode { | |
| 488 | + | case 0: // title | |
| 489 | + | title := event.String() | |
| 490 | + | ||
| 491 | + | for i, handler := range o.handlersForTitle() { | |
| 492 | + | _ = i | |
| 493 | + | handler(title) | |
| 494 | + | } | |
| 495 | + | case 1: // app_id | |
| 496 | + | appId := event.String() | |
| 497 | + | ||
| 498 | + | for i, handler := range o.handlersForAppId() { | |
| 499 | + | _ = i | |
| 500 | + | handler(appId) | |
| 501 | + | } | |
| 502 | + | case 2: // output_enter | |
| 503 | + | outputID := event.Uint32() | |
| 504 | + | ||
| 505 | + | for i, handler := range o.handlersForOutputEnter() { | |
| 506 | + | _ = i | |
| 507 | + | handler(outputID) | |
| 508 | + | } | |
| 509 | + | case 3: // output_leave | |
| 510 | + | outputID := event.Uint32() | |
| 511 | + | ||
| 512 | + | for i, handler := range o.handlersForOutputLeave() { | |
| 513 | + | _ = i | |
| 514 | + | handler(outputID) | |
| 515 | + | } | |
| 516 | + | case 4: // state | |
| 517 | + | state := event.Array() | |
| 518 | + | ||
| 519 | + | for i, handler := range o.handlersForState() { | |
| 520 | + | _ = i | |
| 521 | + | handler(state) | |
| 522 | + | } | |
| 523 | + | case 5: // done | |
| 524 | + | ||
| 525 | + | for i, handler := range o.handlersForDone() { | |
| 526 | + | _ = i | |
| 527 | + | handler() | |
| 528 | + | } | |
| 529 | + | case 6: // closed | |
| 530 | + | ||
| 531 | + | for i, handler := range o.handlersForClosed() { | |
| 532 | + | _ = i | |
| 533 | + | handler() | |
| 534 | + | } | |
| 535 | + | case 7: // parent | |
| 536 | + | parentID := event.Uint32() | |
| 537 | + | ||
| 538 | + | for i, handler := range o.handlersForParent() { | |
| 539 | + | _ = i | |
| 540 | + | handler(parentID) | |
| 541 | + | } | |
| 542 | + | default: | |
| 543 | + | } | |
| 544 | + | } | |
M protocol/fractionalscale/fractional-scale-v1_generated.go +25 -3
| @@ -2,6 +2,28 @@ | |||
| 2 | 2 | // Protocol: fractional_scale_v1 | |
| 3 | 3 | // Source: fractional-scale-v1.xml | |
| 4 | 4 | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2022 Kenny Levinsen | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 5 | 27 | package fractionalscale | |
| 6 | 28 | ||
| 7 | 29 | import ( | |
| @@ -32,7 +54,7 @@ func NewWpFractionalScaleManager(ctx *wl.Context) *WpFractionalScaleManager { | |||
| 32 | 54 | ||
| 33 | 55 | // Informs the server that the client will not be using this protocol object anymore. This does not affect any other objects, wp_fractional_scale_v1 objects included. | |
| 34 | 56 | func (o *WpFractionalScaleManager) Destroy() error { | |
| 35 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_fractional_scale_manager_v1.destroy", Destructor: true}); err != nil { | |
| 57 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_fractional_scale_manager_v1.destroy", Destructor: true}); err != nil { | |
| 36 | 58 | return err | |
| 37 | 59 | } | |
| 38 | 60 | return nil | |
| @@ -46,7 +68,7 @@ func (o *WpFractionalScaleManager) GetFractionalScale(surface *cross_wl_surface. | |||
| 46 | 68 | } | |
| 47 | 69 | child := &WpFractionalScale{} | |
| 48 | 70 | child.SetContext(o.Context()) | |
| 49 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wp_fractional_scale_manager_v1.get_fractional_scale", Child: child}, child, arg1); err != nil { | |
| 71 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_fractional_scale_manager_v1.get_fractional_scale", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 50 | 72 | return nil, err | |
| 51 | 73 | } | |
| 52 | 74 | return child, nil | |
| @@ -89,7 +111,7 @@ func NewWpFractionalScale(ctx *wl.Context) *WpFractionalScale { | |||
| 89 | 111 | ||
| 90 | 112 | // Destroy the fractional scale object. When this object is destroyed, preferred_scale events will no longer be sent. | |
| 91 | 113 | func (o *WpFractionalScale) Destroy() error { | |
| 92 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_fractional_scale_v1.destroy", Destructor: true}); err != nil { | |
| 114 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_fractional_scale_v1.destroy", Destructor: true}); err != nil { | |
| 93 | 115 | return err | |
| 94 | 116 | } | |
| 95 | 117 | return nil | |
A protocol/headless_extensions_test.go +430 -0
| @@ -0,0 +1,430 @@ | |||
| 1 | + | //go:build linux | |
| 2 | + | ||
| 3 | + | package protocol_test | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "fmt" | |
| 7 | + | "sort" | |
| 8 | + | "testing" | |
| 9 | + | ||
| 10 | + | "github.com/bnema/wlturbo" | |
| 11 | + | "github.com/bnema/wlturbo/protocol/alphamodifier" | |
| 12 | + | "github.com/bnema/wlturbo/protocol/colormanagement" | |
| 13 | + | "github.com/bnema/wlturbo/protocol/colorrepresentation" | |
| 14 | + | "github.com/bnema/wlturbo/protocol/committiming" | |
| 15 | + | "github.com/bnema/wlturbo/protocol/contenttype" | |
| 16 | + | "github.com/bnema/wlturbo/protocol/core" | |
| 17 | + | "github.com/bnema/wlturbo/protocol/cursorshape" | |
| 18 | + | "github.com/bnema/wlturbo/protocol/datacontrol" | |
| 19 | + | "github.com/bnema/wlturbo/protocol/drmlease" | |
| 20 | + | "github.com/bnema/wlturbo/protocol/drmsyncobj" | |
| 21 | + | "github.com/bnema/wlturbo/protocol/extforeigntoplevel" | |
| 22 | + | "github.com/bnema/wlturbo/protocol/fifo" | |
| 23 | + | "github.com/bnema/wlturbo/protocol/foreigntoplevel" | |
| 24 | + | "github.com/bnema/wlturbo/protocol/fractionalscale" | |
| 25 | + | "github.com/bnema/wlturbo/protocol/idleinhibit" | |
| 26 | + | "github.com/bnema/wlturbo/protocol/idlenotify" | |
| 27 | + | "github.com/bnema/wlturbo/protocol/imagecapturesource" | |
| 28 | + | "github.com/bnema/wlturbo/protocol/imagecopycapture" | |
| 29 | + | "github.com/bnema/wlturbo/protocol/inputmethod" | |
| 30 | + | "github.com/bnema/wlturbo/protocol/kdeserverdecoration" | |
| 31 | + | "github.com/bnema/wlturbo/protocol/layershell" | |
| 32 | + | "github.com/bnema/wlturbo/protocol/linuxdmabuf" | |
| 33 | + | "github.com/bnema/wlturbo/protocol/outputmanagement" | |
| 34 | + | "github.com/bnema/wlturbo/protocol/outputpower" | |
| 35 | + | "github.com/bnema/wlturbo/protocol/pointerconstraints" | |
| 36 | + | "github.com/bnema/wlturbo/protocol/pointerwarp" | |
| 37 | + | "github.com/bnema/wlturbo/protocol/presentation" | |
| 38 | + | "github.com/bnema/wlturbo/protocol/primaryselection" | |
| 39 | + | "github.com/bnema/wlturbo/protocol/relativepointer" | |
| 40 | + | "github.com/bnema/wlturbo/protocol/screencopy" | |
| 41 | + | "github.com/bnema/wlturbo/protocol/shortcutsinhibit" | |
| 42 | + | "github.com/bnema/wlturbo/protocol/tablet" | |
| 43 | + | "github.com/bnema/wlturbo/protocol/tearingcontrol" | |
| 44 | + | "github.com/bnema/wlturbo/protocol/textinput" | |
| 45 | + | "github.com/bnema/wlturbo/protocol/viewporter" | |
| 46 | + | "github.com/bnema/wlturbo/protocol/virtualkeyboard" | |
| 47 | + | "github.com/bnema/wlturbo/protocol/workspace" | |
| 48 | + | "github.com/bnema/wlturbo/protocol/xdgactivation" | |
| 49 | + | "github.com/bnema/wlturbo/protocol/xdgdecoration" | |
| 50 | + | "github.com/bnema/wlturbo/protocol/xdgoutput" | |
| 51 | + | "github.com/bnema/wlturbo/protocol/xdgshell" | |
| 52 | + | "golang.org/x/sys/unix" | |
| 53 | + | ) | |
| 54 | + | ||
| 55 | + | // headlessBinding is one generated root object and the highest version its | |
| 56 | + | // package supports (the XML interface version). | |
| 57 | + | type headlessBinding struct { | |
| 58 | + | iface string | |
| 59 | + | supported uint32 | |
| 60 | + | make func(*wlturbo.Context) wlturbo.Proxy | |
| 61 | + | // optional marks globals that depend on GPU, DRM or input devices, or that | |
| 62 | + | // this NeferWL build does not advertise headless: absence is logged, not | |
| 63 | + | // a failure. Everything else must be announced. | |
| 64 | + | optional bool | |
| 65 | + | } | |
| 66 | + | ||
| 67 | + | func headlessBindings() []headlessBinding { | |
| 68 | + | return []headlessBinding{ | |
| 69 | + | {core.CompositorInterface, 7, func(c *wlturbo.Context) wlturbo.Proxy { return core.NewCompositor(c) }, false}, | |
| 70 | + | {core.SubcompositorInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return core.NewSubcompositor(c) }, false}, | |
| 71 | + | {core.ShmInterface, 3, func(c *wlturbo.Context) wlturbo.Proxy { return core.NewShm(c) }, false}, | |
| 72 | + | {core.SeatInterface, 11, func(c *wlturbo.Context) wlturbo.Proxy { return core.NewSeat(c) }, false}, | |
| 73 | + | {core.OutputInterface, 4, func(c *wlturbo.Context) wlturbo.Proxy { return core.NewOutput(c) }, false}, | |
| 74 | + | {core.DataDeviceManagerInterface, 4, func(c *wlturbo.Context) wlturbo.Proxy { return core.NewDataDeviceManager(c) }, false}, | |
| 75 | + | {xdgshell.XdgWmBaseInterface, 7, func(c *wlturbo.Context) wlturbo.Proxy { return xdgshell.NewXdgWmBase(c) }, false}, | |
| 76 | + | {linuxdmabuf.LinuxDmabufInterface, 6, func(c *wlturbo.Context) wlturbo.Proxy { return linuxdmabuf.NewLinuxDmabuf(c) }, true}, | |
| 77 | + | {drmsyncobj.WpLinuxDrmSyncobjManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return drmsyncobj.NewWpLinuxDrmSyncobjManager(c) }, true}, | |
| 78 | + | {viewporter.WpViewporterInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return viewporter.NewWpViewporter(c) }, false}, | |
| 79 | + | {fractionalscale.WpFractionalScaleManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return fractionalscale.NewWpFractionalScaleManager(c) }, false}, | |
| 80 | + | {cursorshape.WpCursorShapeManagerInterface, 2, func(c *wlturbo.Context) wlturbo.Proxy { return cursorshape.NewWpCursorShapeManager(c) }, false}, | |
| 81 | + | {tablet.TabletManagerInterface, 2, func(c *wlturbo.Context) wlturbo.Proxy { return tablet.NewTabletManager(c) }, true}, | |
| 82 | + | {textinput.TextInputManagerV3Interface, 2, func(c *wlturbo.Context) wlturbo.Proxy { return textinput.NewTextInputManagerV3(c) }, false}, | |
| 83 | + | {alphamodifier.WpAlphaModifierInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return alphamodifier.NewWpAlphaModifier(c) }, false}, | |
| 84 | + | {colormanagement.WpColorManagerInterface, 3, func(c *wlturbo.Context) wlturbo.Proxy { return colormanagement.NewWpColorManager(c) }, false}, | |
| 85 | + | {colorrepresentation.WpColorRepresentationManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return colorrepresentation.NewWpColorRepresentationManager(c) }, false}, | |
| 86 | + | {committiming.WpCommitTimingManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return committiming.NewWpCommitTimingManager(c) }, false}, | |
| 87 | + | {contenttype.WpContentTypeManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return contenttype.NewWpContentTypeManager(c) }, false}, | |
| 88 | + | {datacontrol.ExtDataControlManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return datacontrol.NewExtDataControlManager(c) }, false}, | |
| 89 | + | {drmlease.WpDrmLeaseDeviceInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return drmlease.NewWpDrmLeaseDevice(c) }, true}, | |
| 90 | + | {extforeigntoplevel.ExtForeignToplevelListInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return extforeigntoplevel.NewExtForeignToplevelList(c) }, true}, | |
| 91 | + | {fifo.WpFifoManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return fifo.NewWpFifoManager(c) }, false}, | |
| 92 | + | {foreigntoplevel.ForeignToplevelManagerInterface, 3, func(c *wlturbo.Context) wlturbo.Proxy { return foreigntoplevel.NewForeignToplevelManager(c) }, false}, | |
| 93 | + | {idleinhibit.IdleInhibitManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return idleinhibit.NewIdleInhibitManager(c) }, false}, | |
| 94 | + | {idlenotify.ExtIdleNotifierInterface, 2, func(c *wlturbo.Context) wlturbo.Proxy { return idlenotify.NewExtIdleNotifier(c) }, false}, | |
| 95 | + | {imagecapturesource.ExtOutputImageCaptureSourceManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { | |
| 96 | + | return imagecapturesource.NewExtOutputImageCaptureSourceManager(c) | |
| 97 | + | }, false}, | |
| 98 | + | {imagecapturesource.ExtForeignToplevelImageCaptureSourceManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { | |
| 99 | + | return imagecapturesource.NewExtForeignToplevelImageCaptureSourceManager(c) | |
| 100 | + | }, true}, | |
| 101 | + | {imagecopycapture.ExtImageCopyCaptureManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return imagecopycapture.NewExtImageCopyCaptureManager(c) }, false}, | |
| 102 | + | {inputmethod.InputMethodManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return inputmethod.NewInputMethodManager(c) }, false}, | |
| 103 | + | {kdeserverdecoration.OrgKdeKwinServerDecorationManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { | |
| 104 | + | return kdeserverdecoration.NewOrgKdeKwinServerDecorationManager(c) | |
| 105 | + | }, false}, | |
| 106 | + | {layershell.LayerShellInterface, 5, func(c *wlturbo.Context) wlturbo.Proxy { return layershell.NewLayerShell(c) }, false}, | |
| 107 | + | {outputmanagement.OutputManagerInterface, 4, func(c *wlturbo.Context) wlturbo.Proxy { return outputmanagement.NewOutputManager(c) }, false}, | |
| 108 | + | {outputpower.OutputPowerManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return outputpower.NewOutputPowerManager(c) }, false}, | |
| 109 | + | {pointerconstraints.PointerConstraintsInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return pointerconstraints.NewPointerConstraints(c) }, false}, | |
| 110 | + | {pointerwarp.WpPointerWarpInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return pointerwarp.NewWpPointerWarp(c) }, false}, | |
| 111 | + | {presentation.WpPresentationInterface, 2, func(c *wlturbo.Context) wlturbo.Proxy { return presentation.NewWpPresentation(c) }, false}, | |
| 112 | + | {primaryselection.PrimarySelectionDeviceManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return primaryselection.NewPrimarySelectionDeviceManager(c) }, false}, | |
| 113 | + | {relativepointer.RelativePointerManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return relativepointer.NewRelativePointerManager(c) }, false}, | |
| 114 | + | {screencopy.ScreencopyManagerInterface, 3, func(c *wlturbo.Context) wlturbo.Proxy { return screencopy.NewScreencopyManager(c) }, false}, | |
| 115 | + | {shortcutsinhibit.KeyboardShortcutsInhibitManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return shortcutsinhibit.NewKeyboardShortcutsInhibitManager(c) }, false}, | |
| 116 | + | {tearingcontrol.WpTearingControlManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return tearingcontrol.NewWpTearingControlManager(c) }, false}, | |
| 117 | + | {virtualkeyboard.VirtualKeyboardManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return virtualkeyboard.NewVirtualKeyboardManager(c) }, false}, | |
| 118 | + | {workspace.ExtWorkspaceManagerInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return workspace.NewExtWorkspaceManager(c) }, false}, | |
| 119 | + | {xdgactivation.XdgActivationInterface, 1, func(c *wlturbo.Context) wlturbo.Proxy { return xdgactivation.NewXdgActivation(c) }, false}, | |
| 120 | + | {xdgdecoration.ZxdgDecorationManagerInterface, 2, func(c *wlturbo.Context) wlturbo.Proxy { return xdgdecoration.NewZxdgDecorationManager(c) }, false}, | |
| 121 | + | {xdgoutput.ZxdgOutputManagerInterface, 3, func(c *wlturbo.Context) wlturbo.Proxy { return xdgoutput.NewZxdgOutputManager(c) }, false}, | |
| 122 | + | } | |
| 123 | + | } | |
| 124 | + | ||
| 125 | + | // waitGlobal blocks in Dispatch until iface is announced. wl_output is added | |
| 126 | + | // by the compositor after startup, so it can follow the first roundtrip. The | |
| 127 | + | // instance context ends a wait that never completes. | |
| 128 | + | func (h *headlessInstance) waitGlobal(t *testing.T, d *wlturbo.Display, iface string) { | |
| 129 | + | t.Helper() | |
| 130 | + | for { | |
| 131 | + | if _, ok := d.Registry().FindGlobal(iface); ok { | |
| 132 | + | return | |
| 133 | + | } | |
| 134 | + | if e := d.Dispatch(); e != nil { | |
| 135 | + | t.Fatalf("waiting for %s: %v (ctx %v)\n%s", iface, e, h.ctx.Err(), h.Log()) | |
| 136 | + | } | |
| 137 | + | } | |
| 138 | + | } | |
| 139 | + | ||
| 140 | + | // bindOne binds a global at its negotiated version and fails on any error. | |
| 141 | + | func (h *headlessInstance) bindOne(t *testing.T, d *wlturbo.Display, iface string, supported uint32, p wlturbo.Proxy) uint32 { | |
| 142 | + | t.Helper() | |
| 143 | + | v, e := d.Registry().BindNegotiated(iface, supported, p) | |
| 144 | + | if e != nil { | |
| 145 | + | t.Fatalf("bind %s: %v\n%s", iface, e, h.Log()) | |
| 146 | + | } | |
| 147 | + | return v | |
| 148 | + | } | |
| 149 | + | ||
| 150 | + | func TestHeadlessExtensions(t *testing.T) { | |
| 151 | + | h := startHeadless(t) | |
| 152 | + | ||
| 153 | + | t.Run("bind announced globals", func(t *testing.T) { | |
| 154 | + | d := h.connect(t) | |
| 155 | + | h.waitGlobal(t, d, core.OutputInterface) | |
| 156 | + | for _, b := range headlessBindings() { | |
| 157 | + | g, ok := d.Registry().FindGlobal(b.iface) | |
| 158 | + | if !ok { | |
| 159 | + | if b.optional { | |
| 160 | + | t.Logf("%s absent (optional: hardware, device or build dependent)", b.iface) | |
| 161 | + | } else { | |
| 162 | + | t.Errorf("%s not announced", b.iface) | |
| 163 | + | } | |
| 164 | + | continue | |
| 165 | + | } | |
| 166 | + | p := b.make(d.Context()) | |
| 167 | + | v, e := d.Registry().BindNegotiated(b.iface, b.supported, p) | |
| 168 | + | if e != nil { | |
| 169 | + | t.Errorf("bind %s: %v", b.iface, e) | |
| 170 | + | continue | |
| 171 | + | } | |
| 172 | + | want := min(g.Version, b.supported) | |
| 173 | + | if v != want || v == 0 { | |
| 174 | + | t.Errorf("%s negotiated %d, announced %d supported %d", b.iface, v, g.Version, b.supported) | |
| 175 | + | } | |
| 176 | + | if pv, ok := p.(interface{ Version() uint32 }); ok && pv.Version() != v { | |
| 177 | + | t.Errorf("%s proxy version %d, negotiated %d", b.iface, pv.Version(), v) | |
| 178 | + | } | |
| 179 | + | t.Logf("%s announced=%d supported=%d negotiated=%d", b.iface, g.Version, b.supported, v) | |
| 180 | + | } | |
| 181 | + | // Every bind request is validated by the compositor before this returns. | |
| 182 | + | h.sync(t, d, "bind all") | |
| 183 | + | // Report announced globals that no generated package covers. | |
| 184 | + | known := map[string]bool{"wl_fixes": true} | |
| 185 | + | for _, b := range headlessBindings() { | |
| 186 | + | known[b.iface] = true | |
| 187 | + | } | |
| 188 | + | var extra []string | |
| 189 | + | for _, g := range d.Registry().GetGlobals() { | |
| 190 | + | if !known[g.Interface] { | |
| 191 | + | extra = append(extra, g.Interface) | |
| 192 | + | } | |
| 193 | + | } | |
| 194 | + | sort.Strings(extra) | |
| 195 | + | t.Logf("announced without a client binding: %v", extra) | |
| 196 | + | }) | |
| 197 | + | ||
| 198 | + | t.Run("output description", func(t *testing.T) { | |
| 199 | + | d := h.connect(t) | |
| 200 | + | h.waitGlobal(t, d, core.OutputInterface) | |
| 201 | + | out := core.NewOutput(d.Context()) | |
| 202 | + | h.bindOne(t, d, core.OutputInterface, 4, out) | |
| 203 | + | xm := xdgoutput.NewZxdgOutputManager(d.Context()) | |
| 204 | + | h.bindOne(t, d, xdgoutput.ZxdgOutputManagerInterface, 3, xm) | |
| 205 | + | xo, e := xm.GetXdgOutput(out) | |
| 206 | + | noerr(t, e) | |
| 207 | + | var lw, lh int32 | |
| 208 | + | var name string | |
| 209 | + | var wlDone, xdgDone bool | |
| 210 | + | var modes int | |
| 211 | + | out.OnMode(func(flags uint32, w, h, refresh int32) { modes++ }) | |
| 212 | + | out.OnDone(func() { wlDone = true }) | |
| 213 | + | xo.OnLogicalSize(func(w, h int32) { lw, lh = w, h }) | |
| 214 | + | xo.OnName(func(n string) { name = n }) | |
| 215 | + | xo.OnDone(func() { xdgDone = true }) | |
| 216 | + | // Registered after the bind request but before any event is read. | |
| 217 | + | h.sync(t, d, "xdg_output") | |
| 218 | + | if lw != 640 || lh != 480 || name == "" || modes == 0 || !(wlDone || xdgDone) { | |
| 219 | + | t.Fatalf("logical=%dx%d name=%q modes=%d wl_done=%t xdg_done=%t\n%s", lw, lh, name, modes, wlDone, xdgDone, h.Log()) | |
| 220 | + | } | |
| 221 | + | t.Logf("output %q logical %dx%d", name, lw, lh) | |
| 222 | + | ||
| 223 | + | // wlr-output-management lists the same output as a head with modes. | |
| 224 | + | om := outputmanagement.NewOutputManager(d.Context()) | |
| 225 | + | h.bindOne(t, d, outputmanagement.OutputManagerInterface, 4, om) | |
| 226 | + | // Head events arrive in any order, so each head keeps its own record. | |
| 227 | + | type head struct { | |
| 228 | + | name string | |
| 229 | + | modes int | |
| 230 | + | } | |
| 231 | + | var heads []*head | |
| 232 | + | done := false | |
| 233 | + | om.OnHead(func(hd *outputmanagement.OutputHead) { | |
| 234 | + | rec := &head{} | |
| 235 | + | heads = append(heads, rec) | |
| 236 | + | hd.OnName(func(s string) { rec.name = s }) | |
| 237 | + | hd.OnMode(func(*outputmanagement.OutputMode) { rec.modes++ }) | |
| 238 | + | }) | |
| 239 | + | om.OnDone(func(serial uint32) { done = true }) | |
| 240 | + | h.sync(t, d, "output manager") | |
| 241 | + | found := false | |
| 242 | + | for _, rec := range heads { | |
| 243 | + | found = found || (rec.name == name && rec.modes > 0) | |
| 244 | + | } | |
| 245 | + | if !done || !found { | |
| 246 | + | t.Fatalf("done=%t want head %q with modes; heads:%s\n%s", done, name, func() (s string) { | |
| 247 | + | for _, rec := range heads { | |
| 248 | + | s += fmt.Sprintf(" %q/%d", rec.name, rec.modes) | |
| 249 | + | } | |
| 250 | + | return | |
| 251 | + | }(), h.Log()) | |
| 252 | + | } | |
| 253 | + | noerr(t, xo.Destroy()) | |
| 254 | + | noerr(t, om.Stop()) | |
| 255 | + | h.sync(t, d, "output teardown") | |
| 256 | + | }) | |
| 257 | + | ||
| 258 | + | t.Run("decoration negotiation", func(t *testing.T) { | |
| 259 | + | d := h.connect(t) | |
| 260 | + | compositor := core.NewCompositor(d.Context()) | |
| 261 | + | h.bindOne(t, d, core.CompositorInterface, 6, compositor) | |
| 262 | + | wm := xdgshell.NewXdgWmBase(d.Context()) | |
| 263 | + | h.bindOne(t, d, xdgshell.XdgWmBaseInterface, 6, wm) | |
| 264 | + | dm := xdgdecoration.NewZxdgDecorationManager(d.Context()) | |
| 265 | + | h.bindOne(t, d, xdgdecoration.ZxdgDecorationManagerInterface, 2, dm) | |
| 266 | + | kde := kdeserverdecoration.NewOrgKdeKwinServerDecorationManager(d.Context()) | |
| 267 | + | var kdeDefault uint32 = 99 | |
| 268 | + | kde.OnDefaultMode(func(m uint32) { kdeDefault = m }) | |
| 269 | + | h.bindOne(t, d, kdeserverdecoration.OrgKdeKwinServerDecorationManagerInterface, 1, kde) | |
| 270 | + | ||
| 271 | + | surface, e := compositor.CreateSurface() | |
| 272 | + | noerr(t, e) | |
| 273 | + | xs, e := wm.GetXdgSurface(surface) | |
| 274 | + | noerr(t, e) | |
| 275 | + | top, e := xs.GetToplevel() | |
| 276 | + | noerr(t, e) | |
| 277 | + | deco, e := dm.GetToplevelDecoration(top) | |
| 278 | + | noerr(t, e) | |
| 279 | + | var modes []uint32 | |
| 280 | + | deco.OnConfigure(func(m uint32) { modes = append(modes, m) }) | |
| 281 | + | // A client asking for client-side is answered with the compositor's server-side mode. | |
| 282 | + | noerr(t, deco.SetMode(xdgdecoration.MODE_CLIENT_SIDE)) | |
| 283 | + | xs.OnConfigure(func(serial uint32) { noerr(t, xs.AckConfigure(serial)) }) | |
| 284 | + | // The initial empty commit lets the compositor send xdg_surface.configure. | |
| 285 | + | noerr(t, surface.Commit()) | |
| 286 | + | h.sync(t, d, "decoration") | |
| 287 | + | if len(modes) == 0 || modes[len(modes)-1] != xdgdecoration.MODE_SERVER_SIDE { | |
| 288 | + | t.Fatalf("xdg decoration modes %v\n%s", modes, h.Log()) | |
| 289 | + | } | |
| 290 | + | kdeDeco, e := kde.Create(surface) | |
| 291 | + | noerr(t, e) | |
| 292 | + | var kdeMode uint32 = 99 | |
| 293 | + | kdeDeco.OnMode(func(m uint32) { kdeMode = m }) | |
| 294 | + | h.sync(t, d, "kde decoration") | |
| 295 | + | if kdeDefault != kdeserverdecoration.ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER || kdeMode != kdeserverdecoration.ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER { | |
| 296 | + | t.Fatalf("kde default=%d mode=%d", kdeDefault, kdeMode) | |
| 297 | + | } | |
| 298 | + | noerr(t, kdeDeco.Release()) | |
| 299 | + | noerr(t, deco.Destroy()) | |
| 300 | + | noerr(t, top.Destroy()) | |
| 301 | + | noerr(t, xs.Destroy()) | |
| 302 | + | noerr(t, surface.Destroy()) | |
| 303 | + | h.sync(t, d, "decoration teardown") | |
| 304 | + | }) | |
| 305 | + | ||
| 306 | + | t.Run("workspaces", func(t *testing.T) { | |
| 307 | + | d := h.connect(t) | |
| 308 | + | wsm := workspace.NewExtWorkspaceManager(d.Context()) | |
| 309 | + | groups, workspaces, done, finished := 0, 0, false, false | |
| 310 | + | names := map[string]bool{} | |
| 311 | + | wsm.OnWorkspaceGroup(func(*workspace.ExtWorkspaceGroupHandle) { groups++ }) | |
| 312 | + | wsm.OnWorkspace(func(w *workspace.ExtWorkspaceHandle) { | |
| 313 | + | workspaces++ | |
| 314 | + | w.OnName(func(n string) { names[n] = true }) | |
| 315 | + | }) | |
| 316 | + | wsm.OnDone(func() { done = true }) | |
| 317 | + | wsm.OnFinished(func() { finished = true }) | |
| 318 | + | h.bindOne(t, d, workspace.ExtWorkspaceManagerInterface, 1, wsm) | |
| 319 | + | h.sync(t, d, "workspace snapshot") | |
| 320 | + | if !done || groups == 0 || workspaces == 0 || len(names) == 0 { | |
| 321 | + | t.Fatalf("done=%t groups=%d workspaces=%d names=%v\n%s", done, groups, workspaces, names, h.Log()) | |
| 322 | + | } | |
| 323 | + | t.Logf("workspaces: groups=%d workspaces=%d names=%v", groups, workspaces, names) | |
| 324 | + | // stop is answered by finished; wait for it with the blocking dispatch. | |
| 325 | + | noerr(t, wsm.Stop()) | |
| 326 | + | for !finished { | |
| 327 | + | if e := d.Dispatch(); e != nil { | |
| 328 | + | t.Fatalf("waiting for finished: %v\n%s", e, h.Log()) | |
| 329 | + | } | |
| 330 | + | } | |
| 331 | + | }) | |
| 332 | + | ||
| 333 | + | t.Run("color capabilities", func(t *testing.T) { | |
| 334 | + | d := h.connect(t) | |
| 335 | + | cm := colormanagement.NewWpColorManager(d.Context()) | |
| 336 | + | intents, features, tfs, prims := map[uint32]bool{}, map[uint32]bool{}, map[uint32]bool{}, map[uint32]bool{} | |
| 337 | + | cmDone := false | |
| 338 | + | cm.OnSupportedIntent(func(v uint32) { intents[v] = true }) | |
| 339 | + | cm.OnSupportedFeature(func(v uint32) { features[v] = true }) | |
| 340 | + | cm.OnSupportedTfNamed(func(v uint32) { tfs[v] = true }) | |
| 341 | + | cm.OnSupportedPrimariesNamed(func(v uint32) { prims[v] = true }) | |
| 342 | + | cm.OnDone(func() { cmDone = true }) | |
| 343 | + | version := h.bindOne(t, d, colormanagement.WpColorManagerInterface, 3, cm) | |
| 344 | + | ||
| 345 | + | cr := colorrepresentation.NewWpColorRepresentationManager(d.Context()) | |
| 346 | + | alpha, crDone := map[uint32]bool{}, false | |
| 347 | + | cr.OnSupportedAlphaMode(func(v uint32) { alpha[v] = true }) | |
| 348 | + | cr.OnDone(func() { crDone = true }) | |
| 349 | + | h.bindOne(t, d, colorrepresentation.WpColorRepresentationManagerInterface, 1, cr) | |
| 350 | + | h.sync(t, d, "color capabilities") | |
| 351 | + | ||
| 352 | + | if !cmDone || !intents[colormanagement.RENDER_INTENT_PERCEPTUAL] || !features[colormanagement.FEATURE_PARAMETRIC] || | |
| 353 | + | !tfs[colormanagement.TRANSFER_FUNCTION_SRGB] || !prims[colormanagement.PRIMARIES_SRGB] { | |
| 354 | + | t.Fatalf("color manager v%d done=%t intents=%v features=%v tf=%v primaries=%v\n%s", version, cmDone, intents, features, tfs, prims, h.Log()) | |
| 355 | + | } | |
| 356 | + | if !crDone || len(alpha) == 0 { | |
| 357 | + | t.Fatalf("color representation done=%t alpha=%v", crDone, alpha) | |
| 358 | + | } | |
| 359 | + | t.Logf("color v%d intents=%v features=%v tf=%v primaries=%v alpha=%v", version, intents, features, tfs, prims, alpha) | |
| 360 | + | }) | |
| 361 | + | ||
| 362 | + | t.Run("presentation clock", func(t *testing.T) { | |
| 363 | + | d := h.connect(t) | |
| 364 | + | p := presentation.NewWpPresentation(d.Context()) | |
| 365 | + | clock, got := uint32(0), false | |
| 366 | + | p.OnClockId(func(id uint32) { clock, got = id, true }) | |
| 367 | + | h.bindOne(t, d, presentation.WpPresentationInterface, 2, p) | |
| 368 | + | h.sync(t, d, "presentation clock") | |
| 369 | + | // An empty commit produces no frame, so only the clock is asserted. | |
| 370 | + | if !got || clock != unix.CLOCK_MONOTONIC { | |
| 371 | + | t.Fatalf("clock_id got=%t %d, want CLOCK_MONOTONIC", got, clock) | |
| 372 | + | } | |
| 373 | + | noerr(t, p.Destroy()) | |
| 374 | + | h.sync(t, d, "presentation teardown") | |
| 375 | + | }) | |
| 376 | + | ||
| 377 | + | t.Run("layer surface configure", func(t *testing.T) { | |
| 378 | + | d := h.connect(t) | |
| 379 | + | h.waitGlobal(t, d, core.OutputInterface) | |
| 380 | + | compositor := core.NewCompositor(d.Context()) | |
| 381 | + | h.bindOne(t, d, core.CompositorInterface, 6, compositor) | |
| 382 | + | shell := layershell.NewLayerShell(d.Context()) | |
| 383 | + | h.bindOne(t, d, layershell.LayerShellInterface, 5, shell) | |
| 384 | + | surface, e := compositor.CreateSurface() | |
| 385 | + | noerr(t, e) | |
| 386 | + | ls, e := shell.GetLayerSurface(surface, nil, layershell.LAYER_TOP, "wlturbo-test") | |
| 387 | + | noerr(t, e) | |
| 388 | + | noerr(t, ls.SetAnchor(layershell.ANCHOR_TOP|layershell.ANCHOR_LEFT|layershell.ANCHOR_RIGHT)) | |
| 389 | + | noerr(t, ls.SetSize(0, 30)) | |
| 390 | + | var serial, w, hgt uint32 | |
| 391 | + | configured := false | |
| 392 | + | ls.OnConfigure(func(s, cw, ch uint32) { serial, w, hgt, configured = s, cw, ch, true }) | |
| 393 | + | // The initial empty commit asks the compositor for the first configure. | |
| 394 | + | noerr(t, surface.Commit()) | |
| 395 | + | h.sync(t, d, "layer configure") | |
| 396 | + | if !configured || w != 640 || hgt != 30 { | |
| 397 | + | t.Fatalf("configured=%t %dx%d\n%s", configured, w, hgt, h.Log()) | |
| 398 | + | } | |
| 399 | + | noerr(t, ls.AckConfigure(serial)) | |
| 400 | + | noerr(t, ls.Destroy()) | |
| 401 | + | noerr(t, surface.Destroy()) | |
| 402 | + | h.sync(t, d, "layer teardown") | |
| 403 | + | }) | |
| 404 | + | ||
| 405 | + | t.Run("relative pointer object", func(t *testing.T) { | |
| 406 | + | d := h.connect(t) | |
| 407 | + | seat := core.NewSeat(d.Context()) | |
| 408 | + | var caps uint32 | |
| 409 | + | seat.OnCapabilities(func(c uint32) { caps = c }) | |
| 410 | + | h.bindOne(t, d, core.SeatInterface, 8, seat) | |
| 411 | + | rm := relativepointer.NewRelativePointerManager(d.Context()) | |
| 412 | + | h.bindOne(t, d, relativepointer.RelativePointerManagerInterface, 1, rm) | |
| 413 | + | h.sync(t, d, "seat capabilities") | |
| 414 | + | if caps&core.CAPABILITY_POINTER == 0 { | |
| 415 | + | t.Skipf("seat has no pointer (caps %d); headless input capability dependent", caps) | |
| 416 | + | } | |
| 417 | + | ptr, e := seat.GetPointer() | |
| 418 | + | noerr(t, e) | |
| 419 | + | rp, e := rm.GetRelativePointer(ptr) | |
| 420 | + | noerr(t, e) | |
| 421 | + | // Motion needs pointer focus on a mapped surface, which an empty | |
| 422 | + | // commit cannot provide; creation and teardown must still be valid. | |
| 423 | + | rp.OnRelativeMotion(func(uint32, uint32, wlturbo.Fixed, wlturbo.Fixed, wlturbo.Fixed, wlturbo.Fixed) {}) | |
| 424 | + | h.sync(t, d, "relative pointer") | |
| 425 | + | noerr(t, rp.Destroy()) | |
| 426 | + | noerr(t, ptr.Release()) | |
| 427 | + | noerr(t, rm.Destroy()) | |
| 428 | + | h.sync(t, d, "relative pointer teardown") | |
| 429 | + | }) | |
| 430 | + | } | |
M protocol/headless_test.go +203 -64
| @@ -4,6 +4,7 @@ package protocol_test | |||
| 4 | 4 | ||
| 5 | 5 | import ( | |
| 6 | 6 | "context" | |
| 7 | + | "errors" | |
| 7 | 8 | "fmt" | |
| 8 | 9 | "net" | |
| 9 | 10 | "os" | |
| @@ -21,67 +22,14 @@ import ( | |||
| 21 | 22 | "github.com/bnema/wlturbo/protocol/linuxdmabuf" | |
| 22 | 23 | "github.com/bnema/wlturbo/protocol/viewporter" | |
| 23 | 24 | "github.com/bnema/wlturbo/protocol/xdgshell" | |
| 25 | + | "golang.org/x/sys/unix" | |
| 24 | 26 | ) | |
| 25 | 27 | ||
| 26 | 28 | func TestHeadlessNeferWL(t *testing.T) { | |
| 27 | - | binary := os.Getenv("WLTURBO_HEADLESS") | |
| 28 | - | if binary == "" { | |
| 29 | - | t.Skip("set WLTURBO_HEADLESS to a NeferWL binary") | |
| 30 | - | } | |
| 31 | - | binary, e := filepath.Abs(binary) | |
| 32 | - | noerr(t, e) | |
| 33 | - | runtimeDir := filepath.Join(t.TempDir(), "run") | |
| 34 | - | noerr(t, os.Mkdir(runtimeDir, 0700)) | |
| 35 | - | configDir := filepath.Join(t.TempDir(), "config") | |
| 36 | - | noerr(t, os.Mkdir(configDir, 0700)) | |
| 37 | - | ctx, cancel := context.WithTimeout(context.Background(), 18*time.Second) | |
| 38 | - | defer cancel() | |
| 39 | - | cmd := exec.Command(binary, "--backend=headless", "--no-terminal", "--no-xwayland", "--size", "640x480", "--timeout", "20s") | |
| 40 | - | cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} | |
| 41 | - | cmd.Env = append(cleanDisplayEnv(os.Environ()), "XDG_RUNTIME_DIR="+runtimeDir, "XDG_CONFIG_HOME="+configDir) | |
| 42 | - | log, e := os.Create(filepath.Join(t.TempDir(), "neferwl.log")) | |
| 43 | - | noerr(t, e) | |
| 44 | - | defer log.Close() | |
| 45 | - | cmd.Stdout = log | |
| 46 | - | cmd.Stderr = log | |
| 47 | - | noerr(t, cmd.Start()) | |
| 48 | - | t.Cleanup(func() { _ = syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL); _ = cmd.Wait() }) | |
| 49 | - | // A failed startup must still terminate its process group and reap it. | |
| 50 | - | socket := "" | |
| 51 | - | for socket == "" { | |
| 52 | - | if e := ctx.Err(); e != nil { | |
| 53 | - | t.Fatalf("headless socket timeout: %v\n%s", e, headlessLog(log)) | |
| 54 | - | } | |
| 55 | - | paths, _ := filepath.Glob(filepath.Join(runtimeDir, "wayland-*")) | |
| 56 | - | for _, path := range paths { | |
| 57 | - | info, e := os.Stat(path) | |
| 58 | - | if e == nil && info.Mode()&os.ModeSocket != 0 { | |
| 59 | - | socket = path | |
| 60 | - | break | |
| 61 | - | } | |
| 62 | - | } | |
| 63 | - | if socket == "" { | |
| 64 | - | time.Sleep(20 * time.Millisecond) | |
| 65 | - | } | |
| 66 | - | } | |
| 67 | - | conn, e := net.DialTimeout("unix", socket, time.Second) | |
| 68 | - | noerr(t, e) | |
| 69 | - | d, e := wlturbo.ConnectFromConn(conn) | |
| 70 | - | noerr(t, e) | |
| 71 | - | defer d.Close() | |
| 72 | - | // Close the socket when the test deadline expires so blocking Dispatch exits. | |
| 73 | - | stop := context.AfterFunc(ctx, func() { _ = d.Close() }) | |
| 74 | - | defer stop() | |
| 75 | - | noerr(t, d.Roundtrip()) | |
| 76 | - | bind := func(iface string, supported uint32, proxy wlturbo.Proxy) uint32 { | |
| 77 | - | t.Helper() | |
| 78 | - | v, err := d.Registry().BindNegotiated(iface, supported, proxy) | |
| 79 | - | if err != nil { | |
| 80 | - | t.Fatalf("bind %s: %v\n%s", iface, err, headlessLog(log)) | |
| 81 | - | } | |
| 82 | - | t.Logf("%s negotiated=%d", iface, v) | |
| 83 | - | return v | |
| 84 | - | } | |
| 29 | + | h := startHeadless(t) | |
| 30 | + | d := h.connect(t) | |
| 31 | + | bind := h.binder(t, d) | |
| 32 | + | ctx := h.ctx | |
| 85 | 33 | compositor := core.NewCompositor(d.Context()) | |
| 86 | 34 | bind(core.CompositorInterface, 6, compositor) | |
| 87 | 35 | wm := xdgshell.NewXdgWmBase(d.Context()) | |
| @@ -93,7 +41,7 @@ func TestHeadlessNeferWL(t *testing.T) { | |||
| 93 | 41 | syncManager := drmsyncobj.NewWpLinuxDrmSyncobjManager(d.Context()) | |
| 94 | 42 | bind(drmsyncobj.WpLinuxDrmSyncobjManagerInterface, 1, syncManager) | |
| 95 | 43 | dataManager := core.NewDataDeviceManager(d.Context()) | |
| 96 | - | bind(core.DataDeviceManagerInterface, 4, dataManager) | |
| 44 | + | dataVersion := bind(core.DataDeviceManagerInterface, 4, dataManager) | |
| 97 | 45 | vp := viewporter.NewWpViewporter(d.Context()) | |
| 98 | 46 | bind(viewporter.WpViewporterInterface, 1, vp) | |
| 99 | 47 | if g, ok := d.Registry().FindGlobal(fractionalscale.WpFractionalScaleManagerInterface); ok { | |
| @@ -138,11 +86,11 @@ func TestHeadlessNeferWL(t *testing.T) { | |||
| 138 | 86 | noerr(t, surface.Commit()) | |
| 139 | 87 | for (!configured || !done) && ctx.Err() == nil { | |
| 140 | 88 | if e := d.Dispatch(); e != nil { | |
| 141 | - | t.Fatalf("dispatch: %v\n%s", e, headlessLog(log)) | |
| 89 | + | t.Fatalf("dispatch: %v\n%s", e, h.Log()) | |
| 142 | 90 | } | |
| 143 | 91 | } | |
| 144 | 92 | if !configured || !done || !mainDevice || !tableOK { | |
| 145 | - | t.Fatalf("configure=%t feedback=%t main_device=%t table=%t: %v\n%s", configured, done, mainDevice, tableOK, ctx.Err(), headlessLog(log)) | |
| 93 | + | t.Fatalf("configure=%t feedback=%t main_device=%t table=%t: %v\n%s", configured, done, mainDevice, tableOK, ctx.Err(), h.Log()) | |
| 146 | 94 | } | |
| 147 | 95 | noerr(t, surface.Commit()) | |
| 148 | 96 | // Drop all child objects while their parents are still alive. | |
| @@ -152,22 +100,213 @@ func TestHeadlessNeferWL(t *testing.T) { | |||
| 152 | 100 | noerr(t, xs.Destroy()) | |
| 153 | 101 | noerr(t, surface.Destroy()) | |
| 154 | 102 | noerr(t, vp.Destroy()) | |
| 155 | - | noerr(t, dataManager.Release()) | |
| 103 | + | if dataVersion >= 4 { | |
| 104 | + | noerr(t, dataManager.Release()) | |
| 105 | + | } | |
| 156 | 106 | noerr(t, syncManager.Destroy()) | |
| 157 | 107 | noerr(t, dm.Destroy()) | |
| 158 | 108 | noerr(t, wm.Destroy()) | |
| 159 | 109 | noerr(t, d.Close()) | |
| 160 | 110 | } | |
| 111 | + | ||
| 112 | + | // headlessInstance is one isolated NeferWL process with its own runtime, | |
| 113 | + | // config, data and state directories. Cleanup kills the whole process group | |
| 114 | + | // and reaps it. ctx expires at the test deadline or when the process exits, so | |
| 115 | + | // a blocking Dispatch on a connection made by connect always returns. | |
| 116 | + | type headlessInstance struct { | |
| 117 | + | ctx context.Context | |
| 118 | + | socket string | |
| 119 | + | logf *os.File | |
| 120 | + | done chan struct{} // closed after the process is reaped | |
| 121 | + | waitErr error // valid once done is closed | |
| 122 | + | } | |
| 123 | + | ||
| 124 | + | // startHeadless launches WLTURBO_HEADLESS or skips the test when it is unset. | |
| 125 | + | // It returns once the compositor socket exists, or fails with the process log | |
| 126 | + | // if the process exits early or the 18s test deadline expires. | |
| 127 | + | func startHeadless(t *testing.T) *headlessInstance { | |
| 128 | + | t.Helper() | |
| 129 | + | binary := os.Getenv("WLTURBO_HEADLESS") | |
| 130 | + | if binary == "" { | |
| 131 | + | t.Skip("set WLTURBO_HEADLESS to a NeferWL binary") | |
| 132 | + | } | |
| 133 | + | binary, e := filepath.Abs(binary) | |
| 134 | + | noerr(t, e) | |
| 135 | + | root := t.TempDir() | |
| 136 | + | dirs := map[string]string{} | |
| 137 | + | for _, name := range []string{"run", "config", "data", "state"} { | |
| 138 | + | dirs[name] = filepath.Join(root, name) | |
| 139 | + | noerr(t, os.Mkdir(dirs[name], 0700)) | |
| 140 | + | } | |
| 141 | + | ctx, cancel := context.WithTimeout(context.Background(), 18*time.Second) | |
| 142 | + | t.Cleanup(cancel) | |
| 143 | + | logf, e := os.Create(filepath.Join(root, "neferwl.log")) | |
| 144 | + | noerr(t, e) | |
| 145 | + | t.Cleanup(func() { _ = logf.Close() }) | |
| 146 | + | h := &headlessInstance{logf: logf, done: make(chan struct{})} | |
| 147 | + | // Watch the runtime directory before starting so the socket creation cannot be missed. | |
| 148 | + | // Non-blocking makes os.File use the poller, so Close unblocks the reader goroutine. | |
| 149 | + | ifd, e := unix.InotifyInit1(unix.IN_NONBLOCK | unix.IN_CLOEXEC) | |
| 150 | + | noerr(t, e) | |
| 151 | + | watch := os.NewFile(uintptr(ifd), "inotify") | |
| 152 | + | t.Cleanup(func() { _ = watch.Close() }) | |
| 153 | + | _, e = unix.InotifyAddWatch(ifd, dirs["run"], unix.IN_CREATE|unix.IN_ATTRIB) | |
| 154 | + | noerr(t, e) | |
| 155 | + | cmd := exec.Command(binary, "--backend=headless", "--no-terminal", "--no-xwayland", "--size", "640x480", "--timeout", "20s") | |
| 156 | + | cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} | |
| 157 | + | cmd.Env = append(cleanDisplayEnv(os.Environ()), | |
| 158 | + | "XDG_RUNTIME_DIR="+dirs["run"], "XDG_CONFIG_HOME="+dirs["config"], | |
| 159 | + | "XDG_DATA_HOME="+dirs["data"], "XDG_STATE_HOME="+dirs["state"]) | |
| 160 | + | cmd.Stdout = logf | |
| 161 | + | cmd.Stderr = logf | |
| 162 | + | noerr(t, cmd.Start()) | |
| 163 | + | // A failed startup must still terminate the process group and reap it. | |
| 164 | + | t.Cleanup(func() { | |
| 165 | + | _ = syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) | |
| 166 | + | <-h.done | |
| 167 | + | }) | |
| 168 | + | // Process exit cancels ctx, which also unblocks any Dispatch (see connect). | |
| 169 | + | ctx, stopCtx := context.WithCancel(ctx) | |
| 170 | + | t.Cleanup(stopCtx) | |
| 171 | + | h.ctx = ctx | |
| 172 | + | go func() { | |
| 173 | + | h.waitErr = cmd.Wait() | |
| 174 | + | close(h.done) | |
| 175 | + | stopCtx() | |
| 176 | + | }() | |
| 177 | + | events := make(chan struct{}, 1) | |
| 178 | + | go func() { | |
| 179 | + | buf := make([]byte, 4096) | |
| 180 | + | for { | |
| 181 | + | if _, e := watch.Read(buf); e != nil { | |
| 182 | + | return | |
| 183 | + | } | |
| 184 | + | select { | |
| 185 | + | case events <- struct{}{}: | |
| 186 | + | default: | |
| 187 | + | } | |
| 188 | + | } | |
| 189 | + | }() | |
| 190 | + | find := func() string { | |
| 191 | + | paths, _ := filepath.Glob(filepath.Join(dirs["run"], "wayland-*")) | |
| 192 | + | for _, path := range paths { | |
| 193 | + | if info, e := os.Stat(path); e == nil && info.Mode()&os.ModeSocket != 0 { | |
| 194 | + | return path | |
| 195 | + | } | |
| 196 | + | } | |
| 197 | + | return "" | |
| 198 | + | } | |
| 199 | + | for h.socket = find(); h.socket == ""; h.socket = find() { | |
| 200 | + | select { | |
| 201 | + | case <-events: | |
| 202 | + | case <-h.done: | |
| 203 | + | t.Fatalf("neferwl exited before serving: %v\n%s", h.waitErr, h.Log()) | |
| 204 | + | case <-ctx.Done(): | |
| 205 | + | t.Fatalf("headless socket timeout: %v\n%s", ctx.Err(), h.Log()) | |
| 206 | + | } | |
| 207 | + | } | |
| 208 | + | return h | |
| 209 | + | } | |
| 210 | + | ||
| 211 | + | // Log returns the tail of the compositor output. | |
| 212 | + | func (h *headlessInstance) Log() string { return headlessLog(h.logf) } | |
| 213 | + | ||
| 214 | + | // connect dials the compositor and completes the initial registry roundtrip. | |
| 215 | + | // The instance context closes the connection when the test deadline expires or | |
| 216 | + | // the compositor exits, so a blocking Dispatch returns instead of hanging. | |
| 217 | + | func (h *headlessInstance) connect(t *testing.T) *wlturbo.Display { | |
| 218 | + | t.Helper() | |
| 219 | + | var conn net.Conn | |
| 220 | + | for { | |
| 221 | + | var e error | |
| 222 | + | conn, e = (&net.Dialer{Timeout: time.Second}).DialContext(h.ctx, "unix", h.socket) | |
| 223 | + | if e == nil { | |
| 224 | + | break | |
| 225 | + | } | |
| 226 | + | // The socket file appears at bind(); listen() follows immediately, so | |
| 227 | + | // a refused dial is transient unless the compositor is gone. | |
| 228 | + | if !errors.Is(e, syscall.ECONNREFUSED) { | |
| 229 | + | t.Fatalf("dial: %v\n%s", e, h.Log()) | |
| 230 | + | } | |
| 231 | + | select { | |
| 232 | + | case <-h.done: | |
| 233 | + | t.Fatalf("neferwl exited before accepting: %v\n%s", h.waitErr, h.Log()) | |
| 234 | + | case <-h.ctx.Done(): | |
| 235 | + | t.Fatalf("dial timeout: %v\n%s", h.ctx.Err(), h.Log()) | |
| 236 | + | case <-time.After(5 * time.Millisecond): | |
| 237 | + | } | |
| 238 | + | } | |
| 239 | + | d, e := wlturbo.ConnectFromConn(conn) | |
| 240 | + | if e != nil { | |
| 241 | + | _ = conn.Close() | |
| 242 | + | t.Fatal(e) | |
| 243 | + | } | |
| 244 | + | t.Cleanup(func() { _ = d.Close() }) | |
| 245 | + | stop := context.AfterFunc(h.ctx, func() { _ = d.Close() }) | |
| 246 | + | t.Cleanup(func() { stop() }) | |
| 247 | + | h.sync(t, d, "registry roundtrip") | |
| 248 | + | return d | |
| 249 | + | } | |
| 250 | + | ||
| 251 | + | // binder returns a bind function that fails the test with the compositor log. | |
| 252 | + | func (h *headlessInstance) binder(t *testing.T, d *wlturbo.Display) func(string, uint32, wlturbo.Proxy) uint32 { | |
| 253 | + | return func(iface string, supported uint32, proxy wlturbo.Proxy) uint32 { | |
| 254 | + | t.Helper() | |
| 255 | + | v, err := d.Registry().BindNegotiated(iface, supported, proxy) | |
| 256 | + | if err != nil { | |
| 257 | + | t.Fatalf("bind %s: %v\n%s", iface, err, h.Log()) | |
| 258 | + | } | |
| 259 | + | t.Logf("%s negotiated=%d", iface, v) | |
| 260 | + | return v | |
| 261 | + | } | |
| 262 | + | } | |
| 263 | + | ||
| 264 | + | // sync completes a roundtrip, reporting compositor protocol errors with its log. | |
| 265 | + | func (h *headlessInstance) sync(t *testing.T, d *wlturbo.Display, what string) { | |
| 266 | + | t.Helper() | |
| 267 | + | if e := d.Roundtrip(); e != nil { | |
| 268 | + | t.Fatalf("%s: %v (ctx %v)\n%s", what, e, h.ctx.Err(), h.Log()) | |
| 269 | + | } | |
| 270 | + | } | |
| 271 | + | ||
| 272 | + | // headlessEnvDrop lists the environment prefixes the child must not inherit: | |
| 273 | + | // anything that could attach it to, or make it act on, the caller's session, | |
| 274 | + | // plus NeferWL's own configuration. The test client's own environment is not | |
| 275 | + | // changed; only the child process is isolated. | |
| 276 | + | var headlessEnvDrop = []string{"DISPLAY=", "WAYLAND_DISPLAY=", "WAYLAND_SOCKET=", "NOTIFY_SOCKET=", "DBUS_SESSION_BUS_ADDRESS=", | |
| 277 | + | "XDG_RUNTIME_DIR=", "XDG_CONFIG_HOME=", "XDG_DATA_HOME=", "XDG_STATE_HOME=", "XDG_SESSION_", "XDG_VTNR=", "XDG_SEAT=", | |
| 278 | + | "XDG_CURRENT_DESKTOP=", "NIRI_SOCKET=", "SWAYSOCK=", "HYPRLAND_INSTANCE_SIGNATURE=", "NEFERWL_"} | |
| 279 | + | ||
| 161 | 280 | func cleanDisplayEnv(in []string) []string { | |
| 162 | 281 | out := make([]string, 0, len(in)) | |
| 282 | + | next: | |
| 163 | 283 | for _, e := range in { | |
| 164 | - | if strings.HasPrefix(e, "DISPLAY=") || strings.HasPrefix(e, "WAYLAND_DISPLAY=") || strings.HasPrefix(e, "XDG_RUNTIME_DIR=") || strings.HasPrefix(e, "XDG_CONFIG_HOME=") { | |
| 165 | - | continue | |
| 284 | + | for _, p := range headlessEnvDrop { | |
| 285 | + | if strings.HasPrefix(e, p) { | |
| 286 | + | continue next | |
| 287 | + | } | |
| 166 | 288 | } | |
| 167 | 289 | out = append(out, e) | |
| 168 | 290 | } | |
| 169 | 291 | return out | |
| 170 | 292 | } | |
| 293 | + | ||
| 294 | + | func TestCleanDisplayEnv(t *testing.T) { | |
| 295 | + | keep := []string{"PATH=/bin", "HOME=/h", "DISPLAYS=x", "XDG_DATA_DIRS=/d", "MY_NEFERWL_X=1"} | |
| 296 | + | in := append([]string(nil), keep...) | |
| 297 | + | for _, p := range headlessEnvDrop { | |
| 298 | + | e := p + "placeholder" | |
| 299 | + | if !strings.HasSuffix(p, "=") { | |
| 300 | + | e += "=1" // a prefix such as XDG_SESSION_ names a family of variables | |
| 301 | + | } | |
| 302 | + | in = append(in, e) | |
| 303 | + | } | |
| 304 | + | got := cleanDisplayEnv(in) | |
| 305 | + | if strings.Join(got, "\n") != strings.Join(keep, "\n") { | |
| 306 | + | t.Fatalf("cleanDisplayEnv = %q, want %q", got, keep) | |
| 307 | + | } | |
| 308 | + | } | |
| 309 | + | ||
| 171 | 310 | func headlessLog(f *os.File) string { | |
| 172 | 311 | b, e := os.ReadFile(f.Name()) | |
| 173 | 312 | if e != nil { | |
A protocol/idleinhibit/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package idleinhibit | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p idleinhibit -o idle-inhibit-unstable-v1_generated.go -import wl_surface=github.com/bnema/wlturbo/protocol/core idle-inhibit-unstable-v1.xml | |
A protocol/idleinhibit/idle-inhibit-unstable-v1.xml +83 -0
| @@ -0,0 +1,83 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="idle_inhibit_unstable_v1"> | |
| 3 | + | ||
| 4 | + | <copyright> | |
| 5 | + | Copyright © 2015 Samsung Electronics Co., Ltd | |
| 6 | + | ||
| 7 | + | Permission is hereby granted, free of charge, to any person obtaining a | |
| 8 | + | copy of this software and associated documentation files (the "Software"), | |
| 9 | + | to deal in the Software without restriction, including without limitation | |
| 10 | + | the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 11 | + | and/or sell copies of the Software, and to permit persons to whom the | |
| 12 | + | Software is furnished to do so, subject to the following conditions: | |
| 13 | + | ||
| 14 | + | The above copyright notice and this permission notice (including the next | |
| 15 | + | paragraph) shall be included in all copies or substantial portions of the | |
| 16 | + | Software. | |
| 17 | + | ||
| 18 | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | + | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | + | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 21 | + | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | + | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 23 | + | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 24 | + | DEALINGS IN THE SOFTWARE. | |
| 25 | + | </copyright> | |
| 26 | + | ||
| 27 | + | <interface name="zwp_idle_inhibit_manager_v1" version="1"> | |
| 28 | + | <description summary="control behavior when display idles"> | |
| 29 | + | This interface permits inhibiting the idle behavior such as screen | |
| 30 | + | blanking, locking, and screensaving. The client binds the idle manager | |
| 31 | + | globally, then creates idle-inhibitor objects for each surface. | |
| 32 | + | ||
| 33 | + | Warning! The protocol described in this file is experimental and | |
| 34 | + | backward incompatible changes may be made. Backward compatible changes | |
| 35 | + | may be added together with the corresponding interface version bump. | |
| 36 | + | Backward incompatible changes are done by bumping the version number in | |
| 37 | + | the protocol and interface names and resetting the interface version. | |
| 38 | + | Once the protocol is to be declared stable, the 'z' prefix and the | |
| 39 | + | version number in the protocol and interface names are removed and the | |
| 40 | + | interface version number is reset. | |
| 41 | + | </description> | |
| 42 | + | ||
| 43 | + | <request name="destroy" type="destructor"> | |
| 44 | + | <description summary="destroy the idle inhibitor object"> | |
| 45 | + | Destroy the inhibit manager. | |
| 46 | + | </description> | |
| 47 | + | </request> | |
| 48 | + | ||
| 49 | + | <request name="create_inhibitor"> | |
| 50 | + | <description summary="create a new inhibitor object"> | |
| 51 | + | Create a new inhibitor object associated with the given surface. | |
| 52 | + | </description> | |
| 53 | + | <arg name="id" type="new_id" interface="zwp_idle_inhibitor_v1"/> | |
| 54 | + | <arg name="surface" type="object" interface="wl_surface" | |
| 55 | + | summary="the surface that inhibits the idle behavior"/> | |
| 56 | + | </request> | |
| 57 | + | ||
| 58 | + | </interface> | |
| 59 | + | ||
| 60 | + | <interface name="zwp_idle_inhibitor_v1" version="1"> | |
| 61 | + | <description summary="context object for inhibiting idle behavior"> | |
| 62 | + | An idle inhibitor prevents the output that the associated surface is | |
| 63 | + | visible on from being set to a state where it is not visually usable due | |
| 64 | + | to lack of user interaction (e.g. blanked, dimmed, locked, set to power | |
| 65 | + | save, etc.) Any screensaver processes are also blocked from displaying. | |
| 66 | + | ||
| 67 | + | If the surface is destroyed, unmapped, becomes occluded, loses | |
| 68 | + | visibility, or otherwise becomes not visually relevant for the user, the | |
| 69 | + | idle inhibitor will not be honored by the compositor; if the surface | |
| 70 | + | subsequently regains visibility the inhibitor takes effect once again. | |
| 71 | + | Likewise, the inhibitor isn't honored if the system was already idled at | |
| 72 | + | the time the inhibitor was established, although if the system later | |
| 73 | + | de-idles and re-idles the inhibitor will take effect. | |
| 74 | + | </description> | |
| 75 | + | ||
| 76 | + | <request name="destroy" type="destructor"> | |
| 77 | + | <description summary="destroy the idle inhibitor object"> | |
| 78 | + | Remove the inhibitor effect from the associated wl_surface. | |
| 79 | + | </description> | |
| 80 | + | </request> | |
| 81 | + | ||
| 82 | + | </interface> | |
| 83 | + | </protocol> | |
A protocol/idleinhibit/idle-inhibit-unstable-v1_generated.go +124 -0
| @@ -0,0 +1,124 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: idle_inhibit_unstable_v1 | |
| 3 | + | // Source: idle-inhibit-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2015 Samsung Electronics Co., Ltd | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package idleinhibit | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | cross_wl_surface "github.com/bnema/wlturbo/protocol/core" | |
| 31 | + | "github.com/bnema/wlturbo/wl" | |
| 32 | + | ) | |
| 33 | + | ||
| 34 | + | // IdleInhibitManagerInterface is the protocol interface name. | |
| 35 | + | const IdleInhibitManagerInterface = "zwp_idle_inhibit_manager_v1" | |
| 36 | + | ||
| 37 | + | // IdleInhibitManager is the generated binding for zwp_idle_inhibit_manager_v1 version 1. | |
| 38 | + | type IdleInhibitManager struct { | |
| 39 | + | wl.BaseProxy | |
| 40 | + | } | |
| 41 | + | ||
| 42 | + | // NewIdleInhibitManager returns an unbound IdleInhibitManager. | |
| 43 | + | func NewIdleInhibitManager(ctx *wl.Context) *IdleInhibitManager { | |
| 44 | + | obj := &IdleInhibitManager{} | |
| 45 | + | obj.SetContext(ctx) | |
| 46 | + | ctx.Register(obj) | |
| 47 | + | return obj | |
| 48 | + | } | |
| 49 | + | ||
| 50 | + | // Destroy the inhibit manager. | |
| 51 | + | func (o *IdleInhibitManager) Destroy() error { | |
| 52 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_idle_inhibit_manager_v1.destroy", Destructor: true}); err != nil { | |
| 53 | + | return err | |
| 54 | + | } | |
| 55 | + | return nil | |
| 56 | + | } | |
| 57 | + | ||
| 58 | + | // Create a new inhibitor object associated with the given surface. | |
| 59 | + | func (o *IdleInhibitManager) CreateInhibitor(surface *cross_wl_surface.Surface) (*IdleInhibitor, error) { | |
| 60 | + | var arg1 wl.Object | |
| 61 | + | if surface != nil { | |
| 62 | + | arg1 = surface | |
| 63 | + | } | |
| 64 | + | child := &IdleInhibitor{} | |
| 65 | + | child.SetContext(o.Context()) | |
| 66 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_idle_inhibit_manager_v1.create_inhibitor", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 67 | + | return nil, err | |
| 68 | + | } | |
| 69 | + | return child, nil | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | // EventSignature returns the declared event argument types in wire order. | |
| 73 | + | func (o *IdleInhibitManager) EventSignature(opcode uint16) (string, bool) { | |
| 74 | + | switch opcode { | |
| 75 | + | default: | |
| 76 | + | return "", false | |
| 77 | + | } | |
| 78 | + | } | |
| 79 | + | ||
| 80 | + | // Dispatch decodes one event on zwp_idle_inhibit_manager_v1 and calls the registered handlers. | |
| 81 | + | func (o *IdleInhibitManager) Dispatch(event *wl.Event) { | |
| 82 | + | switch event.Opcode { | |
| 83 | + | default: | |
| 84 | + | } | |
| 85 | + | } | |
| 86 | + | ||
| 87 | + | // IdleInhibitorInterface is the protocol interface name. | |
| 88 | + | const IdleInhibitorInterface = "zwp_idle_inhibitor_v1" | |
| 89 | + | ||
| 90 | + | // IdleInhibitor is the generated binding for zwp_idle_inhibitor_v1 version 1. | |
| 91 | + | type IdleInhibitor struct { | |
| 92 | + | wl.BaseProxy | |
| 93 | + | } | |
| 94 | + | ||
| 95 | + | // NewIdleInhibitor returns an unbound IdleInhibitor. | |
| 96 | + | func NewIdleInhibitor(ctx *wl.Context) *IdleInhibitor { | |
| 97 | + | obj := &IdleInhibitor{} | |
| 98 | + | obj.SetContext(ctx) | |
| 99 | + | ctx.Register(obj) | |
| 100 | + | return obj | |
| 101 | + | } | |
| 102 | + | ||
| 103 | + | // Remove the inhibitor effect from the associated wl_surface. | |
| 104 | + | func (o *IdleInhibitor) Destroy() error { | |
| 105 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_idle_inhibitor_v1.destroy", Destructor: true}); err != nil { | |
| 106 | + | return err | |
| 107 | + | } | |
| 108 | + | return nil | |
| 109 | + | } | |
| 110 | + | ||
| 111 | + | // EventSignature returns the declared event argument types in wire order. | |
| 112 | + | func (o *IdleInhibitor) EventSignature(opcode uint16) (string, bool) { | |
| 113 | + | switch opcode { | |
| 114 | + | default: | |
| 115 | + | return "", false | |
| 116 | + | } | |
| 117 | + | } | |
| 118 | + | ||
| 119 | + | // Dispatch decodes one event on zwp_idle_inhibitor_v1 and calls the registered handlers. | |
| 120 | + | func (o *IdleInhibitor) Dispatch(event *wl.Event) { | |
| 121 | + | switch event.Opcode { | |
| 122 | + | default: | |
| 123 | + | } | |
| 124 | + | } | |
A protocol/idlenotify/ext-idle-notify-v1.xml +131 -0
| @@ -0,0 +1,131 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="ext_idle_notify_v1"> | |
| 3 | + | <copyright> | |
| 4 | + | Copyright © 2015 Martin Gräßlin | |
| 5 | + | Copyright © 2022 Simon Ser | |
| 6 | + | ||
| 7 | + | Permission is hereby granted, free of charge, to any person obtaining a | |
| 8 | + | copy of this software and associated documentation files (the "Software"), | |
| 9 | + | to deal in the Software without restriction, including without limitation | |
| 10 | + | the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 11 | + | and/or sell copies of the Software, and to permit persons to whom the | |
| 12 | + | Software is furnished to do so, subject to the following conditions: | |
| 13 | + | ||
| 14 | + | The above copyright notice and this permission notice (including the next | |
| 15 | + | paragraph) shall be included in all copies or substantial portions of the | |
| 16 | + | Software. | |
| 17 | + | ||
| 18 | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | + | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | + | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 21 | + | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | + | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 23 | + | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 24 | + | DEALINGS IN THE SOFTWARE. | |
| 25 | + | </copyright> | |
| 26 | + | ||
| 27 | + | <interface name="ext_idle_notifier_v1" version="2"> | |
| 28 | + | <description summary="idle notification manager"> | |
| 29 | + | This interface allows clients to monitor user idle status. | |
| 30 | + | ||
| 31 | + | After binding to this global, clients can create ext_idle_notification_v1 | |
| 32 | + | objects to get notified when the user is idle for a given amount of time. | |
| 33 | + | </description> | |
| 34 | + | ||
| 35 | + | <request name="destroy" type="destructor"> | |
| 36 | + | <description summary="destroy the manager"> | |
| 37 | + | Destroy the manager object. All objects created via this interface | |
| 38 | + | remain valid. | |
| 39 | + | </description> | |
| 40 | + | </request> | |
| 41 | + | ||
| 42 | + | <request name="get_idle_notification"> | |
| 43 | + | <description summary="create a notification object"> | |
| 44 | + | Create a new idle notification object. | |
| 45 | + | ||
| 46 | + | The notification object has a minimum timeout duration and is tied to a | |
| 47 | + | seat. The client will be notified if the seat is inactive for at least | |
| 48 | + | the provided timeout. See ext_idle_notification_v1 for more details. | |
| 49 | + | ||
| 50 | + | A zero timeout is valid and means the client wants to be notified as | |
| 51 | + | soon as possible when the seat is inactive. | |
| 52 | + | </description> | |
| 53 | + | <arg name="id" type="new_id" interface="ext_idle_notification_v1"/> | |
| 54 | + | <arg name="timeout" type="uint" summary="minimum idle timeout in msec"/> | |
| 55 | + | <arg name="seat" type="object" interface="wl_seat"/> | |
| 56 | + | </request> | |
| 57 | + | ||
| 58 | + | <!-- Version 2 additions --> | |
| 59 | + | ||
| 60 | + | <request name="get_input_idle_notification" since="2"> | |
| 61 | + | <description summary="create a notification object"> | |
| 62 | + | Create a new idle notification object to track input from the | |
| 63 | + | user, such as keyboard and mouse movement. Because this object is | |
| 64 | + | meant to track user input alone, it ignores idle inhibitors. | |
| 65 | + | ||
| 66 | + | The notification object has a minimum timeout duration and is tied to a | |
| 67 | + | seat. The client will be notified if the seat is inactive for at least | |
| 68 | + | the provided timeout. See ext_idle_notification_v1 for more details. | |
| 69 | + | ||
| 70 | + | A zero timeout is valid and means the client wants to be notified as | |
| 71 | + | soon as possible when the seat is inactive. | |
| 72 | + | </description> | |
| 73 | + | <arg name="id" type="new_id" interface="ext_idle_notification_v1"/> | |
| 74 | + | <arg name="timeout" type="uint" summary="minimum idle timeout in msec"/> | |
| 75 | + | <arg name="seat" type="object" interface="wl_seat"/> | |
| 76 | + | </request> | |
| 77 | + | ||
| 78 | + | </interface> | |
| 79 | + | ||
| 80 | + | <interface name="ext_idle_notification_v1" version="2"> | |
| 81 | + | <description summary="idle notification"> | |
| 82 | + | This interface is used by the compositor to send idle notification events | |
| 83 | + | to clients. | |
| 84 | + | ||
| 85 | + | Initially the notification object is not idle. The notification object | |
| 86 | + | becomes idle when no user activity has happened for at least the timeout | |
| 87 | + | duration, starting from the creation of the notification object. User | |
| 88 | + | activity may include input events or a presence sensor, but is | |
| 89 | + | compositor-specific. | |
| 90 | + | ||
| 91 | + | How this notification responds to idle inhibitors depends on how | |
| 92 | + | it was constructed. If constructed from the | |
| 93 | + | get_idle_notification request, then if an idle inhibitor is | |
| 94 | + | active (e.g. another client has created a zwp_idle_inhibitor_v1 | |
| 95 | + | on a visible surface), the compositor must not make the | |
| 96 | + | notification object idle. However, if constructed from the | |
| 97 | + | get_input_idle_notification request, then idle inhibitors are | |
| 98 | + | ignored, and only input from the user, e.g. from a keyboard or | |
| 99 | + | mouse, counts as activity. | |
| 100 | + | ||
| 101 | + | When the notification object becomes idle, an idled event is sent. When | |
| 102 | + | user activity starts again, the notification object stops being idle, | |
| 103 | + | a resumed event is sent and the timeout is restarted. | |
| 104 | + | </description> | |
| 105 | + | ||
| 106 | + | <request name="destroy" type="destructor"> | |
| 107 | + | <description summary="destroy the notification object"> | |
| 108 | + | Destroy the notification object. | |
| 109 | + | </description> | |
| 110 | + | </request> | |
| 111 | + | ||
| 112 | + | <event name="idled"> | |
| 113 | + | <description summary="notification object is idle"> | |
| 114 | + | This event is sent when the notification object becomes idle. | |
| 115 | + | ||
| 116 | + | It's a compositor protocol error to send this event twice without a | |
| 117 | + | resumed event in-between. | |
| 118 | + | </description> | |
| 119 | + | </event> | |
| 120 | + | ||
| 121 | + | <event name="resumed"> | |
| 122 | + | <description summary="notification object is no longer idle"> | |
| 123 | + | This event is sent when the notification object stops being idle. | |
| 124 | + | ||
| 125 | + | It's a compositor protocol error to send this event twice without an | |
| 126 | + | idled event in-between. It's a compositor protocol error to send this | |
| 127 | + | event prior to any idled event. | |
| 128 | + | </description> | |
| 129 | + | </event> | |
| 130 | + | </interface> | |
| 131 | + | </protocol> | |
A protocol/idlenotify/ext-idle-notify-v1_generated.go +206 -0
| @@ -0,0 +1,206 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: ext_idle_notify_v1 | |
| 3 | + | // Source: ext-idle-notify-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2015 Martin Gräßlin | |
| 7 | + | // Copyright © 2022 Simon Ser | |
| 8 | + | // | |
| 9 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 10 | + | // copy of this software and associated documentation files (the "Software"), | |
| 11 | + | // to deal in the Software without restriction, including without limitation | |
| 12 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 13 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 14 | + | // Software is furnished to do so, subject to the following conditions: | |
| 15 | + | // | |
| 16 | + | // The above copyright notice and this permission notice (including the next | |
| 17 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 18 | + | // Software. | |
| 19 | + | // | |
| 20 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 21 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 22 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 23 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 24 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 25 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 26 | + | // DEALINGS IN THE SOFTWARE. | |
| 27 | + | ||
| 28 | + | package idlenotify | |
| 29 | + | ||
| 30 | + | import ( | |
| 31 | + | "sync" | |
| 32 | + | ||
| 33 | + | cross_wl_seat "github.com/bnema/wlturbo/protocol/core" | |
| 34 | + | "github.com/bnema/wlturbo/wl" | |
| 35 | + | ) | |
| 36 | + | ||
| 37 | + | // ExtIdleNotifierInterface is the protocol interface name. | |
| 38 | + | const ExtIdleNotifierInterface = "ext_idle_notifier_v1" | |
| 39 | + | ||
| 40 | + | // ExtIdleNotifier is the generated binding for ext_idle_notifier_v1 version 2. | |
| 41 | + | type ExtIdleNotifier struct { | |
| 42 | + | wl.BaseProxy | |
| 43 | + | } | |
| 44 | + | ||
| 45 | + | // NewExtIdleNotifier returns an unbound ExtIdleNotifier. | |
| 46 | + | func NewExtIdleNotifier(ctx *wl.Context) *ExtIdleNotifier { | |
| 47 | + | obj := &ExtIdleNotifier{} | |
| 48 | + | obj.SetContext(ctx) | |
| 49 | + | ctx.Register(obj) | |
| 50 | + | return obj | |
| 51 | + | } | |
| 52 | + | ||
| 53 | + | // Destroy the manager object. All objects created via this interface remain valid. | |
| 54 | + | func (o *ExtIdleNotifier) Destroy() error { | |
| 55 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_idle_notifier_v1.destroy", Destructor: true}); err != nil { | |
| 56 | + | return err | |
| 57 | + | } | |
| 58 | + | return nil | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | // Create a new idle notification object. The notification object has a minimum timeout duration and is tied to a seat. The client will be notified if the seat is inactive for at least the provided timeout. See ext_idle_notification_v1 for more details. A zero timeout is valid and means the client wants to be notified as soon as possible when the seat is inactive. | |
| 62 | + | func (o *ExtIdleNotifier) GetIdleNotification(timeout uint32, seat *cross_wl_seat.Seat) (*ExtIdleNotification, error) { | |
| 63 | + | var arg2 wl.Object | |
| 64 | + | if seat != nil { | |
| 65 | + | arg2 = seat | |
| 66 | + | } | |
| 67 | + | child := &ExtIdleNotification{} | |
| 68 | + | child.SetContext(o.Context()) | |
| 69 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_idle_notifier_v1.get_idle_notification", Child: child}, wl.ArgObject(child), wl.ArgUint(timeout), wl.ArgObject(arg2)); err != nil { | |
| 70 | + | return nil, err | |
| 71 | + | } | |
| 72 | + | return child, nil | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | // Create a new idle notification object to track input from the user, such as keyboard and mouse movement. Because this object is meant to track user input alone, it ignores idle inhibitors. The notification object has a minimum timeout duration and is tied to a seat. The client will be notified if the seat is inactive for at least the provided timeout. See ext_idle_notification_v1 for more details. A zero timeout is valid and means the client wants to be notified as soon as possible when the seat is inactive. | |
| 76 | + | func (o *ExtIdleNotifier) GetInputIdleNotification(timeout uint32, seat *cross_wl_seat.Seat) (*ExtIdleNotification, error) { | |
| 77 | + | var arg2 wl.Object | |
| 78 | + | if seat != nil { | |
| 79 | + | arg2 = seat | |
| 80 | + | } | |
| 81 | + | child := &ExtIdleNotification{} | |
| 82 | + | child.SetContext(o.Context()) | |
| 83 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "ext_idle_notifier_v1.get_input_idle_notification", Since: 2, Child: child}, wl.ArgObject(child), wl.ArgUint(timeout), wl.ArgObject(arg2)); err != nil { | |
| 84 | + | return nil, err | |
| 85 | + | } | |
| 86 | + | return child, nil | |
| 87 | + | } | |
| 88 | + | ||
| 89 | + | // EventSignature returns the declared event argument types in wire order. | |
| 90 | + | func (o *ExtIdleNotifier) EventSignature(opcode uint16) (string, bool) { | |
| 91 | + | switch opcode { | |
| 92 | + | default: | |
| 93 | + | return "", false | |
| 94 | + | } | |
| 95 | + | } | |
| 96 | + | ||
| 97 | + | // Dispatch decodes one event on ext_idle_notifier_v1 and calls the registered handlers. | |
| 98 | + | func (o *ExtIdleNotifier) Dispatch(event *wl.Event) { | |
| 99 | + | switch event.Opcode { | |
| 100 | + | default: | |
| 101 | + | } | |
| 102 | + | } | |
| 103 | + | ||
| 104 | + | // ExtIdleNotificationInterface is the protocol interface name. | |
| 105 | + | const ExtIdleNotificationInterface = "ext_idle_notification_v1" | |
| 106 | + | ||
| 107 | + | // ExtIdleNotification is the generated binding for ext_idle_notification_v1 version 2. | |
| 108 | + | type ExtIdleNotification struct { | |
| 109 | + | wl.BaseProxy | |
| 110 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 111 | + | // handlers while another goroutine dispatches events. | |
| 112 | + | handlersMu sync.Mutex | |
| 113 | + | onIdled []func() | |
| 114 | + | onResumed []func() | |
| 115 | + | } | |
| 116 | + | ||
| 117 | + | // NewExtIdleNotification returns an unbound ExtIdleNotification. | |
| 118 | + | func NewExtIdleNotification(ctx *wl.Context) *ExtIdleNotification { | |
| 119 | + | obj := &ExtIdleNotification{} | |
| 120 | + | obj.SetContext(ctx) | |
| 121 | + | ctx.Register(obj) | |
| 122 | + | return obj | |
| 123 | + | } | |
| 124 | + | ||
| 125 | + | // Destroy the notification object. | |
| 126 | + | func (o *ExtIdleNotification) Destroy() error { | |
| 127 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_idle_notification_v1.destroy", Destructor: true}); err != nil { | |
| 128 | + | return err | |
| 129 | + | } | |
| 130 | + | return nil | |
| 131 | + | } | |
| 132 | + | ||
| 133 | + | // OnIdled registers a handler for the idled event. | |
| 134 | + | // | |
| 135 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 136 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 137 | + | func (o *ExtIdleNotification) OnIdled(handler func()) { | |
| 138 | + | if handler == nil { | |
| 139 | + | return | |
| 140 | + | } | |
| 141 | + | o.handlersMu.Lock() | |
| 142 | + | defer o.handlersMu.Unlock() | |
| 143 | + | o.onIdled = append(o.onIdled, handler) | |
| 144 | + | } | |
| 145 | + | ||
| 146 | + | // handlersForIdled returns the handlers registered for idled, taken | |
| 147 | + | // under the lock so a handler may register another handler while events are | |
| 148 | + | // being dispatched. | |
| 149 | + | func (o *ExtIdleNotification) handlersForIdled() []func() { | |
| 150 | + | o.handlersMu.Lock() | |
| 151 | + | defer o.handlersMu.Unlock() | |
| 152 | + | return o.onIdled | |
| 153 | + | } | |
| 154 | + | ||
| 155 | + | // OnResumed registers a handler for the resumed event. | |
| 156 | + | // | |
| 157 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 158 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 159 | + | func (o *ExtIdleNotification) OnResumed(handler func()) { | |
| 160 | + | if handler == nil { | |
| 161 | + | return | |
| 162 | + | } | |
| 163 | + | o.handlersMu.Lock() | |
| 164 | + | defer o.handlersMu.Unlock() | |
| 165 | + | o.onResumed = append(o.onResumed, handler) | |
| 166 | + | } | |
| 167 | + | ||
| 168 | + | // handlersForResumed returns the handlers registered for resumed, taken | |
| 169 | + | // under the lock so a handler may register another handler while events are | |
| 170 | + | // being dispatched. | |
| 171 | + | func (o *ExtIdleNotification) handlersForResumed() []func() { | |
| 172 | + | o.handlersMu.Lock() | |
| 173 | + | defer o.handlersMu.Unlock() | |
| 174 | + | return o.onResumed | |
| 175 | + | } | |
| 176 | + | ||
| 177 | + | // EventSignature returns the declared event argument types in wire order. | |
| 178 | + | func (o *ExtIdleNotification) EventSignature(opcode uint16) (string, bool) { | |
| 179 | + | switch opcode { | |
| 180 | + | case 0: | |
| 181 | + | return "", true | |
| 182 | + | case 1: | |
| 183 | + | return "", true | |
| 184 | + | default: | |
| 185 | + | return "", false | |
| 186 | + | } | |
| 187 | + | } | |
| 188 | + | ||
| 189 | + | // Dispatch decodes one event on ext_idle_notification_v1 and calls the registered handlers. | |
| 190 | + | func (o *ExtIdleNotification) Dispatch(event *wl.Event) { | |
| 191 | + | switch event.Opcode { | |
| 192 | + | case 0: // idled | |
| 193 | + | ||
| 194 | + | for i, handler := range o.handlersForIdled() { | |
| 195 | + | _ = i | |
| 196 | + | handler() | |
| 197 | + | } | |
| 198 | + | case 1: // resumed | |
| 199 | + | ||
| 200 | + | for i, handler := range o.handlersForResumed() { | |
| 201 | + | _ = i | |
| 202 | + | handler() | |
| 203 | + | } | |
| 204 | + | default: | |
| 205 | + | } | |
| 206 | + | } | |
A protocol/idlenotify/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package idlenotify | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p idlenotify -o ext-idle-notify-v1_generated.go -import wl_seat=github.com/bnema/wlturbo/protocol/core ext-idle-notify-v1.xml | |
A protocol/imagecapturesource/ext-image-capture-source-v1.xml +109 -0
| @@ -0,0 +1,109 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="ext_image_capture_source_v1"> | |
| 3 | + | <copyright> | |
| 4 | + | Copyright © 2022 Andri Yngvason | |
| 5 | + | Copyright © 2024 Simon Ser | |
| 6 | + | ||
| 7 | + | Permission is hereby granted, free of charge, to any person obtaining a | |
| 8 | + | copy of this software and associated documentation files (the "Software"), | |
| 9 | + | to deal in the Software without restriction, including without limitation | |
| 10 | + | the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 11 | + | and/or sell copies of the Software, and to permit persons to whom the | |
| 12 | + | Software is furnished to do so, subject to the following conditions: | |
| 13 | + | ||
| 14 | + | The above copyright notice and this permission notice (including the next | |
| 15 | + | paragraph) shall be included in all copies or substantial portions of the | |
| 16 | + | Software. | |
| 17 | + | ||
| 18 | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | + | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | + | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 21 | + | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | + | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 23 | + | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 24 | + | DEALINGS IN THE SOFTWARE. | |
| 25 | + | </copyright> | |
| 26 | + | ||
| 27 | + | <description summary="opaque image capture source objects"> | |
| 28 | + | This protocol serves as an intermediary between capturing protocols and | |
| 29 | + | potential image capture sources such as outputs and toplevels. | |
| 30 | + | ||
| 31 | + | This protocol may be extended to support more image capture sources in the | |
| 32 | + | future, thereby adding those image capture sources to other protocols that | |
| 33 | + | use the image capture source object without having to modify those | |
| 34 | + | protocols. | |
| 35 | + | ||
| 36 | + | Warning! The protocol described in this file is currently in the testing | |
| 37 | + | phase. Backward compatible changes may be added together with the | |
| 38 | + | corresponding interface version bump. Backward incompatible changes can | |
| 39 | + | only be done by creating a new major version of the extension. | |
| 40 | + | </description> | |
| 41 | + | ||
| 42 | + | <interface name="ext_image_capture_source_v1" version="1" frozen="true"> | |
| 43 | + | <description summary="opaque image capture source object"> | |
| 44 | + | The image capture source object is an opaque descriptor for a capturable | |
| 45 | + | resource. This resource may be any sort of entity from which an image | |
| 46 | + | may be derived. | |
| 47 | + | ||
| 48 | + | Note, because ext_image_capture_source_v1 objects are created from multiple | |
| 49 | + | independent factory interfaces, the ext_image_capture_source_v1 interface is | |
| 50 | + | frozen at version 1. | |
| 51 | + | </description> | |
| 52 | + | ||
| 53 | + | <request name="destroy" type="destructor"> | |
| 54 | + | <description summary="delete this object"> | |
| 55 | + | Destroys the image capture source. This request may be sent at any time | |
| 56 | + | by the client. | |
| 57 | + | </description> | |
| 58 | + | </request> | |
| 59 | + | </interface> | |
| 60 | + | ||
| 61 | + | <interface name="ext_output_image_capture_source_manager_v1" version="1"> | |
| 62 | + | <description summary="image capture source manager for outputs"> | |
| 63 | + | A manager for creating image capture source objects for wl_output objects. | |
| 64 | + | </description> | |
| 65 | + | ||
| 66 | + | <request name="create_source"> | |
| 67 | + | <description summary="create source object for output"> | |
| 68 | + | Creates a source object for an output. Images captured from this source | |
| 69 | + | will show the same content as the output. Some elements may be omitted, | |
| 70 | + | such as cursors and overlays that have been marked as transparent to | |
| 71 | + | capturing. | |
| 72 | + | </description> | |
| 73 | + | <arg name="source" type="new_id" interface="ext_image_capture_source_v1"/> | |
| 74 | + | <arg name="output" type="object" interface="wl_output"/> | |
| 75 | + | </request> | |
| 76 | + | ||
| 77 | + | <request name="destroy" type="destructor"> | |
| 78 | + | <description summary="delete this object"> | |
| 79 | + | Destroys the manager. This request may be sent at any time by the client | |
| 80 | + | and objects created by the manager will remain valid after its | |
| 81 | + | destruction. | |
| 82 | + | </description> | |
| 83 | + | </request> | |
| 84 | + | </interface> | |
| 85 | + | ||
| 86 | + | <interface name="ext_foreign_toplevel_image_capture_source_manager_v1" version="1"> | |
| 87 | + | <description summary="image capture source manager for foreign toplevels"> | |
| 88 | + | A manager for creating image capture source objects for | |
| 89 | + | ext_foreign_toplevel_handle_v1 objects. | |
| 90 | + | </description> | |
| 91 | + | ||
| 92 | + | <request name="create_source"> | |
| 93 | + | <description summary="create source object for foreign toplevel"> | |
| 94 | + | Creates a source object for a foreign toplevel handle. Images captured | |
| 95 | + | from this source will show the same content as the toplevel. | |
| 96 | + | </description> | |
| 97 | + | <arg name="source" type="new_id" interface="ext_image_capture_source_v1"/> | |
| 98 | + | <arg name="toplevel_handle" type="object" interface="ext_foreign_toplevel_handle_v1"/> | |
| 99 | + | </request> | |
| 100 | + | ||
| 101 | + | <request name="destroy" type="destructor"> | |
| 102 | + | <description summary="delete this object"> | |
| 103 | + | Destroys the manager. This request may be sent at any time by the client | |
| 104 | + | and objects created by the manager will remain valid after its | |
| 105 | + | destruction. | |
| 106 | + | </description> | |
| 107 | + | </request> | |
| 108 | + | </interface> | |
| 109 | + | </protocol> | |
A protocol/imagecapturesource/ext-image-capture-source-v1_generated.go +179 -0
| @@ -0,0 +1,179 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: ext_image_capture_source_v1 | |
| 3 | + | // Source: ext-image-capture-source-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2022 Andri Yngvason | |
| 7 | + | // Copyright © 2024 Simon Ser | |
| 8 | + | // | |
| 9 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 10 | + | // copy of this software and associated documentation files (the "Software"), | |
| 11 | + | // to deal in the Software without restriction, including without limitation | |
| 12 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 13 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 14 | + | // Software is furnished to do so, subject to the following conditions: | |
| 15 | + | // | |
| 16 | + | // The above copyright notice and this permission notice (including the next | |
| 17 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 18 | + | // Software. | |
| 19 | + | // | |
| 20 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 21 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 22 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 23 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 24 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 25 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 26 | + | // DEALINGS IN THE SOFTWARE. | |
| 27 | + | ||
| 28 | + | package imagecapturesource | |
| 29 | + | ||
| 30 | + | import ( | |
| 31 | + | cross_wl_output "github.com/bnema/wlturbo/protocol/core" | |
| 32 | + | cross_ext_foreign_toplevel_handle_v1 "github.com/bnema/wlturbo/protocol/extforeigntoplevel" | |
| 33 | + | "github.com/bnema/wlturbo/wl" | |
| 34 | + | ) | |
| 35 | + | ||
| 36 | + | // ExtImageCaptureSourceInterface is the protocol interface name. | |
| 37 | + | const ExtImageCaptureSourceInterface = "ext_image_capture_source_v1" | |
| 38 | + | ||
| 39 | + | // ExtImageCaptureSource is the generated binding for ext_image_capture_source_v1 version 1. | |
| 40 | + | type ExtImageCaptureSource struct { | |
| 41 | + | wl.BaseProxy | |
| 42 | + | } | |
| 43 | + | ||
| 44 | + | // NewExtImageCaptureSource returns an unbound ExtImageCaptureSource. | |
| 45 | + | func NewExtImageCaptureSource(ctx *wl.Context) *ExtImageCaptureSource { | |
| 46 | + | obj := &ExtImageCaptureSource{} | |
| 47 | + | obj.SetContext(ctx) | |
| 48 | + | ctx.Register(obj) | |
| 49 | + | return obj | |
| 50 | + | } | |
| 51 | + | ||
| 52 | + | // Destroys the image capture source. This request may be sent at any time by the client. | |
| 53 | + | func (o *ExtImageCaptureSource) Destroy() error { | |
| 54 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_image_capture_source_v1.destroy", Destructor: true}); err != nil { | |
| 55 | + | return err | |
| 56 | + | } | |
| 57 | + | return nil | |
| 58 | + | } | |
| 59 | + | ||
| 60 | + | // EventSignature returns the declared event argument types in wire order. | |
| 61 | + | func (o *ExtImageCaptureSource) EventSignature(opcode uint16) (string, bool) { | |
| 62 | + | switch opcode { | |
| 63 | + | default: | |
| 64 | + | return "", false | |
| 65 | + | } | |
| 66 | + | } | |
| 67 | + | ||
| 68 | + | // Dispatch decodes one event on ext_image_capture_source_v1 and calls the registered handlers. | |
| 69 | + | func (o *ExtImageCaptureSource) Dispatch(event *wl.Event) { | |
| 70 | + | switch event.Opcode { | |
| 71 | + | default: | |
| 72 | + | } | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | // ExtOutputImageCaptureSourceManagerInterface is the protocol interface name. | |
| 76 | + | const ExtOutputImageCaptureSourceManagerInterface = "ext_output_image_capture_source_manager_v1" | |
| 77 | + | ||
| 78 | + | // ExtOutputImageCaptureSourceManager is the generated binding for ext_output_image_capture_source_manager_v1 version 1. | |
| 79 | + | type ExtOutputImageCaptureSourceManager struct { | |
| 80 | + | wl.BaseProxy | |
| 81 | + | } | |
| 82 | + | ||
| 83 | + | // NewExtOutputImageCaptureSourceManager returns an unbound ExtOutputImageCaptureSourceManager. | |
| 84 | + | func NewExtOutputImageCaptureSourceManager(ctx *wl.Context) *ExtOutputImageCaptureSourceManager { | |
| 85 | + | obj := &ExtOutputImageCaptureSourceManager{} | |
| 86 | + | obj.SetContext(ctx) | |
| 87 | + | ctx.Register(obj) | |
| 88 | + | return obj | |
| 89 | + | } | |
| 90 | + | ||
| 91 | + | // Creates a source object for an output. Images captured from this source will show the same content as the output. Some elements may be omitted, such as cursors and overlays that have been marked as transparent to capturing. | |
| 92 | + | func (o *ExtOutputImageCaptureSourceManager) CreateSource(output *cross_wl_output.Output) (*ExtImageCaptureSource, error) { | |
| 93 | + | var arg1 wl.Object | |
| 94 | + | if output != nil { | |
| 95 | + | arg1 = output | |
| 96 | + | } | |
| 97 | + | child := &ExtImageCaptureSource{} | |
| 98 | + | child.SetContext(o.Context()) | |
| 99 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_output_image_capture_source_manager_v1.create_source", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 100 | + | return nil, err | |
| 101 | + | } | |
| 102 | + | return child, nil | |
| 103 | + | } | |
| 104 | + | ||
| 105 | + | // Destroys the manager. This request may be sent at any time by the client and objects created by the manager will remain valid after its destruction. | |
| 106 | + | func (o *ExtOutputImageCaptureSourceManager) Destroy() error { | |
| 107 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_output_image_capture_source_manager_v1.destroy", Destructor: true}); err != nil { | |
| 108 | + | return err | |
| 109 | + | } | |
| 110 | + | return nil | |
| 111 | + | } | |
| 112 | + | ||
| 113 | + | // EventSignature returns the declared event argument types in wire order. | |
| 114 | + | func (o *ExtOutputImageCaptureSourceManager) EventSignature(opcode uint16) (string, bool) { | |
| 115 | + | switch opcode { | |
| 116 | + | default: | |
| 117 | + | return "", false | |
| 118 | + | } | |
| 119 | + | } | |
| 120 | + | ||
| 121 | + | // Dispatch decodes one event on ext_output_image_capture_source_manager_v1 and calls the registered handlers. | |
| 122 | + | func (o *ExtOutputImageCaptureSourceManager) Dispatch(event *wl.Event) { | |
| 123 | + | switch event.Opcode { | |
| 124 | + | default: | |
| 125 | + | } | |
| 126 | + | } | |
| 127 | + | ||
| 128 | + | // ExtForeignToplevelImageCaptureSourceManagerInterface is the protocol interface name. | |
| 129 | + | const ExtForeignToplevelImageCaptureSourceManagerInterface = "ext_foreign_toplevel_image_capture_source_manager_v1" | |
| 130 | + | ||
| 131 | + | // ExtForeignToplevelImageCaptureSourceManager is the generated binding for ext_foreign_toplevel_image_capture_source_manager_v1 version 1. | |
| 132 | + | type ExtForeignToplevelImageCaptureSourceManager struct { | |
| 133 | + | wl.BaseProxy | |
| 134 | + | } | |
| 135 | + | ||
| 136 | + | // NewExtForeignToplevelImageCaptureSourceManager returns an unbound ExtForeignToplevelImageCaptureSourceManager. | |
| 137 | + | func NewExtForeignToplevelImageCaptureSourceManager(ctx *wl.Context) *ExtForeignToplevelImageCaptureSourceManager { | |
| 138 | + | obj := &ExtForeignToplevelImageCaptureSourceManager{} | |
| 139 | + | obj.SetContext(ctx) | |
| 140 | + | ctx.Register(obj) | |
| 141 | + | return obj | |
| 142 | + | } | |
| 143 | + | ||
| 144 | + | // Creates a source object for a foreign toplevel handle. Images captured from this source will show the same content as the toplevel. | |
| 145 | + | func (o *ExtForeignToplevelImageCaptureSourceManager) CreateSource(toplevelHandle *cross_ext_foreign_toplevel_handle_v1.ExtForeignToplevelHandle) (*ExtImageCaptureSource, error) { | |
| 146 | + | var arg1 wl.Object | |
| 147 | + | if toplevelHandle != nil { | |
| 148 | + | arg1 = toplevelHandle | |
| 149 | + | } | |
| 150 | + | child := &ExtImageCaptureSource{} | |
| 151 | + | child.SetContext(o.Context()) | |
| 152 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_foreign_toplevel_image_capture_source_manager_v1.create_source", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 153 | + | return nil, err | |
| 154 | + | } | |
| 155 | + | return child, nil | |
| 156 | + | } | |
| 157 | + | ||
| 158 | + | // Destroys the manager. This request may be sent at any time by the client and objects created by the manager will remain valid after its destruction. | |
| 159 | + | func (o *ExtForeignToplevelImageCaptureSourceManager) Destroy() error { | |
| 160 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_foreign_toplevel_image_capture_source_manager_v1.destroy", Destructor: true}); err != nil { | |
| 161 | + | return err | |
| 162 | + | } | |
| 163 | + | return nil | |
| 164 | + | } | |
| 165 | + | ||
| 166 | + | // EventSignature returns the declared event argument types in wire order. | |
| 167 | + | func (o *ExtForeignToplevelImageCaptureSourceManager) EventSignature(opcode uint16) (string, bool) { | |
| 168 | + | switch opcode { | |
| 169 | + | default: | |
| 170 | + | return "", false | |
| 171 | + | } | |
| 172 | + | } | |
| 173 | + | ||
| 174 | + | // Dispatch decodes one event on ext_foreign_toplevel_image_capture_source_manager_v1 and calls the registered handlers. | |
| 175 | + | func (o *ExtForeignToplevelImageCaptureSourceManager) Dispatch(event *wl.Event) { | |
| 176 | + | switch event.Opcode { | |
| 177 | + | default: | |
| 178 | + | } | |
| 179 | + | } | |
A protocol/imagecapturesource/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package imagecapturesource | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p imagecapturesource -import ext_foreign_toplevel_handle_v1=github.com/bnema/wlturbo/protocol/extforeigntoplevel -o ext-image-capture-source-v1_generated.go -import wl_output=github.com/bnema/wlturbo/protocol/core ext-image-capture-source-v1.xml | |
A protocol/imagecopycapture/ext-image-copy-capture-v1.xml +456 -0
| @@ -0,0 +1,456 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="ext_image_copy_capture_v1"> | |
| 3 | + | <copyright> | |
| 4 | + | Copyright © 2021-2023 Andri Yngvason | |
| 5 | + | Copyright © 2024 Simon Ser | |
| 6 | + | ||
| 7 | + | Permission is hereby granted, free of charge, to any person obtaining a | |
| 8 | + | copy of this software and associated documentation files (the "Software"), | |
| 9 | + | to deal in the Software without restriction, including without limitation | |
| 10 | + | the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 11 | + | and/or sell copies of the Software, and to permit persons to whom the | |
| 12 | + | Software is furnished to do so, subject to the following conditions: | |
| 13 | + | ||
| 14 | + | The above copyright notice and this permission notice (including the next | |
| 15 | + | paragraph) shall be included in all copies or substantial portions of the | |
| 16 | + | Software. | |
| 17 | + | ||
| 18 | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | + | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | + | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 21 | + | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | + | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 23 | + | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 24 | + | DEALINGS IN THE SOFTWARE. | |
| 25 | + | </copyright> | |
| 26 | + | ||
| 27 | + | <description summary="image capturing into client buffers"> | |
| 28 | + | This protocol allows clients to ask the compositor to capture image sources | |
| 29 | + | such as outputs and toplevels into user submitted buffers. | |
| 30 | + | ||
| 31 | + | Warning! The protocol described in this file is currently in the testing | |
| 32 | + | phase. Backward compatible changes may be added together with the | |
| 33 | + | corresponding interface version bump. Backward incompatible changes can | |
| 34 | + | only be done by creating a new major version of the extension. | |
| 35 | + | </description> | |
| 36 | + | ||
| 37 | + | <interface name="ext_image_copy_capture_manager_v1" version="1"> | |
| 38 | + | <description summary="manager to inform clients and begin capturing"> | |
| 39 | + | This object is a manager which offers requests to start capturing from a | |
| 40 | + | source. | |
| 41 | + | </description> | |
| 42 | + | ||
| 43 | + | <enum name="error"> | |
| 44 | + | <entry name="invalid_option" value="1" summary="invalid option flag"/> | |
| 45 | + | </enum> | |
| 46 | + | ||
| 47 | + | <enum name="options" bitfield="true"> | |
| 48 | + | <entry name="paint_cursors" value="1" summary="paint cursors onto captured frames"/> | |
| 49 | + | </enum> | |
| 50 | + | ||
| 51 | + | <request name="create_session"> | |
| 52 | + | <description summary="capture an image capture source"> | |
| 53 | + | Create a capturing session for an image capture source. | |
| 54 | + | ||
| 55 | + | If the paint_cursors option is set, cursors shall be composited onto | |
| 56 | + | the captured frame. The cursor must not be composited onto the frame | |
| 57 | + | if this flag is not set. | |
| 58 | + | ||
| 59 | + | If the options bitfield is invalid, the invalid_option protocol error | |
| 60 | + | is sent. | |
| 61 | + | </description> | |
| 62 | + | <arg name="session" type="new_id" interface="ext_image_copy_capture_session_v1"/> | |
| 63 | + | <arg name="source" type="object" interface="ext_image_capture_source_v1"/> | |
| 64 | + | <arg name="options" type="uint" enum="options"/> | |
| 65 | + | </request> | |
| 66 | + | ||
| 67 | + | <request name="create_pointer_cursor_session"> | |
| 68 | + | <description summary="capture the pointer cursor of an image capture source"> | |
| 69 | + | Create a cursor capturing session for the pointer of an image capture | |
| 70 | + | source. | |
| 71 | + | </description> | |
| 72 | + | <arg name="session" type="new_id" interface="ext_image_copy_capture_cursor_session_v1"/> | |
| 73 | + | <arg name="source" type="object" interface="ext_image_capture_source_v1"/> | |
| 74 | + | <arg name="pointer" type="object" interface="wl_pointer"/> | |
| 75 | + | </request> | |
| 76 | + | ||
| 77 | + | <request name="destroy" type="destructor"> | |
| 78 | + | <description summary="destroy the manager"> | |
| 79 | + | Destroy the manager object. | |
| 80 | + | ||
| 81 | + | Other objects created via this interface are unaffected. | |
| 82 | + | </description> | |
| 83 | + | </request> | |
| 84 | + | </interface> | |
| 85 | + | ||
| 86 | + | <interface name="ext_image_copy_capture_session_v1" version="1"> | |
| 87 | + | <description summary="image copy capture session"> | |
| 88 | + | This object represents an active image copy capture session. | |
| 89 | + | ||
| 90 | + | After a capture session is created, buffer constraint events will be | |
| 91 | + | emitted from the compositor to tell the client which buffer types and | |
| 92 | + | formats are supported for reading from the session. The compositor may | |
| 93 | + | re-send buffer constraint events whenever they change. | |
| 94 | + | ||
| 95 | + | To advertise buffer constraints, the compositor must send in no | |
| 96 | + | particular order: zero or more shm_format and dmabuf_format events, zero | |
| 97 | + | or one dmabuf_device event, and exactly one buffer_size event. Then the | |
| 98 | + | compositor must send a done event. | |
| 99 | + | ||
| 100 | + | When the client has received all the buffer constraints, it can create a | |
| 101 | + | buffer accordingly, attach it to the capture session using the | |
| 102 | + | attach_buffer request, set the buffer damage using the damage_buffer | |
| 103 | + | request and then send the capture request. | |
| 104 | + | </description> | |
| 105 | + | ||
| 106 | + | <enum name="error"> | |
| 107 | + | <entry name="duplicate_frame" value="1" | |
| 108 | + | summary="create_frame sent before destroying previous frame"/> | |
| 109 | + | </enum> | |
| 110 | + | ||
| 111 | + | <event name="buffer_size"> | |
| 112 | + | <description summary="image capture source dimensions"> | |
| 113 | + | Provides the dimensions of the source image in buffer pixel coordinates. | |
| 114 | + | ||
| 115 | + | The client must attach buffers that match this size. | |
| 116 | + | </description> | |
| 117 | + | <arg name="width" type="uint" summary="buffer width"/> | |
| 118 | + | <arg name="height" type="uint" summary="buffer height"/> | |
| 119 | + | </event> | |
| 120 | + | ||
| 121 | + | <event name="shm_format"> | |
| 122 | + | <description summary="shm buffer format"> | |
| 123 | + | Provides the format that must be used for shared-memory buffers. | |
| 124 | + | ||
| 125 | + | This event may be emitted multiple times, in which case the client may | |
| 126 | + | choose any given format. | |
| 127 | + | </description> | |
| 128 | + | <arg name="format" type="uint" enum="wl_shm.format" summary="shm format"/> | |
| 129 | + | </event> | |
| 130 | + | ||
| 131 | + | <event name="dmabuf_device"> | |
| 132 | + | <description summary="dma-buf device"> | |
| 133 | + | This event advertises the device buffers must be allocated on for | |
| 134 | + | dma-buf buffers. | |
| 135 | + | ||
| 136 | + | In general the device is a DRM node. The DRM node type (primary vs. | |
| 137 | + | render) is unspecified. Clients must not rely on the compositor sending | |
| 138 | + | a particular node type. Clients cannot check two devices for equality | |
| 139 | + | by comparing the dev_t value. | |
| 140 | + | </description> | |
| 141 | + | <arg name="device" type="array" summary="device dev_t value"/> | |
| 142 | + | </event> | |
| 143 | + | ||
| 144 | + | <event name="dmabuf_format"> | |
| 145 | + | <description summary="dma-buf format"> | |
| 146 | + | Provides the format that must be used for dma-buf buffers. | |
| 147 | + | ||
| 148 | + | The client may choose any of the modifiers advertised in the array of | |
| 149 | + | 64-bit unsigned integers. | |
| 150 | + | ||
| 151 | + | This event may be emitted multiple times, in which case the client may | |
| 152 | + | choose any given format. | |
| 153 | + | </description> | |
| 154 | + | <arg name="format" type="uint" summary="drm format code"/> | |
| 155 | + | <arg name="modifiers" type="array" summary="drm format modifiers"/> | |
| 156 | + | </event> | |
| 157 | + | ||
| 158 | + | <event name="done"> | |
| 159 | + | <description summary="all constraints have been sent"> | |
| 160 | + | This event is sent once when all buffer constraint events have been | |
| 161 | + | sent. | |
| 162 | + | ||
| 163 | + | The compositor must always end a batch of buffer constraint events with | |
| 164 | + | this event, regardless of whether it sends the initial constraints or | |
| 165 | + | an update. | |
| 166 | + | </description> | |
| 167 | + | </event> | |
| 168 | + | ||
| 169 | + | <event name="stopped"> | |
| 170 | + | <description summary="session is no longer available"> | |
| 171 | + | This event indicates that the capture session has stopped and is no | |
| 172 | + | longer available. This can happen in a number of cases, e.g. when the | |
| 173 | + | underlying source is destroyed, if the user decides to end the image | |
| 174 | + | capture, or if an unrecoverable runtime error has occurred. | |
| 175 | + | ||
| 176 | + | The client should destroy the session after receiving this event. | |
| 177 | + | </description> | |
| 178 | + | </event> | |
| 179 | + | ||
| 180 | + | <request name="create_frame"> | |
| 181 | + | <description summary="create a frame"> | |
| 182 | + | Create a capture frame for this session. | |
| 183 | + | ||
| 184 | + | At most one frame object can exist for a given session at any time. If | |
| 185 | + | a client sends a create_frame request before a previous frame object | |
| 186 | + | has been destroyed, the duplicate_frame protocol error is raised. | |
| 187 | + | </description> | |
| 188 | + | <arg name="frame" type="new_id" interface="ext_image_copy_capture_frame_v1"/> | |
| 189 | + | </request> | |
| 190 | + | ||
| 191 | + | <request name="destroy" type="destructor"> | |
| 192 | + | <description summary="delete this object"> | |
| 193 | + | Destroys the session. This request can be sent at any time by the | |
| 194 | + | client. | |
| 195 | + | ||
| 196 | + | This request doesn't affect ext_image_copy_capture_frame_v1 objects created by | |
| 197 | + | this object. | |
| 198 | + | </description> | |
| 199 | + | </request> | |
| 200 | + | </interface> | |
| 201 | + | ||
| 202 | + | <interface name="ext_image_copy_capture_frame_v1" version="1"> | |
| 203 | + | <description summary="image capture frame"> | |
| 204 | + | This object represents an image capture frame. | |
| 205 | + | ||
| 206 | + | The client should attach a buffer, damage the buffer, and then send a | |
| 207 | + | capture request. | |
| 208 | + | ||
| 209 | + | If the capture is successful, the compositor must send the frame metadata | |
| 210 | + | (transform, damage, presentation_time in any order) followed by the ready | |
| 211 | + | event. | |
| 212 | + | ||
| 213 | + | If the capture fails, the compositor must send the failed event. | |
| 214 | + | </description> | |
| 215 | + | ||
| 216 | + | <enum name="error"> | |
| 217 | + | <entry name="no_buffer" value="1" summary="capture sent without attach_buffer"/> | |
| 218 | + | <entry name="invalid_buffer_damage" value="2" summary="invalid buffer damage"/> | |
| 219 | + | <entry name="already_captured" value="3" summary="capture request has been sent"/> | |
| 220 | + | </enum> | |
| 221 | + | ||
| 222 | + | <request name="destroy" type="destructor"> | |
| 223 | + | <description summary="destroy this object"> | |
| 224 | + | Destroys the frame. This request can be sent at any time by the | |
| 225 | + | client. | |
| 226 | + | </description> | |
| 227 | + | </request> | |
| 228 | + | ||
| 229 | + | <request name="attach_buffer"> | |
| 230 | + | <description summary="attach buffer to session"> | |
| 231 | + | Attach a buffer to the session. | |
| 232 | + | ||
| 233 | + | The wl_buffer.release request is unused. | |
| 234 | + | ||
| 235 | + | The new buffer replaces any previously attached buffer. | |
| 236 | + | ||
| 237 | + | This request must not be sent after capture, or else the | |
| 238 | + | already_captured protocol error is raised. | |
| 239 | + | </description> | |
| 240 | + | <arg name="buffer" type="object" interface="wl_buffer"/> | |
| 241 | + | </request> | |
| 242 | + | ||
| 243 | + | <request name="damage_buffer"> | |
| 244 | + | <description summary="damage buffer"> | |
| 245 | + | Apply damage to the buffer which is to be captured next. This request | |
| 246 | + | may be sent multiple times to describe a region. | |
| 247 | + | ||
| 248 | + | The client indicates the accumulated damage since this wl_buffer was | |
| 249 | + | last captured. During capture, the compositor will update the buffer | |
| 250 | + | with at least the union of the region passed by the client and the | |
| 251 | + | region advertised by ext_image_copy_capture_frame_v1.damage. | |
| 252 | + | ||
| 253 | + | When a wl_buffer is captured for the first time, or when the client | |
| 254 | + | doesn't track damage, the client must damage the whole buffer. | |
| 255 | + | ||
| 256 | + | This is for optimisation purposes. The compositor may use this | |
| 257 | + | information to reduce copying. | |
| 258 | + | ||
| 259 | + | These coordinates originate from the upper left corner of the buffer. | |
| 260 | + | ||
| 261 | + | If x or y are strictly negative, or if width or height are negative or | |
| 262 | + | zero, the invalid_buffer_damage protocol error is raised. | |
| 263 | + | ||
| 264 | + | This request must not be sent after capture, or else the | |
| 265 | + | already_captured protocol error is raised. | |
| 266 | + | </description> | |
| 267 | + | <arg name="x" type="int" summary="region x coordinate"/> | |
| 268 | + | <arg name="y" type="int" summary="region y coordinate"/> | |
| 269 | + | <arg name="width" type="int" summary="region width"/> | |
| 270 | + | <arg name="height" type="int" summary="region height"/> | |
| 271 | + | </request> | |
| 272 | + | ||
| 273 | + | <request name="capture"> | |
| 274 | + | <description summary="capture a frame"> | |
| 275 | + | Capture a frame. | |
| 276 | + | ||
| 277 | + | Unless this is the first successful captured frame performed in this | |
| 278 | + | session, the compositor may wait an indefinite amount of time for the | |
| 279 | + | source content to change before performing the copy. | |
| 280 | + | ||
| 281 | + | This request may only be sent once, or else the already_captured | |
| 282 | + | protocol error is raised. A buffer must be attached before this request | |
| 283 | + | is sent, or else the no_buffer protocol error is raised. | |
| 284 | + | </description> | |
| 285 | + | </request> | |
| 286 | + | ||
| 287 | + | <event name="transform"> | |
| 288 | + | <description summary="buffer transform"> | |
| 289 | + | This event is sent before the ready event and holds the transform that | |
| 290 | + | the compositor has applied to the buffer contents. | |
| 291 | + | </description> | |
| 292 | + | <arg name="transform" type="uint" enum="wl_output.transform"/> | |
| 293 | + | </event> | |
| 294 | + | ||
| 295 | + | <event name="damage"> | |
| 296 | + | <description summary="buffer damaged region"> | |
| 297 | + | This event is sent before the ready event. It may be generated multiple | |
| 298 | + | times to describe a region. | |
| 299 | + | ||
| 300 | + | The first captured frame in a session will always carry full damage. | |
| 301 | + | Subsequent frames' damaged regions describe which parts of the buffer | |
| 302 | + | have changed since the last ready event. | |
| 303 | + | ||
| 304 | + | These coordinates originate in the upper left corner of the buffer. | |
| 305 | + | </description> | |
| 306 | + | <arg name="x" type="int" summary="damage x coordinate"/> | |
| 307 | + | <arg name="y" type="int" summary="damage y coordinate"/> | |
| 308 | + | <arg name="width" type="int" summary="damage width"/> | |
| 309 | + | <arg name="height" type="int" summary="damage height"/> | |
| 310 | + | </event> | |
| 311 | + | ||
| 312 | + | <event name="presentation_time"> | |
| 313 | + | <description summary="presentation time of the frame"> | |
| 314 | + | This event indicates the time at which the frame is presented to the | |
| 315 | + | output in system monotonic time. This event is sent before the ready | |
| 316 | + | event. | |
| 317 | + | ||
| 318 | + | The timestamp is expressed as tv_sec_hi, tv_sec_lo, tv_nsec triples, | |
| 319 | + | each component being an unsigned 32-bit value. Whole seconds are in | |
| 320 | + | tv_sec which is a 64-bit value combined from tv_sec_hi and tv_sec_lo, | |
| 321 | + | and the additional fractional part in tv_nsec as nanoseconds. Hence, | |
| 322 | + | for valid timestamps tv_nsec must be in [0, 999999999]. | |
| 323 | + | </description> | |
| 324 | + | <arg name="tv_sec_hi" type="uint" | |
| 325 | + | summary="high 32 bits of the seconds part of the timestamp"/> | |
| 326 | + | <arg name="tv_sec_lo" type="uint" | |
| 327 | + | summary="low 32 bits of the seconds part of the timestamp"/> | |
| 328 | + | <arg name="tv_nsec" type="uint" | |
| 329 | + | summary="nanoseconds part of the timestamp"/> | |
| 330 | + | </event> | |
| 331 | + | ||
| 332 | + | <event name="ready"> | |
| 333 | + | <description summary="frame is available for reading"> | |
| 334 | + | Called as soon as the frame is copied, indicating it is available | |
| 335 | + | for reading. | |
| 336 | + | ||
| 337 | + | The buffer may be re-used by the client after this event. | |
| 338 | + | ||
| 339 | + | After receiving this event, the client must destroy the object. | |
| 340 | + | </description> | |
| 341 | + | </event> | |
| 342 | + | ||
| 343 | + | <enum name="failure_reason"> | |
| 344 | + | <entry name="unknown" value="0"> | |
| 345 | + | <description summary="unknown runtime error"> | |
| 346 | + | An unspecified runtime error has occurred. The client may retry. | |
| 347 | + | </description> | |
| 348 | + | </entry> | |
| 349 | + | <entry name="buffer_constraints" value="1"> | |
| 350 | + | <description summary="buffer constraints mismatch"> | |
| 351 | + | The buffer submitted by the client doesn't match the latest session | |
| 352 | + | constraints. The client should re-allocate its buffers and retry. | |
| 353 | + | </description> | |
| 354 | + | </entry> | |
| 355 | + | <entry name="stopped" value="2"> | |
| 356 | + | <description summary="session is no longer available"> | |
| 357 | + | The session has stopped. See ext_image_copy_capture_session_v1.stopped. | |
| 358 | + | </description> | |
| 359 | + | </entry> | |
| 360 | + | </enum> | |
| 361 | + | ||
| 362 | + | <event name="failed"> | |
| 363 | + | <description summary="capture failed"> | |
| 364 | + | This event indicates that the attempted frame copy has failed. | |
| 365 | + | ||
| 366 | + | After receiving this event, the client must destroy the object. | |
| 367 | + | </description> | |
| 368 | + | <arg name="reason" type="uint" enum="failure_reason"/> | |
| 369 | + | </event> | |
| 370 | + | </interface> | |
| 371 | + | ||
| 372 | + | <interface name="ext_image_copy_capture_cursor_session_v1" version="1"> | |
| 373 | + | <description summary="cursor capture session"> | |
| 374 | + | This object represents a cursor capture session. It extends the base | |
| 375 | + | capture session with cursor-specific metadata. | |
| 376 | + | </description> | |
| 377 | + | ||
| 378 | + | <enum name="error"> | |
| 379 | + | <entry name="duplicate_session" value="1" summary="get_capture_session sent twice"/> | |
| 380 | + | </enum> | |
| 381 | + | ||
| 382 | + | <request name="destroy" type="destructor"> | |
| 383 | + | <description summary="delete this object"> | |
| 384 | + | Destroys the session. This request can be sent at any time by the | |
| 385 | + | client. | |
| 386 | + | ||
| 387 | + | This request doesn't affect ext_image_copy_capture_frame_v1 objects created by | |
| 388 | + | this object. | |
| 389 | + | </description> | |
| 390 | + | </request> | |
| 391 | + | ||
| 392 | + | <request name="get_capture_session"> | |
| 393 | + | <description summary="get image copy capturer session"> | |
| 394 | + | Gets the image copy capture session for this cursor session. | |
| 395 | + | ||
| 396 | + | The session will produce frames of the cursor image. The compositor may | |
| 397 | + | pause the session when the cursor leaves the captured area. | |
| 398 | + | ||
| 399 | + | This request must not be sent more than once, or else the | |
| 400 | + | duplicate_session protocol error is raised. | |
| 401 | + | </description> | |
| 402 | + | <arg name="session" type="new_id" interface="ext_image_copy_capture_session_v1"/> | |
| 403 | + | </request> | |
| 404 | + | ||
| 405 | + | <event name="enter"> | |
| 406 | + | <description summary="cursor entered captured area"> | |
| 407 | + | Sent when a cursor enters the captured area. It shall be generated | |
| 408 | + | before the "position" and "hotspot" events when and only when a cursor | |
| 409 | + | enters the area. | |
| 410 | + | ||
| 411 | + | The cursor enters the captured area when the cursor image intersects | |
| 412 | + | with the captured area. Note, this is different from e.g. | |
| 413 | + | wl_pointer.enter. | |
| 414 | + | </description> | |
| 415 | + | </event> | |
| 416 | + | ||
| 417 | + | <event name="leave"> | |
| 418 | + | <description summary="cursor left captured area"> | |
| 419 | + | Sent when a cursor leaves the captured area. No "position" or "hotspot" | |
| 420 | + | event is generated for the cursor until the cursor enters the captured | |
| 421 | + | area again. | |
| 422 | + | </description> | |
| 423 | + | </event> | |
| 424 | + | ||
| 425 | + | <event name="position"> | |
| 426 | + | <description summary="position changed"> | |
| 427 | + | Cursors outside the image capture source do not get captured and no | |
| 428 | + | event will be generated for them. | |
| 429 | + | ||
| 430 | + | The given position is the position of the cursor's hotspot and it is | |
| 431 | + | relative to the main buffer's top left corner in transformed buffer | |
| 432 | + | pixel coordinates. The coordinates may be negative or greater than the | |
| 433 | + | main buffer size. | |
| 434 | + | </description> | |
| 435 | + | <arg name="x" type="int" summary="position x coordinates"/> | |
| 436 | + | <arg name="y" type="int" summary="position y coordinates"/> | |
| 437 | + | </event> | |
| 438 | + | ||
| 439 | + | <event name="hotspot"> | |
| 440 | + | <description summary="hotspot changed"> | |
| 441 | + | The hotspot describes the offset between the cursor image and the | |
| 442 | + | position of the input device. | |
| 443 | + | ||
| 444 | + | The given coordinates are the hotspot's offset from the origin in | |
| 445 | + | buffer coordinates. | |
| 446 | + | ||
| 447 | + | Clients should not apply the hotspot immediately: the hotspot becomes | |
| 448 | + | effective when the next ext_image_copy_capture_frame_v1.ready event is received. | |
| 449 | + | ||
| 450 | + | Compositors may delay this event until the client captures a new frame. | |
| 451 | + | </description> | |
| 452 | + | <arg name="x" type="int" summary="hotspot x coordinates"/> | |
| 453 | + | <arg name="y" type="int" summary="hotspot y coordinates"/> | |
| 454 | + | </event> | |
| 455 | + | </interface> | |
| 456 | + | </protocol> | |
A protocol/imagecopycapture/ext-image-copy-capture-v1_generated.go +796 -0
| @@ -0,0 +1,796 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: ext_image_copy_capture_v1 | |
| 3 | + | // Source: ext-image-copy-capture-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2021-2023 Andri Yngvason | |
| 7 | + | // Copyright © 2024 Simon Ser | |
| 8 | + | // | |
| 9 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 10 | + | // copy of this software and associated documentation files (the "Software"), | |
| 11 | + | // to deal in the Software without restriction, including without limitation | |
| 12 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 13 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 14 | + | // Software is furnished to do so, subject to the following conditions: | |
| 15 | + | // | |
| 16 | + | // The above copyright notice and this permission notice (including the next | |
| 17 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 18 | + | // Software. | |
| 19 | + | // | |
| 20 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 21 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 22 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 23 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 24 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 25 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 26 | + | // DEALINGS IN THE SOFTWARE. | |
| 27 | + | ||
| 28 | + | package imagecopycapture | |
| 29 | + | ||
| 30 | + | import ( | |
| 31 | + | "sync" | |
| 32 | + | ||
| 33 | + | cross_wl_buffer "github.com/bnema/wlturbo/protocol/core" | |
| 34 | + | cross_wl_pointer "github.com/bnema/wlturbo/protocol/core" | |
| 35 | + | cross_ext_image_capture_source_v1 "github.com/bnema/wlturbo/protocol/imagecapturesource" | |
| 36 | + | "github.com/bnema/wlturbo/wl" | |
| 37 | + | ) | |
| 38 | + | ||
| 39 | + | // ERROR_INVALID_OPTION is the error invalid_option value. | |
| 40 | + | const ERROR_INVALID_OPTION = 1 | |
| 41 | + | ||
| 42 | + | // OPTIONS_PAINT_CURSORS is the options paint_cursors value. | |
| 43 | + | const OPTIONS_PAINT_CURSORS = 1 | |
| 44 | + | ||
| 45 | + | // ERROR_DUPLICATE_FRAME is the error duplicate_frame value. | |
| 46 | + | const ERROR_DUPLICATE_FRAME = 1 | |
| 47 | + | ||
| 48 | + | // ERROR_NO_BUFFER is the error no_buffer value. | |
| 49 | + | const ERROR_NO_BUFFER = 1 | |
| 50 | + | ||
| 51 | + | // ERROR_INVALID_BUFFER_DAMAGE is the error invalid_buffer_damage value. | |
| 52 | + | const ERROR_INVALID_BUFFER_DAMAGE = 2 | |
| 53 | + | ||
| 54 | + | // ERROR_ALREADY_CAPTURED is the error already_captured value. | |
| 55 | + | const ERROR_ALREADY_CAPTURED = 3 | |
| 56 | + | ||
| 57 | + | // FAILURE_REASON_UNKNOWN is the failure_reason unknown value. | |
| 58 | + | const FAILURE_REASON_UNKNOWN = 0 | |
| 59 | + | ||
| 60 | + | // FAILURE_REASON_BUFFER_CONSTRAINTS is the failure_reason buffer_constraints value. | |
| 61 | + | const FAILURE_REASON_BUFFER_CONSTRAINTS = 1 | |
| 62 | + | ||
| 63 | + | // FAILURE_REASON_STOPPED is the failure_reason stopped value. | |
| 64 | + | const FAILURE_REASON_STOPPED = 2 | |
| 65 | + | ||
| 66 | + | // ERROR_DUPLICATE_SESSION is the error duplicate_session value. | |
| 67 | + | const ERROR_DUPLICATE_SESSION = 1 | |
| 68 | + | ||
| 69 | + | // ExtImageCopyCaptureManagerInterface is the protocol interface name. | |
| 70 | + | const ExtImageCopyCaptureManagerInterface = "ext_image_copy_capture_manager_v1" | |
| 71 | + | ||
| 72 | + | // ExtImageCopyCaptureManager is the generated binding for ext_image_copy_capture_manager_v1 version 1. | |
| 73 | + | type ExtImageCopyCaptureManager struct { | |
| 74 | + | wl.BaseProxy | |
| 75 | + | } | |
| 76 | + | ||
| 77 | + | // NewExtImageCopyCaptureManager returns an unbound ExtImageCopyCaptureManager. | |
| 78 | + | func NewExtImageCopyCaptureManager(ctx *wl.Context) *ExtImageCopyCaptureManager { | |
| 79 | + | obj := &ExtImageCopyCaptureManager{} | |
| 80 | + | obj.SetContext(ctx) | |
| 81 | + | ctx.Register(obj) | |
| 82 | + | return obj | |
| 83 | + | } | |
| 84 | + | ||
| 85 | + | // Create a capturing session for an image capture source. If the paint_cursors option is set, cursors shall be composited onto the captured frame. The cursor must not be composited onto the frame if this flag is not set. If the options bitfield is invalid, the invalid_option protocol error is sent. | |
| 86 | + | func (o *ExtImageCopyCaptureManager) CreateSession(source *cross_ext_image_capture_source_v1.ExtImageCaptureSource, options uint32) (*ExtImageCopyCaptureSession, error) { | |
| 87 | + | var arg1 wl.Object | |
| 88 | + | if source != nil { | |
| 89 | + | arg1 = source | |
| 90 | + | } | |
| 91 | + | child := &ExtImageCopyCaptureSession{} | |
| 92 | + | child.SetContext(o.Context()) | |
| 93 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_image_copy_capture_manager_v1.create_session", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1), wl.ArgUint(options)); err != nil { | |
| 94 | + | return nil, err | |
| 95 | + | } | |
| 96 | + | return child, nil | |
| 97 | + | } | |
| 98 | + | ||
| 99 | + | // Create a cursor capturing session for the pointer of an image capture source. | |
| 100 | + | func (o *ExtImageCopyCaptureManager) CreatePointerCursorSession(source *cross_ext_image_capture_source_v1.ExtImageCaptureSource, pointer *cross_wl_pointer.Pointer) (*ExtImageCopyCaptureCursorSession, error) { | |
| 101 | + | var arg1 wl.Object | |
| 102 | + | if source != nil { | |
| 103 | + | arg1 = source | |
| 104 | + | } | |
| 105 | + | var arg2 wl.Object | |
| 106 | + | if pointer != nil { | |
| 107 | + | arg2 = pointer | |
| 108 | + | } | |
| 109 | + | child := &ExtImageCopyCaptureCursorSession{} | |
| 110 | + | child.SetContext(o.Context()) | |
| 111 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_image_copy_capture_manager_v1.create_pointer_cursor_session", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1), wl.ArgObject(arg2)); err != nil { | |
| 112 | + | return nil, err | |
| 113 | + | } | |
| 114 | + | return child, nil | |
| 115 | + | } | |
| 116 | + | ||
| 117 | + | // Destroy the manager object. Other objects created via this interface are unaffected. | |
| 118 | + | func (o *ExtImageCopyCaptureManager) Destroy() error { | |
| 119 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "ext_image_copy_capture_manager_v1.destroy", Destructor: true}); err != nil { | |
| 120 | + | return err | |
| 121 | + | } | |
| 122 | + | return nil | |
| 123 | + | } | |
| 124 | + | ||
| 125 | + | // EventSignature returns the declared event argument types in wire order. | |
| 126 | + | func (o *ExtImageCopyCaptureManager) EventSignature(opcode uint16) (string, bool) { | |
| 127 | + | switch opcode { | |
| 128 | + | default: | |
| 129 | + | return "", false | |
| 130 | + | } | |
| 131 | + | } | |
| 132 | + | ||
| 133 | + | // Dispatch decodes one event on ext_image_copy_capture_manager_v1 and calls the registered handlers. | |
| 134 | + | func (o *ExtImageCopyCaptureManager) Dispatch(event *wl.Event) { | |
| 135 | + | switch event.Opcode { | |
| 136 | + | default: | |
| 137 | + | } | |
| 138 | + | } | |
| 139 | + | ||
| 140 | + | // ExtImageCopyCaptureSessionInterface is the protocol interface name. | |
| 141 | + | const ExtImageCopyCaptureSessionInterface = "ext_image_copy_capture_session_v1" | |
| 142 | + | ||
| 143 | + | // ExtImageCopyCaptureSession is the generated binding for ext_image_copy_capture_session_v1 version 1. | |
| 144 | + | type ExtImageCopyCaptureSession struct { | |
| 145 | + | wl.BaseProxy | |
| 146 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 147 | + | // handlers while another goroutine dispatches events. | |
| 148 | + | handlersMu sync.Mutex | |
| 149 | + | onBufferSize []func(width uint32, height uint32) | |
| 150 | + | onShmFormat []func(format uint32) | |
| 151 | + | onDmabufDevice []func(device []byte) | |
| 152 | + | onDmabufFormat []func(format uint32, modifiers []byte) | |
| 153 | + | onDone []func() | |
| 154 | + | onStopped []func() | |
| 155 | + | } | |
| 156 | + | ||
| 157 | + | // NewExtImageCopyCaptureSession returns an unbound ExtImageCopyCaptureSession. | |
| 158 | + | func NewExtImageCopyCaptureSession(ctx *wl.Context) *ExtImageCopyCaptureSession { | |
| 159 | + | obj := &ExtImageCopyCaptureSession{} | |
| 160 | + | obj.SetContext(ctx) | |
| 161 | + | ctx.Register(obj) | |
| 162 | + | return obj | |
| 163 | + | } | |
| 164 | + | ||
| 165 | + | // Create a capture frame for this session. At most one frame object can exist for a given session at any time. If a client sends a create_frame request before a previous frame object has been destroyed, the duplicate_frame protocol error is raised. | |
| 166 | + | func (o *ExtImageCopyCaptureSession) CreateFrame() (*ExtImageCopyCaptureFrame, error) { | |
| 167 | + | child := &ExtImageCopyCaptureFrame{} | |
| 168 | + | child.SetContext(o.Context()) | |
| 169 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_image_copy_capture_session_v1.create_frame", Child: child}, wl.ArgObject(child)); err != nil { | |
| 170 | + | return nil, err | |
| 171 | + | } | |
| 172 | + | return child, nil | |
| 173 | + | } | |
| 174 | + | ||
| 175 | + | // Destroys the session. This request can be sent at any time by the client. This request doesn't affect ext_image_copy_capture_frame_v1 objects created by this object. | |
| 176 | + | func (o *ExtImageCopyCaptureSession) Destroy() error { | |
| 177 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_image_copy_capture_session_v1.destroy", Destructor: true}); err != nil { | |
| 178 | + | return err | |
| 179 | + | } | |
| 180 | + | return nil | |
| 181 | + | } | |
| 182 | + | ||
| 183 | + | // OnBufferSize registers a handler for the buffer_size event. | |
| 184 | + | // | |
| 185 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 186 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 187 | + | func (o *ExtImageCopyCaptureSession) OnBufferSize(handler func(width uint32, height uint32)) { | |
| 188 | + | if handler == nil { | |
| 189 | + | return | |
| 190 | + | } | |
| 191 | + | o.handlersMu.Lock() | |
| 192 | + | defer o.handlersMu.Unlock() | |
| 193 | + | o.onBufferSize = append(o.onBufferSize, handler) | |
| 194 | + | } | |
| 195 | + | ||
| 196 | + | // handlersForBufferSize returns the handlers registered for buffer_size, taken | |
| 197 | + | // under the lock so a handler may register another handler while events are | |
| 198 | + | // being dispatched. | |
| 199 | + | func (o *ExtImageCopyCaptureSession) handlersForBufferSize() []func(width uint32, height uint32) { | |
| 200 | + | o.handlersMu.Lock() | |
| 201 | + | defer o.handlersMu.Unlock() | |
| 202 | + | return o.onBufferSize | |
| 203 | + | } | |
| 204 | + | ||
| 205 | + | // OnShmFormat registers a handler for the shm_format event. | |
| 206 | + | // | |
| 207 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 208 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 209 | + | func (o *ExtImageCopyCaptureSession) OnShmFormat(handler func(format uint32)) { | |
| 210 | + | if handler == nil { | |
| 211 | + | return | |
| 212 | + | } | |
| 213 | + | o.handlersMu.Lock() | |
| 214 | + | defer o.handlersMu.Unlock() | |
| 215 | + | o.onShmFormat = append(o.onShmFormat, handler) | |
| 216 | + | } | |
| 217 | + | ||
| 218 | + | // handlersForShmFormat returns the handlers registered for shm_format, taken | |
| 219 | + | // under the lock so a handler may register another handler while events are | |
| 220 | + | // being dispatched. | |
| 221 | + | func (o *ExtImageCopyCaptureSession) handlersForShmFormat() []func(format uint32) { | |
| 222 | + | o.handlersMu.Lock() | |
| 223 | + | defer o.handlersMu.Unlock() | |
| 224 | + | return o.onShmFormat | |
| 225 | + | } | |
| 226 | + | ||
| 227 | + | // OnDmabufDevice registers a handler for the dmabuf_device event. | |
| 228 | + | // | |
| 229 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 230 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 231 | + | func (o *ExtImageCopyCaptureSession) OnDmabufDevice(handler func(device []byte)) { | |
| 232 | + | if handler == nil { | |
| 233 | + | return | |
| 234 | + | } | |
| 235 | + | o.handlersMu.Lock() | |
| 236 | + | defer o.handlersMu.Unlock() | |
| 237 | + | o.onDmabufDevice = append(o.onDmabufDevice, handler) | |
| 238 | + | } | |
| 239 | + | ||
| 240 | + | // handlersForDmabufDevice returns the handlers registered for dmabuf_device, taken | |
| 241 | + | // under the lock so a handler may register another handler while events are | |
| 242 | + | // being dispatched. | |
| 243 | + | func (o *ExtImageCopyCaptureSession) handlersForDmabufDevice() []func(device []byte) { | |
| 244 | + | o.handlersMu.Lock() | |
| 245 | + | defer o.handlersMu.Unlock() | |
| 246 | + | return o.onDmabufDevice | |
| 247 | + | } | |
| 248 | + | ||
| 249 | + | // OnDmabufFormat registers a handler for the dmabuf_format event. | |
| 250 | + | // | |
| 251 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 252 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 253 | + | func (o *ExtImageCopyCaptureSession) OnDmabufFormat(handler func(format uint32, modifiers []byte)) { | |
| 254 | + | if handler == nil { | |
| 255 | + | return | |
| 256 | + | } | |
| 257 | + | o.handlersMu.Lock() | |
| 258 | + | defer o.handlersMu.Unlock() | |
| 259 | + | o.onDmabufFormat = append(o.onDmabufFormat, handler) | |
| 260 | + | } | |
| 261 | + | ||
| 262 | + | // handlersForDmabufFormat returns the handlers registered for dmabuf_format, taken | |
| 263 | + | // under the lock so a handler may register another handler while events are | |
| 264 | + | // being dispatched. | |
| 265 | + | func (o *ExtImageCopyCaptureSession) handlersForDmabufFormat() []func(format uint32, modifiers []byte) { | |
| 266 | + | o.handlersMu.Lock() | |
| 267 | + | defer o.handlersMu.Unlock() | |
| 268 | + | return o.onDmabufFormat | |
| 269 | + | } | |
| 270 | + | ||
| 271 | + | // OnDone registers a handler for the done event. | |
| 272 | + | // | |
| 273 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 274 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 275 | + | func (o *ExtImageCopyCaptureSession) OnDone(handler func()) { | |
| 276 | + | if handler == nil { | |
| 277 | + | return | |
| 278 | + | } | |
| 279 | + | o.handlersMu.Lock() | |
| 280 | + | defer o.handlersMu.Unlock() | |
| 281 | + | o.onDone = append(o.onDone, handler) | |
| 282 | + | } | |
| 283 | + | ||
| 284 | + | // handlersForDone returns the handlers registered for done, taken | |
| 285 | + | // under the lock so a handler may register another handler while events are | |
| 286 | + | // being dispatched. | |
| 287 | + | func (o *ExtImageCopyCaptureSession) handlersForDone() []func() { | |
| 288 | + | o.handlersMu.Lock() | |
| 289 | + | defer o.handlersMu.Unlock() | |
| 290 | + | return o.onDone | |
| 291 | + | } | |
| 292 | + | ||
| 293 | + | // OnStopped registers a handler for the stopped event. | |
| 294 | + | // | |
| 295 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 296 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 297 | + | func (o *ExtImageCopyCaptureSession) OnStopped(handler func()) { | |
| 298 | + | if handler == nil { | |
| 299 | + | return | |
| 300 | + | } | |
| 301 | + | o.handlersMu.Lock() | |
| 302 | + | defer o.handlersMu.Unlock() | |
| 303 | + | o.onStopped = append(o.onStopped, handler) | |
| 304 | + | } | |
| 305 | + | ||
| 306 | + | // handlersForStopped returns the handlers registered for stopped, taken | |
| 307 | + | // under the lock so a handler may register another handler while events are | |
| 308 | + | // being dispatched. | |
| 309 | + | func (o *ExtImageCopyCaptureSession) handlersForStopped() []func() { | |
| 310 | + | o.handlersMu.Lock() | |
| 311 | + | defer o.handlersMu.Unlock() | |
| 312 | + | return o.onStopped | |
| 313 | + | } | |
| 314 | + | ||
| 315 | + | // EventSignature returns the declared event argument types in wire order. | |
| 316 | + | func (o *ExtImageCopyCaptureSession) EventSignature(opcode uint16) (string, bool) { | |
| 317 | + | switch opcode { | |
| 318 | + | case 0: | |
| 319 | + | return "uint,uint,", true | |
| 320 | + | case 1: | |
| 321 | + | return "uint,", true | |
| 322 | + | case 2: | |
| 323 | + | return "array,", true | |
| 324 | + | case 3: | |
| 325 | + | return "uint,array,", true | |
| 326 | + | case 4: | |
| 327 | + | return "", true | |
| 328 | + | case 5: | |
| 329 | + | return "", true | |
| 330 | + | default: | |
| 331 | + | return "", false | |
| 332 | + | } | |
| 333 | + | } | |
| 334 | + | ||
| 335 | + | // Dispatch decodes one event on ext_image_copy_capture_session_v1 and calls the registered handlers. | |
| 336 | + | func (o *ExtImageCopyCaptureSession) Dispatch(event *wl.Event) { | |
| 337 | + | switch event.Opcode { | |
| 338 | + | case 0: // buffer_size | |
| 339 | + | width := event.Uint32() | |
| 340 | + | height := event.Uint32() | |
| 341 | + | ||
| 342 | + | for i, handler := range o.handlersForBufferSize() { | |
| 343 | + | _ = i | |
| 344 | + | handler(width, height) | |
| 345 | + | } | |
| 346 | + | case 1: // shm_format | |
| 347 | + | format := event.Uint32() | |
| 348 | + | ||
| 349 | + | for i, handler := range o.handlersForShmFormat() { | |
| 350 | + | _ = i | |
| 351 | + | handler(format) | |
| 352 | + | } | |
| 353 | + | case 2: // dmabuf_device | |
| 354 | + | device := event.Array() | |
| 355 | + | ||
| 356 | + | for i, handler := range o.handlersForDmabufDevice() { | |
| 357 | + | _ = i | |
| 358 | + | handler(device) | |
| 359 | + | } | |
| 360 | + | case 3: // dmabuf_format | |
| 361 | + | format := event.Uint32() | |
| 362 | + | modifiers := event.Array() | |
| 363 | + | ||
| 364 | + | for i, handler := range o.handlersForDmabufFormat() { | |
| 365 | + | _ = i | |
| 366 | + | handler(format, modifiers) | |
| 367 | + | } | |
| 368 | + | case 4: // done | |
| 369 | + | ||
| 370 | + | for i, handler := range o.handlersForDone() { | |
| 371 | + | _ = i | |
| 372 | + | handler() | |
| 373 | + | } | |
| 374 | + | case 5: // stopped | |
| 375 | + | ||
| 376 | + | for i, handler := range o.handlersForStopped() { | |
| 377 | + | _ = i | |
| 378 | + | handler() | |
| 379 | + | } | |
| 380 | + | default: | |
| 381 | + | } | |
| 382 | + | } | |
| 383 | + | ||
| 384 | + | // ExtImageCopyCaptureFrameInterface is the protocol interface name. | |
| 385 | + | const ExtImageCopyCaptureFrameInterface = "ext_image_copy_capture_frame_v1" | |
| 386 | + | ||
| 387 | + | // ExtImageCopyCaptureFrame is the generated binding for ext_image_copy_capture_frame_v1 version 1. | |
| 388 | + | type ExtImageCopyCaptureFrame struct { | |
| 389 | + | wl.BaseProxy | |
| 390 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 391 | + | // handlers while another goroutine dispatches events. | |
| 392 | + | handlersMu sync.Mutex | |
| 393 | + | onTransform []func(transform uint32) | |
| 394 | + | onDamage []func(x int32, y int32, width int32, height int32) | |
| 395 | + | onPresentationTime []func(tvSecHi uint32, tvSecLo uint32, tvNsec uint32) | |
| 396 | + | onReady []func() | |
| 397 | + | onFailed []func(reason uint32) | |
| 398 | + | } | |
| 399 | + | ||
| 400 | + | // NewExtImageCopyCaptureFrame returns an unbound ExtImageCopyCaptureFrame. | |
| 401 | + | func NewExtImageCopyCaptureFrame(ctx *wl.Context) *ExtImageCopyCaptureFrame { | |
| 402 | + | obj := &ExtImageCopyCaptureFrame{} | |
| 403 | + | obj.SetContext(ctx) | |
| 404 | + | ctx.Register(obj) | |
| 405 | + | return obj | |
| 406 | + | } | |
| 407 | + | ||
| 408 | + | // Destroys the frame. This request can be sent at any time by the client. | |
| 409 | + | func (o *ExtImageCopyCaptureFrame) Destroy() error { | |
| 410 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_image_copy_capture_frame_v1.destroy", Destructor: true}); err != nil { | |
| 411 | + | return err | |
| 412 | + | } | |
| 413 | + | return nil | |
| 414 | + | } | |
| 415 | + | ||
| 416 | + | // Attach a buffer to the session. The wl_buffer.release request is unused. The new buffer replaces any previously attached buffer. This request must not be sent after capture, or else the already_captured protocol error is raised. | |
| 417 | + | func (o *ExtImageCopyCaptureFrame) AttachBuffer(buffer *cross_wl_buffer.Buffer) error { | |
| 418 | + | var arg0 wl.Object | |
| 419 | + | if buffer != nil { | |
| 420 | + | arg0 = buffer | |
| 421 | + | } | |
| 422 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_image_copy_capture_frame_v1.attach_buffer"}, wl.ArgObject(arg0)); err != nil { | |
| 423 | + | return err | |
| 424 | + | } | |
| 425 | + | return nil | |
| 426 | + | } | |
| 427 | + | ||
| 428 | + | // Apply damage to the buffer which is to be captured next. This request may be sent multiple times to describe a region. The client indicates the accumulated damage since this wl_buffer was last captured. During capture, the compositor will update the buffer with at least the union of the region passed by the client and the region advertised by ext_image_copy_capture_frame_v1.damage. When a wl_buffer is captured for the first time, or when the client doesn't track damage, the client must damage the whole buffer. This is for optimisation purposes. The compositor may use this information to reduce copying. These coordinates originate from the upper left corner of the buffer. If x or y are strictly negative, or if width or height are negative or zero, the invalid_buffer_damage protocol error is raised. This request must not be sent after capture, or else the already_captured protocol error is raised. | |
| 429 | + | func (o *ExtImageCopyCaptureFrame) DamageBuffer(x int32, y int32, width int32, height int32) error { | |
| 430 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "ext_image_copy_capture_frame_v1.damage_buffer"}, wl.ArgInt(x), wl.ArgInt(y), wl.ArgInt(width), wl.ArgInt(height)); err != nil { | |
| 431 | + | return err | |
| 432 | + | } | |
| 433 | + | return nil | |
| 434 | + | } | |
| 435 | + | ||
| 436 | + | // Capture a frame. Unless this is the first successful captured frame performed in this session, the compositor may wait an indefinite amount of time for the source content to change before performing the copy. This request may only be sent once, or else the already_captured protocol error is raised. A buffer must be attached before this request is sent, or else the no_buffer protocol error is raised. | |
| 437 | + | func (o *ExtImageCopyCaptureFrame) Capture() error { | |
| 438 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "ext_image_copy_capture_frame_v1.capture"}); err != nil { | |
| 439 | + | return err | |
| 440 | + | } | |
| 441 | + | return nil | |
| 442 | + | } | |
| 443 | + | ||
| 444 | + | // OnTransform registers a handler for the transform event. | |
| 445 | + | // | |
| 446 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 447 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 448 | + | func (o *ExtImageCopyCaptureFrame) OnTransform(handler func(transform uint32)) { | |
| 449 | + | if handler == nil { | |
| 450 | + | return | |
| 451 | + | } | |
| 452 | + | o.handlersMu.Lock() | |
| 453 | + | defer o.handlersMu.Unlock() | |
| 454 | + | o.onTransform = append(o.onTransform, handler) | |
| 455 | + | } | |
| 456 | + | ||
| 457 | + | // handlersForTransform returns the handlers registered for transform, taken | |
| 458 | + | // under the lock so a handler may register another handler while events are | |
| 459 | + | // being dispatched. | |
| 460 | + | func (o *ExtImageCopyCaptureFrame) handlersForTransform() []func(transform uint32) { | |
| 461 | + | o.handlersMu.Lock() | |
| 462 | + | defer o.handlersMu.Unlock() | |
| 463 | + | return o.onTransform | |
| 464 | + | } | |
| 465 | + | ||
| 466 | + | // OnDamage registers a handler for the damage event. | |
| 467 | + | // | |
| 468 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 469 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 470 | + | func (o *ExtImageCopyCaptureFrame) OnDamage(handler func(x int32, y int32, width int32, height int32)) { | |
| 471 | + | if handler == nil { | |
| 472 | + | return | |
| 473 | + | } | |
| 474 | + | o.handlersMu.Lock() | |
| 475 | + | defer o.handlersMu.Unlock() | |
| 476 | + | o.onDamage = append(o.onDamage, handler) | |
| 477 | + | } | |
| 478 | + | ||
| 479 | + | // handlersForDamage returns the handlers registered for damage, taken | |
| 480 | + | // under the lock so a handler may register another handler while events are | |
| 481 | + | // being dispatched. | |
| 482 | + | func (o *ExtImageCopyCaptureFrame) handlersForDamage() []func(x int32, y int32, width int32, height int32) { | |
| 483 | + | o.handlersMu.Lock() | |
| 484 | + | defer o.handlersMu.Unlock() | |
| 485 | + | return o.onDamage | |
| 486 | + | } | |
| 487 | + | ||
| 488 | + | // OnPresentationTime registers a handler for the presentation_time event. | |
| 489 | + | // | |
| 490 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 491 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 492 | + | func (o *ExtImageCopyCaptureFrame) OnPresentationTime(handler func(tvSecHi uint32, tvSecLo uint32, tvNsec uint32)) { | |
| 493 | + | if handler == nil { | |
| 494 | + | return | |
| 495 | + | } | |
| 496 | + | o.handlersMu.Lock() | |
| 497 | + | defer o.handlersMu.Unlock() | |
| 498 | + | o.onPresentationTime = append(o.onPresentationTime, handler) | |
| 499 | + | } | |
| 500 | + | ||
| 501 | + | // handlersForPresentationTime returns the handlers registered for presentation_time, taken | |
| 502 | + | // under the lock so a handler may register another handler while events are | |
| 503 | + | // being dispatched. | |
| 504 | + | func (o *ExtImageCopyCaptureFrame) handlersForPresentationTime() []func(tvSecHi uint32, tvSecLo uint32, tvNsec uint32) { | |
| 505 | + | o.handlersMu.Lock() | |
| 506 | + | defer o.handlersMu.Unlock() | |
| 507 | + | return o.onPresentationTime | |
| 508 | + | } | |
| 509 | + | ||
| 510 | + | // OnReady registers a handler for the ready event. | |
| 511 | + | // | |
| 512 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 513 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 514 | + | func (o *ExtImageCopyCaptureFrame) OnReady(handler func()) { | |
| 515 | + | if handler == nil { | |
| 516 | + | return | |
| 517 | + | } | |
| 518 | + | o.handlersMu.Lock() | |
| 519 | + | defer o.handlersMu.Unlock() | |
| 520 | + | o.onReady = append(o.onReady, handler) | |
| 521 | + | } | |
| 522 | + | ||
| 523 | + | // handlersForReady returns the handlers registered for ready, taken | |
| 524 | + | // under the lock so a handler may register another handler while events are | |
| 525 | + | // being dispatched. | |
| 526 | + | func (o *ExtImageCopyCaptureFrame) handlersForReady() []func() { | |
| 527 | + | o.handlersMu.Lock() | |
| 528 | + | defer o.handlersMu.Unlock() | |
| 529 | + | return o.onReady | |
| 530 | + | } | |
| 531 | + | ||
| 532 | + | // OnFailed registers a handler for the failed event. | |
| 533 | + | // | |
| 534 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 535 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 536 | + | func (o *ExtImageCopyCaptureFrame) OnFailed(handler func(reason uint32)) { | |
| 537 | + | if handler == nil { | |
| 538 | + | return | |
| 539 | + | } | |
| 540 | + | o.handlersMu.Lock() | |
| 541 | + | defer o.handlersMu.Unlock() | |
| 542 | + | o.onFailed = append(o.onFailed, handler) | |
| 543 | + | } | |
| 544 | + | ||
| 545 | + | // handlersForFailed returns the handlers registered for failed, taken | |
| 546 | + | // under the lock so a handler may register another handler while events are | |
| 547 | + | // being dispatched. | |
| 548 | + | func (o *ExtImageCopyCaptureFrame) handlersForFailed() []func(reason uint32) { | |
| 549 | + | o.handlersMu.Lock() | |
| 550 | + | defer o.handlersMu.Unlock() | |
| 551 | + | return o.onFailed | |
| 552 | + | } | |
| 553 | + | ||
| 554 | + | // EventSignature returns the declared event argument types in wire order. | |
| 555 | + | func (o *ExtImageCopyCaptureFrame) EventSignature(opcode uint16) (string, bool) { | |
| 556 | + | switch opcode { | |
| 557 | + | case 0: | |
| 558 | + | return "uint,", true | |
| 559 | + | case 1: | |
| 560 | + | return "int,int,int,int,", true | |
| 561 | + | case 2: | |
| 562 | + | return "uint,uint,uint,", true | |
| 563 | + | case 3: | |
| 564 | + | return "", true | |
| 565 | + | case 4: | |
| 566 | + | return "uint,", true | |
| 567 | + | default: | |
| 568 | + | return "", false | |
| 569 | + | } | |
| 570 | + | } | |
| 571 | + | ||
| 572 | + | // Dispatch decodes one event on ext_image_copy_capture_frame_v1 and calls the registered handlers. | |
| 573 | + | func (o *ExtImageCopyCaptureFrame) Dispatch(event *wl.Event) { | |
| 574 | + | switch event.Opcode { | |
| 575 | + | case 0: // transform | |
| 576 | + | transform := event.Uint32() | |
| 577 | + | ||
| 578 | + | for i, handler := range o.handlersForTransform() { | |
| 579 | + | _ = i | |
| 580 | + | handler(transform) | |
| 581 | + | } | |
| 582 | + | case 1: // damage | |
| 583 | + | x := event.Int32() | |
| 584 | + | y := event.Int32() | |
| 585 | + | width := event.Int32() | |
| 586 | + | height := event.Int32() | |
| 587 | + | ||
| 588 | + | for i, handler := range o.handlersForDamage() { | |
| 589 | + | _ = i | |
| 590 | + | handler(x, y, width, height) | |
| 591 | + | } | |
| 592 | + | case 2: // presentation_time | |
| 593 | + | tvSecHi := event.Uint32() | |
| 594 | + | tvSecLo := event.Uint32() | |
| 595 | + | tvNsec := event.Uint32() | |
| 596 | + | ||
| 597 | + | for i, handler := range o.handlersForPresentationTime() { | |
| 598 | + | _ = i | |
| 599 | + | handler(tvSecHi, tvSecLo, tvNsec) | |
| 600 | + | } | |
| 601 | + | case 3: // ready | |
| 602 | + | ||
| 603 | + | for i, handler := range o.handlersForReady() { | |
| 604 | + | _ = i | |
| 605 | + | handler() | |
| 606 | + | } | |
| 607 | + | case 4: // failed | |
| 608 | + | reason := event.Uint32() | |
| 609 | + | ||
| 610 | + | for i, handler := range o.handlersForFailed() { | |
| 611 | + | _ = i | |
| 612 | + | handler(reason) | |
| 613 | + | } | |
| 614 | + | default: | |
| 615 | + | } | |
| 616 | + | } | |
| 617 | + | ||
| 618 | + | // ExtImageCopyCaptureCursorSessionInterface is the protocol interface name. | |
| 619 | + | const ExtImageCopyCaptureCursorSessionInterface = "ext_image_copy_capture_cursor_session_v1" | |
| 620 | + | ||
| 621 | + | // ExtImageCopyCaptureCursorSession is the generated binding for ext_image_copy_capture_cursor_session_v1 version 1. | |
| 622 | + | type ExtImageCopyCaptureCursorSession struct { | |
| 623 | + | wl.BaseProxy | |
| 624 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 625 | + | // handlers while another goroutine dispatches events. | |
| 626 | + | handlersMu sync.Mutex | |
| 627 | + | onEnter []func() | |
| 628 | + | onLeave []func() | |
| 629 | + | onPosition []func(x int32, y int32) | |
| 630 | + | onHotspot []func(x int32, y int32) | |
| 631 | + | } | |
| 632 | + | ||
| 633 | + | // NewExtImageCopyCaptureCursorSession returns an unbound ExtImageCopyCaptureCursorSession. | |
| 634 | + | func NewExtImageCopyCaptureCursorSession(ctx *wl.Context) *ExtImageCopyCaptureCursorSession { | |
| 635 | + | obj := &ExtImageCopyCaptureCursorSession{} | |
| 636 | + | obj.SetContext(ctx) | |
| 637 | + | ctx.Register(obj) | |
| 638 | + | return obj | |
| 639 | + | } | |
| 640 | + | ||
| 641 | + | // Destroys the session. This request can be sent at any time by the client. This request doesn't affect ext_image_copy_capture_frame_v1 objects created by this object. | |
| 642 | + | func (o *ExtImageCopyCaptureCursorSession) Destroy() error { | |
| 643 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "ext_image_copy_capture_cursor_session_v1.destroy", Destructor: true}); err != nil { | |
| 644 | + | return err | |
| 645 | + | } | |
| 646 | + | return nil | |
| 647 | + | } | |
| 648 | + | ||
| 649 | + | // Gets the image copy capture session for this cursor session. The session will produce frames of the cursor image. The compositor may pause the session when the cursor leaves the captured area. This request must not be sent more than once, or else the duplicate_session protocol error is raised. | |
| 650 | + | func (o *ExtImageCopyCaptureCursorSession) GetCaptureSession() (*ExtImageCopyCaptureSession, error) { | |
| 651 | + | child := &ExtImageCopyCaptureSession{} | |
| 652 | + | child.SetContext(o.Context()) | |
| 653 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "ext_image_copy_capture_cursor_session_v1.get_capture_session", Child: child}, wl.ArgObject(child)); err != nil { | |
| 654 | + | return nil, err | |
| 655 | + | } | |
| 656 | + | return child, nil | |
| 657 | + | } | |
| 658 | + | ||
| 659 | + | // OnEnter registers a handler for the enter event. | |
| 660 | + | // | |
| 661 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 662 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 663 | + | func (o *ExtImageCopyCaptureCursorSession) OnEnter(handler func()) { | |
| 664 | + | if handler == nil { | |
| 665 | + | return | |
| 666 | + | } | |
| 667 | + | o.handlersMu.Lock() | |
| 668 | + | defer o.handlersMu.Unlock() | |
| 669 | + | o.onEnter = append(o.onEnter, handler) | |
| 670 | + | } | |
| 671 | + | ||
| 672 | + | // handlersForEnter returns the handlers registered for enter, taken | |
| 673 | + | // under the lock so a handler may register another handler while events are | |
| 674 | + | // being dispatched. | |
| 675 | + | func (o *ExtImageCopyCaptureCursorSession) handlersForEnter() []func() { | |
| 676 | + | o.handlersMu.Lock() | |
| 677 | + | defer o.handlersMu.Unlock() | |
| 678 | + | return o.onEnter | |
| 679 | + | } | |
| 680 | + | ||
| 681 | + | // OnLeave registers a handler for the leave event. | |
| 682 | + | // | |
| 683 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 684 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 685 | + | func (o *ExtImageCopyCaptureCursorSession) OnLeave(handler func()) { | |
| 686 | + | if handler == nil { | |
| 687 | + | return | |
| 688 | + | } | |
| 689 | + | o.handlersMu.Lock() | |
| 690 | + | defer o.handlersMu.Unlock() | |
| 691 | + | o.onLeave = append(o.onLeave, handler) | |
| 692 | + | } | |
| 693 | + | ||
| 694 | + | // handlersForLeave returns the handlers registered for leave, taken | |
| 695 | + | // under the lock so a handler may register another handler while events are | |
| 696 | + | // being dispatched. | |
| 697 | + | func (o *ExtImageCopyCaptureCursorSession) handlersForLeave() []func() { | |
| 698 | + | o.handlersMu.Lock() | |
| 699 | + | defer o.handlersMu.Unlock() | |
| 700 | + | return o.onLeave | |
| 701 | + | } | |
| 702 | + | ||
| 703 | + | // OnPosition registers a handler for the position event. | |
| 704 | + | // | |
| 705 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 706 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 707 | + | func (o *ExtImageCopyCaptureCursorSession) OnPosition(handler func(x int32, y int32)) { | |
| 708 | + | if handler == nil { | |
| 709 | + | return | |
| 710 | + | } | |
| 711 | + | o.handlersMu.Lock() | |
| 712 | + | defer o.handlersMu.Unlock() | |
| 713 | + | o.onPosition = append(o.onPosition, handler) | |
| 714 | + | } | |
| 715 | + | ||
| 716 | + | // handlersForPosition returns the handlers registered for position, taken | |
| 717 | + | // under the lock so a handler may register another handler while events are | |
| 718 | + | // being dispatched. | |
| 719 | + | func (o *ExtImageCopyCaptureCursorSession) handlersForPosition() []func(x int32, y int32) { | |
| 720 | + | o.handlersMu.Lock() | |
| 721 | + | defer o.handlersMu.Unlock() | |
| 722 | + | return o.onPosition | |
| 723 | + | } | |
| 724 | + | ||
| 725 | + | // OnHotspot registers a handler for the hotspot event. | |
| 726 | + | // | |
| 727 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 728 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 729 | + | func (o *ExtImageCopyCaptureCursorSession) OnHotspot(handler func(x int32, y int32)) { | |
| 730 | + | if handler == nil { | |
| 731 | + | return | |
| 732 | + | } | |
| 733 | + | o.handlersMu.Lock() | |
| 734 | + | defer o.handlersMu.Unlock() | |
| 735 | + | o.onHotspot = append(o.onHotspot, handler) | |
| 736 | + | } | |
| 737 | + | ||
| 738 | + | // handlersForHotspot returns the handlers registered for hotspot, taken | |
| 739 | + | // under the lock so a handler may register another handler while events are | |
| 740 | + | // being dispatched. | |
| 741 | + | func (o *ExtImageCopyCaptureCursorSession) handlersForHotspot() []func(x int32, y int32) { | |
| 742 | + | o.handlersMu.Lock() | |
| 743 | + | defer o.handlersMu.Unlock() | |
| 744 | + | return o.onHotspot | |
| 745 | + | } | |
| 746 | + | ||
| 747 | + | // EventSignature returns the declared event argument types in wire order. | |
| 748 | + | func (o *ExtImageCopyCaptureCursorSession) EventSignature(opcode uint16) (string, bool) { | |
| 749 | + | switch opcode { | |
| 750 | + | case 0: | |
| 751 | + | return "", true | |
| 752 | + | case 1: | |
| 753 | + | return "", true | |
| 754 | + | case 2: | |
| 755 | + | return "int,int,", true | |
| 756 | + | case 3: | |
| 757 | + | return "int,int,", true | |
| 758 | + | default: | |
| 759 | + | return "", false | |
| 760 | + | } | |
| 761 | + | } | |
| 762 | + | ||
| 763 | + | // Dispatch decodes one event on ext_image_copy_capture_cursor_session_v1 and calls the registered handlers. | |
| 764 | + | func (o *ExtImageCopyCaptureCursorSession) Dispatch(event *wl.Event) { | |
| 765 | + | switch event.Opcode { | |
| 766 | + | case 0: // enter | |
| 767 | + | ||
| 768 | + | for i, handler := range o.handlersForEnter() { | |
| 769 | + | _ = i | |
| 770 | + | handler() | |
| 771 | + | } | |
| 772 | + | case 1: // leave | |
| 773 | + | ||
| 774 | + | for i, handler := range o.handlersForLeave() { | |
| 775 | + | _ = i | |
| 776 | + | handler() | |
| 777 | + | } | |
| 778 | + | case 2: // position | |
| 779 | + | x := event.Int32() | |
| 780 | + | y := event.Int32() | |
| 781 | + | ||
| 782 | + | for i, handler := range o.handlersForPosition() { | |
| 783 | + | _ = i | |
| 784 | + | handler(x, y) | |
| 785 | + | } | |
| 786 | + | case 3: // hotspot | |
| 787 | + | x := event.Int32() | |
| 788 | + | y := event.Int32() | |
| 789 | + | ||
| 790 | + | for i, handler := range o.handlersForHotspot() { | |
| 791 | + | _ = i | |
| 792 | + | handler(x, y) | |
| 793 | + | } | |
| 794 | + | default: | |
| 795 | + | } | |
| 796 | + | } | |
A protocol/imagecopycapture/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package imagecopycapture | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p imagecopycapture -o ext-image-copy-capture-v1_generated.go -import ext_image_capture_source_v1=github.com/bnema/wlturbo/protocol/imagecapturesource -import wl_buffer=github.com/bnema/wlturbo/protocol/core -import wl_pointer=github.com/bnema/wlturbo/protocol/core ext-image-copy-capture-v1.xml | |
A protocol/input_desktop_extensions_test.go +726 -0
| @@ -0,0 +1,726 @@ | |||
| 1 | + | //go:build linux | |
| 2 | + | ||
| 3 | + | package protocol_test | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "encoding/binary" | |
| 7 | + | "errors" | |
| 8 | + | "os" | |
| 9 | + | "reflect" | |
| 10 | + | "testing" | |
| 11 | + | "time" | |
| 12 | + | ||
| 13 | + | "github.com/bnema/wlturbo" | |
| 14 | + | "github.com/bnema/wlturbo/protocol/datacontrol" | |
| 15 | + | "github.com/bnema/wlturbo/protocol/extforeigntoplevel" | |
| 16 | + | "github.com/bnema/wlturbo/protocol/idleinhibit" | |
| 17 | + | "github.com/bnema/wlturbo/protocol/idlenotify" | |
| 18 | + | "github.com/bnema/wlturbo/protocol/imagecapturesource" | |
| 19 | + | "github.com/bnema/wlturbo/protocol/imagecopycapture" | |
| 20 | + | "github.com/bnema/wlturbo/protocol/pointerconstraints" | |
| 21 | + | "github.com/bnema/wlturbo/protocol/primaryselection" | |
| 22 | + | "github.com/bnema/wlturbo/protocol/relativepointer" | |
| 23 | + | "github.com/bnema/wlturbo/protocol/shortcutsinhibit" | |
| 24 | + | "github.com/bnema/wlturbo/protocol/workspace" | |
| 25 | + | "github.com/bnema/wlturbo/protocol/xdgdecoration" | |
| 26 | + | "github.com/bnema/wlturbo/protocol/xdgoutput" | |
| 27 | + | "github.com/bnema/wlturbo/protocol/xdgshell" | |
| 28 | + | "golang.org/x/sys/unix" | |
| 29 | + | ) | |
| 30 | + | ||
| 31 | + | func TestRelativePointerMotionDecode(t *testing.T) { | |
| 32 | + | s := newWireEnv(t) | |
| 33 | + | ptr := s.pointer() | |
| 34 | + | mgr := relativepointer.NewRelativePointerManager(s.d.Context()) | |
| 35 | + | s.bind(1, relativepointer.RelativePointerManagerInterface, 1, 1, mgr) | |
| 36 | + | rp, e := mgr.GetRelativePointer(ptr) | |
| 37 | + | noerr(t, e) | |
| 38 | + | wantWords(t, "get_relative_pointer", s.req(mgr.ID(), 1), rp.ID(), ptr.ID()) | |
| 39 | + | ||
| 40 | + | type motion struct { | |
| 41 | + | hi, lo uint32 | |
| 42 | + | dx, dy, ux, uy wlturbo.Fixed | |
| 43 | + | } | |
| 44 | + | var got []motion | |
| 45 | + | rp.OnRelativeMotion(func(hi, lo uint32, dx, dy, ux, uy wlturbo.Fixed) { | |
| 46 | + | got = append(got, motion{hi, lo, dx, dy, ux, uy}) | |
| 47 | + | }) | |
| 48 | + | // 64-bit microsecond timestamp split in two words; negative deltas must | |
| 49 | + | // keep their sign through the 24.8 fixed-point decode. | |
| 50 | + | want := motion{1, 0x89abcdef, wlturbo.NewFixed(-1.5), wlturbo.NewFixed(2.25), wlturbo.NewFixed(-3), wlturbo.NewFixed(0.5)} | |
| 51 | + | s.event(rp.ID(), 0, wordBytes(want.hi, want.lo, uint32(want.dx), uint32(want.dy), uint32(want.ux), uint32(want.uy))...) | |
| 52 | + | if len(got) != 1 || got[0] != want { | |
| 53 | + | t.Fatalf("motion %+v, want %+v", got, want) | |
| 54 | + | } | |
| 55 | + | if got[0].dx.Float64() != -1.5 || got[0].dy.Float64() != 2.25 { | |
| 56 | + | t.Fatalf("fixed decode %v %v", got[0].dx.Float64(), got[0].dy.Float64()) | |
| 57 | + | } | |
| 58 | + | // Two handlers are both called, in registration order. | |
| 59 | + | var order []int | |
| 60 | + | rp.OnRelativeMotion(func(_, _ uint32, _, _, _, _ wlturbo.Fixed) { order = append(order, 1) }) | |
| 61 | + | rp.OnRelativeMotion(func(_, _ uint32, _, _, _, _ wlturbo.Fixed) { order = append(order, 2) }) | |
| 62 | + | s.event(rp.ID(), 0, wordBytes(0, 1, 0, 0, 0, 0)...) | |
| 63 | + | if !reflect.DeepEqual(order, []int{1, 2}) || len(got) != 2 { | |
| 64 | + | t.Fatalf("handlers order=%v motions=%d", order, len(got)) | |
| 65 | + | } | |
| 66 | + | noerr(t, rp.Destroy()) | |
| 67 | + | s.req(rp.ID(), 0) | |
| 68 | + | noerr(t, mgr.Destroy()) | |
| 69 | + | s.req(mgr.ID(), 0) | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | func TestPointerConstraintsNullableRegion(t *testing.T) { | |
| 73 | + | s := newWireEnv(t) | |
| 74 | + | surf, ptr := s.surface(), s.pointer() | |
| 75 | + | pc := pointerconstraints.NewPointerConstraints(s.d.Context()) | |
| 76 | + | s.bind(1, pointerconstraints.PointerConstraintsInterface, 1, 1, pc) | |
| 77 | + | ||
| 78 | + | // A null region means "use the surface input region" and is wire id 0. | |
| 79 | + | lock, e := pc.LockPointer(surf, ptr, nil, pointerconstraints.LIFETIME_PERSISTENT) | |
| 80 | + | noerr(t, e) | |
| 81 | + | wantWords(t, "lock_pointer(nil)", s.req(pc.ID(), 1), lock.ID(), surf.ID(), ptr.ID(), 0, pointerconstraints.LIFETIME_PERSISTENT) | |
| 82 | + | ||
| 83 | + | reg := s.region() | |
| 84 | + | conf, e := pc.ConfinePointer(surf, ptr, reg, pointerconstraints.LIFETIME_ONESHOT) | |
| 85 | + | noerr(t, e) | |
| 86 | + | wantWords(t, "confine_pointer(region)", s.req(pc.ID(), 2), conf.ID(), surf.ID(), ptr.ID(), reg.ID(), pointerconstraints.LIFETIME_ONESHOT) | |
| 87 | + | ||
| 88 | + | noerr(t, lock.SetCursorPositionHint(wlturbo.NewFixed(10.5), wlturbo.NewFixed(-2))) | |
| 89 | + | wantWords(t, "set_cursor_position_hint", s.req(lock.ID(), 1), uint32(wlturbo.NewFixed(10.5)), uint32(wlturbo.NewFixed(-2))) | |
| 90 | + | noerr(t, lock.SetRegion(nil)) | |
| 91 | + | wantWords(t, "locked.set_region(nil)", s.req(lock.ID(), 2), 0) | |
| 92 | + | noerr(t, lock.SetRegion(reg)) | |
| 93 | + | wantWords(t, "locked.set_region", s.req(lock.ID(), 2), reg.ID()) | |
| 94 | + | noerr(t, conf.SetRegion(nil)) | |
| 95 | + | wantWords(t, "confined.set_region(nil)", s.req(conf.ID(), 1), 0) | |
| 96 | + | ||
| 97 | + | var seq []string | |
| 98 | + | lock.OnLocked(func() { seq = append(seq, "locked") }) | |
| 99 | + | lock.OnUnlocked(func() { seq = append(seq, "unlocked") }) | |
| 100 | + | conf.OnConfined(func() { seq = append(seq, "confined") }) | |
| 101 | + | conf.OnUnconfined(func() { seq = append(seq, "unconfined") }) | |
| 102 | + | s.event(lock.ID(), 0) | |
| 103 | + | s.event(lock.ID(), 1) | |
| 104 | + | s.event(conf.ID(), 0) | |
| 105 | + | s.event(conf.ID(), 1) | |
| 106 | + | if !reflect.DeepEqual(seq, []string{"locked", "unlocked", "confined", "unconfined"}) { | |
| 107 | + | t.Fatal(seq) | |
| 108 | + | } | |
| 109 | + | noerr(t, lock.Destroy()) | |
| 110 | + | s.req(lock.ID(), 0) | |
| 111 | + | noerr(t, conf.Destroy()) | |
| 112 | + | s.req(conf.ID(), 0) | |
| 113 | + | noerr(t, pc.Destroy()) | |
| 114 | + | s.req(pc.ID(), 0) | |
| 115 | + | } | |
| 116 | + | ||
| 117 | + | // rawPipe returns a pipe as plain descriptors. An *os.File would close a reused | |
| 118 | + | // descriptor number on Close after the binding already closed the original. | |
| 119 | + | func rawPipe(t *testing.T) (*os.File, int) { | |
| 120 | + | t.Helper() | |
| 121 | + | var fds [2]int | |
| 122 | + | noerr(t, unix.Pipe2(fds[:], unix.O_CLOEXEC)) | |
| 123 | + | r := os.NewFile(uintptr(fds[0]), "pipe-r") | |
| 124 | + | t.Cleanup(func() { r.Close() }) | |
| 125 | + | return r, fds[1] | |
| 126 | + | } | |
| 127 | + | ||
| 128 | + | func TestPrimarySelectionNewIDAndFDOwnership(t *testing.T) { | |
| 129 | + | s := newWireEnv(t) | |
| 130 | + | seat := s.seat() | |
| 131 | + | mgr := primaryselection.NewPrimarySelectionDeviceManager(s.d.Context()) | |
| 132 | + | s.bind(1, primaryselection.PrimarySelectionDeviceManagerInterface, 1, 1, mgr) | |
| 133 | + | dev, e := mgr.GetDevice(seat) | |
| 134 | + | noerr(t, e) | |
| 135 | + | wantWords(t, "get_device", s.req(mgr.ID(), 1), dev.ID(), seat.ID()) | |
| 136 | + | src, e := mgr.CreateSource() | |
| 137 | + | noerr(t, e) | |
| 138 | + | wantWords(t, "create_source", s.req(mgr.ID(), 0), src.ID()) | |
| 139 | + | noerr(t, src.Offer("text/plain")) | |
| 140 | + | s.req(src.ID(), 0) | |
| 141 | + | noerr(t, dev.SetSelection(src, 77)) | |
| 142 | + | wantWords(t, "set_selection", s.req(dev.ID(), 0), src.ID(), 77) | |
| 143 | + | noerr(t, dev.SetSelection(nil, 78)) | |
| 144 | + | wantWords(t, "set_selection(nil)", s.req(dev.ID(), 0), 0, 78) | |
| 145 | + | ||
| 146 | + | // data_offer carries a server-allocated new_id which must come back as a | |
| 147 | + | // typed, registered child inheriting the device version. | |
| 148 | + | var offer *primaryselection.PrimarySelectionOffer | |
| 149 | + | var mimes []string | |
| 150 | + | dev.OnDataOffer(func(o *primaryselection.PrimarySelectionOffer) { | |
| 151 | + | offer = o | |
| 152 | + | o.OnOffer(func(m string) { mimes = append(mimes, m) }) | |
| 153 | + | }) | |
| 154 | + | var selected []uint32 | |
| 155 | + | dev.OnSelection(func(id uint32) { selected = append(selected, id) }) | |
| 156 | + | s.event(dev.ID(), 0, wordBytes(serverID+1)...) | |
| 157 | + | if offer == nil || offer.ID() != serverID+1 || offer.Version() != dev.Version() { | |
| 158 | + | t.Fatalf("offer %+v", offer) | |
| 159 | + | } | |
| 160 | + | s.event(offer.ID(), 0, str("text/plain")...) | |
| 161 | + | s.event(dev.ID(), 1, wordBytes(offer.ID())...) | |
| 162 | + | s.event(dev.ID(), 1, wordBytes(0)...) // null selection | |
| 163 | + | if !reflect.DeepEqual(mimes, []string{"text/plain"}) || !reflect.DeepEqual(selected, []uint32{offer.ID(), 0}) { | |
| 164 | + | t.Fatalf("mimes=%v selected=%v", mimes, selected) | |
| 165 | + | } | |
| 166 | + | ||
| 167 | + | // Client -> compositor: the sent descriptor is duplicated by the kernel and | |
| 168 | + | // the client's copy is closed by the binding. | |
| 169 | + | r, w := rawPipe(t) | |
| 170 | + | noerr(t, offer.Receive("text/plain", w)) | |
| 171 | + | // Check before reading the request: the received duplicate may reuse the | |
| 172 | + | // number of the descriptor the client just closed. | |
| 173 | + | requireFDClosed(t, w) | |
| 174 | + | body, fd := s.reqFD(offer.ID(), 0) | |
| 175 | + | // Closed explicitly below; the guard covers early t.Fatal paths only. | |
| 176 | + | defer func() { | |
| 177 | + | if fd >= 0 { | |
| 178 | + | unix.Close(fd) | |
| 179 | + | } | |
| 180 | + | }() | |
| 181 | + | if len(body) < 4 { | |
| 182 | + | t.Fatalf("receive body %x", body) | |
| 183 | + | } | |
| 184 | + | _, e = unix.Write(fd, []byte("payload")) | |
| 185 | + | noerr(t, e) | |
| 186 | + | noerr(t, unix.Close(fd)) | |
| 187 | + | fd = -1 | |
| 188 | + | buf := make([]byte, 16) | |
| 189 | + | n, e := r.Read(buf) | |
| 190 | + | noerr(t, e) | |
| 191 | + | if string(buf[:n]) != "payload" { | |
| 192 | + | t.Fatalf("payload %q", buf[:n]) | |
| 193 | + | } | |
| 194 | + | ||
| 195 | + | // Compositor -> client: source.send hands over an owned descriptor. | |
| 196 | + | var taken, ignored *wlturbo.OwnedFD | |
| 197 | + | var sendMimes []string | |
| 198 | + | src.OnSend(func(m string, f *wlturbo.OwnedFD) { | |
| 199 | + | sendMimes = append(sendMimes, m) | |
| 200 | + | if taken == nil { | |
| 201 | + | taken = f | |
| 202 | + | n, e := f.Take() | |
| 203 | + | noerr(t, e) | |
| 204 | + | _, e = unix.Write(n, []byte("from-client")) | |
| 205 | + | noerr(t, e) | |
| 206 | + | unix.Close(n) | |
| 207 | + | return | |
| 208 | + | } | |
| 209 | + | ignored = f // deliberately neither taken nor closed | |
| 210 | + | }) | |
| 211 | + | sr, sw, e := os.Pipe() | |
| 212 | + | noerr(t, e) | |
| 213 | + | send(t, s.p, payload(src.ID(), 0, str("text/plain")...), int(sw.Fd())) | |
| 214 | + | s.dispatch() | |
| 215 | + | sw.Close() | |
| 216 | + | n, e = sr.Read(buf) | |
| 217 | + | noerr(t, e) | |
| 218 | + | if string(buf[:n]) != "from-client" { | |
| 219 | + | t.Fatalf("source payload %q", buf[:n]) | |
| 220 | + | } | |
| 221 | + | if _, e := taken.Take(); e == nil { | |
| 222 | + | t.Fatal("second Take on a taken descriptor must fail") | |
| 223 | + | } | |
| 224 | + | sr.Close() | |
| 225 | + | // An unclaimed descriptor is closed by the transport when dispatch ends, | |
| 226 | + | // so the pipe reader sees EOF although the handler never closed it. | |
| 227 | + | pr, pw, e := os.Pipe() | |
| 228 | + | noerr(t, e) | |
| 229 | + | defer pr.Close() | |
| 230 | + | send(t, s.p, payload(src.ID(), 0, str("text/html")...), int(pw.Fd())) | |
| 231 | + | pw.Close() // only the in-flight duplicate keeps the write end alive | |
| 232 | + | s.dispatch() | |
| 233 | + | if ignored == nil || len(sendMimes) != 2 { | |
| 234 | + | t.Fatalf("send events %v", sendMimes) | |
| 235 | + | } | |
| 236 | + | if _, e := ignored.Take(); e == nil { | |
| 237 | + | t.Fatal("unclaimed descriptor must be closed after dispatch, but Take succeeded") | |
| 238 | + | } | |
| 239 | + | pr.SetReadDeadline(time.Now().Add(2 * time.Second)) | |
| 240 | + | if n, e := pr.Read(buf); n != 0 || e == nil { | |
| 241 | + | t.Fatalf("unclaimed descriptor still open: n=%d err=%v", n, e) | |
| 242 | + | } | |
| 243 | + | var cancelled bool | |
| 244 | + | src.OnCancelled(func() { cancelled = true }) | |
| 245 | + | s.event(src.ID(), 1) | |
| 246 | + | if !cancelled { | |
| 247 | + | t.Fatal("cancelled not delivered") | |
| 248 | + | } | |
| 249 | + | noerr(t, offer.Destroy()) | |
| 250 | + | s.req(offer.ID(), 1) | |
| 251 | + | noerr(t, src.Destroy()) | |
| 252 | + | s.req(src.ID(), 1) | |
| 253 | + | noerr(t, dev.Destroy()) | |
| 254 | + | s.req(dev.ID(), 1) | |
| 255 | + | noerr(t, mgr.Destroy()) | |
| 256 | + | s.req(mgr.ID(), 2) | |
| 257 | + | } | |
| 258 | + | ||
| 259 | + | func TestDataControlNewIDAndFDOwnership(t *testing.T) { | |
| 260 | + | s := newWireEnv(t) | |
| 261 | + | seat := s.seat() | |
| 262 | + | mgr := datacontrol.NewExtDataControlManager(s.d.Context()) | |
| 263 | + | s.bind(1, datacontrol.ExtDataControlManagerInterface, 1, 1, mgr) | |
| 264 | + | dev, e := mgr.GetDataDevice(seat) | |
| 265 | + | noerr(t, e) | |
| 266 | + | wantWords(t, "get_data_device", s.req(mgr.ID(), 1), dev.ID(), seat.ID()) | |
| 267 | + | src, e := mgr.CreateDataSource() | |
| 268 | + | noerr(t, e) | |
| 269 | + | wantWords(t, "create_data_source", s.req(mgr.ID(), 0), src.ID()) | |
| 270 | + | noerr(t, dev.SetSelection(src)) | |
| 271 | + | wantWords(t, "set_selection", s.req(dev.ID(), 0), src.ID()) | |
| 272 | + | noerr(t, dev.SetPrimarySelection(nil)) | |
| 273 | + | wantWords(t, "set_primary_selection(nil)", s.req(dev.ID(), 2), 0) | |
| 274 | + | ||
| 275 | + | var offers []*datacontrol.ExtDataControlOffer | |
| 276 | + | dev.OnDataOffer(func(o *datacontrol.ExtDataControlOffer) { offers = append(offers, o) }) | |
| 277 | + | var sel, primary []uint32 | |
| 278 | + | dev.OnSelection(func(id uint32) { sel = append(sel, id) }) | |
| 279 | + | dev.OnPrimarySelection(func(id uint32) { primary = append(primary, id) }) | |
| 280 | + | var finished bool | |
| 281 | + | dev.OnFinished(func() { finished = true }) | |
| 282 | + | s.event(dev.ID(), 0, wordBytes(serverID+1)...) | |
| 283 | + | s.event(dev.ID(), 0, wordBytes(serverID+2)...) | |
| 284 | + | if len(offers) != 2 || offers[0].ID() != serverID+1 || offers[1].ID() != serverID+2 { | |
| 285 | + | t.Fatalf("offers %+v", offers) | |
| 286 | + | } | |
| 287 | + | s.event(dev.ID(), 1, wordBytes(serverID+1)...) | |
| 288 | + | s.event(dev.ID(), 3, wordBytes(serverID+2)...) | |
| 289 | + | s.event(dev.ID(), 3, wordBytes(0)...) | |
| 290 | + | if !reflect.DeepEqual(sel, []uint32{serverID + 1}) || !reflect.DeepEqual(primary, []uint32{serverID + 2, 0}) { | |
| 291 | + | t.Fatalf("sel=%v primary=%v", sel, primary) | |
| 292 | + | } | |
| 293 | + | var mime string | |
| 294 | + | offers[0].OnOffer(func(m string) { mime = m }) | |
| 295 | + | s.event(offers[0].ID(), 0, str("text/uri-list")...) | |
| 296 | + | if mime != "text/uri-list" { | |
| 297 | + | t.Fatal(mime) | |
| 298 | + | } | |
| 299 | + | ||
| 300 | + | r, w := rawPipe(t) | |
| 301 | + | noerr(t, offers[0].Receive("text/uri-list", w)) | |
| 302 | + | requireFDClosed(t, w) | |
| 303 | + | _, fd := s.reqFD(offers[0].ID(), 0) | |
| 304 | + | unix.Close(fd) | |
| 305 | + | buf := make([]byte, 8) | |
| 306 | + | if n, e := r.Read(buf); n != 0 || e == nil { | |
| 307 | + | t.Fatalf("expected EOF once both write ends closed, n=%d err=%v", n, e) | |
| 308 | + | } | |
| 309 | + | ||
| 310 | + | // source.send: the handler owns the descriptor and can Close it early. | |
| 311 | + | var closedByHandler bool | |
| 312 | + | src.OnSend(func(m string, f *wlturbo.OwnedFD) { | |
| 313 | + | noerr(t, f.Close()) | |
| 314 | + | noerr(t, f.Close()) // idempotent | |
| 315 | + | if _, e := f.Take(); e == nil { | |
| 316 | + | t.Error("Take after Close must fail") | |
| 317 | + | } | |
| 318 | + | closedByHandler = true | |
| 319 | + | }) | |
| 320 | + | pr, pw, e := os.Pipe() | |
| 321 | + | noerr(t, e) | |
| 322 | + | defer pr.Close() | |
| 323 | + | send(t, s.p, payload(src.ID(), 0, str("text/plain")...), int(pw.Fd())) | |
| 324 | + | pw.Close() | |
| 325 | + | s.dispatch() | |
| 326 | + | pr.SetReadDeadline(time.Now().Add(2 * time.Second)) | |
| 327 | + | if n, e := pr.Read(buf); !closedByHandler || n != 0 || e == nil { | |
| 328 | + | t.Fatalf("closed=%v n=%d err=%v", closedByHandler, n, e) | |
| 329 | + | } | |
| 330 | + | s.event(dev.ID(), 2) | |
| 331 | + | if !finished { | |
| 332 | + | t.Fatal("finished not delivered") | |
| 333 | + | } | |
| 334 | + | noerr(t, src.Offer("text/plain")) | |
| 335 | + | s.req(src.ID(), 0) | |
| 336 | + | noerr(t, offers[0].Destroy()) | |
| 337 | + | s.req(offers[0].ID(), 1) | |
| 338 | + | noerr(t, src.Destroy()) | |
| 339 | + | s.req(src.ID(), 1) | |
| 340 | + | noerr(t, dev.Destroy()) | |
| 341 | + | s.req(dev.ID(), 1) | |
| 342 | + | noerr(t, mgr.Destroy()) | |
| 343 | + | s.req(mgr.ID(), 2) | |
| 344 | + | } | |
| 345 | + | ||
| 346 | + | func TestWorkspaceLifecycle(t *testing.T) { | |
| 347 | + | s := newWireEnv(t) | |
| 348 | + | out := s.output() | |
| 349 | + | mgr := workspace.NewExtWorkspaceManager(s.d.Context()) | |
| 350 | + | s.bind(1, workspace.ExtWorkspaceManagerInterface, 1, 1, mgr) | |
| 351 | + | ||
| 352 | + | var groups []*workspace.ExtWorkspaceGroupHandle | |
| 353 | + | var spaces []*workspace.ExtWorkspaceHandle | |
| 354 | + | var log []string | |
| 355 | + | mgr.OnWorkspaceGroup(func(g *workspace.ExtWorkspaceGroupHandle) { groups = append(groups, g) }) | |
| 356 | + | mgr.OnWorkspace(func(w *workspace.ExtWorkspaceHandle) { spaces = append(spaces, w) }) | |
| 357 | + | mgr.OnDone(func() { log = append(log, "done") }) | |
| 358 | + | mgr.OnFinished(func() { log = append(log, "finished") }) | |
| 359 | + | ||
| 360 | + | s.event(mgr.ID(), 0, wordBytes(serverID+1)...) | |
| 361 | + | s.event(mgr.ID(), 1, wordBytes(serverID+2)...) | |
| 362 | + | if len(groups) != 1 || len(spaces) != 1 || groups[0].ID() != serverID+1 || spaces[0].ID() != serverID+2 { | |
| 363 | + | t.Fatal("typed children missing") | |
| 364 | + | } | |
| 365 | + | g, w := groups[0], spaces[0] | |
| 366 | + | var gcaps, wcaps, state uint32 | |
| 367 | + | var outs, entered []uint32 | |
| 368 | + | var id, name string | |
| 369 | + | var coords []byte | |
| 370 | + | g.OnCapabilities(func(c uint32) { gcaps = c }) | |
| 371 | + | g.OnOutputEnter(func(o uint32) { outs = append(outs, o) }) | |
| 372 | + | g.OnWorkspaceEnter(func(x uint32) { entered = append(entered, x) }) | |
| 373 | + | g.OnRemoved(func() { log = append(log, "group-removed") }) | |
| 374 | + | w.OnId(func(v string) { id = v }) | |
| 375 | + | w.OnName(func(v string) { name = v }) | |
| 376 | + | w.OnCoordinates(func(c []byte) { coords = c }) | |
| 377 | + | w.OnState(func(v uint32) { state = v }) | |
| 378 | + | w.OnCapabilities(func(v uint32) { wcaps = v }) | |
| 379 | + | w.OnRemoved(func() { log = append(log, "workspace-removed") }) | |
| 380 | + | ||
| 381 | + | s.event(g.ID(), 0, wordBytes(workspace.GROUP_CAPABILITIES_CREATE_WORKSPACE)...) | |
| 382 | + | s.event(g.ID(), 1, wordBytes(out.ID())...) | |
| 383 | + | s.event(g.ID(), 3, wordBytes(w.ID())...) | |
| 384 | + | s.event(w.ID(), 0, str("ws-1")...) | |
| 385 | + | s.event(w.ID(), 1, str("Workspace é")...) | |
| 386 | + | s.event(w.ID(), 2, arr(wordBytes(1, 2))...) | |
| 387 | + | s.event(w.ID(), 3, wordBytes(workspace.STATE_ACTIVE|workspace.STATE_URGENT)...) | |
| 388 | + | s.event(w.ID(), 4, wordBytes(workspace.WORKSPACE_CAPABILITIES_ACTIVATE|workspace.WORKSPACE_CAPABILITIES_ASSIGN)...) | |
| 389 | + | s.event(mgr.ID(), 2) | |
| 390 | + | if gcaps != workspace.GROUP_CAPABILITIES_CREATE_WORKSPACE || !reflect.DeepEqual(outs, []uint32{out.ID()}) || !reflect.DeepEqual(entered, []uint32{w.ID()}) || | |
| 391 | + | id != "ws-1" || name != "Workspace é" || !reflect.DeepEqual(decodeWords(coords), []uint32{1, 2}) || | |
| 392 | + | state != 3 || wcaps != 9 || !reflect.DeepEqual(log, []string{"done"}) { | |
| 393 | + | t.Fatalf("state gcaps=%d outs=%v entered=%v id=%q name=%q coords=%v state=%d wcaps=%d log=%v", gcaps, outs, entered, id, name, coords, state, wcaps, log) | |
| 394 | + | } | |
| 395 | + | ||
| 396 | + | // Requests are only transactional after commit, so the wire order is | |
| 397 | + | // request, request, commit. | |
| 398 | + | noerr(t, w.Activate()) | |
| 399 | + | s.req(w.ID(), 1) | |
| 400 | + | noerr(t, w.Assign(g)) | |
| 401 | + | wantWords(t, "assign", s.req(w.ID(), 3), g.ID()) | |
| 402 | + | noerr(t, g.CreateWorkspace("new")) | |
| 403 | + | if b := s.req(g.ID(), 0); binary.NativeEndian.Uint32(b) != 4 || string(b[4:7]) != "new" { | |
| 404 | + | t.Fatalf("create_workspace %x", b) | |
| 405 | + | } | |
| 406 | + | noerr(t, w.Deactivate()) | |
| 407 | + | s.req(w.ID(), 2) | |
| 408 | + | noerr(t, w.Remove()) | |
| 409 | + | s.req(w.ID(), 4) | |
| 410 | + | noerr(t, mgr.Commit()) | |
| 411 | + | s.req(mgr.ID(), 0) | |
| 412 | + | ||
| 413 | + | // Removal: the compositor sends removed, the client answers with destroy. | |
| 414 | + | s.event(w.ID(), 5) | |
| 415 | + | s.event(g.ID(), 5) | |
| 416 | + | noerr(t, w.Destroy()) | |
| 417 | + | s.req(w.ID(), 0) | |
| 418 | + | noerr(t, g.Destroy()) | |
| 419 | + | s.req(g.ID(), 1) | |
| 420 | + | // stop is answered by finished, which is the final event. | |
| 421 | + | noerr(t, mgr.Stop()) | |
| 422 | + | s.req(mgr.ID(), 1) | |
| 423 | + | s.event(mgr.ID(), 3) | |
| 424 | + | if !reflect.DeepEqual(log, []string{"done", "workspace-removed", "group-removed", "finished"}) { | |
| 425 | + | t.Fatal(log) | |
| 426 | + | } | |
| 427 | + | // finished is a destructor event: the manager is dead and must not | |
| 428 | + | // reach the compositor any more. | |
| 429 | + | if e := mgr.Commit(); e == nil { | |
| 430 | + | t.Fatal("Commit after finished must fail") | |
| 431 | + | } | |
| 432 | + | s.noRequest() | |
| 433 | + | } | |
| 434 | + | ||
| 435 | + | func TestIdleNotifyVersionGate(t *testing.T) { | |
| 436 | + | s := newWireEnv(t) | |
| 437 | + | seat := s.seat() | |
| 438 | + | old := idlenotify.NewExtIdleNotifier(s.d.Context()) | |
| 439 | + | s.bind(1, idlenotify.ExtIdleNotifierInterface, 2, 1, old) // negotiated v1 | |
| 440 | + | if _, e := old.GetInputIdleNotification(1000, seat); !errors.Is(e, wlturbo.ErrVersionTooLow) { | |
| 441 | + | t.Fatalf("v1 get_input_idle_notification = %v, want ErrVersionTooLow", e) | |
| 442 | + | } | |
| 443 | + | s.noRequest() // refused locally, nothing reaches the compositor | |
| 444 | + | n, e := old.GetIdleNotification(1000, seat) | |
| 445 | + | noerr(t, e) | |
| 446 | + | wantWords(t, "get_idle_notification", s.req(old.ID(), 1), n.ID(), 1000, seat.ID()) | |
| 447 | + | ||
| 448 | + | send(t, s.p, msg(s.d.Registry().ID(), 1, 1)) // global_remove for the v1 bind | |
| 449 | + | s.dispatch() | |
| 450 | + | cur := idlenotify.NewExtIdleNotifier(s.d.Context()) | |
| 451 | + | s.bind(2, idlenotify.ExtIdleNotifierInterface, 2, 2, cur) | |
| 452 | + | in, e := cur.GetInputIdleNotification(0, seat) // zero timeout is valid | |
| 453 | + | noerr(t, e) | |
| 454 | + | wantWords(t, "get_input_idle_notification", s.req(cur.ID(), 2), in.ID(), 0, seat.ID()) | |
| 455 | + | var seq []string | |
| 456 | + | in.OnIdled(func() { seq = append(seq, "idled") }) | |
| 457 | + | in.OnResumed(func() { seq = append(seq, "resumed") }) | |
| 458 | + | s.event(in.ID(), 0) | |
| 459 | + | s.event(in.ID(), 1) | |
| 460 | + | if !reflect.DeepEqual(seq, []string{"idled", "resumed"}) { | |
| 461 | + | t.Fatal(seq) | |
| 462 | + | } | |
| 463 | + | noerr(t, in.Destroy()) | |
| 464 | + | s.req(in.ID(), 0) | |
| 465 | + | noerr(t, n.Destroy()) | |
| 466 | + | s.req(n.ID(), 0) | |
| 467 | + | } | |
| 468 | + | ||
| 469 | + | func TestInhibitAndDesktopHintsWire(t *testing.T) { | |
| 470 | + | s := newWireEnv(t) | |
| 471 | + | surf, seat, out := s.surface(), s.seat(), s.output() | |
| 472 | + | ||
| 473 | + | ii := idleinhibit.NewIdleInhibitManager(s.d.Context()) | |
| 474 | + | s.bind(1, idleinhibit.IdleInhibitManagerInterface, 1, 1, ii) | |
| 475 | + | inh, e := ii.CreateInhibitor(surf) | |
| 476 | + | noerr(t, e) | |
| 477 | + | wantWords(t, "create_inhibitor", s.req(ii.ID(), 1), inh.ID(), surf.ID()) | |
| 478 | + | noerr(t, inh.Destroy()) | |
| 479 | + | s.req(inh.ID(), 0) | |
| 480 | + | noerr(t, ii.Destroy()) | |
| 481 | + | s.req(ii.ID(), 0) | |
| 482 | + | ||
| 483 | + | ks := shortcutsinhibit.NewKeyboardShortcutsInhibitManager(s.d.Context()) | |
| 484 | + | s.bind(2, shortcutsinhibit.KeyboardShortcutsInhibitManagerInterface, 1, 1, ks) | |
| 485 | + | k, e := ks.InhibitShortcuts(surf, seat) | |
| 486 | + | noerr(t, e) | |
| 487 | + | wantWords(t, "inhibit_shortcuts", s.req(ks.ID(), 1), k.ID(), surf.ID(), seat.ID()) | |
| 488 | + | var seq []string | |
| 489 | + | k.OnActive(func() { seq = append(seq, "active") }) | |
| 490 | + | k.OnInactive(func() { seq = append(seq, "inactive") }) | |
| 491 | + | s.event(k.ID(), 0) | |
| 492 | + | s.event(k.ID(), 1) | |
| 493 | + | if !reflect.DeepEqual(seq, []string{"active", "inactive"}) { | |
| 494 | + | t.Fatal(seq) | |
| 495 | + | } | |
| 496 | + | noerr(t, k.Destroy()) | |
| 497 | + | s.req(k.ID(), 0) | |
| 498 | + | noerr(t, ks.Destroy()) | |
| 499 | + | s.req(ks.ID(), 0) | |
| 500 | + | ||
| 501 | + | xo := xdgoutput.NewZxdgOutputManager(s.d.Context()) | |
| 502 | + | s.bind(3, xdgoutput.ZxdgOutputManagerInterface, 3, 3, xo) | |
| 503 | + | o, e := xo.GetXdgOutput(out) | |
| 504 | + | noerr(t, e) | |
| 505 | + | wantWords(t, "get_xdg_output", s.req(xo.ID(), 1), o.ID(), out.ID()) | |
| 506 | + | var pos, size [2]int32 | |
| 507 | + | var name string | |
| 508 | + | o.OnLogicalPosition(func(x, y int32) { pos = [2]int32{x, y} }) | |
| 509 | + | o.OnLogicalSize(func(w, h int32) { size = [2]int32{w, h} }) | |
| 510 | + | o.OnName(func(n string) { name = n }) | |
| 511 | + | s.event(o.ID(), 0, wordBytes(uint32(0xfffffff6), 20)...) // -10, 20 | |
| 512 | + | s.event(o.ID(), 1, wordBytes(1920, 1080)...) | |
| 513 | + | s.event(o.ID(), 3, str("DP-1")...) | |
| 514 | + | if pos != [2]int32{-10, 20} || size != [2]int32{1920, 1080} || name != "DP-1" { | |
| 515 | + | t.Fatal(pos, size, name) | |
| 516 | + | } | |
| 517 | + | noerr(t, o.Destroy()) | |
| 518 | + | s.req(o.ID(), 0) | |
| 519 | + | noerr(t, xo.Destroy()) | |
| 520 | + | s.req(xo.ID(), 0) | |
| 521 | + | } | |
| 522 | + | ||
| 523 | + | func TestXdgDecorationCrossPackageToplevel(t *testing.T) { | |
| 524 | + | s := newWireEnv(t) | |
| 525 | + | surf := s.surface() | |
| 526 | + | wm := xdgshell.NewXdgWmBase(s.d.Context()) | |
| 527 | + | s.bind(1, xdgshell.XdgWmBaseInterface, 6, 6, wm) | |
| 528 | + | xs, e := wm.GetXdgSurface(surf) | |
| 529 | + | noerr(t, e) | |
| 530 | + | s.req(wm.ID(), 2) | |
| 531 | + | top, e := xs.GetToplevel() | |
| 532 | + | noerr(t, e) | |
| 533 | + | s.req(xs.ID(), 1) | |
| 534 | + | ||
| 535 | + | dm := xdgdecoration.NewZxdgDecorationManager(s.d.Context()) | |
| 536 | + | s.bind(2, xdgdecoration.ZxdgDecorationManagerInterface, 2, 2, dm) | |
| 537 | + | dec, e := dm.GetToplevelDecoration(top) | |
| 538 | + | noerr(t, e) | |
| 539 | + | wantWords(t, "get_toplevel_decoration", s.req(dm.ID(), 1), dec.ID(), top.ID()) | |
| 540 | + | noerr(t, dec.SetMode(xdgdecoration.MODE_SERVER_SIDE)) | |
| 541 | + | wantWords(t, "set_mode", s.req(dec.ID(), 1), xdgdecoration.MODE_SERVER_SIDE) | |
| 542 | + | var modes []uint32 | |
| 543 | + | dec.OnConfigure(func(m uint32) { modes = append(modes, m) }) | |
| 544 | + | s.event(dec.ID(), 0, wordBytes(xdgdecoration.MODE_CLIENT_SIDE)...) | |
| 545 | + | if !reflect.DeepEqual(modes, []uint32{xdgdecoration.MODE_CLIENT_SIDE}) { | |
| 546 | + | t.Fatal(modes) | |
| 547 | + | } | |
| 548 | + | noerr(t, dec.UnsetMode()) | |
| 549 | + | s.req(dec.ID(), 2) | |
| 550 | + | noerr(t, dec.Destroy()) | |
| 551 | + | s.req(dec.ID(), 0) | |
| 552 | + | noerr(t, dm.Destroy()) | |
| 553 | + | s.req(dm.ID(), 0) | |
| 554 | + | } | |
| 555 | + | ||
| 556 | + | func TestImageCaptureCrossPackageChildren(t *testing.T) { | |
| 557 | + | s := newWireEnv(t) | |
| 558 | + | out, ptr := s.output(), s.pointer() | |
| 559 | + | ||
| 560 | + | // Foreign toplevel handles come from ext-foreign-toplevel-list and are | |
| 561 | + | // consumed by a different package (imagecapturesource). | |
| 562 | + | list := extforeigntoplevel.NewExtForeignToplevelList(s.d.Context()) | |
| 563 | + | s.bind(1, extforeigntoplevel.ExtForeignToplevelListInterface, 1, 1, list) | |
| 564 | + | var handle *extforeigntoplevel.ExtForeignToplevelHandle | |
| 565 | + | list.OnToplevel(func(h *extforeigntoplevel.ExtForeignToplevelHandle) { handle = h }) | |
| 566 | + | s.event(list.ID(), 0, wordBytes(serverID+1)...) | |
| 567 | + | if handle == nil || handle.ID() != serverID+1 { | |
| 568 | + | t.Fatal("toplevel handle missing") | |
| 569 | + | } | |
| 570 | + | var title, appID, ident string | |
| 571 | + | handle.OnTitle(func(v string) { title = v }) | |
| 572 | + | handle.OnAppId(func(v string) { appID = v }) | |
| 573 | + | handle.OnIdentifier(func(v string) { ident = v }) | |
| 574 | + | s.event(handle.ID(), 2, str("term")...) | |
| 575 | + | s.event(handle.ID(), 3, str("org.example.term")...) | |
| 576 | + | s.event(handle.ID(), 4, str("id-1")...) | |
| 577 | + | if title != "term" || appID != "org.example.term" || ident != "id-1" { | |
| 578 | + | t.Fatal(title, appID, ident) | |
| 579 | + | } | |
| 580 | + | ||
| 581 | + | om := imagecapturesource.NewExtOutputImageCaptureSourceManager(s.d.Context()) | |
| 582 | + | s.bind(2, imagecapturesource.ExtOutputImageCaptureSourceManagerInterface, 1, 1, om) | |
| 583 | + | fm := imagecapturesource.NewExtForeignToplevelImageCaptureSourceManager(s.d.Context()) | |
| 584 | + | s.bind(3, imagecapturesource.ExtForeignToplevelImageCaptureSourceManagerInterface, 1, 1, fm) | |
| 585 | + | outSrc, e := om.CreateSource(out) | |
| 586 | + | noerr(t, e) | |
| 587 | + | wantWords(t, "output create_source", s.req(om.ID(), 0), outSrc.ID(), out.ID()) | |
| 588 | + | topSrc, e := fm.CreateSource(handle) | |
| 589 | + | noerr(t, e) | |
| 590 | + | wantWords(t, "toplevel create_source", s.req(fm.ID(), 0), topSrc.ID(), handle.ID()) | |
| 591 | + | ||
| 592 | + | cm := imagecopycapture.NewExtImageCopyCaptureManager(s.d.Context()) | |
| 593 | + | s.bind(4, imagecopycapture.ExtImageCopyCaptureManagerInterface, 1, 1, cm) | |
| 594 | + | sess, e := cm.CreateSession(topSrc, imagecopycapture.OPTIONS_PAINT_CURSORS) | |
| 595 | + | noerr(t, e) | |
| 596 | + | wantWords(t, "create_session", s.req(cm.ID(), 0), sess.ID(), topSrc.ID(), imagecopycapture.OPTIONS_PAINT_CURSORS) | |
| 597 | + | cur, e := cm.CreatePointerCursorSession(outSrc, ptr) | |
| 598 | + | noerr(t, e) | |
| 599 | + | wantWords(t, "create_pointer_cursor_session", s.req(cm.ID(), 1), cur.ID(), outSrc.ID(), ptr.ID()) | |
| 600 | + | ||
| 601 | + | // Session constraints: advertised before done, arrays decoded. | |
| 602 | + | var log []string | |
| 603 | + | var size [2]uint32 | |
| 604 | + | var dev []byte | |
| 605 | + | var dmaFormat uint32 | |
| 606 | + | var mods []byte | |
| 607 | + | sess.OnBufferSize(func(w, h uint32) { size = [2]uint32{w, h}; log = append(log, "size") }) | |
| 608 | + | var shm []uint32 | |
| 609 | + | sess.OnShmFormat(func(f uint32) { shm = append(shm, f); log = append(log, "shm") }) | |
| 610 | + | sess.OnDmabufDevice(func(d []byte) { dev = d; log = append(log, "dev") }) | |
| 611 | + | sess.OnDmabufFormat(func(f uint32, m []byte) { dmaFormat, mods = f, m; log = append(log, "dmabuf") }) | |
| 612 | + | sess.OnDone(func() { log = append(log, "done") }) | |
| 613 | + | sess.OnStopped(func() { log = append(log, "stopped") }) | |
| 614 | + | s.event(sess.ID(), 0, wordBytes(1280, 720)...) | |
| 615 | + | s.event(sess.ID(), 1, wordBytes(1)...) // wl_shm.format xrgb8888 | |
| 616 | + | s.event(sess.ID(), 2, arr(make([]byte, 8))...) | |
| 617 | + | s.event(sess.ID(), 3, cat(wordBytes(0x34325258), arr(wordBytes(0, 0, 1, 0)))...) | |
| 618 | + | s.event(sess.ID(), 4) | |
| 619 | + | if !reflect.DeepEqual(shm, []uint32{1}) { | |
| 620 | + | t.Fatalf("shm formats %v", shm) | |
| 621 | + | } | |
| 622 | + | if size != [2]uint32{1280, 720} || len(dev) != 8 || dmaFormat != 0x34325258 || len(mods) != 16 || | |
| 623 | + | !reflect.DeepEqual(log, []string{"size", "shm", "dev", "dmabuf", "done"}) { | |
| 624 | + | t.Fatal(size, dev, dmaFormat, mods, log) | |
| 625 | + | } | |
| 626 | + | ||
| 627 | + | frame, e := sess.CreateFrame() | |
| 628 | + | noerr(t, e) | |
| 629 | + | wantWords(t, "create_frame", s.req(sess.ID(), 0), frame.ID()) | |
| 630 | + | buf := s.buffer() | |
| 631 | + | noerr(t, frame.AttachBuffer(buf)) | |
| 632 | + | wantWords(t, "attach_buffer", s.req(frame.ID(), 1), buf.ID()) | |
| 633 | + | noerr(t, frame.DamageBuffer(0, 0, 1280, 720)) | |
| 634 | + | wantWords(t, "damage_buffer", s.req(frame.ID(), 2), 0, 0, 1280, 720) | |
| 635 | + | noerr(t, frame.Capture()) | |
| 636 | + | s.req(frame.ID(), 3) | |
| 637 | + | ||
| 638 | + | var fl []string | |
| 639 | + | var damage [4]int32 | |
| 640 | + | var tv [3]uint32 | |
| 641 | + | frame.OnTransform(func(v uint32) { fl = append(fl, "transform") }) | |
| 642 | + | frame.OnDamage(func(x, y, w, h int32) { damage = [4]int32{x, y, w, h}; fl = append(fl, "damage") }) | |
| 643 | + | frame.OnPresentationTime(func(hi, lo, ns uint32) { tv = [3]uint32{hi, lo, ns}; fl = append(fl, "time") }) | |
| 644 | + | frame.OnReady(func() { fl = append(fl, "ready") }) | |
| 645 | + | frame.OnFailed(func(uint32) { fl = append(fl, "failed") }) | |
| 646 | + | s.event(frame.ID(), 0, wordBytes(0)...) | |
| 647 | + | s.event(frame.ID(), 1, wordBytes(1, 2, 3, 4)...) | |
| 648 | + | s.event(frame.ID(), 2, wordBytes(0, 1700000000, 999)...) | |
| 649 | + | s.event(frame.ID(), 3) | |
| 650 | + | if damage != [4]int32{1, 2, 3, 4} || tv != [3]uint32{0, 1700000000, 999} || | |
| 651 | + | !reflect.DeepEqual(fl, []string{"transform", "damage", "time", "ready"}) { | |
| 652 | + | t.Fatal(damage, tv, fl) | |
| 653 | + | } | |
| 654 | + | // ready is terminal for a frame, and a session allows one frame at a time | |
| 655 | + | // even after ready, so destroy it before creating the frame that fails. | |
| 656 | + | noerr(t, frame.Destroy()) | |
| 657 | + | s.req(frame.ID(), 0) | |
| 658 | + | failing, e := sess.CreateFrame() | |
| 659 | + | noerr(t, e) | |
| 660 | + | wantWords(t, "create_frame(2)", s.req(sess.ID(), 0), failing.ID()) | |
| 661 | + | noerr(t, failing.AttachBuffer(buf)) | |
| 662 | + | s.req(failing.ID(), 1) | |
| 663 | + | noerr(t, failing.Capture()) | |
| 664 | + | s.req(failing.ID(), 3) | |
| 665 | + | var reasons []uint32 | |
| 666 | + | failing.OnReady(func() { t.Error("failed frame must not become ready") }) | |
| 667 | + | failing.OnFailed(func(r uint32) { reasons = append(reasons, r) }) | |
| 668 | + | s.event(failing.ID(), 4, wordBytes(imagecopycapture.FAILURE_REASON_BUFFER_CONSTRAINTS)...) | |
| 669 | + | if !reflect.DeepEqual(reasons, []uint32{imagecopycapture.FAILURE_REASON_BUFFER_CONSTRAINTS}) { | |
| 670 | + | t.Fatal(reasons) | |
| 671 | + | } | |
| 672 | + | ||
| 673 | + | // Cursor session: get_capture_session is a typed child too. | |
| 674 | + | var cl []string | |
| 675 | + | var pos, hot [2]int32 | |
| 676 | + | cur.OnEnter(func() { cl = append(cl, "enter") }) | |
| 677 | + | cur.OnLeave(func() { cl = append(cl, "leave") }) | |
| 678 | + | cur.OnPosition(func(x, y int32) { pos = [2]int32{x, y} }) | |
| 679 | + | cur.OnHotspot(func(x, y int32) { hot = [2]int32{x, y} }) | |
| 680 | + | s.event(cur.ID(), 0) | |
| 681 | + | s.event(cur.ID(), 2, wordBytes(uint32(0xfffffffb), 9)...) // -5, 9 | |
| 682 | + | s.event(cur.ID(), 3, wordBytes(4, 6)...) | |
| 683 | + | s.event(cur.ID(), 1) | |
| 684 | + | if pos != [2]int32{-5, 9} || hot != [2]int32{4, 6} || !reflect.DeepEqual(cl, []string{"enter", "leave"}) { | |
| 685 | + | t.Fatal(pos, hot, cl) | |
| 686 | + | } | |
| 687 | + | csess, e := cur.GetCaptureSession() | |
| 688 | + | noerr(t, e) | |
| 689 | + | wantWords(t, "get_capture_session", s.req(cur.ID(), 1), csess.ID()) | |
| 690 | + | if csess.Version() != cur.Version() { | |
| 691 | + | t.Fatalf("child version %d, parent %d", csess.Version(), cur.Version()) | |
| 692 | + | } | |
| 693 | + | ||
| 694 | + | // destroy order: children, sources, managers, toplevel handle. | |
| 695 | + | for _, c := range []struct { | |
| 696 | + | name string | |
| 697 | + | id uint32 | |
| 698 | + | op uint16 | |
| 699 | + | fn func() error | |
| 700 | + | }{ | |
| 701 | + | {"failed frame", failing.ID(), 0, failing.Destroy}, | |
| 702 | + | {"capture session", csess.ID(), 1, csess.Destroy}, | |
| 703 | + | {"session", sess.ID(), 1, sess.Destroy}, | |
| 704 | + | {"cursor", cur.ID(), 0, cur.Destroy}, | |
| 705 | + | {"output source", outSrc.ID(), 0, outSrc.Destroy}, | |
| 706 | + | {"toplevel source", topSrc.ID(), 0, topSrc.Destroy}, | |
| 707 | + | {"copy manager", cm.ID(), 2, cm.Destroy}, | |
| 708 | + | {"output manager", om.ID(), 1, om.Destroy}, | |
| 709 | + | {"toplevel manager", fm.ID(), 1, fm.Destroy}, | |
| 710 | + | {"handle", handle.ID(), 0, handle.Destroy}, | |
| 711 | + | } { | |
| 712 | + | // Subtests run serially (no t.Parallel): the wire order of destroy | |
| 713 | + | // requests on the shared socketpair is part of what is asserted. | |
| 714 | + | ok := t.Run(c.name, func(t *testing.T) { | |
| 715 | + | ss := *s | |
| 716 | + | ss.t = t | |
| 717 | + | noerr(t, c.fn()) | |
| 718 | + | ss.req(c.id, c.op) | |
| 719 | + | }) | |
| 720 | + | if !ok { | |
| 721 | + | // A failed step leaves unread bytes on the socket; carrying on | |
| 722 | + | // would misattribute them to later destroys. | |
| 723 | + | t.FailNow() | |
| 724 | + | } | |
| 725 | + | } | |
| 726 | + | } | |
A protocol/inputmethod/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package inputmethod | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p inputmethod -o input-method-unstable-v2_generated.go -import wl_seat=github.com/bnema/wlturbo/protocol/core -import wl_surface=github.com/bnema/wlturbo/protocol/core input-method-unstable-v2.xml | |
A protocol/inputmethod/input-method-unstable-v2.xml +494 -0
| @@ -0,0 +1,494 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="input_method_unstable_v2"> | |
| 3 | + | ||
| 4 | + | <copyright> | |
| 5 | + | Copyright © 2008-2011 Kristian Høgsberg | |
| 6 | + | Copyright © 2010-2011 Intel Corporation | |
| 7 | + | Copyright © 2012-2013 Collabora, Ltd. | |
| 8 | + | Copyright © 2012, 2013 Intel Corporation | |
| 9 | + | Copyright © 2015, 2016 Jan Arne Petersen | |
| 10 | + | Copyright © 2017, 2018 Red Hat, Inc. | |
| 11 | + | Copyright © 2018 Purism SPC | |
| 12 | + | ||
| 13 | + | Permission is hereby granted, free of charge, to any person obtaining a | |
| 14 | + | copy of this software and associated documentation files (the "Software"), | |
| 15 | + | to deal in the Software without restriction, including without limitation | |
| 16 | + | the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 17 | + | and/or sell copies of the Software, and to permit persons to whom the | |
| 18 | + | Software is furnished to do so, subject to the following conditions: | |
| 19 | + | ||
| 20 | + | The above copyright notice and this permission notice (including the next | |
| 21 | + | paragraph) shall be included in all copies or substantial portions of the | |
| 22 | + | Software. | |
| 23 | + | ||
| 24 | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 25 | + | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 26 | + | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 27 | + | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 28 | + | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 29 | + | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 30 | + | DEALINGS IN THE SOFTWARE. | |
| 31 | + | </copyright> | |
| 32 | + | ||
| 33 | + | <description summary="Protocol for creating input methods"> | |
| 34 | + | This protocol allows applications to act as input methods for compositors. | |
| 35 | + | ||
| 36 | + | An input method context is used to manage the state of the input method. | |
| 37 | + | ||
| 38 | + | Text strings are UTF-8 encoded, their indices and lengths are in bytes. | |
| 39 | + | ||
| 40 | + | This document adheres to the RFC 2119 when using words like "must", | |
| 41 | + | "should", "may", etc. | |
| 42 | + | ||
| 43 | + | Warning! The protocol described in this file is experimental and | |
| 44 | + | backward incompatible changes may be made. Backward compatible changes | |
| 45 | + | may be added together with the corresponding interface version bump. | |
| 46 | + | Backward incompatible changes are done by bumping the version number in | |
| 47 | + | the protocol and interface names and resetting the interface version. | |
| 48 | + | Once the protocol is to be declared stable, the 'z' prefix and the | |
| 49 | + | version number in the protocol and interface names are removed and the | |
| 50 | + | interface version number is reset. | |
| 51 | + | </description> | |
| 52 | + | ||
| 53 | + | <interface name="zwp_input_method_v2" version="1"> | |
| 54 | + | <description summary="input method"> | |
| 55 | + | An input method object allows for clients to compose text. | |
| 56 | + | ||
| 57 | + | The objects connects the client to a text input in an application, and | |
| 58 | + | lets the client to serve as an input method for a seat. | |
| 59 | + | ||
| 60 | + | The zwp_input_method_v2 object can occupy two distinct states: active and | |
| 61 | + | inactive. In the active state, the object is associated to and | |
| 62 | + | communicates with a text input. In the inactive state, there is no | |
| 63 | + | associated text input, and the only communication is with the compositor. | |
| 64 | + | Initially, the input method is in the inactive state. | |
| 65 | + | ||
| 66 | + | Requests issued in the inactive state must be accepted by the compositor. | |
| 67 | + | Because of the serial mechanism, and the state reset on activate event, | |
| 68 | + | they will not have any effect on the state of the next text input. | |
| 69 | + | ||
| 70 | + | There must be no more than one input method object per seat. | |
| 71 | + | </description> | |
| 72 | + | ||
| 73 | + | <enum name="error"> | |
| 74 | + | <entry name="role" value="0" summary="wl_surface has another role"/> | |
| 75 | + | </enum> | |
| 76 | + | ||
| 77 | + | <event name="activate"> | |
| 78 | + | <description summary="input method has been requested"> | |
| 79 | + | Notification that a text input focused on this seat requested the input | |
| 80 | + | method to be activated. | |
| 81 | + | ||
| 82 | + | This event serves the purpose of providing the compositor with an | |
| 83 | + | active input method. | |
| 84 | + | ||
| 85 | + | This event resets all state associated with previous enable, disable, | |
| 86 | + | surrounding_text, text_change_cause, and content_type events, as well | |
| 87 | + | as the state associated with set_preedit_string, commit_string, and | |
| 88 | + | delete_surrounding_text requests. In addition, it marks the | |
| 89 | + | zwp_input_method_v2 object as active, and makes any existing | |
| 90 | + | zwp_input_popup_surface_v2 objects visible. | |
| 91 | + | ||
| 92 | + | The surrounding_text, and content_type events must follow before the | |
| 93 | + | next done event if the text input supports the respective | |
| 94 | + | functionality. | |
| 95 | + | ||
| 96 | + | State set with this event is double-buffered. It will get applied on | |
| 97 | + | the next zwp_input_method_v2.done event, and stay valid until changed. | |
| 98 | + | </description> | |
| 99 | + | </event> | |
| 100 | + | ||
| 101 | + | <event name="deactivate"> | |
| 102 | + | <description summary="deactivate event"> | |
| 103 | + | Notification that no focused text input currently needs an active | |
| 104 | + | input method on this seat. | |
| 105 | + | ||
| 106 | + | This event marks the zwp_input_method_v2 object as inactive. The | |
| 107 | + | compositor must make all existing zwp_input_popup_surface_v2 objects | |
| 108 | + | invisible until the next activate event. | |
| 109 | + | ||
| 110 | + | State set with this event is double-buffered. It will get applied on | |
| 111 | + | the next zwp_input_method_v2.done event, and stay valid until changed. | |
| 112 | + | </description> | |
| 113 | + | </event> | |
| 114 | + | ||
| 115 | + | <event name="surrounding_text"> | |
| 116 | + | <description summary="surrounding text event"> | |
| 117 | + | Updates the surrounding plain text around the cursor, excluding the | |
| 118 | + | preedit text. | |
| 119 | + | ||
| 120 | + | If any preedit text is present, it is replaced with the cursor for the | |
| 121 | + | purpose of this event. | |
| 122 | + | ||
| 123 | + | The argument text is a buffer containing the preedit string, and must | |
| 124 | + | include the cursor position, and the complete selection. It should | |
| 125 | + | contain additional characters before and after these. There is a | |
| 126 | + | maximum length of wayland messages, so text can not be longer than 4000 | |
| 127 | + | bytes. | |
| 128 | + | ||
| 129 | + | cursor is the byte offset of the cursor within the text buffer. | |
| 130 | + | ||
| 131 | + | anchor is the byte offset of the selection anchor within the text | |
| 132 | + | buffer. If there is no selected text, anchor must be the same as | |
| 133 | + | cursor. | |
| 134 | + | ||
| 135 | + | If this event does not arrive before the first done event, the input | |
| 136 | + | method may assume that the text input does not support this | |
| 137 | + | functionality and ignore following surrounding_text events. | |
| 138 | + | ||
| 139 | + | Values set with this event are double-buffered. They will get applied | |
| 140 | + | and set to initial values on the next zwp_input_method_v2.done | |
| 141 | + | event. | |
| 142 | + | ||
| 143 | + | The initial state for affected fields is empty, meaning that the text | |
| 144 | + | input does not support sending surrounding text. If the empty values | |
| 145 | + | get applied, subsequent attempts to change them may have no effect. | |
| 146 | + | </description> | |
| 147 | + | <arg name="text" type="string"/> | |
| 148 | + | <arg name="cursor" type="uint"/> | |
| 149 | + | <arg name="anchor" type="uint"/> | |
| 150 | + | </event> | |
| 151 | + | ||
| 152 | + | <event name="text_change_cause"> | |
| 153 | + | <description summary="indicates the cause of surrounding text change"> | |
| 154 | + | Tells the input method why the text surrounding the cursor changed. | |
| 155 | + | ||
| 156 | + | Whenever the client detects an external change in text, cursor, or | |
| 157 | + | anchor position, it must issue this request to the compositor. This | |
| 158 | + | request is intended to give the input method a chance to update the | |
| 159 | + | preedit text in an appropriate way, e.g. by removing it when the user | |
| 160 | + | starts typing with a keyboard. | |
| 161 | + | ||
| 162 | + | cause describes the source of the change. | |
| 163 | + | ||
| 164 | + | The value set with this event is double-buffered. It will get applied | |
| 165 | + | and set to its initial value on the next zwp_input_method_v2.done | |
| 166 | + | event. | |
| 167 | + | ||
| 168 | + | The initial value of cause is input_method. | |
| 169 | + | </description> | |
| 170 | + | <arg name="cause" type="uint" enum="zwp_text_input_v3.change_cause"/> | |
| 171 | + | </event> | |
| 172 | + | ||
| 173 | + | <event name="content_type"> | |
| 174 | + | <description summary="content purpose and hint"> | |
| 175 | + | Indicates the content type and hint for the current | |
| 176 | + | zwp_input_method_v2 instance. | |
| 177 | + | ||
| 178 | + | Values set with this event are double-buffered. They will get applied | |
| 179 | + | on the next zwp_input_method_v2.done event. | |
| 180 | + | ||
| 181 | + | The initial value for hint is none, and the initial value for purpose | |
| 182 | + | is normal. | |
| 183 | + | </description> | |
| 184 | + | <arg name="hint" type="uint" enum="zwp_text_input_v3.content_hint"/> | |
| 185 | + | <arg name="purpose" type="uint" enum="zwp_text_input_v3.content_purpose"/> | |
| 186 | + | </event> | |
| 187 | + | ||
| 188 | + | <event name="done"> | |
| 189 | + | <description summary="apply state"> | |
| 190 | + | Atomically applies state changes recently sent to the client. | |
| 191 | + | ||
| 192 | + | The done event establishes and updates the state of the client, and | |
| 193 | + | must be issued after any changes to apply them. | |
| 194 | + | ||
| 195 | + | Text input state (content purpose, content hint, surrounding text, and | |
| 196 | + | change cause) is conceptually double-buffered within an input method | |
| 197 | + | context. | |
| 198 | + | ||
| 199 | + | Events modify the pending state, as opposed to the current state in use | |
| 200 | + | by the input method. A done event atomically applies all pending state, | |
| 201 | + | replacing the current state. After done, the new pending state is as | |
| 202 | + | documented for each related request. | |
| 203 | + | ||
| 204 | + | Events must be applied in the order of arrival. | |
| 205 | + | ||
| 206 | + | Neither current nor pending state are modified unless noted otherwise. | |
| 207 | + | </description> | |
| 208 | + | </event> | |
| 209 | + | ||
| 210 | + | <request name="commit_string"> | |
| 211 | + | <description summary="commit string"> | |
| 212 | + | Send the commit string text for insertion to the application. | |
| 213 | + | ||
| 214 | + | Inserts a string at current cursor position (see commit event | |
| 215 | + | sequence). The string to commit could be either just a single character | |
| 216 | + | after a key press or the result of some composing. | |
| 217 | + | ||
| 218 | + | The argument text is a buffer containing the string to insert. There is | |
| 219 | + | a maximum length of wayland messages, so text can not be longer than | |
| 220 | + | 4000 bytes. | |
| 221 | + | ||
| 222 | + | Values set with this event are double-buffered. They must be applied | |
| 223 | + | and reset to initial on the next zwp_text_input_v3.commit request. | |
| 224 | + | ||
| 225 | + | The initial value of text is an empty string. | |
| 226 | + | </description> | |
| 227 | + | <arg name="text" type="string"/> | |
| 228 | + | </request> | |
| 229 | + | ||
| 230 | + | <request name="set_preedit_string"> | |
| 231 | + | <description summary="pre-edit string"> | |
| 232 | + | Send the pre-edit string text to the application text input. | |
| 233 | + | ||
| 234 | + | Place a new composing text (pre-edit) at the current cursor position. | |
| 235 | + | Any previously set composing text must be removed. Any previously | |
| 236 | + | existing selected text must be removed. The cursor is moved to a new | |
| 237 | + | position within the preedit string. | |
| 238 | + | ||
| 239 | + | The argument text is a buffer containing the preedit string. There is | |
| 240 | + | a maximum length of wayland messages, so text can not be longer than | |
| 241 | + | 4000 bytes. | |
| 242 | + | ||
| 243 | + | The arguments cursor_begin and cursor_end are counted in bytes relative | |
| 244 | + | to the beginning of the submitted string buffer. Cursor should be | |
| 245 | + | hidden by the text input when both are equal to -1. | |
| 246 | + | ||
| 247 | + | cursor_begin indicates the beginning of the cursor. cursor_end | |
| 248 | + | indicates the end of the cursor. It may be equal or different than | |
| 249 | + | cursor_begin. | |
| 250 | + | ||
| 251 | + | Values set with this event are double-buffered. They must be applied on | |
| 252 | + | the next zwp_input_method_v2.commit event. | |
| 253 | + | ||
| 254 | + | The initial value of text is an empty string. The initial value of | |
| 255 | + | cursor_begin, and cursor_end are both 0. | |
| 256 | + | </description> | |
| 257 | + | <arg name="text" type="string"/> | |
| 258 | + | <arg name="cursor_begin" type="int"/> | |
| 259 | + | <arg name="cursor_end" type="int"/> | |
| 260 | + | </request> | |
| 261 | + | ||
| 262 | + | <request name="delete_surrounding_text"> | |
| 263 | + | <description summary="delete text"> | |
| 264 | + | Remove the surrounding text. | |
| 265 | + | ||
| 266 | + | before_length and after_length are the number of bytes before and after | |
| 267 | + | the current cursor index (excluding the preedit text) to delete. | |
| 268 | + | ||
| 269 | + | If any preedit text is present, it is replaced with the cursor for the | |
| 270 | + | purpose of this event. In effect before_length is counted from the | |
| 271 | + | beginning of preedit text, and after_length from its end (see commit | |
| 272 | + | event sequence). | |
| 273 | + | ||
| 274 | + | Values set with this event are double-buffered. They must be applied | |
| 275 | + | and reset to initial on the next zwp_input_method_v2.commit request. | |
| 276 | + | ||
| 277 | + | The initial values of both before_length and after_length are 0. | |
| 278 | + | </description> | |
| 279 | + | <arg name="before_length" type="uint"/> | |
| 280 | + | <arg name="after_length" type="uint"/> | |
| 281 | + | </request> | |
| 282 | + | ||
| 283 | + | <request name="commit"> | |
| 284 | + | <description summary="apply state"> | |
| 285 | + | Apply state changes from commit_string, set_preedit_string and | |
| 286 | + | delete_surrounding_text requests. | |
| 287 | + | ||
| 288 | + | The state relating to these events is double-buffered, and each one | |
| 289 | + | modifies the pending state. This request replaces the current state | |
| 290 | + | with the pending state. | |
| 291 | + | ||
| 292 | + | The connected text input is expected to proceed by evaluating the | |
| 293 | + | changes in the following order: | |
| 294 | + | ||
| 295 | + | 1. Replace existing preedit string with the cursor. | |
| 296 | + | 2. Delete requested surrounding text. | |
| 297 | + | 3. Insert commit string with the cursor at its end. | |
| 298 | + | 4. Calculate surrounding text to send. | |
| 299 | + | 5. Insert new preedit text in cursor position. | |
| 300 | + | 6. Place cursor inside preedit text. | |
| 301 | + | ||
| 302 | + | The serial number reflects the last state of the zwp_input_method_v2 | |
| 303 | + | object known to the client. The value of the serial argument must be | |
| 304 | + | equal to the number of done events already issued by that object. When | |
| 305 | + | the compositor receives a commit request with a serial different than | |
| 306 | + | the number of past done events, it must proceed as normal, except it | |
| 307 | + | should not change the current state of the zwp_input_method_v2 object. | |
| 308 | + | </description> | |
| 309 | + | <arg name="serial" type="uint"/> | |
| 310 | + | </request> | |
| 311 | + | ||
| 312 | + | <request name="get_input_popup_surface"> | |
| 313 | + | <description summary="create popup surface"> | |
| 314 | + | Creates a new zwp_input_popup_surface_v2 object wrapping a given | |
| 315 | + | surface. | |
| 316 | + | ||
| 317 | + | The surface gets assigned the "input_popup" role. If the surface | |
| 318 | + | already has an assigned role, the compositor must issue a protocol | |
| 319 | + | error. | |
| 320 | + | </description> | |
| 321 | + | <arg name="id" type="new_id" interface="zwp_input_popup_surface_v2"/> | |
| 322 | + | <arg name="surface" type="object" interface="wl_surface"/> | |
| 323 | + | </request> | |
| 324 | + | ||
| 325 | + | <request name="grab_keyboard"> | |
| 326 | + | <description summary="grab hardware keyboard"> | |
| 327 | + | Allow an input method to receive hardware keyboard input and process | |
| 328 | + | key events to generate text events (with pre-edit) over the wire. This | |
| 329 | + | allows input methods which compose multiple key events for inputting | |
| 330 | + | text like it is done for CJK languages. | |
| 331 | + | ||
| 332 | + | The compositor should send all keyboard events on the seat to the grab | |
| 333 | + | holder via the returned wl_keyboard object. Nevertheless, the | |
| 334 | + | compositor may decide not to forward any particular event. The | |
| 335 | + | compositor must not further process any event after it has been | |
| 336 | + | forwarded to the grab holder. | |
| 337 | + | ||
| 338 | + | Releasing the resulting wl_keyboard object releases the grab. | |
| 339 | + | </description> | |
| 340 | + | <arg name="keyboard" type="new_id" | |
| 341 | + | interface="zwp_input_method_keyboard_grab_v2"/> | |
| 342 | + | </request> | |
| 343 | + | ||
| 344 | + | <event name="unavailable"> | |
| 345 | + | <description summary="input method unavailable"> | |
| 346 | + | The input method ceased to be available. | |
| 347 | + | ||
| 348 | + | The compositor must issue this event as the only event on the object if | |
| 349 | + | there was another input_method object associated with the same seat at | |
| 350 | + | the time of its creation. | |
| 351 | + | ||
| 352 | + | The compositor must issue this request when the object is no longer | |
| 353 | + | usable, e.g. due to seat removal. | |
| 354 | + | ||
| 355 | + | The input method context becomes inert and should be destroyed after | |
| 356 | + | deactivation is handled. Any further requests and events except for the | |
| 357 | + | destroy request must be ignored. | |
| 358 | + | </description> | |
| 359 | + | </event> | |
| 360 | + | ||
| 361 | + | <request name="destroy" type="destructor"> | |
| 362 | + | <description summary="destroy the text input"> | |
| 363 | + | Destroys the zwp_text_input_v2 object and any associated child | |
| 364 | + | objects, i.e. zwp_input_popup_surface_v2 and | |
| 365 | + | zwp_input_method_keyboard_grab_v2. | |
| 366 | + | </description> | |
| 367 | + | </request> | |
| 368 | + | </interface> | |
| 369 | + | ||
| 370 | + | <interface name="zwp_input_popup_surface_v2" version="1"> | |
| 371 | + | <description summary="popup surface"> | |
| 372 | + | This interface marks a surface as a popup for interacting with an input | |
| 373 | + | method. | |
| 374 | + | ||
| 375 | + | The compositor should place it near the active text input area. It must | |
| 376 | + | be visible if and only if the input method is in the active state. | |
| 377 | + | ||
| 378 | + | The client must not destroy the underlying wl_surface while the | |
| 379 | + | zwp_input_popup_surface_v2 object exists. | |
| 380 | + | </description> | |
| 381 | + | ||
| 382 | + | <event name="text_input_rectangle"> | |
| 383 | + | <description summary="set text input area position"> | |
| 384 | + | Notify about the position of the area of the text input expressed as a | |
| 385 | + | rectangle in surface local coordinates. | |
| 386 | + | ||
| 387 | + | This is a hint to the input method telling it the relative position of | |
| 388 | + | the text being entered. | |
| 389 | + | </description> | |
| 390 | + | <arg name="x" type="int"/> | |
| 391 | + | <arg name="y" type="int"/> | |
| 392 | + | <arg name="width" type="int"/> | |
| 393 | + | <arg name="height" type="int"/> | |
| 394 | + | </event> | |
| 395 | + | ||
| 396 | + | <request name="destroy" type="destructor"/> | |
| 397 | + | </interface> | |
| 398 | + | ||
| 399 | + | <interface name="zwp_input_method_keyboard_grab_v2" version="1"> | |
| 400 | + | <!-- Closely follows wl_keyboard version 6 --> | |
| 401 | + | <description summary="keyboard grab"> | |
| 402 | + | The zwp_input_method_keyboard_grab_v2 interface represents an exclusive | |
| 403 | + | grab of the wl_keyboard interface associated with the seat. | |
| 404 | + | </description> | |
| 405 | + | ||
| 406 | + | <event name="keymap"> | |
| 407 | + | <description summary="keyboard mapping"> | |
| 408 | + | This event provides a file descriptor to the client which can be | |
| 409 | + | memory-mapped to provide a keyboard mapping description. | |
| 410 | + | </description> | |
| 411 | + | <arg name="format" type="uint" enum="wl_keyboard.keymap_format" | |
| 412 | + | summary="keymap format"/> | |
| 413 | + | <arg name="fd" type="fd" summary="keymap file descriptor"/> | |
| 414 | + | <arg name="size" type="uint" summary="keymap size, in bytes"/> | |
| 415 | + | </event> | |
| 416 | + | ||
| 417 | + | <event name="key"> | |
| 418 | + | <description summary="key event"> | |
| 419 | + | A key was pressed or released. | |
| 420 | + | The time argument is a timestamp with millisecond granularity, with an | |
| 421 | + | undefined base. | |
| 422 | + | </description> | |
| 423 | + | <arg name="serial" type="uint" summary="serial number of the key event"/> | |
| 424 | + | <arg name="time" type="uint" summary="timestamp with millisecond granularity"/> | |
| 425 | + | <arg name="key" type="uint" summary="key that produced the event"/> | |
| 426 | + | <arg name="state" type="uint" enum="wl_keyboard.key_state" | |
| 427 | + | summary="physical state of the key"/> | |
| 428 | + | </event> | |
| 429 | + | ||
| 430 | + | <event name="modifiers"> | |
| 431 | + | <description summary="modifier and group state"> | |
| 432 | + | Notifies clients that the modifier and/or group state has changed, and | |
| 433 | + | it should update its local state. | |
| 434 | + | </description> | |
| 435 | + | <arg name="serial" type="uint" summary="serial number of the modifiers event"/> | |
| 436 | + | <arg name="mods_depressed" type="uint" summary="depressed modifiers"/> | |
| 437 | + | <arg name="mods_latched" type="uint" summary="latched modifiers"/> | |
| 438 | + | <arg name="mods_locked" type="uint" summary="locked modifiers"/> | |
| 439 | + | <arg name="group" type="uint" summary="keyboard layout"/> | |
| 440 | + | </event> | |
| 441 | + | ||
| 442 | + | <request name="release" type="destructor"> | |
| 443 | + | <description summary="release the grab object"/> | |
| 444 | + | </request> | |
| 445 | + | ||
| 446 | + | <event name="repeat_info"> | |
| 447 | + | <description summary="repeat rate and delay"> | |
| 448 | + | Informs the client about the keyboard's repeat rate and delay. | |
| 449 | + | ||
| 450 | + | This event is sent as soon as the zwp_input_method_keyboard_grab_v2 | |
| 451 | + | object has been created, and is guaranteed to be received by the | |
| 452 | + | client before any key press event. | |
| 453 | + | ||
| 454 | + | Negative values for either rate or delay are illegal. A rate of zero | |
| 455 | + | will disable any repeating (regardless of the value of delay). | |
| 456 | + | ||
| 457 | + | This event can be sent later on as well with a new value if necessary, | |
| 458 | + | so clients should continue listening for the event past the creation | |
| 459 | + | of zwp_input_method_keyboard_grab_v2. | |
| 460 | + | </description> | |
| 461 | + | <arg name="rate" type="int" | |
| 462 | + | summary="the rate of repeating keys in characters per second"/> | |
| 463 | + | <arg name="delay" type="int" | |
| 464 | + | summary="delay in milliseconds since key down until repeating starts"/> | |
| 465 | + | </event> | |
| 466 | + | </interface> | |
| 467 | + | ||
| 468 | + | <interface name="zwp_input_method_manager_v2" version="1"> | |
| 469 | + | <description summary="input method manager"> | |
| 470 | + | The input method manager allows the client to become the input method on | |
| 471 | + | a chosen seat. | |
| 472 | + | ||
| 473 | + | No more than one input method must be associated with any seat at any | |
| 474 | + | given time. | |
| 475 | + | </description> | |
| 476 | + | ||
| 477 | + | <request name="get_input_method"> | |
| 478 | + | <description summary="request an input method object"> | |
| 479 | + | Request a new input zwp_input_method_v2 object associated with a given | |
| 480 | + | seat. | |
| 481 | + | </description> | |
| 482 | + | <arg name="seat" type="object" interface="wl_seat"/> | |
| 483 | + | <arg name="input_method" type="new_id" interface="zwp_input_method_v2"/> | |
| 484 | + | </request> | |
| 485 | + | ||
| 486 | + | <request name="destroy" type="destructor"> | |
| 487 | + | <description summary="destroy the input method manager"> | |
| 488 | + | Destroys the zwp_input_method_manager_v2 object. | |
| 489 | + | ||
| 490 | + | The zwp_input_method_v2 objects originating from it remain valid. | |
| 491 | + | </description> | |
| 492 | + | </request> | |
| 493 | + | </interface> | |
| 494 | + | </protocol> | |
A protocol/inputmethod/input-method-unstable-v2_generated.go +677 -0
| @@ -0,0 +1,677 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: input_method_unstable_v2 | |
| 3 | + | // Source: input-method-unstable-v2.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2008-2011 Kristian Høgsberg | |
| 7 | + | // Copyright © 2010-2011 Intel Corporation | |
| 8 | + | // Copyright © 2012-2013 Collabora, Ltd. | |
| 9 | + | // Copyright © 2012, 2013 Intel Corporation | |
| 10 | + | // Copyright © 2015, 2016 Jan Arne Petersen | |
| 11 | + | // Copyright © 2017, 2018 Red Hat, Inc. | |
| 12 | + | // Copyright © 2018 Purism SPC | |
| 13 | + | // | |
| 14 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 15 | + | // copy of this software and associated documentation files (the "Software"), | |
| 16 | + | // to deal in the Software without restriction, including without limitation | |
| 17 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 18 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 19 | + | // Software is furnished to do so, subject to the following conditions: | |
| 20 | + | // | |
| 21 | + | // The above copyright notice and this permission notice (including the next | |
| 22 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 23 | + | // Software. | |
| 24 | + | // | |
| 25 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 26 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 27 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 28 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 29 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 30 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 31 | + | // DEALINGS IN THE SOFTWARE. | |
| 32 | + | ||
| 33 | + | package inputmethod | |
| 34 | + | ||
| 35 | + | import ( | |
| 36 | + | "sync" | |
| 37 | + | ||
| 38 | + | cross_wl_seat "github.com/bnema/wlturbo/protocol/core" | |
| 39 | + | cross_wl_surface "github.com/bnema/wlturbo/protocol/core" | |
| 40 | + | "github.com/bnema/wlturbo/wl" | |
| 41 | + | ) | |
| 42 | + | ||
| 43 | + | // ERROR_ROLE is the error role value. | |
| 44 | + | const ERROR_ROLE = 0 | |
| 45 | + | ||
| 46 | + | // InputMethodInterface is the protocol interface name. | |
| 47 | + | const InputMethodInterface = "zwp_input_method_v2" | |
| 48 | + | ||
| 49 | + | // InputMethod is the generated binding for zwp_input_method_v2 version 1. | |
| 50 | + | type InputMethod struct { | |
| 51 | + | wl.BaseProxy | |
| 52 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 53 | + | // handlers while another goroutine dispatches events. | |
| 54 | + | handlersMu sync.Mutex | |
| 55 | + | onActivate []func() | |
| 56 | + | onDeactivate []func() | |
| 57 | + | onSurroundingText []func(text string, cursor uint32, anchor uint32) | |
| 58 | + | onTextChangeCause []func(cause uint32) | |
| 59 | + | onContentType []func(hint uint32, purpose uint32) | |
| 60 | + | onDone []func() | |
| 61 | + | onUnavailable []func() | |
| 62 | + | } | |
| 63 | + | ||
| 64 | + | // NewInputMethod returns an unbound InputMethod. | |
| 65 | + | func NewInputMethod(ctx *wl.Context) *InputMethod { | |
| 66 | + | obj := &InputMethod{} | |
| 67 | + | obj.SetContext(ctx) | |
| 68 | + | ctx.Register(obj) | |
| 69 | + | return obj | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | // Send the commit string text for insertion to the application. Inserts a string at current cursor position (see commit event sequence). The string to commit could be either just a single character after a key press or the result of some composing. The argument text is a buffer containing the string to insert. There is a maximum length of wayland messages, so text can not be longer than 4000 bytes. Values set with this event are double-buffered. They must be applied and reset to initial on the next zwp_text_input_v3.commit request. The initial value of text is an empty string. | |
| 73 | + | func (o *InputMethod) CommitString(text string) error { | |
| 74 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_input_method_v2.commit_string"}, wl.ArgString(text)); err != nil { | |
| 75 | + | return err | |
| 76 | + | } | |
| 77 | + | return nil | |
| 78 | + | } | |
| 79 | + | ||
| 80 | + | // Send the pre-edit string text to the application text input. Place a new composing text (pre-edit) at the current cursor position. Any previously set composing text must be removed. Any previously existing selected text must be removed. The cursor is moved to a new position within the preedit string. The argument text is a buffer containing the preedit string. There is a maximum length of wayland messages, so text can not be longer than 4000 bytes. The arguments cursor_begin and cursor_end are counted in bytes relative to the beginning of the submitted string buffer. Cursor should be hidden by the text input when both are equal to -1. cursor_begin indicates the beginning of the cursor. cursor_end indicates the end of the cursor. It may be equal or different than cursor_begin. Values set with this event are double-buffered. They must be applied on the next zwp_input_method_v2.commit event. The initial value of text is an empty string. The initial value of cursor_begin, and cursor_end are both 0. | |
| 81 | + | func (o *InputMethod) SetPreeditString(text string, cursorBegin int32, cursorEnd int32) error { | |
| 82 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_input_method_v2.set_preedit_string"}, wl.ArgString(text), wl.ArgInt(cursorBegin), wl.ArgInt(cursorEnd)); err != nil { | |
| 83 | + | return err | |
| 84 | + | } | |
| 85 | + | return nil | |
| 86 | + | } | |
| 87 | + | ||
| 88 | + | // Remove the surrounding text. before_length and after_length are the number of bytes before and after the current cursor index (excluding the preedit text) to delete. If any preedit text is present, it is replaced with the cursor for the purpose of this event. In effect before_length is counted from the beginning of preedit text, and after_length from its end (see commit event sequence). Values set with this event are double-buffered. They must be applied and reset to initial on the next zwp_input_method_v2.commit request. The initial values of both before_length and after_length are 0. | |
| 89 | + | func (o *InputMethod) DeleteSurroundingText(beforeLength uint32, afterLength uint32) error { | |
| 90 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_input_method_v2.delete_surrounding_text"}, wl.ArgUint(beforeLength), wl.ArgUint(afterLength)); err != nil { | |
| 91 | + | return err | |
| 92 | + | } | |
| 93 | + | return nil | |
| 94 | + | } | |
| 95 | + | ||
| 96 | + | // Apply state changes from commit_string, set_preedit_string and delete_surrounding_text requests. The state relating to these events is double-buffered, and each one modifies the pending state. This request replaces the current state with the pending state. The connected text input is expected to proceed by evaluating the changes in the following order: 1. Replace existing preedit string with the cursor. 2. Delete requested surrounding text. 3. Insert commit string with the cursor at its end. 4. Calculate surrounding text to send. 5. Insert new preedit text in cursor position. 6. Place cursor inside preedit text. The serial number reflects the last state of the zwp_input_method_v2 object known to the client. The value of the serial argument must be equal to the number of done events already issued by that object. When the compositor receives a commit request with a serial different than the number of past done events, it must proceed as normal, except it should not change the current state of the zwp_input_method_v2 object. | |
| 97 | + | func (o *InputMethod) Commit(serial uint32) error { | |
| 98 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "zwp_input_method_v2.commit"}, wl.ArgUint(serial)); err != nil { | |
| 99 | + | return err | |
| 100 | + | } | |
| 101 | + | return nil | |
| 102 | + | } | |
| 103 | + | ||
| 104 | + | // Creates a new zwp_input_popup_surface_v2 object wrapping a given surface. The surface gets assigned the "input_popup" role. If the surface already has an assigned role, the compositor must issue a protocol error. | |
| 105 | + | func (o *InputMethod) GetInputPopupSurface(surface *cross_wl_surface.Surface) (*InputPopupSurface, error) { | |
| 106 | + | var arg1 wl.Object | |
| 107 | + | if surface != nil { | |
| 108 | + | arg1 = surface | |
| 109 | + | } | |
| 110 | + | child := &InputPopupSurface{} | |
| 111 | + | child.SetContext(o.Context()) | |
| 112 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 4, Name: "zwp_input_method_v2.get_input_popup_surface", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 113 | + | return nil, err | |
| 114 | + | } | |
| 115 | + | return child, nil | |
| 116 | + | } | |
| 117 | + | ||
| 118 | + | // Allow an input method to receive hardware keyboard input and process key events to generate text events (with pre-edit) over the wire. This allows input methods which compose multiple key events for inputting text like it is done for CJK languages. The compositor should send all keyboard events on the seat to the grab holder via the returned wl_keyboard object. Nevertheless, the compositor may decide not to forward any particular event. The compositor must not further process any event after it has been forwarded to the grab holder. Releasing the resulting wl_keyboard object releases the grab. | |
| 119 | + | func (o *InputMethod) GrabKeyboard() (*InputMethodKeyboardGrab, error) { | |
| 120 | + | child := &InputMethodKeyboardGrab{} | |
| 121 | + | child.SetContext(o.Context()) | |
| 122 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 5, Name: "zwp_input_method_v2.grab_keyboard", Child: child}, wl.ArgObject(child)); err != nil { | |
| 123 | + | return nil, err | |
| 124 | + | } | |
| 125 | + | return child, nil | |
| 126 | + | } | |
| 127 | + | ||
| 128 | + | // Destroys the zwp_text_input_v2 object and any associated child objects, i.e. zwp_input_popup_surface_v2 and zwp_input_method_keyboard_grab_v2. | |
| 129 | + | func (o *InputMethod) Destroy() error { | |
| 130 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 6, Name: "zwp_input_method_v2.destroy", Destructor: true}); err != nil { | |
| 131 | + | return err | |
| 132 | + | } | |
| 133 | + | return nil | |
| 134 | + | } | |
| 135 | + | ||
| 136 | + | // OnActivate registers a handler for the activate event. | |
| 137 | + | // | |
| 138 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 139 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 140 | + | func (o *InputMethod) OnActivate(handler func()) { | |
| 141 | + | if handler == nil { | |
| 142 | + | return | |
| 143 | + | } | |
| 144 | + | o.handlersMu.Lock() | |
| 145 | + | defer o.handlersMu.Unlock() | |
| 146 | + | o.onActivate = append(o.onActivate, handler) | |
| 147 | + | } | |
| 148 | + | ||
| 149 | + | // handlersForActivate returns the handlers registered for activate, taken | |
| 150 | + | // under the lock so a handler may register another handler while events are | |
| 151 | + | // being dispatched. | |
| 152 | + | func (o *InputMethod) handlersForActivate() []func() { | |
| 153 | + | o.handlersMu.Lock() | |
| 154 | + | defer o.handlersMu.Unlock() | |
| 155 | + | return o.onActivate | |
| 156 | + | } | |
| 157 | + | ||
| 158 | + | // OnDeactivate registers a handler for the deactivate event. | |
| 159 | + | // | |
| 160 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 161 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 162 | + | func (o *InputMethod) OnDeactivate(handler func()) { | |
| 163 | + | if handler == nil { | |
| 164 | + | return | |
| 165 | + | } | |
| 166 | + | o.handlersMu.Lock() | |
| 167 | + | defer o.handlersMu.Unlock() | |
| 168 | + | o.onDeactivate = append(o.onDeactivate, handler) | |
| 169 | + | } | |
| 170 | + | ||
| 171 | + | // handlersForDeactivate returns the handlers registered for deactivate, taken | |
| 172 | + | // under the lock so a handler may register another handler while events are | |
| 173 | + | // being dispatched. | |
| 174 | + | func (o *InputMethod) handlersForDeactivate() []func() { | |
| 175 | + | o.handlersMu.Lock() | |
| 176 | + | defer o.handlersMu.Unlock() | |
| 177 | + | return o.onDeactivate | |
| 178 | + | } | |
| 179 | + | ||
| 180 | + | // OnSurroundingText registers a handler for the surrounding_text event. | |
| 181 | + | // | |
| 182 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 183 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 184 | + | func (o *InputMethod) OnSurroundingText(handler func(text string, cursor uint32, anchor uint32)) { | |
| 185 | + | if handler == nil { | |
| 186 | + | return | |
| 187 | + | } | |
| 188 | + | o.handlersMu.Lock() | |
| 189 | + | defer o.handlersMu.Unlock() | |
| 190 | + | o.onSurroundingText = append(o.onSurroundingText, handler) | |
| 191 | + | } | |
| 192 | + | ||
| 193 | + | // handlersForSurroundingText returns the handlers registered for surrounding_text, taken | |
| 194 | + | // under the lock so a handler may register another handler while events are | |
| 195 | + | // being dispatched. | |
| 196 | + | func (o *InputMethod) handlersForSurroundingText() []func(text string, cursor uint32, anchor uint32) { | |
| 197 | + | o.handlersMu.Lock() | |
| 198 | + | defer o.handlersMu.Unlock() | |
| 199 | + | return o.onSurroundingText | |
| 200 | + | } | |
| 201 | + | ||
| 202 | + | // OnTextChangeCause registers a handler for the text_change_cause event. | |
| 203 | + | // | |
| 204 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 205 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 206 | + | func (o *InputMethod) OnTextChangeCause(handler func(cause uint32)) { | |
| 207 | + | if handler == nil { | |
| 208 | + | return | |
| 209 | + | } | |
| 210 | + | o.handlersMu.Lock() | |
| 211 | + | defer o.handlersMu.Unlock() | |
| 212 | + | o.onTextChangeCause = append(o.onTextChangeCause, handler) | |
| 213 | + | } | |
| 214 | + | ||
| 215 | + | // handlersForTextChangeCause returns the handlers registered for text_change_cause, taken | |
| 216 | + | // under the lock so a handler may register another handler while events are | |
| 217 | + | // being dispatched. | |
| 218 | + | func (o *InputMethod) handlersForTextChangeCause() []func(cause uint32) { | |
| 219 | + | o.handlersMu.Lock() | |
| 220 | + | defer o.handlersMu.Unlock() | |
| 221 | + | return o.onTextChangeCause | |
| 222 | + | } | |
| 223 | + | ||
| 224 | + | // OnContentType registers a handler for the content_type event. | |
| 225 | + | // | |
| 226 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 227 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 228 | + | func (o *InputMethod) OnContentType(handler func(hint uint32, purpose uint32)) { | |
| 229 | + | if handler == nil { | |
| 230 | + | return | |
| 231 | + | } | |
| 232 | + | o.handlersMu.Lock() | |
| 233 | + | defer o.handlersMu.Unlock() | |
| 234 | + | o.onContentType = append(o.onContentType, handler) | |
| 235 | + | } | |
| 236 | + | ||
| 237 | + | // handlersForContentType returns the handlers registered for content_type, taken | |
| 238 | + | // under the lock so a handler may register another handler while events are | |
| 239 | + | // being dispatched. | |
| 240 | + | func (o *InputMethod) handlersForContentType() []func(hint uint32, purpose uint32) { | |
| 241 | + | o.handlersMu.Lock() | |
| 242 | + | defer o.handlersMu.Unlock() | |
| 243 | + | return o.onContentType | |
| 244 | + | } | |
| 245 | + | ||
| 246 | + | // OnDone registers a handler for the done event. | |
| 247 | + | // | |
| 248 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 249 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 250 | + | func (o *InputMethod) OnDone(handler func()) { | |
| 251 | + | if handler == nil { | |
| 252 | + | return | |
| 253 | + | } | |
| 254 | + | o.handlersMu.Lock() | |
| 255 | + | defer o.handlersMu.Unlock() | |
| 256 | + | o.onDone = append(o.onDone, handler) | |
| 257 | + | } | |
| 258 | + | ||
| 259 | + | // handlersForDone returns the handlers registered for done, taken | |
| 260 | + | // under the lock so a handler may register another handler while events are | |
| 261 | + | // being dispatched. | |
| 262 | + | func (o *InputMethod) handlersForDone() []func() { | |
| 263 | + | o.handlersMu.Lock() | |
| 264 | + | defer o.handlersMu.Unlock() | |
| 265 | + | return o.onDone | |
| 266 | + | } | |
| 267 | + | ||
| 268 | + | // OnUnavailable registers a handler for the unavailable event. | |
| 269 | + | // | |
| 270 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 271 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 272 | + | func (o *InputMethod) OnUnavailable(handler func()) { | |
| 273 | + | if handler == nil { | |
| 274 | + | return | |
| 275 | + | } | |
| 276 | + | o.handlersMu.Lock() | |
| 277 | + | defer o.handlersMu.Unlock() | |
| 278 | + | o.onUnavailable = append(o.onUnavailable, handler) | |
| 279 | + | } | |
| 280 | + | ||
| 281 | + | // handlersForUnavailable returns the handlers registered for unavailable, taken | |
| 282 | + | // under the lock so a handler may register another handler while events are | |
| 283 | + | // being dispatched. | |
| 284 | + | func (o *InputMethod) handlersForUnavailable() []func() { | |
| 285 | + | o.handlersMu.Lock() | |
| 286 | + | defer o.handlersMu.Unlock() | |
| 287 | + | return o.onUnavailable | |
| 288 | + | } | |
| 289 | + | ||
| 290 | + | // EventSignature returns the declared event argument types in wire order. | |
| 291 | + | func (o *InputMethod) EventSignature(opcode uint16) (string, bool) { | |
| 292 | + | switch opcode { | |
| 293 | + | case 0: | |
| 294 | + | return "", true | |
| 295 | + | case 1: | |
| 296 | + | return "", true | |
| 297 | + | case 2: | |
| 298 | + | return "string,uint,uint,", true | |
| 299 | + | case 3: | |
| 300 | + | return "uint,", true | |
| 301 | + | case 4: | |
| 302 | + | return "uint,uint,", true | |
| 303 | + | case 5: | |
| 304 | + | return "", true | |
| 305 | + | case 6: | |
| 306 | + | return "", true | |
| 307 | + | default: | |
| 308 | + | return "", false | |
| 309 | + | } | |
| 310 | + | } | |
| 311 | + | ||
| 312 | + | // Dispatch decodes one event on zwp_input_method_v2 and calls the registered handlers. | |
| 313 | + | func (o *InputMethod) Dispatch(event *wl.Event) { | |
| 314 | + | switch event.Opcode { | |
| 315 | + | case 0: // activate | |
| 316 | + | ||
| 317 | + | for i, handler := range o.handlersForActivate() { | |
| 318 | + | _ = i | |
| 319 | + | handler() | |
| 320 | + | } | |
| 321 | + | case 1: // deactivate | |
| 322 | + | ||
| 323 | + | for i, handler := range o.handlersForDeactivate() { | |
| 324 | + | _ = i | |
| 325 | + | handler() | |
| 326 | + | } | |
| 327 | + | case 2: // surrounding_text | |
| 328 | + | text := event.String() | |
| 329 | + | cursor := event.Uint32() | |
| 330 | + | anchor := event.Uint32() | |
| 331 | + | ||
| 332 | + | for i, handler := range o.handlersForSurroundingText() { | |
| 333 | + | _ = i | |
| 334 | + | handler(text, cursor, anchor) | |
| 335 | + | } | |
| 336 | + | case 3: // text_change_cause | |
| 337 | + | cause := event.Uint32() | |
| 338 | + | ||
| 339 | + | for i, handler := range o.handlersForTextChangeCause() { | |
| 340 | + | _ = i | |
| 341 | + | handler(cause) | |
| 342 | + | } | |
| 343 | + | case 4: // content_type | |
| 344 | + | hint := event.Uint32() | |
| 345 | + | purpose := event.Uint32() | |
| 346 | + | ||
| 347 | + | for i, handler := range o.handlersForContentType() { | |
| 348 | + | _ = i | |
| 349 | + | handler(hint, purpose) | |
| 350 | + | } | |
| 351 | + | case 5: // done | |
| 352 | + | ||
| 353 | + | for i, handler := range o.handlersForDone() { | |
| 354 | + | _ = i | |
| 355 | + | handler() | |
| 356 | + | } | |
| 357 | + | case 6: // unavailable | |
| 358 | + | ||
| 359 | + | for i, handler := range o.handlersForUnavailable() { | |
| 360 | + | _ = i | |
| 361 | + | handler() | |
| 362 | + | } | |
| 363 | + | default: | |
| 364 | + | } | |
| 365 | + | } | |
| 366 | + | ||
| 367 | + | // InputPopupSurfaceInterface is the protocol interface name. | |
| 368 | + | const InputPopupSurfaceInterface = "zwp_input_popup_surface_v2" | |
| 369 | + | ||
| 370 | + | // InputPopupSurface is the generated binding for zwp_input_popup_surface_v2 version 1. | |
| 371 | + | type InputPopupSurface struct { | |
| 372 | + | wl.BaseProxy | |
| 373 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 374 | + | // handlers while another goroutine dispatches events. | |
| 375 | + | handlersMu sync.Mutex | |
| 376 | + | onTextInputRectangle []func(x int32, y int32, width int32, height int32) | |
| 377 | + | } | |
| 378 | + | ||
| 379 | + | // NewInputPopupSurface returns an unbound InputPopupSurface. | |
| 380 | + | func NewInputPopupSurface(ctx *wl.Context) *InputPopupSurface { | |
| 381 | + | obj := &InputPopupSurface{} | |
| 382 | + | obj.SetContext(ctx) | |
| 383 | + | ctx.Register(obj) | |
| 384 | + | return obj | |
| 385 | + | } | |
| 386 | + | func (o *InputPopupSurface) Destroy() error { | |
| 387 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_input_popup_surface_v2.destroy", Destructor: true}); err != nil { | |
| 388 | + | return err | |
| 389 | + | } | |
| 390 | + | return nil | |
| 391 | + | } | |
| 392 | + | ||
| 393 | + | // OnTextInputRectangle registers a handler for the text_input_rectangle event. | |
| 394 | + | // | |
| 395 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 396 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 397 | + | func (o *InputPopupSurface) OnTextInputRectangle(handler func(x int32, y int32, width int32, height int32)) { | |
| 398 | + | if handler == nil { | |
| 399 | + | return | |
| 400 | + | } | |
| 401 | + | o.handlersMu.Lock() | |
| 402 | + | defer o.handlersMu.Unlock() | |
| 403 | + | o.onTextInputRectangle = append(o.onTextInputRectangle, handler) | |
| 404 | + | } | |
| 405 | + | ||
| 406 | + | // handlersForTextInputRectangle returns the handlers registered for text_input_rectangle, taken | |
| 407 | + | // under the lock so a handler may register another handler while events are | |
| 408 | + | // being dispatched. | |
| 409 | + | func (o *InputPopupSurface) handlersForTextInputRectangle() []func(x int32, y int32, width int32, height int32) { | |
| 410 | + | o.handlersMu.Lock() | |
| 411 | + | defer o.handlersMu.Unlock() | |
| 412 | + | return o.onTextInputRectangle | |
| 413 | + | } | |
| 414 | + | ||
| 415 | + | // EventSignature returns the declared event argument types in wire order. | |
| 416 | + | func (o *InputPopupSurface) EventSignature(opcode uint16) (string, bool) { | |
| 417 | + | switch opcode { | |
| 418 | + | case 0: | |
| 419 | + | return "int,int,int,int,", true | |
| 420 | + | default: | |
| 421 | + | return "", false | |
| 422 | + | } | |
| 423 | + | } | |
| 424 | + | ||
| 425 | + | // Dispatch decodes one event on zwp_input_popup_surface_v2 and calls the registered handlers. | |
| 426 | + | func (o *InputPopupSurface) Dispatch(event *wl.Event) { | |
| 427 | + | switch event.Opcode { | |
| 428 | + | case 0: // text_input_rectangle | |
| 429 | + | x := event.Int32() | |
| 430 | + | y := event.Int32() | |
| 431 | + | width := event.Int32() | |
| 432 | + | height := event.Int32() | |
| 433 | + | ||
| 434 | + | for i, handler := range o.handlersForTextInputRectangle() { | |
| 435 | + | _ = i | |
| 436 | + | handler(x, y, width, height) | |
| 437 | + | } | |
| 438 | + | default: | |
| 439 | + | } | |
| 440 | + | } | |
| 441 | + | ||
| 442 | + | // InputMethodKeyboardGrabInterface is the protocol interface name. | |
| 443 | + | const InputMethodKeyboardGrabInterface = "zwp_input_method_keyboard_grab_v2" | |
| 444 | + | ||
| 445 | + | // InputMethodKeyboardGrab is the generated binding for zwp_input_method_keyboard_grab_v2 version 1. | |
| 446 | + | type InputMethodKeyboardGrab struct { | |
| 447 | + | wl.BaseProxy | |
| 448 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 449 | + | // handlers while another goroutine dispatches events. | |
| 450 | + | handlersMu sync.Mutex | |
| 451 | + | onKeymap []func(format uint32, fd *wl.OwnedFD, size uint32) | |
| 452 | + | onKey []func(serial uint32, time uint32, key uint32, state uint32) | |
| 453 | + | onModifiers []func(serial uint32, modsDepressed uint32, modsLatched uint32, modsLocked uint32, group uint32) | |
| 454 | + | onRepeatInfo []func(rate int32, delay int32) | |
| 455 | + | } | |
| 456 | + | ||
| 457 | + | // NewInputMethodKeyboardGrab returns an unbound InputMethodKeyboardGrab. | |
| 458 | + | func NewInputMethodKeyboardGrab(ctx *wl.Context) *InputMethodKeyboardGrab { | |
| 459 | + | obj := &InputMethodKeyboardGrab{} | |
| 460 | + | obj.SetContext(ctx) | |
| 461 | + | ctx.Register(obj) | |
| 462 | + | return obj | |
| 463 | + | } | |
| 464 | + | ||
| 465 | + | // release the grab object | |
| 466 | + | func (o *InputMethodKeyboardGrab) Release() error { | |
| 467 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_input_method_keyboard_grab_v2.release", Destructor: true}); err != nil { | |
| 468 | + | return err | |
| 469 | + | } | |
| 470 | + | return nil | |
| 471 | + | } | |
| 472 | + | ||
| 473 | + | // OnKeymap registers a handler for the keymap event. | |
| 474 | + | // | |
| 475 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 476 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 477 | + | func (o *InputMethodKeyboardGrab) OnKeymap(handler func(format uint32, fd *wl.OwnedFD, size uint32)) { | |
| 478 | + | if handler == nil { | |
| 479 | + | return | |
| 480 | + | } | |
| 481 | + | o.handlersMu.Lock() | |
| 482 | + | defer o.handlersMu.Unlock() | |
| 483 | + | o.onKeymap = append(o.onKeymap, handler) | |
| 484 | + | } | |
| 485 | + | ||
| 486 | + | // handlersForKeymap returns the handlers registered for keymap, taken | |
| 487 | + | // under the lock so a handler may register another handler while events are | |
| 488 | + | // being dispatched. | |
| 489 | + | func (o *InputMethodKeyboardGrab) handlersForKeymap() []func(format uint32, fd *wl.OwnedFD, size uint32) { | |
| 490 | + | o.handlersMu.Lock() | |
| 491 | + | defer o.handlersMu.Unlock() | |
| 492 | + | return o.onKeymap | |
| 493 | + | } | |
| 494 | + | ||
| 495 | + | // OnKey registers a handler for the key event. | |
| 496 | + | // | |
| 497 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 498 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 499 | + | func (o *InputMethodKeyboardGrab) OnKey(handler func(serial uint32, time uint32, key uint32, state uint32)) { | |
| 500 | + | if handler == nil { | |
| 501 | + | return | |
| 502 | + | } | |
| 503 | + | o.handlersMu.Lock() | |
| 504 | + | defer o.handlersMu.Unlock() | |
| 505 | + | o.onKey = append(o.onKey, handler) | |
| 506 | + | } | |
| 507 | + | ||
| 508 | + | // handlersForKey returns the handlers registered for key, taken | |
| 509 | + | // under the lock so a handler may register another handler while events are | |
| 510 | + | // being dispatched. | |
| 511 | + | func (o *InputMethodKeyboardGrab) handlersForKey() []func(serial uint32, time uint32, key uint32, state uint32) { | |
| 512 | + | o.handlersMu.Lock() | |
| 513 | + | defer o.handlersMu.Unlock() | |
| 514 | + | return o.onKey | |
| 515 | + | } | |
| 516 | + | ||
| 517 | + | // OnModifiers registers a handler for the modifiers event. | |
| 518 | + | // | |
| 519 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 520 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 521 | + | func (o *InputMethodKeyboardGrab) OnModifiers(handler func(serial uint32, modsDepressed uint32, modsLatched uint32, modsLocked uint32, group uint32)) { | |
| 522 | + | if handler == nil { | |
| 523 | + | return | |
| 524 | + | } | |
| 525 | + | o.handlersMu.Lock() | |
| 526 | + | defer o.handlersMu.Unlock() | |
| 527 | + | o.onModifiers = append(o.onModifiers, handler) | |
| 528 | + | } | |
| 529 | + | ||
| 530 | + | // handlersForModifiers returns the handlers registered for modifiers, taken | |
| 531 | + | // under the lock so a handler may register another handler while events are | |
| 532 | + | // being dispatched. | |
| 533 | + | func (o *InputMethodKeyboardGrab) handlersForModifiers() []func(serial uint32, modsDepressed uint32, modsLatched uint32, modsLocked uint32, group uint32) { | |
| 534 | + | o.handlersMu.Lock() | |
| 535 | + | defer o.handlersMu.Unlock() | |
| 536 | + | return o.onModifiers | |
| 537 | + | } | |
| 538 | + | ||
| 539 | + | // OnRepeatInfo registers a handler for the repeat_info event. | |
| 540 | + | // | |
| 541 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 542 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 543 | + | func (o *InputMethodKeyboardGrab) OnRepeatInfo(handler func(rate int32, delay int32)) { | |
| 544 | + | if handler == nil { | |
| 545 | + | return | |
| 546 | + | } | |
| 547 | + | o.handlersMu.Lock() | |
| 548 | + | defer o.handlersMu.Unlock() | |
| 549 | + | o.onRepeatInfo = append(o.onRepeatInfo, handler) | |
| 550 | + | } | |
| 551 | + | ||
| 552 | + | // handlersForRepeatInfo returns the handlers registered for repeat_info, taken | |
| 553 | + | // under the lock so a handler may register another handler while events are | |
| 554 | + | // being dispatched. | |
| 555 | + | func (o *InputMethodKeyboardGrab) handlersForRepeatInfo() []func(rate int32, delay int32) { | |
| 556 | + | o.handlersMu.Lock() | |
| 557 | + | defer o.handlersMu.Unlock() | |
| 558 | + | return o.onRepeatInfo | |
| 559 | + | } | |
| 560 | + | ||
| 561 | + | // EventSignature returns the declared event argument types in wire order. | |
| 562 | + | func (o *InputMethodKeyboardGrab) EventSignature(opcode uint16) (string, bool) { | |
| 563 | + | switch opcode { | |
| 564 | + | case 0: | |
| 565 | + | return "uint,fd,uint,", true | |
| 566 | + | case 1: | |
| 567 | + | return "uint,uint,uint,uint,", true | |
| 568 | + | case 2: | |
| 569 | + | return "uint,uint,uint,uint,uint,", true | |
| 570 | + | case 3: | |
| 571 | + | return "int,int,", true | |
| 572 | + | default: | |
| 573 | + | return "", false | |
| 574 | + | } | |
| 575 | + | } | |
| 576 | + | ||
| 577 | + | // Dispatch decodes one event on zwp_input_method_keyboard_grab_v2 and calls the registered handlers. | |
| 578 | + | func (o *InputMethodKeyboardGrab) Dispatch(event *wl.Event) { | |
| 579 | + | switch event.Opcode { | |
| 580 | + | case 0: // keymap | |
| 581 | + | format := event.Uint32() | |
| 582 | + | fd := event.FD() | |
| 583 | + | size := event.Uint32() | |
| 584 | + | ownedfd := fd | |
| 585 | + | defer ownedfd.Close() | |
| 586 | + | ||
| 587 | + | for i, handler := range o.handlersForKeymap() { | |
| 588 | + | if i > 0 { | |
| 589 | + | fd = nil | |
| 590 | + | } | |
| 591 | + | handler(format, fd, size) | |
| 592 | + | } | |
| 593 | + | case 1: // key | |
| 594 | + | serial := event.Uint32() | |
| 595 | + | time := event.Uint32() | |
| 596 | + | key := event.Uint32() | |
| 597 | + | state := event.Uint32() | |
| 598 | + | ||
| 599 | + | for i, handler := range o.handlersForKey() { | |
| 600 | + | _ = i | |
| 601 | + | handler(serial, time, key, state) | |
| 602 | + | } | |
| 603 | + | case 2: // modifiers | |
| 604 | + | serial := event.Uint32() | |
| 605 | + | modsDepressed := event.Uint32() | |
| 606 | + | modsLatched := event.Uint32() | |
| 607 | + | modsLocked := event.Uint32() | |
| 608 | + | group := event.Uint32() | |
| 609 | + | ||
| 610 | + | for i, handler := range o.handlersForModifiers() { | |
| 611 | + | _ = i | |
| 612 | + | handler(serial, modsDepressed, modsLatched, modsLocked, group) | |
| 613 | + | } | |
| 614 | + | case 3: // repeat_info | |
| 615 | + | rate := event.Int32() | |
| 616 | + | delay := event.Int32() | |
| 617 | + | ||
| 618 | + | for i, handler := range o.handlersForRepeatInfo() { | |
| 619 | + | _ = i | |
| 620 | + | handler(rate, delay) | |
| 621 | + | } | |
| 622 | + | default: | |
| 623 | + | } | |
| 624 | + | } | |
| 625 | + | ||
| 626 | + | // InputMethodManagerInterface is the protocol interface name. | |
| 627 | + | const InputMethodManagerInterface = "zwp_input_method_manager_v2" | |
| 628 | + | ||
| 629 | + | // InputMethodManager is the generated binding for zwp_input_method_manager_v2 version 1. | |
| 630 | + | type InputMethodManager struct { | |
| 631 | + | wl.BaseProxy | |
| 632 | + | } | |
| 633 | + | ||
| 634 | + | // NewInputMethodManager returns an unbound InputMethodManager. | |
| 635 | + | func NewInputMethodManager(ctx *wl.Context) *InputMethodManager { | |
| 636 | + | obj := &InputMethodManager{} | |
| 637 | + | obj.SetContext(ctx) | |
| 638 | + | ctx.Register(obj) | |
| 639 | + | return obj | |
| 640 | + | } | |
| 641 | + | ||
| 642 | + | // Request a new input zwp_input_method_v2 object associated with a given seat. | |
| 643 | + | func (o *InputMethodManager) GetInputMethod(seat *cross_wl_seat.Seat) (*InputMethod, error) { | |
| 644 | + | var arg0 wl.Object | |
| 645 | + | if seat != nil { | |
| 646 | + | arg0 = seat | |
| 647 | + | } | |
| 648 | + | child := &InputMethod{} | |
| 649 | + | child.SetContext(o.Context()) | |
| 650 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_input_method_manager_v2.get_input_method", Child: child}, wl.ArgObject(arg0), wl.ArgObject(child)); err != nil { | |
| 651 | + | return nil, err | |
| 652 | + | } | |
| 653 | + | return child, nil | |
| 654 | + | } | |
| 655 | + | ||
| 656 | + | // Destroys the zwp_input_method_manager_v2 object. The zwp_input_method_v2 objects originating from it remain valid. | |
| 657 | + | func (o *InputMethodManager) Destroy() error { | |
| 658 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_input_method_manager_v2.destroy", Destructor: true}); err != nil { | |
| 659 | + | return err | |
| 660 | + | } | |
| 661 | + | return nil | |
| 662 | + | } | |
| 663 | + | ||
| 664 | + | // EventSignature returns the declared event argument types in wire order. | |
| 665 | + | func (o *InputMethodManager) EventSignature(opcode uint16) (string, bool) { | |
| 666 | + | switch opcode { | |
| 667 | + | default: | |
| 668 | + | return "", false | |
| 669 | + | } | |
| 670 | + | } | |
| 671 | + | ||
| 672 | + | // Dispatch decodes one event on zwp_input_method_manager_v2 and calls the registered handlers. | |
| 673 | + | func (o *InputMethodManager) Dispatch(event *wl.Event) { | |
| 674 | + | switch event.Opcode { | |
| 675 | + | default: | |
| 676 | + | } | |
| 677 | + | } | |
A protocol/kdeserverdecoration/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package kdeserverdecoration | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p kdeserverdecoration -o server-decoration_generated.go -import wl_surface=github.com/bnema/wlturbo/protocol/core server-decoration.xml | |
A protocol/kdeserverdecoration/server-decoration.xml +85 -0
| @@ -0,0 +1,85 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="server_decoration"> | |
| 3 | + | <copyright><![CDATA[ | |
| 4 | + | SPDX-FileCopyrightText: 2015 Martin Gräßlin | |
| 5 | + | ||
| 6 | + | SPDX-License-Identifier: LGPL-2.1-or-later | |
| 7 | + | ]]></copyright> | |
| 8 | + | <interface name="org_kde_kwin_server_decoration_manager" version="1"> | |
| 9 | + | <description summary="Server side window decoration manager"> | |
| 10 | + | This interface allows to coordinate whether the server should create | |
| 11 | + | a server-side window decoration around a wl_surface representing a | |
| 12 | + | shell surface (wl_shell_surface or similar). By announcing support | |
| 13 | + | for this interface the server indicates that it supports server | |
| 14 | + | side decorations. | |
| 15 | + | ||
| 16 | + | Use in conjunction with zxdg_decoration_manager_v1 is undefined. | |
| 17 | + | </description> | |
| 18 | + | <request name="create"> | |
| 19 | + | <description summary="Create a server-side decoration object for a given surface"> | |
| 20 | + | When a client creates a server-side decoration object it indicates | |
| 21 | + | that it supports the protocol. The client is supposed to tell the | |
| 22 | + | server whether it wants server-side decorations or will provide | |
| 23 | + | client-side decorations. | |
| 24 | + | ||
| 25 | + | If the client does not create a server-side decoration object for | |
| 26 | + | a surface the server interprets this as lack of support for this | |
| 27 | + | protocol and considers it as client-side decorated. Nevertheless a | |
| 28 | + | client-side decorated surface should use this protocol to indicate | |
| 29 | + | to the server that it does not want a server-side deco. | |
| 30 | + | </description> | |
| 31 | + | <arg name="id" type="new_id" interface="org_kde_kwin_server_decoration"/> | |
| 32 | + | <arg name="surface" type="object" interface="wl_surface"/> | |
| 33 | + | </request> | |
| 34 | + | <enum name="mode"> | |
| 35 | + | <description summary="Possible values to use in request_mode and the event mode."/> | |
| 36 | + | <entry name="None" value="0" summary="Undecorated: The surface is not decorated at all, neither server nor client-side. An example is a popup surface which should not be decorated."/> | |
| 37 | + | <entry name="Client" value="1" summary="Client-side decoration: The decoration is part of the surface and the client."/> | |
| 38 | + | <entry name="Server" value="2" summary="Server-side decoration: The server embeds the surface into a decoration frame."/> | |
| 39 | + | </enum> | |
| 40 | + | <event name="default_mode"> | |
| 41 | + | <description summary="The default mode used on the server"> | |
| 42 | + | This event is emitted directly after binding the interface. It contains | |
| 43 | + | the default mode for the decoration. When a new server decoration object | |
| 44 | + | is created this new object will be in the default mode until the first | |
| 45 | + | request_mode is requested. | |
| 46 | + | ||
| 47 | + | The server may change the default mode at any time. | |
| 48 | + | </description> | |
| 49 | + | <arg name="mode" type="uint" summary="The default decoration mode applied to newly created server decorations."/> | |
| 50 | + | </event> | |
| 51 | + | </interface> | |
| 52 | + | <interface name="org_kde_kwin_server_decoration" version="1"> | |
| 53 | + | <request name="release" type="destructor"> | |
| 54 | + | <description summary="release the server decoration object"/> | |
| 55 | + | </request> | |
| 56 | + | <enum name="mode"> | |
| 57 | + | <description summary="Possible values to use in request_mode and the event mode."/> | |
| 58 | + | <entry name="None" value="0" summary="Undecorated: The surface is not decorated at all, neither server nor client-side. An example is a popup surface which should not be decorated."/> | |
| 59 | + | <entry name="Client" value="1" summary="Client-side decoration: The decoration is part of the surface and the client."/> | |
| 60 | + | <entry name="Server" value="2" summary="Server-side decoration: The server embeds the surface into a decoration frame."/> | |
| 61 | + | </enum> | |
| 62 | + | <request name="request_mode"> | |
| 63 | + | <description summary="The decoration mode the surface wants to use."/> | |
| 64 | + | <arg name="mode" type="uint" summary="The mode this surface wants to use."/> | |
| 65 | + | </request> | |
| 66 | + | <event name="mode"> | |
| 67 | + | <description summary="The new decoration mode applied by the server"> | |
| 68 | + | This event is emitted directly after the decoration is created and | |
| 69 | + | represents the base decoration policy by the server. E.g. a server | |
| 70 | + | which wants all surfaces to be client-side decorated will send Client, | |
| 71 | + | a server which wants server-side decoration will send Server. | |
| 72 | + | ||
| 73 | + | The client can request a different mode through the decoration request. | |
| 74 | + | The server will acknowledge this by another event with the same mode. So | |
| 75 | + | even if a server prefers server-side decoration it's possible to force a | |
| 76 | + | client-side decoration. | |
| 77 | + | ||
| 78 | + | The server may emit this event at any time. In this case the client can | |
| 79 | + | again request a different mode. It's the responsibility of the server to | |
| 80 | + | prevent a feedback loop. | |
| 81 | + | </description> | |
| 82 | + | <arg name="mode" type="uint" summary="The decoration mode applied to the surface by the server."/> | |
| 83 | + | </event> | |
| 84 | + | </interface> | |
| 85 | + | </protocol> | |
A protocol/kdeserverdecoration/server-decoration_generated.go +197 -0
| @@ -0,0 +1,197 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: server_decoration | |
| 3 | + | // Source: server-decoration.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // SPDX-FileCopyrightText: 2015 Martin Gräßlin | |
| 7 | + | // | |
| 8 | + | // SPDX-License-Identifier: LGPL-2.1-or-later | |
| 9 | + | ||
| 10 | + | package kdeserverdecoration | |
| 11 | + | ||
| 12 | + | import ( | |
| 13 | + | "sync" | |
| 14 | + | ||
| 15 | + | cross_wl_surface "github.com/bnema/wlturbo/protocol/core" | |
| 16 | + | "github.com/bnema/wlturbo/wl" | |
| 17 | + | ) | |
| 18 | + | ||
| 19 | + | // ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_NONE is the mode None value. | |
| 20 | + | const ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_NONE = 0 | |
| 21 | + | ||
| 22 | + | // ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT is the mode Client value. | |
| 23 | + | const ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT = 1 | |
| 24 | + | ||
| 25 | + | // ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER is the mode Server value. | |
| 26 | + | const ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER = 2 | |
| 27 | + | ||
| 28 | + | // ORG_KDE_KWIN_SERVER_DECORATION_MODE_NONE is the mode None value. | |
| 29 | + | const ORG_KDE_KWIN_SERVER_DECORATION_MODE_NONE = 0 | |
| 30 | + | ||
| 31 | + | // ORG_KDE_KWIN_SERVER_DECORATION_MODE_CLIENT is the mode Client value. | |
| 32 | + | const ORG_KDE_KWIN_SERVER_DECORATION_MODE_CLIENT = 1 | |
| 33 | + | ||
| 34 | + | // ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER is the mode Server value. | |
| 35 | + | const ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER = 2 | |
| 36 | + | ||
| 37 | + | // OrgKdeKwinServerDecorationManagerInterface is the protocol interface name. | |
| 38 | + | const OrgKdeKwinServerDecorationManagerInterface = "org_kde_kwin_server_decoration_manager" | |
| 39 | + | ||
| 40 | + | // OrgKdeKwinServerDecorationManager is the generated binding for org_kde_kwin_server_decoration_manager version 1. | |
| 41 | + | type OrgKdeKwinServerDecorationManager struct { | |
| 42 | + | wl.BaseProxy | |
| 43 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 44 | + | // handlers while another goroutine dispatches events. | |
| 45 | + | handlersMu sync.Mutex | |
| 46 | + | onDefaultMode []func(mode uint32) | |
| 47 | + | } | |
| 48 | + | ||
| 49 | + | // NewOrgKdeKwinServerDecorationManager returns an unbound OrgKdeKwinServerDecorationManager. | |
| 50 | + | func NewOrgKdeKwinServerDecorationManager(ctx *wl.Context) *OrgKdeKwinServerDecorationManager { | |
| 51 | + | obj := &OrgKdeKwinServerDecorationManager{} | |
| 52 | + | obj.SetContext(ctx) | |
| 53 | + | ctx.Register(obj) | |
| 54 | + | return obj | |
| 55 | + | } | |
| 56 | + | ||
| 57 | + | // When a client creates a server-side decoration object it indicates that it supports the protocol. The client is supposed to tell the server whether it wants server-side decorations or will provide client-side decorations. If the client does not create a server-side decoration object for a surface the server interprets this as lack of support for this protocol and considers it as client-side decorated. Nevertheless a client-side decorated surface should use this protocol to indicate to the server that it does not want a server-side deco. | |
| 58 | + | func (o *OrgKdeKwinServerDecorationManager) Create(surface *cross_wl_surface.Surface) (*OrgKdeKwinServerDecoration, error) { | |
| 59 | + | var arg1 wl.Object | |
| 60 | + | if surface != nil { | |
| 61 | + | arg1 = surface | |
| 62 | + | } | |
| 63 | + | child := &OrgKdeKwinServerDecoration{} | |
| 64 | + | child.SetContext(o.Context()) | |
| 65 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "org_kde_kwin_server_decoration_manager.create", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 66 | + | return nil, err | |
| 67 | + | } | |
| 68 | + | return child, nil | |
| 69 | + | } | |
| 70 | + | ||
| 71 | + | // OnDefaultMode registers a handler for the default_mode event. | |
| 72 | + | // | |
| 73 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 74 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 75 | + | func (o *OrgKdeKwinServerDecorationManager) OnDefaultMode(handler func(mode uint32)) { | |
| 76 | + | if handler == nil { | |
| 77 | + | return | |
| 78 | + | } | |
| 79 | + | o.handlersMu.Lock() | |
| 80 | + | defer o.handlersMu.Unlock() | |
| 81 | + | o.onDefaultMode = append(o.onDefaultMode, handler) | |
| 82 | + | } | |
| 83 | + | ||
| 84 | + | // handlersForDefaultMode returns the handlers registered for default_mode, taken | |
| 85 | + | // under the lock so a handler may register another handler while events are | |
| 86 | + | // being dispatched. | |
| 87 | + | func (o *OrgKdeKwinServerDecorationManager) handlersForDefaultMode() []func(mode uint32) { | |
| 88 | + | o.handlersMu.Lock() | |
| 89 | + | defer o.handlersMu.Unlock() | |
| 90 | + | return o.onDefaultMode | |
| 91 | + | } | |
| 92 | + | ||
| 93 | + | // EventSignature returns the declared event argument types in wire order. | |
| 94 | + | func (o *OrgKdeKwinServerDecorationManager) EventSignature(opcode uint16) (string, bool) { | |
| 95 | + | switch opcode { | |
| 96 | + | case 0: | |
| 97 | + | return "uint,", true | |
| 98 | + | default: | |
| 99 | + | return "", false | |
| 100 | + | } | |
| 101 | + | } | |
| 102 | + | ||
| 103 | + | // Dispatch decodes one event on org_kde_kwin_server_decoration_manager and calls the registered handlers. | |
| 104 | + | func (o *OrgKdeKwinServerDecorationManager) Dispatch(event *wl.Event) { | |
| 105 | + | switch event.Opcode { | |
| 106 | + | case 0: // default_mode | |
| 107 | + | mode := event.Uint32() | |
| 108 | + | ||
| 109 | + | for i, handler := range o.handlersForDefaultMode() { | |
| 110 | + | _ = i | |
| 111 | + | handler(mode) | |
| 112 | + | } | |
| 113 | + | default: | |
| 114 | + | } | |
| 115 | + | } | |
| 116 | + | ||
| 117 | + | // OrgKdeKwinServerDecorationInterface is the protocol interface name. | |
| 118 | + | const OrgKdeKwinServerDecorationInterface = "org_kde_kwin_server_decoration" | |
| 119 | + | ||
| 120 | + | // OrgKdeKwinServerDecoration is the generated binding for org_kde_kwin_server_decoration version 1. | |
| 121 | + | type OrgKdeKwinServerDecoration struct { | |
| 122 | + | wl.BaseProxy | |
| 123 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 124 | + | // handlers while another goroutine dispatches events. | |
| 125 | + | handlersMu sync.Mutex | |
| 126 | + | onMode []func(mode uint32) | |
| 127 | + | } | |
| 128 | + | ||
| 129 | + | // NewOrgKdeKwinServerDecoration returns an unbound OrgKdeKwinServerDecoration. | |
| 130 | + | func NewOrgKdeKwinServerDecoration(ctx *wl.Context) *OrgKdeKwinServerDecoration { | |
| 131 | + | obj := &OrgKdeKwinServerDecoration{} | |
| 132 | + | obj.SetContext(ctx) | |
| 133 | + | ctx.Register(obj) | |
| 134 | + | return obj | |
| 135 | + | } | |
| 136 | + | ||
| 137 | + | // release the server decoration object | |
| 138 | + | func (o *OrgKdeKwinServerDecoration) Release() error { | |
| 139 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "org_kde_kwin_server_decoration.release", Destructor: true}); err != nil { | |
| 140 | + | return err | |
| 141 | + | } | |
| 142 | + | return nil | |
| 143 | + | } | |
| 144 | + | ||
| 145 | + | // The decoration mode the surface wants to use. | |
| 146 | + | func (o *OrgKdeKwinServerDecoration) RequestMode(mode uint32) error { | |
| 147 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "org_kde_kwin_server_decoration.request_mode"}, wl.ArgUint(mode)); err != nil { | |
| 148 | + | return err | |
| 149 | + | } | |
| 150 | + | return nil | |
| 151 | + | } | |
| 152 | + | ||
| 153 | + | // OnMode registers a handler for the mode event. | |
| 154 | + | // | |
| 155 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 156 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 157 | + | func (o *OrgKdeKwinServerDecoration) OnMode(handler func(mode uint32)) { | |
| 158 | + | if handler == nil { | |
| 159 | + | return | |
| 160 | + | } | |
| 161 | + | o.handlersMu.Lock() | |
| 162 | + | defer o.handlersMu.Unlock() | |
| 163 | + | o.onMode = append(o.onMode, handler) | |
| 164 | + | } | |
| 165 | + | ||
| 166 | + | // handlersForMode returns the handlers registered for mode, taken | |
| 167 | + | // under the lock so a handler may register another handler while events are | |
| 168 | + | // being dispatched. | |
| 169 | + | func (o *OrgKdeKwinServerDecoration) handlersForMode() []func(mode uint32) { | |
| 170 | + | o.handlersMu.Lock() | |
| 171 | + | defer o.handlersMu.Unlock() | |
| 172 | + | return o.onMode | |
| 173 | + | } | |
| 174 | + | ||
| 175 | + | // EventSignature returns the declared event argument types in wire order. | |
| 176 | + | func (o *OrgKdeKwinServerDecoration) EventSignature(opcode uint16) (string, bool) { | |
| 177 | + | switch opcode { | |
| 178 | + | case 0: | |
| 179 | + | return "uint,", true | |
| 180 | + | default: | |
| 181 | + | return "", false | |
| 182 | + | } | |
| 183 | + | } | |
| 184 | + | ||
| 185 | + | // Dispatch decodes one event on org_kde_kwin_server_decoration and calls the registered handlers. | |
| 186 | + | func (o *OrgKdeKwinServerDecoration) Dispatch(event *wl.Event) { | |
| 187 | + | switch event.Opcode { | |
| 188 | + | case 0: // mode | |
| 189 | + | mode := event.Uint32() | |
| 190 | + | ||
| 191 | + | for i, handler := range o.handlersForMode() { | |
| 192 | + | _ = i | |
| 193 | + | handler(mode) | |
| 194 | + | } | |
| 195 | + | default: | |
| 196 | + | } | |
| 197 | + | } | |
A protocol/layershell/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package layershell | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p layershell -o wlr-layer-shell-unstable-v1_generated.go -import wl_surface=github.com/bnema/wlturbo/protocol/core -import wl_output=github.com/bnema/wlturbo/protocol/core -import xdg_popup=github.com/bnema/wlturbo/protocol/xdgshell wlr-layer-shell-unstable-v1.xml | |
A protocol/layershell/wlr-layer-shell-unstable-v1.xml +407 -0
| @@ -0,0 +1,407 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="wlr_layer_shell_unstable_v1"> | |
| 3 | + | <copyright> | |
| 4 | + | Copyright © 2017 Drew DeVault | |
| 5 | + | ||
| 6 | + | Permission to use, copy, modify, distribute, and sell this | |
| 7 | + | software and its documentation for any purpose is hereby granted | |
| 8 | + | without fee, provided that the above copyright notice appear in | |
| 9 | + | all copies and that both that copyright notice and this permission | |
| 10 | + | notice appear in supporting documentation, and that the name of | |
| 11 | + | the copyright holders not be used in advertising or publicity | |
| 12 | + | pertaining to distribution of the software without specific, | |
| 13 | + | written prior permission. The copyright holders make no | |
| 14 | + | representations about the suitability of this software for any | |
| 15 | + | purpose. It is provided "as is" without express or implied | |
| 16 | + | warranty. | |
| 17 | + | ||
| 18 | + | THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
| 19 | + | SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| 20 | + | FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| 21 | + | SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 22 | + | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
| 23 | + | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
| 24 | + | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| 25 | + | THIS SOFTWARE. | |
| 26 | + | </copyright> | |
| 27 | + | ||
| 28 | + | <interface name="zwlr_layer_shell_v1" version="5"> | |
| 29 | + | <description summary="create surfaces that are layers of the desktop"> | |
| 30 | + | Clients can use this interface to assign the surface_layer role to | |
| 31 | + | wl_surfaces. Such surfaces are assigned to a "layer" of the output and | |
| 32 | + | rendered with a defined z-depth respective to each other. They may also be | |
| 33 | + | anchored to the edges and corners of a screen and specify input handling | |
| 34 | + | semantics. This interface should be suitable for the implementation of | |
| 35 | + | many desktop shell components, and a broad number of other applications | |
| 36 | + | that interact with the desktop. | |
| 37 | + | </description> | |
| 38 | + | ||
| 39 | + | <request name="get_layer_surface"> | |
| 40 | + | <description summary="create a layer_surface from a surface"> | |
| 41 | + | Create a layer surface for an existing surface. This assigns the role of | |
| 42 | + | layer_surface, or raises a protocol error if another role is already | |
| 43 | + | assigned. | |
| 44 | + | ||
| 45 | + | Creating a layer surface from a wl_surface which has a buffer attached | |
| 46 | + | or committed is a client error, and any attempts by a client to attach | |
| 47 | + | or manipulate a buffer prior to the first layer_surface.configure call | |
| 48 | + | must also be treated as errors. | |
| 49 | + | ||
| 50 | + | After creating a layer_surface object and setting it up, the client | |
| 51 | + | must perform an initial commit without any buffer attached. | |
| 52 | + | The compositor will reply with a layer_surface.configure event. | |
| 53 | + | The client must acknowledge it and is then allowed to attach a buffer | |
| 54 | + | to map the surface. | |
| 55 | + | ||
| 56 | + | You may pass NULL for output to allow the compositor to decide which | |
| 57 | + | output to use. Generally this will be the one that the user most | |
| 58 | + | recently interacted with. | |
| 59 | + | ||
| 60 | + | Clients can specify a namespace that defines the purpose of the layer | |
| 61 | + | surface. | |
| 62 | + | </description> | |
| 63 | + | <arg name="id" type="new_id" interface="zwlr_layer_surface_v1"/> | |
| 64 | + | <arg name="surface" type="object" interface="wl_surface"/> | |
| 65 | + | <arg name="output" type="object" interface="wl_output" allow-null="true"/> | |
| 66 | + | <arg name="layer" type="uint" enum="layer" summary="layer to add this surface to"/> | |
| 67 | + | <arg name="namespace" type="string" summary="namespace for the layer surface"/> | |
| 68 | + | </request> | |
| 69 | + | ||
| 70 | + | <enum name="error"> | |
| 71 | + | <entry name="role" value="0" summary="wl_surface has another role"/> | |
| 72 | + | <entry name="invalid_layer" value="1" summary="layer value is invalid"/> | |
| 73 | + | <entry name="already_constructed" value="2" summary="wl_surface has a buffer attached or committed"/> | |
| 74 | + | </enum> | |
| 75 | + | ||
| 76 | + | <enum name="layer"> | |
| 77 | + | <description summary="available layers for surfaces"> | |
| 78 | + | These values indicate which layers a surface can be rendered in. They | |
| 79 | + | are ordered by z depth, bottom-most first. Traditional shell surfaces | |
| 80 | + | will typically be rendered between the bottom and top layers. | |
| 81 | + | Fullscreen shell surfaces are typically rendered at the top layer. | |
| 82 | + | Multiple surfaces can share a single layer, and ordering within a | |
| 83 | + | single layer is undefined. | |
| 84 | + | </description> | |
| 85 | + | ||
| 86 | + | <entry name="background" value="0"/> | |
| 87 | + | <entry name="bottom" value="1"/> | |
| 88 | + | <entry name="top" value="2"/> | |
| 89 | + | <entry name="overlay" value="3"/> | |
| 90 | + | </enum> | |
| 91 | + | ||
| 92 | + | <!-- Version 3 additions --> | |
| 93 | + | ||
| 94 | + | <request name="destroy" type="destructor" since="3"> | |
| 95 | + | <description summary="destroy the layer_shell object"> | |
| 96 | + | This request indicates that the client will not use the layer_shell | |
| 97 | + | object any more. Objects that have been created through this instance | |
| 98 | + | are not affected. | |
| 99 | + | </description> | |
| 100 | + | </request> | |
| 101 | + | </interface> | |
| 102 | + | ||
| 103 | + | <interface name="zwlr_layer_surface_v1" version="5"> | |
| 104 | + | <description summary="layer metadata interface"> | |
| 105 | + | An interface that may be implemented by a wl_surface, for surfaces that | |
| 106 | + | are designed to be rendered as a layer of a stacked desktop-like | |
| 107 | + | environment. | |
| 108 | + | ||
| 109 | + | Layer surface state (layer, size, anchor, exclusive zone, | |
| 110 | + | margin, interactivity) is double-buffered, and will be applied at the | |
| 111 | + | time wl_surface.commit of the corresponding wl_surface is called. | |
| 112 | + | ||
| 113 | + | Attaching a null buffer to a layer surface unmaps it. | |
| 114 | + | ||
| 115 | + | Unmapping a layer_surface means that the surface cannot be shown by the | |
| 116 | + | compositor until it is explicitly mapped again. The layer_surface | |
| 117 | + | returns to the state it had right after layer_shell.get_layer_surface. | |
| 118 | + | The client can re-map the surface by performing a commit without any | |
| 119 | + | buffer attached, waiting for a configure event and handling it as usual. | |
| 120 | + | </description> | |
| 121 | + | ||
| 122 | + | <request name="set_size"> | |
| 123 | + | <description summary="sets the size of the surface"> | |
| 124 | + | Sets the size of the surface in surface-local coordinates. The | |
| 125 | + | compositor will display the surface centered with respect to its | |
| 126 | + | anchors. | |
| 127 | + | ||
| 128 | + | If you pass 0 for either value, the compositor will assign it and | |
| 129 | + | inform you of the assignment in the configure event. You must set your | |
| 130 | + | anchor to opposite edges in the dimensions you omit; not doing so is a | |
| 131 | + | protocol error. Both values are 0 by default. | |
| 132 | + | ||
| 133 | + | Size is double-buffered, see wl_surface.commit. | |
| 134 | + | </description> | |
| 135 | + | <arg name="width" type="uint"/> | |
| 136 | + | <arg name="height" type="uint"/> | |
| 137 | + | </request> | |
| 138 | + | ||
| 139 | + | <request name="set_anchor"> | |
| 140 | + | <description summary="configures the anchor point of the surface"> | |
| 141 | + | Requests that the compositor anchor the surface to the specified edges | |
| 142 | + | and corners. If two orthogonal edges are specified (e.g. 'top' and | |
| 143 | + | 'left'), then the anchor point will be the intersection of the edges | |
| 144 | + | (e.g. the top left corner of the output); otherwise the anchor point | |
| 145 | + | will be centered on that edge, or in the center if none is specified. | |
| 146 | + | ||
| 147 | + | Anchor is double-buffered, see wl_surface.commit. | |
| 148 | + | </description> | |
| 149 | + | <arg name="anchor" type="uint" enum="anchor"/> | |
| 150 | + | </request> | |
| 151 | + | ||
| 152 | + | <request name="set_exclusive_zone"> | |
| 153 | + | <description summary="configures the exclusive geometry of this surface"> | |
| 154 | + | Requests that the compositor avoids occluding an area with other | |
| 155 | + | surfaces. The compositor's use of this information is | |
| 156 | + | implementation-dependent - do not assume that this region will not | |
| 157 | + | actually be occluded. | |
| 158 | + | ||
| 159 | + | A positive value is only meaningful if the surface is anchored to one | |
| 160 | + | edge or an edge and both perpendicular edges. If the surface is not | |
| 161 | + | anchored, anchored to only two perpendicular edges (a corner), anchored | |
| 162 | + | to only two parallel edges or anchored to all edges, a positive value | |
| 163 | + | will be treated the same as zero. | |
| 164 | + | ||
| 165 | + | A positive zone is the distance from the edge in surface-local | |
| 166 | + | coordinates to consider exclusive. | |
| 167 | + | ||
| 168 | + | Surfaces that do not wish to have an exclusive zone may instead specify | |
| 169 | + | how they should interact with surfaces that do. If set to zero, the | |
| 170 | + | surface indicates that it would like to be moved to avoid occluding | |
| 171 | + | surfaces with a positive exclusive zone. If set to -1, the surface | |
| 172 | + | indicates that it would not like to be moved to accommodate for other | |
| 173 | + | surfaces, and the compositor should extend it all the way to the edges | |
| 174 | + | it is anchored to. | |
| 175 | + | ||
| 176 | + | For example, a panel might set its exclusive zone to 10, so that | |
| 177 | + | maximized shell surfaces are not shown on top of it. A notification | |
| 178 | + | might set its exclusive zone to 0, so that it is moved to avoid | |
| 179 | + | occluding the panel, but shell surfaces are shown underneath it. A | |
| 180 | + | wallpaper or lock screen might set their exclusive zone to -1, so that | |
| 181 | + | they stretch below or over the panel. | |
| 182 | + | ||
| 183 | + | The default value is 0. | |
| 184 | + | ||
| 185 | + | Exclusive zone is double-buffered, see wl_surface.commit. | |
| 186 | + | </description> | |
| 187 | + | <arg name="zone" type="int"/> | |
| 188 | + | </request> | |
| 189 | + | ||
| 190 | + | <request name="set_margin"> | |
| 191 | + | <description summary="sets a margin from the anchor point"> | |
| 192 | + | Requests that the surface be placed some distance away from the anchor | |
| 193 | + | point on the output, in surface-local coordinates. Setting this value | |
| 194 | + | for edges you are not anchored to has no effect. | |
| 195 | + | ||
| 196 | + | The exclusive zone includes the margin. | |
| 197 | + | ||
| 198 | + | Margin is double-buffered, see wl_surface.commit. | |
| 199 | + | </description> | |
| 200 | + | <arg name="top" type="int"/> | |
| 201 | + | <arg name="right" type="int"/> | |
| 202 | + | <arg name="bottom" type="int"/> | |
| 203 | + | <arg name="left" type="int"/> | |
| 204 | + | </request> | |
| 205 | + | ||
| 206 | + | <enum name="keyboard_interactivity"> | |
| 207 | + | <description summary="types of keyboard interaction possible for a layer shell surface"> | |
| 208 | + | Types of keyboard interaction possible for layer shell surfaces. The | |
| 209 | + | rationale for this is twofold: (1) some applications are not interested | |
| 210 | + | in keyboard events and not allowing them to be focused can improve the | |
| 211 | + | desktop experience; (2) some applications will want to take exclusive | |
| 212 | + | keyboard focus. | |
| 213 | + | </description> | |
| 214 | + | ||
| 215 | + | <entry name="none" value="0"> | |
| 216 | + | <description summary="no keyboard focus is possible"> | |
| 217 | + | This value indicates that this surface is not interested in keyboard | |
| 218 | + | events and the compositor should never assign it the keyboard focus. | |
| 219 | + | ||
| 220 | + | This is the default value, set for newly created layer shell surfaces. | |
| 221 | + | ||
| 222 | + | This is useful for e.g. desktop widgets that display information or | |
| 223 | + | only have interaction with non-keyboard input devices. | |
| 224 | + | </description> | |
| 225 | + | </entry> | |
| 226 | + | <entry name="exclusive" value="1"> | |
| 227 | + | <description summary="request exclusive keyboard focus"> | |
| 228 | + | Request exclusive keyboard focus if this surface is above the shell surface layer. | |
| 229 | + | ||
| 230 | + | For the top and overlay layers, the seat will always give | |
| 231 | + | exclusive keyboard focus to the top-most layer which has keyboard | |
| 232 | + | interactivity set to exclusive. If this layer contains multiple | |
| 233 | + | surfaces with keyboard interactivity set to exclusive, the compositor | |
| 234 | + | determines the one receiving keyboard events in an implementation- | |
| 235 | + | defined manner. In this case, no guarantee is made when this surface | |
| 236 | + | will receive keyboard focus (if ever). | |
| 237 | + | ||
| 238 | + | For the bottom and background layers, the compositor is allowed to use | |
| 239 | + | normal focus semantics. | |
| 240 | + | ||
| 241 | + | This setting is mainly intended for applications that need to ensure | |
| 242 | + | they receive all keyboard events, such as a lock screen or a password | |
| 243 | + | prompt. | |
| 244 | + | </description> | |
| 245 | + | </entry> | |
| 246 | + | <entry name="on_demand" value="2" since="4"> | |
| 247 | + | <description summary="request regular keyboard focus semantics"> | |
| 248 | + | This requests the compositor to allow this surface to be focused and | |
| 249 | + | unfocused by the user in an implementation-defined manner. The user | |
| 250 | + | should be able to unfocus this surface even regardless of the layer | |
| 251 | + | it is on. | |
| 252 | + | ||
| 253 | + | Typically, the compositor will want to use its normal mechanism to | |
| 254 | + | manage keyboard focus between layer shell surfaces with this setting | |
| 255 | + | and regular toplevels on the desktop layer (e.g. click to focus). | |
| 256 | + | Nevertheless, it is possible for a compositor to require a special | |
| 257 | + | interaction to focus or unfocus layer shell surfaces (e.g. requiring | |
| 258 | + | a click even if focus follows the mouse normally, or providing a | |
| 259 | + | keybinding to switch focus between layers). | |
| 260 | + | ||
| 261 | + | This setting is mainly intended for desktop shell components (e.g. | |
| 262 | + | panels) that allow keyboard interaction. Using this option can allow | |
| 263 | + | implementing a desktop shell that can be fully usable without the | |
| 264 | + | mouse. | |
| 265 | + | </description> | |
| 266 | + | </entry> | |
| 267 | + | </enum> | |
| 268 | + | ||
| 269 | + | <request name="set_keyboard_interactivity"> | |
| 270 | + | <description summary="requests keyboard events"> | |
| 271 | + | Set how keyboard events are delivered to this surface. By default, | |
| 272 | + | layer shell surfaces do not receive keyboard events; this request can | |
| 273 | + | be used to change this. | |
| 274 | + | ||
| 275 | + | This setting is inherited by child surfaces set by the get_popup | |
| 276 | + | request. | |
| 277 | + | ||
| 278 | + | Layer surfaces receive pointer, touch, and tablet events normally. If | |
| 279 | + | you do not want to receive them, set the input region on your surface | |
| 280 | + | to an empty region. | |
| 281 | + | ||
| 282 | + | Keyboard interactivity is double-buffered, see wl_surface.commit. | |
| 283 | + | </description> | |
| 284 | + | <arg name="keyboard_interactivity" type="uint" enum="keyboard_interactivity"/> | |
| 285 | + | </request> | |
| 286 | + | ||
| 287 | + | <request name="get_popup"> | |
| 288 | + | <description summary="assign this layer_surface as an xdg_popup parent"> | |
| 289 | + | This assigns an xdg_popup's parent to this layer_surface. This popup | |
| 290 | + | should have been created via xdg_surface::get_popup with the parent set | |
| 291 | + | to NULL, and this request must be invoked before committing the popup's | |
| 292 | + | initial state. | |
| 293 | + | ||
| 294 | + | See the documentation of xdg_popup for more details about what an | |
| 295 | + | xdg_popup is and how it is used. | |
| 296 | + | </description> | |
| 297 | + | <arg name="popup" type="object" interface="xdg_popup"/> | |
| 298 | + | </request> | |
| 299 | + | ||
| 300 | + | <request name="ack_configure"> | |
| 301 | + | <description summary="ack a configure event"> | |
| 302 | + | When a configure event is received, if a client commits the | |
| 303 | + | surface in response to the configure event, then the client | |
| 304 | + | must make an ack_configure request sometime before the commit | |
| 305 | + | request, passing along the serial of the configure event. | |
| 306 | + | ||
| 307 | + | If the client receives multiple configure events before it | |
| 308 | + | can respond to one, it only has to ack the last configure event. | |
| 309 | + | ||
| 310 | + | A client is not required to commit immediately after sending | |
| 311 | + | an ack_configure request - it may even ack_configure several times | |
| 312 | + | before its next surface commit. | |
| 313 | + | ||
| 314 | + | A client may send multiple ack_configure requests before committing, but | |
| 315 | + | only the last request sent before a commit indicates which configure | |
| 316 | + | event the client really is responding to. | |
| 317 | + | </description> | |
| 318 | + | <arg name="serial" type="uint" summary="the serial from the configure event"/> | |
| 319 | + | </request> | |
| 320 | + | ||
| 321 | + | <request name="destroy" type="destructor"> | |
| 322 | + | <description summary="destroy the layer_surface"> | |
| 323 | + | This request destroys the layer surface. | |
| 324 | + | </description> | |
| 325 | + | </request> | |
| 326 | + | ||
| 327 | + | <event name="configure"> | |
| 328 | + | <description summary="suggest a surface change"> | |
| 329 | + | The configure event asks the client to resize its surface. | |
| 330 | + | ||
| 331 | + | Clients should arrange their surface for the new states, and then send | |
| 332 | + | an ack_configure request with the serial sent in this configure event at | |
| 333 | + | some point before committing the new surface. | |
| 334 | + | ||
| 335 | + | The client is free to dismiss all but the last configure event it | |
| 336 | + | received. | |
| 337 | + | ||
| 338 | + | The width and height arguments specify the size of the window in | |
| 339 | + | surface-local coordinates. | |
| 340 | + | ||
| 341 | + | The size is a hint, in the sense that the client is free to ignore it if | |
| 342 | + | it doesn't resize, pick a smaller size (to satisfy aspect ratio or | |
| 343 | + | resize in steps of NxM pixels). If the client picks a smaller size and | |
| 344 | + | is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the | |
| 345 | + | surface will be centered on this axis. | |
| 346 | + | ||
| 347 | + | If the width or height arguments are zero, it means the client should | |
| 348 | + | decide its own window dimension. | |
| 349 | + | </description> | |
| 350 | + | <arg name="serial" type="uint"/> | |
| 351 | + | <arg name="width" type="uint"/> | |
| 352 | + | <arg name="height" type="uint"/> | |
| 353 | + | </event> | |
| 354 | + | ||
| 355 | + | <event name="closed"> | |
| 356 | + | <description summary="surface should be closed"> | |
| 357 | + | The closed event is sent by the compositor when the surface will no | |
| 358 | + | longer be shown. The output may have been destroyed or the user may | |
| 359 | + | have asked for it to be removed. Further changes to the surface will be | |
| 360 | + | ignored. The client should destroy the resource after receiving this | |
| 361 | + | event, and create a new surface if they so choose. | |
| 362 | + | </description> | |
| 363 | + | </event> | |
| 364 | + | ||
| 365 | + | <enum name="error"> | |
| 366 | + | <entry name="invalid_surface_state" value="0" summary="provided surface state is invalid"/> | |
| 367 | + | <entry name="invalid_size" value="1" summary="size is invalid"/> | |
| 368 | + | <entry name="invalid_anchor" value="2" summary="anchor bitfield is invalid"/> | |
| 369 | + | <entry name="invalid_keyboard_interactivity" value="3" summary="keyboard interactivity is invalid"/> | |
| 370 | + | <entry name="invalid_exclusive_edge" value="4" summary="exclusive edge is invalid given the surface anchors"/> | |
| 371 | + | </enum> | |
| 372 | + | ||
| 373 | + | <enum name="anchor" bitfield="true"> | |
| 374 | + | <entry name="top" value="1" summary="the top edge of the anchor rectangle"/> | |
| 375 | + | <entry name="bottom" value="2" summary="the bottom edge of the anchor rectangle"/> | |
| 376 | + | <entry name="left" value="4" summary="the left edge of the anchor rectangle"/> | |
| 377 | + | <entry name="right" value="8" summary="the right edge of the anchor rectangle"/> | |
| 378 | + | </enum> | |
| 379 | + | ||
| 380 | + | <!-- Version 2 additions --> | |
| 381 | + | ||
| 382 | + | <request name="set_layer" since="2"> | |
| 383 | + | <description summary="change the layer of the surface"> | |
| 384 | + | Change the layer that the surface is rendered on. | |
| 385 | + | ||
| 386 | + | Layer is double-buffered, see wl_surface.commit. | |
| 387 | + | </description> | |
| 388 | + | <arg name="layer" type="uint" enum="zwlr_layer_shell_v1.layer" summary="layer to move this surface to"/> | |
| 389 | + | </request> | |
| 390 | + | ||
| 391 | + | <!-- Version 5 additions --> | |
| 392 | + | ||
| 393 | + | <request name="set_exclusive_edge" since="5"> | |
| 394 | + | <description summary="set the edge the exclusive zone will be applied to"> | |
| 395 | + | Requests an edge for the exclusive zone to apply. The exclusive | |
| 396 | + | edge will be automatically deduced from anchor points when possible, | |
| 397 | + | but when the surface is anchored to a corner, it will be necessary | |
| 398 | + | to set it explicitly to disambiguate, as it is not possible to deduce | |
| 399 | + | which one of the two corner edges should be used. | |
| 400 | + | ||
| 401 | + | The edge must be one the surface is anchored to, otherwise the | |
| 402 | + | invalid_exclusive_edge protocol error will be raised. | |
| 403 | + | </description> | |
| 404 | + | <arg name="edge" type="uint" enum="anchor"/> | |
| 405 | + | </request> | |
| 406 | + | </interface> | |
| 407 | + | </protocol> | |
A protocol/layershell/wlr-layer-shell-unstable-v1_generated.go +335 -0
| @@ -0,0 +1,335 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: wlr_layer_shell_unstable_v1 | |
| 3 | + | // Source: wlr-layer-shell-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2017 Drew DeVault | |
| 7 | + | // | |
| 8 | + | // Permission to use, copy, modify, distribute, and sell this | |
| 9 | + | // software and its documentation for any purpose is hereby granted | |
| 10 | + | // without fee, provided that the above copyright notice appear in | |
| 11 | + | // all copies and that both that copyright notice and this permission | |
| 12 | + | // notice appear in supporting documentation, and that the name of | |
| 13 | + | // the copyright holders not be used in advertising or publicity | |
| 14 | + | // pertaining to distribution of the software without specific, | |
| 15 | + | // written prior permission. The copyright holders make no | |
| 16 | + | // representations about the suitability of this software for any | |
| 17 | + | // purpose. It is provided "as is" without express or implied | |
| 18 | + | // warranty. | |
| 19 | + | // | |
| 20 | + | // THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
| 21 | + | // SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| 22 | + | // FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| 23 | + | // SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 24 | + | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
| 25 | + | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
| 26 | + | // ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| 27 | + | // THIS SOFTWARE. | |
| 28 | + | ||
| 29 | + | package layershell | |
| 30 | + | ||
| 31 | + | import ( | |
| 32 | + | "sync" | |
| 33 | + | ||
| 34 | + | cross_wl_output "github.com/bnema/wlturbo/protocol/core" | |
| 35 | + | cross_wl_surface "github.com/bnema/wlturbo/protocol/core" | |
| 36 | + | cross_xdg_popup "github.com/bnema/wlturbo/protocol/xdgshell" | |
| 37 | + | "github.com/bnema/wlturbo/wl" | |
| 38 | + | ) | |
| 39 | + | ||
| 40 | + | // ERROR_ROLE is the error role value. | |
| 41 | + | const ERROR_ROLE = 0 | |
| 42 | + | ||
| 43 | + | // ERROR_INVALID_LAYER is the error invalid_layer value. | |
| 44 | + | const ERROR_INVALID_LAYER = 1 | |
| 45 | + | ||
| 46 | + | // ERROR_ALREADY_CONSTRUCTED is the error already_constructed value. | |
| 47 | + | const ERROR_ALREADY_CONSTRUCTED = 2 | |
| 48 | + | ||
| 49 | + | // LAYER_BACKGROUND is the layer background value. | |
| 50 | + | const LAYER_BACKGROUND = 0 | |
| 51 | + | ||
| 52 | + | // LAYER_BOTTOM is the layer bottom value. | |
| 53 | + | const LAYER_BOTTOM = 1 | |
| 54 | + | ||
| 55 | + | // LAYER_TOP is the layer top value. | |
| 56 | + | const LAYER_TOP = 2 | |
| 57 | + | ||
| 58 | + | // LAYER_OVERLAY is the layer overlay value. | |
| 59 | + | const LAYER_OVERLAY = 3 | |
| 60 | + | ||
| 61 | + | // KEYBOARD_INTERACTIVITY_NONE is the keyboard_interactivity none value. | |
| 62 | + | const KEYBOARD_INTERACTIVITY_NONE = 0 | |
| 63 | + | ||
| 64 | + | // KEYBOARD_INTERACTIVITY_EXCLUSIVE is the keyboard_interactivity exclusive value. | |
| 65 | + | const KEYBOARD_INTERACTIVITY_EXCLUSIVE = 1 | |
| 66 | + | ||
| 67 | + | // KEYBOARD_INTERACTIVITY_ON_DEMAND is the keyboard_interactivity on_demand value. | |
| 68 | + | const KEYBOARD_INTERACTIVITY_ON_DEMAND = 2 | |
| 69 | + | ||
| 70 | + | // ERROR_INVALID_SURFACE_STATE is the error invalid_surface_state value. | |
| 71 | + | const ERROR_INVALID_SURFACE_STATE = 0 | |
| 72 | + | ||
| 73 | + | // ERROR_INVALID_SIZE is the error invalid_size value. | |
| 74 | + | const ERROR_INVALID_SIZE = 1 | |
| 75 | + | ||
| 76 | + | // ERROR_INVALID_ANCHOR is the error invalid_anchor value. | |
| 77 | + | const ERROR_INVALID_ANCHOR = 2 | |
| 78 | + | ||
| 79 | + | // ERROR_INVALID_KEYBOARD_INTERACTIVITY is the error invalid_keyboard_interactivity value. | |
| 80 | + | const ERROR_INVALID_KEYBOARD_INTERACTIVITY = 3 | |
| 81 | + | ||
| 82 | + | // ERROR_INVALID_EXCLUSIVE_EDGE is the error invalid_exclusive_edge value. | |
| 83 | + | const ERROR_INVALID_EXCLUSIVE_EDGE = 4 | |
| 84 | + | ||
| 85 | + | // ANCHOR_TOP is the anchor top value. | |
| 86 | + | const ANCHOR_TOP = 1 | |
| 87 | + | ||
| 88 | + | // ANCHOR_BOTTOM is the anchor bottom value. | |
| 89 | + | const ANCHOR_BOTTOM = 2 | |
| 90 | + | ||
| 91 | + | // ANCHOR_LEFT is the anchor left value. | |
| 92 | + | const ANCHOR_LEFT = 4 | |
| 93 | + | ||
| 94 | + | // ANCHOR_RIGHT is the anchor right value. | |
| 95 | + | const ANCHOR_RIGHT = 8 | |
| 96 | + | ||
| 97 | + | // LayerShellInterface is the protocol interface name. | |
| 98 | + | const LayerShellInterface = "zwlr_layer_shell_v1" | |
| 99 | + | ||
| 100 | + | // LayerShell is the generated binding for zwlr_layer_shell_v1 version 5. | |
| 101 | + | type LayerShell struct { | |
| 102 | + | wl.BaseProxy | |
| 103 | + | } | |
| 104 | + | ||
| 105 | + | // NewLayerShell returns an unbound LayerShell. | |
| 106 | + | func NewLayerShell(ctx *wl.Context) *LayerShell { | |
| 107 | + | obj := &LayerShell{} | |
| 108 | + | obj.SetContext(ctx) | |
| 109 | + | ctx.Register(obj) | |
| 110 | + | return obj | |
| 111 | + | } | |
| 112 | + | ||
| 113 | + | // Create a layer surface for an existing surface. This assigns the role of layer_surface, or raises a protocol error if another role is already assigned. Creating a layer surface from a wl_surface which has a buffer attached or committed is a client error, and any attempts by a client to attach or manipulate a buffer prior to the first layer_surface.configure call must also be treated as errors. After creating a layer_surface object and setting it up, the client must perform an initial commit without any buffer attached. The compositor will reply with a layer_surface.configure event. The client must acknowledge it and is then allowed to attach a buffer to map the surface. You may pass NULL for output to allow the compositor to decide which output to use. Generally this will be the one that the user most recently interacted with. Clients can specify a namespace that defines the purpose of the layer surface. | |
| 114 | + | func (o *LayerShell) GetLayerSurface(surface *cross_wl_surface.Surface, output *cross_wl_output.Output, layer uint32, namespace string) (*LayerSurface, error) { | |
| 115 | + | var arg1 wl.Object | |
| 116 | + | if surface != nil { | |
| 117 | + | arg1 = surface | |
| 118 | + | } | |
| 119 | + | var arg2 wl.Object | |
| 120 | + | if output != nil { | |
| 121 | + | arg2 = output | |
| 122 | + | } | |
| 123 | + | child := &LayerSurface{} | |
| 124 | + | child.SetContext(o.Context()) | |
| 125 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_layer_shell_v1.get_layer_surface", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1), wl.ArgObject(arg2), wl.ArgUint(layer), wl.ArgString(namespace)); err != nil { | |
| 126 | + | return nil, err | |
| 127 | + | } | |
| 128 | + | return child, nil | |
| 129 | + | } | |
| 130 | + | ||
| 131 | + | // This request indicates that the client will not use the layer_shell object any more. Objects that have been created through this instance are not affected. | |
| 132 | + | func (o *LayerShell) Destroy() error { | |
| 133 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwlr_layer_shell_v1.destroy", Since: 3, Destructor: true}); err != nil { | |
| 134 | + | return err | |
| 135 | + | } | |
| 136 | + | return nil | |
| 137 | + | } | |
| 138 | + | ||
| 139 | + | // EventSignature returns the declared event argument types in wire order. | |
| 140 | + | func (o *LayerShell) EventSignature(opcode uint16) (string, bool) { | |
| 141 | + | switch opcode { | |
| 142 | + | default: | |
| 143 | + | return "", false | |
| 144 | + | } | |
| 145 | + | } | |
| 146 | + | ||
| 147 | + | // Dispatch decodes one event on zwlr_layer_shell_v1 and calls the registered handlers. | |
| 148 | + | func (o *LayerShell) Dispatch(event *wl.Event) { | |
| 149 | + | switch event.Opcode { | |
| 150 | + | default: | |
| 151 | + | } | |
| 152 | + | } | |
| 153 | + | ||
| 154 | + | // LayerSurfaceInterface is the protocol interface name. | |
| 155 | + | const LayerSurfaceInterface = "zwlr_layer_surface_v1" | |
| 156 | + | ||
| 157 | + | // LayerSurface is the generated binding for zwlr_layer_surface_v1 version 5. | |
| 158 | + | type LayerSurface struct { | |
| 159 | + | wl.BaseProxy | |
| 160 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 161 | + | // handlers while another goroutine dispatches events. | |
| 162 | + | handlersMu sync.Mutex | |
| 163 | + | onConfigure []func(serial uint32, width uint32, height uint32) | |
| 164 | + | onClosed []func() | |
| 165 | + | } | |
| 166 | + | ||
| 167 | + | // NewLayerSurface returns an unbound LayerSurface. | |
| 168 | + | func NewLayerSurface(ctx *wl.Context) *LayerSurface { | |
| 169 | + | obj := &LayerSurface{} | |
| 170 | + | obj.SetContext(ctx) | |
| 171 | + | ctx.Register(obj) | |
| 172 | + | return obj | |
| 173 | + | } | |
| 174 | + | ||
| 175 | + | // Sets the size of the surface in surface-local coordinates. The compositor will display the surface centered with respect to its anchors. If you pass 0 for either value, the compositor will assign it and inform you of the assignment in the configure event. You must set your anchor to opposite edges in the dimensions you omit; not doing so is a protocol error. Both values are 0 by default. Size is double-buffered, see wl_surface.commit. | |
| 176 | + | func (o *LayerSurface) SetSize(width uint32, height uint32) error { | |
| 177 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_layer_surface_v1.set_size"}, wl.ArgUint(width), wl.ArgUint(height)); err != nil { | |
| 178 | + | return err | |
| 179 | + | } | |
| 180 | + | return nil | |
| 181 | + | } | |
| 182 | + | ||
| 183 | + | // Requests that the compositor anchor the surface to the specified edges and corners. If two orthogonal edges are specified (e.g. 'top' and 'left'), then the anchor point will be the intersection of the edges (e.g. the top left corner of the output); otherwise the anchor point will be centered on that edge, or in the center if none is specified. Anchor is double-buffered, see wl_surface.commit. | |
| 184 | + | func (o *LayerSurface) SetAnchor(anchor uint32) error { | |
| 185 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwlr_layer_surface_v1.set_anchor"}, wl.ArgUint(anchor)); err != nil { | |
| 186 | + | return err | |
| 187 | + | } | |
| 188 | + | return nil | |
| 189 | + | } | |
| 190 | + | ||
| 191 | + | // Requests that the compositor avoids occluding an area with other surfaces. The compositor's use of this information is implementation-dependent - do not assume that this region will not actually be occluded. A positive value is only meaningful if the surface is anchored to one edge or an edge and both perpendicular edges. If the surface is not anchored, anchored to only two perpendicular edges (a corner), anchored to only two parallel edges or anchored to all edges, a positive value will be treated the same as zero. A positive zone is the distance from the edge in surface-local coordinates to consider exclusive. Surfaces that do not wish to have an exclusive zone may instead specify how they should interact with surfaces that do. If set to zero, the surface indicates that it would like to be moved to avoid occluding surfaces with a positive exclusive zone. If set to -1, the surface indicates that it would not like to be moved to accommodate for other surfaces, and the compositor should extend it all the way to the edges it is anchored to. For example, a panel might set its exclusive zone to 10, so that maximized shell surfaces are not shown on top of it. A notification might set its exclusive zone to 0, so that it is moved to avoid occluding the panel, but shell surfaces are shown underneath it. A wallpaper or lock screen might set their exclusive zone to -1, so that they stretch below or over the panel. The default value is 0. Exclusive zone is double-buffered, see wl_surface.commit. | |
| 192 | + | func (o *LayerSurface) SetExclusiveZone(zone int32) error { | |
| 193 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwlr_layer_surface_v1.set_exclusive_zone"}, wl.ArgInt(zone)); err != nil { | |
| 194 | + | return err | |
| 195 | + | } | |
| 196 | + | return nil | |
| 197 | + | } | |
| 198 | + | ||
| 199 | + | // Requests that the surface be placed some distance away from the anchor point on the output, in surface-local coordinates. Setting this value for edges you are not anchored to has no effect. The exclusive zone includes the margin. Margin is double-buffered, see wl_surface.commit. | |
| 200 | + | func (o *LayerSurface) SetMargin(top int32, right int32, bottom int32, left int32) error { | |
| 201 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "zwlr_layer_surface_v1.set_margin"}, wl.ArgInt(top), wl.ArgInt(right), wl.ArgInt(bottom), wl.ArgInt(left)); err != nil { | |
| 202 | + | return err | |
| 203 | + | } | |
| 204 | + | return nil | |
| 205 | + | } | |
| 206 | + | ||
| 207 | + | // Set how keyboard events are delivered to this surface. By default, layer shell surfaces do not receive keyboard events; this request can be used to change this. This setting is inherited by child surfaces set by the get_popup request. Layer surfaces receive pointer, touch, and tablet events normally. If you do not want to receive them, set the input region on your surface to an empty region. Keyboard interactivity is double-buffered, see wl_surface.commit. | |
| 208 | + | func (o *LayerSurface) SetKeyboardInteractivity(keyboardInteractivity uint32) error { | |
| 209 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 4, Name: "zwlr_layer_surface_v1.set_keyboard_interactivity"}, wl.ArgUint(keyboardInteractivity)); err != nil { | |
| 210 | + | return err | |
| 211 | + | } | |
| 212 | + | return nil | |
| 213 | + | } | |
| 214 | + | ||
| 215 | + | // This assigns an xdg_popup's parent to this layer_surface. This popup should have been created via xdg_surface::get_popup with the parent set to NULL, and this request must be invoked before committing the popup's initial state. See the documentation of xdg_popup for more details about what an xdg_popup is and how it is used. | |
| 216 | + | func (o *LayerSurface) GetPopup(popup *cross_xdg_popup.XdgPopup) error { | |
| 217 | + | var arg0 wl.Object | |
| 218 | + | if popup != nil { | |
| 219 | + | arg0 = popup | |
| 220 | + | } | |
| 221 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 5, Name: "zwlr_layer_surface_v1.get_popup"}, wl.ArgObject(arg0)); err != nil { | |
| 222 | + | return err | |
| 223 | + | } | |
| 224 | + | return nil | |
| 225 | + | } | |
| 226 | + | ||
| 227 | + | // When a configure event is received, if a client commits the surface in response to the configure event, then the client must make an ack_configure request sometime before the commit request, passing along the serial of the configure event. If the client receives multiple configure events before it can respond to one, it only has to ack the last configure event. A client is not required to commit immediately after sending an ack_configure request - it may even ack_configure several times before its next surface commit. A client may send multiple ack_configure requests before committing, but only the last request sent before a commit indicates which configure event the client really is responding to. | |
| 228 | + | func (o *LayerSurface) AckConfigure(serial uint32) error { | |
| 229 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 6, Name: "zwlr_layer_surface_v1.ack_configure"}, wl.ArgUint(serial)); err != nil { | |
| 230 | + | return err | |
| 231 | + | } | |
| 232 | + | return nil | |
| 233 | + | } | |
| 234 | + | ||
| 235 | + | // This request destroys the layer surface. | |
| 236 | + | func (o *LayerSurface) Destroy() error { | |
| 237 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 7, Name: "zwlr_layer_surface_v1.destroy", Destructor: true}); err != nil { | |
| 238 | + | return err | |
| 239 | + | } | |
| 240 | + | return nil | |
| 241 | + | } | |
| 242 | + | ||
| 243 | + | // Change the layer that the surface is rendered on. Layer is double-buffered, see wl_surface.commit. | |
| 244 | + | func (o *LayerSurface) SetLayer(layer uint32) error { | |
| 245 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 8, Name: "zwlr_layer_surface_v1.set_layer", Since: 2}, wl.ArgUint(layer)); err != nil { | |
| 246 | + | return err | |
| 247 | + | } | |
| 248 | + | return nil | |
| 249 | + | } | |
| 250 | + | ||
| 251 | + | // Requests an edge for the exclusive zone to apply. The exclusive edge will be automatically deduced from anchor points when possible, but when the surface is anchored to a corner, it will be necessary to set it explicitly to disambiguate, as it is not possible to deduce which one of the two corner edges should be used. The edge must be one the surface is anchored to, otherwise the invalid_exclusive_edge protocol error will be raised. | |
| 252 | + | func (o *LayerSurface) SetExclusiveEdge(edge uint32) error { | |
| 253 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 9, Name: "zwlr_layer_surface_v1.set_exclusive_edge", Since: 5}, wl.ArgUint(edge)); err != nil { | |
| 254 | + | return err | |
| 255 | + | } | |
| 256 | + | return nil | |
| 257 | + | } | |
| 258 | + | ||
| 259 | + | // OnConfigure registers a handler for the configure event. | |
| 260 | + | // | |
| 261 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 262 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 263 | + | func (o *LayerSurface) OnConfigure(handler func(serial uint32, width uint32, height uint32)) { | |
| 264 | + | if handler == nil { | |
| 265 | + | return | |
| 266 | + | } | |
| 267 | + | o.handlersMu.Lock() | |
| 268 | + | defer o.handlersMu.Unlock() | |
| 269 | + | o.onConfigure = append(o.onConfigure, handler) | |
| 270 | + | } | |
| 271 | + | ||
| 272 | + | // handlersForConfigure returns the handlers registered for configure, taken | |
| 273 | + | // under the lock so a handler may register another handler while events are | |
| 274 | + | // being dispatched. | |
| 275 | + | func (o *LayerSurface) handlersForConfigure() []func(serial uint32, width uint32, height uint32) { | |
| 276 | + | o.handlersMu.Lock() | |
| 277 | + | defer o.handlersMu.Unlock() | |
| 278 | + | return o.onConfigure | |
| 279 | + | } | |
| 280 | + | ||
| 281 | + | // OnClosed registers a handler for the closed event. | |
| 282 | + | // | |
| 283 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 284 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 285 | + | func (o *LayerSurface) OnClosed(handler func()) { | |
| 286 | + | if handler == nil { | |
| 287 | + | return | |
| 288 | + | } | |
| 289 | + | o.handlersMu.Lock() | |
| 290 | + | defer o.handlersMu.Unlock() | |
| 291 | + | o.onClosed = append(o.onClosed, handler) | |
| 292 | + | } | |
| 293 | + | ||
| 294 | + | // handlersForClosed returns the handlers registered for closed, taken | |
| 295 | + | // under the lock so a handler may register another handler while events are | |
| 296 | + | // being dispatched. | |
| 297 | + | func (o *LayerSurface) handlersForClosed() []func() { | |
| 298 | + | o.handlersMu.Lock() | |
| 299 | + | defer o.handlersMu.Unlock() | |
| 300 | + | return o.onClosed | |
| 301 | + | } | |
| 302 | + | ||
| 303 | + | // EventSignature returns the declared event argument types in wire order. | |
| 304 | + | func (o *LayerSurface) EventSignature(opcode uint16) (string, bool) { | |
| 305 | + | switch opcode { | |
| 306 | + | case 0: | |
| 307 | + | return "uint,uint,uint,", true | |
| 308 | + | case 1: | |
| 309 | + | return "", true | |
| 310 | + | default: | |
| 311 | + | return "", false | |
| 312 | + | } | |
| 313 | + | } | |
| 314 | + | ||
| 315 | + | // Dispatch decodes one event on zwlr_layer_surface_v1 and calls the registered handlers. | |
| 316 | + | func (o *LayerSurface) Dispatch(event *wl.Event) { | |
| 317 | + | switch event.Opcode { | |
| 318 | + | case 0: // configure | |
| 319 | + | serial := event.Uint32() | |
| 320 | + | width := event.Uint32() | |
| 321 | + | height := event.Uint32() | |
| 322 | + | ||
| 323 | + | for i, handler := range o.handlersForConfigure() { | |
| 324 | + | _ = i | |
| 325 | + | handler(serial, width, height) | |
| 326 | + | } | |
| 327 | + | case 1: // closed | |
| 328 | + | ||
| 329 | + | for i, handler := range o.handlersForClosed() { | |
| 330 | + | _ = i | |
| 331 | + | handler() | |
| 332 | + | } | |
| 333 | + | default: | |
| 334 | + | } | |
| 335 | + | } | |
M protocol/linuxdmabuf/linux-dmabuf-v1_generated.go +32 -10
| @@ -2,6 +2,28 @@ | |||
| 2 | 2 | // Protocol: linux_dmabuf_v1 | |
| 3 | 3 | // Source: linux-dmabuf-v1.xml | |
| 4 | 4 | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2014, 2015 Collabora, Ltd. | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 5 | 27 | package linuxdmabuf | |
| 6 | 28 | ||
| 7 | 29 | import ( | |
| @@ -77,7 +99,7 @@ func NewLinuxDmabuf(ctx *wl.Context) *LinuxDmabuf { | |||
| 77 | 99 | ||
| 78 | 100 | // Objects created through this interface, especially wl_buffers, will remain valid. | |
| 79 | 101 | func (o *LinuxDmabuf) Destroy() error { | |
| 80 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_linux_dmabuf_v1.destroy", Destructor: true}); err != nil { | |
| 102 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_linux_dmabuf_v1.destroy", Destructor: true}); err != nil { | |
| 81 | 103 | return err | |
| 82 | 104 | } | |
| 83 | 105 | return nil | |
| @@ -87,7 +109,7 @@ func (o *LinuxDmabuf) Destroy() error { | |||
| 87 | 109 | func (o *LinuxDmabuf) CreateParams() (*LinuxBufferParams, error) { | |
| 88 | 110 | child := &LinuxBufferParams{} | |
| 89 | 111 | child.SetContext(o.Context()) | |
| 90 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_linux_dmabuf_v1.create_params", Child: child}, child); err != nil { | |
| 112 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_linux_dmabuf_v1.create_params", Child: child}, wl.ArgObject(child)); err != nil { | |
| 91 | 113 | return nil, err | |
| 92 | 114 | } | |
| 93 | 115 | return child, nil | |
| @@ -97,7 +119,7 @@ func (o *LinuxDmabuf) CreateParams() (*LinuxBufferParams, error) { | |||
| 97 | 119 | func (o *LinuxDmabuf) GetDefaultFeedback() (*LinuxDmabufFeedback, error) { | |
| 98 | 120 | child := &LinuxDmabufFeedback{} | |
| 99 | 121 | child.SetContext(o.Context()) | |
| 100 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_linux_dmabuf_v1.get_default_feedback", Since: 4, Child: child}, child); err != nil { | |
| 122 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_linux_dmabuf_v1.get_default_feedback", Since: 4, Child: child}, wl.ArgObject(child)); err != nil { | |
| 101 | 123 | return nil, err | |
| 102 | 124 | } | |
| 103 | 125 | return child, nil | |
| @@ -111,7 +133,7 @@ func (o *LinuxDmabuf) GetSurfaceFeedback(surface *cross_wl_surface.Surface) (*Li | |||
| 111 | 133 | } | |
| 112 | 134 | child := &LinuxDmabufFeedback{} | |
| 113 | 135 | child.SetContext(o.Context()) | |
| 114 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "zwp_linux_dmabuf_v1.get_surface_feedback", Since: 4, Child: child}, child, arg1); err != nil { | |
| 136 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "zwp_linux_dmabuf_v1.get_surface_feedback", Since: 4, Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 115 | 137 | return nil, err | |
| 116 | 138 | } | |
| 117 | 139 | return child, nil | |
| @@ -219,7 +241,7 @@ func NewLinuxBufferParams(ctx *wl.Context) *LinuxBufferParams { | |||
| 219 | 241 | ||
| 220 | 242 | // Cleans up the temporary data sent to the server for dmabuf-based wl_buffer creation. | |
| 221 | 243 | func (o *LinuxBufferParams) Destroy() error { | |
| 222 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_linux_buffer_params_v1.destroy", Destructor: true}); err != nil { | |
| 244 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_linux_buffer_params_v1.destroy", Destructor: true}); err != nil { | |
| 223 | 245 | return err | |
| 224 | 246 | } | |
| 225 | 247 | return nil | |
| @@ -227,7 +249,7 @@ func (o *LinuxBufferParams) Destroy() error { | |||
| 227 | 249 | ||
| 228 | 250 | // This request adds one dmabuf to the set in this zwp_linux_buffer_params_v1. The 64-bit unsigned value combined from modifier_hi and modifier_lo is the dmabuf layout modifier. DRM AddFB2 ioctl calls this the fb modifier, which is defined in drm_mode.h of Linux UAPI. This is an opaque token. Drivers use this token to express tiling, compression, etc. driver-specific modifications to the base format defined by the DRM fourcc code. Starting from version 4, the invalid_format protocol error is sent if the format + modifier pair was not advertised as supported. Starting from version 5, the invalid_format protocol error is sent if all planes don't use the same modifier. This request raises the PLANE_IDX error if plane_idx is too large. The error PLANE_SET is raised if attempting to set a plane that was already set. | |
| 229 | 251 | func (o *LinuxBufferParams) Add(fd int, planeIdx uint32, offset uint32, stride uint32, modifierHi uint32, modifierLo uint32) error { | |
| 230 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_linux_buffer_params_v1.add", FDs: []int{fd}}, uintptr(fd), planeIdx, offset, stride, modifierHi, modifierLo); err != nil { | |
| 252 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_linux_buffer_params_v1.add", FDs: []int{fd}}, wl.ArgFD(), wl.ArgUint(planeIdx), wl.ArgUint(offset), wl.ArgUint(stride), wl.ArgUint(modifierHi), wl.ArgUint(modifierLo)); err != nil { | |
| 231 | 253 | return err | |
| 232 | 254 | } | |
| 233 | 255 | return nil | |
| @@ -235,7 +257,7 @@ func (o *LinuxBufferParams) Add(fd int, planeIdx uint32, offset uint32, stride u | |||
| 235 | 257 | ||
| 236 | 258 | // This asks for creation of a wl_buffer from the added dmabuf buffers. The wl_buffer is not created immediately but returned via the 'created' event if the dmabuf sharing succeeds. The sharing may fail at runtime for reasons a client cannot predict, in which case the 'failed' event is triggered. The 'format' argument is a DRM_FORMAT code, as defined by the libdrm's drm_fourcc.h. The Linux kernel's DRM sub-system is the authoritative source on how the format codes should work. The 'flags' is a bitfield of the flags defined in enum "flags". 'y_invert' means that the image needs to be y-flipped. Flag 'interlaced' means that the frame in the buffer is not progressive as usual, but interlaced. An interlaced buffer as supported here must always contain both top and bottom fields. The top field always begins on the first pixel row. The temporal ordering between the two fields is top field first, unless 'bottom_first' is specified. It is undefined whether 'bottom_first' is ignored if 'interlaced' is not set. This protocol does not convey any information about field rate, duration, or timing, other than the relative ordering between the two fields in one buffer. A compositor may have to estimate the intended field rate from the incoming buffer rate. It is undefined whether the time of receiving wl_surface.commit with a new buffer attached, applying the wl_surface state, wl_surface.frame callback trigger, presentation, or any other point in the compositor cycle is used to measure the frame or field times. There is no support for detecting missed or late frames/fields/buffers either, and there is no support whatsoever for cooperating with interlaced compositor output. The composited image quality resulting from the use of interlaced buffers is explicitly undefined. A compositor may use elaborate hardware features or software to deinterlace and create progressive output frames from a sequence of interlaced input buffers, or it may produce substandard image quality. However, compositors that cannot guarantee reasonable image quality in all cases are recommended to just reject all interlaced buffers. Any argument errors, including non-positive width or height, mismatch between the number of planes and the format, bad format, bad offset or stride, may be indicated by fatal protocol errors: INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS, OUT_OF_BOUNDS. Dmabuf import errors in the server that are not obvious client bugs are returned via the 'failed' event as non-fatal. This allows attempting dmabuf sharing and falling back in the client if it fails. This request can be sent only once in the object's lifetime, after which the only legal request is destroy. This object should be destroyed after issuing a 'create' request. Attempting to use this object after issuing 'create' raises the ALREADY_USED protocol error. It is not mandatory to issue 'create'. If a client wants to cancel the buffer creation, it can just destroy this object. | |
| 237 | 259 | func (o *LinuxBufferParams) Create(width int32, height int32, format uint32, flags uint32) error { | |
| 238 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_linux_buffer_params_v1.create"}, width, height, format, flags); err != nil { | |
| 260 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_linux_buffer_params_v1.create"}, wl.ArgInt(width), wl.ArgInt(height), wl.ArgUint(format), wl.ArgUint(flags)); err != nil { | |
| 239 | 261 | return err | |
| 240 | 262 | } | |
| 241 | 263 | return nil | |
| @@ -244,7 +266,7 @@ func (o *LinuxBufferParams) Create(width int32, height int32, format uint32, fla | |||
| 244 | 266 | // This asks for immediate creation of a wl_buffer by importing the added dmabufs. In case of import success, no event is sent from the server, and the wl_buffer is ready to be used by the client. Upon import failure, either of the following may happen, as seen fit by the implementation: - the client is terminated with one of the following fatal protocol errors: - INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS, OUT_OF_BOUNDS, in case of argument errors such as mismatch between the number of planes and the format, bad format, non-positive width or height, or bad offset or stride. - INVALID_WL_BUFFER, in case the cause for failure is unknown or platform specific. - the server creates an invalid wl_buffer, marks it as failed and sends a 'failed' event to the client. The result of using this invalid wl_buffer as an argument in any request by the client is defined by the compositor implementation. This takes the same arguments as a 'create' request, and obeys the same restrictions. | |
| 245 | 267 | func (o *LinuxBufferParams) CreateImmed(width int32, height int32, format uint32, flags uint32) (*cross_wl_buffer.Buffer, error) { | |
| 246 | 268 | child := cross_wl_buffer.NewBuffer(o.Context()) | |
| 247 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "zwp_linux_buffer_params_v1.create_immed", Since: 2, Child: child}, child, width, height, format, flags); err != nil { | |
| 269 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "zwp_linux_buffer_params_v1.create_immed", Since: 2, Child: child}, wl.ArgObject(child), wl.ArgInt(width), wl.ArgInt(height), wl.ArgUint(format), wl.ArgUint(flags)); err != nil { | |
| 248 | 270 | return nil, err | |
| 249 | 271 | } | |
| 250 | 272 | return child, nil | |
| @@ -252,7 +274,7 @@ func (o *LinuxBufferParams) CreateImmed(width int32, height int32, format uint32 | |||
| 252 | 274 | ||
| 253 | 275 | // Set the device the compositor should import the dmabufs to for sampling in the next create or create_immed request. To avoid race conditions when the compositor removes a device from the tranches, it is not a protocol error if the device hasn't been advertised by the compositor in a tranche with the sampling flag, but the import is likely to fail in that case. If the client doesn't know a suitable target device, it shouldn't set one, and the compositor should attempt import on all devices it supports. If the array is too small to contain a dev_t or larger than required, the invalid_dev_t_size error will be emitted. | |
| 254 | 276 | func (o *LinuxBufferParams) SetSamplingDevice(device []byte) error { | |
| 255 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "zwp_linux_buffer_params_v1.set_sampling_device", Since: 6}, device); err != nil { | |
| 277 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 4, Name: "zwp_linux_buffer_params_v1.set_sampling_device", Since: 6}, wl.ArgArray(device)); err != nil { | |
| 256 | 278 | return err | |
| 257 | 279 | } | |
| 258 | 280 | return nil | |
| @@ -366,7 +388,7 @@ func NewLinuxDmabufFeedback(ctx *wl.Context) *LinuxDmabufFeedback { | |||
| 366 | 388 | ||
| 367 | 389 | // Using this request a client can tell the server that it is not going to use the zwp_linux_dmabuf_feedback_v1 object anymore. | |
| 368 | 390 | func (o *LinuxDmabufFeedback) Destroy() error { | |
| 369 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_linux_dmabuf_feedback_v1.destroy", Destructor: true}); err != nil { | |
| 391 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_linux_dmabuf_feedback_v1.destroy", Destructor: true}); err != nil { | |
| 370 | 392 | return err | |
| 371 | 393 | } | |
| 372 | 394 | return nil | |
A protocol/outputmanagement/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package outputmanagement | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p outputmanagement -o wlr-output-management-unstable-v1_generated.go wlr-output-management-unstable-v1.xml | |
A protocol/outputmanagement/wlr-output-management-unstable-v1.xml +611 -0
| @@ -0,0 +1,611 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="wlr_output_management_unstable_v1"> | |
| 3 | + | <copyright> | |
| 4 | + | Copyright © 2019 Purism SPC | |
| 5 | + | ||
| 6 | + | Permission to use, copy, modify, distribute, and sell this | |
| 7 | + | software and its documentation for any purpose is hereby granted | |
| 8 | + | without fee, provided that the above copyright notice appear in | |
| 9 | + | all copies and that both that copyright notice and this permission | |
| 10 | + | notice appear in supporting documentation, and that the name of | |
| 11 | + | the copyright holders not be used in advertising or publicity | |
| 12 | + | pertaining to distribution of the software without specific, | |
| 13 | + | written prior permission. The copyright holders make no | |
| 14 | + | representations about the suitability of this software for any | |
| 15 | + | purpose. It is provided "as is" without express or implied | |
| 16 | + | warranty. | |
| 17 | + | ||
| 18 | + | THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
| 19 | + | SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| 20 | + | FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| 21 | + | SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 22 | + | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
| 23 | + | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
| 24 | + | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| 25 | + | THIS SOFTWARE. | |
| 26 | + | </copyright> | |
| 27 | + | ||
| 28 | + | <description summary="protocol to configure output devices"> | |
| 29 | + | This protocol exposes interfaces to obtain and modify output device | |
| 30 | + | configuration. | |
| 31 | + | ||
| 32 | + | Warning! The protocol described in this file is experimental and | |
| 33 | + | backward incompatible changes may be made. Backward compatible changes | |
| 34 | + | may be added together with the corresponding interface version bump. | |
| 35 | + | Backward incompatible changes are done by bumping the version number in | |
| 36 | + | the protocol and interface names and resetting the interface version. | |
| 37 | + | Once the protocol is to be declared stable, the 'z' prefix and the | |
| 38 | + | version number in the protocol and interface names are removed and the | |
| 39 | + | interface version number is reset. | |
| 40 | + | </description> | |
| 41 | + | ||
| 42 | + | <interface name="zwlr_output_manager_v1" version="4"> | |
| 43 | + | <description summary="output device configuration manager"> | |
| 44 | + | This interface is a manager that allows reading and writing the current | |
| 45 | + | output device configuration. | |
| 46 | + | ||
| 47 | + | Output devices that display pixels (e.g. a physical monitor or a virtual | |
| 48 | + | output in a window) are represented as heads. Heads cannot be created nor | |
| 49 | + | destroyed by the client, but they can be enabled or disabled and their | |
| 50 | + | properties can be changed. Each head may have one or more available modes. | |
| 51 | + | ||
| 52 | + | Whenever a head appears (e.g. a monitor is plugged in), it will be | |
| 53 | + | advertised via the head event. Immediately after the output manager is | |
| 54 | + | bound, all current heads are advertised. | |
| 55 | + | ||
| 56 | + | Whenever a head's properties change, the relevant wlr_output_head events | |
| 57 | + | will be sent. Not all head properties will be sent: only properties that | |
| 58 | + | have changed need to. | |
| 59 | + | ||
| 60 | + | Whenever a head disappears (e.g. a monitor is unplugged), a | |
| 61 | + | wlr_output_head.finished event will be sent. | |
| 62 | + | ||
| 63 | + | After one or more heads appear, change or disappear, the done event will | |
| 64 | + | be sent. It carries a serial which can be used in a create_configuration | |
| 65 | + | request to update heads properties. | |
| 66 | + | ||
| 67 | + | The information obtained from this protocol should only be used for output | |
| 68 | + | configuration purposes. This protocol is not designed to be a generic | |
| 69 | + | output property advertisement protocol for regular clients. Instead, | |
| 70 | + | protocols such as xdg-output should be used. | |
| 71 | + | </description> | |
| 72 | + | ||
| 73 | + | <event name="head"> | |
| 74 | + | <description summary="introduce a new head"> | |
| 75 | + | This event introduces a new head. This happens whenever a new head | |
| 76 | + | appears (e.g. a monitor is plugged in) or after the output manager is | |
| 77 | + | bound. | |
| 78 | + | </description> | |
| 79 | + | <arg name="head" type="new_id" interface="zwlr_output_head_v1"/> | |
| 80 | + | </event> | |
| 81 | + | ||
| 82 | + | <event name="done"> | |
| 83 | + | <description summary="sent all information about current configuration"> | |
| 84 | + | This event is sent after all information has been sent after binding to | |
| 85 | + | the output manager object and after any subsequent changes. This applies | |
| 86 | + | to child head and mode objects as well. In other words, this event is | |
| 87 | + | sent whenever a head or mode is created or destroyed and whenever one of | |
| 88 | + | their properties has been changed. Not all state is re-sent each time | |
| 89 | + | the current configuration changes: only the actual changes are sent. | |
| 90 | + | ||
| 91 | + | This allows changes to the output configuration to be seen as atomic, | |
| 92 | + | even if they happen via multiple events. | |
| 93 | + | ||
| 94 | + | A serial is sent to be used in a future create_configuration request. | |
| 95 | + | </description> | |
| 96 | + | <arg name="serial" type="uint" summary="current configuration serial"/> | |
| 97 | + | </event> | |
| 98 | + | ||
| 99 | + | <request name="create_configuration"> | |
| 100 | + | <description summary="create a new output configuration object"> | |
| 101 | + | Create a new output configuration object. This allows to update head | |
| 102 | + | properties. | |
| 103 | + | </description> | |
| 104 | + | <arg name="id" type="new_id" interface="zwlr_output_configuration_v1"/> | |
| 105 | + | <arg name="serial" type="uint"/> | |
| 106 | + | </request> | |
| 107 | + | ||
| 108 | + | <request name="stop"> | |
| 109 | + | <description summary="stop sending events"> | |
| 110 | + | Indicates the client no longer wishes to receive events for output | |
| 111 | + | configuration changes. However the compositor may emit further events, | |
| 112 | + | until the finished event is emitted. | |
| 113 | + | ||
| 114 | + | The client must not send any more requests after this one. | |
| 115 | + | </description> | |
| 116 | + | </request> | |
| 117 | + | ||
| 118 | + | <event name="finished" type="destructor"> | |
| 119 | + | <description summary="the compositor has finished with the manager"> | |
| 120 | + | This event indicates that the compositor is done sending manager events. | |
| 121 | + | The compositor will destroy the object immediately after sending this | |
| 122 | + | event, so it will become invalid and the client should release any | |
| 123 | + | resources associated with it. | |
| 124 | + | </description> | |
| 125 | + | </event> | |
| 126 | + | </interface> | |
| 127 | + | ||
| 128 | + | <interface name="zwlr_output_head_v1" version="4"> | |
| 129 | + | <description summary="output device"> | |
| 130 | + | A head is an output device. The difference between a wl_output object and | |
| 131 | + | a head is that heads are advertised even if they are turned off. A head | |
| 132 | + | object only advertises properties and cannot be used directly to change | |
| 133 | + | them. | |
| 134 | + | ||
| 135 | + | A head has some read-only properties: modes, name, description and | |
| 136 | + | physical_size. These cannot be changed by clients. | |
| 137 | + | ||
| 138 | + | Other properties can be updated via a wlr_output_configuration object. | |
| 139 | + | ||
| 140 | + | Properties sent via this interface are applied atomically via the | |
| 141 | + | wlr_output_manager.done event. No guarantees are made regarding the order | |
| 142 | + | in which properties are sent. | |
| 143 | + | </description> | |
| 144 | + | ||
| 145 | + | <event name="name"> | |
| 146 | + | <description summary="head name"> | |
| 147 | + | This event describes the head name. | |
| 148 | + | ||
| 149 | + | The naming convention is compositor defined, but limited to alphanumeric | |
| 150 | + | characters and dashes (-). Each name is unique among all wlr_output_head | |
| 151 | + | objects, but if a wlr_output_head object is destroyed the same name may | |
| 152 | + | be reused later. The names will also remain consistent across sessions | |
| 153 | + | with the same hardware and software configuration. | |
| 154 | + | ||
| 155 | + | Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. However, do | |
| 156 | + | not assume that the name is a reflection of an underlying DRM | |
| 157 | + | connector, X11 connection, etc. | |
| 158 | + | ||
| 159 | + | If this head matches a wl_output, the wl_output.name event must report | |
| 160 | + | the same name. | |
| 161 | + | ||
| 162 | + | The name event is sent after a wlr_output_head object is created. This | |
| 163 | + | event is only sent once per object, and the name does not change over | |
| 164 | + | the lifetime of the wlr_output_head object. | |
| 165 | + | </description> | |
| 166 | + | <arg name="name" type="string"/> | |
| 167 | + | </event> | |
| 168 | + | ||
| 169 | + | <event name="description"> | |
| 170 | + | <description summary="head description"> | |
| 171 | + | This event describes a human-readable description of the head. | |
| 172 | + | ||
| 173 | + | The description is a UTF-8 string with no convention defined for its | |
| 174 | + | contents. Examples might include 'Foocorp 11" Display' or 'Virtual X11 | |
| 175 | + | output via :1'. However, do not assume that the name is a reflection of | |
| 176 | + | the make, model, serial of the underlying DRM connector or the display | |
| 177 | + | name of the underlying X11 connection, etc. | |
| 178 | + | ||
| 179 | + | If this head matches a wl_output, the wl_output.description event must | |
| 180 | + | report the same name. | |
| 181 | + | ||
| 182 | + | The description event is sent after a wlr_output_head object is created. | |
| 183 | + | This event is only sent once per object, and the description does not | |
| 184 | + | change over the lifetime of the wlr_output_head object. | |
| 185 | + | </description> | |
| 186 | + | <arg name="description" type="string"/> | |
| 187 | + | </event> | |
| 188 | + | ||
| 189 | + | <event name="physical_size"> | |
| 190 | + | <description summary="head physical size"> | |
| 191 | + | This event describes the physical size of the head. This event is only | |
| 192 | + | sent if the head has a physical size (e.g. is not a projector or a | |
| 193 | + | virtual device). | |
| 194 | + | ||
| 195 | + | The physical size event is sent after a wlr_output_head object is created. This | |
| 196 | + | event is only sent once per object, and the physical size does not change over | |
| 197 | + | the lifetime of the wlr_output_head object. | |
| 198 | + | </description> | |
| 199 | + | <arg name="width" type="int" summary="width in millimeters of the output"/> | |
| 200 | + | <arg name="height" type="int" summary="height in millimeters of the output"/> | |
| 201 | + | </event> | |
| 202 | + | ||
| 203 | + | <event name="mode"> | |
| 204 | + | <description summary="introduce a mode"> | |
| 205 | + | This event introduces a mode for this head. It is sent once per | |
| 206 | + | supported mode. | |
| 207 | + | </description> | |
| 208 | + | <arg name="mode" type="new_id" interface="zwlr_output_mode_v1"/> | |
| 209 | + | </event> | |
| 210 | + | ||
| 211 | + | <event name="enabled"> | |
| 212 | + | <description summary="head is enabled or disabled"> | |
| 213 | + | This event describes whether the head is enabled. A disabled head is not | |
| 214 | + | mapped to a region of the global compositor space. | |
| 215 | + | ||
| 216 | + | When a head is disabled, some properties (current_mode, position, | |
| 217 | + | transform and scale) are irrelevant. | |
| 218 | + | </description> | |
| 219 | + | <arg name="enabled" type="int" summary="zero if disabled, non-zero if enabled"/> | |
| 220 | + | </event> | |
| 221 | + | ||
| 222 | + | <event name="current_mode"> | |
| 223 | + | <description summary="current mode"> | |
| 224 | + | This event describes the mode currently in use for this head. It is only | |
| 225 | + | sent if the output is enabled. | |
| 226 | + | </description> | |
| 227 | + | <arg name="mode" type="object" interface="zwlr_output_mode_v1"/> | |
| 228 | + | </event> | |
| 229 | + | ||
| 230 | + | <event name="position"> | |
| 231 | + | <description summary="current position"> | |
| 232 | + | This events describes the position of the head in the global compositor | |
| 233 | + | space. It is only sent if the output is enabled. | |
| 234 | + | </description> | |
| 235 | + | <arg name="x" type="int" | |
| 236 | + | summary="x position within the global compositor space"/> | |
| 237 | + | <arg name="y" type="int" | |
| 238 | + | summary="y position within the global compositor space"/> | |
| 239 | + | </event> | |
| 240 | + | ||
| 241 | + | <event name="transform"> | |
| 242 | + | <description summary="current transformation"> | |
| 243 | + | This event describes the transformation currently applied to the head. | |
| 244 | + | It is only sent if the output is enabled. | |
| 245 | + | </description> | |
| 246 | + | <arg name="transform" type="int" enum="wl_output.transform"/> | |
| 247 | + | </event> | |
| 248 | + | ||
| 249 | + | <event name="scale"> | |
| 250 | + | <description summary="current scale"> | |
| 251 | + | This events describes the scale of the head in the global compositor | |
| 252 | + | space. It is only sent if the output is enabled. | |
| 253 | + | </description> | |
| 254 | + | <arg name="scale" type="fixed"/> | |
| 255 | + | </event> | |
| 256 | + | ||
| 257 | + | <event name="finished"> | |
| 258 | + | <description summary="the head has disappeared"> | |
| 259 | + | This event indicates that the head is no longer available. The head | |
| 260 | + | object becomes inert. Clients should send a destroy request and release | |
| 261 | + | any resources associated with it. | |
| 262 | + | </description> | |
| 263 | + | </event> | |
| 264 | + | ||
| 265 | + | <!-- Version 2 additions --> | |
| 266 | + | ||
| 267 | + | <event name="make" since="2"> | |
| 268 | + | <description summary="head manufacturer"> | |
| 269 | + | This event describes the manufacturer of the head. | |
| 270 | + | ||
| 271 | + | Together with the model and serial_number events the purpose is to | |
| 272 | + | allow clients to recognize heads from previous sessions and for example | |
| 273 | + | load head-specific configurations back. | |
| 274 | + | ||
| 275 | + | It is not guaranteed this event will be ever sent. A reason for that | |
| 276 | + | can be that the compositor does not have information about the make of | |
| 277 | + | the head or the definition of a make is not sensible in the current | |
| 278 | + | setup, for example in a virtual session. Clients can still try to | |
| 279 | + | identify the head by available information from other events but should | |
| 280 | + | be aware that there is an increased risk of false positives. | |
| 281 | + | ||
| 282 | + | If sent, the make event is sent after a wlr_output_head object is | |
| 283 | + | created and only sent once per object. The make does not change over | |
| 284 | + | the lifetime of the wlr_output_head object. | |
| 285 | + | ||
| 286 | + | It is not recommended to display the make string in UI to users. For | |
| 287 | + | that the string provided by the description event should be preferred. | |
| 288 | + | </description> | |
| 289 | + | <arg name="make" type="string"/> | |
| 290 | + | </event> | |
| 291 | + | ||
| 292 | + | <event name="model" since="2"> | |
| 293 | + | <description summary="head model"> | |
| 294 | + | This event describes the model of the head. | |
| 295 | + | ||
| 296 | + | Together with the make and serial_number events the purpose is to | |
| 297 | + | allow clients to recognize heads from previous sessions and for example | |
| 298 | + | load head-specific configurations back. | |
| 299 | + | ||
| 300 | + | It is not guaranteed this event will be ever sent. A reason for that | |
| 301 | + | can be that the compositor does not have information about the model of | |
| 302 | + | the head or the definition of a model is not sensible in the current | |
| 303 | + | setup, for example in a virtual session. Clients can still try to | |
| 304 | + | identify the head by available information from other events but should | |
| 305 | + | be aware that there is an increased risk of false positives. | |
| 306 | + | ||
| 307 | + | If sent, the model event is sent after a wlr_output_head object is | |
| 308 | + | created and only sent once per object. The model does not change over | |
| 309 | + | the lifetime of the wlr_output_head object. | |
| 310 | + | ||
| 311 | + | It is not recommended to display the model string in UI to users. For | |
| 312 | + | that the string provided by the description event should be preferred. | |
| 313 | + | </description> | |
| 314 | + | <arg name="model" type="string"/> | |
| 315 | + | </event> | |
| 316 | + | ||
| 317 | + | <event name="serial_number" since="2"> | |
| 318 | + | <description summary="head serial number"> | |
| 319 | + | This event describes the serial number of the head. | |
| 320 | + | ||
| 321 | + | Together with the make and model events the purpose is to allow clients | |
| 322 | + | to recognize heads from previous sessions and for example load head- | |
| 323 | + | specific configurations back. | |
| 324 | + | ||
| 325 | + | It is not guaranteed this event will be ever sent. A reason for that | |
| 326 | + | can be that the compositor does not have information about the serial | |
| 327 | + | number of the head or the definition of a serial number is not sensible | |
| 328 | + | in the current setup. Clients can still try to identify the head by | |
| 329 | + | available information from other events but should be aware that there | |
| 330 | + | is an increased risk of false positives. | |
| 331 | + | ||
| 332 | + | If sent, the serial number event is sent after a wlr_output_head object | |
| 333 | + | is created and only sent once per object. The serial number does not | |
| 334 | + | change over the lifetime of the wlr_output_head object. | |
| 335 | + | ||
| 336 | + | It is not recommended to display the serial_number string in UI to | |
| 337 | + | users. For that the string provided by the description event should be | |
| 338 | + | preferred. | |
| 339 | + | </description> | |
| 340 | + | <arg name="serial_number" type="string"/> | |
| 341 | + | </event> | |
| 342 | + | ||
| 343 | + | <!-- Version 3 additions --> | |
| 344 | + | ||
| 345 | + | <request name="release" type="destructor" since="3"> | |
| 346 | + | <description summary="destroy the head object"> | |
| 347 | + | This request indicates that the client will no longer use this head | |
| 348 | + | object. | |
| 349 | + | </description> | |
| 350 | + | </request> | |
| 351 | + | ||
| 352 | + | <!-- Version 4 additions --> | |
| 353 | + | ||
| 354 | + | <enum name="adaptive_sync_state" since="4"> | |
| 355 | + | <entry name="disabled" value="0" summary="adaptive sync is disabled"/> | |
| 356 | + | <entry name="enabled" value="1" summary="adaptive sync is enabled"/> | |
| 357 | + | </enum> | |
| 358 | + | ||
| 359 | + | <event name="adaptive_sync" since="4"> | |
| 360 | + | <description summary="current adaptive sync state"> | |
| 361 | + | This event describes whether adaptive sync is currently enabled for | |
| 362 | + | the head or not. Adaptive sync is also known as Variable Refresh | |
| 363 | + | Rate or VRR. | |
| 364 | + | </description> | |
| 365 | + | <arg name="state" type="uint" enum="adaptive_sync_state"/> | |
| 366 | + | </event> | |
| 367 | + | </interface> | |
| 368 | + | ||
| 369 | + | <interface name="zwlr_output_mode_v1" version="3"> | |
| 370 | + | <description summary="output mode"> | |
| 371 | + | This object describes an output mode. | |
| 372 | + | ||
| 373 | + | Some heads don't support output modes, in which case modes won't be | |
| 374 | + | advertised. | |
| 375 | + | ||
| 376 | + | Properties sent via this interface are applied atomically via the | |
| 377 | + | wlr_output_manager.done event. No guarantees are made regarding the order | |
| 378 | + | in which properties are sent. | |
| 379 | + | </description> | |
| 380 | + | ||
| 381 | + | <event name="size"> | |
| 382 | + | <description summary="mode size"> | |
| 383 | + | This event describes the mode size. The size is given in physical | |
| 384 | + | hardware units of the output device. This is not necessarily the same as | |
| 385 | + | the output size in the global compositor space. For instance, the output | |
| 386 | + | may be scaled or transformed. | |
| 387 | + | </description> | |
| 388 | + | <arg name="width" type="int" summary="width of the mode in hardware units"/> | |
| 389 | + | <arg name="height" type="int" summary="height of the mode in hardware units"/> | |
| 390 | + | </event> | |
| 391 | + | ||
| 392 | + | <event name="refresh"> | |
| 393 | + | <description summary="mode refresh rate"> | |
| 394 | + | This event describes the mode's fixed vertical refresh rate. It is only | |
| 395 | + | sent if the mode has a fixed refresh rate. | |
| 396 | + | </description> | |
| 397 | + | <arg name="refresh" type="int" summary="vertical refresh rate in mHz"/> | |
| 398 | + | </event> | |
| 399 | + | ||
| 400 | + | <event name="preferred"> | |
| 401 | + | <description summary="mode is preferred"> | |
| 402 | + | This event advertises this mode as preferred. | |
| 403 | + | </description> | |
| 404 | + | </event> | |
| 405 | + | ||
| 406 | + | <event name="finished"> | |
| 407 | + | <description summary="the mode has disappeared"> | |
| 408 | + | This event indicates that the mode is no longer available. The mode | |
| 409 | + | object becomes inert. Clients should send a destroy request and release | |
| 410 | + | any resources associated with it. | |
| 411 | + | </description> | |
| 412 | + | </event> | |
| 413 | + | ||
| 414 | + | <!-- Version 3 additions --> | |
| 415 | + | ||
| 416 | + | <request name="release" type="destructor" since="3"> | |
| 417 | + | <description summary="destroy the mode object"> | |
| 418 | + | This request indicates that the client will no longer use this mode | |
| 419 | + | object. | |
| 420 | + | </description> | |
| 421 | + | </request> | |
| 422 | + | </interface> | |
| 423 | + | ||
| 424 | + | <interface name="zwlr_output_configuration_v1" version="4"> | |
| 425 | + | <description summary="output configuration"> | |
| 426 | + | This object is used by the client to describe a full output configuration. | |
| 427 | + | ||
| 428 | + | First, the client needs to setup the output configuration. Each head can | |
| 429 | + | be either enabled (and configured) or disabled. It is a protocol error to | |
| 430 | + | send two enable_head or disable_head requests with the same head. It is a | |
| 431 | + | protocol error to omit a head in a configuration. | |
| 432 | + | ||
| 433 | + | Then, the client can apply or test the configuration. The compositor will | |
| 434 | + | then reply with a succeeded, failed or cancelled event. Finally the client | |
| 435 | + | should destroy the configuration object. | |
| 436 | + | </description> | |
| 437 | + | ||
| 438 | + | <enum name="error"> | |
| 439 | + | <entry name="already_configured_head" value="1" | |
| 440 | + | summary="head has been configured twice"/> | |
| 441 | + | <entry name="unconfigured_head" value="2" | |
| 442 | + | summary="head has not been configured"/> | |
| 443 | + | <entry name="already_used" value="3" | |
| 444 | + | summary="request sent after configuration has been applied or tested"/> | |
| 445 | + | </enum> | |
| 446 | + | ||
| 447 | + | <request name="enable_head"> | |
| 448 | + | <description summary="enable and configure a head"> | |
| 449 | + | Enable a head. This request creates a head configuration object that can | |
| 450 | + | be used to change the head's properties. | |
| 451 | + | </description> | |
| 452 | + | <arg name="id" type="new_id" interface="zwlr_output_configuration_head_v1" | |
| 453 | + | summary="a new object to configure the head"/> | |
| 454 | + | <arg name="head" type="object" interface="zwlr_output_head_v1" | |
| 455 | + | summary="the head to be enabled"/> | |
| 456 | + | </request> | |
| 457 | + | ||
| 458 | + | <request name="disable_head"> | |
| 459 | + | <description summary="disable a head"> | |
| 460 | + | Disable a head. | |
| 461 | + | </description> | |
| 462 | + | <arg name="head" type="object" interface="zwlr_output_head_v1" | |
| 463 | + | summary="the head to be disabled"/> | |
| 464 | + | </request> | |
| 465 | + | ||
| 466 | + | <request name="apply"> | |
| 467 | + | <description summary="apply the configuration"> | |
| 468 | + | Apply the new output configuration. | |
| 469 | + | ||
| 470 | + | In case the configuration is successfully applied, there is no guarantee | |
| 471 | + | that the new output state matches completely the requested | |
| 472 | + | configuration. For instance, a compositor might round the scale if it | |
| 473 | + | doesn't support fractional scaling. | |
| 474 | + | ||
| 475 | + | After this request has been sent, the compositor must respond with an | |
| 476 | + | succeeded, failed or cancelled event. Sending a request that isn't the | |
| 477 | + | destructor is a protocol error. | |
| 478 | + | </description> | |
| 479 | + | </request> | |
| 480 | + | ||
| 481 | + | <request name="test"> | |
| 482 | + | <description summary="test the configuration"> | |
| 483 | + | Test the new output configuration. The configuration won't be applied, | |
| 484 | + | but will only be validated. | |
| 485 | + | ||
| 486 | + | Even if the compositor succeeds to test a configuration, applying it may | |
| 487 | + | fail. | |
| 488 | + | ||
| 489 | + | After this request has been sent, the compositor must respond with an | |
| 490 | + | succeeded, failed or cancelled event. Sending a request that isn't the | |
| 491 | + | destructor is a protocol error. | |
| 492 | + | </description> | |
| 493 | + | </request> | |
| 494 | + | ||
| 495 | + | <event name="succeeded"> | |
| 496 | + | <description summary="configuration changes succeeded"> | |
| 497 | + | Sent after the compositor has successfully applied the changes or | |
| 498 | + | tested them. | |
| 499 | + | ||
| 500 | + | Upon receiving this event, the client should destroy this object. | |
| 501 | + | ||
| 502 | + | If the current configuration has changed, events to describe the changes | |
| 503 | + | will be sent followed by a wlr_output_manager.done event. | |
| 504 | + | </description> | |
| 505 | + | </event> | |
| 506 | + | ||
| 507 | + | <event name="failed"> | |
| 508 | + | <description summary="configuration changes failed"> | |
| 509 | + | Sent if the compositor rejects the changes or failed to apply them. The | |
| 510 | + | compositor should revert any changes made by the apply request that | |
| 511 | + | triggered this event. | |
| 512 | + | ||
| 513 | + | Upon receiving this event, the client should destroy this object. | |
| 514 | + | </description> | |
| 515 | + | </event> | |
| 516 | + | ||
| 517 | + | <event name="cancelled"> | |
| 518 | + | <description summary="configuration has been cancelled"> | |
| 519 | + | Sent if the compositor cancels the configuration because the state of an | |
| 520 | + | output changed and the client has outdated information (e.g. after an | |
| 521 | + | output has been hotplugged). | |
| 522 | + | ||
| 523 | + | The client can create a new configuration with a newer serial and try | |
| 524 | + | again. | |
| 525 | + | ||
| 526 | + | Upon receiving this event, the client should destroy this object. | |
| 527 | + | </description> | |
| 528 | + | </event> | |
| 529 | + | ||
| 530 | + | <request name="destroy" type="destructor"> | |
| 531 | + | <description summary="destroy the output configuration"> | |
| 532 | + | Using this request a client can tell the compositor that it is not going | |
| 533 | + | to use the configuration object anymore. Any changes to the outputs | |
| 534 | + | that have not been applied will be discarded. | |
| 535 | + | ||
| 536 | + | This request also destroys wlr_output_configuration_head objects created | |
| 537 | + | via this object. | |
| 538 | + | </description> | |
| 539 | + | </request> | |
| 540 | + | </interface> | |
| 541 | + | ||
| 542 | + | <interface name="zwlr_output_configuration_head_v1" version="4"> | |
| 543 | + | <description summary="head configuration"> | |
| 544 | + | This object is used by the client to update a single head's configuration. | |
| 545 | + | ||
| 546 | + | It is a protocol error to set the same property twice. | |
| 547 | + | </description> | |
| 548 | + | ||
| 549 | + | <enum name="error"> | |
| 550 | + | <entry name="already_set" value="1" summary="property has already been set"/> | |
| 551 | + | <entry name="invalid_mode" value="2" summary="mode doesn't belong to head"/> | |
| 552 | + | <entry name="invalid_custom_mode" value="3" summary="mode is invalid"/> | |
| 553 | + | <entry name="invalid_transform" value="4" summary="transform value outside enum"/> | |
| 554 | + | <entry name="invalid_scale" value="5" summary="scale negative or zero"/> | |
| 555 | + | <entry name="invalid_adaptive_sync_state" value="6" since="4" | |
| 556 | + | summary="invalid enum value used in the set_adaptive_sync request"/> | |
| 557 | + | </enum> | |
| 558 | + | ||
| 559 | + | <request name="set_mode"> | |
| 560 | + | <description summary="set the mode"> | |
| 561 | + | This request sets the head's mode. | |
| 562 | + | </description> | |
| 563 | + | <arg name="mode" type="object" interface="zwlr_output_mode_v1"/> | |
| 564 | + | </request> | |
| 565 | + | ||
| 566 | + | <request name="set_custom_mode"> | |
| 567 | + | <description summary="set a custom mode"> | |
| 568 | + | This request assigns a custom mode to the head. The size is given in | |
| 569 | + | physical hardware units of the output device. If set to zero, the | |
| 570 | + | refresh rate is unspecified. | |
| 571 | + | ||
| 572 | + | It is a protocol error to set both a mode and a custom mode. | |
| 573 | + | </description> | |
| 574 | + | <arg name="width" type="int" summary="width of the mode in hardware units"/> | |
| 575 | + | <arg name="height" type="int" summary="height of the mode in hardware units"/> | |
| 576 | + | <arg name="refresh" type="int" summary="vertical refresh rate in mHz or zero"/> | |
| 577 | + | </request> | |
| 578 | + | ||
| 579 | + | <request name="set_position"> | |
| 580 | + | <description summary="set the position"> | |
| 581 | + | This request sets the head's position in the global compositor space. | |
| 582 | + | </description> | |
| 583 | + | <arg name="x" type="int" summary="x position in the global compositor space"/> | |
| 584 | + | <arg name="y" type="int" summary="y position in the global compositor space"/> | |
| 585 | + | </request> | |
| 586 | + | ||
| 587 | + | <request name="set_transform"> | |
| 588 | + | <description summary="set the transform"> | |
| 589 | + | This request sets the head's transform. | |
| 590 | + | </description> | |
| 591 | + | <arg name="transform" type="int" enum="wl_output.transform"/> | |
| 592 | + | </request> | |
| 593 | + | ||
| 594 | + | <request name="set_scale"> | |
| 595 | + | <description summary="set the scale"> | |
| 596 | + | This request sets the head's scale. | |
| 597 | + | </description> | |
| 598 | + | <arg name="scale" type="fixed"/> | |
| 599 | + | </request> | |
| 600 | + | ||
| 601 | + | <!-- Version 4 additions --> | |
| 602 | + | ||
| 603 | + | <request name="set_adaptive_sync" since="4"> | |
| 604 | + | <description summary="enable/disable adaptive sync"> | |
| 605 | + | This request enables/disables adaptive sync. Adaptive sync is also | |
| 606 | + | known as Variable Refresh Rate or VRR. | |
| 607 | + | </description> | |
| 608 | + | <arg name="state" type="uint" enum="zwlr_output_head_v1.adaptive_sync_state"/> | |
| 609 | + | </request> | |
| 610 | + | </interface> | |
| 611 | + | </protocol> | |
A protocol/outputmanagement/wlr-output-management-unstable-v1_generated.go +1146 -0
| @@ -0,0 +1,1146 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: wlr_output_management_unstable_v1 | |
| 3 | + | // Source: wlr-output-management-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2019 Purism SPC | |
| 7 | + | // | |
| 8 | + | // Permission to use, copy, modify, distribute, and sell this | |
| 9 | + | // software and its documentation for any purpose is hereby granted | |
| 10 | + | // without fee, provided that the above copyright notice appear in | |
| 11 | + | // all copies and that both that copyright notice and this permission | |
| 12 | + | // notice appear in supporting documentation, and that the name of | |
| 13 | + | // the copyright holders not be used in advertising or publicity | |
| 14 | + | // pertaining to distribution of the software without specific, | |
| 15 | + | // written prior permission. The copyright holders make no | |
| 16 | + | // representations about the suitability of this software for any | |
| 17 | + | // purpose. It is provided "as is" without express or implied | |
| 18 | + | // warranty. | |
| 19 | + | // | |
| 20 | + | // THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS | |
| 21 | + | // SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |
| 22 | + | // FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
| 23 | + | // SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 24 | + | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |
| 25 | + | // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
| 26 | + | // ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
| 27 | + | // THIS SOFTWARE. | |
| 28 | + | ||
| 29 | + | package outputmanagement | |
| 30 | + | ||
| 31 | + | import ( | |
| 32 | + | "sync" | |
| 33 | + | ||
| 34 | + | "github.com/bnema/wlturbo/wl" | |
| 35 | + | ) | |
| 36 | + | ||
| 37 | + | // ADAPTIVE_SYNC_STATE_DISABLED is the adaptive_sync_state disabled value. | |
| 38 | + | const ADAPTIVE_SYNC_STATE_DISABLED = 0 | |
| 39 | + | ||
| 40 | + | // ADAPTIVE_SYNC_STATE_ENABLED is the adaptive_sync_state enabled value. | |
| 41 | + | const ADAPTIVE_SYNC_STATE_ENABLED = 1 | |
| 42 | + | ||
| 43 | + | // ERROR_ALREADY_CONFIGURED_HEAD is the error already_configured_head value. | |
| 44 | + | const ERROR_ALREADY_CONFIGURED_HEAD = 1 | |
| 45 | + | ||
| 46 | + | // ERROR_UNCONFIGURED_HEAD is the error unconfigured_head value. | |
| 47 | + | const ERROR_UNCONFIGURED_HEAD = 2 | |
| 48 | + | ||
| 49 | + | // ERROR_ALREADY_USED is the error already_used value. | |
| 50 | + | const ERROR_ALREADY_USED = 3 | |
| 51 | + | ||
| 52 | + | // ERROR_ALREADY_SET is the error already_set value. | |
| 53 | + | const ERROR_ALREADY_SET = 1 | |
| 54 | + | ||
| 55 | + | // ERROR_INVALID_MODE is the error invalid_mode value. | |
| 56 | + | const ERROR_INVALID_MODE = 2 | |
| 57 | + | ||
| 58 | + | // ERROR_INVALID_CUSTOM_MODE is the error invalid_custom_mode value. | |
| 59 | + | const ERROR_INVALID_CUSTOM_MODE = 3 | |
| 60 | + | ||
| 61 | + | // ERROR_INVALID_TRANSFORM is the error invalid_transform value. | |
| 62 | + | const ERROR_INVALID_TRANSFORM = 4 | |
| 63 | + | ||
| 64 | + | // ERROR_INVALID_SCALE is the error invalid_scale value. | |
| 65 | + | const ERROR_INVALID_SCALE = 5 | |
| 66 | + | ||
| 67 | + | // ERROR_INVALID_ADAPTIVE_SYNC_STATE is the error invalid_adaptive_sync_state value. | |
| 68 | + | const ERROR_INVALID_ADAPTIVE_SYNC_STATE = 6 | |
| 69 | + | ||
| 70 | + | // OutputManagerInterface is the protocol interface name. | |
| 71 | + | const OutputManagerInterface = "zwlr_output_manager_v1" | |
| 72 | + | ||
| 73 | + | // OutputManager is the generated binding for zwlr_output_manager_v1 version 4. | |
| 74 | + | type OutputManager struct { | |
| 75 | + | wl.BaseProxy | |
| 76 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 77 | + | // handlers while another goroutine dispatches events. | |
| 78 | + | handlersMu sync.Mutex | |
| 79 | + | onHead []func(headObject *OutputHead) | |
| 80 | + | onDone []func(serial uint32) | |
| 81 | + | onFinished []func() | |
| 82 | + | } | |
| 83 | + | ||
| 84 | + | // NewOutputManager returns an unbound OutputManager. | |
| 85 | + | func NewOutputManager(ctx *wl.Context) *OutputManager { | |
| 86 | + | obj := &OutputManager{} | |
| 87 | + | obj.SetContext(ctx) | |
| 88 | + | ctx.Register(obj) | |
| 89 | + | return obj | |
| 90 | + | } | |
| 91 | + | ||
| 92 | + | // Create a new output configuration object. This allows to update head properties. | |
| 93 | + | func (o *OutputManager) CreateConfiguration(serial uint32) (*OutputConfiguration, error) { | |
| 94 | + | child := &OutputConfiguration{} | |
| 95 | + | child.SetContext(o.Context()) | |
| 96 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_output_manager_v1.create_configuration", Child: child}, wl.ArgObject(child), wl.ArgUint(serial)); err != nil { | |
| 97 | + | return nil, err | |
| 98 | + | } | |
| 99 | + | return child, nil | |
| 100 | + | } | |
| 101 | + | ||
| 102 | + | // Indicates the client no longer wishes to receive events for output configuration changes. However the compositor may emit further events, until the finished event is emitted. The client must not send any more requests after this one. | |
| 103 | + | func (o *OutputManager) Stop() error { | |
| 104 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwlr_output_manager_v1.stop"}); err != nil { | |
| 105 | + | return err | |
| 106 | + | } | |
| 107 | + | return nil | |
| 108 | + | } | |
| 109 | + | ||
| 110 | + | // OnHead registers a handler for the head event. | |
| 111 | + | // | |
| 112 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 113 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 114 | + | func (o *OutputManager) OnHead(handler func(headObject *OutputHead)) { | |
| 115 | + | if handler == nil { | |
| 116 | + | return | |
| 117 | + | } | |
| 118 | + | o.handlersMu.Lock() | |
| 119 | + | defer o.handlersMu.Unlock() | |
| 120 | + | o.onHead = append(o.onHead, handler) | |
| 121 | + | } | |
| 122 | + | ||
| 123 | + | // handlersForHead returns the handlers registered for head, taken | |
| 124 | + | // under the lock so a handler may register another handler while events are | |
| 125 | + | // being dispatched. | |
| 126 | + | func (o *OutputManager) handlersForHead() []func(headObject *OutputHead) { | |
| 127 | + | o.handlersMu.Lock() | |
| 128 | + | defer o.handlersMu.Unlock() | |
| 129 | + | return o.onHead | |
| 130 | + | } | |
| 131 | + | ||
| 132 | + | // OnDone registers a handler for the done event. | |
| 133 | + | // | |
| 134 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 135 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 136 | + | func (o *OutputManager) OnDone(handler func(serial uint32)) { | |
| 137 | + | if handler == nil { | |
| 138 | + | return | |
| 139 | + | } | |
| 140 | + | o.handlersMu.Lock() | |
| 141 | + | defer o.handlersMu.Unlock() | |
| 142 | + | o.onDone = append(o.onDone, handler) | |
| 143 | + | } | |
| 144 | + | ||
| 145 | + | // handlersForDone returns the handlers registered for done, taken | |
| 146 | + | // under the lock so a handler may register another handler while events are | |
| 147 | + | // being dispatched. | |
| 148 | + | func (o *OutputManager) handlersForDone() []func(serial uint32) { | |
| 149 | + | o.handlersMu.Lock() | |
| 150 | + | defer o.handlersMu.Unlock() | |
| 151 | + | return o.onDone | |
| 152 | + | } | |
| 153 | + | ||
| 154 | + | // OnFinished registers a handler for the finished event. | |
| 155 | + | // | |
| 156 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 157 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 158 | + | func (o *OutputManager) OnFinished(handler func()) { | |
| 159 | + | if handler == nil { | |
| 160 | + | return | |
| 161 | + | } | |
| 162 | + | o.handlersMu.Lock() | |
| 163 | + | defer o.handlersMu.Unlock() | |
| 164 | + | o.onFinished = append(o.onFinished, handler) | |
| 165 | + | } | |
| 166 | + | ||
| 167 | + | // handlersForFinished returns the handlers registered for finished, taken | |
| 168 | + | // under the lock so a handler may register another handler while events are | |
| 169 | + | // being dispatched. | |
| 170 | + | func (o *OutputManager) handlersForFinished() []func() { | |
| 171 | + | o.handlersMu.Lock() | |
| 172 | + | defer o.handlersMu.Unlock() | |
| 173 | + | return o.onFinished | |
| 174 | + | } | |
| 175 | + | ||
| 176 | + | // EventSignature returns the declared event argument types in wire order. | |
| 177 | + | func (o *OutputManager) EventSignature(opcode uint16) (string, bool) { | |
| 178 | + | switch opcode { | |
| 179 | + | case 0: | |
| 180 | + | return "new_id,", true | |
| 181 | + | case 1: | |
| 182 | + | return "uint,", true | |
| 183 | + | case 2: | |
| 184 | + | return "", true | |
| 185 | + | default: | |
| 186 | + | return "", false | |
| 187 | + | } | |
| 188 | + | } | |
| 189 | + | ||
| 190 | + | // Dispatch decodes one event on zwlr_output_manager_v1 and calls the registered handlers. | |
| 191 | + | func (o *OutputManager) Dispatch(event *wl.Event) { | |
| 192 | + | switch event.Opcode { | |
| 193 | + | case 0: // head | |
| 194 | + | headID := event.Uint32() | |
| 195 | + | headObject := &OutputHead{} | |
| 196 | + | headObject.SetContext(o.Context()) | |
| 197 | + | headObject.SetID(headID) | |
| 198 | + | headObject.SetVersion(o.Version()) | |
| 199 | + | o.Context().Register(headObject) | |
| 200 | + | ||
| 201 | + | for i, handler := range o.handlersForHead() { | |
| 202 | + | _ = i | |
| 203 | + | handler(headObject) | |
| 204 | + | } | |
| 205 | + | case 1: // done | |
| 206 | + | serial := event.Uint32() | |
| 207 | + | ||
| 208 | + | for i, handler := range o.handlersForDone() { | |
| 209 | + | _ = i | |
| 210 | + | handler(serial) | |
| 211 | + | } | |
| 212 | + | case 2: // finished | |
| 213 | + | ||
| 214 | + | for i, handler := range o.handlersForFinished() { | |
| 215 | + | _ = i | |
| 216 | + | handler() | |
| 217 | + | } | |
| 218 | + | o.Context().Unregister(o) | |
| 219 | + | default: | |
| 220 | + | } | |
| 221 | + | } | |
| 222 | + | ||
| 223 | + | // OutputHeadInterface is the protocol interface name. | |
| 224 | + | const OutputHeadInterface = "zwlr_output_head_v1" | |
| 225 | + | ||
| 226 | + | // OutputHead is the generated binding for zwlr_output_head_v1 version 4. | |
| 227 | + | type OutputHead struct { | |
| 228 | + | wl.BaseProxy | |
| 229 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 230 | + | // handlers while another goroutine dispatches events. | |
| 231 | + | handlersMu sync.Mutex | |
| 232 | + | onName []func(name string) | |
| 233 | + | onDescription []func(description string) | |
| 234 | + | onPhysicalSize []func(width int32, height int32) | |
| 235 | + | onMode []func(modeObject *OutputMode) | |
| 236 | + | onEnabled []func(enabled int32) | |
| 237 | + | onCurrentMode []func(modeID uint32) | |
| 238 | + | onPosition []func(x int32, y int32) | |
| 239 | + | onTransform []func(transform int32) | |
| 240 | + | onScale []func(scale wl.Fixed) | |
| 241 | + | onFinished []func() | |
| 242 | + | onMake []func(make string) | |
| 243 | + | onModel []func(model string) | |
| 244 | + | onSerialNumber []func(serialNumber string) | |
| 245 | + | onAdaptiveSync []func(state uint32) | |
| 246 | + | } | |
| 247 | + | ||
| 248 | + | // NewOutputHead returns an unbound OutputHead. | |
| 249 | + | func NewOutputHead(ctx *wl.Context) *OutputHead { | |
| 250 | + | obj := &OutputHead{} | |
| 251 | + | obj.SetContext(ctx) | |
| 252 | + | ctx.Register(obj) | |
| 253 | + | return obj | |
| 254 | + | } | |
| 255 | + | ||
| 256 | + | // This request indicates that the client will no longer use this head object. | |
| 257 | + | func (o *OutputHead) Release() error { | |
| 258 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_output_head_v1.release", Since: 3, Destructor: true}); err != nil { | |
| 259 | + | return err | |
| 260 | + | } | |
| 261 | + | return nil | |
| 262 | + | } | |
| 263 | + | ||
| 264 | + | // OnName registers a handler for the name event. | |
| 265 | + | // | |
| 266 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 267 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 268 | + | func (o *OutputHead) OnName(handler func(name string)) { | |
| 269 | + | if handler == nil { | |
| 270 | + | return | |
| 271 | + | } | |
| 272 | + | o.handlersMu.Lock() | |
| 273 | + | defer o.handlersMu.Unlock() | |
| 274 | + | o.onName = append(o.onName, handler) | |
| 275 | + | } | |
| 276 | + | ||
| 277 | + | // handlersForName returns the handlers registered for name, taken | |
| 278 | + | // under the lock so a handler may register another handler while events are | |
| 279 | + | // being dispatched. | |
| 280 | + | func (o *OutputHead) handlersForName() []func(name string) { | |
| 281 | + | o.handlersMu.Lock() | |
| 282 | + | defer o.handlersMu.Unlock() | |
| 283 | + | return o.onName | |
| 284 | + | } | |
| 285 | + | ||
| 286 | + | // OnDescription registers a handler for the description event. | |
| 287 | + | // | |
| 288 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 289 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 290 | + | func (o *OutputHead) OnDescription(handler func(description string)) { | |
| 291 | + | if handler == nil { | |
| 292 | + | return | |
| 293 | + | } | |
| 294 | + | o.handlersMu.Lock() | |
| 295 | + | defer o.handlersMu.Unlock() | |
| 296 | + | o.onDescription = append(o.onDescription, handler) | |
| 297 | + | } | |
| 298 | + | ||
| 299 | + | // handlersForDescription returns the handlers registered for description, taken | |
| 300 | + | // under the lock so a handler may register another handler while events are | |
| 301 | + | // being dispatched. | |
| 302 | + | func (o *OutputHead) handlersForDescription() []func(description string) { | |
| 303 | + | o.handlersMu.Lock() | |
| 304 | + | defer o.handlersMu.Unlock() | |
| 305 | + | return o.onDescription | |
| 306 | + | } | |
| 307 | + | ||
| 308 | + | // OnPhysicalSize registers a handler for the physical_size event. | |
| 309 | + | // | |
| 310 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 311 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 312 | + | func (o *OutputHead) OnPhysicalSize(handler func(width int32, height int32)) { | |
| 313 | + | if handler == nil { | |
| 314 | + | return | |
| 315 | + | } | |
| 316 | + | o.handlersMu.Lock() | |
| 317 | + | defer o.handlersMu.Unlock() | |
| 318 | + | o.onPhysicalSize = append(o.onPhysicalSize, handler) | |
| 319 | + | } | |
| 320 | + | ||
| 321 | + | // handlersForPhysicalSize returns the handlers registered for physical_size, taken | |
| 322 | + | // under the lock so a handler may register another handler while events are | |
| 323 | + | // being dispatched. | |
| 324 | + | func (o *OutputHead) handlersForPhysicalSize() []func(width int32, height int32) { | |
| 325 | + | o.handlersMu.Lock() | |
| 326 | + | defer o.handlersMu.Unlock() | |
| 327 | + | return o.onPhysicalSize | |
| 328 | + | } | |
| 329 | + | ||
| 330 | + | // OnMode registers a handler for the mode event. | |
| 331 | + | // | |
| 332 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 333 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 334 | + | func (o *OutputHead) OnMode(handler func(modeObject *OutputMode)) { | |
| 335 | + | if handler == nil { | |
| 336 | + | return | |
| 337 | + | } | |
| 338 | + | o.handlersMu.Lock() | |
| 339 | + | defer o.handlersMu.Unlock() | |
| 340 | + | o.onMode = append(o.onMode, handler) | |
| 341 | + | } | |
| 342 | + | ||
| 343 | + | // handlersForMode returns the handlers registered for mode, taken | |
| 344 | + | // under the lock so a handler may register another handler while events are | |
| 345 | + | // being dispatched. | |
| 346 | + | func (o *OutputHead) handlersForMode() []func(modeObject *OutputMode) { | |
| 347 | + | o.handlersMu.Lock() | |
| 348 | + | defer o.handlersMu.Unlock() | |
| 349 | + | return o.onMode | |
| 350 | + | } | |
| 351 | + | ||
| 352 | + | // OnEnabled registers a handler for the enabled event. | |
| 353 | + | // | |
| 354 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 355 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 356 | + | func (o *OutputHead) OnEnabled(handler func(enabled int32)) { | |
| 357 | + | if handler == nil { | |
| 358 | + | return | |
| 359 | + | } | |
| 360 | + | o.handlersMu.Lock() | |
| 361 | + | defer o.handlersMu.Unlock() | |
| 362 | + | o.onEnabled = append(o.onEnabled, handler) | |
| 363 | + | } | |
| 364 | + | ||
| 365 | + | // handlersForEnabled returns the handlers registered for enabled, taken | |
| 366 | + | // under the lock so a handler may register another handler while events are | |
| 367 | + | // being dispatched. | |
| 368 | + | func (o *OutputHead) handlersForEnabled() []func(enabled int32) { | |
| 369 | + | o.handlersMu.Lock() | |
| 370 | + | defer o.handlersMu.Unlock() | |
| 371 | + | return o.onEnabled | |
| 372 | + | } | |
| 373 | + | ||
| 374 | + | // OnCurrentMode registers a handler for the current_mode event. | |
| 375 | + | // | |
| 376 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 377 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 378 | + | func (o *OutputHead) OnCurrentMode(handler func(modeID uint32)) { | |
| 379 | + | if handler == nil { | |
| 380 | + | return | |
| 381 | + | } | |
| 382 | + | o.handlersMu.Lock() | |
| 383 | + | defer o.handlersMu.Unlock() | |
| 384 | + | o.onCurrentMode = append(o.onCurrentMode, handler) | |
| 385 | + | } | |
| 386 | + | ||
| 387 | + | // handlersForCurrentMode returns the handlers registered for current_mode, taken | |
| 388 | + | // under the lock so a handler may register another handler while events are | |
| 389 | + | // being dispatched. | |
| 390 | + | func (o *OutputHead) handlersForCurrentMode() []func(modeID uint32) { | |
| 391 | + | o.handlersMu.Lock() | |
| 392 | + | defer o.handlersMu.Unlock() | |
| 393 | + | return o.onCurrentMode | |
| 394 | + | } | |
| 395 | + | ||
| 396 | + | // OnPosition registers a handler for the position event. | |
| 397 | + | // | |
| 398 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 399 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 400 | + | func (o *OutputHead) OnPosition(handler func(x int32, y int32)) { | |
| 401 | + | if handler == nil { | |
| 402 | + | return | |
| 403 | + | } | |
| 404 | + | o.handlersMu.Lock() | |
| 405 | + | defer o.handlersMu.Unlock() | |
| 406 | + | o.onPosition = append(o.onPosition, handler) | |
| 407 | + | } | |
| 408 | + | ||
| 409 | + | // handlersForPosition returns the handlers registered for position, taken | |
| 410 | + | // under the lock so a handler may register another handler while events are | |
| 411 | + | // being dispatched. | |
| 412 | + | func (o *OutputHead) handlersForPosition() []func(x int32, y int32) { | |
| 413 | + | o.handlersMu.Lock() | |
| 414 | + | defer o.handlersMu.Unlock() | |
| 415 | + | return o.onPosition | |
| 416 | + | } | |
| 417 | + | ||
| 418 | + | // OnTransform registers a handler for the transform event. | |
| 419 | + | // | |
| 420 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 421 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 422 | + | func (o *OutputHead) OnTransform(handler func(transform int32)) { | |
| 423 | + | if handler == nil { | |
| 424 | + | return | |
| 425 | + | } | |
| 426 | + | o.handlersMu.Lock() | |
| 427 | + | defer o.handlersMu.Unlock() | |
| 428 | + | o.onTransform = append(o.onTransform, handler) | |
| 429 | + | } | |
| 430 | + | ||
| 431 | + | // handlersForTransform returns the handlers registered for transform, taken | |
| 432 | + | // under the lock so a handler may register another handler while events are | |
| 433 | + | // being dispatched. | |
| 434 | + | func (o *OutputHead) handlersForTransform() []func(transform int32) { | |
| 435 | + | o.handlersMu.Lock() | |
| 436 | + | defer o.handlersMu.Unlock() | |
| 437 | + | return o.onTransform | |
| 438 | + | } | |
| 439 | + | ||
| 440 | + | // OnScale registers a handler for the scale event. | |
| 441 | + | // | |
| 442 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 443 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 444 | + | func (o *OutputHead) OnScale(handler func(scale wl.Fixed)) { | |
| 445 | + | if handler == nil { | |
| 446 | + | return | |
| 447 | + | } | |
| 448 | + | o.handlersMu.Lock() | |
| 449 | + | defer o.handlersMu.Unlock() | |
| 450 | + | o.onScale = append(o.onScale, handler) | |
| 451 | + | } | |
| 452 | + | ||
| 453 | + | // handlersForScale returns the handlers registered for scale, taken | |
| 454 | + | // under the lock so a handler may register another handler while events are | |
| 455 | + | // being dispatched. | |
| 456 | + | func (o *OutputHead) handlersForScale() []func(scale wl.Fixed) { | |
| 457 | + | o.handlersMu.Lock() | |
| 458 | + | defer o.handlersMu.Unlock() | |
| 459 | + | return o.onScale | |
| 460 | + | } | |
| 461 | + | ||
| 462 | + | // OnFinished registers a handler for the finished event. | |
| 463 | + | // | |
| 464 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 465 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 466 | + | func (o *OutputHead) OnFinished(handler func()) { | |
| 467 | + | if handler == nil { | |
| 468 | + | return | |
| 469 | + | } | |
| 470 | + | o.handlersMu.Lock() | |
| 471 | + | defer o.handlersMu.Unlock() | |
| 472 | + | o.onFinished = append(o.onFinished, handler) | |
| 473 | + | } | |
| 474 | + | ||
| 475 | + | // handlersForFinished returns the handlers registered for finished, taken | |
| 476 | + | // under the lock so a handler may register another handler while events are | |
| 477 | + | // being dispatched. | |
| 478 | + | func (o *OutputHead) handlersForFinished() []func() { | |
| 479 | + | o.handlersMu.Lock() | |
| 480 | + | defer o.handlersMu.Unlock() | |
| 481 | + | return o.onFinished | |
| 482 | + | } | |
| 483 | + | ||
| 484 | + | // OnMake registers a handler for the make event. | |
| 485 | + | // | |
| 486 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 487 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 488 | + | func (o *OutputHead) OnMake(handler func(make string)) { | |
| 489 | + | if handler == nil { | |
| 490 | + | return | |
| 491 | + | } | |
| 492 | + | o.handlersMu.Lock() | |
| 493 | + | defer o.handlersMu.Unlock() | |
| 494 | + | o.onMake = append(o.onMake, handler) | |
| 495 | + | } | |
| 496 | + | ||
| 497 | + | // handlersForMake returns the handlers registered for make, taken | |
| 498 | + | // under the lock so a handler may register another handler while events are | |
| 499 | + | // being dispatched. | |
| 500 | + | func (o *OutputHead) handlersForMake() []func(make string) { | |
| 501 | + | o.handlersMu.Lock() | |
| 502 | + | defer o.handlersMu.Unlock() | |
| 503 | + | return o.onMake | |
| 504 | + | } | |
| 505 | + | ||
| 506 | + | // OnModel registers a handler for the model event. | |
| 507 | + | // | |
| 508 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 509 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 510 | + | func (o *OutputHead) OnModel(handler func(model string)) { | |
| 511 | + | if handler == nil { | |
| 512 | + | return | |
| 513 | + | } | |
| 514 | + | o.handlersMu.Lock() | |
| 515 | + | defer o.handlersMu.Unlock() | |
| 516 | + | o.onModel = append(o.onModel, handler) | |
| 517 | + | } | |
| 518 | + | ||
| 519 | + | // handlersForModel returns the handlers registered for model, taken | |
| 520 | + | // under the lock so a handler may register another handler while events are | |
| 521 | + | // being dispatched. | |
| 522 | + | func (o *OutputHead) handlersForModel() []func(model string) { | |
| 523 | + | o.handlersMu.Lock() | |
| 524 | + | defer o.handlersMu.Unlock() | |
| 525 | + | return o.onModel | |
| 526 | + | } | |
| 527 | + | ||
| 528 | + | // OnSerialNumber registers a handler for the serial_number event. | |
| 529 | + | // | |
| 530 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 531 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 532 | + | func (o *OutputHead) OnSerialNumber(handler func(serialNumber string)) { | |
| 533 | + | if handler == nil { | |
| 534 | + | return | |
| 535 | + | } | |
| 536 | + | o.handlersMu.Lock() | |
| 537 | + | defer o.handlersMu.Unlock() | |
| 538 | + | o.onSerialNumber = append(o.onSerialNumber, handler) | |
| 539 | + | } | |
| 540 | + | ||
| 541 | + | // handlersForSerialNumber returns the handlers registered for serial_number, taken | |
| 542 | + | // under the lock so a handler may register another handler while events are | |
| 543 | + | // being dispatched. | |
| 544 | + | func (o *OutputHead) handlersForSerialNumber() []func(serialNumber string) { | |
| 545 | + | o.handlersMu.Lock() | |
| 546 | + | defer o.handlersMu.Unlock() | |
| 547 | + | return o.onSerialNumber | |
| 548 | + | } | |
| 549 | + | ||
| 550 | + | // OnAdaptiveSync registers a handler for the adaptive_sync event. | |
| 551 | + | // | |
| 552 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 553 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 554 | + | func (o *OutputHead) OnAdaptiveSync(handler func(state uint32)) { | |
| 555 | + | if handler == nil { | |
| 556 | + | return | |
| 557 | + | } | |
| 558 | + | o.handlersMu.Lock() | |
| 559 | + | defer o.handlersMu.Unlock() | |
| 560 | + | o.onAdaptiveSync = append(o.onAdaptiveSync, handler) | |
| 561 | + | } | |
| 562 | + | ||
| 563 | + | // handlersForAdaptiveSync returns the handlers registered for adaptive_sync, taken | |
| 564 | + | // under the lock so a handler may register another handler while events are | |
| 565 | + | // being dispatched. | |
| 566 | + | func (o *OutputHead) handlersForAdaptiveSync() []func(state uint32) { | |
| 567 | + | o.handlersMu.Lock() | |
| 568 | + | defer o.handlersMu.Unlock() | |
| 569 | + | return o.onAdaptiveSync | |
| 570 | + | } | |
| 571 | + | ||
| 572 | + | // EventSignature returns the declared event argument types in wire order. | |
| 573 | + | func (o *OutputHead) EventSignature(opcode uint16) (string, bool) { | |
| 574 | + | switch opcode { | |
| 575 | + | case 0: | |
| 576 | + | return "string,", true | |
| 577 | + | case 1: | |
| 578 | + | return "string,", true | |
| 579 | + | case 2: | |
| 580 | + | return "int,int,", true | |
| 581 | + | case 3: | |
| 582 | + | return "new_id,", true | |
| 583 | + | case 4: | |
| 584 | + | return "int,", true | |
| 585 | + | case 5: | |
| 586 | + | return "object,", true | |
| 587 | + | case 6: | |
| 588 | + | return "int,int,", true | |
| 589 | + | case 7: | |
| 590 | + | return "int,", true | |
| 591 | + | case 8: | |
| 592 | + | return "fixed,", true | |
| 593 | + | case 9: | |
| 594 | + | return "", true | |
| 595 | + | case 10: | |
| 596 | + | return "string,", true | |
| 597 | + | case 11: | |
| 598 | + | return "string,", true | |
| 599 | + | case 12: | |
| 600 | + | return "string,", true | |
| 601 | + | case 13: | |
| 602 | + | return "uint,", true | |
| 603 | + | default: | |
| 604 | + | return "", false | |
| 605 | + | } | |
| 606 | + | } | |
| 607 | + | ||
| 608 | + | // Dispatch decodes one event on zwlr_output_head_v1 and calls the registered handlers. | |
| 609 | + | func (o *OutputHead) Dispatch(event *wl.Event) { | |
| 610 | + | switch event.Opcode { | |
| 611 | + | case 0: // name | |
| 612 | + | name := event.String() | |
| 613 | + | ||
| 614 | + | for i, handler := range o.handlersForName() { | |
| 615 | + | _ = i | |
| 616 | + | handler(name) | |
| 617 | + | } | |
| 618 | + | case 1: // description | |
| 619 | + | description := event.String() | |
| 620 | + | ||
| 621 | + | for i, handler := range o.handlersForDescription() { | |
| 622 | + | _ = i | |
| 623 | + | handler(description) | |
| 624 | + | } | |
| 625 | + | case 2: // physical_size | |
| 626 | + | width := event.Int32() | |
| 627 | + | height := event.Int32() | |
| 628 | + | ||
| 629 | + | for i, handler := range o.handlersForPhysicalSize() { | |
| 630 | + | _ = i | |
| 631 | + | handler(width, height) | |
| 632 | + | } | |
| 633 | + | case 3: // mode | |
| 634 | + | modeID := event.Uint32() | |
| 635 | + | modeObject := &OutputMode{} | |
| 636 | + | modeObject.SetContext(o.Context()) | |
| 637 | + | modeObject.SetID(modeID) | |
| 638 | + | modeObject.SetVersion(o.Version()) | |
| 639 | + | o.Context().Register(modeObject) | |
| 640 | + | ||
| 641 | + | for i, handler := range o.handlersForMode() { | |
| 642 | + | _ = i | |
| 643 | + | handler(modeObject) | |
| 644 | + | } | |
| 645 | + | case 4: // enabled | |
| 646 | + | enabled := event.Int32() | |
| 647 | + | ||
| 648 | + | for i, handler := range o.handlersForEnabled() { | |
| 649 | + | _ = i | |
| 650 | + | handler(enabled) | |
| 651 | + | } | |
| 652 | + | case 5: // current_mode | |
| 653 | + | modeID := event.Uint32() | |
| 654 | + | ||
| 655 | + | for i, handler := range o.handlersForCurrentMode() { | |
| 656 | + | _ = i | |
| 657 | + | handler(modeID) | |
| 658 | + | } | |
| 659 | + | case 6: // position | |
| 660 | + | x := event.Int32() | |
| 661 | + | y := event.Int32() | |
| 662 | + | ||
| 663 | + | for i, handler := range o.handlersForPosition() { | |
| 664 | + | _ = i | |
| 665 | + | handler(x, y) | |
| 666 | + | } | |
| 667 | + | case 7: // transform | |
| 668 | + | transform := event.Int32() | |
| 669 | + | ||
| 670 | + | for i, handler := range o.handlersForTransform() { | |
| 671 | + | _ = i | |
| 672 | + | handler(transform) | |
| 673 | + | } | |
| 674 | + | case 8: // scale | |
| 675 | + | scale := event.Fixed() | |
| 676 | + | ||
| 677 | + | for i, handler := range o.handlersForScale() { | |
| 678 | + | _ = i | |
| 679 | + | handler(scale) | |
| 680 | + | } | |
| 681 | + | case 9: // finished | |
| 682 | + | ||
| 683 | + | for i, handler := range o.handlersForFinished() { | |
| 684 | + | _ = i | |
| 685 | + | handler() | |
| 686 | + | } | |
| 687 | + | case 10: // make | |
| 688 | + | make := event.String() | |
| 689 | + | ||
| 690 | + | for i, handler := range o.handlersForMake() { | |
| 691 | + | _ = i | |
| 692 | + | handler(make) | |
| 693 | + | } | |
| 694 | + | case 11: // model | |
| 695 | + | model := event.String() | |
| 696 | + | ||
| 697 | + | for i, handler := range o.handlersForModel() { | |
| 698 | + | _ = i | |
| 699 | + | handler(model) | |
| 700 | + | } | |
| 701 | + | case 12: // serial_number | |
| 702 | + | serialNumber := event.String() | |
| 703 | + | ||
| 704 | + | for i, handler := range o.handlersForSerialNumber() { | |
| 705 | + | _ = i | |
| 706 | + | handler(serialNumber) | |
| 707 | + | } | |
| 708 | + | case 13: // adaptive_sync | |
| 709 | + | state := event.Uint32() | |
| 710 | + | ||
| 711 | + | for i, handler := range o.handlersForAdaptiveSync() { | |
| 712 | + | _ = i | |
| 713 | + | handler(state) | |
| 714 | + | } | |
| 715 | + | default: | |
| 716 | + | } | |
| 717 | + | } | |
| 718 | + | ||
| 719 | + | // OutputModeInterface is the protocol interface name. | |
| 720 | + | const OutputModeInterface = "zwlr_output_mode_v1" | |
| 721 | + | ||
| 722 | + | // OutputMode is the generated binding for zwlr_output_mode_v1 version 3. | |
| 723 | + | type OutputMode struct { | |
| 724 | + | wl.BaseProxy | |
| 725 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 726 | + | // handlers while another goroutine dispatches events. | |
| 727 | + | handlersMu sync.Mutex | |
| 728 | + | onSize []func(width int32, height int32) | |
| 729 | + | onRefresh []func(refresh int32) | |
| 730 | + | onPreferred []func() | |
| 731 | + | onFinished []func() | |
| 732 | + | } | |
| 733 | + | ||
| 734 | + | // NewOutputMode returns an unbound OutputMode. | |
| 735 | + | func NewOutputMode(ctx *wl.Context) *OutputMode { | |
| 736 | + | obj := &OutputMode{} | |
| 737 | + | obj.SetContext(ctx) | |
| 738 | + | ctx.Register(obj) | |
| 739 | + | return obj | |
| 740 | + | } | |
| 741 | + | ||
| 742 | + | // This request indicates that the client will no longer use this mode object. | |
| 743 | + | func (o *OutputMode) Release() error { | |
| 744 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_output_mode_v1.release", Since: 3, Destructor: true}); err != nil { | |
| 745 | + | return err | |
| 746 | + | } | |
| 747 | + | return nil | |
| 748 | + | } | |
| 749 | + | ||
| 750 | + | // OnSize registers a handler for the size event. | |
| 751 | + | // | |
| 752 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 753 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 754 | + | func (o *OutputMode) OnSize(handler func(width int32, height int32)) { | |
| 755 | + | if handler == nil { | |
| 756 | + | return | |
| 757 | + | } | |
| 758 | + | o.handlersMu.Lock() | |
| 759 | + | defer o.handlersMu.Unlock() | |
| 760 | + | o.onSize = append(o.onSize, handler) | |
| 761 | + | } | |
| 762 | + | ||
| 763 | + | // handlersForSize returns the handlers registered for size, taken | |
| 764 | + | // under the lock so a handler may register another handler while events are | |
| 765 | + | // being dispatched. | |
| 766 | + | func (o *OutputMode) handlersForSize() []func(width int32, height int32) { | |
| 767 | + | o.handlersMu.Lock() | |
| 768 | + | defer o.handlersMu.Unlock() | |
| 769 | + | return o.onSize | |
| 770 | + | } | |
| 771 | + | ||
| 772 | + | // OnRefresh registers a handler for the refresh event. | |
| 773 | + | // | |
| 774 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 775 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 776 | + | func (o *OutputMode) OnRefresh(handler func(refresh int32)) { | |
| 777 | + | if handler == nil { | |
| 778 | + | return | |
| 779 | + | } | |
| 780 | + | o.handlersMu.Lock() | |
| 781 | + | defer o.handlersMu.Unlock() | |
| 782 | + | o.onRefresh = append(o.onRefresh, handler) | |
| 783 | + | } | |
| 784 | + | ||
| 785 | + | // handlersForRefresh returns the handlers registered for refresh, taken | |
| 786 | + | // under the lock so a handler may register another handler while events are | |
| 787 | + | // being dispatched. | |
| 788 | + | func (o *OutputMode) handlersForRefresh() []func(refresh int32) { | |
| 789 | + | o.handlersMu.Lock() | |
| 790 | + | defer o.handlersMu.Unlock() | |
| 791 | + | return o.onRefresh | |
| 792 | + | } | |
| 793 | + | ||
| 794 | + | // OnPreferred registers a handler for the preferred event. | |
| 795 | + | // | |
| 796 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 797 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 798 | + | func (o *OutputMode) OnPreferred(handler func()) { | |
| 799 | + | if handler == nil { | |
| 800 | + | return | |
| 801 | + | } | |
| 802 | + | o.handlersMu.Lock() | |
| 803 | + | defer o.handlersMu.Unlock() | |
| 804 | + | o.onPreferred = append(o.onPreferred, handler) | |
| 805 | + | } | |
| 806 | + | ||
| 807 | + | // handlersForPreferred returns the handlers registered for preferred, taken | |
| 808 | + | // under the lock so a handler may register another handler while events are | |
| 809 | + | // being dispatched. | |
| 810 | + | func (o *OutputMode) handlersForPreferred() []func() { | |
| 811 | + | o.handlersMu.Lock() | |
| 812 | + | defer o.handlersMu.Unlock() | |
| 813 | + | return o.onPreferred | |
| 814 | + | } | |
| 815 | + | ||
| 816 | + | // OnFinished registers a handler for the finished event. | |
| 817 | + | // | |
| 818 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 819 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 820 | + | func (o *OutputMode) OnFinished(handler func()) { | |
| 821 | + | if handler == nil { | |
| 822 | + | return | |
| 823 | + | } | |
| 824 | + | o.handlersMu.Lock() | |
| 825 | + | defer o.handlersMu.Unlock() | |
| 826 | + | o.onFinished = append(o.onFinished, handler) | |
| 827 | + | } | |
| 828 | + | ||
| 829 | + | // handlersForFinished returns the handlers registered for finished, taken | |
| 830 | + | // under the lock so a handler may register another handler while events are | |
| 831 | + | // being dispatched. | |
| 832 | + | func (o *OutputMode) handlersForFinished() []func() { | |
| 833 | + | o.handlersMu.Lock() | |
| 834 | + | defer o.handlersMu.Unlock() | |
| 835 | + | return o.onFinished | |
| 836 | + | } | |
| 837 | + | ||
| 838 | + | // EventSignature returns the declared event argument types in wire order. | |
| 839 | + | func (o *OutputMode) EventSignature(opcode uint16) (string, bool) { | |
| 840 | + | switch opcode { | |
| 841 | + | case 0: | |
| 842 | + | return "int,int,", true | |
| 843 | + | case 1: | |
| 844 | + | return "int,", true | |
| 845 | + | case 2: | |
| 846 | + | return "", true | |
| 847 | + | case 3: | |
| 848 | + | return "", true | |
| 849 | + | default: | |
| 850 | + | return "", false | |
| 851 | + | } | |
| 852 | + | } | |
| 853 | + | ||
| 854 | + | // Dispatch decodes one event on zwlr_output_mode_v1 and calls the registered handlers. | |
| 855 | + | func (o *OutputMode) Dispatch(event *wl.Event) { | |
| 856 | + | switch event.Opcode { | |
| 857 | + | case 0: // size | |
| 858 | + | width := event.Int32() | |
| 859 | + | height := event.Int32() | |
| 860 | + | ||
| 861 | + | for i, handler := range o.handlersForSize() { | |
| 862 | + | _ = i | |
| 863 | + | handler(width, height) | |
| 864 | + | } | |
| 865 | + | case 1: // refresh | |
| 866 | + | refresh := event.Int32() | |
| 867 | + | ||
| 868 | + | for i, handler := range o.handlersForRefresh() { | |
| 869 | + | _ = i | |
| 870 | + | handler(refresh) | |
| 871 | + | } | |
| 872 | + | case 2: // preferred | |
| 873 | + | ||
| 874 | + | for i, handler := range o.handlersForPreferred() { | |
| 875 | + | _ = i | |
| 876 | + | handler() | |
| 877 | + | } | |
| 878 | + | case 3: // finished | |
| 879 | + | ||
| 880 | + | for i, handler := range o.handlersForFinished() { | |
| 881 | + | _ = i | |
| 882 | + | handler() | |
| 883 | + | } | |
| 884 | + | default: | |
| 885 | + | } | |
| 886 | + | } | |
| 887 | + | ||
| 888 | + | // OutputConfigurationInterface is the protocol interface name. | |
| 889 | + | const OutputConfigurationInterface = "zwlr_output_configuration_v1" | |
| 890 | + | ||
| 891 | + | // OutputConfiguration is the generated binding for zwlr_output_configuration_v1 version 4. | |
| 892 | + | type OutputConfiguration struct { | |
| 893 | + | wl.BaseProxy | |
| 894 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 895 | + | // handlers while another goroutine dispatches events. | |
| 896 | + | handlersMu sync.Mutex | |
| 897 | + | onSucceeded []func() | |
| 898 | + | onFailed []func() | |
| 899 | + | onCancelled []func() | |
| 900 | + | } | |
| 901 | + | ||
| 902 | + | // NewOutputConfiguration returns an unbound OutputConfiguration. | |
| 903 | + | func NewOutputConfiguration(ctx *wl.Context) *OutputConfiguration { | |
| 904 | + | obj := &OutputConfiguration{} | |
| 905 | + | obj.SetContext(ctx) | |
| 906 | + | ctx.Register(obj) | |
| 907 | + | return obj | |
| 908 | + | } | |
| 909 | + | ||
| 910 | + | // Enable a head. This request creates a head configuration object that can be used to change the head's properties. | |
| 911 | + | func (o *OutputConfiguration) EnableHead(head *OutputHead) (*OutputConfigurationHead, error) { | |
| 912 | + | var arg1 wl.Object | |
| 913 | + | if head != nil { | |
| 914 | + | arg1 = head | |
| 915 | + | } | |
| 916 | + | child := &OutputConfigurationHead{} | |
| 917 | + | child.SetContext(o.Context()) | |
| 918 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_output_configuration_v1.enable_head", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 919 | + | return nil, err | |
| 920 | + | } | |
| 921 | + | return child, nil | |
| 922 | + | } | |
| 923 | + | ||
| 924 | + | // Disable a head. | |
| 925 | + | func (o *OutputConfiguration) DisableHead(head *OutputHead) error { | |
| 926 | + | var arg0 wl.Object | |
| 927 | + | if head != nil { | |
| 928 | + | arg0 = head | |
| 929 | + | } | |
| 930 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwlr_output_configuration_v1.disable_head"}, wl.ArgObject(arg0)); err != nil { | |
| 931 | + | return err | |
| 932 | + | } | |
| 933 | + | return nil | |
| 934 | + | } | |
| 935 | + | ||
| 936 | + | // Apply the new output configuration. In case the configuration is successfully applied, there is no guarantee that the new output state matches completely the requested configuration. For instance, a compositor might round the scale if it doesn't support fractional scaling. After this request has been sent, the compositor must respond with an succeeded, failed or cancelled event. Sending a request that isn't the destructor is a protocol error. | |
| 937 | + | func (o *OutputConfiguration) Apply() error { | |
| 938 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwlr_output_configuration_v1.apply"}); err != nil { | |
| 939 | + | return err | |
| 940 | + | } | |
| 941 | + | return nil | |
| 942 | + | } | |
| 943 | + | ||
| 944 | + | // Test the new output configuration. The configuration won't be applied, but will only be validated. Even if the compositor succeeds to test a configuration, applying it may fail. After this request has been sent, the compositor must respond with an succeeded, failed or cancelled event. Sending a request that isn't the destructor is a protocol error. | |
| 945 | + | func (o *OutputConfiguration) Test() error { | |
| 946 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "zwlr_output_configuration_v1.test"}); err != nil { | |
| 947 | + | return err | |
| 948 | + | } | |
| 949 | + | return nil | |
| 950 | + | } | |
| 951 | + | ||
| 952 | + | // Using this request a client can tell the compositor that it is not going to use the configuration object anymore. Any changes to the outputs that have not been applied will be discarded. This request also destroys wlr_output_configuration_head objects created via this object. | |
| 953 | + | func (o *OutputConfiguration) Destroy() error { | |
| 954 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 4, Name: "zwlr_output_configuration_v1.destroy", Destructor: true}); err != nil { | |
| 955 | + | return err | |
| 956 | + | } | |
| 957 | + | return nil | |
| 958 | + | } | |
| 959 | + | ||
| 960 | + | // OnSucceeded registers a handler for the succeeded event. | |
| 961 | + | // | |
| 962 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 963 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 964 | + | func (o *OutputConfiguration) OnSucceeded(handler func()) { | |
| 965 | + | if handler == nil { | |
| 966 | + | return | |
| 967 | + | } | |
| 968 | + | o.handlersMu.Lock() | |
| 969 | + | defer o.handlersMu.Unlock() | |
| 970 | + | o.onSucceeded = append(o.onSucceeded, handler) | |
| 971 | + | } | |
| 972 | + | ||
| 973 | + | // handlersForSucceeded returns the handlers registered for succeeded, taken | |
| 974 | + | // under the lock so a handler may register another handler while events are | |
| 975 | + | // being dispatched. | |
| 976 | + | func (o *OutputConfiguration) handlersForSucceeded() []func() { | |
| 977 | + | o.handlersMu.Lock() | |
| 978 | + | defer o.handlersMu.Unlock() | |
| 979 | + | return o.onSucceeded | |
| 980 | + | } | |
| 981 | + | ||
| 982 | + | // OnFailed registers a handler for the failed event. | |
| 983 | + | // | |
| 984 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 985 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 986 | + | func (o *OutputConfiguration) OnFailed(handler func()) { | |
| 987 | + | if handler == nil { | |
| 988 | + | return | |
| 989 | + | } | |
| 990 | + | o.handlersMu.Lock() | |
| 991 | + | defer o.handlersMu.Unlock() | |
| 992 | + | o.onFailed = append(o.onFailed, handler) | |
| 993 | + | } | |
| 994 | + | ||
| 995 | + | // handlersForFailed returns the handlers registered for failed, taken | |
| 996 | + | // under the lock so a handler may register another handler while events are | |
| 997 | + | // being dispatched. | |
| 998 | + | func (o *OutputConfiguration) handlersForFailed() []func() { | |
| 999 | + | o.handlersMu.Lock() | |
| 1000 | + | defer o.handlersMu.Unlock() | |
| 1001 | + | return o.onFailed | |
| 1002 | + | } | |
| 1003 | + | ||
| 1004 | + | // OnCancelled registers a handler for the cancelled event. | |
| 1005 | + | // | |
| 1006 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 1007 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 1008 | + | func (o *OutputConfiguration) OnCancelled(handler func()) { | |
| 1009 | + | if handler == nil { | |
| 1010 | + | return | |
| 1011 | + | } | |
| 1012 | + | o.handlersMu.Lock() | |
| 1013 | + | defer o.handlersMu.Unlock() | |
| 1014 | + | o.onCancelled = append(o.onCancelled, handler) | |
| 1015 | + | } | |
| 1016 | + | ||
| 1017 | + | // handlersForCancelled returns the handlers registered for cancelled, taken | |
| 1018 | + | // under the lock so a handler may register another handler while events are | |
| 1019 | + | // being dispatched. | |
| 1020 | + | func (o *OutputConfiguration) handlersForCancelled() []func() { | |
| 1021 | + | o.handlersMu.Lock() | |
| 1022 | + | defer o.handlersMu.Unlock() | |
| 1023 | + | return o.onCancelled | |
| 1024 | + | } | |
| 1025 | + | ||
| 1026 | + | // EventSignature returns the declared event argument types in wire order. | |
| 1027 | + | func (o *OutputConfiguration) EventSignature(opcode uint16) (string, bool) { | |
| 1028 | + | switch opcode { | |
| 1029 | + | case 0: | |
| 1030 | + | return "", true | |
| 1031 | + | case 1: | |
| 1032 | + | return "", true | |
| 1033 | + | case 2: | |
| 1034 | + | return "", true | |
| 1035 | + | default: | |
| 1036 | + | return "", false | |
| 1037 | + | } | |
| 1038 | + | } | |
| 1039 | + | ||
| 1040 | + | // Dispatch decodes one event on zwlr_output_configuration_v1 and calls the registered handlers. | |
| 1041 | + | func (o *OutputConfiguration) Dispatch(event *wl.Event) { | |
| 1042 | + | switch event.Opcode { | |
| 1043 | + | case 0: // succeeded | |
| 1044 | + | ||
| 1045 | + | for i, handler := range o.handlersForSucceeded() { | |
| 1046 | + | _ = i | |
| 1047 | + | handler() | |
| 1048 | + | } | |
| 1049 | + | case 1: // failed | |
| 1050 | + | ||
| 1051 | + | for i, handler := range o.handlersForFailed() { | |
| 1052 | + | _ = i | |
| 1053 | + | handler() | |
| 1054 | + | } | |
| 1055 | + | case 2: // cancelled | |
| 1056 | + | ||
| 1057 | + | for i, handler := range o.handlersForCancelled() { | |
| 1058 | + | _ = i | |
| 1059 | + | handler() | |
| 1060 | + | } | |
| 1061 | + | default: | |
| 1062 | + | } | |
| 1063 | + | } | |
| 1064 | + | ||
| 1065 | + | // OutputConfigurationHeadInterface is the protocol interface name. | |
| 1066 | + | const OutputConfigurationHeadInterface = "zwlr_output_configuration_head_v1" | |
| 1067 | + | ||
| 1068 | + | // OutputConfigurationHead is the generated binding for zwlr_output_configuration_head_v1 version 4. | |
| 1069 | + | type OutputConfigurationHead struct { | |
| 1070 | + | wl.BaseProxy | |
| 1071 | + | } | |
| 1072 | + | ||
| 1073 | + | // NewOutputConfigurationHead returns an unbound OutputConfigurationHead. | |
| 1074 | + | func NewOutputConfigurationHead(ctx *wl.Context) *OutputConfigurationHead { | |
| 1075 | + | obj := &OutputConfigurationHead{} | |
| 1076 | + | obj.SetContext(ctx) | |
| 1077 | + | ctx.Register(obj) | |
| 1078 | + | return obj | |
| 1079 | + | } | |
| 1080 | + | ||
| 1081 | + | // This request sets the head's mode. | |
| 1082 | + | func (o *OutputConfigurationHead) SetMode(mode *OutputMode) error { | |
| 1083 | + | var arg0 wl.Object | |
| 1084 | + | if mode != nil { | |
| 1085 | + | arg0 = mode | |
| 1086 | + | } | |
| 1087 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_output_configuration_head_v1.set_mode"}, wl.ArgObject(arg0)); err != nil { | |
| 1088 | + | return err | |
| 1089 | + | } | |
| 1090 | + | return nil | |
| 1091 | + | } | |
| 1092 | + | ||
| 1093 | + | // This request assigns a custom mode to the head. The size is given in physical hardware units of the output device. If set to zero, the refresh rate is unspecified. It is a protocol error to set both a mode and a custom mode. | |
| 1094 | + | func (o *OutputConfigurationHead) SetCustomMode(width int32, height int32, refresh int32) error { | |
| 1095 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwlr_output_configuration_head_v1.set_custom_mode"}, wl.ArgInt(width), wl.ArgInt(height), wl.ArgInt(refresh)); err != nil { | |
| 1096 | + | return err | |
| 1097 | + | } | |
| 1098 | + | return nil | |
| 1099 | + | } | |
| 1100 | + | ||
| 1101 | + | // This request sets the head's position in the global compositor space. | |
| 1102 | + | func (o *OutputConfigurationHead) SetPosition(x int32, y int32) error { | |
| 1103 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwlr_output_configuration_head_v1.set_position"}, wl.ArgInt(x), wl.ArgInt(y)); err != nil { | |
| 1104 | + | return err | |
| 1105 | + | } | |
| 1106 | + | return nil | |
| 1107 | + | } | |
| 1108 | + | ||
| 1109 | + | // This request sets the head's transform. | |
| 1110 | + | func (o *OutputConfigurationHead) SetTransform(transform int32) error { | |
| 1111 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "zwlr_output_configuration_head_v1.set_transform"}, wl.ArgInt(transform)); err != nil { | |
| 1112 | + | return err | |
| 1113 | + | } | |
| 1114 | + | return nil | |
| 1115 | + | } | |
| 1116 | + | ||
| 1117 | + | // This request sets the head's scale. | |
| 1118 | + | func (o *OutputConfigurationHead) SetScale(scale wl.Fixed) error { | |
| 1119 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 4, Name: "zwlr_output_configuration_head_v1.set_scale"}, wl.ArgFixed(scale)); err != nil { | |
| 1120 | + | return err | |
| 1121 | + | } | |
| 1122 | + | return nil | |
| 1123 | + | } | |
| 1124 | + | ||
| 1125 | + | // This request enables/disables adaptive sync. Adaptive sync is also known as Variable Refresh Rate or VRR. | |
| 1126 | + | func (o *OutputConfigurationHead) SetAdaptiveSync(state uint32) error { | |
| 1127 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 5, Name: "zwlr_output_configuration_head_v1.set_adaptive_sync", Since: 4}, wl.ArgUint(state)); err != nil { | |
| 1128 | + | return err | |
| 1129 | + | } | |
| 1130 | + | return nil | |
| 1131 | + | } | |
| 1132 | + | ||
| 1133 | + | // EventSignature returns the declared event argument types in wire order. | |
| 1134 | + | func (o *OutputConfigurationHead) EventSignature(opcode uint16) (string, bool) { | |
| 1135 | + | switch opcode { | |
| 1136 | + | default: | |
| 1137 | + | return "", false | |
| 1138 | + | } | |
| 1139 | + | } | |
| 1140 | + | ||
| 1141 | + | // Dispatch decodes one event on zwlr_output_configuration_head_v1 and calls the registered handlers. | |
| 1142 | + | func (o *OutputConfigurationHead) Dispatch(event *wl.Event) { | |
| 1143 | + | switch event.Opcode { | |
| 1144 | + | default: | |
| 1145 | + | } | |
| 1146 | + | } | |
A protocol/outputpower/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package outputpower | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p outputpower -o wlr-output-power-management-unstable-v1_generated.go -import wl_output=github.com/bnema/wlturbo/protocol/core wlr-output-power-management-unstable-v1.xml | |
A protocol/outputpower/wlr-output-power-management-unstable-v1.xml +128 -0
| @@ -0,0 +1,128 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="wlr_output_power_management_unstable_v1"> | |
| 3 | + | <copyright> | |
| 4 | + | Copyright © 2019 Purism SPC | |
| 5 | + | ||
| 6 | + | Permission is hereby granted, free of charge, to any person obtaining a | |
| 7 | + | copy of this software and associated documentation files (the "Software"), | |
| 8 | + | to deal in the Software without restriction, including without limitation | |
| 9 | + | the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 10 | + | and/or sell copies of the Software, and to permit persons to whom the | |
| 11 | + | Software is furnished to do so, subject to the following conditions: | |
| 12 | + | ||
| 13 | + | The above copyright notice and this permission notice (including the next | |
| 14 | + | paragraph) shall be included in all copies or substantial portions of the | |
| 15 | + | Software. | |
| 16 | + | ||
| 17 | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 18 | + | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 19 | + | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 20 | + | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 21 | + | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 22 | + | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 23 | + | DEALINGS IN THE SOFTWARE. | |
| 24 | + | </copyright> | |
| 25 | + | ||
| 26 | + | <description summary="Control power management modes of outputs"> | |
| 27 | + | This protocol allows clients to control power management modes | |
| 28 | + | of outputs that are currently part of the compositor space. The | |
| 29 | + | intent is to allow special clients like desktop shells to power | |
| 30 | + | down outputs when the system is idle. | |
| 31 | + | ||
| 32 | + | To modify outputs not currently part of the compositor space see | |
| 33 | + | wlr-output-management. | |
| 34 | + | ||
| 35 | + | Warning! The protocol described in this file is experimental and | |
| 36 | + | backward incompatible changes may be made. Backward compatible changes | |
| 37 | + | may be added together with the corresponding interface version bump. | |
| 38 | + | Backward incompatible changes are done by bumping the version number in | |
| 39 | + | the protocol and interface names and resetting the interface version. | |
| 40 | + | Once the protocol is to be declared stable, the 'z' prefix and the | |
| 41 | + | version number in the protocol and interface names are removed and the | |
| 42 | + | interface version number is reset. | |
| 43 | + | </description> | |
| 44 | + | ||
| 45 | + | <interface name="zwlr_output_power_manager_v1" version="1"> | |
| 46 | + | <description summary="manager to create per-output power management"> | |
| 47 | + | This interface is a manager that allows creating per-output power | |
| 48 | + | management mode controls. | |
| 49 | + | </description> | |
| 50 | + | ||
| 51 | + | <request name="get_output_power"> | |
| 52 | + | <description summary="get a power management for an output"> | |
| 53 | + | Create an output power management mode control that can be used to | |
| 54 | + | adjust the power management mode for a given output. | |
| 55 | + | </description> | |
| 56 | + | <arg name="id" type="new_id" interface="zwlr_output_power_v1"/> | |
| 57 | + | <arg name="output" type="object" interface="wl_output"/> | |
| 58 | + | </request> | |
| 59 | + | ||
| 60 | + | <request name="destroy" type="destructor"> | |
| 61 | + | <description summary="destroy the manager"> | |
| 62 | + | All objects created by the manager will still remain valid, until their | |
| 63 | + | appropriate destroy request has been called. | |
| 64 | + | </description> | |
| 65 | + | </request> | |
| 66 | + | </interface> | |
| 67 | + | ||
| 68 | + | <interface name="zwlr_output_power_v1" version="1"> | |
| 69 | + | <description summary="adjust power management mode for an output"> | |
| 70 | + | This object offers requests to set the power management mode of | |
| 71 | + | an output. | |
| 72 | + | </description> | |
| 73 | + | ||
| 74 | + | <enum name="mode"> | |
| 75 | + | <entry name="off" value="0" | |
| 76 | + | summary="Output is turned off."/> | |
| 77 | + | <entry name="on" value="1" | |
| 78 | + | summary="Output is turned on, no power saving"/> | |
| 79 | + | </enum> | |
| 80 | + | ||
| 81 | + | <enum name="error"> | |
| 82 | + | <entry name="invalid_mode" value="1" summary="nonexistent power save mode"/> | |
| 83 | + | </enum> | |
| 84 | + | ||
| 85 | + | <request name="set_mode"> | |
| 86 | + | <description summary="Set an outputs power save mode"> | |
| 87 | + | Set an output's power save mode to the given mode. The mode change | |
| 88 | + | is effective immediately. If the output does not support the given | |
| 89 | + | mode a failed event is sent. | |
| 90 | + | </description> | |
| 91 | + | <arg name="mode" type="uint" enum="mode" summary="the power save mode to set"/> | |
| 92 | + | </request> | |
| 93 | + | ||
| 94 | + | <event name="mode"> | |
| 95 | + | <description summary="Report a power management mode change"> | |
| 96 | + | Report the power management mode change of an output. | |
| 97 | + | ||
| 98 | + | The mode event is sent after an output changed its power | |
| 99 | + | management mode. The reason can be a client using set_mode or the | |
| 100 | + | compositor deciding to change an output's mode. | |
| 101 | + | This event is also sent immediately when the object is created | |
| 102 | + | so the client is informed about the current power management mode. | |
| 103 | + | </description> | |
| 104 | + | <arg name="mode" type="uint" enum="mode" | |
| 105 | + | summary="the output's new power management mode"/> | |
| 106 | + | </event> | |
| 107 | + | ||
| 108 | + | <event name="failed"> | |
| 109 | + | <description summary="object no longer valid"> | |
| 110 | + | This event indicates that the output power management mode control | |
| 111 | + | is no longer valid. This can happen for a number of reasons, | |
| 112 | + | including: | |
| 113 | + | - The output doesn't support power management | |
| 114 | + | - Another client already has exclusive power management mode control | |
| 115 | + | for this output | |
| 116 | + | - The output disappeared | |
| 117 | + | ||
| 118 | + | Upon receiving this event, the client should destroy this object. | |
| 119 | + | </description> | |
| 120 | + | </event> | |
| 121 | + | ||
| 122 | + | <request name="destroy" type="destructor"> | |
| 123 | + | <description summary="destroy this power management"> | |
| 124 | + | Destroys the output power management mode control object. | |
| 125 | + | </description> | |
| 126 | + | </request> | |
| 127 | + | </interface> | |
| 128 | + | </protocol> | |
A protocol/outputpower/wlr-output-power-management-unstable-v1_generated.go +209 -0
| @@ -0,0 +1,209 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: wlr_output_power_management_unstable_v1 | |
| 3 | + | // Source: wlr-output-power-management-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2019 Purism SPC | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package outputpower | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | "sync" | |
| 31 | + | ||
| 32 | + | cross_wl_output "github.com/bnema/wlturbo/protocol/core" | |
| 33 | + | "github.com/bnema/wlturbo/wl" | |
| 34 | + | ) | |
| 35 | + | ||
| 36 | + | // MODE_OFF is the mode off value. | |
| 37 | + | const MODE_OFF = 0 | |
| 38 | + | ||
| 39 | + | // MODE_ON is the mode on value. | |
| 40 | + | const MODE_ON = 1 | |
| 41 | + | ||
| 42 | + | // ERROR_INVALID_MODE is the error invalid_mode value. | |
| 43 | + | const ERROR_INVALID_MODE = 1 | |
| 44 | + | ||
| 45 | + | // OutputPowerManagerInterface is the protocol interface name. | |
| 46 | + | const OutputPowerManagerInterface = "zwlr_output_power_manager_v1" | |
| 47 | + | ||
| 48 | + | // OutputPowerManager is the generated binding for zwlr_output_power_manager_v1 version 1. | |
| 49 | + | type OutputPowerManager struct { | |
| 50 | + | wl.BaseProxy | |
| 51 | + | } | |
| 52 | + | ||
| 53 | + | // NewOutputPowerManager returns an unbound OutputPowerManager. | |
| 54 | + | func NewOutputPowerManager(ctx *wl.Context) *OutputPowerManager { | |
| 55 | + | obj := &OutputPowerManager{} | |
| 56 | + | obj.SetContext(ctx) | |
| 57 | + | ctx.Register(obj) | |
| 58 | + | return obj | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | // Create an output power management mode control that can be used to adjust the power management mode for a given output. | |
| 62 | + | func (o *OutputPowerManager) GetOutputPower(output *cross_wl_output.Output) (*OutputPower, error) { | |
| 63 | + | var arg1 wl.Object | |
| 64 | + | if output != nil { | |
| 65 | + | arg1 = output | |
| 66 | + | } | |
| 67 | + | child := &OutputPower{} | |
| 68 | + | child.SetContext(o.Context()) | |
| 69 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_output_power_manager_v1.get_output_power", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 70 | + | return nil, err | |
| 71 | + | } | |
| 72 | + | return child, nil | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | // All objects created by the manager will still remain valid, until their appropriate destroy request has been called. | |
| 76 | + | func (o *OutputPowerManager) Destroy() error { | |
| 77 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwlr_output_power_manager_v1.destroy", Destructor: true}); err != nil { | |
| 78 | + | return err | |
| 79 | + | } | |
| 80 | + | return nil | |
| 81 | + | } | |
| 82 | + | ||
| 83 | + | // EventSignature returns the declared event argument types in wire order. | |
| 84 | + | func (o *OutputPowerManager) EventSignature(opcode uint16) (string, bool) { | |
| 85 | + | switch opcode { | |
| 86 | + | default: | |
| 87 | + | return "", false | |
| 88 | + | } | |
| 89 | + | } | |
| 90 | + | ||
| 91 | + | // Dispatch decodes one event on zwlr_output_power_manager_v1 and calls the registered handlers. | |
| 92 | + | func (o *OutputPowerManager) Dispatch(event *wl.Event) { | |
| 93 | + | switch event.Opcode { | |
| 94 | + | default: | |
| 95 | + | } | |
| 96 | + | } | |
| 97 | + | ||
| 98 | + | // OutputPowerInterface is the protocol interface name. | |
| 99 | + | const OutputPowerInterface = "zwlr_output_power_v1" | |
| 100 | + | ||
| 101 | + | // OutputPower is the generated binding for zwlr_output_power_v1 version 1. | |
| 102 | + | type OutputPower struct { | |
| 103 | + | wl.BaseProxy | |
| 104 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 105 | + | // handlers while another goroutine dispatches events. | |
| 106 | + | handlersMu sync.Mutex | |
| 107 | + | onMode []func(mode uint32) | |
| 108 | + | onFailed []func() | |
| 109 | + | } | |
| 110 | + | ||
| 111 | + | // NewOutputPower returns an unbound OutputPower. | |
| 112 | + | func NewOutputPower(ctx *wl.Context) *OutputPower { | |
| 113 | + | obj := &OutputPower{} | |
| 114 | + | obj.SetContext(ctx) | |
| 115 | + | ctx.Register(obj) | |
| 116 | + | return obj | |
| 117 | + | } | |
| 118 | + | ||
| 119 | + | // Set an output's power save mode to the given mode. The mode change is effective immediately. If the output does not support the given mode a failed event is sent. | |
| 120 | + | func (o *OutputPower) SetMode(mode uint32) error { | |
| 121 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwlr_output_power_v1.set_mode"}, wl.ArgUint(mode)); err != nil { | |
| 122 | + | return err | |
| 123 | + | } | |
| 124 | + | return nil | |
| 125 | + | } | |
| 126 | + | ||
| 127 | + | // Destroys the output power management mode control object. | |
| 128 | + | func (o *OutputPower) Destroy() error { | |
| 129 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwlr_output_power_v1.destroy", Destructor: true}); err != nil { | |
| 130 | + | return err | |
| 131 | + | } | |
| 132 | + | return nil | |
| 133 | + | } | |
| 134 | + | ||
| 135 | + | // OnMode registers a handler for the mode event. | |
| 136 | + | // | |
| 137 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 138 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 139 | + | func (o *OutputPower) OnMode(handler func(mode uint32)) { | |
| 140 | + | if handler == nil { | |
| 141 | + | return | |
| 142 | + | } | |
| 143 | + | o.handlersMu.Lock() | |
| 144 | + | defer o.handlersMu.Unlock() | |
| 145 | + | o.onMode = append(o.onMode, handler) | |
| 146 | + | } | |
| 147 | + | ||
| 148 | + | // handlersForMode returns the handlers registered for mode, taken | |
| 149 | + | // under the lock so a handler may register another handler while events are | |
| 150 | + | // being dispatched. | |
| 151 | + | func (o *OutputPower) handlersForMode() []func(mode uint32) { | |
| 152 | + | o.handlersMu.Lock() | |
| 153 | + | defer o.handlersMu.Unlock() | |
| 154 | + | return o.onMode | |
| 155 | + | } | |
| 156 | + | ||
| 157 | + | // OnFailed registers a handler for the failed event. | |
| 158 | + | // | |
| 159 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 160 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 161 | + | func (o *OutputPower) OnFailed(handler func()) { | |
| 162 | + | if handler == nil { | |
| 163 | + | return | |
| 164 | + | } | |
| 165 | + | o.handlersMu.Lock() | |
| 166 | + | defer o.handlersMu.Unlock() | |
| 167 | + | o.onFailed = append(o.onFailed, handler) | |
| 168 | + | } | |
| 169 | + | ||
| 170 | + | // handlersForFailed returns the handlers registered for failed, taken | |
| 171 | + | // under the lock so a handler may register another handler while events are | |
| 172 | + | // being dispatched. | |
| 173 | + | func (o *OutputPower) handlersForFailed() []func() { | |
| 174 | + | o.handlersMu.Lock() | |
| 175 | + | defer o.handlersMu.Unlock() | |
| 176 | + | return o.onFailed | |
| 177 | + | } | |
| 178 | + | ||
| 179 | + | // EventSignature returns the declared event argument types in wire order. | |
| 180 | + | func (o *OutputPower) EventSignature(opcode uint16) (string, bool) { | |
| 181 | + | switch opcode { | |
| 182 | + | case 0: | |
| 183 | + | return "uint,", true | |
| 184 | + | case 1: | |
| 185 | + | return "", true | |
| 186 | + | default: | |
| 187 | + | return "", false | |
| 188 | + | } | |
| 189 | + | } | |
| 190 | + | ||
| 191 | + | // Dispatch decodes one event on zwlr_output_power_v1 and calls the registered handlers. | |
| 192 | + | func (o *OutputPower) Dispatch(event *wl.Event) { | |
| 193 | + | switch event.Opcode { | |
| 194 | + | case 0: // mode | |
| 195 | + | mode := event.Uint32() | |
| 196 | + | ||
| 197 | + | for i, handler := range o.handlersForMode() { | |
| 198 | + | _ = i | |
| 199 | + | handler(mode) | |
| 200 | + | } | |
| 201 | + | case 1: // failed | |
| 202 | + | ||
| 203 | + | for i, handler := range o.handlersForFailed() { | |
| 204 | + | _ = i | |
| 205 | + | handler() | |
| 206 | + | } | |
| 207 | + | default: | |
| 208 | + | } | |
| 209 | + | } | |
A protocol/performance_test.go +393 -0
| @@ -0,0 +1,393 @@ | |||
| 1 | + | //go:build linux | |
| 2 | + | ||
| 3 | + | package protocol_test | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "encoding/binary" | |
| 7 | + | "net" | |
| 8 | + | "os" | |
| 9 | + | "testing" | |
| 10 | + | "time" | |
| 11 | + | ||
| 12 | + | "github.com/bnema/wlturbo" | |
| 13 | + | "github.com/bnema/wlturbo/protocol/core" | |
| 14 | + | "github.com/bnema/wlturbo/protocol/cursorshape" | |
| 15 | + | "github.com/bnema/wlturbo/protocol/fractionalscale" | |
| 16 | + | "github.com/bnema/wlturbo/protocol/viewporter" | |
| 17 | + | "golang.org/x/sys/unix" | |
| 18 | + | ) | |
| 19 | + | ||
| 20 | + | // Allocation profile of generated bindings, measured against the current | |
| 21 | + | // transport (see the regression tests below for what is pinned): | |
| 22 | + | // | |
| 23 | + | // - Event dispatch of numeric arguments (uint/int/fixed) is allocation-free. | |
| 24 | + | // - Zero-argument requests are allocation-free. | |
| 25 | + | // - Generated requests pass typed wl.Arg values to Context.RequestArgs, so | |
| 26 | + | // numeric requests are allocation-free for every value. (The legacy | |
| 27 | + | // Context.Request boxed each argument into an interface: one heap | |
| 28 | + | // allocation per 32-bit value >= 256, e.g. set_source 4, set_destination | |
| 29 | + | // 2, set_shape 1 before this path existed.) | |
| 30 | + | // - Allocations that are inherent to the operation are kept separate below: | |
| 31 | + | // new_id child creation (proxy object + map entries), received strings | |
| 32 | + | // (Event.String copies), and received file descriptors (OwnedFD). | |
| 33 | + | ||
| 34 | + | // loopConn is an in-memory net.Conn. Reads replay a fixed byte pattern made of | |
| 35 | + | // whole frames (never splitting one), and writes are discarded, so a benchmark | |
| 36 | + | // measures generated-binding and transport cost without socket scheduling. | |
| 37 | + | type loopConn struct{ pattern []byte } | |
| 38 | + | ||
| 39 | + | func (c *loopConn) Read(p []byte) (int, error) { | |
| 40 | + | n := len(p) / len(c.pattern) * len(c.pattern) | |
| 41 | + | if n == 0 { | |
| 42 | + | return 0, net.ErrClosed | |
| 43 | + | } | |
| 44 | + | for off := 0; off < n; off += len(c.pattern) { | |
| 45 | + | copy(p[off:], c.pattern) | |
| 46 | + | } | |
| 47 | + | return n, nil | |
| 48 | + | } | |
| 49 | + | func (c *loopConn) Write(p []byte) (int, error) { return len(p), nil } | |
| 50 | + | func (c *loopConn) Close() error { return nil } | |
| 51 | + | func (c *loopConn) LocalAddr() net.Addr { return loopAddr{} } | |
| 52 | + | func (c *loopConn) RemoteAddr() net.Addr { return loopAddr{} } | |
| 53 | + | func (c *loopConn) SetDeadline(time.Time) error { return nil } | |
| 54 | + | func (c *loopConn) SetReadDeadline(time.Time) error { return nil } | |
| 55 | + | func (c *loopConn) SetWriteDeadline(time.Time) error { return nil } | |
| 56 | + | ||
| 57 | + | type loopAddr struct{} | |
| 58 | + | ||
| 59 | + | func (loopAddr) Network() string { return "loop" } | |
| 60 | + | func (loopAddr) String() string { return "loop" } | |
| 61 | + | ||
| 62 | + | // loopEnv is a display over loopConn with one registered object of each kind | |
| 63 | + | // used by the tests. Tests replay an event by assigning its frame to c.pattern. | |
| 64 | + | type loopEnv struct { | |
| 65 | + | d *wlturbo.Display | |
| 66 | + | c *loopConn | |
| 67 | + | surface *core.Surface | |
| 68 | + | ptr *core.Pointer | |
| 69 | + | output *core.Output | |
| 70 | + | vp *viewporter.WpViewport | |
| 71 | + | shape *cursorshape.WpCursorShapeDevice | |
| 72 | + | scale *fractionalscale.WpFractionalScale | |
| 73 | + | vpr *viewporter.WpViewporter | |
| 74 | + | } | |
| 75 | + | ||
| 76 | + | func newLoopEnv(tb testing.TB) *loopEnv { | |
| 77 | + | tb.Helper() | |
| 78 | + | c := &loopConn{pattern: make([]byte, 12)} | |
| 79 | + | d, err := wlturbo.ConnectFromConn(c) | |
| 80 | + | if err != nil { | |
| 81 | + | tb.Fatal(err) | |
| 82 | + | } | |
| 83 | + | tb.Cleanup(func() { d.Close() }) | |
| 84 | + | e := &loopEnv{d: d, c: c} | |
| 85 | + | reg := func(p wlturbo.Proxy) { | |
| 86 | + | p.SetID(d.AllocateID()) | |
| 87 | + | d.Context().Register(p) | |
| 88 | + | } | |
| 89 | + | e.surface = core.NewSurface(d.Context()) | |
| 90 | + | e.ptr = core.NewPointer(d.Context()) | |
| 91 | + | e.output = core.NewOutput(d.Context()) | |
| 92 | + | e.vp = viewporter.NewWpViewport(d.Context()) | |
| 93 | + | e.shape = cursorshape.NewWpCursorShapeDevice(d.Context()) | |
| 94 | + | e.scale = fractionalscale.NewWpFractionalScale(d.Context()) | |
| 95 | + | e.vpr = viewporter.NewWpViewporter(d.Context()) | |
| 96 | + | for _, p := range []wlturbo.Proxy{e.surface, e.ptr, e.output, e.vp, e.shape, e.scale, e.vpr} { | |
| 97 | + | reg(p) | |
| 98 | + | } | |
| 99 | + | return e | |
| 100 | + | } | |
| 101 | + | ||
| 102 | + | // perfFrame encodes one event with 32-bit words as its whole body. | |
| 103 | + | func perfFrame(id uint32, op uint16, words ...uint32) []byte { | |
| 104 | + | b := make([]byte, 8+4*len(words)) | |
| 105 | + | binary.LittleEndian.PutUint32(b, id) | |
| 106 | + | binary.LittleEndian.PutUint32(b[4:], uint32(len(b))<<16|uint32(op)) | |
| 107 | + | for i, v := range words { | |
| 108 | + | binary.LittleEndian.PutUint32(b[8+i*4:], v) | |
| 109 | + | } | |
| 110 | + | return b | |
| 111 | + | } | |
| 112 | + | ||
| 113 | + | // perfStringFrame encodes an event whose only argument is a string. | |
| 114 | + | func perfStringFrame(id uint32, op uint16, s string) []byte { | |
| 115 | + | n := len(s) + 1 | |
| 116 | + | padded := (n + 3) &^ 3 | |
| 117 | + | b := make([]byte, 8+4+padded) | |
| 118 | + | binary.LittleEndian.PutUint32(b, id) | |
| 119 | + | binary.LittleEndian.PutUint32(b[4:], uint32(len(b))<<16|uint32(op)) | |
| 120 | + | binary.LittleEndian.PutUint32(b[8:], uint32(n)) | |
| 121 | + | copy(b[12:], s) | |
| 122 | + | return b | |
| 123 | + | } | |
| 124 | + | ||
| 125 | + | // numericRequests are numeric requests with values that do NOT hit the | |
| 126 | + | // runtime's small-integer boxing table: this is the realistic cost. | |
| 127 | + | func (e *loopEnv) numericRequests() []struct { | |
| 128 | + | name string | |
| 129 | + | args int // number of numeric arguments | |
| 130 | + | run func() error | |
| 131 | + | } { | |
| 132 | + | x, w := wlturbo.NewFixed(10.5), wlturbo.NewFixed(1920) | |
| 133 | + | return []struct { | |
| 134 | + | name string | |
| 135 | + | args int | |
| 136 | + | run func() error | |
| 137 | + | }{ | |
| 138 | + | {"wp_viewport.set_source", 4, func() error { return e.vp.SetSource(x, x, w, w) }}, | |
| 139 | + | {"wp_viewport.set_destination", 2, func() error { return e.vp.SetDestination(1920, 1080) }}, | |
| 140 | + | {"wp_cursor_shape_device_v1.set_shape", 2, func() error { return e.shape.SetShape(123456, cursorshape.SHAPE_POINTER) }}, | |
| 141 | + | {"wl_surface.damage_buffer", 4, func() error { return e.surface.DamageBuffer(0, 0, 1920, 1080) }}, | |
| 142 | + | {"wl_surface.set_buffer_scale", 1, func() error { return e.surface.SetBufferScale(1000) }}, | |
| 143 | + | } | |
| 144 | + | } | |
| 145 | + | ||
| 146 | + | // TestRequestAllocations pins the request-side allocation contract. | |
| 147 | + | func TestRequestAllocations(t *testing.T) { | |
| 148 | + | e := newLoopEnv(t) | |
| 149 | + | run := func(name string, f func() error) float64 { | |
| 150 | + | var err error | |
| 151 | + | n := testing.AllocsPerRun(500, func() { err = f() }) | |
| 152 | + | if err != nil { | |
| 153 | + | t.Fatalf("%s: %v", name, err) | |
| 154 | + | } | |
| 155 | + | return n | |
| 156 | + | } | |
| 157 | + | // Requests without arguments, and numeric requests whose values are | |
| 158 | + | // below 256 (the runtime's static boxing table), are allocation-free. | |
| 159 | + | // Both must stay so, whatever the generator does with arguments. | |
| 160 | + | for _, tc := range []struct { | |
| 161 | + | name string | |
| 162 | + | f func() error | |
| 163 | + | }{ | |
| 164 | + | {"wl_surface.commit", e.surface.Commit}, | |
| 165 | + | {"wl_surface.set_buffer_scale(2)", func() error { return e.surface.SetBufferScale(2) }}, | |
| 166 | + | {"wp_viewport.set_destination(64,32)", func() error { return e.vp.SetDestination(64, 32) }}, | |
| 167 | + | {"wp_cursor_shape_device_v1.set_shape(small)", func() error { return e.shape.SetShape(7, cursorshape.SHAPE_DEFAULT) }}, | |
| 168 | + | } { | |
| 169 | + | if n := run(tc.name, tc.f); n != 0 { | |
| 170 | + | t.Errorf("%s: %v allocs/op, want 0", tc.name, n) | |
| 171 | + | } | |
| 172 | + | } | |
| 173 | + | // Realistic values (outside the runtime's small-integer boxing table) | |
| 174 | + | // travel as typed wl.Arg values and must not allocate either. | |
| 175 | + | for _, tc := range e.numericRequests() { | |
| 176 | + | if n := run(tc.name, tc.run); n != 0 { | |
| 177 | + | t.Errorf("%s: %v allocs/op, want 0 (%d numeric args)", tc.name, n, tc.args) | |
| 178 | + | } | |
| 179 | + | } | |
| 180 | + | } | |
| 181 | + | ||
| 182 | + | // TestNumericEventDispatchAllocationFree pins the event side: framing, | |
| 183 | + | // signature validation, pooled Event and typed handler dispatch for numeric | |
| 184 | + | // arguments must not allocate. | |
| 185 | + | func TestNumericEventDispatchAllocationFree(t *testing.T) { | |
| 186 | + | // One environment per case: loopConn refills a whole receive chunk, so | |
| 187 | + | // frames of a previous pattern would still be buffered. | |
| 188 | + | for _, tc := range []struct { | |
| 189 | + | name string | |
| 190 | + | setup func(e *loopEnv) (frame []byte, observed func() bool) | |
| 191 | + | }{ | |
| 192 | + | {"wp_fractional_scale_v1.preferred_scale", func(e *loopEnv) ([]byte, func() bool) { | |
| 193 | + | var scale uint32 | |
| 194 | + | e.scale.OnPreferredScale(func(s uint32) { scale = s }) | |
| 195 | + | return perfFrame(e.scale.ID(), 0, 180), func() bool { return scale == 180 } | |
| 196 | + | }}, | |
| 197 | + | {"wl_pointer.motion", func(e *loopEnv) ([]byte, func() bool) { | |
| 198 | + | var tm uint32 | |
| 199 | + | var fx, fy wlturbo.Fixed | |
| 200 | + | e.ptr.OnMotion(func(t uint32, x, y wlturbo.Fixed) { tm, fx, fy = t, x, y }) | |
| 201 | + | return perfFrame(e.ptr.ID(), 2, 1234567, 300*256, 0xffffff00), func() bool { return tm == 1234567 && fx == 300*256 && fy == -256 } | |
| 202 | + | }}, | |
| 203 | + | {"wl_surface.preferred_buffer_scale", func(e *loopEnv) ([]byte, func() bool) { | |
| 204 | + | var factor int32 | |
| 205 | + | e.surface.OnPreferredBufferScale(func(f int32) { factor = f }) | |
| 206 | + | return perfFrame(e.surface.ID(), 2, 3), func() bool { return factor == 3 } | |
| 207 | + | }}, | |
| 208 | + | } { | |
| 209 | + | t.Run(tc.name, func(t *testing.T) { | |
| 210 | + | e := newLoopEnv(t) | |
| 211 | + | f, observed := tc.setup(e) | |
| 212 | + | e.c.pattern = f | |
| 213 | + | var derr error | |
| 214 | + | n := testing.AllocsPerRun(1000, func() { | |
| 215 | + | if err := e.d.Dispatch(); err != nil { | |
| 216 | + | derr = err | |
| 217 | + | } | |
| 218 | + | }) | |
| 219 | + | if derr != nil { | |
| 220 | + | t.Fatal(derr) | |
| 221 | + | } | |
| 222 | + | if !observed() { | |
| 223 | + | t.Fatal("handler did not observe the event") | |
| 224 | + | } | |
| 225 | + | if n != 0 { | |
| 226 | + | t.Errorf("%v allocs/op, want 0", n) | |
| 227 | + | } | |
| 228 | + | }) | |
| 229 | + | } | |
| 230 | + | } | |
| 231 | + | ||
| 232 | + | // TestNecessaryAllocations documents allocations that are inherent to the | |
| 233 | + | // operation. They are bounded so they cannot silently grow, but they are not | |
| 234 | + | // expected to reach zero. | |
| 235 | + | func TestNecessaryAllocations(t *testing.T) { | |
| 236 | + | e := newLoopEnv(t) | |
| 237 | + | ||
| 238 | + | // A received string is copied out of the receive buffer: one allocation. | |
| 239 | + | var name string | |
| 240 | + | e.output.OnName(func(s string) { name = s }) | |
| 241 | + | e.c.pattern = perfStringFrame(e.output.ID(), 4, "HDMI-A-1") | |
| 242 | + | n := testing.AllocsPerRun(1000, func() { _ = e.d.Dispatch() }) | |
| 243 | + | if name != "HDMI-A-1" { | |
| 244 | + | t.Fatalf("string event not delivered: %q", name) | |
| 245 | + | } | |
| 246 | + | if n > 1 { | |
| 247 | + | t.Errorf("wl_output.name: %v allocs/op, want <= 1 (the string copy)", n) | |
| 248 | + | } | |
| 249 | + | ||
| 250 | + | // A new_id request creates a proxy and registers it in two maps; that is | |
| 251 | + | // the object-creation cost, reported rather than asserted to be zero. | |
| 252 | + | // The IDs are never released in this loopback, so keep the run short. | |
| 253 | + | n = testing.AllocsPerRun(50, func() { | |
| 254 | + | if _, err := e.vpr.GetViewport(e.surface); err != nil { | |
| 255 | + | t.Fatal(err) | |
| 256 | + | } | |
| 257 | + | }) | |
| 258 | + | t.Logf("wp_viewporter.get_viewport (object creation): %v allocs/op", n) | |
| 259 | + | if n < 1 { | |
| 260 | + | t.Errorf("get_viewport allocated %v; a child proxy must be created", n) | |
| 261 | + | } | |
| 262 | + | } | |
| 263 | + | ||
| 264 | + | // BenchmarkRequests measures generated numeric requests with small and | |
| 265 | + | // realistic values; both are allocation-free. | |
| 266 | + | func BenchmarkRequests(b *testing.B) { | |
| 267 | + | e := newLoopEnv(b) | |
| 268 | + | b.Run("no_args/wl_surface.commit", func(b *testing.B) { | |
| 269 | + | b.ReportAllocs() | |
| 270 | + | for i := 0; i < b.N; i++ { | |
| 271 | + | if err := e.surface.Commit(); err != nil { | |
| 272 | + | b.Fatal(err) | |
| 273 | + | } | |
| 274 | + | } | |
| 275 | + | }) | |
| 276 | + | b.Run("small_values/wl_surface.set_buffer_scale", func(b *testing.B) { | |
| 277 | + | b.ReportAllocs() | |
| 278 | + | for i := 0; i < b.N; i++ { | |
| 279 | + | if err := e.surface.SetBufferScale(2); err != nil { | |
| 280 | + | b.Fatal(err) | |
| 281 | + | } | |
| 282 | + | } | |
| 283 | + | }) | |
| 284 | + | for _, tc := range e.numericRequests() { | |
| 285 | + | b.Run("realistic_values/"+tc.name, func(b *testing.B) { | |
| 286 | + | b.ReportAllocs() | |
| 287 | + | for i := 0; i < b.N; i++ { | |
| 288 | + | if err := tc.run(); err != nil { | |
| 289 | + | b.Fatal(err) | |
| 290 | + | } | |
| 291 | + | } | |
| 292 | + | }) | |
| 293 | + | } | |
| 294 | + | } | |
| 295 | + | ||
| 296 | + | // BenchmarkEventDispatch measures typed numeric event dispatch through the | |
| 297 | + | // generated Dispatch methods, without socket scheduling. | |
| 298 | + | func BenchmarkEventDispatch(b *testing.B) { | |
| 299 | + | e := newLoopEnv(b) | |
| 300 | + | var sink uint32 | |
| 301 | + | e.scale.OnPreferredScale(func(s uint32) { sink += s }) | |
| 302 | + | e.ptr.OnMotion(func(tm uint32, x, y wlturbo.Fixed) { sink += tm + uint32(x) + uint32(y) }) | |
| 303 | + | for _, tc := range []struct { | |
| 304 | + | name string | |
| 305 | + | frame []byte | |
| 306 | + | }{ | |
| 307 | + | {"wp_fractional_scale_v1.preferred_scale", perfFrame(e.scale.ID(), 0, 180)}, | |
| 308 | + | {"wl_pointer.motion", perfFrame(e.ptr.ID(), 2, 1234567, 300*256, 400*256)}, | |
| 309 | + | } { | |
| 310 | + | b.Run("numeric/"+tc.name, func(b *testing.B) { | |
| 311 | + | e.c.pattern = tc.frame | |
| 312 | + | b.ReportAllocs() | |
| 313 | + | for i := 0; i < b.N; i++ { | |
| 314 | + | if err := e.d.Dispatch(); err != nil { | |
| 315 | + | b.Fatal(err) | |
| 316 | + | } | |
| 317 | + | } | |
| 318 | + | }) | |
| 319 | + | } | |
| 320 | + | _ = sink | |
| 321 | + | } | |
| 322 | + | ||
| 323 | + | // BenchmarkNecessaryAllocations reports operations whose allocations cannot be | |
| 324 | + | // removed by the generator: string copies, object creation and received FDs. | |
| 325 | + | func BenchmarkNecessaryAllocations(b *testing.B) { | |
| 326 | + | b.Run("string_event/wl_output.name", func(b *testing.B) { | |
| 327 | + | e := newLoopEnv(b) | |
| 328 | + | var name string | |
| 329 | + | e.output.OnName(func(s string) { name = s }) | |
| 330 | + | e.c.pattern = perfStringFrame(e.output.ID(), 4, "HDMI-A-1") | |
| 331 | + | b.ReportAllocs() | |
| 332 | + | for i := 0; i < b.N; i++ { | |
| 333 | + | if err := e.d.Dispatch(); err != nil { | |
| 334 | + | b.Fatal(err) | |
| 335 | + | } | |
| 336 | + | } | |
| 337 | + | _ = name | |
| 338 | + | }) | |
| 339 | + | b.Run("new_id/wp_viewporter.get_viewport", func(b *testing.B) { | |
| 340 | + | e := newLoopEnv(b) | |
| 341 | + | b.ReportAllocs() | |
| 342 | + | for i := 0; i < b.N; i++ { | |
| 343 | + | if _, err := e.vpr.GetViewport(e.surface); err != nil { | |
| 344 | + | b.Fatal(err) | |
| 345 | + | } | |
| 346 | + | } | |
| 347 | + | }) | |
| 348 | + | b.Run("received_fd/wl_keyboard.keymap", func(b *testing.B) { | |
| 349 | + | fds, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0) | |
| 350 | + | if err != nil { | |
| 351 | + | b.Fatal(err) | |
| 352 | + | } | |
| 353 | + | fa, fb := os.NewFile(uintptr(fds[0]), "a"), os.NewFile(uintptr(fds[1]), "b") | |
| 354 | + | ca, err := net.FileConn(fa) | |
| 355 | + | fa.Close() | |
| 356 | + | if err != nil { | |
| 357 | + | b.Fatal(err) | |
| 358 | + | } | |
| 359 | + | cb, err := net.FileConn(fb) | |
| 360 | + | fb.Close() | |
| 361 | + | if err != nil { | |
| 362 | + | b.Fatal(err) | |
| 363 | + | } | |
| 364 | + | defer cb.Close() | |
| 365 | + | peer := cb.(*net.UnixConn) | |
| 366 | + | d, err := wlturbo.ConnectFromConn(ca) | |
| 367 | + | if err != nil { | |
| 368 | + | b.Fatal(err) | |
| 369 | + | } | |
| 370 | + | defer d.Close() | |
| 371 | + | kb := core.NewKeyboard(d.Context()) | |
| 372 | + | kb.SetID(d.AllocateID()) | |
| 373 | + | d.Context().Register(kb) | |
| 374 | + | kb.OnKeymap(func(format uint32, fd *wlturbo.OwnedFD, size uint32) {}) | |
| 375 | + | // The descriptor sent each iteration; the receiver closes its copy. | |
| 376 | + | null, err := os.Open(os.DevNull) | |
| 377 | + | if err != nil { | |
| 378 | + | b.Fatal(err) | |
| 379 | + | } | |
| 380 | + | defer null.Close() | |
| 381 | + | msg := perfFrame(kb.ID(), 0, 1, 4096) | |
| 382 | + | rights := unix.UnixRights(int(null.Fd())) | |
| 383 | + | b.ReportAllocs() | |
| 384 | + | for i := 0; i < b.N; i++ { | |
| 385 | + | if _, _, err := peer.WriteMsgUnix(msg, rights, nil); err != nil { | |
| 386 | + | b.Fatal(err) | |
| 387 | + | } | |
| 388 | + | if err := d.Dispatch(); err != nil { | |
| 389 | + | b.Fatal(err) | |
| 390 | + | } | |
| 391 | + | } | |
| 392 | + | }) | |
| 393 | + | } | |
A protocol/pointerconstraints/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package pointerconstraints | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p pointerconstraints -o pointer-constraints-unstable-v1_generated.go -import wl_pointer=github.com/bnema/wlturbo/protocol/core -import wl_region=github.com/bnema/wlturbo/protocol/core -import wl_surface=github.com/bnema/wlturbo/protocol/core pointer-constraints-unstable-v1.xml | |
A protocol/pointerconstraints/pointer-constraints-unstable-v1.xml +334 -0
| @@ -0,0 +1,334 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="pointer_constraints_unstable_v1"> | |
| 3 | + | ||
| 4 | + | <copyright> | |
| 5 | + | Copyright © 2014 Jonas Ådahl | |
| 6 | + | Copyright © 2015 Red Hat Inc. | |
| 7 | + | ||
| 8 | + | Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | copy of this software and associated documentation files (the "Software"), | |
| 10 | + | to deal in the Software without restriction, including without limitation | |
| 11 | + | the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | Software is furnished to do so, subject to the following conditions: | |
| 14 | + | ||
| 15 | + | The above copyright notice and this permission notice (including the next | |
| 16 | + | paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | Software. | |
| 18 | + | ||
| 19 | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | DEALINGS IN THE SOFTWARE. | |
| 26 | + | </copyright> | |
| 27 | + | ||
| 28 | + | <description summary="protocol for constraining pointer motions"> | |
| 29 | + | This protocol specifies a set of interfaces used for adding constraints to | |
| 30 | + | the motion of a pointer. Possible constraints include confining pointer | |
| 31 | + | motions to a given region, or locking it to its current position. | |
| 32 | + | ||
| 33 | + | In order to constrain the pointer, a client must first bind the global | |
| 34 | + | interface "wp_pointer_constraints" which, if a compositor supports pointer | |
| 35 | + | constraints, is exposed by the registry. Using the bound global object, the | |
| 36 | + | client uses the request that corresponds to the type of constraint it wants | |
| 37 | + | to make. See wp_pointer_constraints for more details. | |
| 38 | + | ||
| 39 | + | Warning! The protocol described in this file is experimental and backward | |
| 40 | + | incompatible changes may be made. Backward compatible changes may be added | |
| 41 | + | together with the corresponding interface version bump. Backward | |
| 42 | + | incompatible changes are done by bumping the version number in the protocol | |
| 43 | + | and interface names and resetting the interface version. Once the protocol | |
| 44 | + | is to be declared stable, the 'z' prefix and the version number in the | |
| 45 | + | protocol and interface names are removed and the interface version number is | |
| 46 | + | reset. | |
| 47 | + | </description> | |
| 48 | + | ||
| 49 | + | <interface name="zwp_pointer_constraints_v1" version="1"> | |
| 50 | + | <description summary="constrain the movement of a pointer"> | |
| 51 | + | The global interface exposing pointer constraining functionality. It | |
| 52 | + | exposes two requests: lock_pointer for locking the pointer to its | |
| 53 | + | position, and confine_pointer for locking the pointer to a region. | |
| 54 | + | ||
| 55 | + | The lock_pointer and confine_pointer requests create the objects | |
| 56 | + | wp_locked_pointer and wp_confined_pointer respectively, and the client can | |
| 57 | + | use these objects to interact with the lock. | |
| 58 | + | ||
| 59 | + | For any surface, only one lock or confinement may be active across all | |
| 60 | + | wl_pointer objects of the same seat. If a lock or confinement is requested | |
| 61 | + | when another lock or confinement is active or requested on the same surface | |
| 62 | + | and with any of the wl_pointer objects of the same seat, an | |
| 63 | + | 'already_constrained' error will be raised. | |
| 64 | + | </description> | |
| 65 | + | ||
| 66 | + | <enum name="error"> | |
| 67 | + | <description summary="wp_pointer_constraints error values"> | |
| 68 | + | These errors can be emitted in response to wp_pointer_constraints | |
| 69 | + | requests. | |
| 70 | + | </description> | |
| 71 | + | <entry name="already_constrained" value="1" | |
| 72 | + | summary="pointer constraint already requested on that surface"/> | |
| 73 | + | </enum> | |
| 74 | + | ||
| 75 | + | <enum name="lifetime"> | |
| 76 | + | <description summary="constraint lifetime"> | |
| 77 | + | These values represent different lifetime semantics. They are passed | |
| 78 | + | as arguments to the factory requests to specify how the constraint | |
| 79 | + | lifetimes should be managed. | |
| 80 | + | </description> | |
| 81 | + | <entry name="oneshot" value="1"> | |
| 82 | + | <description summary="the pointer constraint is defunct once deactivated"> | |
| 83 | + | A oneshot pointer constraint will never reactivate once it has been | |
| 84 | + | deactivated. See the corresponding deactivation event | |
| 85 | + | (wp_locked_pointer.unlocked and wp_confined_pointer.unconfined) for | |
| 86 | + | details. | |
| 87 | + | </description> | |
| 88 | + | </entry> | |
| 89 | + | <entry name="persistent" value="2"> | |
| 90 | + | <description summary="the pointer constraint may reactivate"> | |
| 91 | + | A persistent pointer constraint may again reactivate once it has | |
| 92 | + | been deactivated. See the corresponding deactivation event | |
| 93 | + | (wp_locked_pointer.unlocked and wp_confined_pointer.unconfined) for | |
| 94 | + | details. | |
| 95 | + | </description> | |
| 96 | + | </entry> | |
| 97 | + | </enum> | |
| 98 | + | ||
| 99 | + | <request name="destroy" type="destructor"> | |
| 100 | + | <description summary="destroy the pointer constraints manager object"> | |
| 101 | + | Used by the client to notify the server that it will no longer use this | |
| 102 | + | pointer constraints object. | |
| 103 | + | </description> | |
| 104 | + | </request> | |
| 105 | + | ||
| 106 | + | <request name="lock_pointer"> | |
| 107 | + | <description summary="lock pointer to a position"> | |
| 108 | + | The lock_pointer request lets the client request to disable movements of | |
| 109 | + | the virtual pointer (i.e. the cursor), effectively locking the pointer | |
| 110 | + | to a position. This request may not take effect immediately; in the | |
| 111 | + | future, when the compositor deems implementation-specific constraints | |
| 112 | + | are satisfied, the pointer lock will be activated and the compositor | |
| 113 | + | sends a locked event. | |
| 114 | + | ||
| 115 | + | The protocol provides no guarantee that the constraints are ever | |
| 116 | + | satisfied, and does not require the compositor to send an error if the | |
| 117 | + | constraints cannot ever be satisfied. It is thus possible to request a | |
| 118 | + | lock that will never activate. | |
| 119 | + | ||
| 120 | + | There may not be another pointer constraint of any kind requested or | |
| 121 | + | active on the surface for any of the wl_pointer objects of the seat of | |
| 122 | + | the passed pointer when requesting a lock. If there is, an error will be | |
| 123 | + | raised. See general pointer lock documentation for more details. | |
| 124 | + | ||
| 125 | + | The intersection of the region passed with this request and the input | |
| 126 | + | region of the surface is used to determine where the pointer must be | |
| 127 | + | in order for the lock to activate. It is up to the compositor whether to | |
| 128 | + | warp the pointer or require some kind of user interaction for the lock | |
| 129 | + | to activate. If the region is null the surface input region is used. | |
| 130 | + | ||
| 131 | + | A surface may receive pointer focus without the lock being activated. | |
| 132 | + | ||
| 133 | + | The request creates a new object wp_locked_pointer which is used to | |
| 134 | + | interact with the lock as well as receive updates about its state. See | |
| 135 | + | the the description of wp_locked_pointer for further information. | |
| 136 | + | ||
| 137 | + | Note that while a pointer is locked, the wl_pointer objects of the | |
| 138 | + | corresponding seat will not emit any wl_pointer.motion events, but | |
| 139 | + | relative motion events will still be emitted via wp_relative_pointer | |
| 140 | + | objects of the same seat. wl_pointer.axis and wl_pointer.button events | |
| 141 | + | are unaffected. | |
| 142 | + | </description> | |
| 143 | + | <arg name="id" type="new_id" interface="zwp_locked_pointer_v1"/> | |
| 144 | + | <arg name="surface" type="object" interface="wl_surface" | |
| 145 | + | summary="surface to lock pointer to"/> | |
| 146 | + | <arg name="pointer" type="object" interface="wl_pointer" | |
| 147 | + | summary="the pointer that should be locked"/> | |
| 148 | + | <arg name="region" type="object" interface="wl_region" allow-null="true" | |
| 149 | + | summary="region of surface"/> | |
| 150 | + | <arg name="lifetime" type="uint" enum="lifetime" summary="lock lifetime"/> | |
| 151 | + | </request> | |
| 152 | + | ||
| 153 | + | <request name="confine_pointer"> | |
| 154 | + | <description summary="confine pointer to a region"> | |
| 155 | + | The confine_pointer request lets the client request to confine the | |
| 156 | + | pointer cursor to a given region. This request may not take effect | |
| 157 | + | immediately; in the future, when the compositor deems implementation- | |
| 158 | + | specific constraints are satisfied, the pointer confinement will be | |
| 159 | + | activated and the compositor sends a confined event. | |
| 160 | + | ||
| 161 | + | The intersection of the region passed with this request and the input | |
| 162 | + | region of the surface is used to determine where the pointer must be | |
| 163 | + | in order for the confinement to activate. It is up to the compositor | |
| 164 | + | whether to warp the pointer or require some kind of user interaction for | |
| 165 | + | the confinement to activate. If the region is null the surface input | |
| 166 | + | region is used. | |
| 167 | + | ||
| 168 | + | The request will create a new object wp_confined_pointer which is used | |
| 169 | + | to interact with the confinement as well as receive updates about its | |
| 170 | + | state. See the the description of wp_confined_pointer for further | |
| 171 | + | information. | |
| 172 | + | </description> | |
| 173 | + | <arg name="id" type="new_id" interface="zwp_confined_pointer_v1"/> | |
| 174 | + | <arg name="surface" type="object" interface="wl_surface" | |
| 175 | + | summary="surface to lock pointer to"/> | |
| 176 | + | <arg name="pointer" type="object" interface="wl_pointer" | |
| 177 | + | summary="the pointer that should be confined"/> | |
| 178 | + | <arg name="region" type="object" interface="wl_region" allow-null="true" | |
| 179 | + | summary="region of surface"/> | |
| 180 | + | <arg name="lifetime" type="uint" enum="lifetime" summary="confinement lifetime"/> | |
| 181 | + | </request> | |
| 182 | + | </interface> | |
| 183 | + | ||
| 184 | + | <interface name="zwp_locked_pointer_v1" version="1"> | |
| 185 | + | <description summary="receive relative pointer motion events"> | |
| 186 | + | The wp_locked_pointer interface represents a locked pointer state. | |
| 187 | + | ||
| 188 | + | While the lock of this object is active, the wl_pointer objects of the | |
| 189 | + | associated seat will not emit any wl_pointer.motion events. | |
| 190 | + | ||
| 191 | + | This object will send the event 'locked' when the lock is activated. | |
| 192 | + | Whenever the lock is activated, it is guaranteed that the locked surface | |
| 193 | + | will already have received pointer focus and that the pointer will be | |
| 194 | + | within the region passed to the request creating this object. | |
| 195 | + | ||
| 196 | + | To unlock the pointer, send the destroy request. This will also destroy | |
| 197 | + | the wp_locked_pointer object. | |
| 198 | + | ||
| 199 | + | If the compositor decides to unlock the pointer the unlocked event is | |
| 200 | + | sent. See wp_locked_pointer.unlock for details. | |
| 201 | + | ||
| 202 | + | When unlocking, the compositor may warp the cursor position to the set | |
| 203 | + | cursor position hint. If it does, it will not result in any relative | |
| 204 | + | motion events emitted via wp_relative_pointer. | |
| 205 | + | ||
| 206 | + | If the surface the lock was requested on is destroyed and the lock is not | |
| 207 | + | yet activated, the wp_locked_pointer object is now defunct and must be | |
| 208 | + | destroyed. | |
| 209 | + | </description> | |
| 210 | + | ||
| 211 | + | <request name="destroy" type="destructor"> | |
| 212 | + | <description summary="destroy the locked pointer object"> | |
| 213 | + | Destroy the locked pointer object. If applicable, the compositor will | |
| 214 | + | unlock the pointer. | |
| 215 | + | </description> | |
| 216 | + | </request> | |
| 217 | + | ||
| 218 | + | <request name="set_cursor_position_hint"> | |
| 219 | + | <description summary="set the pointer cursor position hint"> | |
| 220 | + | Set the cursor position hint relative to the top left corner of the | |
| 221 | + | surface. | |
| 222 | + | ||
| 223 | + | If the client is drawing its own cursor, it should update the position | |
| 224 | + | hint to the position of its own cursor. A compositor may use this | |
| 225 | + | information to warp the pointer upon unlock in order to avoid pointer | |
| 226 | + | jumps. | |
| 227 | + | ||
| 228 | + | The cursor position hint is double-buffered state, see | |
| 229 | + | wl_surface.commit. | |
| 230 | + | </description> | |
| 231 | + | <arg name="surface_x" type="fixed" | |
| 232 | + | summary="surface-local x coordinate"/> | |
| 233 | + | <arg name="surface_y" type="fixed" | |
| 234 | + | summary="surface-local y coordinate"/> | |
| 235 | + | </request> | |
| 236 | + | ||
| 237 | + | <request name="set_region"> | |
| 238 | + | <description summary="set a new lock region"> | |
| 239 | + | Set a new region used to lock the pointer. | |
| 240 | + | ||
| 241 | + | The new lock region is double-buffered, see wl_surface.commit. | |
| 242 | + | ||
| 243 | + | For details about the lock region, see wp_locked_pointer. | |
| 244 | + | </description> | |
| 245 | + | <arg name="region" type="object" interface="wl_region" allow-null="true" | |
| 246 | + | summary="region of surface"/> | |
| 247 | + | </request> | |
| 248 | + | ||
| 249 | + | <event name="locked"> | |
| 250 | + | <description summary="lock activation event"> | |
| 251 | + | Notification that the pointer lock of the seat's pointer is activated. | |
| 252 | + | </description> | |
| 253 | + | </event> | |
| 254 | + | ||
| 255 | + | <event name="unlocked"> | |
| 256 | + | <description summary="lock deactivation event"> | |
| 257 | + | Notification that the pointer lock of the seat's pointer is no longer | |
| 258 | + | active. If this is a oneshot pointer lock (see | |
| 259 | + | wp_pointer_constraints.lifetime) this object is now defunct and should | |
| 260 | + | be destroyed. If this is a persistent pointer lock (see | |
| 261 | + | wp_pointer_constraints.lifetime) this pointer lock may again | |
| 262 | + | reactivate in the future. | |
| 263 | + | </description> | |
| 264 | + | </event> | |
| 265 | + | </interface> | |
| 266 | + | ||
| 267 | + | <interface name="zwp_confined_pointer_v1" version="1"> | |
| 268 | + | <description summary="confined pointer object"> | |
| 269 | + | The wp_confined_pointer interface represents a confined pointer state. | |
| 270 | + | ||
| 271 | + | This object will send the event 'confined' when the confinement is | |
| 272 | + | activated. Whenever the confinement is activated, it is guaranteed that | |
| 273 | + | the surface the pointer is confined to will already have received pointer | |
| 274 | + | focus and that the pointer will be within the region passed to the request | |
| 275 | + | creating this object. It is up to the compositor to decide whether this | |
| 276 | + | requires some user interaction and if the pointer will warp to within the | |
| 277 | + | passed region if outside. | |
| 278 | + | ||
| 279 | + | To unconfine the pointer, send the destroy request. This will also destroy | |
| 280 | + | the wp_confined_pointer object. | |
| 281 | + | ||
| 282 | + | If the compositor decides to unconfine the pointer the unconfined event is | |
| 283 | + | sent. The wp_confined_pointer object is at this point defunct and should | |
| 284 | + | be destroyed. | |
| 285 | + | </description> | |
| 286 | + | ||
| 287 | + | <request name="destroy" type="destructor"> | |
| 288 | + | <description summary="destroy the confined pointer object"> | |
| 289 | + | Destroy the confined pointer object. If applicable, the compositor will | |
| 290 | + | unconfine the pointer. | |
| 291 | + | </description> | |
| 292 | + | </request> | |
| 293 | + | ||
| 294 | + | <request name="set_region"> | |
| 295 | + | <description summary="set a new confine region"> | |
| 296 | + | Set a new region used to confine the pointer. | |
| 297 | + | ||
| 298 | + | The new confine region is double-buffered, see wl_surface.commit. | |
| 299 | + | ||
| 300 | + | If the confinement is active when the new confinement region is applied | |
| 301 | + | and the pointer ends up outside of newly applied region, the pointer may | |
| 302 | + | warped to a position within the new confinement region. If warped, a | |
| 303 | + | wl_pointer.motion event will be emitted, but no | |
| 304 | + | wp_relative_pointer.relative_motion event. | |
| 305 | + | ||
| 306 | + | The compositor may also, instead of using the new region, unconfine the | |
| 307 | + | pointer. | |
| 308 | + | ||
| 309 | + | For details about the confine region, see wp_confined_pointer. | |
| 310 | + | </description> | |
| 311 | + | <arg name="region" type="object" interface="wl_region" allow-null="true" | |
| 312 | + | summary="region of surface"/> | |
| 313 | + | </request> | |
| 314 | + | ||
| 315 | + | <event name="confined"> | |
| 316 | + | <description summary="pointer confined"> | |
| 317 | + | Notification that the pointer confinement of the seat's pointer is | |
| 318 | + | activated. | |
| 319 | + | </description> | |
| 320 | + | </event> | |
| 321 | + | ||
| 322 | + | <event name="unconfined"> | |
| 323 | + | <description summary="pointer unconfined"> | |
| 324 | + | Notification that the pointer confinement of the seat's pointer is no | |
| 325 | + | longer active. If this is a oneshot pointer confinement (see | |
| 326 | + | wp_pointer_constraints.lifetime) this object is now defunct and should | |
| 327 | + | be destroyed. If this is a persistent pointer confinement (see | |
| 328 | + | wp_pointer_constraints.lifetime) this pointer confinement may again | |
| 329 | + | reactivate in the future. | |
| 330 | + | </description> | |
| 331 | + | </event> | |
| 332 | + | </interface> | |
| 333 | + | ||
| 334 | + | </protocol> | |
A protocol/pointerconstraints/pointer-constraints-unstable-v1_generated.go +369 -0
| @@ -0,0 +1,369 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: pointer_constraints_unstable_v1 | |
| 3 | + | // Source: pointer-constraints-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2014 Jonas Ådahl | |
| 7 | + | // Copyright © 2015 Red Hat Inc. | |
| 8 | + | // | |
| 9 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 10 | + | // copy of this software and associated documentation files (the "Software"), | |
| 11 | + | // to deal in the Software without restriction, including without limitation | |
| 12 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 13 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 14 | + | // Software is furnished to do so, subject to the following conditions: | |
| 15 | + | // | |
| 16 | + | // The above copyright notice and this permission notice (including the next | |
| 17 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 18 | + | // Software. | |
| 19 | + | // | |
| 20 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 21 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 22 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 23 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 24 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 25 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 26 | + | // DEALINGS IN THE SOFTWARE. | |
| 27 | + | ||
| 28 | + | package pointerconstraints | |
| 29 | + | ||
| 30 | + | import ( | |
| 31 | + | "sync" | |
| 32 | + | ||
| 33 | + | cross_wl_pointer "github.com/bnema/wlturbo/protocol/core" | |
| 34 | + | cross_wl_region "github.com/bnema/wlturbo/protocol/core" | |
| 35 | + | cross_wl_surface "github.com/bnema/wlturbo/protocol/core" | |
| 36 | + | "github.com/bnema/wlturbo/wl" | |
| 37 | + | ) | |
| 38 | + | ||
| 39 | + | // ERROR_ALREADY_CONSTRAINED is the error already_constrained value. | |
| 40 | + | const ERROR_ALREADY_CONSTRAINED = 1 | |
| 41 | + | ||
| 42 | + | // LIFETIME_ONESHOT is the lifetime oneshot value. | |
| 43 | + | const LIFETIME_ONESHOT = 1 | |
| 44 | + | ||
| 45 | + | // LIFETIME_PERSISTENT is the lifetime persistent value. | |
| 46 | + | const LIFETIME_PERSISTENT = 2 | |
| 47 | + | ||
| 48 | + | // PointerConstraintsInterface is the protocol interface name. | |
| 49 | + | const PointerConstraintsInterface = "zwp_pointer_constraints_v1" | |
| 50 | + | ||
| 51 | + | // PointerConstraints is the generated binding for zwp_pointer_constraints_v1 version 1. | |
| 52 | + | type PointerConstraints struct { | |
| 53 | + | wl.BaseProxy | |
| 54 | + | } | |
| 55 | + | ||
| 56 | + | // NewPointerConstraints returns an unbound PointerConstraints. | |
| 57 | + | func NewPointerConstraints(ctx *wl.Context) *PointerConstraints { | |
| 58 | + | obj := &PointerConstraints{} | |
| 59 | + | obj.SetContext(ctx) | |
| 60 | + | ctx.Register(obj) | |
| 61 | + | return obj | |
| 62 | + | } | |
| 63 | + | ||
| 64 | + | // Used by the client to notify the server that it will no longer use this pointer constraints object. | |
| 65 | + | func (o *PointerConstraints) Destroy() error { | |
| 66 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_pointer_constraints_v1.destroy", Destructor: true}); err != nil { | |
| 67 | + | return err | |
| 68 | + | } | |
| 69 | + | return nil | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | // The lock_pointer request lets the client request to disable movements of the virtual pointer (i.e. the cursor), effectively locking the pointer to a position. This request may not take effect immediately; in the future, when the compositor deems implementation-specific constraints are satisfied, the pointer lock will be activated and the compositor sends a locked event. The protocol provides no guarantee that the constraints are ever satisfied, and does not require the compositor to send an error if the constraints cannot ever be satisfied. It is thus possible to request a lock that will never activate. There may not be another pointer constraint of any kind requested or active on the surface for any of the wl_pointer objects of the seat of the passed pointer when requesting a lock. If there is, an error will be raised. See general pointer lock documentation for more details. The intersection of the region passed with this request and the input region of the surface is used to determine where the pointer must be in order for the lock to activate. It is up to the compositor whether to warp the pointer or require some kind of user interaction for the lock to activate. If the region is null the surface input region is used. A surface may receive pointer focus without the lock being activated. The request creates a new object wp_locked_pointer which is used to interact with the lock as well as receive updates about its state. See the the description of wp_locked_pointer for further information. Note that while a pointer is locked, the wl_pointer objects of the corresponding seat will not emit any wl_pointer.motion events, but relative motion events will still be emitted via wp_relative_pointer objects of the same seat. wl_pointer.axis and wl_pointer.button events are unaffected. | |
| 73 | + | func (o *PointerConstraints) LockPointer(surface *cross_wl_surface.Surface, pointer *cross_wl_pointer.Pointer, region *cross_wl_region.Region, lifetime uint32) (*LockedPointer, error) { | |
| 74 | + | var arg1 wl.Object | |
| 75 | + | if surface != nil { | |
| 76 | + | arg1 = surface | |
| 77 | + | } | |
| 78 | + | var arg2 wl.Object | |
| 79 | + | if pointer != nil { | |
| 80 | + | arg2 = pointer | |
| 81 | + | } | |
| 82 | + | var arg3 wl.Object | |
| 83 | + | if region != nil { | |
| 84 | + | arg3 = region | |
| 85 | + | } | |
| 86 | + | child := &LockedPointer{} | |
| 87 | + | child.SetContext(o.Context()) | |
| 88 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_pointer_constraints_v1.lock_pointer", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1), wl.ArgObject(arg2), wl.ArgObject(arg3), wl.ArgUint(lifetime)); err != nil { | |
| 89 | + | return nil, err | |
| 90 | + | } | |
| 91 | + | return child, nil | |
| 92 | + | } | |
| 93 | + | ||
| 94 | + | // The confine_pointer request lets the client request to confine the pointer cursor to a given region. This request may not take effect immediately; in the future, when the compositor deems implementation- specific constraints are satisfied, the pointer confinement will be activated and the compositor sends a confined event. The intersection of the region passed with this request and the input region of the surface is used to determine where the pointer must be in order for the confinement to activate. It is up to the compositor whether to warp the pointer or require some kind of user interaction for the confinement to activate. If the region is null the surface input region is used. The request will create a new object wp_confined_pointer which is used to interact with the confinement as well as receive updates about its state. See the the description of wp_confined_pointer for further information. | |
| 95 | + | func (o *PointerConstraints) ConfinePointer(surface *cross_wl_surface.Surface, pointer *cross_wl_pointer.Pointer, region *cross_wl_region.Region, lifetime uint32) (*ConfinedPointer, error) { | |
| 96 | + | var arg1 wl.Object | |
| 97 | + | if surface != nil { | |
| 98 | + | arg1 = surface | |
| 99 | + | } | |
| 100 | + | var arg2 wl.Object | |
| 101 | + | if pointer != nil { | |
| 102 | + | arg2 = pointer | |
| 103 | + | } | |
| 104 | + | var arg3 wl.Object | |
| 105 | + | if region != nil { | |
| 106 | + | arg3 = region | |
| 107 | + | } | |
| 108 | + | child := &ConfinedPointer{} | |
| 109 | + | child.SetContext(o.Context()) | |
| 110 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_pointer_constraints_v1.confine_pointer", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1), wl.ArgObject(arg2), wl.ArgObject(arg3), wl.ArgUint(lifetime)); err != nil { | |
| 111 | + | return nil, err | |
| 112 | + | } | |
| 113 | + | return child, nil | |
| 114 | + | } | |
| 115 | + | ||
| 116 | + | // EventSignature returns the declared event argument types in wire order. | |
| 117 | + | func (o *PointerConstraints) EventSignature(opcode uint16) (string, bool) { | |
| 118 | + | switch opcode { | |
| 119 | + | default: | |
| 120 | + | return "", false | |
| 121 | + | } | |
| 122 | + | } | |
| 123 | + | ||
| 124 | + | // Dispatch decodes one event on zwp_pointer_constraints_v1 and calls the registered handlers. | |
| 125 | + | func (o *PointerConstraints) Dispatch(event *wl.Event) { | |
| 126 | + | switch event.Opcode { | |
| 127 | + | default: | |
| 128 | + | } | |
| 129 | + | } | |
| 130 | + | ||
| 131 | + | // LockedPointerInterface is the protocol interface name. | |
| 132 | + | const LockedPointerInterface = "zwp_locked_pointer_v1" | |
| 133 | + | ||
| 134 | + | // LockedPointer is the generated binding for zwp_locked_pointer_v1 version 1. | |
| 135 | + | type LockedPointer struct { | |
| 136 | + | wl.BaseProxy | |
| 137 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 138 | + | // handlers while another goroutine dispatches events. | |
| 139 | + | handlersMu sync.Mutex | |
| 140 | + | onLocked []func() | |
| 141 | + | onUnlocked []func() | |
| 142 | + | } | |
| 143 | + | ||
| 144 | + | // NewLockedPointer returns an unbound LockedPointer. | |
| 145 | + | func NewLockedPointer(ctx *wl.Context) *LockedPointer { | |
| 146 | + | obj := &LockedPointer{} | |
| 147 | + | obj.SetContext(ctx) | |
| 148 | + | ctx.Register(obj) | |
| 149 | + | return obj | |
| 150 | + | } | |
| 151 | + | ||
| 152 | + | // Destroy the locked pointer object. If applicable, the compositor will unlock the pointer. | |
| 153 | + | func (o *LockedPointer) Destroy() error { | |
| 154 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_locked_pointer_v1.destroy", Destructor: true}); err != nil { | |
| 155 | + | return err | |
| 156 | + | } | |
| 157 | + | return nil | |
| 158 | + | } | |
| 159 | + | ||
| 160 | + | // Set the cursor position hint relative to the top left corner of the surface. If the client is drawing its own cursor, it should update the position hint to the position of its own cursor. A compositor may use this information to warp the pointer upon unlock in order to avoid pointer jumps. The cursor position hint is double-buffered state, see wl_surface.commit. | |
| 161 | + | func (o *LockedPointer) SetCursorPositionHint(surfaceX wl.Fixed, surfaceY wl.Fixed) error { | |
| 162 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_locked_pointer_v1.set_cursor_position_hint"}, wl.ArgFixed(surfaceX), wl.ArgFixed(surfaceY)); err != nil { | |
| 163 | + | return err | |
| 164 | + | } | |
| 165 | + | return nil | |
| 166 | + | } | |
| 167 | + | ||
| 168 | + | // Set a new region used to lock the pointer. The new lock region is double-buffered, see wl_surface.commit. For details about the lock region, see wp_locked_pointer. | |
| 169 | + | func (o *LockedPointer) SetRegion(region *cross_wl_region.Region) error { | |
| 170 | + | var arg0 wl.Object | |
| 171 | + | if region != nil { | |
| 172 | + | arg0 = region | |
| 173 | + | } | |
| 174 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_locked_pointer_v1.set_region"}, wl.ArgObject(arg0)); err != nil { | |
| 175 | + | return err | |
| 176 | + | } | |
| 177 | + | return nil | |
| 178 | + | } | |
| 179 | + | ||
| 180 | + | // OnLocked registers a handler for the locked event. | |
| 181 | + | // | |
| 182 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 183 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 184 | + | func (o *LockedPointer) OnLocked(handler func()) { | |
| 185 | + | if handler == nil { | |
| 186 | + | return | |
| 187 | + | } | |
| 188 | + | o.handlersMu.Lock() | |
| 189 | + | defer o.handlersMu.Unlock() | |
| 190 | + | o.onLocked = append(o.onLocked, handler) | |
| 191 | + | } | |
| 192 | + | ||
| 193 | + | // handlersForLocked returns the handlers registered for locked, taken | |
| 194 | + | // under the lock so a handler may register another handler while events are | |
| 195 | + | // being dispatched. | |
| 196 | + | func (o *LockedPointer) handlersForLocked() []func() { | |
| 197 | + | o.handlersMu.Lock() | |
| 198 | + | defer o.handlersMu.Unlock() | |
| 199 | + | return o.onLocked | |
| 200 | + | } | |
| 201 | + | ||
| 202 | + | // OnUnlocked registers a handler for the unlocked event. | |
| 203 | + | // | |
| 204 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 205 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 206 | + | func (o *LockedPointer) OnUnlocked(handler func()) { | |
| 207 | + | if handler == nil { | |
| 208 | + | return | |
| 209 | + | } | |
| 210 | + | o.handlersMu.Lock() | |
| 211 | + | defer o.handlersMu.Unlock() | |
| 212 | + | o.onUnlocked = append(o.onUnlocked, handler) | |
| 213 | + | } | |
| 214 | + | ||
| 215 | + | // handlersForUnlocked returns the handlers registered for unlocked, taken | |
| 216 | + | // under the lock so a handler may register another handler while events are | |
| 217 | + | // being dispatched. | |
| 218 | + | func (o *LockedPointer) handlersForUnlocked() []func() { | |
| 219 | + | o.handlersMu.Lock() | |
| 220 | + | defer o.handlersMu.Unlock() | |
| 221 | + | return o.onUnlocked | |
| 222 | + | } | |
| 223 | + | ||
| 224 | + | // EventSignature returns the declared event argument types in wire order. | |
| 225 | + | func (o *LockedPointer) EventSignature(opcode uint16) (string, bool) { | |
| 226 | + | switch opcode { | |
| 227 | + | case 0: | |
| 228 | + | return "", true | |
| 229 | + | case 1: | |
| 230 | + | return "", true | |
| 231 | + | default: | |
| 232 | + | return "", false | |
| 233 | + | } | |
| 234 | + | } | |
| 235 | + | ||
| 236 | + | // Dispatch decodes one event on zwp_locked_pointer_v1 and calls the registered handlers. | |
| 237 | + | func (o *LockedPointer) Dispatch(event *wl.Event) { | |
| 238 | + | switch event.Opcode { | |
| 239 | + | case 0: // locked | |
| 240 | + | ||
| 241 | + | for i, handler := range o.handlersForLocked() { | |
| 242 | + | _ = i | |
| 243 | + | handler() | |
| 244 | + | } | |
| 245 | + | case 1: // unlocked | |
| 246 | + | ||
| 247 | + | for i, handler := range o.handlersForUnlocked() { | |
| 248 | + | _ = i | |
| 249 | + | handler() | |
| 250 | + | } | |
| 251 | + | default: | |
| 252 | + | } | |
| 253 | + | } | |
| 254 | + | ||
| 255 | + | // ConfinedPointerInterface is the protocol interface name. | |
| 256 | + | const ConfinedPointerInterface = "zwp_confined_pointer_v1" | |
| 257 | + | ||
| 258 | + | // ConfinedPointer is the generated binding for zwp_confined_pointer_v1 version 1. | |
| 259 | + | type ConfinedPointer struct { | |
| 260 | + | wl.BaseProxy | |
| 261 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 262 | + | // handlers while another goroutine dispatches events. | |
| 263 | + | handlersMu sync.Mutex | |
| 264 | + | onConfined []func() | |
| 265 | + | onUnconfined []func() | |
| 266 | + | } | |
| 267 | + | ||
| 268 | + | // NewConfinedPointer returns an unbound ConfinedPointer. | |
| 269 | + | func NewConfinedPointer(ctx *wl.Context) *ConfinedPointer { | |
| 270 | + | obj := &ConfinedPointer{} | |
| 271 | + | obj.SetContext(ctx) | |
| 272 | + | ctx.Register(obj) | |
| 273 | + | return obj | |
| 274 | + | } | |
| 275 | + | ||
| 276 | + | // Destroy the confined pointer object. If applicable, the compositor will unconfine the pointer. | |
| 277 | + | func (o *ConfinedPointer) Destroy() error { | |
| 278 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_confined_pointer_v1.destroy", Destructor: true}); err != nil { | |
| 279 | + | return err | |
| 280 | + | } | |
| 281 | + | return nil | |
| 282 | + | } | |
| 283 | + | ||
| 284 | + | // Set a new region used to confine the pointer. The new confine region is double-buffered, see wl_surface.commit. If the confinement is active when the new confinement region is applied and the pointer ends up outside of newly applied region, the pointer may warped to a position within the new confinement region. If warped, a wl_pointer.motion event will be emitted, but no wp_relative_pointer.relative_motion event. The compositor may also, instead of using the new region, unconfine the pointer. For details about the confine region, see wp_confined_pointer. | |
| 285 | + | func (o *ConfinedPointer) SetRegion(region *cross_wl_region.Region) error { | |
| 286 | + | var arg0 wl.Object | |
| 287 | + | if region != nil { | |
| 288 | + | arg0 = region | |
| 289 | + | } | |
| 290 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_confined_pointer_v1.set_region"}, wl.ArgObject(arg0)); err != nil { | |
| 291 | + | return err | |
| 292 | + | } | |
| 293 | + | return nil | |
| 294 | + | } | |
| 295 | + | ||
| 296 | + | // OnConfined registers a handler for the confined event. | |
| 297 | + | // | |
| 298 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 299 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 300 | + | func (o *ConfinedPointer) OnConfined(handler func()) { | |
| 301 | + | if handler == nil { | |
| 302 | + | return | |
| 303 | + | } | |
| 304 | + | o.handlersMu.Lock() | |
| 305 | + | defer o.handlersMu.Unlock() | |
| 306 | + | o.onConfined = append(o.onConfined, handler) | |
| 307 | + | } | |
| 308 | + | ||
| 309 | + | // handlersForConfined returns the handlers registered for confined, taken | |
| 310 | + | // under the lock so a handler may register another handler while events are | |
| 311 | + | // being dispatched. | |
| 312 | + | func (o *ConfinedPointer) handlersForConfined() []func() { | |
| 313 | + | o.handlersMu.Lock() | |
| 314 | + | defer o.handlersMu.Unlock() | |
| 315 | + | return o.onConfined | |
| 316 | + | } | |
| 317 | + | ||
| 318 | + | // OnUnconfined registers a handler for the unconfined event. | |
| 319 | + | // | |
| 320 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 321 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 322 | + | func (o *ConfinedPointer) OnUnconfined(handler func()) { | |
| 323 | + | if handler == nil { | |
| 324 | + | return | |
| 325 | + | } | |
| 326 | + | o.handlersMu.Lock() | |
| 327 | + | defer o.handlersMu.Unlock() | |
| 328 | + | o.onUnconfined = append(o.onUnconfined, handler) | |
| 329 | + | } | |
| 330 | + | ||
| 331 | + | // handlersForUnconfined returns the handlers registered for unconfined, taken | |
| 332 | + | // under the lock so a handler may register another handler while events are | |
| 333 | + | // being dispatched. | |
| 334 | + | func (o *ConfinedPointer) handlersForUnconfined() []func() { | |
| 335 | + | o.handlersMu.Lock() | |
| 336 | + | defer o.handlersMu.Unlock() | |
| 337 | + | return o.onUnconfined | |
| 338 | + | } | |
| 339 | + | ||
| 340 | + | // EventSignature returns the declared event argument types in wire order. | |
| 341 | + | func (o *ConfinedPointer) EventSignature(opcode uint16) (string, bool) { | |
| 342 | + | switch opcode { | |
| 343 | + | case 0: | |
| 344 | + | return "", true | |
| 345 | + | case 1: | |
| 346 | + | return "", true | |
| 347 | + | default: | |
| 348 | + | return "", false | |
| 349 | + | } | |
| 350 | + | } | |
| 351 | + | ||
| 352 | + | // Dispatch decodes one event on zwp_confined_pointer_v1 and calls the registered handlers. | |
| 353 | + | func (o *ConfinedPointer) Dispatch(event *wl.Event) { | |
| 354 | + | switch event.Opcode { | |
| 355 | + | case 0: // confined | |
| 356 | + | ||
| 357 | + | for i, handler := range o.handlersForConfined() { | |
| 358 | + | _ = i | |
| 359 | + | handler() | |
| 360 | + | } | |
| 361 | + | case 1: // unconfined | |
| 362 | + | ||
| 363 | + | for i, handler := range o.handlersForUnconfined() { | |
| 364 | + | _ = i | |
| 365 | + | handler() | |
| 366 | + | } | |
| 367 | + | default: | |
| 368 | + | } | |
| 369 | + | } | |
A protocol/pointerwarp/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package pointerwarp | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p pointerwarp -o pointer-warp-v1_generated.go -import wl_surface=github.com/bnema/wlturbo/protocol/core -import wl_pointer=github.com/bnema/wlturbo/protocol/core pointer-warp-v1.xml | |
A protocol/pointerwarp/pointer-warp-v1.xml +72 -0
| @@ -0,0 +1,72 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="pointer_warp_v1"> | |
| 3 | + | <copyright> | |
| 4 | + | Copyright © 2024 Neal Gompa | |
| 5 | + | Copyright © 2024 Xaver Hugl | |
| 6 | + | Copyright © 2024 Matthias Klumpp | |
| 7 | + | Copyright © 2024 Vlad Zahorodnii | |
| 8 | + | ||
| 9 | + | Permission is hereby granted, free of charge, to any person obtaining a | |
| 10 | + | copy of this software and associated documentation files (the "Software"), | |
| 11 | + | to deal in the Software without restriction, including without limitation | |
| 12 | + | the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 13 | + | and/or sell copies of the Software, and to permit persons to whom the | |
| 14 | + | Software is furnished to do so, subject to the following conditions: | |
| 15 | + | The above copyright notice and this permission notice (including the next | |
| 16 | + | paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | Software. | |
| 18 | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 19 | + | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 20 | + | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 21 | + | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 22 | + | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 23 | + | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 24 | + | DEALINGS IN THE SOFTWARE. | |
| 25 | + | </copyright> | |
| 26 | + | ||
| 27 | + | <interface name="wp_pointer_warp_v1" version="1"> | |
| 28 | + | <description summary="reposition the pointer to a location on a surface"> | |
| 29 | + | This global interface allows applications to request the pointer to be | |
| 30 | + | moved to a position relative to a wl_surface. | |
| 31 | + | ||
| 32 | + | Note that if the desired behavior is to constrain the pointer to an area | |
| 33 | + | or lock it to a position, this protocol does not provide a reliable way | |
| 34 | + | to do that. The pointer constraint and pointer lock protocols should be | |
| 35 | + | used for those use cases instead. | |
| 36 | + | ||
| 37 | + | Warning! The protocol described in this file is currently in the testing | |
| 38 | + | phase. Backward compatible changes may be added together with the | |
| 39 | + | corresponding interface version bump. Backward incompatible changes can | |
| 40 | + | only be done by creating a new major version of the extension. | |
| 41 | + | </description> | |
| 42 | + | ||
| 43 | + | <request name="destroy" type="destructor"> | |
| 44 | + | <description summary="destroy the warp manager"> | |
| 45 | + | Destroy the pointer warp manager. | |
| 46 | + | </description> | |
| 47 | + | </request> | |
| 48 | + | ||
| 49 | + | <request name="warp_pointer"> | |
| 50 | + | <description summary="reposition the pointer"> | |
| 51 | + | Request the compositor to move the pointer to a surface-local position. | |
| 52 | + | Whether or not the compositor honors the request is implementation defined, | |
| 53 | + | but it should | |
| 54 | + | - honor it if the surface has pointer focus, including | |
| 55 | + | when it has an implicit pointer grab | |
| 56 | + | - reject it if the enter serial is incorrect | |
| 57 | + | - reject it if the requested position is outside of the surface | |
| 58 | + | ||
| 59 | + | Note that the enter serial is valid for any surface of the client, | |
| 60 | + | and does not have to be from the surface the pointer is warped to. | |
| 61 | + | ||
| 62 | + | </description> | |
| 63 | + | <arg name="surface" type="object" interface="wl_surface" | |
| 64 | + | summary="surface to position the pointer on"/> | |
| 65 | + | <arg name="pointer" type="object" interface="wl_pointer" | |
| 66 | + | summary="the pointer that should be repositioned"/> | |
| 67 | + | <arg name="x" type="fixed"/> | |
| 68 | + | <arg name="y" type="fixed"/> | |
| 69 | + | <arg name="serial" type="uint" summary="serial number of the enter event"/> | |
| 70 | + | </request> | |
| 71 | + | </interface> | |
| 72 | + | </protocol> | |
A protocol/pointerwarp/pointer-warp-v1_generated.go +89 -0
| @@ -0,0 +1,89 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: pointer_warp_v1 | |
| 3 | + | // Source: pointer-warp-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2024 Neal Gompa | |
| 7 | + | // Copyright © 2024 Xaver Hugl | |
| 8 | + | // Copyright © 2024 Matthias Klumpp | |
| 9 | + | // Copyright © 2024 Vlad Zahorodnii | |
| 10 | + | // | |
| 11 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 12 | + | // copy of this software and associated documentation files (the "Software"), | |
| 13 | + | // to deal in the Software without restriction, including without limitation | |
| 14 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 15 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 16 | + | // Software is furnished to do so, subject to the following conditions: | |
| 17 | + | // The above copyright notice and this permission notice (including the next | |
| 18 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 19 | + | // Software. | |
| 20 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 21 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 22 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 23 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 24 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 25 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 26 | + | // DEALINGS IN THE SOFTWARE. | |
| 27 | + | ||
| 28 | + | package pointerwarp | |
| 29 | + | ||
| 30 | + | import ( | |
| 31 | + | cross_wl_pointer "github.com/bnema/wlturbo/protocol/core" | |
| 32 | + | cross_wl_surface "github.com/bnema/wlturbo/protocol/core" | |
| 33 | + | "github.com/bnema/wlturbo/wl" | |
| 34 | + | ) | |
| 35 | + | ||
| 36 | + | // WpPointerWarpInterface is the protocol interface name. | |
| 37 | + | const WpPointerWarpInterface = "wp_pointer_warp_v1" | |
| 38 | + | ||
| 39 | + | // WpPointerWarp is the generated binding for wp_pointer_warp_v1 version 1. | |
| 40 | + | type WpPointerWarp struct { | |
| 41 | + | wl.BaseProxy | |
| 42 | + | } | |
| 43 | + | ||
| 44 | + | // NewWpPointerWarp returns an unbound WpPointerWarp. | |
| 45 | + | func NewWpPointerWarp(ctx *wl.Context) *WpPointerWarp { | |
| 46 | + | obj := &WpPointerWarp{} | |
| 47 | + | obj.SetContext(ctx) | |
| 48 | + | ctx.Register(obj) | |
| 49 | + | return obj | |
| 50 | + | } | |
| 51 | + | ||
| 52 | + | // Destroy the pointer warp manager. | |
| 53 | + | func (o *WpPointerWarp) Destroy() error { | |
| 54 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_pointer_warp_v1.destroy", Destructor: true}); err != nil { | |
| 55 | + | return err | |
| 56 | + | } | |
| 57 | + | return nil | |
| 58 | + | } | |
| 59 | + | ||
| 60 | + | // Request the compositor to move the pointer to a surface-local position. Whether or not the compositor honors the request is implementation defined, but it should - honor it if the surface has pointer focus, including when it has an implicit pointer grab - reject it if the enter serial is incorrect - reject it if the requested position is outside of the surface Note that the enter serial is valid for any surface of the client, and does not have to be from the surface the pointer is warped to. | |
| 61 | + | func (o *WpPointerWarp) WarpPointer(surface *cross_wl_surface.Surface, pointer *cross_wl_pointer.Pointer, x wl.Fixed, y wl.Fixed, serial uint32) error { | |
| 62 | + | var arg0 wl.Object | |
| 63 | + | if surface != nil { | |
| 64 | + | arg0 = surface | |
| 65 | + | } | |
| 66 | + | var arg1 wl.Object | |
| 67 | + | if pointer != nil { | |
| 68 | + | arg1 = pointer | |
| 69 | + | } | |
| 70 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_pointer_warp_v1.warp_pointer"}, wl.ArgObject(arg0), wl.ArgObject(arg1), wl.ArgFixed(x), wl.ArgFixed(y), wl.ArgUint(serial)); err != nil { | |
| 71 | + | return err | |
| 72 | + | } | |
| 73 | + | return nil | |
| 74 | + | } | |
| 75 | + | ||
| 76 | + | // EventSignature returns the declared event argument types in wire order. | |
| 77 | + | func (o *WpPointerWarp) EventSignature(opcode uint16) (string, bool) { | |
| 78 | + | switch opcode { | |
| 79 | + | default: | |
| 80 | + | return "", false | |
| 81 | + | } | |
| 82 | + | } | |
| 83 | + | ||
| 84 | + | // Dispatch decodes one event on wp_pointer_warp_v1 and calls the registered handlers. | |
| 85 | + | func (o *WpPointerWarp) Dispatch(event *wl.Event) { | |
| 86 | + | switch event.Opcode { | |
| 87 | + | default: | |
| 88 | + | } | |
| 89 | + | } | |
A protocol/presentation/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package presentation | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p presentation -o presentation-time_generated.go -import wl_surface=github.com/bnema/wlturbo/protocol/core -import wl_output=github.com/bnema/wlturbo/protocol/core presentation-time.xml | |
A protocol/presentation/presentation-time.xml +268 -0
| @@ -0,0 +1,268 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="presentation_time"> | |
| 3 | + | <!-- wrap:70 --> | |
| 4 | + | ||
| 5 | + | <copyright> | |
| 6 | + | Copyright © 2013-2014 Collabora, Ltd. | |
| 7 | + | ||
| 8 | + | Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | copy of this software and associated documentation files (the "Software"), | |
| 10 | + | to deal in the Software without restriction, including without limitation | |
| 11 | + | the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | Software is furnished to do so, subject to the following conditions: | |
| 14 | + | ||
| 15 | + | The above copyright notice and this permission notice (including the next | |
| 16 | + | paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | Software. | |
| 18 | + | ||
| 19 | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | DEALINGS IN THE SOFTWARE. | |
| 26 | + | </copyright> | |
| 27 | + | ||
| 28 | + | <interface name="wp_presentation" version="2"> | |
| 29 | + | <description summary="timed presentation related wl_surface requests"> | |
| 30 | + | ||
| 31 | + | <!-- Introduction --> | |
| 32 | + | ||
| 33 | + | The main feature of this interface is accurate presentation | |
| 34 | + | timing feedback to ensure smooth video playback while maintaining | |
| 35 | + | audio/video synchronization. Some features use the concept of a | |
| 36 | + | presentation clock, which is defined in the | |
| 37 | + | presentation.clock_id event. | |
| 38 | + | ||
| 39 | + | A content update for a wl_surface is submitted by a | |
| 40 | + | wl_surface.commit request. Request 'feedback' associates with | |
| 41 | + | the wl_surface.commit and provides feedback on the content | |
| 42 | + | update, particularly the final realized presentation time. | |
| 43 | + | ||
| 44 | + | <!-- Completing presentation --> | |
| 45 | + | ||
| 46 | + | When the final realized presentation time is available, e.g. | |
| 47 | + | after a framebuffer flip completes, the requested | |
| 48 | + | presentation_feedback.presented events are sent. The final | |
| 49 | + | presentation time can differ from the compositor's predicted | |
| 50 | + | display update time and the update's target time, especially | |
| 51 | + | when the compositor misses its target vertical blanking period. | |
| 52 | + | </description> | |
| 53 | + | ||
| 54 | + | <enum name="error"> | |
| 55 | + | <description summary="fatal presentation errors"> | |
| 56 | + | These fatal protocol errors may be emitted in response to | |
| 57 | + | illegal presentation requests. | |
| 58 | + | </description> | |
| 59 | + | <entry name="invalid_timestamp" value="0" | |
| 60 | + | summary="invalid value in tv_nsec"/> | |
| 61 | + | <entry name="invalid_flag" value="1" | |
| 62 | + | summary="invalid flag"/> | |
| 63 | + | </enum> | |
| 64 | + | ||
| 65 | + | <request name="destroy" type="destructor"> | |
| 66 | + | <description summary="unbind from the presentation interface"> | |
| 67 | + | Informs the server that the client will no longer be using | |
| 68 | + | this protocol object. Existing objects created by this object | |
| 69 | + | are not affected. | |
| 70 | + | </description> | |
| 71 | + | </request> | |
| 72 | + | ||
| 73 | + | <request name="feedback"> | |
| 74 | + | <description summary="request presentation feedback information"> | |
| 75 | + | Request presentation feedback for the current content submission | |
| 76 | + | on the given surface. This creates a new presentation_feedback | |
| 77 | + | object, which will deliver the feedback information once. If | |
| 78 | + | multiple presentation_feedback objects are created for the same | |
| 79 | + | submission, they will all deliver the same information. | |
| 80 | + | ||
| 81 | + | For details on what information is returned, see the | |
| 82 | + | presentation_feedback interface. | |
| 83 | + | </description> | |
| 84 | + | <arg name="surface" type="object" interface="wl_surface" | |
| 85 | + | summary="target surface"/> | |
| 86 | + | <arg name="callback" type="new_id" interface="wp_presentation_feedback" | |
| 87 | + | summary="new feedback object"/> | |
| 88 | + | </request> | |
| 89 | + | ||
| 90 | + | <event name="clock_id"> | |
| 91 | + | <description summary="clock ID for timestamps"> | |
| 92 | + | This event tells the client in which clock domain the | |
| 93 | + | compositor interprets the timestamps used by the presentation | |
| 94 | + | extension. This clock is called the presentation clock. | |
| 95 | + | ||
| 96 | + | The compositor sends this event when the client binds to the | |
| 97 | + | presentation interface. The presentation clock does not change | |
| 98 | + | during the lifetime of the client connection. | |
| 99 | + | ||
| 100 | + | The clock identifier is platform dependent. On POSIX platforms, the | |
| 101 | + | identifier value is one of the clockid_t values accepted by | |
| 102 | + | clock_gettime(). clock_gettime() is defined by POSIX.1-2001. | |
| 103 | + | ||
| 104 | + | Timestamps in this clock domain are expressed as tv_sec_hi, | |
| 105 | + | tv_sec_lo, tv_nsec triples, each component being an unsigned | |
| 106 | + | 32-bit value. Whole seconds are in tv_sec which is a 64-bit | |
| 107 | + | value combined from tv_sec_hi and tv_sec_lo, and the | |
| 108 | + | additional fractional part in tv_nsec as nanoseconds. Hence, | |
| 109 | + | for valid timestamps tv_nsec must be in [0, 999999999]. | |
| 110 | + | ||
| 111 | + | Note that clock_id applies only to the presentation clock, | |
| 112 | + | and implies nothing about e.g. the timestamps used in the | |
| 113 | + | Wayland core protocol input events. | |
| 114 | + | ||
| 115 | + | Compositors should prefer a clock which does not jump and is | |
| 116 | + | not slewed e.g. by NTP. The absolute value of the clock is | |
| 117 | + | irrelevant. Precision of one millisecond or better is | |
| 118 | + | recommended. Clients must be able to query the current clock | |
| 119 | + | value directly, not by asking the compositor. | |
| 120 | + | </description> | |
| 121 | + | <arg name="clk_id" type="uint" summary="platform clock identifier"/> | |
| 122 | + | </event> | |
| 123 | + | ||
| 124 | + | </interface> | |
| 125 | + | ||
| 126 | + | <interface name="wp_presentation_feedback" version="2"> | |
| 127 | + | <description summary="presentation time feedback event"> | |
| 128 | + | A presentation_feedback object returns an indication that a | |
| 129 | + | wl_surface content update has become visible to the user. | |
| 130 | + | One object corresponds to one content update submission | |
| 131 | + | (wl_surface.commit). There are two possible outcomes: the | |
| 132 | + | content update is presented to the user, and a presentation | |
| 133 | + | timestamp delivered; or, the user did not see the content | |
| 134 | + | update because it was superseded or its surface destroyed, | |
| 135 | + | and the content update is discarded. | |
| 136 | + | ||
| 137 | + | Once a presentation_feedback object has delivered a 'presented' | |
| 138 | + | or 'discarded' event it is automatically destroyed. | |
| 139 | + | </description> | |
| 140 | + | ||
| 141 | + | <event name="sync_output"> | |
| 142 | + | <description summary="presentation synchronized to this output"> | |
| 143 | + | As presentation can be synchronized to only one output at a | |
| 144 | + | time, this event tells which output it was. This event is only | |
| 145 | + | sent prior to the presented event. | |
| 146 | + | ||
| 147 | + | As clients may bind to the same global wl_output multiple | |
| 148 | + | times, this event is sent for each bound instance that matches | |
| 149 | + | the synchronized output. If a client has not bound to the | |
| 150 | + | right wl_output global at all, this event is not sent. | |
| 151 | + | </description> | |
| 152 | + | <arg name="output" type="object" interface="wl_output" | |
| 153 | + | summary="presentation output"/> | |
| 154 | + | </event> | |
| 155 | + | ||
| 156 | + | <enum name="kind" bitfield="true"> | |
| 157 | + | <description summary="bitmask of flags in presented event"> | |
| 158 | + | These flags provide information about how the presentation of | |
| 159 | + | the related content update was done. The intent is to help | |
| 160 | + | clients assess the reliability of the feedback and the visual | |
| 161 | + | quality with respect to possible tearing and timings. | |
| 162 | + | </description> | |
| 163 | + | <entry name="vsync" value="0x1"> | |
| 164 | + | <description summary="presentation was vsync'd"> | |
| 165 | + | The presentation was synchronized to the "vertical retrace" by | |
| 166 | + | the display hardware such that tearing does not happen. | |
| 167 | + | Relying on software scheduling is not acceptable for this | |
| 168 | + | flag. If presentation is done by a copy to the active | |
| 169 | + | frontbuffer, then it must guarantee that tearing cannot | |
| 170 | + | happen. | |
| 171 | + | </description> | |
| 172 | + | </entry> | |
| 173 | + | <entry name="hw_clock" value="0x2"> | |
| 174 | + | <description summary="hardware provided the presentation timestamp"> | |
| 175 | + | The display hardware provided measurements that the hardware | |
| 176 | + | driver converted into a presentation timestamp. Sampling a | |
| 177 | + | clock in software is not acceptable for this flag. | |
| 178 | + | </description> | |
| 179 | + | </entry> | |
| 180 | + | <entry name="hw_completion" value="0x4"> | |
| 181 | + | <description summary="hardware signalled the start of the presentation"> | |
| 182 | + | The display hardware signalled that it started using the new | |
| 183 | + | image content. The opposite of this is e.g. a timer being used | |
| 184 | + | to guess when the display hardware has switched to the new | |
| 185 | + | image content. | |
| 186 | + | </description> | |
| 187 | + | </entry> | |
| 188 | + | <entry name="zero_copy" value="0x8"> | |
| 189 | + | <description summary="presentation was done zero-copy"> | |
| 190 | + | The presentation of this update was done zero-copy. This means | |
| 191 | + | the buffer from the client was given to display hardware as | |
| 192 | + | is, without copying it. Compositing with OpenGL counts as | |
| 193 | + | copying, even if textured directly from the client buffer. | |
| 194 | + | Possible zero-copy cases include direct scanout of a | |
| 195 | + | fullscreen surface and a surface on a hardware overlay. | |
| 196 | + | </description> | |
| 197 | + | </entry> | |
| 198 | + | </enum> | |
| 199 | + | ||
| 200 | + | <event name="presented" type="destructor"> | |
| 201 | + | <description summary="the content update was displayed"> | |
| 202 | + | The associated content update was displayed to the user at the | |
| 203 | + | indicated time (tv_sec_hi/lo, tv_nsec). For the interpretation of | |
| 204 | + | the timestamp, see presentation.clock_id event. | |
| 205 | + | ||
| 206 | + | The timestamp corresponds to the time when the content update | |
| 207 | + | turned into light the first time on the surface's main output. | |
| 208 | + | Compositors may approximate this from the framebuffer flip | |
| 209 | + | completion events from the system, and the latency of the | |
| 210 | + | physical display path if known. | |
| 211 | + | ||
| 212 | + | This event is preceded by all related sync_output events | |
| 213 | + | telling which output's refresh cycle the feedback corresponds | |
| 214 | + | to, i.e. the main output for the surface. Compositors are | |
| 215 | + | recommended to choose the output containing the largest part | |
| 216 | + | of the wl_surface, or keeping the output they previously | |
| 217 | + | chose. Having a stable presentation output association helps | |
| 218 | + | clients predict future output refreshes (vblank). | |
| 219 | + | ||
| 220 | + | The 'refresh' argument gives the compositor's prediction of how | |
| 221 | + | many nanoseconds after tv_sec, tv_nsec the very next output | |
| 222 | + | refresh may occur. This is to further aid clients in | |
| 223 | + | predicting future refreshes, i.e., estimating the timestamps | |
| 224 | + | targeting the next few vblanks. If such prediction cannot | |
| 225 | + | usefully be done, the argument is zero. | |
| 226 | + | ||
| 227 | + | For version 2 and later, if the output does not have a constant | |
| 228 | + | refresh rate, explicit video mode switches excluded, then the | |
| 229 | + | refresh argument must be either an appropriate rate picked by the | |
| 230 | + | compositor (e.g. fastest rate), or 0 if no such rate exists. | |
| 231 | + | For version 1, if the output does not have a constant refresh rate, | |
| 232 | + | the refresh argument must be zero. | |
| 233 | + | ||
| 234 | + | The 64-bit value combined from seq_hi and seq_lo is the value | |
| 235 | + | of the output's vertical retrace counter when the content | |
| 236 | + | update was first scanned out to the display. This value must | |
| 237 | + | be compatible with the definition of MSC in | |
| 238 | + | GLX_OML_sync_control specification. Note, that if the display | |
| 239 | + | path has a non-zero latency, the time instant specified by | |
| 240 | + | this counter may differ from the timestamp's. | |
| 241 | + | ||
| 242 | + | If the output does not have a concept of vertical retrace or a | |
| 243 | + | refresh cycle, or the output device is self-refreshing without | |
| 244 | + | a way to query the refresh count, then the arguments seq_hi | |
| 245 | + | and seq_lo must be zero. | |
| 246 | + | </description> | |
| 247 | + | <arg name="tv_sec_hi" type="uint" | |
| 248 | + | summary="high 32 bits of the seconds part of the presentation timestamp"/> | |
| 249 | + | <arg name="tv_sec_lo" type="uint" | |
| 250 | + | summary="low 32 bits of the seconds part of the presentation timestamp"/> | |
| 251 | + | <arg name="tv_nsec" type="uint" | |
| 252 | + | summary="nanoseconds part of the presentation timestamp"/> | |
| 253 | + | <arg name="refresh" type="uint" summary="nanoseconds till next refresh"/> | |
| 254 | + | <arg name="seq_hi" type="uint" | |
| 255 | + | summary="high 32 bits of refresh counter"/> | |
| 256 | + | <arg name="seq_lo" type="uint" | |
| 257 | + | summary="low 32 bits of refresh counter"/> | |
| 258 | + | <arg name="flags" type="uint" enum="kind" summary="combination of 'kind' values"/> | |
| 259 | + | </event> | |
| 260 | + | ||
| 261 | + | <event name="discarded" type="destructor"> | |
| 262 | + | <description summary="the content update was not displayed"> | |
| 263 | + | The content update was never displayed to the user. | |
| 264 | + | </description> | |
| 265 | + | </event> | |
| 266 | + | </interface> | |
| 267 | + | ||
| 268 | + | </protocol> | |
A protocol/presentation/presentation-time_generated.go +277 -0
| @@ -0,0 +1,277 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: presentation_time | |
| 3 | + | // Source: presentation-time.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2013-2014 Collabora, Ltd. | |
| 7 | + | // | |
| 8 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | // copy of this software and associated documentation files (the "Software"), | |
| 10 | + | // to deal in the Software without restriction, including without limitation | |
| 11 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | // Software is furnished to do so, subject to the following conditions: | |
| 14 | + | // | |
| 15 | + | // The above copyright notice and this permission notice (including the next | |
| 16 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | // Software. | |
| 18 | + | // | |
| 19 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | // DEALINGS IN THE SOFTWARE. | |
| 26 | + | ||
| 27 | + | package presentation | |
| 28 | + | ||
| 29 | + | import ( | |
| 30 | + | "sync" | |
| 31 | + | ||
| 32 | + | cross_wl_surface "github.com/bnema/wlturbo/protocol/core" | |
| 33 | + | "github.com/bnema/wlturbo/wl" | |
| 34 | + | ) | |
| 35 | + | ||
| 36 | + | // ERROR_INVALID_TIMESTAMP is the error invalid_timestamp value. | |
| 37 | + | const ERROR_INVALID_TIMESTAMP = 0 | |
| 38 | + | ||
| 39 | + | // ERROR_INVALID_FLAG is the error invalid_flag value. | |
| 40 | + | const ERROR_INVALID_FLAG = 1 | |
| 41 | + | ||
| 42 | + | // KIND_VSYNC is the kind vsync value. | |
| 43 | + | const KIND_VSYNC = 0x1 | |
| 44 | + | ||
| 45 | + | // KIND_HW_CLOCK is the kind hw_clock value. | |
| 46 | + | const KIND_HW_CLOCK = 0x2 | |
| 47 | + | ||
| 48 | + | // KIND_HW_COMPLETION is the kind hw_completion value. | |
| 49 | + | const KIND_HW_COMPLETION = 0x4 | |
| 50 | + | ||
| 51 | + | // KIND_ZERO_COPY is the kind zero_copy value. | |
| 52 | + | const KIND_ZERO_COPY = 0x8 | |
| 53 | + | ||
| 54 | + | // WpPresentationInterface is the protocol interface name. | |
| 55 | + | const WpPresentationInterface = "wp_presentation" | |
| 56 | + | ||
| 57 | + | // WpPresentation is the generated binding for wp_presentation version 2. | |
| 58 | + | type WpPresentation struct { | |
| 59 | + | wl.BaseProxy | |
| 60 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 61 | + | // handlers while another goroutine dispatches events. | |
| 62 | + | handlersMu sync.Mutex | |
| 63 | + | onClockId []func(clkId uint32) | |
| 64 | + | } | |
| 65 | + | ||
| 66 | + | // NewWpPresentation returns an unbound WpPresentation. | |
| 67 | + | func NewWpPresentation(ctx *wl.Context) *WpPresentation { | |
| 68 | + | obj := &WpPresentation{} | |
| 69 | + | obj.SetContext(ctx) | |
| 70 | + | ctx.Register(obj) | |
| 71 | + | return obj | |
| 72 | + | } | |
| 73 | + | ||
| 74 | + | // Informs the server that the client will no longer be using this protocol object. Existing objects created by this object are not affected. | |
| 75 | + | func (o *WpPresentation) Destroy() error { | |
| 76 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "wp_presentation.destroy", Destructor: true}); err != nil { | |
| 77 | + | return err | |
| 78 | + | } | |
| 79 | + | return nil | |
| 80 | + | } | |
| 81 | + | ||
| 82 | + | // Request presentation feedback for the current content submission on the given surface. This creates a new presentation_feedback object, which will deliver the feedback information once. If multiple presentation_feedback objects are created for the same submission, they will all deliver the same information. For details on what information is returned, see the presentation_feedback interface. | |
| 83 | + | func (o *WpPresentation) Feedback(surface *cross_wl_surface.Surface) (*WpPresentationFeedback, error) { | |
| 84 | + | var arg0 wl.Object | |
| 85 | + | if surface != nil { | |
| 86 | + | arg0 = surface | |
| 87 | + | } | |
| 88 | + | child := &WpPresentationFeedback{} | |
| 89 | + | child.SetContext(o.Context()) | |
| 90 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "wp_presentation.feedback", Child: child}, wl.ArgObject(arg0), wl.ArgObject(child)); err != nil { | |
| 91 | + | return nil, err | |
| 92 | + | } | |
| 93 | + | return child, nil | |
| 94 | + | } | |
| 95 | + | ||
| 96 | + | // OnClockId registers a handler for the clock_id event. | |
| 97 | + | // | |
| 98 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 99 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 100 | + | func (o *WpPresentation) OnClockId(handler func(clkId uint32)) { | |
| 101 | + | if handler == nil { | |
| 102 | + | return | |
| 103 | + | } | |
| 104 | + | o.handlersMu.Lock() | |
| 105 | + | defer o.handlersMu.Unlock() | |
| 106 | + | o.onClockId = append(o.onClockId, handler) | |
| 107 | + | } | |
| 108 | + | ||
| 109 | + | // handlersForClockId returns the handlers registered for clock_id, taken | |
| 110 | + | // under the lock so a handler may register another handler while events are | |
| 111 | + | // being dispatched. | |
| 112 | + | func (o *WpPresentation) handlersForClockId() []func(clkId uint32) { | |
| 113 | + | o.handlersMu.Lock() | |
| 114 | + | defer o.handlersMu.Unlock() | |
| 115 | + | return o.onClockId | |
| 116 | + | } | |
| 117 | + | ||
| 118 | + | // EventSignature returns the declared event argument types in wire order. | |
| 119 | + | func (o *WpPresentation) EventSignature(opcode uint16) (string, bool) { | |
| 120 | + | switch opcode { | |
| 121 | + | case 0: | |
| 122 | + | return "uint,", true | |
| 123 | + | default: | |
| 124 | + | return "", false | |
| 125 | + | } | |
| 126 | + | } | |
| 127 | + | ||
| 128 | + | // Dispatch decodes one event on wp_presentation and calls the registered handlers. | |
| 129 | + | func (o *WpPresentation) Dispatch(event *wl.Event) { | |
| 130 | + | switch event.Opcode { | |
| 131 | + | case 0: // clock_id | |
| 132 | + | clkId := event.Uint32() | |
| 133 | + | ||
| 134 | + | for i, handler := range o.handlersForClockId() { | |
| 135 | + | _ = i | |
| 136 | + | handler(clkId) | |
| 137 | + | } | |
| 138 | + | default: | |
| 139 | + | } | |
| 140 | + | } | |
| 141 | + | ||
| 142 | + | // WpPresentationFeedbackInterface is the protocol interface name. | |
| 143 | + | const WpPresentationFeedbackInterface = "wp_presentation_feedback" | |
| 144 | + | ||
| 145 | + | // WpPresentationFeedback is the generated binding for wp_presentation_feedback version 2. | |
| 146 | + | type WpPresentationFeedback struct { | |
| 147 | + | wl.BaseProxy | |
| 148 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 149 | + | // handlers while another goroutine dispatches events. | |
| 150 | + | handlersMu sync.Mutex | |
| 151 | + | onSyncOutput []func(outputID uint32) | |
| 152 | + | onPresented []func(tvSecHi uint32, tvSecLo uint32, tvNsec uint32, refresh uint32, seqHi uint32, seqLo uint32, flags uint32) | |
| 153 | + | onDiscarded []func() | |
| 154 | + | } | |
| 155 | + | ||
| 156 | + | // NewWpPresentationFeedback returns an unbound WpPresentationFeedback. | |
| 157 | + | func NewWpPresentationFeedback(ctx *wl.Context) *WpPresentationFeedback { | |
| 158 | + | obj := &WpPresentationFeedback{} | |
| 159 | + | obj.SetContext(ctx) | |
| 160 | + | ctx.Register(obj) | |
| 161 | + | return obj | |
| 162 | + | } | |
| 163 | + | ||
| 164 | + | // OnSyncOutput registers a handler for the sync_output event. | |
| 165 | + | // | |
| 166 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 167 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 168 | + | func (o *WpPresentationFeedback) OnSyncOutput(handler func(outputID uint32)) { | |
| 169 | + | if handler == nil { | |
| 170 | + | return | |
| 171 | + | } | |
| 172 | + | o.handlersMu.Lock() | |
| 173 | + | defer o.handlersMu.Unlock() | |
| 174 | + | o.onSyncOutput = append(o.onSyncOutput, handler) | |
| 175 | + | } | |
| 176 | + | ||
| 177 | + | // handlersForSyncOutput returns the handlers registered for sync_output, taken | |
| 178 | + | // under the lock so a handler may register another handler while events are | |
| 179 | + | // being dispatched. | |
| 180 | + | func (o *WpPresentationFeedback) handlersForSyncOutput() []func(outputID uint32) { | |
| 181 | + | o.handlersMu.Lock() | |
| 182 | + | defer o.handlersMu.Unlock() | |
| 183 | + | return o.onSyncOutput | |
| 184 | + | } | |
| 185 | + | ||
| 186 | + | // OnPresented registers a handler for the presented event. | |
| 187 | + | // | |
| 188 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 189 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 190 | + | func (o *WpPresentationFeedback) OnPresented(handler func(tvSecHi uint32, tvSecLo uint32, tvNsec uint32, refresh uint32, seqHi uint32, seqLo uint32, flags uint32)) { | |
| 191 | + | if handler == nil { | |
| 192 | + | return | |
| 193 | + | } | |
| 194 | + | o.handlersMu.Lock() | |
| 195 | + | defer o.handlersMu.Unlock() | |
| 196 | + | o.onPresented = append(o.onPresented, handler) | |
| 197 | + | } | |
| 198 | + | ||
| 199 | + | // handlersForPresented returns the handlers registered for presented, taken | |
| 200 | + | // under the lock so a handler may register another handler while events are | |
| 201 | + | // being dispatched. | |
| 202 | + | func (o *WpPresentationFeedback) handlersForPresented() []func(tvSecHi uint32, tvSecLo uint32, tvNsec uint32, refresh uint32, seqHi uint32, seqLo uint32, flags uint32) { | |
| 203 | + | o.handlersMu.Lock() | |
| 204 | + | defer o.handlersMu.Unlock() | |
| 205 | + | return o.onPresented | |
| 206 | + | } | |
| 207 | + | ||
| 208 | + | // OnDiscarded registers a handler for the discarded event. | |
| 209 | + | // | |
| 210 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 211 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 212 | + | func (o *WpPresentationFeedback) OnDiscarded(handler func()) { | |
| 213 | + | if handler == nil { | |
| 214 | + | return | |
| 215 | + | } | |
| 216 | + | o.handlersMu.Lock() | |
| 217 | + | defer o.handlersMu.Unlock() | |
| 218 | + | o.onDiscarded = append(o.onDiscarded, handler) | |
| 219 | + | } | |
| 220 | + | ||
| 221 | + | // handlersForDiscarded returns the handlers registered for discarded, taken | |
| 222 | + | // under the lock so a handler may register another handler while events are | |
| 223 | + | // being dispatched. | |
| 224 | + | func (o *WpPresentationFeedback) handlersForDiscarded() []func() { | |
| 225 | + | o.handlersMu.Lock() | |
| 226 | + | defer o.handlersMu.Unlock() | |
| 227 | + | return o.onDiscarded | |
| 228 | + | } | |
| 229 | + | ||
| 230 | + | // EventSignature returns the declared event argument types in wire order. | |
| 231 | + | func (o *WpPresentationFeedback) EventSignature(opcode uint16) (string, bool) { | |
| 232 | + | switch opcode { | |
| 233 | + | case 0: | |
| 234 | + | return "object,", true | |
| 235 | + | case 1: | |
| 236 | + | return "uint,uint,uint,uint,uint,uint,uint,", true | |
| 237 | + | case 2: | |
| 238 | + | return "", true | |
| 239 | + | default: | |
| 240 | + | return "", false | |
| 241 | + | } | |
| 242 | + | } | |
| 243 | + | ||
| 244 | + | // Dispatch decodes one event on wp_presentation_feedback and calls the registered handlers. | |
| 245 | + | func (o *WpPresentationFeedback) Dispatch(event *wl.Event) { | |
| 246 | + | switch event.Opcode { | |
| 247 | + | case 0: // sync_output | |
| 248 | + | outputID := event.Uint32() | |
| 249 | + | ||
| 250 | + | for i, handler := range o.handlersForSyncOutput() { | |
| 251 | + | _ = i | |
| 252 | + | handler(outputID) | |
| 253 | + | } | |
| 254 | + | case 1: // presented | |
| 255 | + | tvSecHi := event.Uint32() | |
| 256 | + | tvSecLo := event.Uint32() | |
| 257 | + | tvNsec := event.Uint32() | |
| 258 | + | refresh := event.Uint32() | |
| 259 | + | seqHi := event.Uint32() | |
| 260 | + | seqLo := event.Uint32() | |
| 261 | + | flags := event.Uint32() | |
| 262 | + | ||
| 263 | + | for i, handler := range o.handlersForPresented() { | |
| 264 | + | _ = i | |
| 265 | + | handler(tvSecHi, tvSecLo, tvNsec, refresh, seqHi, seqLo, flags) | |
| 266 | + | } | |
| 267 | + | o.Context().Unregister(o) | |
| 268 | + | case 2: // discarded | |
| 269 | + | ||
| 270 | + | for i, handler := range o.handlersForDiscarded() { | |
| 271 | + | _ = i | |
| 272 | + | handler() | |
| 273 | + | } | |
| 274 | + | o.Context().Unregister(o) | |
| 275 | + | default: | |
| 276 | + | } | |
| 277 | + | } | |
A protocol/primaryselection/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package primaryselection | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p primaryselection -o primary-selection-unstable-v1_generated.go -import wl_seat=github.com/bnema/wlturbo/protocol/core primary-selection-unstable-v1.xml | |
A protocol/primaryselection/primary-selection-unstable-v1.xml +225 -0
| @@ -0,0 +1,225 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="wp_primary_selection_unstable_v1"> | |
| 3 | + | <copyright> | |
| 4 | + | Copyright © 2015, 2016 Red Hat | |
| 5 | + | ||
| 6 | + | Permission is hereby granted, free of charge, to any person obtaining a | |
| 7 | + | copy of this software and associated documentation files (the "Software"), | |
| 8 | + | to deal in the Software without restriction, including without limitation | |
| 9 | + | the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 10 | + | and/or sell copies of the Software, and to permit persons to whom the | |
| 11 | + | Software is furnished to do so, subject to the following conditions: | |
| 12 | + | ||
| 13 | + | The above copyright notice and this permission notice (including the next | |
| 14 | + | paragraph) shall be included in all copies or substantial portions of the | |
| 15 | + | Software. | |
| 16 | + | ||
| 17 | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 18 | + | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 19 | + | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 20 | + | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 21 | + | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 22 | + | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 23 | + | DEALINGS IN THE SOFTWARE. | |
| 24 | + | </copyright> | |
| 25 | + | ||
| 26 | + | <description summary="Primary selection protocol"> | |
| 27 | + | This protocol provides the ability to have a primary selection device to | |
| 28 | + | match that of the X server. This primary selection is a shortcut to the | |
| 29 | + | common clipboard selection, where text just needs to be selected in order | |
| 30 | + | to allow copying it elsewhere. The de facto way to perform this action | |
| 31 | + | is the middle mouse button, although it is not limited to this one. | |
| 32 | + | ||
| 33 | + | Clients wishing to honor primary selection should create a primary | |
| 34 | + | selection source and set it as the selection through | |
| 35 | + | wp_primary_selection_device.set_selection whenever the text selection | |
| 36 | + | changes. In order to minimize calls in pointer-driven text selection, | |
| 37 | + | it should happen only once after the operation finished. Similarly, | |
| 38 | + | a NULL source should be set when text is unselected. | |
| 39 | + | ||
| 40 | + | wp_primary_selection_offer objects are first announced through the | |
| 41 | + | wp_primary_selection_device.data_offer event. Immediately after this event, | |
| 42 | + | the primary data offer will emit wp_primary_selection_offer.offer events | |
| 43 | + | to let know of the mime types being offered. | |
| 44 | + | ||
| 45 | + | When the primary selection changes, the client with the keyboard focus | |
| 46 | + | will receive wp_primary_selection_device.selection events. Only the client | |
| 47 | + | with the keyboard focus will receive such events with a non-NULL | |
| 48 | + | wp_primary_selection_offer. Across keyboard focus changes, previously | |
| 49 | + | focused clients will receive wp_primary_selection_device.events with a | |
| 50 | + | NULL wp_primary_selection_offer. | |
| 51 | + | ||
| 52 | + | In order to request the primary selection data, the client must pass | |
| 53 | + | a recent serial pertaining to the press event that is triggering the | |
| 54 | + | operation, if the compositor deems the serial valid and recent, the | |
| 55 | + | wp_primary_selection_source.send event will happen in the other end | |
| 56 | + | to let the transfer begin. The client owning the primary selection | |
| 57 | + | should write the requested data, and close the file descriptor | |
| 58 | + | immediately. | |
| 59 | + | ||
| 60 | + | If the primary selection owner client disappeared during the transfer, | |
| 61 | + | the client reading the data will receive a | |
| 62 | + | wp_primary_selection_device.selection event with a NULL | |
| 63 | + | wp_primary_selection_offer, the client should take this as a hint | |
| 64 | + | to finish the reads related to the no longer existing offer. | |
| 65 | + | ||
| 66 | + | The primary selection owner should be checking for errors during | |
| 67 | + | writes, merely cancelling the ongoing transfer if any happened. | |
| 68 | + | </description> | |
| 69 | + | ||
| 70 | + | <interface name="zwp_primary_selection_device_manager_v1" version="1"> | |
| 71 | + | <description summary="X primary selection emulation"> | |
| 72 | + | The primary selection device manager is a singleton global object that | |
| 73 | + | provides access to the primary selection. It allows to create | |
| 74 | + | wp_primary_selection_source objects, as well as retrieving the per-seat | |
| 75 | + | wp_primary_selection_device objects. | |
| 76 | + | </description> | |
| 77 | + | ||
| 78 | + | <request name="create_source"> | |
| 79 | + | <description summary="create a new primary selection source"> | |
| 80 | + | Create a new primary selection source. | |
| 81 | + | </description> | |
| 82 | + | <arg name="id" type="new_id" interface="zwp_primary_selection_source_v1"/> | |
| 83 | + | </request> | |
| 84 | + | ||
| 85 | + | <request name="get_device"> | |
| 86 | + | <description summary="create a new primary selection device"> | |
| 87 | + | Create a new data device for a given seat. | |
| 88 | + | </description> | |
| 89 | + | <arg name="id" type="new_id" interface="zwp_primary_selection_device_v1"/> | |
| 90 | + | <arg name="seat" type="object" interface="wl_seat"/> | |
| 91 | + | </request> | |
| 92 | + | ||
| 93 | + | <request name="destroy" type="destructor"> | |
| 94 | + | <description summary="destroy the primary selection device manager"> | |
| 95 | + | Destroy the primary selection device manager. | |
| 96 | + | </description> | |
| 97 | + | </request> | |
| 98 | + | </interface> | |
| 99 | + | ||
| 100 | + | <interface name="zwp_primary_selection_device_v1" version="1"> | |
| 101 | + | <request name="set_selection"> | |
| 102 | + | <description summary="set the primary selection"> | |
| 103 | + | Replaces the current selection. The previous owner of the primary | |
| 104 | + | selection will receive a wp_primary_selection_source.cancelled event. | |
| 105 | + | ||
| 106 | + | To unset the selection, set the source to NULL. | |
| 107 | + | </description> | |
| 108 | + | <arg name="source" type="object" interface="zwp_primary_selection_source_v1" allow-null="true"/> | |
| 109 | + | <arg name="serial" type="uint" summary="serial of the event that triggered this request"/> | |
| 110 | + | </request> | |
| 111 | + | ||
| 112 | + | <event name="data_offer"> | |
| 113 | + | <description summary="introduce a new wp_primary_selection_offer"> | |
| 114 | + | Introduces a new wp_primary_selection_offer object that may be used | |
| 115 | + | to receive the current primary selection. Immediately following this | |
| 116 | + | event, the new wp_primary_selection_offer object will send | |
| 117 | + | wp_primary_selection_offer.offer events to describe the offered mime | |
| 118 | + | types. | |
| 119 | + | </description> | |
| 120 | + | <arg name="offer" type="new_id" interface="zwp_primary_selection_offer_v1"/> | |
| 121 | + | </event> | |
| 122 | + | ||
| 123 | + | <event name="selection"> | |
| 124 | + | <description summary="advertise a new primary selection"> | |
| 125 | + | The wp_primary_selection_device.selection event is sent to notify the | |
| 126 | + | client of a new primary selection. This event is sent after the | |
| 127 | + | wp_primary_selection.data_offer event introducing this object, and after | |
| 128 | + | the offer has announced its mimetypes through | |
| 129 | + | wp_primary_selection_offer.offer. | |
| 130 | + | ||
| 131 | + | The data_offer is valid until a new offer or NULL is received | |
| 132 | + | or until the client loses keyboard focus. The client must destroy the | |
| 133 | + | previous selection data_offer, if any, upon receiving this event. | |
| 134 | + | </description> | |
| 135 | + | <arg name="id" type="object" interface="zwp_primary_selection_offer_v1" allow-null="true"/> | |
| 136 | + | </event> | |
| 137 | + | ||
| 138 | + | <request name="destroy" type="destructor"> | |
| 139 | + | <description summary="destroy the primary selection device"> | |
| 140 | + | Destroy the primary selection device. | |
| 141 | + | </description> | |
| 142 | + | </request> | |
| 143 | + | </interface> | |
| 144 | + | ||
| 145 | + | <interface name="zwp_primary_selection_offer_v1" version="1"> | |
| 146 | + | <description summary="offer to transfer primary selection contents"> | |
| 147 | + | A wp_primary_selection_offer represents an offer to transfer the contents | |
| 148 | + | of the primary selection clipboard to the client. Similar to | |
| 149 | + | wl_data_offer, the offer also describes the mime types that the data can | |
| 150 | + | be converted to and provides the mechanisms for transferring the data | |
| 151 | + | directly to the client. | |
| 152 | + | </description> | |
| 153 | + | ||
| 154 | + | <request name="receive"> | |
| 155 | + | <description summary="request that the data is transferred"> | |
| 156 | + | To transfer the contents of the primary selection clipboard, the client | |
| 157 | + | issues this request and indicates the mime type that it wants to | |
| 158 | + | receive. The transfer happens through the passed file descriptor | |
| 159 | + | (typically created with the pipe system call). The source client writes | |
| 160 | + | the data in the mime type representation requested and then closes the | |
| 161 | + | file descriptor. | |
| 162 | + | ||
| 163 | + | The receiving client reads from the read end of the pipe until EOF and | |
| 164 | + | closes its end, at which point the transfer is complete. | |
| 165 | + | </description> | |
| 166 | + | <arg name="mime_type" type="string"/> | |
| 167 | + | <arg name="fd" type="fd"/> | |
| 168 | + | </request> | |
| 169 | + | ||
| 170 | + | <request name="destroy" type="destructor"> | |
| 171 | + | <description summary="destroy the primary selection offer"> | |
| 172 | + | Destroy the primary selection offer. | |
| 173 | + | </description> | |
| 174 | + | </request> | |
| 175 | + | ||
| 176 | + | <event name="offer"> | |
| 177 | + | <description summary="advertise offered mime type"> | |
| 178 | + | Sent immediately after creating announcing the | |
| 179 | + | wp_primary_selection_offer through | |
| 180 | + | wp_primary_selection_device.data_offer. One event is sent per offered | |
| 181 | + | mime type. | |
| 182 | + | </description> | |
| 183 | + | <arg name="mime_type" type="string"/> | |
| 184 | + | </event> | |
| 185 | + | </interface> | |
| 186 | + | ||
| 187 | + | <interface name="zwp_primary_selection_source_v1" version="1"> | |
| 188 | + | <description summary="offer to replace the contents of the primary selection"> | |
| 189 | + | The source side of a wp_primary_selection_offer, it provides a way to | |
| 190 | + | describe the offered data and respond to requests to transfer the | |
| 191 | + | requested contents of the primary selection clipboard. | |
| 192 | + | </description> | |
| 193 | + | ||
| 194 | + | <request name="offer"> | |
| 195 | + | <description summary="add an offered mime type"> | |
| 196 | + | This request adds a mime type to the set of mime types advertised to | |
| 197 | + | targets. Can be called several times to offer multiple types. | |
| 198 | + | </description> | |
| 199 | + | <arg name="mime_type" type="string"/> | |
| 200 | + | </request> | |
| 201 | + | ||
| 202 | + | <request name="destroy" type="destructor"> | |
| 203 | + | <description summary="destroy the primary selection source"> | |
| 204 | + | Destroy the primary selection source. | |
| 205 | + | </description> | |
| 206 | + | </request> | |
| 207 | + | ||
| 208 | + | <event name="send"> | |
| 209 | + | <description summary="send the primary selection contents"> | |
| 210 | + | Request for the current primary selection contents from the client. | |
| 211 | + | Send the specified mime type over the passed file descriptor, then | |
| 212 | + | close it. | |
| 213 | + | </description> | |
| 214 | + | <arg name="mime_type" type="string"/> | |
| 215 | + | <arg name="fd" type="fd"/> | |
| 216 | + | </event> | |
| 217 | + | ||
| 218 | + | <event name="cancelled"> | |
| 219 | + | <description summary="request for primary selection contents was canceled"> | |
| 220 | + | This primary selection source is no longer valid. The client should | |
| 221 | + | clean up and destroy this primary selection source. | |
| 222 | + | </description> | |
| 223 | + | </event> | |
| 224 | + | </interface> | |
| 225 | + | </protocol> | |
A protocol/primaryselection/primary-selection-unstable-v1_generated.go +420 -0 collapsed to keep the page light
A protocol/relativepointer/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package relativepointer | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p relativepointer -o relative-pointer-unstable-v1_generated.go -import wl_pointer=github.com/bnema/wlturbo/protocol/core relative-pointer-unstable-v1.xml | |
A protocol/relativepointer/relative-pointer-unstable-v1.xml +136 -0
| @@ -0,0 +1,136 @@ | |||
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | + | <protocol name="relative_pointer_unstable_v1"> | |
| 3 | + | ||
| 4 | + | <copyright> | |
| 5 | + | Copyright © 2014 Jonas Ådahl | |
| 6 | + | Copyright © 2015 Red Hat Inc. | |
| 7 | + | ||
| 8 | + | Permission is hereby granted, free of charge, to any person obtaining a | |
| 9 | + | copy of this software and associated documentation files (the "Software"), | |
| 10 | + | to deal in the Software without restriction, including without limitation | |
| 11 | + | the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 12 | + | and/or sell copies of the Software, and to permit persons to whom the | |
| 13 | + | Software is furnished to do so, subject to the following conditions: | |
| 14 | + | ||
| 15 | + | The above copyright notice and this permission notice (including the next | |
| 16 | + | paragraph) shall be included in all copies or substantial portions of the | |
| 17 | + | Software. | |
| 18 | + | ||
| 19 | + | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 23 | + | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 | + | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 25 | + | DEALINGS IN THE SOFTWARE. | |
| 26 | + | </copyright> | |
| 27 | + | ||
| 28 | + | <description summary="protocol for relative pointer motion events"> | |
| 29 | + | This protocol specifies a set of interfaces used for making clients able to | |
| 30 | + | receive relative pointer events not obstructed by barriers (such as the | |
| 31 | + | monitor edge or other pointer barriers). | |
| 32 | + | ||
| 33 | + | To start receiving relative pointer events, a client must first bind the | |
| 34 | + | global interface "wp_relative_pointer_manager" which, if a compositor | |
| 35 | + | supports relative pointer motion events, is exposed by the registry. After | |
| 36 | + | having created the relative pointer manager proxy object, the client uses | |
| 37 | + | it to create the actual relative pointer object using the | |
| 38 | + | "get_relative_pointer" request given a wl_pointer. The relative pointer | |
| 39 | + | motion events will then, when applicable, be transmitted via the proxy of | |
| 40 | + | the newly created relative pointer object. See the documentation of the | |
| 41 | + | relative pointer interface for more details. | |
| 42 | + | ||
| 43 | + | Warning! The protocol described in this file is experimental and backward | |
| 44 | + | incompatible changes may be made. Backward compatible changes may be added | |
| 45 | + | together with the corresponding interface version bump. Backward | |
| 46 | + | incompatible changes are done by bumping the version number in the protocol | |
| 47 | + | and interface names and resetting the interface version. Once the protocol | |
| 48 | + | is to be declared stable, the 'z' prefix and the version number in the | |
| 49 | + | protocol and interface names are removed and the interface version number is | |
| 50 | + | reset. | |
| 51 | + | </description> | |
| 52 | + | ||
| 53 | + | <interface name="zwp_relative_pointer_manager_v1" version="1"> | |
| 54 | + | <description summary="get relative pointer objects"> | |
| 55 | + | A global interface used for getting the relative pointer object for a | |
| 56 | + | given pointer. | |
| 57 | + | </description> | |
| 58 | + | ||
| 59 | + | <request name="destroy" type="destructor"> | |
| 60 | + | <description summary="destroy the relative pointer manager object"> | |
| 61 | + | Used by the client to notify the server that it will no longer use this | |
| 62 | + | relative pointer manager object. | |
| 63 | + | </description> | |
| 64 | + | </request> | |
| 65 | + | ||
| 66 | + | <request name="get_relative_pointer"> | |
| 67 | + | <description summary="get a relative pointer object"> | |
| 68 | + | Create a relative pointer interface given a wl_pointer object. See the | |
| 69 | + | wp_relative_pointer interface for more details. | |
| 70 | + | </description> | |
| 71 | + | <arg name="id" type="new_id" interface="zwp_relative_pointer_v1"/> | |
| 72 | + | <arg name="pointer" type="object" interface="wl_pointer"/> | |
| 73 | + | </request> | |
| 74 | + | </interface> | |
| 75 | + | ||
| 76 | + | <interface name="zwp_relative_pointer_v1" version="1"> | |
| 77 | + | <description summary="relative pointer object"> | |
| 78 | + | A wp_relative_pointer object is an extension to the wl_pointer interface | |
| 79 | + | used for emitting relative pointer events. It shares the same focus as | |
| 80 | + | wl_pointer objects of the same seat and will only emit events when it has | |
| 81 | + | focus. | |
| 82 | + | </description> | |
| 83 | + | ||
| 84 | + | <request name="destroy" type="destructor"> | |
| 85 | + | <description summary="release the relative pointer object"/> | |
| 86 | + | </request> | |
| 87 | + | ||
| 88 | + | <event name="relative_motion"> | |
| 89 | + | <description summary="relative pointer motion"> | |
| 90 | + | Relative x/y pointer motion from the pointer of the seat associated with | |
| 91 | + | this object. | |
| 92 | + | ||
| 93 | + | A relative motion is in the same dimension as regular wl_pointer motion | |
| 94 | + | events, except they do not represent an absolute position. For example, | |
| 95 | + | moving a pointer from (x, y) to (x', y') would have the equivalent | |
| 96 | + | relative motion (x' - x, y' - y). If a pointer motion caused the | |
| 97 | + | absolute pointer position to be clipped by for example the edge of the | |
| 98 | + | monitor, the relative motion is unaffected by the clipping and will | |
| 99 | + | represent the unclipped motion. | |
| 100 | + | ||
| 101 | + | This event also contains non-accelerated motion deltas. The | |
| 102 | + | non-accelerated delta is, when applicable, the regular pointer motion | |
| 103 | + | delta as it was before having applied motion acceleration and other | |
| 104 | + | transformations such as normalization. | |
| 105 | + | ||
| 106 | + | Note that the non-accelerated delta does not represent 'raw' events as | |
| 107 | + | they were read from some device. Pointer motion acceleration is device- | |
| 108 | + | and configuration-specific and non-accelerated deltas and accelerated | |
| 109 | + | deltas may have the same value on some devices. | |
| 110 | + | ||
| 111 | + | Relative motions are not coupled to wl_pointer.motion events, and can be | |
| 112 | + | sent in combination with such events, but also independently. There may | |
| 113 | + | also be scenarios where wl_pointer.motion is sent, but there is no | |
| 114 | + | relative motion. The order of an absolute and relative motion event | |
| 115 | + | originating from the same physical motion is not guaranteed. | |
| 116 | + | ||
| 117 | + | If the client needs button events or focus state, it can receive them | |
| 118 | + | from a wl_pointer object of the same seat that the wp_relative_pointer | |
| 119 | + | object is associated with. | |
| 120 | + | </description> | |
| 121 | + | <arg name="utime_hi" type="uint" | |
| 122 | + | summary="high 32 bits of a 64 bit timestamp with microsecond granularity"/> | |
| 123 | + | <arg name="utime_lo" type="uint" | |
| 124 | + | summary="low 32 bits of a 64 bit timestamp with microsecond granularity"/> | |
| 125 | + | <arg name="dx" type="fixed" | |
| 126 | + | summary="the x component of the motion vector"/> | |
| 127 | + | <arg name="dy" type="fixed" | |
| 128 | + | summary="the y component of the motion vector"/> | |
| 129 | + | <arg name="dx_unaccel" type="fixed" | |
| 130 | + | summary="the x component of the unaccelerated motion vector"/> | |
| 131 | + | <arg name="dy_unaccel" type="fixed" | |
| 132 | + | summary="the y component of the unaccelerated motion vector"/> | |
| 133 | + | </event> | |
| 134 | + | </interface> | |
| 135 | + | ||
| 136 | + | </protocol> | |
A protocol/relativepointer/relative-pointer-unstable-v1_generated.go +167 -0
| @@ -0,0 +1,167 @@ | |||
| 1 | + | // Code generated by wlturbo-scanner. DO NOT EDIT. | |
| 2 | + | // Protocol: relative_pointer_unstable_v1 | |
| 3 | + | // Source: relative-pointer-unstable-v1.xml | |
| 4 | + | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright © 2014 Jonas Ådahl | |
| 7 | + | // Copyright © 2015 Red Hat Inc. | |
| 8 | + | // | |
| 9 | + | // Permission is hereby granted, free of charge, to any person obtaining a | |
| 10 | + | // copy of this software and associated documentation files (the "Software"), | |
| 11 | + | // to deal in the Software without restriction, including without limitation | |
| 12 | + | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| 13 | + | // and/or sell copies of the Software, and to permit persons to whom the | |
| 14 | + | // Software is furnished to do so, subject to the following conditions: | |
| 15 | + | // | |
| 16 | + | // The above copyright notice and this permission notice (including the next | |
| 17 | + | // paragraph) shall be included in all copies or substantial portions of the | |
| 18 | + | // Software. | |
| 19 | + | // | |
| 20 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 21 | + | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 22 | + | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 23 | + | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 24 | + | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 25 | + | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
| 26 | + | // DEALINGS IN THE SOFTWARE. | |
| 27 | + | ||
| 28 | + | package relativepointer | |
| 29 | + | ||
| 30 | + | import ( | |
| 31 | + | "sync" | |
| 32 | + | ||
| 33 | + | cross_wl_pointer "github.com/bnema/wlturbo/protocol/core" | |
| 34 | + | "github.com/bnema/wlturbo/wl" | |
| 35 | + | ) | |
| 36 | + | ||
| 37 | + | // RelativePointerManagerInterface is the protocol interface name. | |
| 38 | + | const RelativePointerManagerInterface = "zwp_relative_pointer_manager_v1" | |
| 39 | + | ||
| 40 | + | // RelativePointerManager is the generated binding for zwp_relative_pointer_manager_v1 version 1. | |
| 41 | + | type RelativePointerManager struct { | |
| 42 | + | wl.BaseProxy | |
| 43 | + | } | |
| 44 | + | ||
| 45 | + | // NewRelativePointerManager returns an unbound RelativePointerManager. | |
| 46 | + | func NewRelativePointerManager(ctx *wl.Context) *RelativePointerManager { | |
| 47 | + | obj := &RelativePointerManager{} | |
| 48 | + | obj.SetContext(ctx) | |
| 49 | + | ctx.Register(obj) | |
| 50 | + | return obj | |
| 51 | + | } | |
| 52 | + | ||
| 53 | + | // Used by the client to notify the server that it will no longer use this relative pointer manager object. | |
| 54 | + | func (o *RelativePointerManager) Destroy() error { | |
| 55 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_relative_pointer_manager_v1.destroy", Destructor: true}); err != nil { | |
| 56 | + | return err | |
| 57 | + | } | |
| 58 | + | return nil | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | // Create a relative pointer interface given a wl_pointer object. See the wp_relative_pointer interface for more details. | |
| 62 | + | func (o *RelativePointerManager) GetRelativePointer(pointer *cross_wl_pointer.Pointer) (*RelativePointer, error) { | |
| 63 | + | var arg1 wl.Object | |
| 64 | + | if pointer != nil { | |
| 65 | + | arg1 = pointer | |
| 66 | + | } | |
| 67 | + | child := &RelativePointer{} | |
| 68 | + | child.SetContext(o.Context()) | |
| 69 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_relative_pointer_manager_v1.get_relative_pointer", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 70 | + | return nil, err | |
| 71 | + | } | |
| 72 | + | return child, nil | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | // EventSignature returns the declared event argument types in wire order. | |
| 76 | + | func (o *RelativePointerManager) EventSignature(opcode uint16) (string, bool) { | |
| 77 | + | switch opcode { | |
| 78 | + | default: | |
| 79 | + | return "", false | |
| 80 | + | } | |
| 81 | + | } | |
| 82 | + | ||
| 83 | + | // Dispatch decodes one event on zwp_relative_pointer_manager_v1 and calls the registered handlers. | |
| 84 | + | func (o *RelativePointerManager) Dispatch(event *wl.Event) { | |
| 85 | + | switch event.Opcode { | |
| 86 | + | default: | |
| 87 | + | } | |
| 88 | + | } | |
| 89 | + | ||
| 90 | + | // RelativePointerInterface is the protocol interface name. | |
| 91 | + | const RelativePointerInterface = "zwp_relative_pointer_v1" | |
| 92 | + | ||
| 93 | + | // RelativePointer is the generated binding for zwp_relative_pointer_v1 version 1. | |
| 94 | + | type RelativePointer struct { | |
| 95 | + | wl.BaseProxy | |
| 96 | + | // handlersMu guards the handler slices: a client may register or replace | |
| 97 | + | // handlers while another goroutine dispatches events. | |
| 98 | + | handlersMu sync.Mutex | |
| 99 | + | onRelativeMotion []func(utimeHi uint32, utimeLo uint32, dx wl.Fixed, dy wl.Fixed, dxUnaccel wl.Fixed, dyUnaccel wl.Fixed) | |
| 100 | + | } | |
| 101 | + | ||
| 102 | + | // NewRelativePointer returns an unbound RelativePointer. | |
| 103 | + | func NewRelativePointer(ctx *wl.Context) *RelativePointer { | |
| 104 | + | obj := &RelativePointer{} | |
| 105 | + | obj.SetContext(ctx) | |
| 106 | + | ctx.Register(obj) | |
| 107 | + | return obj | |
| 108 | + | } | |
| 109 | + | ||
| 110 | + | // release the relative pointer object | |
| 111 | + | func (o *RelativePointer) Destroy() error { | |
| 112 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_relative_pointer_v1.destroy", Destructor: true}); err != nil { | |
| 113 | + | return err | |
| 114 | + | } | |
| 115 | + | return nil | |
| 116 | + | } | |
| 117 | + | ||
| 118 | + | // OnRelativeMotion registers a handler for the relative_motion event. | |
| 119 | + | // | |
| 120 | + | // Handlers are appended, so a second call adds another handler rather than | |
| 121 | + | // replacing the first. Registration is safe while another goroutine dispatches. | |
| 122 | + | func (o *RelativePointer) OnRelativeMotion(handler func(utimeHi uint32, utimeLo uint32, dx wl.Fixed, dy wl.Fixed, dxUnaccel wl.Fixed, dyUnaccel wl.Fixed)) { | |
| 123 | + | if handler == nil { | |
| 124 | + | return | |
| 125 | + | } | |
| 126 | + | o.handlersMu.Lock() | |
| 127 | + | defer o.handlersMu.Unlock() | |
| 128 | + | o.onRelativeMotion = append(o.onRelativeMotion, handler) | |
| 129 | + | } | |
| 130 | + | ||
| 131 | + | // handlersForRelativeMotion returns the handlers registered for relative_motion, taken | |
| 132 | + | // under the lock so a handler may register another handler while events are | |
| 133 | + | // being dispatched. | |
| 134 | + | func (o *RelativePointer) handlersForRelativeMotion() []func(utimeHi uint32, utimeLo uint32, dx wl.Fixed, dy wl.Fixed, dxUnaccel wl.Fixed, dyUnaccel wl.Fixed) { | |
| 135 | + | o.handlersMu.Lock() | |
| 136 | + | defer o.handlersMu.Unlock() | |
| 137 | + | return o.onRelativeMotion | |
| 138 | + | } | |
| 139 | + | ||
| 140 | + | // EventSignature returns the declared event argument types in wire order. | |
| 141 | + | func (o *RelativePointer) EventSignature(opcode uint16) (string, bool) { | |
| 142 | + | switch opcode { | |
| 143 | + | case 0: | |
| 144 | + | return "uint,uint,fixed,fixed,fixed,fixed,", true | |
| 145 | + | default: | |
| 146 | + | return "", false | |
| 147 | + | } | |
| 148 | + | } | |
| 149 | + | ||
| 150 | + | // Dispatch decodes one event on zwp_relative_pointer_v1 and calls the registered handlers. | |
| 151 | + | func (o *RelativePointer) Dispatch(event *wl.Event) { | |
| 152 | + | switch event.Opcode { | |
| 153 | + | case 0: // relative_motion | |
| 154 | + | utimeHi := event.Uint32() | |
| 155 | + | utimeLo := event.Uint32() | |
| 156 | + | dx := event.Fixed() | |
| 157 | + | dy := event.Fixed() | |
| 158 | + | dxUnaccel := event.Fixed() | |
| 159 | + | dyUnaccel := event.Fixed() | |
| 160 | + | ||
| 161 | + | for i, handler := range o.handlersForRelativeMotion() { | |
| 162 | + | _ = i | |
| 163 | + | handler(utimeHi, utimeLo, dx, dy, dxUnaccel, dyUnaccel) | |
| 164 | + | } | |
| 165 | + | default: | |
| 166 | + | } | |
| 167 | + | } | |
A protocol/render_extensions_test.go +864 -0 collapsed to keep the page light
A protocol/screencopy/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package screencopy | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p screencopy -o wlr-screencopy-unstable-v1_generated.go -import wl_output=github.com/bnema/wlturbo/protocol/core -import wl_buffer=github.com/bnema/wlturbo/protocol/core wlr-screencopy-unstable-v1.xml | |
A protocol/screencopy/wlr-screencopy-unstable-v1.xml +234 -0 collapsed to keep the page light
A protocol/screencopy/wlr-screencopy-unstable-v1_generated.go +410 -0 collapsed to keep the page light
A protocol/shortcutsinhibit/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package shortcutsinhibit | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p shortcutsinhibit -o keyboard-shortcuts-inhibit-unstable-v1_generated.go -import wl_seat=github.com/bnema/wlturbo/protocol/core -import wl_surface=github.com/bnema/wlturbo/protocol/core keyboard-shortcuts-inhibit-unstable-v1.xml | |
A protocol/shortcutsinhibit/keyboard-shortcuts-inhibit-unstable-v1.xml +143 -0 collapsed to keep the page light
A protocol/shortcutsinhibit/keyboard-shortcuts-inhibit-unstable-v1_generated.go +199 -0 collapsed to keep the page light
M protocol/tablet/tablet-v2_generated.go +40 -15
| @@ -2,6 +2,31 @@ | |||
| 2 | 2 | // Protocol: tablet_v2 | |
| 3 | 3 | // Source: tablet-v2.xml | |
| 4 | 4 | ||
| 5 | + | // Upstream protocol copyright and license: | |
| 6 | + | // Copyright 2014 © Stephen "Lyude" Chandler Paul | |
| 7 | + | // Copyright 2015-2024 © Red Hat, Inc. | |
| 8 | + | // | |
| 9 | + | // Permission is hereby granted, free of charge, to any person | |
| 10 | + | // obtaining a copy of this software and associated documentation files | |
| 11 | + | // (the "Software"), to deal in the Software without restriction, | |
| 12 | + | // including without limitation the rights to use, copy, modify, merge, | |
| 13 | + | // publish, distribute, sublicense, and/or sell copies of the Software, | |
| 14 | + | // and to permit persons to whom the Software is furnished to do so, | |
| 15 | + | // subject to the following conditions: | |
| 16 | + | // | |
| 17 | + | // The above copyright notice and this permission notice (including the | |
| 18 | + | // next paragraph) shall be included in all copies or substantial | |
| 19 | + | // portions of the Software. | |
| 20 | + | // | |
| 21 | + | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
| 22 | + | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
| 23 | + | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
| 24 | + | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
| 25 | + | // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
| 26 | + | // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
| 27 | + | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 28 | + | // SOFTWARE. | |
| 29 | + | ||
| 5 | 30 | package tablet | |
| 6 | 31 | ||
| 7 | 32 | import ( | |
| @@ -114,7 +139,7 @@ func (o *TabletManager) GetTabletSeat(seat *cross_wl_seat.Seat) (*TabletSeat, er | |||
| 114 | 139 | } | |
| 115 | 140 | child := &TabletSeat{} | |
| 116 | 141 | child.SetContext(o.Context()) | |
| 117 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_manager_v2.get_tablet_seat", Child: child}, child, arg1); err != nil { | |
| 142 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_manager_v2.get_tablet_seat", Child: child}, wl.ArgObject(child), wl.ArgObject(arg1)); err != nil { | |
| 118 | 143 | return nil, err | |
| 119 | 144 | } | |
| 120 | 145 | return child, nil | |
| @@ -122,7 +147,7 @@ func (o *TabletManager) GetTabletSeat(seat *cross_wl_seat.Seat) (*TabletSeat, er | |||
| 122 | 147 | ||
| 123 | 148 | // Destroy the zwp_tablet_manager_v2 object. Objects created from this object are unaffected and should be destroyed separately. | |
| 124 | 149 | func (o *TabletManager) Destroy() error { | |
| 125 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_manager_v2.destroy", Destructor: true}); err != nil { | |
| 150 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_manager_v2.destroy", Destructor: true}); err != nil { | |
| 126 | 151 | return err | |
| 127 | 152 | } | |
| 128 | 153 | return nil | |
| @@ -167,7 +192,7 @@ func NewTabletSeat(ctx *wl.Context) *TabletSeat { | |||
| 167 | 192 | ||
| 168 | 193 | // Destroy the zwp_tablet_seat_v2 object. Objects created from this object are unaffected and should be destroyed separately. | |
| 169 | 194 | func (o *TabletSeat) Destroy() error { | |
| 170 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_seat_v2.destroy", Destructor: true}); err != nil { | |
| 195 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_seat_v2.destroy", Destructor: true}); err != nil { | |
| 171 | 196 | return err | |
| 172 | 197 | } | |
| 173 | 198 | return nil | |
| @@ -340,7 +365,7 @@ func (o *TabletTool) SetCursor(serial uint32, surface *cross_wl_surface.Surface, | |||
| 340 | 365 | if surface != nil { | |
| 341 | 366 | arg1 = surface | |
| 342 | 367 | } | |
| 343 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_tool_v2.set_cursor"}, serial, arg1, hotspotX, hotspotY); err != nil { | |
| 368 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_tool_v2.set_cursor"}, wl.ArgUint(serial), wl.ArgObject(arg1), wl.ArgInt(hotspotX), wl.ArgInt(hotspotY)); err != nil { | |
| 344 | 369 | return err | |
| 345 | 370 | } | |
| 346 | 371 | return nil | |
| @@ -348,7 +373,7 @@ func (o *TabletTool) SetCursor(serial uint32, surface *cross_wl_surface.Surface, | |||
| 348 | 373 | ||
| 349 | 374 | // This destroys the client's resource for this tool object. | |
| 350 | 375 | func (o *TabletTool) Destroy() error { | |
| 351 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_tool_v2.destroy", Destructor: true}); err != nil { | |
| 376 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_tool_v2.destroy", Destructor: true}); err != nil { | |
| 352 | 377 | return err | |
| 353 | 378 | } | |
| 354 | 379 | return nil | |
| @@ -990,7 +1015,7 @@ func NewTablet(ctx *wl.Context) *Tablet { | |||
| 990 | 1015 | ||
| 991 | 1016 | // This destroys the client's resource for this tablet object. | |
| 992 | 1017 | func (o *Tablet) Destroy() error { | |
| 993 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_v2.destroy", Destructor: true}); err != nil { | |
| 1018 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_v2.destroy", Destructor: true}); err != nil { | |
| 994 | 1019 | return err | |
| 995 | 1020 | } | |
| 996 | 1021 | return nil | |
| @@ -1221,7 +1246,7 @@ func NewTabletPadRing(ctx *wl.Context) *TabletPadRing { | |||
| 1221 | 1246 | ||
| 1222 | 1247 | // Request that the compositor use the provided feedback string associated with this ring. This request should be issued immediately after a zwp_tablet_pad_group_v2.mode_switch event from the corresponding group is received, or whenever the ring is mapped to a different action. See zwp_tablet_pad_group_v2.mode_switch for more details. Clients are encouraged to provide context-aware descriptions for the actions associated with the ring; compositors may use this information to offer visual feedback about the button layout (eg. on-screen displays). The provided string 'description' is a UTF-8 encoded string to be associated with this ring, and is considered user-visible; general internationalization rules apply. The serial argument will be that of the last zwp_tablet_pad_group_v2.mode_switch event received for the group of this ring. Requests providing other serials than the most recent one will be ignored. | |
| 1223 | 1248 | func (o *TabletPadRing) SetFeedback(description string, serial uint32) error { | |
| 1224 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_pad_ring_v2.set_feedback"}, description, serial); err != nil { | |
| 1249 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_pad_ring_v2.set_feedback"}, wl.ArgString(description), wl.ArgUint(serial)); err != nil { | |
| 1225 | 1250 | return err | |
| 1226 | 1251 | } | |
| 1227 | 1252 | return nil | |
| @@ -1229,7 +1254,7 @@ func (o *TabletPadRing) SetFeedback(description string, serial uint32) error { | |||
| 1229 | 1254 | ||
| 1230 | 1255 | // This destroys the client's resource for this ring object. | |
| 1231 | 1256 | func (o *TabletPadRing) Destroy() error { | |
| 1232 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_pad_ring_v2.destroy", Destructor: true}); err != nil { | |
| 1257 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_pad_ring_v2.destroy", Destructor: true}); err != nil { | |
| 1233 | 1258 | return err | |
| 1234 | 1259 | } | |
| 1235 | 1260 | return nil | |
| @@ -1398,7 +1423,7 @@ func NewTabletPadStrip(ctx *wl.Context) *TabletPadStrip { | |||
| 1398 | 1423 | ||
| 1399 | 1424 | // Requests the compositor to use the provided feedback string associated with this strip. This request should be issued immediately after a zwp_tablet_pad_group_v2.mode_switch event from the corresponding group is received, or whenever the strip is mapped to a different action. See zwp_tablet_pad_group_v2.mode_switch for more details. Clients are encouraged to provide context-aware descriptions for the actions associated with the strip, and compositors may use this information to offer visual feedback about the button layout (eg. on-screen displays). The provided string 'description' is a UTF-8 encoded string to be associated with this ring, and is considered user-visible; general internationalization rules apply. The serial argument will be that of the last zwp_tablet_pad_group_v2.mode_switch event received for the group of this strip. Requests providing other serials than the most recent one will be ignored. | |
| 1400 | 1425 | func (o *TabletPadStrip) SetFeedback(description string, serial uint32) error { | |
| 1401 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_pad_strip_v2.set_feedback"}, description, serial); err != nil { | |
| 1426 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_pad_strip_v2.set_feedback"}, wl.ArgString(description), wl.ArgUint(serial)); err != nil { | |
| 1402 | 1427 | return err | |
| 1403 | 1428 | } | |
| 1404 | 1429 | return nil | |
| @@ -1406,7 +1431,7 @@ func (o *TabletPadStrip) SetFeedback(description string, serial uint32) error { | |||
| 1406 | 1431 | ||
| 1407 | 1432 | // This destroys the client's resource for this strip object. | |
| 1408 | 1433 | func (o *TabletPadStrip) Destroy() error { | |
| 1409 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_pad_strip_v2.destroy", Destructor: true}); err != nil { | |
| 1434 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_pad_strip_v2.destroy", Destructor: true}); err != nil { | |
| 1410 | 1435 | return err | |
| 1411 | 1436 | } | |
| 1412 | 1437 | return nil | |
| @@ -1578,7 +1603,7 @@ func NewTabletPadGroup(ctx *wl.Context) *TabletPadGroup { | |||
| 1578 | 1603 | ||
| 1579 | 1604 | // Destroy the zwp_tablet_pad_group_v2 object. Objects created from this object are unaffected and should be destroyed separately. | |
| 1580 | 1605 | func (o *TabletPadGroup) Destroy() error { | |
| 1581 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_pad_group_v2.destroy", Destructor: true}); err != nil { | |
| 1606 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_pad_group_v2.destroy", Destructor: true}); err != nil { | |
| 1582 | 1607 | return err | |
| 1583 | 1608 | } | |
| 1584 | 1609 | return nil | |
| @@ -1861,7 +1886,7 @@ func NewTabletPad(ctx *wl.Context) *TabletPad { | |||
| 1861 | 1886 | ||
| 1862 | 1887 | // Requests the compositor to use the provided feedback string associated with this button. This request should be issued immediately after a zwp_tablet_pad_group_v2.mode_switch event from the corresponding group is received, or whenever a button is mapped to a different action. See zwp_tablet_pad_group_v2.mode_switch for more details. Clients are encouraged to provide context-aware descriptions for the actions associated with each button, and compositors may use this information to offer visual feedback on the button layout (e.g. on-screen displays). Button indices start at 0. Setting the feedback string on a button that is reserved by the compositor (i.e. not belonging to any zwp_tablet_pad_group_v2) does not generate an error but the compositor is free to ignore the request. The provided string 'description' is a UTF-8 encoded string to be associated with this ring, and is considered user-visible; general internationalization rules apply. The serial argument will be that of the last zwp_tablet_pad_group_v2.mode_switch event received for the group of this button. Requests providing other serials than the most recent one will be ignored. | |
| 1863 | 1888 | func (o *TabletPad) SetFeedback(button uint32, description string, serial uint32) error { | |
| 1864 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_pad_v2.set_feedback"}, button, description, serial); err != nil { | |
| 1889 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_pad_v2.set_feedback"}, wl.ArgUint(button), wl.ArgString(description), wl.ArgUint(serial)); err != nil { | |
| 1865 | 1890 | return err | |
| 1866 | 1891 | } | |
| 1867 | 1892 | return nil | |
| @@ -1869,7 +1894,7 @@ func (o *TabletPad) SetFeedback(button uint32, description string, serial uint32 | |||
| 1869 | 1894 | ||
| 1870 | 1895 | // Destroy the zwp_tablet_pad_v2 object. Objects created from this object are unaffected and should be destroyed separately. | |
| 1871 | 1896 | func (o *TabletPad) Destroy() error { | |
| 1872 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_pad_v2.destroy", Destructor: true}); err != nil { | |
| 1897 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_pad_v2.destroy", Destructor: true}); err != nil { | |
| 1873 | 1898 | return err | |
| 1874 | 1899 | } | |
| 1875 | 1900 | return nil | |
| @@ -2169,7 +2194,7 @@ func NewTabletPadDial(ctx *wl.Context) *TabletPadDial { | |||
| 2169 | 2194 | ||
| 2170 | 2195 | // Requests the compositor to use the provided feedback string associated with this dial. This request should be issued immediately after a zwp_tablet_pad_group_v2.mode_switch event from the corresponding group is received, or whenever the dial is mapped to a different action. See zwp_tablet_pad_group_v2.mode_switch for more details. Clients are encouraged to provide context-aware descriptions for the actions associated with the dial, and compositors may use this information to offer visual feedback about the button layout (eg. on-screen displays). The provided string 'description' is a UTF-8 encoded string to be associated with this ring, and is considered user-visible; general internationalization rules apply. The serial argument will be that of the last zwp_tablet_pad_group_v2.mode_switch event received for the group of this dial. Requests providing other serials than the most recent one will be ignored. | |
| 2171 | 2196 | func (o *TabletPadDial) SetFeedback(description string, serial uint32) error { | |
| 2172 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_pad_dial_v2.set_feedback"}, description, serial); err != nil { | |
| 2197 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_pad_dial_v2.set_feedback"}, wl.ArgString(description), wl.ArgUint(serial)); err != nil { | |
| 2173 | 2198 | return err | |
| 2174 | 2199 | } | |
| 2175 | 2200 | return nil | |
| @@ -2177,7 +2202,7 @@ func (o *TabletPadDial) SetFeedback(description string, serial uint32) error { | |||
| 2177 | 2202 | ||
| 2178 | 2203 | // This destroys the client's resource for this dial object. | |
| 2179 | 2204 | func (o *TabletPadDial) Destroy() error { | |
| 2180 | - | if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_pad_dial_v2.destroy", Destructor: true}); err != nil { | |
| 2205 | + | if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_pad_dial_v2.destroy", Destructor: true}); err != nil { | |
| 2181 | 2206 | return err | |
| 2182 | 2207 | } | |
| 2183 | 2208 | return nil | |
A protocol/tearingcontrol/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package tearingcontrol | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p tearingcontrol -o tearing-control-v1_generated.go -import wl_surface=github.com/bnema/wlturbo/protocol/core tearing-control-v1.xml | |
A protocol/tearingcontrol/tearing-control-v1.xml +123 -0 collapsed to keep the page light
A protocol/tearingcontrol/tearing-control-v1_generated.go +141 -0 collapsed to keep the page light
M protocol/textinput/text-input-unstable-v3_generated.go +40 -13 collapsed to keep the page light
M protocol/viewporter/viewporter_generated.go +27 -5 collapsed to keep the page light
A protocol/virtualkeyboard/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package virtualkeyboard | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p virtualkeyboard -o virtual-keyboard-unstable-v1_generated.go -import wl_seat=github.com/bnema/wlturbo/protocol/core virtual-keyboard-unstable-v1.xml | |
A protocol/virtualkeyboard/virtual-keyboard-unstable-v1.xml +113 -0 collapsed to keep the page light
A protocol/virtualkeyboard/virtual-keyboard-unstable-v1_generated.go +149 -0 collapsed to keep the page light
A protocol/wlr_extensions_test.go +652 -0
| @@ -0,0 +1,652 @@ | |||
| 1 | + | //go:build linux | |
| 2 | + | ||
| 3 | + | package protocol_test | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "bytes" | |
| 7 | + | "encoding/binary" | |
| 8 | + | "errors" | |
| 9 | + | "os" | |
| 10 | + | "reflect" | |
| 11 | + | "testing" | |
| 12 | + | "time" | |
| 13 | + | ||
| 14 | + | "github.com/bnema/wlturbo" | |
| 15 | + | "github.com/bnema/wlturbo/protocol/core" | |
| 16 | + | "github.com/bnema/wlturbo/protocol/foreigntoplevel" | |
| 17 | + | "github.com/bnema/wlturbo/protocol/inputmethod" | |
| 18 | + | "github.com/bnema/wlturbo/protocol/kdeserverdecoration" | |
| 19 | + | "github.com/bnema/wlturbo/protocol/layershell" | |
| 20 | + | "github.com/bnema/wlturbo/protocol/outputmanagement" | |
| 21 | + | "github.com/bnema/wlturbo/protocol/outputpower" | |
| 22 | + | "github.com/bnema/wlturbo/protocol/screencopy" | |
| 23 | + | "github.com/bnema/wlturbo/protocol/textinput" | |
| 24 | + | "github.com/bnema/wlturbo/protocol/virtualkeyboard" | |
| 25 | + | "github.com/bnema/wlturbo/protocol/xdgshell" | |
| 26 | + | "golang.org/x/sys/unix" | |
| 27 | + | ) | |
| 28 | + | ||
| 29 | + | // The output head, its modes and configuration objects are all created by | |
| 30 | + | // server events (new_id in an event) or nested client requests. | |
| 31 | + | func TestWlrOutputManagementHeadNewID(t *testing.T) { | |
| 32 | + | s := newWireEnv(t) | |
| 33 | + | mgr := outputmanagement.NewOutputManager(s.d.Context()) | |
| 34 | + | s.bind(1, outputmanagement.OutputManagerInterface, 4, 4, mgr) | |
| 35 | + | ||
| 36 | + | var head *outputmanagement.OutputHead | |
| 37 | + | mgr.OnHead(func(h *outputmanagement.OutputHead) { head = h }) | |
| 38 | + | var serial uint32 | |
| 39 | + | mgr.OnDone(func(v uint32) { serial = v }) | |
| 40 | + | s.event(mgr.ID(), 0, wordBytes(serverID+1)...) | |
| 41 | + | if head == nil || head.ID() != serverID+1 || head.Version() != mgr.Version() || head.Version() != 4 { | |
| 42 | + | t.Fatalf("head %+v", head) | |
| 43 | + | } | |
| 44 | + | ||
| 45 | + | var name string | |
| 46 | + | var mode *outputmanagement.OutputMode | |
| 47 | + | var current uint32 | |
| 48 | + | var scale wlturbo.Fixed | |
| 49 | + | var enabled int32 | |
| 50 | + | head.OnName(func(v string) { name = v }) | |
| 51 | + | head.OnMode(func(m *outputmanagement.OutputMode) { mode = m }) | |
| 52 | + | head.OnCurrentMode(func(id uint32) { current = id }) | |
| 53 | + | head.OnScale(func(v wlturbo.Fixed) { scale = v }) | |
| 54 | + | head.OnEnabled(func(v int32) { enabled = v }) | |
| 55 | + | s.event(head.ID(), 0, str("HDMI-A-1")...) | |
| 56 | + | s.event(head.ID(), 3, wordBytes(serverID+2)...) | |
| 57 | + | if mode == nil || mode.ID() != serverID+2 || mode.Version() != 4 { | |
| 58 | + | t.Fatalf("mode %+v", mode) | |
| 59 | + | } | |
| 60 | + | var w, h, refresh int32 | |
| 61 | + | var preferred bool | |
| 62 | + | mode.OnSize(func(a, b int32) { w, h = a, b }) | |
| 63 | + | mode.OnRefresh(func(v int32) { refresh = v }) | |
| 64 | + | mode.OnPreferred(func() { preferred = true }) | |
| 65 | + | s.event(mode.ID(), 0, wordBytes(1920, 1080)...) | |
| 66 | + | s.event(mode.ID(), 1, wordBytes(60000)...) | |
| 67 | + | s.event(mode.ID(), 2) | |
| 68 | + | s.event(head.ID(), 4, wordBytes(1)...) | |
| 69 | + | s.event(head.ID(), 5, wordBytes(mode.ID())...) | |
| 70 | + | s.event(head.ID(), 8, wordBytes(uint32(wlturbo.NewFixed(1.5)))...) | |
| 71 | + | s.event(mgr.ID(), 1, wordBytes(41)...) | |
| 72 | + | if name != "HDMI-A-1" || w != 1920 || h != 1080 || refresh != 60000 || !preferred || | |
| 73 | + | enabled != 1 || current != mode.ID() || scale.Float64() != 1.5 || serial != 41 { | |
| 74 | + | t.Fatal(name, w, h, refresh, preferred, enabled, current, scale, serial) | |
| 75 | + | } | |
| 76 | + | ||
| 77 | + | // create_configuration -> enable_head (new_id + object) -> setters -> apply. | |
| 78 | + | cfg, e := mgr.CreateConfiguration(serial) | |
| 79 | + | noerr(t, e) | |
| 80 | + | wantWords(t, "create_configuration", s.req(mgr.ID(), 0), cfg.ID(), 41) | |
| 81 | + | ch, e := cfg.EnableHead(head) | |
| 82 | + | noerr(t, e) | |
| 83 | + | wantWords(t, "enable_head", s.req(cfg.ID(), 0), ch.ID(), head.ID()) | |
| 84 | + | noerr(t, ch.SetMode(mode)) | |
| 85 | + | wantWords(t, "set_mode", s.req(ch.ID(), 0), mode.ID()) | |
| 86 | + | noerr(t, ch.SetPosition(-10, 20)) | |
| 87 | + | wantWords(t, "set_position", s.req(ch.ID(), 2), 0xfffffff6, 20) | |
| 88 | + | noerr(t, ch.SetTransform(core.TRANSFORM_90)) | |
| 89 | + | wantWords(t, "set_transform", s.req(ch.ID(), 3), core.TRANSFORM_90) | |
| 90 | + | noerr(t, ch.SetScale(wlturbo.NewFixed(2))) | |
| 91 | + | wantWords(t, "set_scale", s.req(ch.ID(), 4), uint32(wlturbo.NewFixed(2))) | |
| 92 | + | noerr(t, ch.SetAdaptiveSync(outputmanagement.ADAPTIVE_SYNC_STATE_ENABLED)) | |
| 93 | + | wantWords(t, "set_adaptive_sync", s.req(ch.ID(), 5), 1) | |
| 94 | + | noerr(t, cfg.Test()) | |
| 95 | + | s.req(cfg.ID(), 3) | |
| 96 | + | noerr(t, cfg.Apply()) | |
| 97 | + | s.req(cfg.ID(), 2) | |
| 98 | + | var results []string | |
| 99 | + | cfg.OnSucceeded(func() { results = append(results, "succeeded") }) | |
| 100 | + | cfg.OnFailed(func() { results = append(results, "failed") }) | |
| 101 | + | cfg.OnCancelled(func() { results = append(results, "cancelled") }) | |
| 102 | + | s.event(cfg.ID(), 0) | |
| 103 | + | s.event(cfg.ID(), 1) | |
| 104 | + | s.event(cfg.ID(), 2) | |
| 105 | + | if !reflect.DeepEqual(results, []string{"succeeded", "failed", "cancelled"}) { | |
| 106 | + | t.Fatal(results) | |
| 107 | + | } | |
| 108 | + | noerr(t, cfg.Destroy()) | |
| 109 | + | s.req(cfg.ID(), 4) | |
| 110 | + | ||
| 111 | + | // Release destructors (since 3) and manager finished (destructor event). | |
| 112 | + | var headFinished bool | |
| 113 | + | head.OnFinished(func() { headFinished = true }) | |
| 114 | + | s.event(head.ID(), 9) | |
| 115 | + | if !headFinished { | |
| 116 | + | t.Fatal("head finished not delivered") | |
| 117 | + | } | |
| 118 | + | noerr(t, mode.Release()) | |
| 119 | + | s.req(mode.ID(), 0) | |
| 120 | + | noerr(t, head.Release()) | |
| 121 | + | s.req(head.ID(), 0) | |
| 122 | + | noerr(t, mgr.Stop()) | |
| 123 | + | s.req(mgr.ID(), 1) | |
| 124 | + | var finished bool | |
| 125 | + | mgr.OnFinished(func() { finished = true }) | |
| 126 | + | s.event(mgr.ID(), 2) | |
| 127 | + | if !finished { | |
| 128 | + | t.Fatal("finished not delivered") | |
| 129 | + | } | |
| 130 | + | if e := mgr.Stop(); e == nil { | |
| 131 | + | t.Fatal("request on a finished manager must fail") | |
| 132 | + | } | |
| 133 | + | s.noRequest() | |
| 134 | + | } | |
| 135 | + | ||
| 136 | + | func TestWlrOutputManagementVersionGate(t *testing.T) { | |
| 137 | + | s := newWireEnv(t) | |
| 138 | + | mgr := outputmanagement.NewOutputManager(s.d.Context()) | |
| 139 | + | s.bind(1, outputmanagement.OutputManagerInterface, 4, 2, mgr) | |
| 140 | + | var head *outputmanagement.OutputHead | |
| 141 | + | mgr.OnHead(func(h *outputmanagement.OutputHead) { head = h }) | |
| 142 | + | s.event(mgr.ID(), 0, wordBytes(serverID+1)...) | |
| 143 | + | if head == nil || head.Version() != 2 { | |
| 144 | + | t.Fatalf("head %+v", head) | |
| 145 | + | } | |
| 146 | + | if e := head.Release(); !errors.Is(e, wlturbo.ErrVersionTooLow) { | |
| 147 | + | t.Fatalf("release on v2 head: %v", e) | |
| 148 | + | } | |
| 149 | + | s.noRequest() | |
| 150 | + | } | |
| 151 | + | ||
| 152 | + | func TestWlrScreencopyBufferFlow(t *testing.T) { | |
| 153 | + | s := newWireEnv(t) | |
| 154 | + | out := s.output() | |
| 155 | + | shm := core.NewShm(s.d.Context()) | |
| 156 | + | s.bind(1, core.ShmInterface, 1, 1, shm) | |
| 157 | + | mgr := screencopy.NewScreencopyManager(s.d.Context()) | |
| 158 | + | s.bind(2, screencopy.ScreencopyManagerInterface, 3, 3, mgr) | |
| 159 | + | ||
| 160 | + | frame, e := mgr.CaptureOutput(1, out) | |
| 161 | + | noerr(t, e) | |
| 162 | + | wantWords(t, "capture_output", s.req(mgr.ID(), 0), frame.ID(), 1, out.ID()) | |
| 163 | + | if frame.Version() != 3 { | |
| 164 | + | t.Fatalf("frame version %d", frame.Version()) | |
| 165 | + | } | |
| 166 | + | var events []string | |
| 167 | + | var shmW, shmH, shmStride, shmFormat uint32 | |
| 168 | + | frame.OnBuffer(func(f, w, h, st uint32) { | |
| 169 | + | shmFormat, shmW, shmH, shmStride = f, w, h, st | |
| 170 | + | events = append(events, "buffer") | |
| 171 | + | }) | |
| 172 | + | frame.OnLinuxDmabuf(func(f, w, h uint32) { events = append(events, "dmabuf") }) | |
| 173 | + | frame.OnBufferDone(func() { events = append(events, "done") }) | |
| 174 | + | frame.OnFlags(func(f uint32) { | |
| 175 | + | if f != screencopy.FLAGS_Y_INVERT { | |
| 176 | + | t.Fatalf("flags %d", f) | |
| 177 | + | } | |
| 178 | + | events = append(events, "flags") | |
| 179 | + | }) | |
| 180 | + | var sec uint64 | |
| 181 | + | var nsec uint32 | |
| 182 | + | frame.OnReady(func(hi, lo, ns uint32) { sec, nsec = uint64(hi)<<32|uint64(lo), ns; events = append(events, "ready") }) | |
| 183 | + | s.event(frame.ID(), 0, wordBytes(core.FORMAT_XRGB8888, 4, 2, 16)...) | |
| 184 | + | s.event(frame.ID(), 5, wordBytes(0x34325258, 4, 2)...) | |
| 185 | + | s.event(frame.ID(), 6) | |
| 186 | + | if shmFormat != core.FORMAT_XRGB8888 || shmW != 4 || shmH != 2 || shmStride != 16 { | |
| 187 | + | t.Fatal(shmFormat, shmW, shmH, shmStride) | |
| 188 | + | } | |
| 189 | + | ||
| 190 | + | // Build the wl_shm buffer the compositor asked for; the pool descriptor is | |
| 191 | + | // duplicated by the kernel and the client's copy is closed by the binding. | |
| 192 | + | memfd, e := unix.MemfdCreate("wlturbo-shm", unix.MFD_CLOEXEC) | |
| 193 | + | noerr(t, e) | |
| 194 | + | noerr(t, unix.Ftruncate(memfd, 32)) | |
| 195 | + | pool, e := shm.CreatePool(memfd, 32) | |
| 196 | + | noerr(t, e) | |
| 197 | + | requireFDClosed(t, memfd) | |
| 198 | + | body, fd := s.reqFD(shm.ID(), 0) | |
| 199 | + | unix.Close(fd) | |
| 200 | + | wantWords(t, "create_pool", body, pool.ID(), 32) | |
| 201 | + | buf, e := pool.CreateBuffer(0, 4, 2, 16, core.FORMAT_XRGB8888) | |
| 202 | + | noerr(t, e) | |
| 203 | + | wantWords(t, "create_buffer", s.req(pool.ID(), 0), buf.ID(), 0, 4, 2, 16, core.FORMAT_XRGB8888) | |
| 204 | + | ||
| 205 | + | noerr(t, frame.Copy(buf)) | |
| 206 | + | wantWords(t, "copy", s.req(frame.ID(), 0), buf.ID()) | |
| 207 | + | s.event(frame.ID(), 1, wordBytes(screencopy.FLAGS_Y_INVERT)...) | |
| 208 | + | s.event(frame.ID(), 2, wordBytes(1, 2, 999999999)...) | |
| 209 | + | if sec != 1<<32|2 || nsec != 999999999 { | |
| 210 | + | t.Fatal(sec, nsec) | |
| 211 | + | } | |
| 212 | + | want := []string{"buffer", "dmabuf", "done", "flags", "ready"} | |
| 213 | + | if !reflect.DeepEqual(events, want) { | |
| 214 | + | t.Fatalf("events %v, want %v", events, want) | |
| 215 | + | } | |
| 216 | + | noerr(t, frame.Destroy()) | |
| 217 | + | s.req(frame.ID(), 1) | |
| 218 | + | ||
| 219 | + | // Region capture + damage + failure on a second frame. | |
| 220 | + | f2, e := mgr.CaptureOutputRegion(0, out, -1, 2, 30, 40) | |
| 221 | + | noerr(t, e) | |
| 222 | + | wantWords(t, "capture_output_region", s.req(mgr.ID(), 1), f2.ID(), 0, out.ID(), 0xffffffff, 2, 30, 40) | |
| 223 | + | noerr(t, f2.CopyWithDamage(buf)) | |
| 224 | + | wantWords(t, "copy_with_damage", s.req(f2.ID(), 2), buf.ID()) | |
| 225 | + | var damage []uint32 | |
| 226 | + | var failed bool | |
| 227 | + | f2.OnDamage(func(x, y, w, h uint32) { damage = []uint32{x, y, w, h} }) | |
| 228 | + | f2.OnFailed(func() { failed = true }) | |
| 229 | + | s.event(f2.ID(), 4, wordBytes(1, 2, 3, 4)...) | |
| 230 | + | s.event(f2.ID(), 3) | |
| 231 | + | if !reflect.DeepEqual(damage, []uint32{1, 2, 3, 4}) || !failed { | |
| 232 | + | t.Fatal(damage, failed) | |
| 233 | + | } | |
| 234 | + | noerr(t, f2.Destroy()) | |
| 235 | + | s.req(f2.ID(), 1) | |
| 236 | + | noerr(t, buf.Destroy()) | |
| 237 | + | s.req(buf.ID(), 0) | |
| 238 | + | noerr(t, mgr.Destroy()) | |
| 239 | + | s.req(mgr.ID(), 2) | |
| 240 | + | } | |
| 241 | + | ||
| 242 | + | func TestWlrScreencopyVersionGate(t *testing.T) { | |
| 243 | + | s := newWireEnv(t) | |
| 244 | + | out := s.output() | |
| 245 | + | mgr := screencopy.NewScreencopyManager(s.d.Context()) | |
| 246 | + | s.bind(1, screencopy.ScreencopyManagerInterface, 3, 1, mgr) | |
| 247 | + | frame, e := mgr.CaptureOutput(0, out) | |
| 248 | + | noerr(t, e) | |
| 249 | + | s.req(mgr.ID(), 0) | |
| 250 | + | buf := core.NewBuffer(s.d.Context()) | |
| 251 | + | buf.SetID(s.d.AllocateID()) | |
| 252 | + | s.d.Context().Register(buf) | |
| 253 | + | if e := frame.CopyWithDamage(buf); !errors.Is(e, wlturbo.ErrVersionTooLow) { | |
| 254 | + | t.Fatalf("copy_with_damage on v1 frame: %v", e) | |
| 255 | + | } | |
| 256 | + | s.noRequest() | |
| 257 | + | noerr(t, frame.Copy(buf)) | |
| 258 | + | s.req(frame.ID(), 0) | |
| 259 | + | } | |
| 260 | + | ||
| 261 | + | func TestWlrInputMethodFDAndCrossPackageEnums(t *testing.T) { | |
| 262 | + | s := newWireEnv(t) | |
| 263 | + | seat, surf := s.seat(), s.surface() | |
| 264 | + | mgr := inputmethod.NewInputMethodManager(s.d.Context()) | |
| 265 | + | s.bind(1, inputmethod.InputMethodManagerInterface, 1, 1, mgr) | |
| 266 | + | im, e := mgr.GetInputMethod(seat) | |
| 267 | + | noerr(t, e) | |
| 268 | + | wantWords(t, "get_input_method", s.req(mgr.ID(), 0), seat.ID(), im.ID()) | |
| 269 | + | ||
| 270 | + | var seq []string | |
| 271 | + | var text string | |
| 272 | + | var cursor, anchor, cause, hint, purpose uint32 | |
| 273 | + | im.OnActivate(func() { seq = append(seq, "activate") }) | |
| 274 | + | im.OnSurroundingText(func(tx string, c, a uint32) { text, cursor, anchor = tx, c, a; seq = append(seq, "surrounding") }) | |
| 275 | + | im.OnTextChangeCause(func(c uint32) { cause = c; seq = append(seq, "cause") }) | |
| 276 | + | im.OnContentType(func(h, p uint32) { hint, purpose = h, p; seq = append(seq, "content") }) | |
| 277 | + | im.OnDone(func() { seq = append(seq, "done") }) | |
| 278 | + | s.event(im.ID(), 0) | |
| 279 | + | s.event(im.ID(), 2, cat(str("héllo"), wordBytes(3, 3))...) | |
| 280 | + | s.event(im.ID(), 3, wordBytes(textinput.CHANGE_CAUSE_OTHER)...) | |
| 281 | + | s.event(im.ID(), 4, wordBytes(textinput.CONTENT_HINT_SPELLCHECK, textinput.CONTENT_PURPOSE_EMAIL)...) | |
| 282 | + | s.event(im.ID(), 5) | |
| 283 | + | if !reflect.DeepEqual(seq, []string{"activate", "surrounding", "cause", "content", "done"}) || | |
| 284 | + | text != "héllo" || cursor != 3 || anchor != 3 || cause != textinput.CHANGE_CAUSE_OTHER || | |
| 285 | + | hint != textinput.CONTENT_HINT_SPELLCHECK || purpose != textinput.CONTENT_PURPOSE_EMAIL { | |
| 286 | + | t.Fatal(seq, text, cursor, anchor, cause, hint, purpose) | |
| 287 | + | } | |
| 288 | + | ||
| 289 | + | noerr(t, im.CommitString("ok")) | |
| 290 | + | if b := s.req(im.ID(), 0); !bytes.Equal(b, str("ok")) { | |
| 291 | + | t.Fatalf("commit_string %x", b) | |
| 292 | + | } | |
| 293 | + | noerr(t, im.SetPreeditString("pre", -1, -1)) | |
| 294 | + | if b := s.req(im.ID(), 1); !bytes.Equal(b, cat(str("pre"), wordBytes(0xffffffff, 0xffffffff))) { | |
| 295 | + | t.Fatalf("set_preedit_string %x", b) | |
| 296 | + | } | |
| 297 | + | noerr(t, im.DeleteSurroundingText(2, 1)) | |
| 298 | + | wantWords(t, "delete_surrounding_text", s.req(im.ID(), 2), 2, 1) | |
| 299 | + | noerr(t, im.Commit(1)) | |
| 300 | + | wantWords(t, "commit", s.req(im.ID(), 3), 1) | |
| 301 | + | ||
| 302 | + | popup, e := im.GetInputPopupSurface(surf) | |
| 303 | + | noerr(t, e) | |
| 304 | + | wantWords(t, "get_input_popup_surface", s.req(im.ID(), 4), popup.ID(), surf.ID()) | |
| 305 | + | var rect []int32 | |
| 306 | + | popup.OnTextInputRectangle(func(x, y, w, h int32) { rect = []int32{x, y, w, h} }) | |
| 307 | + | s.event(popup.ID(), 0, wordBytes(0xfffffffe, 5, 30, 12)...) | |
| 308 | + | if !reflect.DeepEqual(rect, []int32{-2, 5, 30, 12}) { | |
| 309 | + | t.Fatal(rect) | |
| 310 | + | } | |
| 311 | + | ||
| 312 | + | grab, e := im.GrabKeyboard() | |
| 313 | + | noerr(t, e) | |
| 314 | + | wantWords(t, "grab_keyboard", s.req(im.ID(), 5), grab.ID()) | |
| 315 | + | ||
| 316 | + | // keymap carries a descriptor: the first handler may take ownership, the | |
| 317 | + | // second sees nil, and an unclaimed descriptor is closed by the transport. | |
| 318 | + | var claim = true | |
| 319 | + | var first, second []*wlturbo.OwnedFD | |
| 320 | + | var format, size uint32 | |
| 321 | + | var got []byte | |
| 322 | + | grab.OnKeymap(func(f uint32, fd *wlturbo.OwnedFD, sz uint32) { | |
| 323 | + | first = append(first, fd) | |
| 324 | + | format, size = f, sz | |
| 325 | + | if !claim { | |
| 326 | + | return | |
| 327 | + | } | |
| 328 | + | n, e := fd.Take() | |
| 329 | + | noerr(t, e) | |
| 330 | + | buf := make([]byte, 16) | |
| 331 | + | m, e := unix.Read(n, buf) | |
| 332 | + | noerr(t, e) | |
| 333 | + | got = buf[:m] | |
| 334 | + | unix.Close(n) | |
| 335 | + | }) | |
| 336 | + | grab.OnKeymap(func(f uint32, fd *wlturbo.OwnedFD, sz uint32) { second = append(second, fd) }) | |
| 337 | + | pr, pw, e := os.Pipe() | |
| 338 | + | noerr(t, e) | |
| 339 | + | _, e = pw.Write([]byte("xkb-keymap")) | |
| 340 | + | noerr(t, e) | |
| 341 | + | send(t, s.p, payload(grab.ID(), 0, wordBytes(core.KEYMAP_FORMAT_XKB_V1, 10)...), int(pr.Fd())) | |
| 342 | + | pr.Close() | |
| 343 | + | pw.Close() | |
| 344 | + | s.dispatch() | |
| 345 | + | if string(got) != "xkb-keymap" || format != core.KEYMAP_FORMAT_XKB_V1 || size != 10 || len(second) != 1 || second[0] != nil { | |
| 346 | + | t.Fatalf("keymap got=%q format=%d size=%d second=%v", got, format, size, second) | |
| 347 | + | } | |
| 348 | + | ||
| 349 | + | claim = false | |
| 350 | + | pr2, pw2, e := os.Pipe() | |
| 351 | + | noerr(t, e) | |
| 352 | + | defer pr2.Close() | |
| 353 | + | send(t, s.p, payload(grab.ID(), 0, wordBytes(core.KEYMAP_FORMAT_XKB_V1, 0)...), int(pw2.Fd())) | |
| 354 | + | pw2.Close() // only the in-flight duplicate keeps the write end alive | |
| 355 | + | s.dispatch() | |
| 356 | + | pr2.SetReadDeadline(time.Now().Add(2 * time.Second)) | |
| 357 | + | if n, e := pr2.Read(make([]byte, 4)); n != 0 || e == nil { | |
| 358 | + | t.Fatalf("unclaimed descriptor still open: n=%d err=%v", n, e) | |
| 359 | + | } | |
| 360 | + | ||
| 361 | + | var key, mods, repeat []uint32 | |
| 362 | + | grab.OnKey(func(serial, tm, k, st uint32) { key = []uint32{serial, tm, k, st} }) | |
| 363 | + | grab.OnModifiers(func(serial, d, l, lk, g uint32) { mods = []uint32{serial, d, l, lk, g} }) | |
| 364 | + | grab.OnRepeatInfo(func(rate, delay int32) { repeat = []uint32{uint32(rate), uint32(delay)} }) | |
| 365 | + | s.event(grab.ID(), 1, wordBytes(7, 100, 30, core.KEY_STATE_PRESSED)...) | |
| 366 | + | s.event(grab.ID(), 2, wordBytes(8, 1, 2, 4, 1)...) | |
| 367 | + | s.event(grab.ID(), 3, wordBytes(25, 600)...) | |
| 368 | + | if !reflect.DeepEqual(key, []uint32{7, 100, 30, core.KEY_STATE_PRESSED}) || | |
| 369 | + | !reflect.DeepEqual(mods, []uint32{8, 1, 2, 4, 1}) || !reflect.DeepEqual(repeat, []uint32{25, 600}) { | |
| 370 | + | t.Fatal(key, mods, repeat) | |
| 371 | + | } | |
| 372 | + | ||
| 373 | + | noerr(t, grab.Release()) | |
| 374 | + | s.req(grab.ID(), 0) | |
| 375 | + | noerr(t, popup.Destroy()) | |
| 376 | + | s.req(popup.ID(), 0) | |
| 377 | + | var unavailable bool | |
| 378 | + | im.OnUnavailable(func() { unavailable = true }) | |
| 379 | + | s.event(im.ID(), 6) | |
| 380 | + | if !unavailable { | |
| 381 | + | t.Fatal("unavailable not delivered") | |
| 382 | + | } | |
| 383 | + | noerr(t, im.Destroy()) | |
| 384 | + | s.req(im.ID(), 6) | |
| 385 | + | noerr(t, mgr.Destroy()) | |
| 386 | + | s.req(mgr.ID(), 1) | |
| 387 | + | } | |
| 388 | + | ||
| 389 | + | func TestWlrVirtualKeyboardKeymapFD(t *testing.T) { | |
| 390 | + | s := newWireEnv(t) | |
| 391 | + | seat := s.seat() | |
| 392 | + | mgr := virtualkeyboard.NewVirtualKeyboardManager(s.d.Context()) | |
| 393 | + | s.bind(1, virtualkeyboard.VirtualKeyboardManagerInterface, 1, 1, mgr) | |
| 394 | + | kb, e := mgr.CreateVirtualKeyboard(seat) | |
| 395 | + | noerr(t, e) | |
| 396 | + | wantWords(t, "create_virtual_keyboard", s.req(mgr.ID(), 0), seat.ID(), kb.ID()) | |
| 397 | + | ||
| 398 | + | r, w, e := os.Pipe() | |
| 399 | + | noerr(t, e) | |
| 400 | + | defer r.Close() | |
| 401 | + | // Hand the write end to the binding as a plain descriptor. | |
| 402 | + | fd, e := unix.Dup(int(w.Fd())) | |
| 403 | + | noerr(t, e) | |
| 404 | + | w.Close() | |
| 405 | + | noerr(t, kb.Keymap(core.KEYMAP_FORMAT_XKB_V1, fd, 6)) | |
| 406 | + | requireFDClosed(t, fd) | |
| 407 | + | body, got := s.reqFD(kb.ID(), 0) | |
| 408 | + | wantWords(t, "keymap", body, core.KEYMAP_FORMAT_XKB_V1, 6) | |
| 409 | + | _, e = unix.Write(got, []byte("keymap")) | |
| 410 | + | noerr(t, e) | |
| 411 | + | unix.Close(got) | |
| 412 | + | buf := make([]byte, 16) | |
| 413 | + | r.SetReadDeadline(time.Now().Add(2 * time.Second)) | |
| 414 | + | n, e := r.Read(buf) | |
| 415 | + | noerr(t, e) | |
| 416 | + | if string(buf[:n]) != "keymap" { | |
| 417 | + | t.Fatalf("keymap payload %q", buf[:n]) | |
| 418 | + | } | |
| 419 | + | ||
| 420 | + | noerr(t, kb.Key(1234, 30, core.KEY_STATE_PRESSED)) | |
| 421 | + | wantWords(t, "key", s.req(kb.ID(), 1), 1234, 30, core.KEY_STATE_PRESSED) | |
| 422 | + | noerr(t, kb.Modifiers(1, 2, 4, 0)) | |
| 423 | + | wantWords(t, "modifiers", s.req(kb.ID(), 2), 1, 2, 4, 0) | |
| 424 | + | noerr(t, kb.Destroy()) | |
| 425 | + | s.req(kb.ID(), 3) | |
| 426 | + | if e := kb.Key(1, 1, 0); e == nil { | |
| 427 | + | t.Fatal("request after destroy must fail") | |
| 428 | + | } | |
| 429 | + | s.noRequest() | |
| 430 | + | } | |
| 431 | + | ||
| 432 | + | // A layer surface is a wl_surface role defined in layershell, and its popup is | |
| 433 | + | // an xdg_popup from xdgshell; both packages must agree on the same objects. | |
| 434 | + | func TestWlrLayerShellPopupCrossPackage(t *testing.T) { | |
| 435 | + | s := newWireEnv(t) | |
| 436 | + | panel, popupSurf := s.surface(), s.surface() | |
| 437 | + | out := s.output() | |
| 438 | + | ||
| 439 | + | wm := xdgshell.NewXdgWmBase(s.d.Context()) | |
| 440 | + | s.bind(1, xdgshell.XdgWmBaseInterface, 6, 6, wm) | |
| 441 | + | ls := layershell.NewLayerShell(s.d.Context()) | |
| 442 | + | s.bind(2, layershell.LayerShellInterface, 5, 5, ls) | |
| 443 | + | ||
| 444 | + | surf, e := ls.GetLayerSurface(panel, out, layershell.LAYER_TOP, "panel") | |
| 445 | + | noerr(t, e) | |
| 446 | + | if b := s.req(ls.ID(), 0); !bytes.Equal(b, cat(wordBytes(surf.ID(), panel.ID(), out.ID(), layershell.LAYER_TOP), str("panel"))) { | |
| 447 | + | t.Fatalf("get_layer_surface %x", b) | |
| 448 | + | } | |
| 449 | + | if surf.Version() != 5 { | |
| 450 | + | t.Fatalf("layer surface version %d", surf.Version()) | |
| 451 | + | } | |
| 452 | + | // A nullable output is encoded as object 0. | |
| 453 | + | nullOut, e := ls.GetLayerSurface(s.surface(), nil, layershell.LAYER_BACKGROUND, "wallpaper") | |
| 454 | + | noerr(t, e) | |
| 455 | + | if b := s.req(ls.ID(), 0); binary.NativeEndian.Uint32(b[8:]) != 0 || binary.NativeEndian.Uint32(b[:4]) != nullOut.ID() { | |
| 456 | + | t.Fatalf("null output %x", b) | |
| 457 | + | } | |
| 458 | + | ||
| 459 | + | anchors := uint32(layershell.ANCHOR_TOP | layershell.ANCHOR_LEFT | layershell.ANCHOR_RIGHT) | |
| 460 | + | noerr(t, surf.SetSize(0, 30)) | |
| 461 | + | wantWords(t, "set_size", s.req(surf.ID(), 0), 0, 30) | |
| 462 | + | noerr(t, surf.SetAnchor(anchors)) | |
| 463 | + | wantWords(t, "set_anchor", s.req(surf.ID(), 1), anchors) | |
| 464 | + | noerr(t, surf.SetExclusiveZone(-1)) | |
| 465 | + | wantWords(t, "set_exclusive_zone", s.req(surf.ID(), 2), 0xffffffff) | |
| 466 | + | noerr(t, surf.SetMargin(1, 2, 3, 4)) | |
| 467 | + | wantWords(t, "set_margin", s.req(surf.ID(), 3), 1, 2, 3, 4) | |
| 468 | + | noerr(t, surf.SetKeyboardInteractivity(layershell.KEYBOARD_INTERACTIVITY_ON_DEMAND)) | |
| 469 | + | wantWords(t, "set_keyboard_interactivity", s.req(surf.ID(), 4), layershell.KEYBOARD_INTERACTIVITY_ON_DEMAND) | |
| 470 | + | noerr(t, surf.SetLayer(layershell.LAYER_OVERLAY)) | |
| 471 | + | wantWords(t, "set_layer", s.req(surf.ID(), 8), layershell.LAYER_OVERLAY) | |
| 472 | + | noerr(t, surf.SetExclusiveEdge(layershell.ANCHOR_TOP)) | |
| 473 | + | wantWords(t, "set_exclusive_edge", s.req(surf.ID(), 9), layershell.ANCHOR_TOP) | |
| 474 | + | ||
| 475 | + | var cfgSerial, cfgW, cfgH uint32 | |
| 476 | + | surf.OnConfigure(func(serial, w, h uint32) { | |
| 477 | + | cfgSerial, cfgW, cfgH = serial, w, h | |
| 478 | + | noerr(t, surf.AckConfigure(serial)) | |
| 479 | + | }) | |
| 480 | + | s.event(surf.ID(), 0, wordBytes(77, 1920, 30)...) | |
| 481 | + | if cfgSerial != 77 || cfgW != 1920 || cfgH != 30 { | |
| 482 | + | t.Fatal(cfgSerial, cfgW, cfgH) | |
| 483 | + | } | |
| 484 | + | wantWords(t, "ack_configure", s.req(surf.ID(), 6), 77) | |
| 485 | + | ||
| 486 | + | // The popup is created through xdg_shell with a NULL parent, then adopted | |
| 487 | + | // by the layer surface. | |
| 488 | + | xs, e := wm.GetXdgSurface(popupSurf) | |
| 489 | + | noerr(t, e) | |
| 490 | + | s.req(wm.ID(), 2) | |
| 491 | + | pos, e := wm.CreatePositioner() | |
| 492 | + | noerr(t, e) | |
| 493 | + | s.req(wm.ID(), 1) | |
| 494 | + | noerr(t, pos.SetSize(100, 50)) | |
| 495 | + | wantWords(t, "positioner size", s.req(pos.ID(), 1), 100, 50) | |
| 496 | + | noerr(t, pos.SetAnchorRect(0, 0, 10, 30)) | |
| 497 | + | s.req(pos.ID(), 2) | |
| 498 | + | popup, e := xs.GetPopup(nil, pos) | |
| 499 | + | noerr(t, e) | |
| 500 | + | wantWords(t, "get_popup", s.req(xs.ID(), 2), popup.ID(), 0, pos.ID()) | |
| 501 | + | noerr(t, surf.GetPopup(popup)) | |
| 502 | + | wantWords(t, "layer get_popup", s.req(surf.ID(), 5), popup.ID()) | |
| 503 | + | ||
| 504 | + | var popupCfg []int32 | |
| 505 | + | var done bool | |
| 506 | + | popup.OnConfigure(func(x, y, w, h int32) { popupCfg = []int32{x, y, w, h} }) | |
| 507 | + | popup.OnPopupDone(func() { done = true }) | |
| 508 | + | s.event(popup.ID(), 0, wordBytes(4, 30, 100, 50)...) | |
| 509 | + | s.event(popup.ID(), 1) | |
| 510 | + | if !reflect.DeepEqual(popupCfg, []int32{4, 30, 100, 50}) || !done { | |
| 511 | + | t.Fatal(popupCfg, done) | |
| 512 | + | } | |
| 513 | + | ||
| 514 | + | var closed bool | |
| 515 | + | surf.OnClosed(func() { closed = true }) | |
| 516 | + | s.event(surf.ID(), 1) | |
| 517 | + | if !closed { | |
| 518 | + | t.Fatal("closed not delivered") | |
| 519 | + | } | |
| 520 | + | noerr(t, popup.Destroy()) | |
| 521 | + | s.req(popup.ID(), 0) | |
| 522 | + | noerr(t, surf.Destroy()) | |
| 523 | + | s.req(surf.ID(), 7) | |
| 524 | + | noerr(t, ls.Destroy()) | |
| 525 | + | s.req(ls.ID(), 1) | |
| 526 | + | if e := surf.SetSize(1, 1); e == nil { | |
| 527 | + | t.Fatal("request after destroy must fail") | |
| 528 | + | } | |
| 529 | + | s.noRequest() | |
| 530 | + | } | |
| 531 | + | ||
| 532 | + | func TestWlrLayerShellVersionGate(t *testing.T) { | |
| 533 | + | s := newWireEnv(t) | |
| 534 | + | ls := layershell.NewLayerShell(s.d.Context()) | |
| 535 | + | s.bind(1, layershell.LayerShellInterface, 5, 4, ls) | |
| 536 | + | surf, e := ls.GetLayerSurface(s.surface(), nil, layershell.LAYER_TOP, "x") | |
| 537 | + | noerr(t, e) | |
| 538 | + | s.req(ls.ID(), 0) | |
| 539 | + | if e := surf.SetExclusiveEdge(layershell.ANCHOR_TOP); !errors.Is(e, wlturbo.ErrVersionTooLow) { | |
| 540 | + | t.Fatalf("set_exclusive_edge on v4: %v", e) | |
| 541 | + | } | |
| 542 | + | s.noRequest() | |
| 543 | + | noerr(t, surf.SetLayer(layershell.LAYER_BOTTOM)) | |
| 544 | + | s.req(surf.ID(), 8) | |
| 545 | + | } | |
| 546 | + | ||
| 547 | + | func TestWlrForeignToplevelOutputPowerAndKDEDecoration(t *testing.T) { | |
| 548 | + | s := newWireEnv(t) | |
| 549 | + | seat, surf, out := s.seat(), s.surface(), s.output() | |
| 550 | + | ||
| 551 | + | // foreign-toplevel: toplevel is a server new_id event; finished destroys. | |
| 552 | + | tm := foreigntoplevel.NewForeignToplevelManager(s.d.Context()) | |
| 553 | + | s.bind(1, foreigntoplevel.ForeignToplevelManagerInterface, 3, 3, tm) | |
| 554 | + | var top *foreigntoplevel.ForeignToplevelHandle | |
| 555 | + | tm.OnToplevel(func(h *foreigntoplevel.ForeignToplevelHandle) { top = h }) | |
| 556 | + | s.event(tm.ID(), 0, wordBytes(serverID+1)...) | |
| 557 | + | if top == nil || top.ID() != serverID+1 || top.Version() != 3 { | |
| 558 | + | t.Fatalf("toplevel %+v", top) | |
| 559 | + | } | |
| 560 | + | var title, appID string | |
| 561 | + | var states []byte | |
| 562 | + | var enter, parent uint32 | |
| 563 | + | var done, closed bool | |
| 564 | + | top.OnTitle(func(v string) { title = v }) | |
| 565 | + | top.OnAppId(func(v string) { appID = v }) | |
| 566 | + | top.OnState(func(v []byte) { states = append([]byte(nil), v...) }) | |
| 567 | + | top.OnOutputEnter(func(id uint32) { enter = id }) | |
| 568 | + | top.OnParent(func(id uint32) { parent = id }) | |
| 569 | + | top.OnDone(func() { done = true }) | |
| 570 | + | top.OnClosed(func() { closed = true }) | |
| 571 | + | s.event(top.ID(), 0, str("term")...) | |
| 572 | + | s.event(top.ID(), 1, str("org.example.term")...) | |
| 573 | + | s.event(top.ID(), 2, wordBytes(out.ID())...) | |
| 574 | + | s.event(top.ID(), 4, arr(wordBytes(foreigntoplevel.STATE_MAXIMIZED, foreigntoplevel.STATE_ACTIVATED))...) | |
| 575 | + | s.event(top.ID(), 7, wordBytes(0)...) | |
| 576 | + | s.event(top.ID(), 5) | |
| 577 | + | if title != "term" || appID != "org.example.term" || enter != out.ID() || parent != 0 || !done || | |
| 578 | + | !bytes.Equal(states, wordBytes(foreigntoplevel.STATE_MAXIMIZED, foreigntoplevel.STATE_ACTIVATED)) { | |
| 579 | + | t.Fatal(title, appID, enter, parent, done, states) | |
| 580 | + | } | |
| 581 | + | noerr(t, top.SetMaximized()) | |
| 582 | + | s.req(top.ID(), 0) | |
| 583 | + | noerr(t, top.Activate(seat)) | |
| 584 | + | wantWords(t, "activate", s.req(top.ID(), 4), seat.ID()) | |
| 585 | + | noerr(t, top.SetRectangle(surf, 1, 2, 3, 4)) | |
| 586 | + | wantWords(t, "set_rectangle", s.req(top.ID(), 6), surf.ID(), 1, 2, 3, 4) | |
| 587 | + | noerr(t, top.SetFullscreen(nil)) | |
| 588 | + | wantWords(t, "set_fullscreen(nil)", s.req(top.ID(), 8), 0) | |
| 589 | + | noerr(t, top.SetFullscreen(out)) | |
| 590 | + | wantWords(t, "set_fullscreen", s.req(top.ID(), 8), out.ID()) | |
| 591 | + | noerr(t, top.Close()) | |
| 592 | + | s.req(top.ID(), 5) | |
| 593 | + | s.event(top.ID(), 6) | |
| 594 | + | if !closed { | |
| 595 | + | t.Fatal("closed not delivered") | |
| 596 | + | } | |
| 597 | + | noerr(t, top.Destroy()) | |
| 598 | + | s.req(top.ID(), 7) | |
| 599 | + | noerr(t, tm.Stop()) | |
| 600 | + | s.req(tm.ID(), 0) | |
| 601 | + | s.event(tm.ID(), 1) | |
| 602 | + | if e := tm.Stop(); e == nil { | |
| 603 | + | t.Fatal("request on a finished manager must fail") | |
| 604 | + | } | |
| 605 | + | ||
| 606 | + | // output-power: object argument + mode/failed events. | |
| 607 | + | pm := outputpower.NewOutputPowerManager(s.d.Context()) | |
| 608 | + | s.bind(2, outputpower.OutputPowerManagerInterface, 1, 1, pm) | |
| 609 | + | pw, e := pm.GetOutputPower(out) | |
| 610 | + | noerr(t, e) | |
| 611 | + | wantWords(t, "get_output_power", s.req(pm.ID(), 0), pw.ID(), out.ID()) | |
| 612 | + | var modes []uint32 | |
| 613 | + | var failed bool | |
| 614 | + | pw.OnMode(func(m uint32) { modes = append(modes, m) }) | |
| 615 | + | pw.OnFailed(func() { failed = true }) | |
| 616 | + | s.event(pw.ID(), 0, wordBytes(outputpower.MODE_ON)...) | |
| 617 | + | noerr(t, pw.SetMode(outputpower.MODE_OFF)) | |
| 618 | + | wantWords(t, "set_mode", s.req(pw.ID(), 0), outputpower.MODE_OFF) | |
| 619 | + | s.event(pw.ID(), 0, wordBytes(outputpower.MODE_OFF)...) | |
| 620 | + | s.event(pw.ID(), 1) | |
| 621 | + | if !reflect.DeepEqual(modes, []uint32{outputpower.MODE_ON, outputpower.MODE_OFF}) || !failed { | |
| 622 | + | t.Fatal(modes, failed) | |
| 623 | + | } | |
| 624 | + | noerr(t, pw.Destroy()) | |
| 625 | + | s.req(pw.ID(), 1) | |
| 626 | + | noerr(t, pm.Destroy()) | |
| 627 | + | s.req(pm.ID(), 1) | |
| 628 | + | ||
| 629 | + | // KDE server decoration: mode enums are per-interface constants. | |
| 630 | + | dm := kdeserverdecoration.NewOrgKdeKwinServerDecorationManager(s.d.Context()) | |
| 631 | + | s.bind(3, kdeserverdecoration.OrgKdeKwinServerDecorationManagerInterface, 1, 1, dm) | |
| 632 | + | var def uint32 = 99 | |
| 633 | + | dm.OnDefaultMode(func(m uint32) { def = m }) | |
| 634 | + | s.event(dm.ID(), 0, wordBytes(kdeserverdecoration.ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT)...) | |
| 635 | + | if def != kdeserverdecoration.ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT { | |
| 636 | + | t.Fatal(def) | |
| 637 | + | } | |
| 638 | + | dec, e := dm.Create(surf) | |
| 639 | + | noerr(t, e) | |
| 640 | + | wantWords(t, "create", s.req(dm.ID(), 0), dec.ID(), surf.ID()) | |
| 641 | + | var mode uint32 = 99 | |
| 642 | + | dec.OnMode(func(m uint32) { mode = m }) | |
| 643 | + | noerr(t, dec.RequestMode(kdeserverdecoration.ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER)) | |
| 644 | + | wantWords(t, "request_mode", s.req(dec.ID(), 1), kdeserverdecoration.ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER) | |
| 645 | + | s.event(dec.ID(), 0, wordBytes(kdeserverdecoration.ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER)...) | |
| 646 | + | if mode != kdeserverdecoration.ORG_KDE_KWIN_SERVER_DECORATION_MODE_SERVER { | |
| 647 | + | t.Fatal(mode) | |
| 648 | + | } | |
| 649 | + | noerr(t, dec.Release()) | |
| 650 | + | s.req(dec.ID(), 0) | |
| 651 | + | s.noRequest() | |
| 652 | + | } | |
A protocol/workspace/ext-workspace-v1.xml +422 -0 collapsed to keep the page light
A protocol/workspace/ext-workspace-v1_generated.go +758 -0 collapsed to keep the page light
A protocol/workspace/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package workspace | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p workspace -o ext-workspace-v1_generated.go -import wl_output=github.com/bnema/wlturbo/protocol/core ext-workspace-v1.xml | |
A protocol/xdgactivation/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package xdgactivation | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p xdgactivation -o xdg-activation-v1_generated.go -import wl_surface=github.com/bnema/wlturbo/protocol/core -import wl_seat=github.com/bnema/wlturbo/protocol/core xdg-activation-v1.xml | |
A protocol/xdgactivation/xdg-activation-v1.xml +200 -0 collapsed to keep the page light
A protocol/xdgactivation/xdg-activation-v1_generated.go +214 -0 collapsed to keep the page light
A protocol/xdgdecoration/generate.go +3 -0
| @@ -0,0 +1,3 @@ | |||
| 1 | + | package xdgdecoration | |
| 2 | + | ||
| 3 | + | //go:generate go run ../../cmd/wlturbo-scanner -p xdgdecoration -o xdg-decoration-unstable-v1_generated.go -import xdg_toplevel=github.com/bnema/wlturbo/protocol/xdgshell xdg-decoration-unstable-v1.xml | |