detached 9c230c3

Merge pull request #2 from bnema/feat/client-protocol-coverage

feat(protocol): expand Wayland client bindings and remove numeric allocations
commit
9c230c35e3b70fea4e350cbf3b0385d5ebab8a09
author
bnema · · 2026-09-30 05:30 UTC
committer
GitHub · · 2026-09-30 05:30 UTC
merge of
96f3aeb + ccdd267 · diff against the first parent
signature
GPG UnverifiedB5690EEEBB952194 The key is unknown
refs
tag: v0.4.0
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
44
55 ## Overview
66
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.
88
99 ## Architecture
1010
@@ -15,11 +15,24 @@ WLTurbo provides the foundational Wayland client infrastructure:
1515 - **Connection Management**: Unix socket communication with the compositor
1616 - **Memory Management**: Shared memory support via file descriptor passing
1717
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.
1919
2020 ## Generated protocols
2121
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.
2336
2437 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.
2538
@@ -29,7 +42,7 @@ After `display.Roundtrip()` discovers globals, call `display.Registry().BindNego
2942 - **Descriptor ownership**: received FDs belong to the event that declares them and are closed if a handler does not take them.
3043 - **Object lifecycle**: destroyed objects stay as zombies until `delete_id`, so events already in flight are dropped instead of failing the connection.
3144 - **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.
3346
3447 ## Quick Start
3548
@@ -58,7 +71,27 @@ func main() {
5871 }
5972 ```
6073
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.
6295
6396 ## Requirements
6497
@@ -68,7 +101,11 @@ For device control and input injection, use [libwldevices-go](https://github.com
68101
69102 ## License
70103
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).
72109
73110 ## Contributing
74111
M client.go +66 -27
@@ -230,12 +230,14 @@ func (d *Display) SendRequest(objectID uint32, opcode uint16, args ...interface{
230230
231231 // SendRequestWithFDs sends a request with file descriptors
232232 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)
234234 }
235235
236236 // sendRequest marshals a request, then runs guard and writes the message
237237 // 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 {
239241 // Get buffer from pool
240242 buf := bufferPool.Get().(*bytes.Buffer)
241243 defer func() {
@@ -253,6 +255,11 @@ func (d *Display) sendRequest(objectID uint32, opcode uint16, fds []int, guard f
253255 return fmt.Errorf("failed to marshal argument: %w", err)
254256 }
255257 }
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+ }
256263
257264 // Update header with actual size in bytes
258265 bufLen := buf.Len()
@@ -279,6 +286,61 @@ func putUint32(buf *bytes.Buffer, v uint32) {
279286 _, _ = buf.Write(w[:])
280287 }
281288
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+
282344 // marshalArg marshals a single argument
283345 func (d *Display) marshalArg(buf *bytes.Buffer, arg interface{}) error {
284346 switch v := arg.(type) {
@@ -289,32 +351,9 @@ func (d *Display) marshalArg(buf *bytes.Buffer, arg interface{}) error {
289351 case Fixed:
290352 putUint32(buf, uint32(v))
291353 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)
305355 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)
318357 case Object:
319358 if v != nil {
320359 putUint32(buf, v.ID())
M core.go +43 -11
@@ -75,10 +75,7 @@ func (c *Context) SendRequest(proxy Proxy, opcode uint32, args ...interface{}) e
7575 // SendRequestWithFDs sends a request with file descriptors through the context.
7676 // On error the FDs remain owned by the caller.
7777 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)
8279 }
8380
8481 // CheckProxy rejects stale and foreign proxies before any bytes are written.
@@ -96,7 +93,8 @@ func (c *Context) CheckProxy(proxy Proxy) error {
9693 return nil
9794 }
9895
99-// Request describes one protocol request for Context.Request.
96+// Request describes one protocol request for Context.Request and
97+// Context.RequestArgs.
10098 type Request struct {
10199 Proxy Proxy
102100 Opcode uint32
@@ -112,7 +110,35 @@ type Request struct {
112110 // sends, and then either closes the sent descriptors or, on error,
113111 // unregisters Child and leaves the descriptors with the caller. Child must
114112 // 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.
115117 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+ }
116142 if err := c.CheckProxy(r.Proxy); err != nil {
117143 return err
118144 }
@@ -132,9 +158,9 @@ func (c *Context) Request(r Request, args ...interface{}) error {
132158 }
133159 var err error
134160 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)
136162 } 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)
138164 }
139165 if err != nil {
140166 if r.Child != nil {
@@ -148,6 +174,15 @@ func (c *Context) Request(r Request, args ...interface{}) error {
148174 return nil
149175 }
150176
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+
151186 // SendDestructor sends a destructor request exactly once. The proxy is
152187 // claimed (unregistered) under the connection send lock, after marshaling
153188 // and immediately before the write: concurrent destructors and later requests
@@ -161,10 +196,7 @@ func (c *Context) SendDestructor(proxy Proxy, opcode uint32, args ...interface{}
161196 // SendDestructorWithFDs is SendDestructor for requests carrying FDs. On error
162197 // the FDs remain owned by the caller.
163198 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)
168200 }
169201
170202 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
2727 `GOWORK=off go generate ./...`; metadata and XML license are in
2828 `protocol/SOURCE.md`. Extension packages under `protocol/` use the same scanner
2929 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 {
162162 Package string
163163 Protocol string
164164 Source string
165+ Copyright string
165166 ImportBlock string
166167 Constants []constantData
167168 Interfaces []interfaceData
@@ -252,6 +253,15 @@ func (s *Scanner) prepareTemplateData(packageName string) (templateData, error)
252253 Protocol: s.protocol.Name,
253254 Source: s.source,
254255 }
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+ }
255265
256266 imports := []string{TransportImport}
257267 usedCross := make(map[string]bool)
@@ -449,17 +459,29 @@ func (s *Scanner) processRequest(iface Interface, req Request, opcode int) (requ
449459 fmt.Sprintf("if %s != nil {", name),
450460 fmt.Sprintf("\t%s = %s", holder, name),
451461 "}")
452- expr = holder
462+ expr = "wl.ArgObject(" + holder + ")"
453463
454464 case "fd":
455465 // Descriptors travel out of band: the body carries no value for
456466 // them, and the descriptor list is attached to the request.
457467 params = append(params, name+" int")
458468 fdExprs = append(fdExprs, name)
459- expr = "uintptr(" + name + ")"
469+ expr = "wl.ArgFD()"
460470
461471 default:
462472 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+ }
463485 }
464486
465487 argSlots = append(argSlots, argSlot{expr: expr})
@@ -479,7 +501,7 @@ func (s *Scanner) processRequest(iface Interface, req Request, opcode int) (requ
479501
480502 for _, slot := range argSlots {
481503 if slot.newID {
482- argExprs = append(argExprs, data.ChildVar)
504+ argExprs = append(argExprs, "wl.ArgObject("+data.ChildVar+")")
483505 continue
484506 }
485507 argExprs = append(argExprs, slot.expr)
@@ -490,7 +512,7 @@ func (s *Scanner) processRequest(iface Interface, req Request, opcode int) (requ
490512 if len(argExprs) > 0 {
491513 args = ", " + strings.Join(argExprs, ", ")
492514 }
493- // Context.Request owns the lifecycle: destructors claim the proxy
515+ // Context.RequestArgs owns the lifecycle: destructors claim the proxy
494516 // atomically, children are registered before the send and descriptors are
495517 // closed only after a successful send.
496518 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
33 // protocolTemplate is the template for generating WLTurbo-backed Go bindings.
44 //
55 // 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
99 // socket or frames messages itself: that is the transport's job.
1010 const protocolTemplate = `// Code generated by wlturbo-scanner. DO NOT EDIT.
1111 // Protocol: {{.Protocol}}
1212 // Source: {{.Source}}
13-
13+{{if .Copyright}}
14+// Upstream protocol copyright and license:
15+{{.Copyright}}{{end}}
1416 package {{.Package}}
1517
1618 {{.ImportBlock}}
@@ -62,7 +64,7 @@ func (o *{{$iface.GoName}}) {{.GoName}}({{.Params}}) {{.Results}} {
6264 {{.ChildVar}}.SetContext(o.Context())
6365 {{- end}}
6466 {{- 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}}"
6668 {{- if gt .Since 1}}, Since: {{.Since}}{{end}}
6769 {{- if .Destructor}}, Destructor: true{{end}}
6870 {{- if .CreatesChild}}, Child: {{.ChildVar}}{{end}}
M protocol/SOURCE.md +69 -4
@@ -6,11 +6,11 @@
66 SHA-256: `cc860987e54f8d85c940e97fa1270c69b6e4ad31fbcf5a7f00107ce1157f5e07`.
77 License: MIT (full copyright and grant in `wayland.xml` `<copyright>`).
88
9-## Required extensions
9+## wayland-protocols extensions
1010
1111 The following XML files come from `https://gitlab.freedesktop.org/wayland/wayland-protocols`,
1212 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.
1414 SHA-256 (of the vendored XML bytes):
1515
1616 | Upstream path (under tag 1.49) | Vendored path | SHA-256 |
@@ -23,6 +23,71 @@ SHA-256 (of the vendored XML bytes):
2323 | `unstable/text-input/text-input-unstable-v3.xml` | `textinput/text-input-unstable-v3.xml` | `160815cda13c285a30df1971d8f0a5b3aac07071537df59916d2f748b18e4f59` |
2424 | `staging/cursor-shape/cursor-shape-v1.xml` | `cursorshape/cursor-shape-v1.xml` | `bb57d91e53a79dadab7c612dab87c233393cee73673feefa7442cfbfdd9aed2f` |
2525 | `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` |
2650
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 @@
22 // Protocol: wayland
33 // Source: wayland.xml
44
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+
531 package core
632
733 import (
@@ -775,7 +801,7 @@ func NewCompositor(ctx *wl.Context) *Compositor {
775801 func (o *Compositor) CreateSurface() (*Surface, error) {
776802 child := &Surface{}
777803 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 {
779805 return nil, err
780806 }
781807 return child, nil
@@ -785,7 +811,7 @@ func (o *Compositor) CreateSurface() (*Surface, error) {
785811 func (o *Compositor) CreateRegion() (*Region, error) {
786812 child := &Region{}
787813 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 {
789815 return nil, err
790816 }
791817 return child, nil
@@ -793,7 +819,7 @@ func (o *Compositor) CreateRegion() (*Region, error) {
793819
794820 // This request destroys the wl_compositor. This has no effect on any other objects.
795821 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 {
797823 return err
798824 }
799825 return nil
@@ -834,7 +860,7 @@ func NewShmPool(ctx *wl.Context) *ShmPool {
834860 func (o *ShmPool) CreateBuffer(offset int32, width int32, height int32, stride int32, format uint32) (*Buffer, error) {
835861 child := &Buffer{}
836862 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 {
838864 return nil, err
839865 }
840866 return child, nil
@@ -842,7 +868,7 @@ func (o *ShmPool) CreateBuffer(offset int32, width int32, height int32, stride i
842868
843869 // Destroy the shared memory pool. The mmapped memory will be released when all buffers that have been created from this pool are gone.
844870 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 {
846872 return err
847873 }
848874 return nil
@@ -850,7 +876,7 @@ func (o *ShmPool) Destroy() error {
850876
851877 // 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.
852878 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 {
854880 return err
855881 }
856882 return nil
@@ -895,7 +921,7 @@ func NewShm(ctx *wl.Context) *Shm {
895921 func (o *Shm) CreatePool(fd int, size int32) (*ShmPool, error) {
896922 child := &ShmPool{}
897923 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 {
899925 return nil, err
900926 }
901927 return child, nil
@@ -903,7 +929,7 @@ func (o *Shm) CreatePool(fd int, size int32) (*ShmPool, error) {
903929
904930 // 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.
905931 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 {
907933 return err
908934 }
909935 return nil
@@ -977,7 +1003,7 @@ func NewBuffer(ctx *wl.Context) *Buffer {
9771003
9781004 // 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.
9791005 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 {
9811007 return err
9821008 }
9831009 return nil
@@ -1052,7 +1078,7 @@ func NewDataOffer(ctx *wl.Context) *DataOffer {
10521078
10531079 // 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.
10541080 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 {
10561082 return err
10571083 }
10581084 return nil
@@ -1060,7 +1086,7 @@ func (o *DataOffer) Accept(serial uint32, mimeType string) error {
10601086
10611087 // 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.
10621088 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 {
10641090 return err
10651091 }
10661092 return nil
@@ -1068,7 +1094,7 @@ func (o *DataOffer) Receive(mimeType string, fd int) error {
10681094
10691095 // Destroy the data offer.
10701096 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 {
10721098 return err
10731099 }
10741100 return nil
@@ -1076,7 +1102,7 @@ func (o *DataOffer) Destroy() error {
10761102
10771103 // 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.
10781104 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 {
10801106 return err
10811107 }
10821108 return nil
@@ -1084,7 +1110,7 @@ func (o *DataOffer) Finish() error {
10841110
10851111 // 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.
10861112 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 {
10881114 return err
10891115 }
10901116 return nil
@@ -1225,7 +1251,7 @@ func NewDataSource(ctx *wl.Context) *DataSource {
12251251
12261252 // This request adds a mime type to the set of mime types advertised to targets. Can be called several times to offer multiple types.
12271253 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 {
12291255 return err
12301256 }
12311257 return nil
@@ -1233,7 +1259,7 @@ func (o *DataSource) Offer(mimeType string) error {
12331259
12341260 // Destroy the data source.
12351261 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 {
12371263 return err
12381264 }
12391265 return nil
@@ -1241,7 +1267,7 @@ func (o *DataSource) Destroy() error {
12411267
12421268 // 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.
12431269 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 {
12451271 return err
12461272 }
12471273 return nil
@@ -1489,7 +1515,7 @@ func (o *DataDevice) StartDrag(source *DataSource, origin *Surface, icon *Surfac
14891515 if icon != nil {
14901516 arg2 = icon
14911517 }
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 {
14931519 return err
14941520 }
14951521 return nil
@@ -1501,7 +1527,7 @@ func (o *DataDevice) SetSelection(source *DataSource, serial uint32) error {
15011527 if source != nil {
15021528 arg0 = source
15031529 }
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 {
15051531 return err
15061532 }
15071533 return nil
@@ -1509,7 +1535,7 @@ func (o *DataDevice) SetSelection(source *DataSource, serial uint32) error {
15091535
15101536 // This request destroys the data device.
15111537 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 {
15131539 return err
15141540 }
15151541 return nil
@@ -1745,7 +1771,7 @@ func NewDataDeviceManager(ctx *wl.Context) *DataDeviceManager {
17451771 func (o *DataDeviceManager) CreateDataSource() (*DataSource, error) {
17461772 child := &DataSource{}
17471773 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 {
17491775 return nil, err
17501776 }
17511777 return child, nil
@@ -1759,7 +1785,7 @@ func (o *DataDeviceManager) GetDataDevice(seat *Seat) (*DataDevice, error) {
17591785 }
17601786 child := &DataDevice{}
17611787 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 {
17631789 return nil, err
17641790 }
17651791 return child, nil
@@ -1767,7 +1793,7 @@ func (o *DataDeviceManager) GetDataDevice(seat *Seat) (*DataDevice, error) {
17671793
17681794 // This request destroys the wl_data_device_manager. This has no effect on any other objects.
17691795 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 {
17711797 return err
17721798 }
17731799 return nil
@@ -1812,7 +1838,7 @@ func (o *Shell) GetShellSurface(surface *Surface) (*ShellSurface, error) {
18121838 }
18131839 child := &ShellSurface{}
18141840 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 {
18161842 return nil, err
18171843 }
18181844 return child, nil
@@ -1857,7 +1883,7 @@ func NewShellSurface(ctx *wl.Context) *ShellSurface {
18571883
18581884 // A client must respond to a ping event with a pong request or the client may be deemed unresponsive.
18591885 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 {
18611887 return err
18621888 }
18631889 return nil
@@ -1869,7 +1895,7 @@ func (o *ShellSurface) Move(seat *Seat, serial uint32) error {
18691895 if seat != nil {
18701896 arg0 = seat
18711897 }
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 {
18731899 return err
18741900 }
18751901 return nil
@@ -1881,7 +1907,7 @@ func (o *ShellSurface) Resize(seat *Seat, serial uint32, edges uint32) error {
18811907 if seat != nil {
18821908 arg0 = seat
18831909 }
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 {
18851911 return err
18861912 }
18871913 return nil
@@ -1889,7 +1915,7 @@ func (o *ShellSurface) Resize(seat *Seat, serial uint32, edges uint32) error {
18891915
18901916 // Map the surface as a toplevel surface. A toplevel surface is not fullscreen, maximized or transient.
18911917 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 {
18931919 return err
18941920 }
18951921 return nil
@@ -1901,7 +1927,7 @@ func (o *ShellSurface) SetTransient(parent *Surface, x int32, y int32, flags uin
19011927 if parent != nil {
19021928 arg0 = parent
19031929 }
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 {
19051931 return err
19061932 }
19071933 return nil
@@ -1913,7 +1939,7 @@ func (o *ShellSurface) SetFullscreen(method uint32, framerate uint32, output *Ou
19131939 if output != nil {
19141940 arg2 = output
19151941 }
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 {
19171943 return err
19181944 }
19191945 return nil
@@ -1929,7 +1955,7 @@ func (o *ShellSurface) SetPopup(seat *Seat, serial uint32, parent *Surface, x in
19291955 if parent != nil {
19301956 arg2 = parent
19311957 }
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 {
19331959 return err
19341960 }
19351961 return nil
@@ -1941,7 +1967,7 @@ func (o *ShellSurface) SetMaximized(output *Output) error {
19411967 if output != nil {
19421968 arg0 = output
19431969 }
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 {
19451971 return err
19461972 }
19471973 return nil
@@ -1949,7 +1975,7 @@ func (o *ShellSurface) SetMaximized(output *Output) error {
19491975
19501976 // 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.
19511977 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 {
19531979 return err
19541980 }
19551981 return nil
@@ -1957,7 +1983,7 @@ func (o *ShellSurface) SetTitle(title string) error {
19571983
19581984 // 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.
19591985 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 {
19611987 return err
19621988 }
19631989 return nil
@@ -2097,7 +2123,7 @@ func NewSurface(ctx *wl.Context) *Surface {
20972123
20982124 // Deletes the surface and invalidates its object ID.
20992125 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 {
21012127 return err
21022128 }
21032129 return nil
@@ -2109,7 +2135,7 @@ func (o *Surface) Attach(buffer *Buffer, x int32, y int32) error {
21092135 if buffer != nil {
21102136 arg0 = buffer
21112137 }
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 {
21132139 return err
21142140 }
21152141 return nil
@@ -2117,7 +2143,7 @@ func (o *Surface) Attach(buffer *Buffer, x int32, y int32) error {
21172143
21182144 // 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.
21192145 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 {
21212147 return err
21222148 }
21232149 return nil
@@ -2127,7 +2153,7 @@ func (o *Surface) Damage(x int32, y int32, width int32, height int32) error {
21272153 func (o *Surface) Frame() (*Callback, error) {
21282154 child := &Callback{}
21292155 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 {
21312157 return nil, err
21322158 }
21332159 return child, nil
@@ -2139,7 +2165,7 @@ func (o *Surface) SetOpaqueRegion(region *Region) error {
21392165 if region != nil {
21402166 arg0 = region
21412167 }
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 {
21432169 return err
21442170 }
21452171 return nil
@@ -2151,7 +2177,7 @@ func (o *Surface) SetInputRegion(region *Region) error {
21512177 if region != nil {
21522178 arg0 = region
21532179 }
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 {
21552181 return err
21562182 }
21572183 return nil
@@ -2159,7 +2185,7 @@ func (o *Surface) SetInputRegion(region *Region) error {
21592185
21602186 // 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.
21612187 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 {
21632189 return err
21642190 }
21652191 return nil
@@ -2167,7 +2193,7 @@ func (o *Surface) Commit() error {
21672193
21682194 // 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.
21692195 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 {
21712197 return err
21722198 }
21732199 return nil
@@ -2175,7 +2201,7 @@ func (o *Surface) SetBufferTransform(transform int32) error {
21752201
21762202 // 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.
21772203 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 {
21792205 return err
21802206 }
21812207 return nil
@@ -2183,7 +2209,7 @@ func (o *Surface) SetBufferScale(scale int32) error {
21832209
21842210 // 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.
21852211 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 {
21872213 return err
21882214 }
21892215 return nil
@@ -2191,7 +2217,7 @@ func (o *Surface) DamageBuffer(x int32, y int32, width int32, height int32) erro
21912217
21922218 // 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.
21932219 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 {
21952221 return err
21962222 }
21972223 return nil
@@ -2201,7 +2227,7 @@ func (o *Surface) Offset(x int32, y int32) error {
22012227 func (o *Surface) GetRelease() (*Callback, error) {
22022228 child := &Callback{}
22032229 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 {
22052231 return nil, err
22062232 }
22072233 return child, nil
@@ -2371,7 +2397,7 @@ func NewSeat(ctx *wl.Context) *Seat {
23712397 func (o *Seat) GetPointer() (*Pointer, error) {
23722398 child := &Pointer{}
23732399 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 {
23752401 return nil, err
23762402 }
23772403 return child, nil
@@ -2381,7 +2407,7 @@ func (o *Seat) GetPointer() (*Pointer, error) {
23812407 func (o *Seat) GetKeyboard() (*Keyboard, error) {
23822408 child := &Keyboard{}
23832409 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 {
23852411 return nil, err
23862412 }
23872413 return child, nil
@@ -2391,7 +2417,7 @@ func (o *Seat) GetKeyboard() (*Keyboard, error) {
23912417 func (o *Seat) GetTouch() (*Touch, error) {
23922418 child := &Touch{}
23932419 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 {
23952421 return nil, err
23962422 }
23972423 return child, nil
@@ -2399,7 +2425,7 @@ func (o *Seat) GetTouch() (*Touch, error) {
23992425
24002426 // Using this request a client can tell the server that it is not going to use the seat object anymore.
24012427 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 {
24032429 return err
24042430 }
24052431 return nil
@@ -2519,7 +2545,7 @@ func (o *Pointer) SetCursor(serial uint32, surface *Surface, hotspotX int32, hot
25192545 if surface != nil {
25202546 arg1 = surface
25212547 }
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 {
25232549 return err
25242550 }
25252551 return nil
@@ -2527,7 +2553,7 @@ func (o *Pointer) SetCursor(serial uint32, surface *Surface, hotspotX int32, hot
25272553
25282554 // 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.
25292555 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 {
25312557 return err
25322558 }
25332559 return nil
@@ -2962,7 +2988,7 @@ func NewKeyboard(ctx *wl.Context) *Keyboard {
29622988
29632989 // release the keyboard object
29642990 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 {
29662992 return err
29672993 }
29682994 return nil
@@ -3214,7 +3240,7 @@ func NewTouch(ctx *wl.Context) *Touch {
32143240
32153241 // release the touch object
32163242 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 {
32183244 return err
32193245 }
32203246 return nil
@@ -3490,7 +3516,7 @@ func NewOutput(ctx *wl.Context) *Output {
34903516
34913517 // Using this request a client can tell the server that it is not going to use the output object anymore.
34923518 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 {
34943520 return err
34953521 }
34963522 return nil
@@ -3724,7 +3750,7 @@ func NewRegion(ctx *wl.Context) *Region {
37243750
37253751 // Destroy the region. This will invalidate the object ID.
37263752 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 {
37283754 return err
37293755 }
37303756 return nil
@@ -3732,7 +3758,7 @@ func (o *Region) Destroy() error {
37323758
37333759 // Add the specified rectangle to the region.
37343760 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 {
37363762 return err
37373763 }
37383764 return nil
@@ -3740,7 +3766,7 @@ func (o *Region) Add(x int32, y int32, width int32, height int32) error {
37403766
37413767 // Subtract the specified rectangle from the region.
37423768 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 {
37443770 return err
37453771 }
37463772 return nil
@@ -3779,7 +3805,7 @@ func NewSubcompositor(ctx *wl.Context) *Subcompositor {
37793805
37803806 // 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.
37813807 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 {
37833809 return err
37843810 }
37853811 return nil
@@ -3797,7 +3823,7 @@ func (o *Subcompositor) GetSubsurface(surface *Surface, parent *Surface) (*Subsu
37973823 }
37983824 child := &Subsurface{}
37993825 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 {
38013827 return nil, err
38023828 }
38033829 return child, nil
@@ -3836,7 +3862,7 @@ func NewSubsurface(ctx *wl.Context) *Subsurface {
38363862
38373863 // 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.
38383864 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 {
38403866 return err
38413867 }
38423868 return nil
@@ -3844,7 +3870,7 @@ func (o *Subsurface) Destroy() error {
38443870
38453871 // 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.
38463872 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 {
38483874 return err
38493875 }
38503876 return nil
@@ -3856,7 +3882,7 @@ func (o *Subsurface) PlaceAbove(sibling *Surface) error {
38563882 if sibling != nil {
38573883 arg0 = sibling
38583884 }
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 {
38603886 return err
38613887 }
38623888 return nil
@@ -3868,7 +3894,7 @@ func (o *Subsurface) PlaceBelow(sibling *Surface) error {
38683894 if sibling != nil {
38693895 arg0 = sibling
38703896 }
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 {
38723898 return err
38733899 }
38743900 return nil
@@ -3876,7 +3902,7 @@ func (o *Subsurface) PlaceBelow(sibling *Surface) error {
38763902
38773903 // Change the commit behaviour of the sub-surface to synchronized mode. See wl_subsurface and wl_surface.commit for more information.
38783904 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 {
38803906 return err
38813907 }
38823908 return nil
@@ -3884,7 +3910,7 @@ func (o *Subsurface) SetSync() error {
38843910
38853911 // Change the commit behaviour of the sub-surface to desynchronized mode. See wl_subsurface and wl_surface.commit for more information.
38863912 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 {
38883914 return err
38893915 }
38903916 return nil
@@ -3923,7 +3949,7 @@ func NewFixes(ctx *wl.Context) *Fixes {
39233949
39243950 // destroys this object
39253951 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 {
39273953 return err
39283954 }
39293955 return nil
@@ -3935,7 +3961,7 @@ func (o *Fixes) DestroyRegistry(registry *wl.Registry) error {
39353961 if registry != nil {
39363962 arg0 = registry
39373963 }
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 {
39393965 return err
39403966 }
39413967 return nil
@@ -3947,7 +3973,7 @@ func (o *Fixes) AckGlobalRemove(registry *wl.Registry, name uint32) error {
39473973 if registry != nil {
39483974 arg0 = registry
39493975 }
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 {
39513977 return err
39523978 }
39533979 return nil
M protocol/cursorshape/cursor-shape-v1_generated.go +26 -5
@@ -2,6 +2,27 @@
22 // Protocol: cursor_shape_v1
33 // Source: cursor-shape-v1.xml
44
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+
526 package cursorshape
627
728 import (
@@ -139,7 +160,7 @@ func NewWpCursorShapeManager(ctx *wl.Context) *WpCursorShapeManager {
139160
140161 // Destroy the cursor shape manager.
141162 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 {
143164 return err
144165 }
145166 return nil
@@ -153,7 +174,7 @@ func (o *WpCursorShapeManager) GetPointer(pointer *cross_wl_pointer.Pointer) (*W
153174 }
154175 child := &WpCursorShapeDevice{}
155176 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 {
157178 return nil, err
158179 }
159180 return child, nil
@@ -167,7 +188,7 @@ func (o *WpCursorShapeManager) GetTabletTool(tabletTool *cross_zwp_tablet_tool_v
167188 }
168189 child := &WpCursorShapeDevice{}
169190 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 {
171192 return nil, err
172193 }
173194 return child, nil
@@ -206,7 +227,7 @@ func NewWpCursorShapeDevice(ctx *wl.Context) *WpCursorShapeDevice {
206227
207228 // Destroy the cursor shape device. The device cursor shape remains unchanged.
208229 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 {
210231 return err
211232 }
212233 return nil
@@ -214,7 +235,7 @@ func (o *WpCursorShapeDevice) Destroy() error {
214235
215236 // 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.
216237 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 {
218239 return err
219240 }
220241 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 &amp; 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 @@
22 // Protocol: linux_drm_syncobj_v1
33 // Source: linux-drm-syncobj-v1.xml
44
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+
530 package drmsyncobj
631
732 import (
@@ -51,7 +76,7 @@ func NewWpLinuxDrmSyncobjManager(ctx *wl.Context) *WpLinuxDrmSyncobjManager {
5176
5277 // Destroy this explicit synchronization factory object. Other objects shall not be affected by this request.
5378 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 {
5580 return err
5681 }
5782 return nil
@@ -65,7 +90,7 @@ func (o *WpLinuxDrmSyncobjManager) GetSurface(surface *cross_wl_surface.Surface)
6590 }
6691 child := &WpLinuxDrmSyncobjSurface{}
6792 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 {
6994 return nil, err
7095 }
7196 return child, nil
@@ -75,7 +100,7 @@ func (o *WpLinuxDrmSyncobjManager) GetSurface(surface *cross_wl_surface.Surface)
75100 func (o *WpLinuxDrmSyncobjManager) ImportTimeline(fd int) (*WpLinuxDrmSyncobjTimeline, error) {
76101 child := &WpLinuxDrmSyncobjTimeline{}
77102 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 {
79104 return nil, err
80105 }
81106 return child, nil
@@ -114,7 +139,7 @@ func NewWpLinuxDrmSyncobjTimeline(ctx *wl.Context) *WpLinuxDrmSyncobjTimeline {
114139
115140 // 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.
116141 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 {
118143 return err
119144 }
120145 return nil
@@ -153,7 +178,7 @@ func NewWpLinuxDrmSyncobjSurface(ctx *wl.Context) *WpLinuxDrmSyncobjSurface {
153178
154179 // 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.
155180 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 {
157182 return err
158183 }
159184 return nil
@@ -165,7 +190,7 @@ func (o *WpLinuxDrmSyncobjSurface) SetAcquirePoint(timeline *WpLinuxDrmSyncobjTi
165190 if timeline != nil {
166191 arg0 = timeline
167192 }
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 {
169194 return err
170195 }
171196 return nil
@@ -177,7 +202,7 @@ func (o *WpLinuxDrmSyncobjSurface) SetReleasePoint(timeline *WpLinuxDrmSyncobjTi
177202 if timeline != nil {
178203 arg0 = timeline
179204 }
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 {
181206 return err
182207 }
183208 return nil
M protocol/extensions_test.go +219 -0
@@ -7,6 +7,7 @@ import (
77 "errors"
88 "net"
99 "os"
10+ "slices"
1011 "strings"
1112 "testing"
1213 "time"
@@ -111,6 +112,224 @@ func bind(t *testing.T, d *wlturbo.Display, p *net.UnixConn, name uint32, iface
111112 t.Fatalf("bad bind %s announced=%d supported=%d negotiated=%d wire=%x", iface, announced, supported, v, b)
112113 }
113114 }
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+
114333 func TestExtensionsOverSocketpair(t *testing.T) {
115334 c, p := pair(t)
116335 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 @@
22 // Protocol: fractional_scale_v1
33 // Source: fractional-scale-v1.xml
44
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+
527 package fractionalscale
628
729 import (
@@ -32,7 +54,7 @@ func NewWpFractionalScaleManager(ctx *wl.Context) *WpFractionalScaleManager {
3254
3355 // 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.
3456 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 {
3658 return err
3759 }
3860 return nil
@@ -46,7 +68,7 @@ func (o *WpFractionalScaleManager) GetFractionalScale(surface *cross_wl_surface.
4668 }
4769 child := &WpFractionalScale{}
4870 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 {
5072 return nil, err
5173 }
5274 return child, nil
@@ -89,7 +111,7 @@ func NewWpFractionalScale(ctx *wl.Context) *WpFractionalScale {
89111
90112 // Destroy the fractional scale object. When this object is destroyed, preferred_scale events will no longer be sent.
91113 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 {
93115 return err
94116 }
95117 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
44
55 import (
66 "context"
7+ "errors"
78 "fmt"
89 "net"
910 "os"
@@ -21,67 +22,14 @@ import (
2122 "github.com/bnema/wlturbo/protocol/linuxdmabuf"
2223 "github.com/bnema/wlturbo/protocol/viewporter"
2324 "github.com/bnema/wlturbo/protocol/xdgshell"
25+ "golang.org/x/sys/unix"
2426 )
2527
2628 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
8533 compositor := core.NewCompositor(d.Context())
8634 bind(core.CompositorInterface, 6, compositor)
8735 wm := xdgshell.NewXdgWmBase(d.Context())
@@ -93,7 +41,7 @@ func TestHeadlessNeferWL(t *testing.T) {
9341 syncManager := drmsyncobj.NewWpLinuxDrmSyncobjManager(d.Context())
9442 bind(drmsyncobj.WpLinuxDrmSyncobjManagerInterface, 1, syncManager)
9543 dataManager := core.NewDataDeviceManager(d.Context())
96- bind(core.DataDeviceManagerInterface, 4, dataManager)
44+ dataVersion := bind(core.DataDeviceManagerInterface, 4, dataManager)
9745 vp := viewporter.NewWpViewporter(d.Context())
9846 bind(viewporter.WpViewporterInterface, 1, vp)
9947 if g, ok := d.Registry().FindGlobal(fractionalscale.WpFractionalScaleManagerInterface); ok {
@@ -138,11 +86,11 @@ func TestHeadlessNeferWL(t *testing.T) {
13886 noerr(t, surface.Commit())
13987 for (!configured || !done) && ctx.Err() == nil {
14088 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())
14290 }
14391 }
14492 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())
14694 }
14795 noerr(t, surface.Commit())
14896 // Drop all child objects while their parents are still alive.
@@ -152,22 +100,213 @@ func TestHeadlessNeferWL(t *testing.T) {
152100 noerr(t, xs.Destroy())
153101 noerr(t, surface.Destroy())
154102 noerr(t, vp.Destroy())
155- noerr(t, dataManager.Release())
103+ if dataVersion >= 4 {
104+ noerr(t, dataManager.Release())
105+ }
156106 noerr(t, syncManager.Destroy())
157107 noerr(t, dm.Destroy())
158108 noerr(t, wm.Destroy())
159109 noerr(t, d.Close())
160110 }
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+
161280 func cleanDisplayEnv(in []string) []string {
162281 out := make([]string, 0, len(in))
282+next:
163283 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+ }
166288 }
167289 out = append(out, e)
168290 }
169291 return out
170292 }
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+
171310 func headlessLog(f *os.File) string {
172311 b, e := os.ReadFile(f.Name())
173312 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 @@
22 // Protocol: linux_dmabuf_v1
33 // Source: linux-dmabuf-v1.xml
44
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+
527 package linuxdmabuf
628
729 import (
@@ -77,7 +99,7 @@ func NewLinuxDmabuf(ctx *wl.Context) *LinuxDmabuf {
7799
78100 // Objects created through this interface, especially wl_buffers, will remain valid.
79101 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 {
81103 return err
82104 }
83105 return nil
@@ -87,7 +109,7 @@ func (o *LinuxDmabuf) Destroy() error {
87109 func (o *LinuxDmabuf) CreateParams() (*LinuxBufferParams, error) {
88110 child := &LinuxBufferParams{}
89111 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 {
91113 return nil, err
92114 }
93115 return child, nil
@@ -97,7 +119,7 @@ func (o *LinuxDmabuf) CreateParams() (*LinuxBufferParams, error) {
97119 func (o *LinuxDmabuf) GetDefaultFeedback() (*LinuxDmabufFeedback, error) {
98120 child := &LinuxDmabufFeedback{}
99121 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 {
101123 return nil, err
102124 }
103125 return child, nil
@@ -111,7 +133,7 @@ func (o *LinuxDmabuf) GetSurfaceFeedback(surface *cross_wl_surface.Surface) (*Li
111133 }
112134 child := &LinuxDmabufFeedback{}
113135 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 {
115137 return nil, err
116138 }
117139 return child, nil
@@ -219,7 +241,7 @@ func NewLinuxBufferParams(ctx *wl.Context) *LinuxBufferParams {
219241
220242 // Cleans up the temporary data sent to the server for dmabuf-based wl_buffer creation.
221243 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 {
223245 return err
224246 }
225247 return nil
@@ -227,7 +249,7 @@ func (o *LinuxBufferParams) Destroy() error {
227249
228250 // 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.
229251 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 {
231253 return err
232254 }
233255 return nil
@@ -235,7 +257,7 @@ func (o *LinuxBufferParams) Add(fd int, planeIdx uint32, offset uint32, stride u
235257
236258 // 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.
237259 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 {
239261 return err
240262 }
241263 return nil
@@ -244,7 +266,7 @@ func (o *LinuxBufferParams) Create(width int32, height int32, format uint32, fla
244266 // 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.
245267 func (o *LinuxBufferParams) CreateImmed(width int32, height int32, format uint32, flags uint32) (*cross_wl_buffer.Buffer, error) {
246268 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 {
248270 return nil, err
249271 }
250272 return child, nil
@@ -252,7 +274,7 @@ func (o *LinuxBufferParams) CreateImmed(width int32, height int32, format uint32
252274
253275 // 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.
254276 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 {
256278 return err
257279 }
258280 return nil
@@ -366,7 +388,7 @@ func NewLinuxDmabufFeedback(ctx *wl.Context) *LinuxDmabufFeedback {
366388
367389 // Using this request a client can tell the server that it is not going to use the zwp_linux_dmabuf_feedback_v1 object anymore.
368390 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 {
370392 return err
371393 }
372394 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 @@
22 // Protocol: tablet_v2
33 // Source: tablet-v2.xml
44
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+
530 package tablet
631
732 import (
@@ -114,7 +139,7 @@ func (o *TabletManager) GetTabletSeat(seat *cross_wl_seat.Seat) (*TabletSeat, er
114139 }
115140 child := &TabletSeat{}
116141 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 {
118143 return nil, err
119144 }
120145 return child, nil
@@ -122,7 +147,7 @@ func (o *TabletManager) GetTabletSeat(seat *cross_wl_seat.Seat) (*TabletSeat, er
122147
123148 // Destroy the zwp_tablet_manager_v2 object. Objects created from this object are unaffected and should be destroyed separately.
124149 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 {
126151 return err
127152 }
128153 return nil
@@ -167,7 +192,7 @@ func NewTabletSeat(ctx *wl.Context) *TabletSeat {
167192
168193 // Destroy the zwp_tablet_seat_v2 object. Objects created from this object are unaffected and should be destroyed separately.
169194 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 {
171196 return err
172197 }
173198 return nil
@@ -340,7 +365,7 @@ func (o *TabletTool) SetCursor(serial uint32, surface *cross_wl_surface.Surface,
340365 if surface != nil {
341366 arg1 = surface
342367 }
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 {
344369 return err
345370 }
346371 return nil
@@ -348,7 +373,7 @@ func (o *TabletTool) SetCursor(serial uint32, surface *cross_wl_surface.Surface,
348373
349374 // This destroys the client's resource for this tool object.
350375 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 {
352377 return err
353378 }
354379 return nil
@@ -990,7 +1015,7 @@ func NewTablet(ctx *wl.Context) *Tablet {
9901015
9911016 // This destroys the client's resource for this tablet object.
9921017 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 {
9941019 return err
9951020 }
9961021 return nil
@@ -1221,7 +1246,7 @@ func NewTabletPadRing(ctx *wl.Context) *TabletPadRing {
12211246
12221247 // 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.
12231248 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 {
12251250 return err
12261251 }
12271252 return nil
@@ -1229,7 +1254,7 @@ func (o *TabletPadRing) SetFeedback(description string, serial uint32) error {
12291254
12301255 // This destroys the client's resource for this ring object.
12311256 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 {
12331258 return err
12341259 }
12351260 return nil
@@ -1398,7 +1423,7 @@ func NewTabletPadStrip(ctx *wl.Context) *TabletPadStrip {
13981423
13991424 // 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.
14001425 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 {
14021427 return err
14031428 }
14041429 return nil
@@ -1406,7 +1431,7 @@ func (o *TabletPadStrip) SetFeedback(description string, serial uint32) error {
14061431
14071432 // This destroys the client's resource for this strip object.
14081433 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 {
14101435 return err
14111436 }
14121437 return nil
@@ -1578,7 +1603,7 @@ func NewTabletPadGroup(ctx *wl.Context) *TabletPadGroup {
15781603
15791604 // Destroy the zwp_tablet_pad_group_v2 object. Objects created from this object are unaffected and should be destroyed separately.
15801605 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 {
15821607 return err
15831608 }
15841609 return nil
@@ -1861,7 +1886,7 @@ func NewTabletPad(ctx *wl.Context) *TabletPad {
18611886
18621887 // 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.
18631888 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 {
18651890 return err
18661891 }
18671892 return nil
@@ -1869,7 +1894,7 @@ func (o *TabletPad) SetFeedback(button uint32, description string, serial uint32
18691894
18701895 // Destroy the zwp_tablet_pad_v2 object. Objects created from this object are unaffected and should be destroyed separately.
18711896 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 {
18731898 return err
18741899 }
18751900 return nil
@@ -2169,7 +2194,7 @@ func NewTabletPadDial(ctx *wl.Context) *TabletPadDial {
21692194
21702195 // 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.
21712196 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 {
21732198 return err
21742199 }
21752200 return nil
@@ -2177,7 +2202,7 @@ func (o *TabletPadDial) SetFeedback(description string, serial uint32) error {
21772202
21782203 // This destroys the client's resource for this dial object.
21792204 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 {
21812206 return err
21822207 }
21832208 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
@@ -0,0 +1,149 @@
1+// Code generated by wlturbo-scanner. DO NOT EDIT.
2+// Protocol: virtual_keyboard_unstable_v1
3+// Source: virtual-keyboard-unstable-v1.xml
4+
5+// Upstream protocol copyright and license:
6+// Copyright © 2008-2011 Kristian Høgsberg
7+// Copyright © 2010-2013 Intel Corporation
8+// Copyright © 2012-2013 Collabora, Ltd.
9+// Copyright © 2018 Purism SPC
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 virtualkeyboard
31+
32+import (
33+ cross_wl_seat "github.com/bnema/wlturbo/protocol/core"
34+ "github.com/bnema/wlturbo/wl"
35+)
36+
37+// ERROR_NO_KEYMAP is the error no_keymap value.
38+const ERROR_NO_KEYMAP = 0
39+
40+// ERROR_UNAUTHORIZED is the error unauthorized value.
41+const ERROR_UNAUTHORIZED = 0
42+
43+// VirtualKeyboardInterface is the protocol interface name.
44+const VirtualKeyboardInterface = "zwp_virtual_keyboard_v1"
45+
46+// VirtualKeyboard is the generated binding for zwp_virtual_keyboard_v1 version 1.
47+type VirtualKeyboard struct {
48+ wl.BaseProxy
49+}
50+
51+// NewVirtualKeyboard returns an unbound VirtualKeyboard.
52+func NewVirtualKeyboard(ctx *wl.Context) *VirtualKeyboard {
53+ obj := &VirtualKeyboard{}
54+ obj.SetContext(ctx)
55+ ctx.Register(obj)
56+ return obj
57+}
58+
59+// Provide a file descriptor to the compositor which can be memory-mapped to provide a keyboard mapping description. Format carries a value from the keymap_format enumeration.
60+func (o *VirtualKeyboard) Keymap(format uint32, fd int, size uint32) error {
61+ if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_virtual_keyboard_v1.keymap", FDs: []int{fd}}, wl.ArgUint(format), wl.ArgFD(), wl.ArgUint(size)); err != nil {
62+ return err
63+ }
64+ return nil
65+}
66+
67+// A key was pressed or released. The time argument is a timestamp with millisecond granularity, with an undefined base. All requests regarding a single object must share the same clock. Keymap must be set before issuing this request. State carries a value from the key_state enumeration.
68+func (o *VirtualKeyboard) Key(time uint32, key uint32, state uint32) error {
69+ if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_virtual_keyboard_v1.key"}, wl.ArgUint(time), wl.ArgUint(key), wl.ArgUint(state)); err != nil {
70+ return err
71+ }
72+ return nil
73+}
74+
75+// Notifies the compositor that the modifier and/or group state has changed, and it should update state. The client should use wl_keyboard.modifiers event to synchronize its internal state with seat state. Keymap must be set before issuing this request.
76+func (o *VirtualKeyboard) Modifiers(modsDepressed uint32, modsLatched uint32, modsLocked uint32, group uint32) error {
77+ if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_virtual_keyboard_v1.modifiers"}, wl.ArgUint(modsDepressed), wl.ArgUint(modsLatched), wl.ArgUint(modsLocked), wl.ArgUint(group)); err != nil {
78+ return err
79+ }
80+ return nil
81+}
82+
83+// destroy the virtual keyboard keyboard object
84+func (o *VirtualKeyboard) Destroy() error {
85+ if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 3, Name: "zwp_virtual_keyboard_v1.destroy", Destructor: true}); err != nil {
86+ return err
87+ }
88+ return nil
89+}
90+
91+// EventSignature returns the declared event argument types in wire order.
92+func (o *VirtualKeyboard) EventSignature(opcode uint16) (string, bool) {
93+ switch opcode {
94+ default:
95+ return "", false
96+ }
97+}
98+
99+// Dispatch decodes one event on zwp_virtual_keyboard_v1 and calls the registered handlers.
100+func (o *VirtualKeyboard) Dispatch(event *wl.Event) {
101+ switch event.Opcode {
102+ default:
103+ }
104+}
105+
106+// VirtualKeyboardManagerInterface is the protocol interface name.
107+const VirtualKeyboardManagerInterface = "zwp_virtual_keyboard_manager_v1"
108+
109+// VirtualKeyboardManager is the generated binding for zwp_virtual_keyboard_manager_v1 version 1.
110+type VirtualKeyboardManager struct {
111+ wl.BaseProxy
112+}
113+
114+// NewVirtualKeyboardManager returns an unbound VirtualKeyboardManager.
115+func NewVirtualKeyboardManager(ctx *wl.Context) *VirtualKeyboardManager {
116+ obj := &VirtualKeyboardManager{}
117+ obj.SetContext(ctx)
118+ ctx.Register(obj)
119+ return obj
120+}
121+
122+// Creates a new virtual keyboard associated to a seat. If the compositor enables a keyboard to perform arbitrary actions, it should present an error when an untrusted client requests a new keyboard.
123+func (o *VirtualKeyboardManager) CreateVirtualKeyboard(seat *cross_wl_seat.Seat) (*VirtualKeyboard, error) {
124+ var arg0 wl.Object
125+ if seat != nil {
126+ arg0 = seat
127+ }
128+ child := &VirtualKeyboard{}
129+ child.SetContext(o.Context())
130+ if err := o.Context().RequestArgs(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_virtual_keyboard_manager_v1.create_virtual_keyboard", Child: child}, wl.ArgObject(arg0), wl.ArgObject(child)); err != nil {
131+ return nil, err
132+ }
133+ return child, nil
134+}
135+
136+// EventSignature returns the declared event argument types in wire order.
137+func (o *VirtualKeyboardManager) EventSignature(opcode uint16) (string, bool) {
138+ switch opcode {
139+ default:
140+ return "", false
141+ }
142+}
143+
144+// Dispatch decodes one event on zwp_virtual_keyboard_manager_v1 and calls the registered handlers.
145+func (o *VirtualKeyboardManager) Dispatch(event *wl.Event) {
146+ switch event.Opcode {
147+ default:
148+ }
149+}
A protocol/wlr_extensions_test.go +652 -0 collapsed to keep the page light
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
A protocol/xdgdecoration/xdg-decoration-unstable-v1.xml +176 -0 collapsed to keep the page light
A protocol/xdgdecoration/xdg-decoration-unstable-v1_generated.go +195 -0 collapsed to keep the page light
A protocol/xdgoutput/generate.go +3 -0 collapsed to keep the page light
A protocol/xdgoutput/xdg-output-unstable-v1.xml +222 -0 collapsed to keep the page light
A protocol/xdgoutput/xdg-output-unstable-v1_generated.go +290 -0 collapsed to keep the page light
M protocol/xdgshell/xdg-shell_generated.go +63 -36 collapsed to keep the page light
A requestargs_test.go +390 -0 collapsed to keep the page light
M wire.go +45 -0 collapsed to keep the page light
M wl/wl.go +22 -0 collapsed to keep the page light

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 8

↑↓ moveenter openesc close