detached edb855f

merge: extension protocol bindings (Veya P3)

commit
edb855fe490716032519a5660897092bda6913ae
author
brice · · 2026-09-28 08:05 UTC
merge of
c83f653 + ef3605f · diff against the first parent
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
24 files · +7095 -2
M README.md +6 -0
@@ -17,6 +17,12 @@ WLTurbo provides the foundational Wayland client infrastructure:
1717
1818 Higher-level protocol implementations (virtual input devices, output management, etc.) are intentionally left to specialized libraries that build on top of WLTurbo.
1919
20+## Generated protocols
21+
22+`protocol/core` provides core Wayland (including data-device); `protocol/xdgshell` provides xdg-shell; `protocol/linuxdmabuf` provides linux-dmabuf v4 feedback; `protocol/drmsyncobj` provides linux-drm-syncobj v1; `protocol/viewporter` provides viewporter; `protocol/fractionalscale` provides fractional-scale v1; and `protocol/textinput` provides text-input v3. Bindings handle wire messages and object lifecycle; applications decide compositor policy.
23+
24+After `display.Roundtrip()` discovers globals, call `display.Registry().BindNegotiated(interfaceName, supportedVersion, proxy)` to bind at the lesser of the advertised and supported versions. It returns the negotiated version; use `errors.Is(err, wlturbo.ErrGlobalNotFound)` to handle absent optional globals.
25+
2026 ## Features
2127
2228 ### Performance Optimizations
M client.go +22 -0
@@ -789,6 +789,28 @@ func (r *Registry) AddHandler(iface string, handler GlobalHandler) {
789789 r.handlers[iface] = handler
790790 }
791791
792+// ErrGlobalNotFound reports that the compositor does not announce a global.
793+var ErrGlobalNotFound = errors.New("wlturbo: global not announced")
794+
795+// BindNegotiated binds the announced global for iface at
796+// min(announced version, supported) and returns that version. It returns
797+// ErrGlobalNotFound when the global is absent, so callers can decide whether
798+// the capability is optional.
799+func (r *Registry) BindNegotiated(iface string, supported uint32, proxy Proxy) (uint32, error) {
800+ if supported == 0 {
801+ return 0, fmt.Errorf("wlturbo: supported version for %s must be at least 1", iface)
802+ }
803+ g, ok := r.FindGlobal(iface)
804+ if !ok || g.Version == 0 {
805+ return 0, fmt.Errorf("%w: %s", ErrGlobalNotFound, iface)
806+ }
807+ version := min(g.Version, supported)
808+ if err := r.Bind(g.Name, iface, version, proxy); err != nil {
809+ return 0, err
810+ }
811+ return version, nil
812+}
813+
792814 // Bind binds to a global object and returns a typed proxy
793815 func (r *Registry) Bind(name uint32, iface string, version uint32, proxy Proxy) error {
794816 // Set the ID if not already set
M consumer_test.go +20 -1
@@ -35,7 +35,26 @@ func TestExternalConsumer(t *testing.T) {
3535 if err := os.WriteFile(filepath.Join(temp, "consumer_test.go"), source, 0600); err != nil {
3636 t.Fatal(err)
3737 }
38- cmd := exec.Command(goBin, "test", "-run", "TestGeneratedCoreOverSocketpair|TestBufferReleaseAndOfferChild", "./...")
38+ // Keep the extension fake server in a separate package: both fixtures
39+ // independently own their socketpair helpers.
40+ extension, err := os.ReadFile(filepath.Join(root, "protocol/extensions_test.go"))
41+ if err != nil {
42+ t.Fatal(err)
43+ }
44+ if err := os.Mkdir(filepath.Join(temp, "extensions"), 0700); err != nil {
45+ t.Fatal(err)
46+ }
47+ if err := os.WriteFile(filepath.Join(temp, "extensions", "extensions_test.go"), extension, 0600); err != nil {
48+ t.Fatal(err)
49+ }
50+ negotiation, err := os.ReadFile(filepath.Join(root, "protocol/negotiation_test.go"))
51+ if err != nil {
52+ t.Fatal(err)
53+ }
54+ if err := os.WriteFile(filepath.Join(temp, "extensions", "negotiation_test.go"), negotiation, 0600); err != nil {
55+ t.Fatal(err)
56+ }
57+ cmd := exec.Command(goBin, "test", "-run", "TestGeneratedCoreOverSocketpair|TestBufferReleaseAndOfferChild|TestExtensionsOverSocketpair|TestAnnouncedVersionNegotiation", "./...")
3958 cmd.Dir = temp
4059 cmd.Env = append(os.Environ(), "GOWORK=off", "GOFLAGS=-mod=mod")
4160 if output, err := cmd.CombinedOutput(); err != nil {
M internal/scanner/scanner.go +2 -1
@@ -265,7 +265,8 @@ func (s *Scanner) prepareTemplateData(packageName string) (templateData, error)
265265 }
266266 for _, ev := range candidate.Events {
267267 for _, arg := range ev.Args {
268- if arg.Type == "object" || arg.Type == "new_id" {
268+ // Event object references are decoded as IDs, not imported proxies.
269+ if arg.Type == "new_id" {
269270 usedCross[arg.Interface] = true
270271 }
271272 }
M protocol/SOURCE.md +16 -0
@@ -5,3 +5,19 @@
55 `87cc8a8728a923fc57938faa81ba0e74f34ecdc7`.
66 SHA-256: `cc860987e54f8d85c940e97fa1270c69b6e4ad31fbcf5a7f00107ce1157f5e07`.
77 License: MIT (full copyright and grant in `wayland.xml` `<copyright>`).
8+
9+## Required extensions
10+
11+The following XML files come from `https://gitlab.freedesktop.org/wayland/wayland-protocols`,
12+tag `1.49` (peeled commit `ee78491a237eaff9389a0ccf8680521d074407d3`).
13+Each file includes its upstream `<copyright>` and MIT-style license grant.
14+SHA-256 (of the vendored XML bytes):
15+
16+| Upstream path (under tag 1.49) | Vendored path | SHA-256 |
17+|---|---|---|
18+| `stable/xdg-shell/xdg-shell.xml` | `xdgshell/xdg-shell.xml` | `7ba7f9c8473deee674cb1f154a18abd0bb0cc072604fc055b0c15e459fc4c7df` |
19+| `stable/linux-dmabuf/linux-dmabuf-v1.xml` | `linuxdmabuf/linux-dmabuf-v1.xml` | `2735bb4589cbb364dfcb6a821dd3abbf0c0257956b716b9691718ddfd453df4c` |
20+| `staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml` | `drmsyncobj/linux-drm-syncobj-v1.xml` | `5ede41a56eced6aa635caa7ab2996066bff9fd211620dbf9f73aafab740bec71` |
21+| `stable/viewporter/viewporter.xml` | `viewporter/viewporter.xml` | `dcb12279a03746301fe490aaed4b38a403485a925abfce2ccfceb644e104fe71` |
22+| `staging/fractional-scale/fractional-scale-v1.xml` | `fractionalscale/fractional-scale-v1.xml` | `5941de5d28f427ecdadddc8623a6f6af0a30b0ab4726847236ba7a7652b81316` |
23+| `unstable/text-input/text-input-unstable-v3.xml` | `textinput/text-input-unstable-v3.xml` | `160815cda13c285a30df1971d8f0a5b3aac07071537df59916d2f748b18e4f59` |
A protocol/drmsyncobj/linux-drm-syncobj-v1.xml +261 -0
@@ -0,0 +1,261 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<protocol name="linux_drm_syncobj_v1">
3+ <copyright>
4+ Copyright 2016 The Chromium Authors.
5+ Copyright 2017 Intel Corporation
6+ Copyright 2018 Collabora, Ltd
7+ Copyright 2021 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+ </copyright>
28+
29+ <description summary="protocol for providing explicit synchronization">
30+ This protocol allows clients to request explicit synchronization for
31+ buffers. It is tied to the Linux DRM synchronization object framework.
32+
33+ Synchronization refers to co-ordination of pipelined operations performed
34+ on buffers. Most GPU clients will schedule an asynchronous operation to
35+ render to the buffer, then immediately send the buffer to the compositor
36+ to be attached to a surface.
37+
38+ With implicit synchronization, ensuring that the rendering operation is
39+ complete before the compositor displays the buffer is an implementation
40+ detail handled by either the kernel or userspace graphics driver.
41+
42+ By contrast, with explicit synchronization, DRM synchronization object
43+ timeline points mark when the asynchronous operations are complete. When
44+ submitting a buffer, the client provides a timeline point which will be
45+ waited on before the compositor accesses the buffer, and another timeline
46+ point that the compositor will signal when it no longer needs to access the
47+ buffer contents for the purposes of the surface commit.
48+
49+ Linux DRM synchronization objects are documented at:
50+ https://dri.freedesktop.org/docs/drm/gpu/drm-mm.html#drm-sync-objects
51+
52+ Warning! The protocol described in this file is currently in the testing
53+ phase. Backward compatible changes may be added together with the
54+ corresponding interface version bump. Backward incompatible changes can
55+ only be done by creating a new major version of the extension.
56+ </description>
57+
58+ <interface name="wp_linux_drm_syncobj_manager_v1" version="1">
59+ <description summary="global for providing explicit synchronization">
60+ This global is a factory interface, allowing clients to request
61+ explicit synchronization for buffers on a per-surface basis.
62+
63+ See wp_linux_drm_syncobj_surface_v1 for more information.
64+ </description>
65+
66+ <request name="destroy" type="destructor">
67+ <description summary="destroy explicit synchronization factory object">
68+ Destroy this explicit synchronization factory object. Other objects
69+ shall not be affected by this request.
70+ </description>
71+ </request>
72+
73+ <enum name="error">
74+ <entry name="surface_exists" value="0"
75+ summary="the surface already has a synchronization object associated"/>
76+ <entry name="invalid_timeline" value="1"
77+ summary="the timeline object could not be imported"/>
78+ </enum>
79+
80+ <request name="get_surface">
81+ <description summary="extend surface interface for explicit synchronization">
82+ Instantiate an interface extension for the given wl_surface to provide
83+ explicit synchronization.
84+
85+ If the given wl_surface already has an explicit synchronization object
86+ associated, the surface_exists protocol error is raised.
87+
88+ Graphics APIs, like EGL or Vulkan, that manage the buffer queue and
89+ commits of a wl_surface themselves, are likely to be using this
90+ extension internally. If a client is using such an API for a
91+ wl_surface, it should not directly use this extension on that surface,
92+ to avoid raising a surface_exists protocol error.
93+ </description>
94+ <arg name="id" type="new_id" interface="wp_linux_drm_syncobj_surface_v1"
95+ summary="the new synchronization surface object id"/>
96+ <arg name="surface" type="object" interface="wl_surface"
97+ summary="the surface"/>
98+ </request>
99+
100+ <request name="import_timeline">
101+ <description summary="import a DRM syncobj timeline">
102+ Import a DRM synchronization object timeline.
103+
104+ If the FD cannot be imported, the invalid_timeline error is raised.
105+ </description>
106+ <arg name="id" type="new_id" interface="wp_linux_drm_syncobj_timeline_v1"/>
107+ <arg name="fd" type="fd" summary="drm_syncobj file descriptor"/>
108+ </request>
109+ </interface>
110+
111+ <interface name="wp_linux_drm_syncobj_timeline_v1" version="1">
112+ <description summary="synchronization object timeline">
113+ This object represents an explicit synchronization object timeline
114+ imported by the client to the compositor.
115+ </description>
116+
117+ <request name="destroy" type="destructor">
118+ <description summary="destroy the timeline">
119+ Destroy the synchronization object timeline. Other objects are not
120+ affected by this request, in particular timeline points set by
121+ set_acquire_point and set_release_point are not unset.
122+ </description>
123+ </request>
124+ </interface>
125+
126+ <interface name="wp_linux_drm_syncobj_surface_v1" version="1">
127+ <description summary="per-surface explicit synchronization">
128+ This object is an add-on interface for wl_surface to enable explicit
129+ synchronization.
130+
131+ Each surface can be associated with only one object of this interface at
132+ any time.
133+
134+ Explicit synchronization is guaranteed to be supported for buffers
135+ created with any version of the linux-dmabuf protocol. Compositors are
136+ free to support explicit synchronization for additional buffer types.
137+ If at surface commit time the attached buffer does not support explicit
138+ synchronization, an unsupported_buffer error is raised.
139+
140+ As long as the wp_linux_drm_syncobj_surface_v1 object is alive, the
141+ compositor may ignore implicit synchronization for buffers attached and
142+ committed to the wl_surface. The delivery of wl_buffer.release events
143+ for buffers attached to the surface becomes undefined.
144+
145+ Clients must set both acquire and release points if and only if a
146+ non-null buffer is attached in the same surface commit. See the
147+ no_buffer, no_acquire_point and no_release_point protocol errors.
148+
149+ If at surface commit time the acquire and release DRM syncobj timelines
150+ are identical, the acquire point value must be strictly less than the
151+ release point value, or else the conflicting_points protocol error is
152+ raised.
153+ </description>
154+
155+ <request name="destroy" type="destructor">
156+ <description summary="destroy the surface synchronization object">
157+ Destroy this surface synchronization object.
158+
159+ Any timeline point set by this object with set_acquire_point or
160+ set_release_point since the last commit may be discarded by the
161+ compositor. Any timeline point set by this object before the last
162+ commit will not be affected.
163+ </description>
164+ </request>
165+
166+ <enum name="error">
167+ <entry name="no_surface" value="1"
168+ summary="the associated wl_surface was destroyed"/>
169+ <entry name="unsupported_buffer" value="2"
170+ summary="the buffer does not support explicit synchronization"/>
171+ <entry name="no_buffer" value="3" summary="no buffer was attached"/>
172+ <entry name="no_acquire_point" value="4"
173+ summary="no acquire timeline point was set"/>
174+ <entry name="no_release_point" value="5"
175+ summary="no release timeline point was set"/>
176+ <entry name="conflicting_points" value="6"
177+ summary="acquire and release timeline points are in conflict"/>
178+ </enum>
179+
180+ <request name="set_acquire_point">
181+ <description summary="set the acquire timeline point">
182+ Set the timeline point that must be signalled before the compositor may
183+ sample from the buffer attached with wl_surface.attach.
184+
185+ The 64-bit unsigned value combined from point_hi and point_lo is the
186+ point value.
187+
188+ The acquire point is double-buffered state, and will be applied on the
189+ next wl_surface.commit request for the associated surface. Thus, it
190+ applies only to the buffer that is attached to the surface at commit
191+ time.
192+
193+ If an acquire point has already been attached during the same commit
194+ cycle, the new point replaces the old one.
195+
196+ If the associated wl_surface was destroyed, a no_surface error is
197+ raised.
198+
199+ If at surface commit time there is a pending acquire timeline point set
200+ but no pending buffer attached, a no_buffer error is raised. If at
201+ surface commit time there is a pending buffer attached but no pending
202+ acquire timeline point set, the no_acquire_point protocol error is
203+ raised.
204+ </description>
205+ <arg name="timeline" type="object" interface="wp_linux_drm_syncobj_timeline_v1"/>
206+ <arg name="point_hi" type="uint" summary="high 32 bits of the point value"/>
207+ <arg name="point_lo" type="uint" summary="low 32 bits of the point value"/>
208+ </request>
209+
210+ <request name="set_release_point">
211+ <description summary="set the release timeline point">
212+ Set the timeline point that must be signalled by the compositor when it
213+ has finished its usage of the buffer attached with wl_surface.attach
214+ for the relevant commit.
215+
216+ Once the timeline point is signaled, and assuming the associated buffer
217+ is not pending release from other wl_surface.commit requests, no
218+ additional explicit or implicit synchronization with the compositor is
219+ required to safely re-use the buffer.
220+
221+ Note that clients cannot rely on the release point being always
222+ signaled after the acquire point: compositors may release buffers
223+ without ever reading from them. In addition, the compositor may use
224+ different presentation paths for different commits, which may have
225+ different release behavior. As a result, the compositor may signal the
226+ release points in a different order than the client committed them.
227+
228+ Because signaling a timeline point also signals every previous point,
229+ it is generally not safe to use the same timeline object for the
230+ release points of multiple buffers. The out-of-order signaling
231+ described above may lead to a release point being signaled before the
232+ compositor has finished reading. To avoid this, it is strongly
233+ recommended that each buffer should use a separate timeline for its
234+ release points.
235+
236+ The 64-bit unsigned value combined from point_hi and point_lo is the
237+ point value.
238+
239+ The release point is double-buffered state, and will be applied on the
240+ next wl_surface.commit request for the associated surface. Thus, it
241+ applies only to the buffer that is attached to the surface at commit
242+ time.
243+
244+ If a release point has already been attached during the same commit
245+ cycle, the new point replaces the old one.
246+
247+ If the associated wl_surface was destroyed, a no_surface error is
248+ raised.
249+
250+ If at surface commit time there is a pending release timeline point set
251+ but no pending buffer attached, a no_buffer error is raised. If at
252+ surface commit time there is a pending buffer attached but no pending
253+ release timeline point set, the no_release_point protocol error is
254+ raised.
255+ </description>
256+ <arg name="timeline" type="object" interface="wp_linux_drm_syncobj_timeline_v1"/>
257+ <arg name="point_hi" type="uint" summary="high 32 bits of the point value"/>
258+ <arg name="point_lo" type="uint" summary="low 32 bits of the point value"/>
259+ </request>
260+ </interface>
261+</protocol>
A protocol/drmsyncobj/linux-drm-syncobj-v1_generated.go +227 -0
@@ -0,0 +1,227 @@
1+// Code generated by wlturbo-scanner. DO NOT EDIT.
2+// Protocol: linux_drm_syncobj_v1
3+// Source: linux-drm-syncobj-v1.xml
4+
5+package drmsyncobj
6+
7+import (
8+ cross_wl_surface "github.com/bnema/wlturbo/protocol/core"
9+ "github.com/bnema/wlturbo/wl"
10+)
11+
12+// ERROR_SURFACE_EXISTS is the error surface_exists value.
13+const ERROR_SURFACE_EXISTS = 0
14+
15+// ERROR_INVALID_TIMELINE is the error invalid_timeline value.
16+const ERROR_INVALID_TIMELINE = 1
17+
18+// ERROR_NO_SURFACE is the error no_surface value.
19+const ERROR_NO_SURFACE = 1
20+
21+// ERROR_UNSUPPORTED_BUFFER is the error unsupported_buffer value.
22+const ERROR_UNSUPPORTED_BUFFER = 2
23+
24+// ERROR_NO_BUFFER is the error no_buffer value.
25+const ERROR_NO_BUFFER = 3
26+
27+// ERROR_NO_ACQUIRE_POINT is the error no_acquire_point value.
28+const ERROR_NO_ACQUIRE_POINT = 4
29+
30+// ERROR_NO_RELEASE_POINT is the error no_release_point value.
31+const ERROR_NO_RELEASE_POINT = 5
32+
33+// ERROR_CONFLICTING_POINTS is the error conflicting_points value.
34+const ERROR_CONFLICTING_POINTS = 6
35+
36+// WpLinuxDrmSyncobjManagerInterface is the protocol interface name.
37+const WpLinuxDrmSyncobjManagerInterface = "wp_linux_drm_syncobj_manager_v1"
38+
39+// WpLinuxDrmSyncobjManager is the generated binding for wp_linux_drm_syncobj_manager_v1 version 1.
40+type WpLinuxDrmSyncobjManager struct {
41+ wl.BaseProxy
42+}
43+
44+// NewWpLinuxDrmSyncobjManager returns an unbound WpLinuxDrmSyncobjManager.
45+func NewWpLinuxDrmSyncobjManager(ctx *wl.Context) *WpLinuxDrmSyncobjManager {
46+ obj := &WpLinuxDrmSyncobjManager{}
47+ obj.SetContext(ctx)
48+ ctx.Register(obj)
49+ return obj
50+}
51+
52+// Destroy this explicit synchronization factory object. Other objects shall not be affected by this request.
53+func (o *WpLinuxDrmSyncobjManager) Destroy() error {
54+ if err := o.Context().CheckProxy(o); err != nil {
55+ return err
56+ }
57+ if err := o.Context().SendDestructor(o, 0); err != nil {
58+ return err
59+ }
60+ return nil
61+}
62+
63+// Instantiate an interface extension for the given wl_surface to provide explicit synchronization. If the given wl_surface already has an explicit synchronization object associated, the surface_exists protocol error is raised. Graphics APIs, like EGL or Vulkan, that manage the buffer queue and commits of a wl_surface themselves, are likely to be using this extension internally. If a client is using such an API for a wl_surface, it should not directly use this extension on that surface, to avoid raising a surface_exists protocol error.
64+func (o *WpLinuxDrmSyncobjManager) GetSurface(surface *cross_wl_surface.Surface) (*WpLinuxDrmSyncobjSurface, error) {
65+ if err := o.Context().CheckProxy(o); err != nil {
66+ return nil, err
67+ }
68+ var arg1 wl.Object
69+ if surface != nil {
70+ arg1 = surface
71+ }
72+ child := &WpLinuxDrmSyncobjSurface{}
73+ child.SetContext(o.Context())
74+ child.SetID(o.Context().AllocateID())
75+ o.Context().Register(child)
76+ if err := o.Context().SendRequest(o, 1, child, arg1); err != nil {
77+ o.Context().Unregister(child)
78+ return nil, err
79+ }
80+ return child, nil
81+}
82+
83+// Import a DRM synchronization object timeline. If the FD cannot be imported, the invalid_timeline error is raised.
84+func (o *WpLinuxDrmSyncobjManager) ImportTimeline(fd int) (*WpLinuxDrmSyncobjTimeline, error) {
85+ if err := o.Context().CheckProxy(o); err != nil {
86+ return nil, err
87+ }
88+ child := &WpLinuxDrmSyncobjTimeline{}
89+ child.SetContext(o.Context())
90+ child.SetID(o.Context().AllocateID())
91+ o.Context().Register(child)
92+ if err := o.Context().SendRequestWithFDs(o, 2, []int{fd}, child, uintptr(fd)); err != nil {
93+ o.Context().Unregister(child)
94+ return nil, err
95+ }
96+ _ = wl.CloseSentFD(fd)
97+ return child, nil
98+}
99+
100+// EventSignature returns the declared event argument types in wire order.
101+func (o *WpLinuxDrmSyncobjManager) EventSignature(opcode uint16) (string, bool) {
102+ switch opcode {
103+ default:
104+ return "", false
105+ }
106+}
107+
108+// Dispatch decodes one event on wp_linux_drm_syncobj_manager_v1 and calls the registered handlers.
109+func (o *WpLinuxDrmSyncobjManager) Dispatch(event *wl.Event) {
110+ switch event.Opcode {
111+ default:
112+ }
113+}
114+
115+// WpLinuxDrmSyncobjTimelineInterface is the protocol interface name.
116+const WpLinuxDrmSyncobjTimelineInterface = "wp_linux_drm_syncobj_timeline_v1"
117+
118+// WpLinuxDrmSyncobjTimeline is the generated binding for wp_linux_drm_syncobj_timeline_v1 version 1.
119+type WpLinuxDrmSyncobjTimeline struct {
120+ wl.BaseProxy
121+}
122+
123+// NewWpLinuxDrmSyncobjTimeline returns an unbound WpLinuxDrmSyncobjTimeline.
124+func NewWpLinuxDrmSyncobjTimeline(ctx *wl.Context) *WpLinuxDrmSyncobjTimeline {
125+ obj := &WpLinuxDrmSyncobjTimeline{}
126+ obj.SetContext(ctx)
127+ ctx.Register(obj)
128+ return obj
129+}
130+
131+// 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.
132+func (o *WpLinuxDrmSyncobjTimeline) Destroy() error {
133+ if err := o.Context().CheckProxy(o); err != nil {
134+ return err
135+ }
136+ if err := o.Context().SendDestructor(o, 0); err != nil {
137+ return err
138+ }
139+ return nil
140+}
141+
142+// EventSignature returns the declared event argument types in wire order.
143+func (o *WpLinuxDrmSyncobjTimeline) EventSignature(opcode uint16) (string, bool) {
144+ switch opcode {
145+ default:
146+ return "", false
147+ }
148+}
149+
150+// Dispatch decodes one event on wp_linux_drm_syncobj_timeline_v1 and calls the registered handlers.
151+func (o *WpLinuxDrmSyncobjTimeline) Dispatch(event *wl.Event) {
152+ switch event.Opcode {
153+ default:
154+ }
155+}
156+
157+// WpLinuxDrmSyncobjSurfaceInterface is the protocol interface name.
158+const WpLinuxDrmSyncobjSurfaceInterface = "wp_linux_drm_syncobj_surface_v1"
159+
160+// WpLinuxDrmSyncobjSurface is the generated binding for wp_linux_drm_syncobj_surface_v1 version 1.
161+type WpLinuxDrmSyncobjSurface struct {
162+ wl.BaseProxy
163+}
164+
165+// NewWpLinuxDrmSyncobjSurface returns an unbound WpLinuxDrmSyncobjSurface.
166+func NewWpLinuxDrmSyncobjSurface(ctx *wl.Context) *WpLinuxDrmSyncobjSurface {
167+ obj := &WpLinuxDrmSyncobjSurface{}
168+ obj.SetContext(ctx)
169+ ctx.Register(obj)
170+ return obj
171+}
172+
173+// 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.
174+func (o *WpLinuxDrmSyncobjSurface) Destroy() error {
175+ if err := o.Context().CheckProxy(o); err != nil {
176+ return err
177+ }
178+ if err := o.Context().SendDestructor(o, 0); err != nil {
179+ return err
180+ }
181+ return nil
182+}
183+
184+// Set the timeline point that must be signalled before the compositor may sample from the buffer attached with wl_surface.attach. The 64-bit unsigned value combined from point_hi and point_lo is the point value. The acquire point is double-buffered state, and will be applied on the next wl_surface.commit request for the associated surface. Thus, it applies only to the buffer that is attached to the surface at commit time. If an acquire point has already been attached during the same commit cycle, the new point replaces the old one. If the associated wl_surface was destroyed, a no_surface error is raised. If at surface commit time there is a pending acquire timeline point set but no pending buffer attached, a no_buffer error is raised. If at surface commit time there is a pending buffer attached but no pending acquire timeline point set, the no_acquire_point protocol error is raised.
185+func (o *WpLinuxDrmSyncobjSurface) SetAcquirePoint(timeline *WpLinuxDrmSyncobjTimeline, pointHi uint32, pointLo uint32) error {
186+ if err := o.Context().CheckProxy(o); err != nil {
187+ return err
188+ }
189+ var arg0 wl.Object
190+ if timeline != nil {
191+ arg0 = timeline
192+ }
193+ if err := o.Context().SendRequest(o, 1, arg0, pointHi, pointLo); err != nil {
194+ return err
195+ }
196+ return nil
197+}
198+
199+// Set the timeline point that must be signalled by the compositor when it has finished its usage of the buffer attached with wl_surface.attach for the relevant commit. Once the timeline point is signaled, and assuming the associated buffer is not pending release from other wl_surface.commit requests, no additional explicit or implicit synchronization with the compositor is required to safely re-use the buffer. Note that clients cannot rely on the release point being always signaled after the acquire point: compositors may release buffers without ever reading from them. In addition, the compositor may use different presentation paths for different commits, which may have different release behavior. As a result, the compositor may signal the release points in a different order than the client committed them. Because signaling a timeline point also signals every previous point, it is generally not safe to use the same timeline object for the release points of multiple buffers. The out-of-order signaling described above may lead to a release point being signaled before the compositor has finished reading. To avoid this, it is strongly recommended that each buffer should use a separate timeline for its release points. The 64-bit unsigned value combined from point_hi and point_lo is the point value. The release point is double-buffered state, and will be applied on the next wl_surface.commit request for the associated surface. Thus, it applies only to the buffer that is attached to the surface at commit time. If a release point has already been attached during the same commit cycle, the new point replaces the old one. If the associated wl_surface was destroyed, a no_surface error is raised. If at surface commit time there is a pending release timeline point set but no pending buffer attached, a no_buffer error is raised. If at surface commit time there is a pending buffer attached but no pending release timeline point set, the no_release_point protocol error is raised.
200+func (o *WpLinuxDrmSyncobjSurface) SetReleasePoint(timeline *WpLinuxDrmSyncobjTimeline, pointHi uint32, pointLo uint32) error {
201+ if err := o.Context().CheckProxy(o); err != nil {
202+ return err
203+ }
204+ var arg0 wl.Object
205+ if timeline != nil {
206+ arg0 = timeline
207+ }
208+ if err := o.Context().SendRequest(o, 2, arg0, pointHi, pointLo); err != nil {
209+ return err
210+ }
211+ return nil
212+}
213+
214+// EventSignature returns the declared event argument types in wire order.
215+func (o *WpLinuxDrmSyncobjSurface) EventSignature(opcode uint16) (string, bool) {
216+ switch opcode {
217+ default:
218+ return "", false
219+ }
220+}
221+
222+// Dispatch decodes one event on wp_linux_drm_syncobj_surface_v1 and calls the registered handlers.
223+func (o *WpLinuxDrmSyncobjSurface) Dispatch(event *wl.Event) {
224+ switch event.Opcode {
225+ default:
226+ }
227+}
A protocol/extensions_test.go +478 -0
@@ -0,0 +1,478 @@
1+//go:build linux
2+
3+package protocol_test
4+
5+import (
6+ "encoding/binary"
7+ "net"
8+ "os"
9+ "strings"
10+ "testing"
11+ "time"
12+
13+ "github.com/bnema/wlturbo"
14+ "github.com/bnema/wlturbo/protocol/core"
15+ "github.com/bnema/wlturbo/protocol/drmsyncobj"
16+ "github.com/bnema/wlturbo/protocol/fractionalscale"
17+ "github.com/bnema/wlturbo/protocol/linuxdmabuf"
18+ "github.com/bnema/wlturbo/protocol/textinput"
19+ "github.com/bnema/wlturbo/protocol/viewporter"
20+ "github.com/bnema/wlturbo/protocol/xdgshell"
21+ "golang.org/x/sys/unix"
22+)
23+
24+func pair(t *testing.T) (*net.UnixConn, *net.UnixConn) {
25+ t.Helper()
26+ fds, e := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0)
27+ if e != nil {
28+ t.Fatal(e)
29+ }
30+ a := os.NewFile(uintptr(fds[0]), "a")
31+ b := os.NewFile(uintptr(fds[1]), "b")
32+ ca, e := net.FileConn(a)
33+ a.Close()
34+ if e != nil {
35+ t.Fatal(e)
36+ }
37+ cb, e := net.FileConn(b)
38+ b.Close()
39+ if e != nil {
40+ t.Fatal(e)
41+ }
42+ t.Cleanup(func() { ca.Close(); cb.Close() })
43+ return ca.(*net.UnixConn), cb.(*net.UnixConn)
44+}
45+func msg(id uint32, op uint16, body ...uint32) []byte {
46+ b := make([]byte, 8+4*len(body))
47+ binary.NativeEndian.PutUint32(b, id)
48+ binary.NativeEndian.PutUint32(b[4:], uint32(len(b))<<16|uint32(op))
49+ for i, v := range body {
50+ binary.NativeEndian.PutUint32(b[8+i*4:], v)
51+ }
52+ return b
53+}
54+func payload(id uint32, op uint16, b ...byte) []byte {
55+ p := make([]byte, 8+len(b))
56+ copy(p, msg(id, op))
57+ copy(p[8:], b)
58+ binary.NativeEndian.PutUint32(p[4:], uint32(len(p))<<16|uint32(op))
59+ return p
60+}
61+func arr(b []byte) []byte {
62+ out := make([]byte, 4+(len(b)+3)&^3)
63+ binary.NativeEndian.PutUint32(out, uint32(len(b)))
64+ copy(out[4:], b)
65+ return out
66+}
67+func str(s string) []byte { return arr(append([]byte(s), 0)) }
68+func send(t *testing.T, p *net.UnixConn, b []byte, fd ...int) {
69+ t.Helper()
70+ var rights []byte
71+ if len(fd) > 0 {
72+ rights = unix.UnixRights(fd...)
73+ }
74+ if _, _, e := p.WriteMsgUnix(b, rights, nil); e != nil {
75+ t.Fatal(e)
76+ }
77+}
78+func request(t *testing.T, p *net.UnixConn) (uint32, uint16, []byte) {
79+ t.Helper()
80+ p.SetReadDeadline(time.Now().Add(2 * time.Second))
81+ b := make([]byte, 4096)
82+ n, e := p.Read(b)
83+ if e != nil {
84+ t.Fatal(e)
85+ }
86+ if n < 8 {
87+ t.Fatal("short request")
88+ }
89+ return binary.NativeEndian.Uint32(b), uint16(binary.NativeEndian.Uint32(b[4:])), b[8:n]
90+}
91+func noerr(t *testing.T, e error) {
92+ t.Helper()
93+ if e != nil {
94+ t.Fatal(e)
95+ }
96+}
97+func bind(t *testing.T, d *wlturbo.Display, p *net.UnixConn, name uint32, iface string, announced uint32, supported uint32, proxy wlturbo.Proxy) {
98+ t.Helper()
99+ // A fake server must advertise a global before clients can negotiate it.
100+ announcement := append(msg(0, 0, name)[8:], str(iface)...)
101+ announcement = append(announcement, msg(0, 0, announced)[8:]...)
102+ send(t, p, payload(d.Registry().ID(), 0, announcement...))
103+ noerr(t, d.Dispatch())
104+ v, err := d.Registry().BindNegotiated(iface, supported, proxy)
105+ noerr(t, err)
106+ want := min(announced, supported)
107+ _, op, b := request(t, p)
108+ if op != 0 || v != want || binary.NativeEndian.Uint32(b) != name || binary.NativeEndian.Uint32(b[len(b)-8:]) != want || binary.NativeEndian.Uint32(b[len(b)-4:]) != proxy.ID() {
109+ t.Fatalf("bad bind %s announced=%d supported=%d negotiated=%d wire=%x", iface, announced, supported, v, b)
110+ }
111+}
112+func TestExtensionsOverSocketpair(t *testing.T) {
113+ c, p := pair(t)
114+ d, e := wlturbo.ConnectFromConn(c)
115+ noerr(t, e)
116+ defer d.Close()
117+ request(t, p)
118+ // A registry announcement is the only input to optional-global discovery.
119+ send(t, p, payload(d.Registry().ID(), 0, append(msg(0, 0, 11)[8:12], append(str(fractionalscale.WpFractionalScaleManagerInterface), msg(0, 0, 1)[8:12]...)...)...))
120+ noerr(t, d.Dispatch())
121+ if g, ok := d.Registry().FindGlobal(fractionalscale.WpFractionalScaleManagerInterface); !ok || g.Version != 1 {
122+ t.Fatal("announced fractional scale missing", g, ok)
123+ }
124+ if _, ok := d.Registry().FindGlobal(textinput.TextInputManagerV3Interface); ok {
125+ t.Fatal("absent text input")
126+ }
127+ // Remove the discovery-only announcement before the bind matrix assigns
128+ // its own global name to this interface.
129+ send(t, p, msg(d.Registry().ID(), 1, 11))
130+ noerr(t, d.Dispatch())
131+ surface := core.NewSurface(d.Context())
132+ surface.SetID(d.AllocateID())
133+ d.Context().Register(surface)
134+ seat := core.NewSeat(d.Context())
135+ seat.SetID(d.AllocateID())
136+ d.Context().Register(seat)
137+ wm := xdgshell.NewXdgWmBase(d.Context())
138+ bind(t, d, p, 1, xdgshell.XdgWmBaseInterface, 6, 7, wm)
139+ xs, e := wm.GetXdgSurface(surface)
140+ noerr(t, e)
141+ request(t, p)
142+ top, e := xs.GetToplevel()
143+ noerr(t, e)
144+ request(t, p)
145+ var sequence []string
146+ top.OnConfigure(func(w, h int32, states []byte) {
147+ if w != 800 || h != 600 {
148+ t.Fatalf("size %d,%d", w, h)
149+ }
150+ sequence = append(sequence, "top")
151+ })
152+ xs.OnConfigure(func(serial uint32) { sequence = append(sequence, "surface"); noerr(t, xs.AckConfigure(serial)) })
153+ send(t, p, payload(top.ID(), 0, append(msg(0, 0, 800, 600)[8:], arr(nil)...)...))
154+ noerr(t, d.Dispatch())
155+ send(t, p, msg(xs.ID(), 0, 9))
156+ noerr(t, d.Dispatch())
157+ _, op, b := request(t, p)
158+ if op != 4 || binary.NativeEndian.Uint32(b) != 9 || strings.Join(sequence, ",") != "top,surface" {
159+ t.Fatalf("xdg %d %x %v", op, b, sequence)
160+ }
161+ noerr(t, top.Destroy())
162+ request(t, p)
163+ noerr(t, xs.Destroy())
164+ request(t, p)
165+ noerr(t, wm.Destroy())
166+ request(t, p)
167+ dm := linuxdmabuf.NewLinuxDmabuf(d.Context())
168+ bind(t, d, p, 2, linuxdmabuf.LinuxDmabufInterface, 6, 4, dm)
169+ fb, e := dm.GetDefaultFeedback()
170+ noerr(t, e)
171+ request(t, p)
172+ table, e := os.CreateTemp(t.TempDir(), "table")
173+ noerr(t, e)
174+ var bytes [32]byte
175+ binary.NativeEndian.PutUint32(bytes[:], 0x34325258)
176+ binary.NativeEndian.PutUint64(bytes[8:], 19)
177+ binary.NativeEndian.PutUint32(bytes[16:], 0x34325241)
178+ binary.NativeEndian.PutUint64(bytes[24:], 42)
179+ _, e = table.Write(bytes[:])
180+ noerr(t, e)
181+ defer table.Close()
182+ var entries []linuxdmabuf.FormatEntry
183+ var indices []uint16
184+ var feedback []string
185+ fb.OnMainDevice(func(dev []byte) {
186+ if len(dev) != 8 {
187+ t.Fatalf("device %x", dev)
188+ }
189+ feedback = append(feedback, "main")
190+ })
191+ fb.OnFormatTable(func(fd *wlturbo.OwnedFD, size uint32) {
192+ entries, e = linuxdmabuf.ReadFormatTable(fd, size)
193+ noerr(t, e)
194+ feedback = append(feedback, "table")
195+ })
196+ fb.OnTrancheTargetDevice(func(dev []byte) { feedback = append(feedback, "target") })
197+ fb.OnTrancheFormats(func(data []byte) {
198+ indices, e = linuxdmabuf.TrancheIndices(data, len(entries))
199+ noerr(t, e)
200+ feedback = append(feedback, "formats")
201+ })
202+ fb.OnTrancheFlags(func(flags uint32) {
203+ if flags != 1 {
204+ t.Fatal(flags)
205+ }
206+ feedback = append(feedback, "flags")
207+ })
208+ fb.OnTrancheDone(func() { feedback = append(feedback, "tranche") })
209+ fb.OnDone(func() { feedback = append(feedback, "done") })
210+ send(t, p, payload(fb.ID(), 2, arr(make([]byte, 8))...))
211+ noerr(t, d.Dispatch())
212+ send(t, p, msg(fb.ID(), 1, 32), int(table.Fd()))
213+ noerr(t, d.Dispatch())
214+ send(t, p, payload(fb.ID(), 4, arr(make([]byte, 8))...))
215+ noerr(t, d.Dispatch())
216+ send(t, p, payload(fb.ID(), 5, arr([]byte{0, 0, 1, 0})...))
217+ noerr(t, d.Dispatch())
218+ send(t, p, msg(fb.ID(), 6, 1))
219+ noerr(t, d.Dispatch())
220+ send(t, p, msg(fb.ID(), 3))
221+ noerr(t, d.Dispatch())
222+ send(t, p, msg(fb.ID(), 0))
223+ noerr(t, d.Dispatch())
224+ if len(entries) != 2 || entries[1].Modifier != 42 || len(indices) != 2 || indices[1] != 1 || strings.Join(feedback, ",") != "main,table,target,formats,flags,tranche,done" {
225+ t.Fatalf("feedback %v %v %v", entries, indices, feedback)
226+ }
227+ noerr(t, fb.Destroy())
228+ request(t, p)
229+ params, e := dm.CreateParams()
230+ noerr(t, e)
231+ request(t, p)
232+ f, e := os.Open("/dev/null")
233+ noerr(t, e)
234+ noerr(t, params.Add(int(f.Fd()), 0, 0, 4, 0, 0))
235+ request(t, p)
236+ if _, e := unix.FcntlInt(f.Fd(), unix.F_GETFD, 0); e == nil {
237+ t.Fatal("sent fd not closed")
238+ }
239+ f.Close()
240+ var buffer *core.Buffer
241+ params.OnCreated(func(b *core.Buffer) { buffer = b })
242+ params.OnFailed(func() { sequence = append(sequence, "failed") })
243+ noerr(t, params.Create(1, 1, 0x34325258, 0))
244+ request(t, p)
245+ send(t, p, msg(params.ID(), 0, 999))
246+ noerr(t, d.Dispatch())
247+ if buffer == nil || buffer.ID() != 999 {
248+ t.Fatal("typed buffer missing")
249+ }
250+ noerr(t, buffer.Destroy())
251+ request(t, p)
252+ noerr(t, params.Destroy())
253+ request(t, p)
254+ failedParams, e := dm.CreateParams()
255+ noerr(t, e)
256+ request(t, p)
257+ failedParams.OnFailed(func() { sequence = append(sequence, "failed") })
258+ noerr(t, failedParams.Create(1, 1, 0x34325258, 0))
259+ request(t, p)
260+ send(t, p, msg(failedParams.ID(), 1))
261+ noerr(t, d.Dispatch())
262+ if sequence[len(sequence)-1] != "failed" {
263+ t.Fatal(sequence)
264+ }
265+ noerr(t, failedParams.Destroy())
266+ request(t, p)
267+ immedParams, e := dm.CreateParams()
268+ noerr(t, e)
269+ request(t, p)
270+ immediate, e := immedParams.CreateImmed(1, 1, 0x34325258, 0)
271+ noerr(t, e)
272+ request(t, p)
273+ noerr(t, immediate.Destroy())
274+ request(t, p)
275+ noerr(t, immedParams.Destroy())
276+ request(t, p)
277+ noerr(t, dm.Destroy())
278+ request(t, p)
279+ sync := drmsyncobj.NewWpLinuxDrmSyncobjManager(d.Context())
280+ bind(t, d, p, 3, drmsyncobj.WpLinuxDrmSyncobjManagerInterface, 1, 1, sync)
281+ ss, e := sync.GetSurface(surface)
282+ noerr(t, e)
283+ request(t, p)
284+ f, e = os.Open("/dev/null")
285+ noerr(t, e)
286+ tl, e := sync.ImportTimeline(int(f.Fd()))
287+ noerr(t, e)
288+ request(t, p)
289+ if _, e := unix.FcntlInt(f.Fd(), unix.F_GETFD, 0); e == nil {
290+ t.Fatal("timeline fd not closed")
291+ }
292+ f.Close()
293+ noerr(t, ss.SetAcquirePoint(tl, 0x123, 0x456))
294+ _, op, b = request(t, p)
295+ if op != 1 || binary.NativeEndian.Uint32(b[4:]) != 0x123 || binary.NativeEndian.Uint32(b[8:]) != 0x456 {
296+ t.Fatalf("acquire %d %x", op, b)
297+ }
298+ noerr(t, ss.SetReleasePoint(tl, 0x789, 0xabc))
299+ _, op, b = request(t, p)
300+ if op != 2 || binary.NativeEndian.Uint32(b[4:]) != 0x789 {
301+ t.Fatalf("release %d %x", op, b)
302+ }
303+ noerr(t, ss.Destroy())
304+ request(t, p)
305+ noerr(t, tl.Destroy())
306+ request(t, p)
307+ noerr(t, sync.Destroy())
308+ request(t, p)
309+ vp := viewporter.NewWpViewporter(d.Context())
310+ bind(t, d, p, 4, viewporter.WpViewporterInterface, 1, 1, vp)
311+ view, e := vp.GetViewport(surface)
312+ noerr(t, e)
313+ request(t, p)
314+ noerr(t, view.Destroy())
315+ request(t, p)
316+ noerr(t, vp.Destroy())
317+ request(t, p)
318+ fs := fractionalscale.NewWpFractionalScaleManager(d.Context())
319+ bind(t, d, p, 5, fractionalscale.WpFractionalScaleManagerInterface, 1, 1, fs)
320+ scale, e := fs.GetFractionalScale(surface)
321+ noerr(t, e)
322+ request(t, p)
323+ var preferred uint32
324+ scale.OnPreferredScale(func(v uint32) { preferred = v })
325+ send(t, p, msg(scale.ID(), 0, 150))
326+ noerr(t, d.Dispatch())
327+ if preferred != 150 {
328+ t.Fatal(preferred)
329+ }
330+ noerr(t, scale.Destroy())
331+ request(t, p)
332+ noerr(t, fs.Destroy())
333+ request(t, p)
334+ ti := textinput.NewTextInputManagerV3(d.Context())
335+ bind(t, d, p, 6, textinput.TextInputManagerV3Interface, 2, 1, ti)
336+ input, e := ti.GetTextInput(seat)
337+ noerr(t, e)
338+ request(t, p)
339+ noerr(t, input.Enable())
340+ request(t, p)
341+ noerr(t, input.SetSurroundingText("hello", 5, 5))
342+ request(t, p)
343+ noerr(t, input.Commit())
344+ request(t, p)
345+ var events []string
346+ input.OnPreeditString(func(s string, _, _ int32) { events = append(events, "preedit:"+s) })
347+ input.OnCommitString(func(s string) { events = append(events, "commit:"+s) })
348+ input.OnDeleteSurroundingText(func(_, _ uint32) { events = append(events, "delete") })
349+ input.OnDone(func(uint32) { events = append(events, "done") })
350+ send(t, p, payload(input.ID(), 2, append(str("é"), msg(0, 0, 0, 0)[8:]...)...))
351+ noerr(t, d.Dispatch())
352+ send(t, p, payload(input.ID(), 3, str("hi")...))
353+ noerr(t, d.Dispatch())
354+ send(t, p, msg(input.ID(), 4, 1, 2))
355+ noerr(t, d.Dispatch())
356+ send(t, p, msg(input.ID(), 5, 1))
357+ noerr(t, d.Dispatch())
358+ if strings.Join(events, ",") != "preedit:é,commit:hi,delete,done" {
359+ t.Fatal(events)
360+ }
361+ noerr(t, input.Disable())
362+ request(t, p)
363+ noerr(t, input.Commit())
364+ request(t, p)
365+ noerr(t, input.Destroy())
366+ request(t, p)
367+ noerr(t, ti.Destroy())
368+ request(t, p)
369+ // Core data-device remains in protocol/core; verify its typed child and
370+ // both directions of clipboard descriptor ownership.
371+ mgr := core.NewDataDeviceManager(d.Context())
372+ bind(t, d, p, 7, core.DataDeviceManagerInterface, 3, 4, mgr)
373+ device, e := mgr.GetDataDevice(seat)
374+ noerr(t, e)
375+ request(t, p)
376+ source, e := mgr.CreateDataSource()
377+ noerr(t, e)
378+ request(t, p)
379+ var offer *core.DataOffer
380+ device.OnDataOffer(func(o *core.DataOffer) { offer = o })
381+ send(t, p, msg(device.ID(), 0, 998))
382+ noerr(t, d.Dispatch())
383+ if offer == nil || offer.ID() != 998 {
384+ t.Fatal("offer not typed")
385+ }
386+ read, write, e := os.Pipe()
387+ noerr(t, e)
388+ defer read.Close()
389+ noerr(t, offer.Receive("text/plain", int(write.Fd())))
390+ request(t, p)
391+ if _, e := unix.FcntlInt(write.Fd(), unix.F_GETFD, 0); e == nil {
392+ t.Fatal("clipboard sent fd retained")
393+ }
394+ write.Close()
395+ source.OnSend(func(mime string, fd *wlturbo.OwnedFD) {
396+ if mime != "text/plain" {
397+ t.Fatal(mime)
398+ }
399+ n, e := fd.Take()
400+ noerr(t, e)
401+ unix.Close(n)
402+ })
403+ received, e := os.Open("/dev/null")
404+ noerr(t, e)
405+ send(t, p, payload(source.ID(), 1, str("text/plain")...), int(received.Fd()))
406+ noerr(t, d.Dispatch())
407+ received.Close()
408+ noerr(t, offer.Destroy())
409+ request(t, p)
410+ noerr(t, source.Destroy())
411+ request(t, p)
412+ noerr(t, device.Release())
413+ request(t, p)
414+ noerr(t, mgr.Release())
415+ request(t, p)
416+
417+}
418+
419+func TestLiveFeedback(t *testing.T) {
420+ if os.Getenv("WLTURBO_LIVE") != "1" {
421+ t.Skip("set WLTURBO_LIVE=1")
422+ }
423+ d, e := wlturbo.Connect("")
424+ noerr(t, e)
425+ defer d.Close()
426+ noerr(t, d.Roundtrip())
427+ for _, iface := range []string{xdgshell.XdgWmBaseInterface, linuxdmabuf.LinuxDmabufInterface, drmsyncobj.WpLinuxDrmSyncobjManagerInterface, viewporter.WpViewporterInterface, fractionalscale.WpFractionalScaleManagerInterface, textinput.TextInputManagerV3Interface} {
428+ g, ok := d.Registry().FindGlobal(iface)
429+ if !ok {
430+ t.Logf("%s absent", iface)
431+ continue
432+ }
433+ v := g.Version
434+ cap := uint32(1)
435+ if iface == xdgshell.XdgWmBaseInterface {
436+ cap = 7
437+ }
438+ if iface == linuxdmabuf.LinuxDmabufInterface {
439+ cap = 4
440+ }
441+ if v > cap {
442+ v = cap
443+ }
444+ t.Logf("%s negotiated=%d (server=%d)", iface, v, g.Version)
445+ if iface != linuxdmabuf.LinuxDmabufInterface {
446+ continue
447+ }
448+ if v < 4 {
449+ t.Fatal("dmabuf feedback requires v4")
450+ }
451+ dm := linuxdmabuf.NewLinuxDmabuf(d.Context())
452+ negotiated, err := d.Registry().BindNegotiated(iface, 4, dm)
453+ noerr(t, err)
454+ if negotiated != v {
455+ t.Fatalf("dmabuf negotiated=%d want=%d", negotiated, v)
456+ }
457+ fb, e := dm.GetDefaultFeedback()
458+ noerr(t, e)
459+ done := false
460+ fb.OnMainDevice(func(b []byte) { t.Logf("main_device=%x", b) })
461+ fb.OnFormatTable(func(fd *wlturbo.OwnedFD, size uint32) {
462+ entries, err := linuxdmabuf.ReadFormatTable(fd, size)
463+ if err != nil {
464+ t.Errorf("table: %v", err)
465+ }
466+ t.Logf("format-table entries=%d", len(entries))
467+ })
468+ fb.OnDone(func() { done = true })
469+ for i := 0; i < 100 && !done; i++ {
470+ noerr(t, d.Dispatch())
471+ }
472+ if !done {
473+ t.Fatal("no feedback done")
474+ }
475+ noerr(t, fb.Destroy())
476+ noerr(t, dm.Destroy())
477+ }
478+}
A protocol/format_table_test.go +71 -0
@@ -0,0 +1,71 @@
1+//go:build linux
2+
3+package protocol_test
4+
5+import (
6+ "errors"
7+ "github.com/bnema/wlturbo"
8+ "github.com/bnema/wlturbo/protocol/linuxdmabuf"
9+ "golang.org/x/sys/unix"
10+ "io"
11+ "os"
12+ "testing"
13+)
14+
15+// Exercise format_table through generated event dispatch so the received FD
16+// has real transport ownership; verify closing by inspecting the taken FD.
17+func TestMalformedFormatTables(t *testing.T) {
18+ for _, tc := range []struct {
19+ name string
20+ contents []byte
21+ size uint32
22+ wantErr bool
23+ }{
24+ {"unaligned", make([]byte, 16), 17, true},
25+ {"truncated", make([]byte, 16), 32, true},
26+ {"zero", nil, 0, false},
27+ {"oversize", nil, (16 << 20) + 16, true},
28+ } {
29+ t.Run(tc.name, func(t *testing.T) {
30+ c, p := pair(t)
31+ d, e := wlturbo.ConnectFromConn(c)
32+ noerr(t, e)
33+ defer d.Close()
34+ request(t, p)
35+ fb := linuxdmabuf.NewLinuxDmabufFeedback(d.Context())
36+ fb.SetID(d.AllocateID())
37+ d.Context().Register(fb)
38+ file, e := os.CreateTemp(t.TempDir(), "table")
39+ noerr(t, e)
40+ defer file.Close()
41+ _, e = file.Write(tc.contents)
42+ noerr(t, e)
43+ called := false
44+ fb.OnFormatTable(func(fd *wlturbo.OwnedFD, size uint32) {
45+ called = true
46+ entries, err := linuxdmabuf.ReadFormatTable(fd, size)
47+ if (err != nil) != tc.wantErr {
48+ t.Fatalf("size=%d entries=%v err=%v", size, entries, err)
49+ }
50+ if tc.name == "truncated" && !errors.Is(err, io.ErrUnexpectedEOF) {
51+ t.Fatalf("short read: %v", err)
52+ }
53+ // Take/Close must be idempotent, including after a failed size check.
54+ if _, err = fd.Take(); err == nil {
55+ t.Fatal("already consumed fd still takeable")
56+ }
57+ noerr(t, fd.Close())
58+ noerr(t, fd.Close())
59+ })
60+ send(t, p, msg(fb.ID(), 1, tc.size), int(file.Fd()))
61+ noerr(t, d.Dispatch())
62+ if !called {
63+ t.Fatal("no callback")
64+ }
65+ // The transport FD was a duplicate: caller's descriptor is still open.
66+ if _, e = unix.FcntlInt(file.Fd(), unix.F_GETFD, 0); e != nil {
67+ t.Fatalf("sender fd closed: %v", e)
68+ }
69+ })
70+ }
71+}
A protocol/fractionalscale/fractional-scale-v1.xml +102 -0
@@ -0,0 +1,102 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<protocol name="fractional_scale_v1">
3+ <copyright>
4+ Copyright © 2022 Kenny Levinsen
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="Protocol for requesting fractional surface scales">
27+ This protocol allows a compositor to suggest for surfaces to render at
28+ fractional scales.
29+
30+ A client can submit scaled content by utilizing wp_viewport. This is done by
31+ creating a wp_viewport object for the surface and setting the destination
32+ rectangle to the surface size before the scale factor is applied.
33+
34+ The buffer size is calculated by multiplying the surface size by the
35+ intended scale.
36+
37+ The wl_surface buffer scale should remain set to 1.
38+
39+ If a surface has a surface-local size of 100 px by 50 px and wishes to
40+ submit buffers with a scale of 1.5, then a buffer of 150px by 75 px should
41+ be used and the wp_viewport destination rectangle should be 100 px by 50 px.
42+
43+ For toplevel surfaces, the size is rounded halfway away from zero. The
44+ rounding algorithm for subsurface position and size is not defined.
45+ </description>
46+
47+ <interface name="wp_fractional_scale_manager_v1" version="1">
48+ <description summary="fractional surface scale information">
49+ A global interface for requesting surfaces to use fractional scales.
50+ </description>
51+
52+ <request name="destroy" type="destructor">
53+ <description summary="unbind the fractional surface scale interface">
54+ Informs the server that the client will not be using this protocol
55+ object anymore. This does not affect any other objects,
56+ wp_fractional_scale_v1 objects included.
57+ </description>
58+ </request>
59+
60+ <enum name="error">
61+ <entry name="fractional_scale_exists" value="0"
62+ summary="the surface already has a fractional_scale object associated"/>
63+ </enum>
64+
65+ <request name="get_fractional_scale">
66+ <description summary="extend surface interface for scale information">
67+ Create an add-on object for the the wl_surface to let the compositor
68+ request fractional scales. If the given wl_surface already has a
69+ wp_fractional_scale_v1 object associated, the fractional_scale_exists
70+ protocol error is raised.
71+ </description>
72+ <arg name="id" type="new_id" interface="wp_fractional_scale_v1"
73+ summary="the new surface scale info interface id"/>
74+ <arg name="surface" type="object" interface="wl_surface"
75+ summary="the surface"/>
76+ </request>
77+ </interface>
78+
79+ <interface name="wp_fractional_scale_v1" version="1">
80+ <description summary="fractional scale interface to a wl_surface">
81+ An additional interface to a wl_surface object which allows the compositor
82+ to inform the client of the preferred scale.
83+ </description>
84+
85+ <request name="destroy" type="destructor">
86+ <description summary="remove surface scale information for surface">
87+ Destroy the fractional scale object. When this object is destroyed,
88+ preferred_scale events will no longer be sent.
89+ </description>
90+ </request>
91+
92+ <event name="preferred_scale">
93+ <description summary="notify of new preferred scale">
94+ Notification of a new preferred scale for this surface that the
95+ compositor suggests that the client should use.
96+
97+ The sent scale is the numerator of a fraction with a denominator of 120.
98+ </description>
99+ <arg name="scale" type="uint" summary="the new preferred scale"/>
100+ </event>
101+ </interface>
102+</protocol>
A protocol/fractionalscale/fractional-scale-v1_generated.go +154 -0
@@ -0,0 +1,154 @@
1+// Code generated by wlturbo-scanner. DO NOT EDIT.
2+// Protocol: fractional_scale_v1
3+// Source: fractional-scale-v1.xml
4+
5+package fractionalscale
6+
7+import (
8+ "sync"
9+
10+ cross_wl_surface "github.com/bnema/wlturbo/protocol/core"
11+ "github.com/bnema/wlturbo/wl"
12+)
13+
14+// ERROR_FRACTIONAL_SCALE_EXISTS is the error fractional_scale_exists value.
15+const ERROR_FRACTIONAL_SCALE_EXISTS = 0
16+
17+// WpFractionalScaleManagerInterface is the protocol interface name.
18+const WpFractionalScaleManagerInterface = "wp_fractional_scale_manager_v1"
19+
20+// WpFractionalScaleManager is the generated binding for wp_fractional_scale_manager_v1 version 1.
21+type WpFractionalScaleManager struct {
22+ wl.BaseProxy
23+}
24+
25+// NewWpFractionalScaleManager returns an unbound WpFractionalScaleManager.
26+func NewWpFractionalScaleManager(ctx *wl.Context) *WpFractionalScaleManager {
27+ obj := &WpFractionalScaleManager{}
28+ obj.SetContext(ctx)
29+ ctx.Register(obj)
30+ return obj
31+}
32+
33+// Informs the server that the client will not be using this protocol object anymore. This does not affect any other objects, wp_fractional_scale_v1 objects included.
34+func (o *WpFractionalScaleManager) Destroy() error {
35+ if err := o.Context().CheckProxy(o); err != nil {
36+ return err
37+ }
38+ if err := o.Context().SendDestructor(o, 0); err != nil {
39+ return err
40+ }
41+ return nil
42+}
43+
44+// Create an add-on object for the the wl_surface to let the compositor request fractional scales. If the given wl_surface already has a wp_fractional_scale_v1 object associated, the fractional_scale_exists protocol error is raised.
45+func (o *WpFractionalScaleManager) GetFractionalScale(surface *cross_wl_surface.Surface) (*WpFractionalScale, error) {
46+ if err := o.Context().CheckProxy(o); err != nil {
47+ return nil, err
48+ }
49+ var arg1 wl.Object
50+ if surface != nil {
51+ arg1 = surface
52+ }
53+ child := &WpFractionalScale{}
54+ child.SetContext(o.Context())
55+ child.SetID(o.Context().AllocateID())
56+ o.Context().Register(child)
57+ if err := o.Context().SendRequest(o, 1, child, arg1); err != nil {
58+ o.Context().Unregister(child)
59+ return nil, err
60+ }
61+ return child, nil
62+}
63+
64+// EventSignature returns the declared event argument types in wire order.
65+func (o *WpFractionalScaleManager) EventSignature(opcode uint16) (string, bool) {
66+ switch opcode {
67+ default:
68+ return "", false
69+ }
70+}
71+
72+// Dispatch decodes one event on wp_fractional_scale_manager_v1 and calls the registered handlers.
73+func (o *WpFractionalScaleManager) Dispatch(event *wl.Event) {
74+ switch event.Opcode {
75+ default:
76+ }
77+}
78+
79+// WpFractionalScaleInterface is the protocol interface name.
80+const WpFractionalScaleInterface = "wp_fractional_scale_v1"
81+
82+// WpFractionalScale is the generated binding for wp_fractional_scale_v1 version 1.
83+type WpFractionalScale struct {
84+ wl.BaseProxy
85+ // handlersMu guards the handler slices: a client may register or replace
86+ // handlers while another goroutine dispatches events.
87+ handlersMu sync.Mutex
88+ onPreferredScale []func(scale uint32)
89+}
90+
91+// NewWpFractionalScale returns an unbound WpFractionalScale.
92+func NewWpFractionalScale(ctx *wl.Context) *WpFractionalScale {
93+ obj := &WpFractionalScale{}
94+ obj.SetContext(ctx)
95+ ctx.Register(obj)
96+ return obj
97+}
98+
99+// Destroy the fractional scale object. When this object is destroyed, preferred_scale events will no longer be sent.
100+func (o *WpFractionalScale) Destroy() error {
101+ if err := o.Context().CheckProxy(o); err != nil {
102+ return err
103+ }
104+ if err := o.Context().SendDestructor(o, 0); err != nil {
105+ return err
106+ }
107+ return nil
108+}
109+
110+// OnPreferredScale registers a handler for the preferred_scale 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 *WpFractionalScale) OnPreferredScale(handler func(scale uint32)) {
115+ if handler == nil {
116+ return
117+ }
118+ o.handlersMu.Lock()
119+ defer o.handlersMu.Unlock()
120+ o.onPreferredScale = append(o.onPreferredScale, handler)
121+}
122+
123+// handlersForPreferredScale returns the handlers registered for preferred_scale, taken
124+// under the lock so a handler may register another handler while events are
125+// being dispatched.
126+func (o *WpFractionalScale) handlersForPreferredScale() []func(scale uint32) {
127+ o.handlersMu.Lock()
128+ defer o.handlersMu.Unlock()
129+ return o.onPreferredScale
130+}
131+
132+// EventSignature returns the declared event argument types in wire order.
133+func (o *WpFractionalScale) EventSignature(opcode uint16) (string, bool) {
134+ switch opcode {
135+ case 0:
136+ return "uint,", true
137+ default:
138+ return "", false
139+ }
140+}
141+
142+// Dispatch decodes one event on wp_fractional_scale_v1 and calls the registered handlers.
143+func (o *WpFractionalScale) Dispatch(event *wl.Event) {
144+ switch event.Opcode {
145+ case 0: // preferred_scale
146+ scale := event.Uint32()
147+
148+ for i, handler := range o.handlersForPreferredScale() {
149+ _ = i
150+ handler(scale)
151+ }
152+ default:
153+ }
154+}
M protocol/generate.go +6 -0
@@ -1,3 +1,9 @@
11 package protocol
22
33 //go:generate go run ../cmd/wlturbo-scanner -p core -o core/wayland_generated.go wayland.xml
4+//go:generate go run ../cmd/wlturbo-scanner -p xdgshell -o xdgshell/xdg-shell_generated.go -import wl_surface=github.com/bnema/wlturbo/protocol/core -import wl_seat=github.com/bnema/wlturbo/protocol/core -import wl_output=github.com/bnema/wlturbo/protocol/core xdgshell/xdg-shell.xml
5+//go:generate go run ../cmd/wlturbo-scanner -p linuxdmabuf -o linuxdmabuf/linux-dmabuf-v1_generated.go -import wl_surface=github.com/bnema/wlturbo/protocol/core -import wl_buffer=github.com/bnema/wlturbo/protocol/core linuxdmabuf/linux-dmabuf-v1.xml
6+//go:generate go run ../cmd/wlturbo-scanner -p drmsyncobj -o drmsyncobj/linux-drm-syncobj-v1_generated.go -import wl_surface=github.com/bnema/wlturbo/protocol/core drmsyncobj/linux-drm-syncobj-v1.xml
7+//go:generate go run ../cmd/wlturbo-scanner -p viewporter -o viewporter/viewporter_generated.go -import wl_surface=github.com/bnema/wlturbo/protocol/core viewporter/viewporter.xml
8+//go:generate go run ../cmd/wlturbo-scanner -p fractionalscale -o fractionalscale/fractional-scale-v1_generated.go -import wl_surface=github.com/bnema/wlturbo/protocol/core fractionalscale/fractional-scale-v1.xml
9+//go:generate go run ../cmd/wlturbo-scanner -p textinput -o textinput/text-input-unstable-v3_generated.go -import wl_surface=github.com/bnema/wlturbo/protocol/core -import wl_seat=github.com/bnema/wlturbo/protocol/core textinput/text-input-unstable-v3.xml
A protocol/headless_test.go +180 -0
@@ -0,0 +1,180 @@
1+//go:build linux
2+
3+package protocol_test
4+
5+import (
6+ "context"
7+ "fmt"
8+ "net"
9+ "os"
10+ "os/exec"
11+ "path/filepath"
12+ "strings"
13+ "syscall"
14+ "testing"
15+ "time"
16+
17+ "github.com/bnema/wlturbo"
18+ "github.com/bnema/wlturbo/protocol/core"
19+ "github.com/bnema/wlturbo/protocol/drmsyncobj"
20+ "github.com/bnema/wlturbo/protocol/fractionalscale"
21+ "github.com/bnema/wlturbo/protocol/linuxdmabuf"
22+ "github.com/bnema/wlturbo/protocol/viewporter"
23+ "github.com/bnema/wlturbo/protocol/xdgshell"
24+)
25+
26+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+ }
85+ compositor := core.NewCompositor(d.Context())
86+ bind(core.CompositorInterface, 6, compositor)
87+ wm := xdgshell.NewXdgWmBase(d.Context())
88+ bind(xdgshell.XdgWmBaseInterface, 7, wm)
89+ dm := linuxdmabuf.NewLinuxDmabuf(d.Context())
90+ if bind(linuxdmabuf.LinuxDmabufInterface, 4, dm) < 4 {
91+ t.Fatal("dmabuf feedback requires v4")
92+ }
93+ syncManager := drmsyncobj.NewWpLinuxDrmSyncobjManager(d.Context())
94+ bind(drmsyncobj.WpLinuxDrmSyncobjManagerInterface, 1, syncManager)
95+ dataManager := core.NewDataDeviceManager(d.Context())
96+ bind(core.DataDeviceManagerInterface, 4, dataManager)
97+ vp := viewporter.NewWpViewporter(d.Context())
98+ bind(viewporter.WpViewporterInterface, 1, vp)
99+ if g, ok := d.Registry().FindGlobal(fractionalscale.WpFractionalScaleManagerInterface); ok {
100+ fs := fractionalscale.NewWpFractionalScaleManager(d.Context())
101+ v := bind(g.Interface, 1, fs)
102+ if v != 1 {
103+ t.Fatalf("fractional scale version %d", v)
104+ }
105+ noerr(t, fs.Destroy())
106+ } else {
107+ t.Log("fractional scale absent")
108+ }
109+ surface, e := compositor.CreateSurface()
110+ noerr(t, e)
111+ xs, e := wm.GetXdgSurface(surface)
112+ noerr(t, e)
113+ top, e := xs.GetToplevel()
114+ noerr(t, e)
115+ feedback, e := dm.GetSurfaceFeedback(surface)
116+ noerr(t, e)
117+ ss, e := syncManager.GetSurface(surface)
118+ noerr(t, e)
119+ configured, done, mainDevice, tableOK := false, false, false, false
120+ top.OnConfigure(func(w, h int32, states []byte) { t.Logf("xdg_toplevel.configure %dx%d", w, h) })
121+ xs.OnConfigure(func(serial uint32) {
122+ noerr(t, xs.AckConfigure(serial))
123+ configured = true
124+ t.Logf("xdg_surface.configure ack=%d", serial)
125+ })
126+ feedback.OnMainDevice(func(b []byte) { mainDevice = len(b) == 8; t.Logf("main_device=%x", b) })
127+ feedback.OnFormatTable(func(fd *wlturbo.OwnedFD, size uint32) {
128+ entries, e := linuxdmabuf.ReadFormatTable(fd, size)
129+ if e != nil {
130+ t.Errorf("format table: %v", e)
131+ } else {
132+ tableOK = len(entries) > 0
133+ t.Logf("format-table entries=%d", len(entries))
134+ }
135+ })
136+ feedback.OnDone(func() { done = true })
137+ // Initial empty commit requests xdg configure; no buffer or window is shown.
138+ noerr(t, surface.Commit())
139+ for (!configured || !done) && ctx.Err() == nil {
140+ if e := d.Dispatch(); e != nil {
141+ t.Fatalf("dispatch: %v\n%s", e, headlessLog(log))
142+ }
143+ }
144+ 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))
146+ }
147+ noerr(t, surface.Commit())
148+ // Drop all child objects while their parents are still alive.
149+ noerr(t, ss.Destroy())
150+ noerr(t, feedback.Destroy())
151+ noerr(t, top.Destroy())
152+ noerr(t, xs.Destroy())
153+ noerr(t, surface.Destroy())
154+ noerr(t, vp.Destroy())
155+ noerr(t, dataManager.Release())
156+ noerr(t, syncManager.Destroy())
157+ noerr(t, dm.Destroy())
158+ noerr(t, wm.Destroy())
159+ noerr(t, d.Close())
160+}
161+func cleanDisplayEnv(in []string) []string {
162+ out := make([]string, 0, len(in))
163+ 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
166+ }
167+ out = append(out, e)
168+ }
169+ return out
170+}
171+func headlessLog(f *os.File) string {
172+ b, e := os.ReadFile(f.Name())
173+ if e != nil {
174+ return fmt.Sprint(e)
175+ }
176+ if len(b) > 8192 {
177+ b = b[len(b)-8192:]
178+ }
179+ return string(b)
180+}
A protocol/linuxdmabuf/linux-dmabuf-v1.xml +623 -0
@@ -0,0 +1,623 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<protocol name="linux_dmabuf_v1">
3+
4+ <copyright>
5+ Copyright © 2014, 2015 Collabora, 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_linux_dmabuf_v1" version="6">
28+ <description summary="factory for creating dmabuf-based wl_buffers">
29+ This interface offers ways to create generic dmabuf-based wl_buffers.
30+
31+ For more information about dmabuf, see:
32+ https://www.kernel.org/doc/html/next/userspace-api/dma-buf-alloc-exchange.html
33+
34+ Clients can use the get_surface_feedback request to get dmabuf feedback
35+ for a particular surface. If the client wants to retrieve feedback not
36+ tied to a surface, they can use the get_default_feedback request.
37+
38+ The following are required from clients:
39+
40+ - Clients must ensure that either all data in the dma-buf is
41+ coherent for all subsequent read access or that coherency is
42+ correctly handled by the underlying kernel-side dma-buf
43+ implementation.
44+
45+ - Don't make any more attachments after sending the buffer to the
46+ compositor. Making more attachments later increases the risk of
47+ the compositor not being able to use (re-import) an existing
48+ dmabuf-based wl_buffer.
49+
50+ The underlying graphics stack must ensure the following:
51+
52+ - The dmabuf file descriptors relayed to the server will stay valid
53+ for the whole lifetime of the wl_buffer. This means the server may
54+ at any time use those fds to import the dmabuf into any kernel
55+ sub-system that might accept it.
56+
57+ However, when the underlying graphics stack fails to deliver the
58+ promise, because of e.g. a device hot-unplug which raises internal
59+ errors, after the wl_buffer has been successfully created the
60+ compositor must not raise protocol errors to the client when dmabuf
61+ import later fails.
62+
63+ To create a wl_buffer from one or more dmabufs, a client creates a
64+ zwp_linux_buffer_params_v1 object with a zwp_linux_dmabuf_v1.create_params
65+ request. All planes required by the intended format are added with
66+ the 'add' request. Finally, a 'create' or 'create_immed' request is
67+ issued, which has the following outcome depending on the import success.
68+
69+ The 'create' request,
70+ - on success, triggers a 'created' event which provides the final
71+ wl_buffer to the client.
72+ - on failure, triggers a 'failed' event to convey that the server
73+ cannot use the dmabufs received from the client.
74+
75+ For the 'create_immed' request,
76+ - on success, the server immediately imports the added dmabufs to
77+ create a wl_buffer. No event is sent from the server in this case.
78+ - on failure, the server can choose to either:
79+ - terminate the client by raising a fatal error.
80+ - mark the wl_buffer as failed, and send a 'failed' event to the
81+ client. If the client uses a failed wl_buffer as an argument to any
82+ request, the behaviour is compositor implementation-defined.
83+
84+ For all DRM formats and unless specified in another protocol extension,
85+ pre-multiplied alpha is used for pixel values.
86+
87+ Unless specified otherwise in another protocol extension, implicit
88+ synchronization is used. In other words, compositors and clients must
89+ wait and signal fences implicitly passed via the DMA-BUF's reservation
90+ mechanism.
91+ </description>
92+
93+ <request name="destroy" type="destructor">
94+ <description summary="unbind the factory">
95+ Objects created through this interface, especially wl_buffers, will
96+ remain valid.
97+ </description>
98+ </request>
99+
100+ <request name="create_params">
101+ <description summary="create a temporary object for buffer parameters">
102+ This temporary object is used to collect multiple dmabuf handles into
103+ a single batch to create a wl_buffer. It can only be used once and
104+ should be destroyed after a 'created' or 'failed' event has been
105+ received.
106+ </description>
107+ <arg name="params_id" type="new_id" interface="zwp_linux_buffer_params_v1"
108+ summary="id for the newly created zwp_linux_buffer_params_v1"/>
109+ </request>
110+
111+ <event name="format" deprecated-since="4">
112+ <description summary="supported buffer format">
113+ This event advertises one buffer format that the server supports.
114+ All the supported formats are advertised once when the client
115+ binds to this interface. A roundtrip after binding guarantees
116+ that the client has received all supported formats.
117+
118+ For the definition of the format codes, see the
119+ zwp_linux_buffer_params_v1::create request.
120+
121+ Starting version 4, the format event is deprecated and must not be
122+ sent by compositors. Instead, use get_default_feedback or
123+ get_surface_feedback.
124+ </description>
125+ <arg name="format" type="uint" summary="DRM_FORMAT code"/>
126+ </event>
127+
128+ <event name="modifier" since="3" deprecated-since="4">
129+ <description summary="supported buffer format modifier">
130+ This event advertises the formats that the server supports, along with
131+ the modifiers supported for each format. All the supported modifiers
132+ for all the supported formats are advertised once when the client
133+ binds to this interface. A roundtrip after binding guarantees that
134+ the client has received all supported format-modifier pairs.
135+
136+ For legacy support, DRM_FORMAT_MOD_INVALID (that is, modifier_hi ==
137+ 0x00ffffff and modifier_lo == 0xffffffff) is allowed in this event.
138+ It indicates that the server can support the format with an implicit
139+ modifier. When a plane has DRM_FORMAT_MOD_INVALID as its modifier, it
140+ is as if no explicit modifier is specified. The effective modifier
141+ will be derived from the dmabuf.
142+
143+ A compositor that sends valid modifiers and DRM_FORMAT_MOD_INVALID for
144+ a given format supports both explicit modifiers and implicit modifiers.
145+
146+ For the definition of the format and modifier codes, see the
147+ zwp_linux_buffer_params_v1::create and zwp_linux_buffer_params_v1::add
148+ requests.
149+
150+ Starting version 4, the modifier event is deprecated and must not be
151+ sent by compositors. Instead, use get_default_feedback or
152+ get_surface_feedback.
153+ </description>
154+ <arg name="format" type="uint" summary="DRM_FORMAT code"/>
155+ <arg name="modifier_hi" type="uint"
156+ summary="high 32 bits of layout modifier"/>
157+ <arg name="modifier_lo" type="uint"
158+ summary="low 32 bits of layout modifier"/>
159+ </event>
160+
161+ <!-- Version 4 additions -->
162+
163+ <request name="get_default_feedback" since="4">
164+ <description summary="get default feedback">
165+ This request creates a new zwp_linux_dmabuf_feedback_v1 object not bound
166+ to a particular surface. This object will deliver feedback about dmabuf
167+ parameters to use if the client doesn't support per-surface feedback
168+ (see get_surface_feedback).
169+ </description>
170+ <arg name="id" type="new_id" interface="zwp_linux_dmabuf_feedback_v1"/>
171+ </request>
172+
173+ <request name="get_surface_feedback" since="4">
174+ <description summary="get feedback for a surface">
175+ This request creates a new zwp_linux_dmabuf_feedback_v1 object for the
176+ specified wl_surface. This object will deliver feedback about dmabuf
177+ parameters to use for buffers attached to this surface.
178+
179+ If the surface is destroyed before the zwp_linux_dmabuf_feedback_v1 object,
180+ the feedback object becomes inert.
181+ </description>
182+ <arg name="id" type="new_id" interface="zwp_linux_dmabuf_feedback_v1"/>
183+ <arg name="surface" type="object" interface="wl_surface"/>
184+ </request>
185+ </interface>
186+
187+ <interface name="zwp_linux_buffer_params_v1" version="6">
188+ <description summary="parameters for creating a dmabuf-based wl_buffer">
189+ This temporary object is a collection of dmabufs and other
190+ parameters that together form a single logical buffer. The temporary
191+ object may eventually create one wl_buffer unless cancelled by
192+ destroying it before requesting 'create'.
193+
194+ Single-planar formats only require one dmabuf, however
195+ multi-planar formats may require more than one dmabuf. For all
196+ formats, an 'add' request must be called once per plane (even if the
197+ underlying dmabuf fd is identical).
198+
199+ You must use consecutive plane indices ('plane_idx' argument for 'add')
200+ from zero to the number of planes used by the drm_fourcc format code.
201+ All planes required by the format must be given exactly once, but can
202+ be given in any order. Each plane index can only be set once; subsequent
203+ calls with a plane index which has already been set will result in a
204+ plane_set error being generated.
205+ </description>
206+
207+ <enum name="error">
208+ <entry name="already_used" value="0"
209+ summary="the zwp_linux_buffer_params_v1 object has already been used to create a wl_buffer"/>
210+ <entry name="plane_idx" value="1"
211+ summary="plane index out of bounds"/>
212+ <entry name="plane_set" value="2"
213+ summary="the plane index was already set"/>
214+ <entry name="incomplete" value="3"
215+ summary="missing or too many planes to create a buffer"/>
216+ <entry name="invalid_format" value="4"
217+ summary="format not supported"/>
218+ <entry name="invalid_dimensions" value="5"
219+ summary="invalid width or height"/>
220+ <entry name="out_of_bounds" value="6"
221+ summary="offset + stride * height goes out of dmabuf bounds"/>
222+ <entry name="invalid_wl_buffer" value="7"
223+ summary="invalid wl_buffer resulted from importing dmabufs via
224+ the create_immed request on given buffer_params"/>
225+ <entry name="invalid_dev_t_size" value="8"
226+ summary="an array with mismatching size for a dev_t was used"/>
227+ </enum>
228+
229+ <request name="destroy" type="destructor">
230+ <description summary="delete this object, used or not">
231+ Cleans up the temporary data sent to the server for dmabuf-based
232+ wl_buffer creation.
233+ </description>
234+ </request>
235+
236+ <request name="add">
237+ <description summary="add a dmabuf to the temporary set">
238+ This request adds one dmabuf to the set in this
239+ zwp_linux_buffer_params_v1.
240+
241+ The 64-bit unsigned value combined from modifier_hi and modifier_lo
242+ is the dmabuf layout modifier. DRM AddFB2 ioctl calls this the
243+ fb modifier, which is defined in drm_mode.h of Linux UAPI.
244+ This is an opaque token. Drivers use this token to express tiling,
245+ compression, etc. driver-specific modifications to the base format
246+ defined by the DRM fourcc code.
247+
248+ Starting from version 4, the invalid_format protocol error is sent if
249+ the format + modifier pair was not advertised as supported.
250+
251+ Starting from version 5, the invalid_format protocol error is sent if
252+ all planes don't use the same modifier.
253+
254+ This request raises the PLANE_IDX error if plane_idx is too large.
255+ The error PLANE_SET is raised if attempting to set a plane that
256+ was already set.
257+ </description>
258+ <arg name="fd" type="fd" summary="dmabuf fd"/>
259+ <arg name="plane_idx" type="uint" summary="plane index"/>
260+ <arg name="offset" type="uint" summary="offset in bytes"/>
261+ <arg name="stride" type="uint" summary="stride in bytes"/>
262+ <arg name="modifier_hi" type="uint"
263+ summary="high 32 bits of layout modifier"/>
264+ <arg name="modifier_lo" type="uint"
265+ summary="low 32 bits of layout modifier"/>
266+ </request>
267+
268+ <enum name="flags" bitfield="true">
269+ <entry name="y_invert" value="1" summary="contents are y-inverted"/>
270+ <entry name="interlaced" value="2" summary="content is interlaced"/>
271+ <entry name="bottom_first" value="4" summary="bottom field first"/>
272+ </enum>
273+
274+ <request name="create">
275+ <description summary="create a wl_buffer from the given dmabufs">
276+ This asks for creation of a wl_buffer from the added dmabuf
277+ buffers. The wl_buffer is not created immediately but returned via
278+ the 'created' event if the dmabuf sharing succeeds. The sharing
279+ may fail at runtime for reasons a client cannot predict, in
280+ which case the 'failed' event is triggered.
281+
282+ The 'format' argument is a DRM_FORMAT code, as defined by the
283+ libdrm's drm_fourcc.h. The Linux kernel's DRM sub-system is the
284+ authoritative source on how the format codes should work.
285+
286+ The 'flags' is a bitfield of the flags defined in enum "flags".
287+ 'y_invert' means that the image needs to be y-flipped.
288+
289+ Flag 'interlaced' means that the frame in the buffer is not
290+ progressive as usual, but interlaced. An interlaced buffer as
291+ supported here must always contain both top and bottom fields.
292+ The top field always begins on the first pixel row. The temporal
293+ ordering between the two fields is top field first, unless
294+ 'bottom_first' is specified. It is undefined whether 'bottom_first'
295+ is ignored if 'interlaced' is not set.
296+
297+ This protocol does not convey any information about field rate,
298+ duration, or timing, other than the relative ordering between the
299+ two fields in one buffer. A compositor may have to estimate the
300+ intended field rate from the incoming buffer rate. It is undefined
301+ whether the time of receiving wl_surface.commit with a new buffer
302+ attached, applying the wl_surface state, wl_surface.frame callback
303+ trigger, presentation, or any other point in the compositor cycle
304+ is used to measure the frame or field times. There is no support
305+ for detecting missed or late frames/fields/buffers either, and
306+ there is no support whatsoever for cooperating with interlaced
307+ compositor output.
308+
309+ The composited image quality resulting from the use of interlaced
310+ buffers is explicitly undefined. A compositor may use elaborate
311+ hardware features or software to deinterlace and create progressive
312+ output frames from a sequence of interlaced input buffers, or it
313+ may produce substandard image quality. However, compositors that
314+ cannot guarantee reasonable image quality in all cases are recommended
315+ to just reject all interlaced buffers.
316+
317+ Any argument errors, including non-positive width or height,
318+ mismatch between the number of planes and the format, bad
319+ format, bad offset or stride, may be indicated by fatal protocol
320+ errors: INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS,
321+ OUT_OF_BOUNDS.
322+
323+ Dmabuf import errors in the server that are not obvious client
324+ bugs are returned via the 'failed' event as non-fatal. This
325+ allows attempting dmabuf sharing and falling back in the client
326+ if it fails.
327+
328+ This request can be sent only once in the object's lifetime, after
329+ which the only legal request is destroy. This object should be
330+ destroyed after issuing a 'create' request. Attempting to use this
331+ object after issuing 'create' raises the ALREADY_USED protocol error.
332+
333+ It is not mandatory to issue 'create'. If a client wants to
334+ cancel the buffer creation, it can just destroy this object.
335+ </description>
336+ <arg name="width" type="int" summary="base plane width in pixels"/>
337+ <arg name="height" type="int" summary="base plane height in pixels"/>
338+ <arg name="format" type="uint" summary="DRM_FORMAT code"/>
339+ <arg name="flags" type="uint" enum="flags" summary="see enum flags"/>
340+ </request>
341+
342+ <event name="created">
343+ <description summary="buffer creation succeeded">
344+ This event indicates that the attempted buffer creation was
345+ successful. It provides the new wl_buffer referencing the dmabuf(s).
346+
347+ Upon receiving this event, the client should destroy the
348+ zwp_linux_buffer_params_v1 object.
349+ </description>
350+ <arg name="buffer" type="new_id" interface="wl_buffer"
351+ summary="id for the the newly created wl_buffer"/>
352+ </event>
353+
354+ <event name="failed">
355+ <description summary="buffer creation failed">
356+ This event indicates that the attempted buffer creation has
357+ failed. It usually means that one of the dmabuf constraints
358+ has not been fulfilled.
359+
360+ Upon receiving this event, the client should destroy the
361+ zwp_linux_buffer_params_v1 object.
362+ </description>
363+ </event>
364+
365+ <request name="create_immed" since="2">
366+ <description summary="immediately create a wl_buffer from the given
367+ dmabufs">
368+ This asks for immediate creation of a wl_buffer by importing the
369+ added dmabufs.
370+
371+ In case of import success, no event is sent from the server, and the
372+ wl_buffer is ready to be used by the client.
373+
374+ Upon import failure, either of the following may happen, as seen fit
375+ by the implementation:
376+ - the client is terminated with one of the following fatal protocol
377+ errors:
378+ - INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS, OUT_OF_BOUNDS,
379+ in case of argument errors such as mismatch between the number
380+ of planes and the format, bad format, non-positive width or
381+ height, or bad offset or stride.
382+ - INVALID_WL_BUFFER, in case the cause for failure is unknown or
383+ platform specific.
384+ - the server creates an invalid wl_buffer, marks it as failed and
385+ sends a 'failed' event to the client. The result of using this
386+ invalid wl_buffer as an argument in any request by the client is
387+ defined by the compositor implementation.
388+
389+ This takes the same arguments as a 'create' request, and obeys the
390+ same restrictions.
391+ </description>
392+ <arg name="buffer_id" type="new_id" interface="wl_buffer"
393+ summary="id for the newly created wl_buffer"/>
394+ <arg name="width" type="int" summary="base plane width in pixels"/>
395+ <arg name="height" type="int" summary="base plane height in pixels"/>
396+ <arg name="format" type="uint" summary="DRM_FORMAT code"/>
397+ <arg name="flags" type="uint" enum="flags" summary="see enum flags"/>
398+ </request>
399+
400+ <request name="set_sampling_device" since="6">
401+ <description summary="set the target device of the wl_buffer">
402+ Set the device the compositor should import the dmabufs to for sampling
403+ in the next create or create_immed request.
404+
405+ To avoid race conditions when the compositor removes a device from the
406+ tranches, it is not a protocol error if the device hasn't been advertised
407+ by the compositor in a tranche with the sampling flag, but the import is
408+ likely to fail in that case.
409+
410+ If the client doesn't know a suitable target device, it shouldn't set one,
411+ and the compositor should attempt import on all devices it supports.
412+
413+ If the array is too small to contain a dev_t or larger than required, the
414+ invalid_dev_t_size error will be emitted.
415+ </description>
416+ <arg name="device" type="array" summary="device dev_t value"/>
417+ </request>
418+ </interface>
419+
420+ <interface name="zwp_linux_dmabuf_feedback_v1" version="6">
421+ <description summary="dmabuf feedback">
422+ This object advertises dmabuf parameters feedback. This includes the
423+ preferred devices and the supported formats/modifiers.
424+
425+ The parameters are sent once when this object is created and whenever they
426+ change. The done event is always sent once after all parameters have been
427+ sent. When a single parameter changes, all parameters are re-sent by the
428+ compositor.
429+
430+ Compositors can re-send the parameters when the current client buffer
431+ allocations are sub-optimal. Compositors should not re-send the
432+ parameters if re-allocating the buffers would not result in a more optimal
433+ configuration. In particular, compositors should avoid sending the exact
434+ same parameters multiple times in a row.
435+
436+ The tranche_target_device and tranche_formats events are grouped by
437+ tranches of preference. For each tranche, a tranche_target_device, one
438+ tranche_flags and one or more tranche_formats events are sent, followed
439+ by a tranche_done event finishing the list. The tranches are sent in
440+ descending order of preference. All formats and modifiers in the same
441+ tranche have the same preference.
442+
443+ To send parameters, the compositor sends one main_device event (unless
444+ the client bound version 6 or above), tranches (each consisting of one
445+ tranche_target_device event, one tranche_flags event, tranche_formats
446+ events and then a tranche_done event), then one done event.
447+
448+ With version 6 and above, the compositor must always advertise at least
449+ one tranche with the sampling flag set.
450+ </description>
451+
452+ <request name="destroy" type="destructor">
453+ <description summary="destroy the feedback object">
454+ Using this request a client can tell the server that it is not going to
455+ use the zwp_linux_dmabuf_feedback_v1 object anymore.
456+ </description>
457+ </request>
458+
459+ <event name="done">
460+ <description summary="all feedback has been sent">
461+ This event is sent after all parameters of a zwp_linux_dmabuf_feedback_v1
462+ object have been sent.
463+
464+ This allows changes to the zwp_linux_dmabuf_feedback_v1 parameters to be
465+ seen as atomic, even if they happen via multiple events.
466+ </description>
467+ </event>
468+
469+ <event name="format_table">
470+ <description summary="format and modifier table">
471+ This event provides a file descriptor which can be memory-mapped to
472+ access the format and modifier table.
473+
474+ The table contains a tightly packed array of consecutive format +
475+ modifier pairs. Each pair is 16 bytes wide. It contains a format as a
476+ 32-bit unsigned integer, followed by 4 bytes of unused padding, and a
477+ modifier as a 64-bit unsigned integer. The native endianness is used.
478+
479+ The client must map the file descriptor in read-only private mode.
480+
481+ Compositors are not allowed to mutate the table file contents once this
482+ event has been sent. Instead, compositors must create a new, separate
483+ table file and re-send feedback parameters. Compositors are allowed to
484+ store duplicate format + modifier pairs in the table.
485+ </description>
486+ <arg name="fd" type="fd" summary="table file descriptor"/>
487+ <arg name="size" type="uint" summary="table size, in bytes"/>
488+ </event>
489+
490+ <event name="main_device" deprecated-since="6">
491+ <description summary="preferred main device">
492+ This event advertises the main device that the server prefers to use
493+ when direct scan-out to the target device isn't possible. The
494+ advertised main device may be different for each
495+ zwp_linux_dmabuf_feedback_v1 object, and may change over time.
496+
497+ There is exactly one main device. The compositor must send at least
498+ one preference tranche with tranche_target_device equal to main_device.
499+
500+ Clients need to create buffers that the main device can import and
501+ read from, otherwise creating the dmabuf wl_buffer will fail (see the
502+ zwp_linux_buffer_params_v1.create and create_immed requests for details).
503+ The main device will also likely be kept active by the compositor,
504+ so clients can use it instead of waking up another device for power
505+ savings.
506+
507+ In general the device is a DRM node. The DRM node type (primary vs.
508+ render) is unspecified. Clients must not rely on the compositor sending
509+ a particular node type. Clients cannot check two devices for equality
510+ by comparing the dev_t value.
511+
512+ If explicit modifiers are not supported and the client performs buffer
513+ allocations on a different device than the main device, then the client
514+ must force the buffer to have a linear layout.
515+
516+ With version 6 and above, this event is no longer sent. Clients should
517+ use a device with the sampling flag in the tranches instead.
518+ </description>
519+ <arg name="device" type="array" summary="device dev_t value"/>
520+ </event>
521+
522+ <event name="tranche_done">
523+ <description summary="a preference tranche has been sent">
524+ This event splits tranche_target_device and tranche_formats events into
525+ preference tranches. It is sent after a set of tranche_target_device
526+ and tranche_formats events; it represents the end of a tranche. The
527+ next tranche will have a lower preference.
528+ </description>
529+ </event>
530+
531+ <event name="tranche_target_device">
532+ <description summary="target device">
533+ This event advertises the target device that the server prefers to use
534+ for a buffer created given this tranche. The advertised target device
535+ may be different for each preference tranche, and may change over time.
536+
537+ There is exactly one target device per tranche.
538+
539+ The target device may be a scan-out device, for example if the
540+ compositor prefers to directly scan-out a buffer created given this
541+ tranche. The target device may be a rendering device, for example if
542+ the compositor prefers to texture from said buffer.
543+
544+ The client can use this hint to allocate the buffer in a way that makes
545+ it accessible from the target device, ideally directly. The buffer must
546+ still be accessible from a device with the sampling flag, either through
547+ direct import or a potentially more expensive fallback path. If the
548+ buffer can't be directly imported for sampling, then clients must be
549+ prepared for the compositor changing the tranche priority or making
550+ wl_buffer creation fail (see the zwp_linux_buffer_params_v1.create and
551+ create_immed requests for details).
552+
553+ If the device is a DRM node, the DRM node type (primary vs. render) is
554+ unspecified. Clients must not rely on the compositor sending a
555+ particular node type. Clients cannot check two devices for equality by
556+ comparing the dev_t value.
557+
558+ This event is tied to a preference tranche, see the tranche_done event.
559+ </description>
560+ <arg name="device" type="array" summary="device dev_t value"/>
561+ </event>
562+
563+ <event name="tranche_formats">
564+ <description summary="supported buffer format modifiers">
565+ This event advertises the format + modifier combinations that the
566+ compositor supports.
567+
568+ It carries an array of indices, each referring to a format + modifier
569+ pair in the last received format table (see the format_table event).
570+ Each index is a 16-bit unsigned integer in native endianness.
571+
572+ For legacy support, DRM_FORMAT_MOD_INVALID is an allowed modifier.
573+ It indicates that the server can support the format with an implicit
574+ modifier. When a buffer has DRM_FORMAT_MOD_INVALID as its modifier, it
575+ is as if no explicit modifier is specified. The effective modifier
576+ will be derived from the dmabuf.
577+
578+ A compositor that sends valid modifiers and DRM_FORMAT_MOD_INVALID for
579+ a given format supports both explicit modifiers and implicit modifiers.
580+
581+ Compositors must not send duplicate format + modifier pairs within the
582+ same tranche or across two different tranches with the same target
583+ device and flags.
584+
585+ This event is tied to a preference tranche, see the tranche_done event.
586+
587+ For the definition of the format and modifier codes, see the
588+ zwp_linux_buffer_params_v1.create request.
589+ </description>
590+ <arg name="indices" type="array" summary="array of 16-bit indexes"/>
591+ </event>
592+
593+ <enum name="tranche_flags" bitfield="true">
594+ <entry name="scanout" value="1" since="4">
595+ <description summary="direct scan-out tranche">
596+ The scanout flag is a hint that direct scan-out may be attempted by
597+ the compositor on the target device if the client appropriately
598+ allocates a buffer. How to allocate a buffer that can be scanned out
599+ on the target device is implementation-defined.
600+ </description>
601+ </entry>
602+ <entry name="sampling" value="2" since="6">
603+ <description summary="sampling tranche">
604+ The sampling flag describes that the compositor is able to efficiently
605+ sample from buffers imported to the target device if the client
606+ appropriately allocates a buffer. How to allocate a buffer that can be
607+ efficiently sampled on the target device is implementation defined.
608+ </description>
609+ </entry>
610+ </enum>
611+
612+ <event name="tranche_flags">
613+ <description summary="tranche flags">
614+ This event sets tranche-specific flags. This event is tied to a
615+ preference tranche, see the tranche_done event.
616+ With version 6 and above, the compositor must set at least one flag
617+ in each tranche.
618+ </description>
619+ <arg name="flags" type="uint" enum="tranche_flags" summary="tranche flags"/>
620+ </event>
621+ </interface>
622+
623+</protocol>
A protocol/linuxdmabuf/linux-dmabuf-v1_generated.go +650 -0
@@ -0,0 +1,650 @@
1+// Code generated by wlturbo-scanner. DO NOT EDIT.
2+// Protocol: linux_dmabuf_v1
3+// Source: linux-dmabuf-v1.xml
4+
5+package linuxdmabuf
6+
7+import (
8+ "sync"
9+
10+ cross_wl_buffer "github.com/bnema/wlturbo/protocol/core"
11+ cross_wl_surface "github.com/bnema/wlturbo/protocol/core"
12+ "github.com/bnema/wlturbo/wl"
13+)
14+
15+// ERROR_ALREADY_USED is the error already_used value.
16+const ERROR_ALREADY_USED = 0
17+
18+// ERROR_PLANE_IDX is the error plane_idx value.
19+const ERROR_PLANE_IDX = 1
20+
21+// ERROR_PLANE_SET is the error plane_set value.
22+const ERROR_PLANE_SET = 2
23+
24+// ERROR_INCOMPLETE is the error incomplete value.
25+const ERROR_INCOMPLETE = 3
26+
27+// ERROR_INVALID_FORMAT is the error invalid_format value.
28+const ERROR_INVALID_FORMAT = 4
29+
30+// ERROR_INVALID_DIMENSIONS is the error invalid_dimensions value.
31+const ERROR_INVALID_DIMENSIONS = 5
32+
33+// ERROR_OUT_OF_BOUNDS is the error out_of_bounds value.
34+const ERROR_OUT_OF_BOUNDS = 6
35+
36+// ERROR_INVALID_WL_BUFFER is the error invalid_wl_buffer value.
37+const ERROR_INVALID_WL_BUFFER = 7
38+
39+// ERROR_INVALID_DEV_T_SIZE is the error invalid_dev_t_size value.
40+const ERROR_INVALID_DEV_T_SIZE = 8
41+
42+// FLAGS_Y_INVERT is the flags y_invert value.
43+const FLAGS_Y_INVERT = 1
44+
45+// FLAGS_INTERLACED is the flags interlaced value.
46+const FLAGS_INTERLACED = 2
47+
48+// FLAGS_BOTTOM_FIRST is the flags bottom_first value.
49+const FLAGS_BOTTOM_FIRST = 4
50+
51+// TRANCHE_FLAGS_SCANOUT is the tranche_flags scanout value.
52+const TRANCHE_FLAGS_SCANOUT = 1
53+
54+// TRANCHE_FLAGS_SAMPLING is the tranche_flags sampling value.
55+const TRANCHE_FLAGS_SAMPLING = 2
56+
57+// LinuxDmabufInterface is the protocol interface name.
58+const LinuxDmabufInterface = "zwp_linux_dmabuf_v1"
59+
60+// LinuxDmabuf is the generated binding for zwp_linux_dmabuf_v1 version 6.
61+type LinuxDmabuf struct {
62+ wl.BaseProxy
63+ // handlersMu guards the handler slices: a client may register or replace
64+ // handlers while another goroutine dispatches events.
65+ handlersMu sync.Mutex
66+ onFormat []func(format uint32)
67+ onModifier []func(format uint32, modifierHi uint32, modifierLo uint32)
68+}
69+
70+// NewLinuxDmabuf returns an unbound LinuxDmabuf.
71+func NewLinuxDmabuf(ctx *wl.Context) *LinuxDmabuf {
72+ obj := &LinuxDmabuf{}
73+ obj.SetContext(ctx)
74+ ctx.Register(obj)
75+ return obj
76+}
77+
78+// Objects created through this interface, especially wl_buffers, will remain valid.
79+func (o *LinuxDmabuf) Destroy() error {
80+ if err := o.Context().CheckProxy(o); err != nil {
81+ return err
82+ }
83+ if err := o.Context().SendDestructor(o, 0); err != nil {
84+ return err
85+ }
86+ return nil
87+}
88+
89+// This temporary object is used to collect multiple dmabuf handles into a single batch to create a wl_buffer. It can only be used once and should be destroyed after a 'created' or 'failed' event has been received.
90+func (o *LinuxDmabuf) CreateParams() (*LinuxBufferParams, error) {
91+ if err := o.Context().CheckProxy(o); err != nil {
92+ return nil, err
93+ }
94+ child := &LinuxBufferParams{}
95+ child.SetContext(o.Context())
96+ child.SetID(o.Context().AllocateID())
97+ o.Context().Register(child)
98+ if err := o.Context().SendRequest(o, 1, child); err != nil {
99+ o.Context().Unregister(child)
100+ return nil, err
101+ }
102+ return child, nil
103+}
104+
105+// This request creates a new zwp_linux_dmabuf_feedback_v1 object not bound to a particular surface. This object will deliver feedback about dmabuf parameters to use if the client doesn't support per-surface feedback (see get_surface_feedback).
106+func (o *LinuxDmabuf) GetDefaultFeedback() (*LinuxDmabufFeedback, error) {
107+ if err := o.Context().CheckProxy(o); err != nil {
108+ return nil, err
109+ }
110+ child := &LinuxDmabufFeedback{}
111+ child.SetContext(o.Context())
112+ child.SetID(o.Context().AllocateID())
113+ o.Context().Register(child)
114+ if err := o.Context().SendRequest(o, 2, child); err != nil {
115+ o.Context().Unregister(child)
116+ return nil, err
117+ }
118+ return child, nil
119+}
120+
121+// This request creates a new zwp_linux_dmabuf_feedback_v1 object for the specified wl_surface. This object will deliver feedback about dmabuf parameters to use for buffers attached to this surface. If the surface is destroyed before the zwp_linux_dmabuf_feedback_v1 object, the feedback object becomes inert.
122+func (o *LinuxDmabuf) GetSurfaceFeedback(surface *cross_wl_surface.Surface) (*LinuxDmabufFeedback, error) {
123+ if err := o.Context().CheckProxy(o); err != nil {
124+ return nil, err
125+ }
126+ var arg1 wl.Object
127+ if surface != nil {
128+ arg1 = surface
129+ }
130+ child := &LinuxDmabufFeedback{}
131+ child.SetContext(o.Context())
132+ child.SetID(o.Context().AllocateID())
133+ o.Context().Register(child)
134+ if err := o.Context().SendRequest(o, 3, child, arg1); err != nil {
135+ o.Context().Unregister(child)
136+ return nil, err
137+ }
138+ return child, nil
139+}
140+
141+// OnFormat registers a handler for the format event.
142+//
143+// Handlers are appended, so a second call adds another handler rather than
144+// replacing the first. Registration is safe while another goroutine dispatches.
145+func (o *LinuxDmabuf) OnFormat(handler func(format uint32)) {
146+ if handler == nil {
147+ return
148+ }
149+ o.handlersMu.Lock()
150+ defer o.handlersMu.Unlock()
151+ o.onFormat = append(o.onFormat, handler)
152+}
153+
154+// handlersForFormat returns the handlers registered for format, taken
155+// under the lock so a handler may register another handler while events are
156+// being dispatched.
157+func (o *LinuxDmabuf) handlersForFormat() []func(format uint32) {
158+ o.handlersMu.Lock()
159+ defer o.handlersMu.Unlock()
160+ return o.onFormat
161+}
162+
163+// OnModifier registers a handler for the modifier event.
164+//
165+// Handlers are appended, so a second call adds another handler rather than
166+// replacing the first. Registration is safe while another goroutine dispatches.
167+func (o *LinuxDmabuf) OnModifier(handler func(format uint32, modifierHi uint32, modifierLo uint32)) {
168+ if handler == nil {
169+ return
170+ }
171+ o.handlersMu.Lock()
172+ defer o.handlersMu.Unlock()
173+ o.onModifier = append(o.onModifier, handler)
174+}
175+
176+// handlersForModifier returns the handlers registered for modifier, taken
177+// under the lock so a handler may register another handler while events are
178+// being dispatched.
179+func (o *LinuxDmabuf) handlersForModifier() []func(format uint32, modifierHi uint32, modifierLo uint32) {
180+ o.handlersMu.Lock()
181+ defer o.handlersMu.Unlock()
182+ return o.onModifier
183+}
184+
185+// EventSignature returns the declared event argument types in wire order.
186+func (o *LinuxDmabuf) EventSignature(opcode uint16) (string, bool) {
187+ switch opcode {
188+ case 0:
189+ return "uint,", true
190+ case 1:
191+ return "uint,uint,uint,", true
192+ default:
193+ return "", false
194+ }
195+}
196+
197+// Dispatch decodes one event on zwp_linux_dmabuf_v1 and calls the registered handlers.
198+func (o *LinuxDmabuf) Dispatch(event *wl.Event) {
199+ switch event.Opcode {
200+ case 0: // format
201+ format := event.Uint32()
202+
203+ for i, handler := range o.handlersForFormat() {
204+ _ = i
205+ handler(format)
206+ }
207+ case 1: // modifier
208+ format := event.Uint32()
209+ modifierHi := event.Uint32()
210+ modifierLo := event.Uint32()
211+
212+ for i, handler := range o.handlersForModifier() {
213+ _ = i
214+ handler(format, modifierHi, modifierLo)
215+ }
216+ default:
217+ }
218+}
219+
220+// LinuxBufferParamsInterface is the protocol interface name.
221+const LinuxBufferParamsInterface = "zwp_linux_buffer_params_v1"
222+
223+// LinuxBufferParams is the generated binding for zwp_linux_buffer_params_v1 version 6.
224+type LinuxBufferParams struct {
225+ wl.BaseProxy
226+ // handlersMu guards the handler slices: a client may register or replace
227+ // handlers while another goroutine dispatches events.
228+ handlersMu sync.Mutex
229+ onCreated []func(bufferObject *cross_wl_buffer.Buffer)
230+ onFailed []func()
231+}
232+
233+// NewLinuxBufferParams returns an unbound LinuxBufferParams.
234+func NewLinuxBufferParams(ctx *wl.Context) *LinuxBufferParams {
235+ obj := &LinuxBufferParams{}
236+ obj.SetContext(ctx)
237+ ctx.Register(obj)
238+ return obj
239+}
240+
241+// Cleans up the temporary data sent to the server for dmabuf-based wl_buffer creation.
242+func (o *LinuxBufferParams) Destroy() error {
243+ if err := o.Context().CheckProxy(o); err != nil {
244+ return err
245+ }
246+ if err := o.Context().SendDestructor(o, 0); err != nil {
247+ return err
248+ }
249+ return nil
250+}
251+
252+// 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.
253+func (o *LinuxBufferParams) Add(fd int, planeIdx uint32, offset uint32, stride uint32, modifierHi uint32, modifierLo uint32) error {
254+ if err := o.Context().CheckProxy(o); err != nil {
255+ return err
256+ }
257+ if err := o.Context().SendRequestWithFDs(o, 1, []int{fd}, uintptr(fd), planeIdx, offset, stride, modifierHi, modifierLo); err != nil {
258+ return err
259+ }
260+ _ = wl.CloseSentFD(fd)
261+ return nil
262+}
263+
264+// 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.
265+func (o *LinuxBufferParams) Create(width int32, height int32, format uint32, flags uint32) error {
266+ if err := o.Context().CheckProxy(o); err != nil {
267+ return err
268+ }
269+ if err := o.Context().SendRequest(o, 2, width, height, format, flags); err != nil {
270+ return err
271+ }
272+ return nil
273+}
274+
275+// 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.
276+func (o *LinuxBufferParams) CreateImmed(width int32, height int32, format uint32, flags uint32) (*cross_wl_buffer.Buffer, error) {
277+ if err := o.Context().CheckProxy(o); err != nil {
278+ return nil, err
279+ }
280+ child := cross_wl_buffer.NewBuffer(o.Context())
281+ child.SetID(o.Context().AllocateID())
282+ o.Context().Register(child)
283+ if err := o.Context().SendRequest(o, 3, child, width, height, format, flags); err != nil {
284+ o.Context().Unregister(child)
285+ return nil, err
286+ }
287+ return child, nil
288+}
289+
290+// 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.
291+func (o *LinuxBufferParams) SetSamplingDevice(device []byte) error {
292+ if err := o.Context().CheckProxy(o); err != nil {
293+ return err
294+ }
295+ if err := o.Context().SendRequest(o, 4, device); err != nil {
296+ return err
297+ }
298+ return nil
299+}
300+
301+// OnCreated registers a handler for the created event.
302+//
303+// Handlers are appended, so a second call adds another handler rather than
304+// replacing the first. Registration is safe while another goroutine dispatches.
305+func (o *LinuxBufferParams) OnCreated(handler func(bufferObject *cross_wl_buffer.Buffer)) {
306+ if handler == nil {
307+ return
308+ }
309+ o.handlersMu.Lock()
310+ defer o.handlersMu.Unlock()
311+ o.onCreated = append(o.onCreated, handler)
312+}
313+
314+// handlersForCreated returns the handlers registered for created, taken
315+// under the lock so a handler may register another handler while events are
316+// being dispatched.
317+func (o *LinuxBufferParams) handlersForCreated() []func(bufferObject *cross_wl_buffer.Buffer) {
318+ o.handlersMu.Lock()
319+ defer o.handlersMu.Unlock()
320+ return o.onCreated
321+}
322+
323+// OnFailed registers a handler for the failed event.
324+//
325+// Handlers are appended, so a second call adds another handler rather than
326+// replacing the first. Registration is safe while another goroutine dispatches.
327+func (o *LinuxBufferParams) OnFailed(handler func()) {
328+ if handler == nil {
329+ return
330+ }
331+ o.handlersMu.Lock()
332+ defer o.handlersMu.Unlock()
333+ o.onFailed = append(o.onFailed, handler)
334+}
335+
336+// handlersForFailed returns the handlers registered for failed, taken
337+// under the lock so a handler may register another handler while events are
338+// being dispatched.
339+func (o *LinuxBufferParams) handlersForFailed() []func() {
340+ o.handlersMu.Lock()
341+ defer o.handlersMu.Unlock()
342+ return o.onFailed
343+}
344+
345+// EventSignature returns the declared event argument types in wire order.
346+func (o *LinuxBufferParams) EventSignature(opcode uint16) (string, bool) {
347+ switch opcode {
348+ case 0:
349+ return "new_id,", true
350+ case 1:
351+ return "", true
352+ default:
353+ return "", false
354+ }
355+}
356+
357+// Dispatch decodes one event on zwp_linux_buffer_params_v1 and calls the registered handlers.
358+func (o *LinuxBufferParams) Dispatch(event *wl.Event) {
359+ switch event.Opcode {
360+ case 0: // created
361+ bufferID := event.Uint32()
362+ bufferObject := cross_wl_buffer.NewBuffer(o.Context())
363+ bufferObject.SetID(bufferID)
364+ o.Context().Register(bufferObject)
365+
366+ for i, handler := range o.handlersForCreated() {
367+ _ = i
368+ handler(bufferObject)
369+ }
370+ case 1: // failed
371+
372+ for i, handler := range o.handlersForFailed() {
373+ _ = i
374+ handler()
375+ }
376+ default:
377+ }
378+}
379+
380+// LinuxDmabufFeedbackInterface is the protocol interface name.
381+const LinuxDmabufFeedbackInterface = "zwp_linux_dmabuf_feedback_v1"
382+
383+// LinuxDmabufFeedback is the generated binding for zwp_linux_dmabuf_feedback_v1 version 6.
384+type LinuxDmabufFeedback struct {
385+ wl.BaseProxy
386+ // handlersMu guards the handler slices: a client may register or replace
387+ // handlers while another goroutine dispatches events.
388+ handlersMu sync.Mutex
389+ onDone []func()
390+ onFormatTable []func(fd *wl.OwnedFD, size uint32)
391+ onMainDevice []func(device []byte)
392+ onTrancheDone []func()
393+ onTrancheTargetDevice []func(device []byte)
394+ onTrancheFormats []func(indices []byte)
395+ onTrancheFlags []func(flags uint32)
396+}
397+
398+// NewLinuxDmabufFeedback returns an unbound LinuxDmabufFeedback.
399+func NewLinuxDmabufFeedback(ctx *wl.Context) *LinuxDmabufFeedback {
400+ obj := &LinuxDmabufFeedback{}
401+ obj.SetContext(ctx)
402+ ctx.Register(obj)
403+ return obj
404+}
405+
406+// Using this request a client can tell the server that it is not going to use the zwp_linux_dmabuf_feedback_v1 object anymore.
407+func (o *LinuxDmabufFeedback) Destroy() error {
408+ if err := o.Context().CheckProxy(o); err != nil {
409+ return err
410+ }
411+ if err := o.Context().SendDestructor(o, 0); err != nil {
412+ return err
413+ }
414+ return nil
415+}
416+
417+// OnDone registers a handler for the done 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 *LinuxDmabufFeedback) OnDone(handler func()) {
422+ if handler == nil {
423+ return
424+ }
425+ o.handlersMu.Lock()
426+ defer o.handlersMu.Unlock()
427+ o.onDone = append(o.onDone, handler)
428+}
429+
430+// handlersForDone returns the handlers registered for done, taken
431+// under the lock so a handler may register another handler while events are
432+// being dispatched.
433+func (o *LinuxDmabufFeedback) handlersForDone() []func() {
434+ o.handlersMu.Lock()
435+ defer o.handlersMu.Unlock()
436+ return o.onDone
437+}
438+
439+// OnFormatTable registers a handler for the format_table 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 *LinuxDmabufFeedback) OnFormatTable(handler func(fd *wl.OwnedFD, size uint32)) {
444+ if handler == nil {
445+ return
446+ }
447+ o.handlersMu.Lock()
448+ defer o.handlersMu.Unlock()
449+ o.onFormatTable = append(o.onFormatTable, handler)
450+}
451+
452+// handlersForFormatTable returns the handlers registered for format_table, taken
453+// under the lock so a handler may register another handler while events are
454+// being dispatched.
455+func (o *LinuxDmabufFeedback) handlersForFormatTable() []func(fd *wl.OwnedFD, size uint32) {
456+ o.handlersMu.Lock()
457+ defer o.handlersMu.Unlock()
458+ return o.onFormatTable
459+}
460+
461+// OnMainDevice registers a handler for the main_device 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 *LinuxDmabufFeedback) OnMainDevice(handler func(device []byte)) {
466+ if handler == nil {
467+ return
468+ }
469+ o.handlersMu.Lock()
470+ defer o.handlersMu.Unlock()
471+ o.onMainDevice = append(o.onMainDevice, handler)
472+}
473+
474+// handlersForMainDevice returns the handlers registered for main_device, taken
475+// under the lock so a handler may register another handler while events are
476+// being dispatched.
477+func (o *LinuxDmabufFeedback) handlersForMainDevice() []func(device []byte) {
478+ o.handlersMu.Lock()
479+ defer o.handlersMu.Unlock()
480+ return o.onMainDevice
481+}
482+
483+// OnTrancheDone registers a handler for the tranche_done event.
484+//
485+// Handlers are appended, so a second call adds another handler rather than
486+// replacing the first. Registration is safe while another goroutine dispatches.
487+func (o *LinuxDmabufFeedback) OnTrancheDone(handler func()) {
488+ if handler == nil {
489+ return
490+ }
491+ o.handlersMu.Lock()
492+ defer o.handlersMu.Unlock()
493+ o.onTrancheDone = append(o.onTrancheDone, handler)
494+}
495+
496+// handlersForTrancheDone returns the handlers registered for tranche_done, taken
497+// under the lock so a handler may register another handler while events are
498+// being dispatched.
499+func (o *LinuxDmabufFeedback) handlersForTrancheDone() []func() {
500+ o.handlersMu.Lock()
501+ defer o.handlersMu.Unlock()
502+ return o.onTrancheDone
503+}
504+
505+// OnTrancheTargetDevice registers a handler for the tranche_target_device event.
506+//
507+// Handlers are appended, so a second call adds another handler rather than
508+// replacing the first. Registration is safe while another goroutine dispatches.
509+func (o *LinuxDmabufFeedback) OnTrancheTargetDevice(handler func(device []byte)) {
510+ if handler == nil {
511+ return
512+ }
513+ o.handlersMu.Lock()
514+ defer o.handlersMu.Unlock()
515+ o.onTrancheTargetDevice = append(o.onTrancheTargetDevice, handler)
516+}
517+
518+// handlersForTrancheTargetDevice returns the handlers registered for tranche_target_device, taken
519+// under the lock so a handler may register another handler while events are
520+// being dispatched.
521+func (o *LinuxDmabufFeedback) handlersForTrancheTargetDevice() []func(device []byte) {
522+ o.handlersMu.Lock()
523+ defer o.handlersMu.Unlock()
524+ return o.onTrancheTargetDevice
525+}
526+
527+// OnTrancheFormats registers a handler for the tranche_formats event.
528+//
529+// Handlers are appended, so a second call adds another handler rather than
530+// replacing the first. Registration is safe while another goroutine dispatches.
531+func (o *LinuxDmabufFeedback) OnTrancheFormats(handler func(indices []byte)) {
532+ if handler == nil {
533+ return
534+ }
535+ o.handlersMu.Lock()
536+ defer o.handlersMu.Unlock()
537+ o.onTrancheFormats = append(o.onTrancheFormats, handler)
538+}
539+
540+// handlersForTrancheFormats returns the handlers registered for tranche_formats, taken
541+// under the lock so a handler may register another handler while events are
542+// being dispatched.
543+func (o *LinuxDmabufFeedback) handlersForTrancheFormats() []func(indices []byte) {
544+ o.handlersMu.Lock()
545+ defer o.handlersMu.Unlock()
546+ return o.onTrancheFormats
547+}
548+
549+// OnTrancheFlags registers a handler for the tranche_flags event.
550+//
551+// Handlers are appended, so a second call adds another handler rather than
552+// replacing the first. Registration is safe while another goroutine dispatches.
553+func (o *LinuxDmabufFeedback) OnTrancheFlags(handler func(flags uint32)) {
554+ if handler == nil {
555+ return
556+ }
557+ o.handlersMu.Lock()
558+ defer o.handlersMu.Unlock()
559+ o.onTrancheFlags = append(o.onTrancheFlags, handler)
560+}
561+
562+// handlersForTrancheFlags returns the handlers registered for tranche_flags, taken
563+// under the lock so a handler may register another handler while events are
564+// being dispatched.
565+func (o *LinuxDmabufFeedback) handlersForTrancheFlags() []func(flags uint32) {
566+ o.handlersMu.Lock()
567+ defer o.handlersMu.Unlock()
568+ return o.onTrancheFlags
569+}
570+
571+// EventSignature returns the declared event argument types in wire order.
572+func (o *LinuxDmabufFeedback) EventSignature(opcode uint16) (string, bool) {
573+ switch opcode {
574+ case 0:
575+ return "", true
576+ case 1:
577+ return "fd,uint,", true
578+ case 2:
579+ return "array,", true
580+ case 3:
581+ return "", true
582+ case 4:
583+ return "array,", true
584+ case 5:
585+ return "array,", true
586+ case 6:
587+ return "uint,", true
588+ default:
589+ return "", false
590+ }
591+}
592+
593+// Dispatch decodes one event on zwp_linux_dmabuf_feedback_v1 and calls the registered handlers.
594+func (o *LinuxDmabufFeedback) Dispatch(event *wl.Event) {
595+ switch event.Opcode {
596+ case 0: // done
597+
598+ for i, handler := range o.handlersForDone() {
599+ _ = i
600+ handler()
601+ }
602+ case 1: // format_table
603+ fd := event.FD()
604+ size := event.Uint32()
605+ ownedfd := fd
606+ defer ownedfd.Close()
607+
608+ for i, handler := range o.handlersForFormatTable() {
609+ if i > 0 {
610+ fd = nil
611+ }
612+ handler(fd, size)
613+ }
614+ case 2: // main_device
615+ device := event.Array()
616+
617+ for i, handler := range o.handlersForMainDevice() {
618+ _ = i
619+ handler(device)
620+ }
621+ case 3: // tranche_done
622+
623+ for i, handler := range o.handlersForTrancheDone() {
624+ _ = i
625+ handler()
626+ }
627+ case 4: // tranche_target_device
628+ device := event.Array()
629+
630+ for i, handler := range o.handlersForTrancheTargetDevice() {
631+ _ = i
632+ handler(device)
633+ }
634+ case 5: // tranche_formats
635+ indices := event.Array()
636+
637+ for i, handler := range o.handlersForTrancheFormats() {
638+ _ = i
639+ handler(indices)
640+ }
641+ case 6: // tranche_flags
642+ flags := event.Uint32()
643+
644+ for i, handler := range o.handlersForTrancheFlags() {
645+ _ = i
646+ handler(flags)
647+ }
648+ default:
649+ }
650+}
A protocol/linuxdmabuf/table.go +68 -0
@@ -0,0 +1,68 @@
1+package linuxdmabuf
2+
3+import (
4+ "encoding/binary"
5+ "fmt"
6+ "io"
7+
8+ "github.com/bnema/wlturbo/wl"
9+ "golang.org/x/sys/unix"
10+)
11+
12+// FormatEntry is one 16-byte format-table record. Padding is ignored.
13+type FormatEntry struct {
14+ Format uint32
15+ Modifier uint64
16+}
17+
18+// ReadFormatTable consumes an owned format_table descriptor, even on error.
19+// It reads a bounded snapshot with pread rather than mapping compositor-owned
20+// memory, avoiding SIGBUS if the backing file is unexpectedly truncated.
21+func ReadFormatTable(fd *wl.OwnedFD, size uint32) ([]FormatEntry, error) {
22+ if fd == nil {
23+ return nil, fmt.Errorf("missing format table descriptor")
24+ }
25+ n, err := fd.Take()
26+ if err != nil {
27+ return nil, err
28+ }
29+ defer unix.Close(n)
30+ if size%16 != 0 || size > 16<<20 {
31+ return nil, fmt.Errorf("invalid format table size %d", size)
32+ }
33+ b := make([]byte, size)
34+ for off := 0; off < len(b); {
35+ read, e := unix.Pread(n, b[off:], int64(off))
36+ off += read
37+ if e == unix.EINTR {
38+ continue
39+ }
40+ if e != nil {
41+ return nil, e
42+ }
43+ if read == 0 {
44+ return nil, io.ErrUnexpectedEOF
45+ }
46+ }
47+ entries := make([]FormatEntry, size/16)
48+ for i := range entries {
49+ off := i * 16
50+ entries[i] = FormatEntry{binary.NativeEndian.Uint32(b[off:]), binary.NativeEndian.Uint64(b[off+8:])}
51+ }
52+ return entries, nil
53+}
54+
55+// TrancheIndices decodes the uint16 indices into a format table.
56+func TrancheIndices(data []byte, count int) ([]uint16, error) {
57+ if len(data)%2 != 0 {
58+ return nil, fmt.Errorf("odd tranche indices length")
59+ }
60+ indices := make([]uint16, len(data)/2)
61+ for i := range indices {
62+ indices[i] = binary.NativeEndian.Uint16(data[i*2:])
63+ if int(indices[i]) >= count {
64+ return nil, fmt.Errorf("format table index %d out of range", indices[i])
65+ }
66+ }
67+ return indices, nil
68+}
A protocol/linuxdmabuf/table_test.go +28 -0
@@ -0,0 +1,28 @@
1+//go:build linux
2+
3+package linuxdmabuf_test
4+
5+import (
6+ "encoding/binary"
7+ "github.com/bnema/wlturbo/protocol/linuxdmabuf"
8+ "testing"
9+)
10+
11+func TestTrancheIndices(t *testing.T) {
12+ b := make([]byte, 4)
13+ binary.NativeEndian.PutUint16(b, 1)
14+ binary.NativeEndian.PutUint16(b[2:], 0)
15+ got, e := linuxdmabuf.TrancheIndices(b, 2)
16+ if e != nil || len(got) != 2 || got[0] != 1 || got[1] != 0 {
17+ t.Fatalf("indices %v %v", got, e)
18+ }
19+ if _, e = linuxdmabuf.TrancheIndices(b, 1); e == nil {
20+ t.Fatal("out of range accepted")
21+ }
22+ if _, e = linuxdmabuf.TrancheIndices(b[:3], 2); e == nil {
23+ t.Fatal("odd length accepted")
24+ }
25+ if _, e = linuxdmabuf.ReadFormatTable(nil, 0); e == nil {
26+ t.Fatal("missing fd accepted")
27+ }
28+}
A protocol/negotiation_test.go +50 -0
@@ -0,0 +1,50 @@
1+//go:build linux
2+
3+package protocol_test
4+
5+import (
6+ "encoding/binary"
7+ "errors"
8+ "testing"
9+
10+ "github.com/bnema/wlturbo"
11+ "github.com/bnema/wlturbo/protocol/xdgshell"
12+)
13+
14+func TestAnnouncedVersionNegotiation(t *testing.T) {
15+ c, p := pair(t)
16+ d, e := wlturbo.ConnectFromConn(c)
17+ noerr(t, e)
18+ defer d.Close()
19+ request(t, p)
20+ iface := xdgshell.XdgWmBaseInterface
21+ if v, e := d.Registry().BindNegotiated(iface, 6, xdgshell.NewXdgWmBase(d.Context())); v != 0 || !errors.Is(e, wlturbo.ErrGlobalNotFound) {
22+ t.Fatalf("missing: %d %v", v, e)
23+ }
24+ if v, e := d.Registry().BindNegotiated(iface, 0, xdgshell.NewXdgWmBase(d.Context())); v != 0 || e == nil || errors.Is(e, wlturbo.ErrGlobalNotFound) {
25+ t.Fatalf("unsupported zero: %d %v", v, e)
26+ }
27+ for i, version := range []uint32{2, 9} {
28+ name := uint32(30 + i)
29+ announcement := append(msg(0, 0, name)[8:], str(iface)...)
30+ announcement = append(announcement, msg(0, 0, version)[8:]...)
31+ send(t, p, payload(d.Registry().ID(), 0, announcement...))
32+ noerr(t, d.Dispatch())
33+ proxy := xdgshell.NewXdgWmBase(d.Context())
34+ if v, e := d.Registry().BindNegotiated(iface, 0, proxy); v != 0 || e == nil || errors.Is(e, wlturbo.ErrGlobalNotFound) {
35+ t.Fatalf("supported zero with global: %d %v", v, e)
36+ }
37+ negotiated, e := d.Registry().BindNegotiated(iface, 6, proxy)
38+ noerr(t, e)
39+ want := version
40+ if want > 6 {
41+ want = 6
42+ }
43+ _, op, body := request(t, p)
44+ if op != 0 || negotiated != want || binary.NativeEndian.Uint32(body) != name || binary.NativeEndian.Uint32(body[len(body)-8:]) != want || binary.NativeEndian.Uint32(body[len(body)-4:]) != proxy.ID() {
45+ t.Fatalf("server=%d negotiated=%d wire=%x", version, negotiated, body)
46+ }
47+ send(t, p, msg(d.Registry().ID(), 1, name))
48+ noerr(t, d.Dispatch())
49+ }
50+}
A protocol/textinput/text-input-unstable-v3.xml +604 -0
@@ -0,0 +1,604 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+
3+<protocol name="text_input_unstable_v3">
4+ <copyright>
5+ Copyright © 2012, 2013 Intel Corporation
6+ Copyright © 2015, 2016 Jan Arne Petersen
7+ Copyright © 2017, 2018 Red Hat, Inc.
8+ Copyright © 2018 Purism SPC
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+ </copyright>
31+
32+ <description summary="Protocol for composing text">
33+ This protocol allows compositors to act as input methods and to send text
34+ to applications. A text input object is used to manage state of what are
35+ typically text entry fields in the application.
36+
37+ This document adheres to the RFC 2119 when using words like "must",
38+ "should", "may", etc.
39+
40+ Warning! The protocol described in this file is experimental and
41+ backward incompatible changes may be made. Backward compatible changes
42+ may be added together with the corresponding interface version bump.
43+ Backward incompatible changes are done by bumping the version number in
44+ the protocol and interface names and resetting the interface version.
45+ Once the protocol is to be declared stable, the 'z' prefix and the
46+ version number in the protocol and interface names are removed and the
47+ interface version number is reset.
48+ </description>
49+
50+ <interface name="zwp_text_input_v3" version="2">
51+ <description summary="text input">
52+ The zwp_text_input_v3 interface represents text input and input methods
53+ associated with a seat. It provides enter/leave events to follow the
54+ text input focus for a seat.
55+
56+ Requests are used to enable/disable the text-input object and set
57+ state information like surrounding and selected text or the content type.
58+ The information about the entered text is sent to the text-input object
59+ via the preedit_string and commit_string events.
60+
61+ Text is valid UTF-8 encoded, indices and lengths are in bytes. Indices
62+ must not point to middle bytes inside a code point: they must either
63+ point to the first byte of a code point or to the end of the buffer.
64+ Lengths must be measured between two valid indices.
65+
66+ Focus moving throughout surfaces will result in the emission of
67+ zwp_text_input_v3.enter and zwp_text_input_v3.leave events. The focused
68+ surface must commit zwp_text_input_v3.enable and
69+ zwp_text_input_v3.disable requests as the keyboard focus moves across
70+ editable and non-editable elements of the UI. Those two requests are not
71+ expected to be paired with each other, the compositor must be able to
72+ handle consecutive series of the same request.
73+
74+ State is sent by the state requests (set_surrounding_text,
75+ set_content_type and set_cursor_rectangle) and a commit request. After an
76+ enter event or disable request all state information is invalidated and
77+ needs to be resent by the client.
78+ </description>
79+
80+ <request name="destroy" type="destructor">
81+ <description summary="Destroy the wp_text_input">
82+ Destroy the wp_text_input object. Also disables all surfaces enabled
83+ through this wp_text_input object.
84+ </description>
85+ </request>
86+
87+ <request name="enable">
88+ <description summary="Request text input to be enabled">
89+ Requests text input on the surface previously obtained from the enter
90+ event.
91+
92+ This request must be issued every time the focused text input changes
93+ to a new one, including within the current surface. Use
94+ zwp_text_input_v3.disable when there is no longer any input focus on
95+ the current surface.
96+
97+ Clients must not enable more than one text input on the single seat
98+ and should disable the current text input before enabling the new one.
99+ Requests to enable a text input when another text input is enabled
100+ on the same seat must be ignored by compositor.
101+
102+ This request resets all state associated with previous enable, disable,
103+ set_surrounding_text, set_text_change_cause, set_content_type, and
104+ set_cursor_rectangle requests, as well as the state associated with
105+ preedit_string, commit_string, and delete_surrounding_text events.
106+
107+ The set_surrounding_text, set_content_type and set_cursor_rectangle
108+ requests must follow if the text input supports the necessary
109+ functionality.
110+
111+ State set with this request is double-buffered. It will get applied on
112+ the next zwp_text_input_v3.commit request, and stay valid until the
113+ next committed enable or disable request.
114+
115+ The changes must be applied by the compositor after issuing a
116+ zwp_text_input_v3.commit request.
117+ </description>
118+ </request>
119+
120+ <request name="disable">
121+ <description summary="Disable text input on a surface">
122+ Explicitly disable text input on the current surface (typically when
123+ there is no focus on any text entry inside the surface).
124+
125+ State set with this request is double-buffered. It will get applied on
126+ the next zwp_text_input_v3.commit request.
127+ </description>
128+ </request>
129+
130+ <request name="set_surrounding_text">
131+ <description summary="sets the surrounding text">
132+ Sets the surrounding plain text around the input, excluding the preedit
133+ text.
134+
135+ The client should notify the compositor of any changes in any of the
136+ values carried with this request, including changes caused by handling
137+ incoming text-input events as well as changes caused by other
138+ mechanisms like keyboard typing.
139+
140+ If the client is unaware of the text around the cursor, it should not
141+ issue this request, to signify lack of support to the compositor.
142+
143+ Text is UTF-8 encoded, and should include the cursor position, the
144+ complete selection and additional characters before and after them.
145+ There is a maximum length of wayland messages, so text can not be
146+ longer than 4000 bytes.
147+
148+ Cursor is the byte offset of the cursor within text buffer.
149+
150+ Anchor is the byte offset of the selection anchor within text buffer.
151+ If there is no selected text, anchor is the same as cursor.
152+
153+ If any preedit text is present, it is replaced with a cursor for the
154+ purpose of this event.
155+
156+ Values set with this request are double-buffered. They will get applied
157+ on the next zwp_text_input_v3.commit request, and stay valid until the
158+ next committed enable or disable request.
159+
160+ The initial state for affected fields is empty, meaning that the text
161+ input does not support sending surrounding text. If the empty values
162+ get applied, subsequent attempts to change them may have no effect.
163+ </description>
164+ <arg name="text" type="string"/>
165+ <arg name="cursor" type="int"/>
166+ <arg name="anchor" type="int"/>
167+ </request>
168+
169+ <enum name="change_cause">
170+ <description summary="text change reason">
171+ Reason for the change of surrounding text or cursor posision.
172+ </description>
173+ <entry name="input_method" value="0" summary="input method caused the change"/>
174+ <entry name="other" value="1" summary="something else than the input method caused the change"/>
175+ </enum>
176+
177+ <request name="set_text_change_cause">
178+ <description summary="indicates the cause of surrounding text change">
179+ Tells the compositor why the text surrounding the cursor changed.
180+
181+ Whenever the client detects an external change in text, cursor, or
182+ anchor posision, it must issue this request to the compositor. This
183+ request is intended to give the input method a chance to update the
184+ preedit text in an appropriate way, e.g. by removing it when the user
185+ starts typing with a keyboard.
186+
187+ cause describes the source of the change.
188+
189+ The value set with this request is double-buffered. It must be applied
190+ and reset to initial at the next zwp_text_input_v3.commit request.
191+
192+ The initial value of cause is input_method.
193+ </description>
194+ <arg name="cause" type="uint" enum="change_cause"/>
195+ </request>
196+
197+ <enum name="content_hint" bitfield="true">
198+ <description summary="content hint">
199+ Content hint is a bitmask to allow to modify the behavior of the text
200+ input.
201+ </description>
202+ <entry name="none" value="0x0" summary="no special behavior"/>
203+ <entry name="completion" value="0x1" summary="suggest word completions"/>
204+ <entry name="spellcheck" value="0x2" summary="suggest word corrections"/>
205+ <entry name="auto_capitalization" value="0x4" summary="switch to uppercase letters at the start of a sentence"/>
206+ <entry name="lowercase" value="0x8" summary="prefer lowercase letters"/>
207+ <entry name="uppercase" value="0x10" summary="prefer uppercase letters"/>
208+ <entry name="titlecase" value="0x20" summary="prefer casing for titles and headings (can be language dependent)"/>
209+ <entry name="hidden_text" value="0x40" summary="characters should be hidden"/>
210+ <entry name="sensitive_data" value="0x80" summary="typed text should not be stored"/>
211+ <entry name="latin" value="0x100" summary="just Latin characters should be entered"/>
212+ <entry name="multiline" value="0x200" summary="the text input is multiline"/>
213+ <entry
214+ name="on_screen_input_provided" value="0x400" since="2"
215+ summary="an on-screen way to fill in the input is already provided by the client"/>
216+ <entry
217+ name="no_emoji" value="0x800" since="2"
218+ summary="prefer not offering emoji support"/>
219+ <entry
220+ name="preedit_shown" value="0x1000" since="2"
221+ summary="the text input will display preedit text in place"/>
222+ </enum>
223+
224+ <enum name="content_purpose">
225+ <description summary="content purpose">
226+ The content purpose allows to specify the primary purpose of a text
227+ input.
228+
229+ This allows an input method to show special purpose input panels with
230+ extra characters or to disallow some characters.
231+ </description>
232+ <entry name="normal" value="0" summary="default input, allowing all characters"/>
233+ <entry name="alpha" value="1" summary="allow only alphabetic characters"/>
234+ <entry name="digits" value="2" summary="allow only digits"/>
235+ <entry name="number" value="3" summary="input a number (including decimal separator and sign)"/>
236+ <entry name="phone" value="4" summary="input a phone number"/>
237+ <entry name="url" value="5" summary="input an URL"/>
238+ <entry name="email" value="6" summary="input an email address"/>
239+ <entry name="name" value="7" summary="input a name of a person"/>
240+ <entry name="password" value="8" summary="input a password (combine with sensitive_data hint)"/>
241+ <entry name="pin" value="9" summary="input is a numeric password (combine with sensitive_data hint)"/>
242+ <entry name="date" value="10" summary="input a date"/>
243+ <entry name="time" value="11" summary="input a time"/>
244+ <entry name="datetime" value="12" summary="input a date and time"/>
245+ <entry name="terminal" value="13" summary="input for a terminal"/>
246+ </enum>
247+
248+ <request name="set_content_type">
249+ <description summary="set content purpose and hint">
250+ Sets the content purpose and content hint. While the purpose is the
251+ basic purpose of an input field, the hint flags allow to modify some of
252+ the behavior.
253+
254+ Values set with this request are double-buffered. They will get applied
255+ on the next zwp_text_input_v3.commit request.
256+ Subsequent attempts to update them may have no effect. The values
257+ remain valid until the next committed enable or disable request.
258+
259+ The initial value for hint is none, and the initial value for purpose
260+ is normal.
261+ </description>
262+ <arg name="hint" type="uint" enum="content_hint"/>
263+ <arg name="purpose" type="uint" enum="content_purpose"/>
264+ </request>
265+
266+ <request name="set_cursor_rectangle">
267+ <description summary="set cursor position">
268+ Marks an area around the cursor as a x, y, width, height rectangle in
269+ surface local coordinates.
270+
271+ Allows the compositor to put a window with word suggestions near the
272+ cursor, without obstructing the text being input.
273+
274+ If the client is unaware of the position of edited text, it should not
275+ issue this request, to signify lack of support to the compositor.
276+
277+ Values set with this request are double-buffered. They will get applied
278+ on the next zwp_text_input_v3.commit request, and stay valid until the
279+ next committed enable or disable request.
280+
281+ The initial values describing a cursor rectangle are empty. That means
282+ the text input does not support describing the cursor area. If the
283+ empty values get applied, subsequent attempts to change them may have
284+ no effect.
285+
286+ As of version 2, the zwp_text_input_v3.commit request does not apply
287+ values sent with this request. Instead, it stores them in a separate
288+ "committed" area. The committed values, if still valid, get applied on
289+ the next wl_surface.commit request on the surface with text-input focus.
290+ Both committed and applied values get invalidated on:
291+
292+ - the next committed enable or disable request, or
293+ - a change of the focused surface of the text-input (leave or enter events).
294+
295+ This double stage application allows the compositor to position
296+ the input method popup in the same frame as the contents
297+ of the text on the surface are updated.
298+ </description>
299+ <arg name="x" type="int"/>
300+ <arg name="y" type="int"/>
301+ <arg name="width" type="int"/>
302+ <arg name="height" type="int"/>
303+ </request>
304+
305+ <request name="commit">
306+ <description summary="commit state">
307+ Atomically applies state changes recently sent to the compositor.
308+
309+ The commit request establishes and updates the state of the client, and
310+ must be issued after any changes to apply them.
311+
312+ Text input state (enabled status, content purpose, content hint,
313+ surrounding text and change cause, cursor rectangle) is conceptually
314+ double-buffered within the context of a text input, i.e. between a
315+ committed enable request and the following committed enable or disable
316+ request.
317+
318+ Protocol requests modify the pending state, as opposed to the current
319+ state in use by the input method. A commit request atomically applies
320+ all pending state, replacing the current state. After commit, the new
321+ pending state is as documented for each related request.
322+
323+ Requests are applied in the order of arrival.
324+
325+ Neither current nor pending state are modified unless noted otherwise.
326+
327+ The compositor must count the number of commit requests coming from
328+ each zwp_text_input_v3 object and use the count as the serial in done
329+ events.
330+ </description>
331+ </request>
332+
333+ <event name="enter">
334+ <description summary="enter event">
335+ Notification that this seat's text-input focus is on a certain surface.
336+
337+ If client has created multiple text input objects, compositor must send
338+ this event to all of them.
339+
340+ When the seat has the keyboard capability the text-input focus follows
341+ the keyboard focus. This event sets the current surface for the
342+ text-input object.
343+ </description>
344+ <arg name="surface" type="object" interface="wl_surface"/>
345+ </event>
346+
347+ <event name="leave">
348+ <description summary="leave event">
349+ Notification that this seat's text-input focus is no longer on a
350+ certain surface. The client should reset any preedit string previously
351+ set.
352+
353+ The leave notification clears the current surface. It is sent before
354+ the enter notification for the new focus. After leave event, compositor
355+ must ignore requests from any text input instances until next enter
356+ event.
357+
358+ When the seat has the keyboard capability the text-input focus follows
359+ the keyboard focus.
360+ </description>
361+ <arg name="surface" type="object" interface="wl_surface"/>
362+ </event>
363+
364+ <event name="preedit_string">
365+ <description summary="pre-edit">
366+ Notify when a new composing text (pre-edit) should be set at the
367+ current cursor position. Any previously set composing text must be
368+ removed. Any previously existing selected text must be removed.
369+
370+ The argument text contains the pre-edit string buffer.
371+
372+ The parameters cursor_begin and cursor_end are counted in bytes
373+ relative to the beginning of the submitted text buffer. Cursor should
374+ be hidden when both are equal to -1.
375+
376+ They could be represented by the client as a line if both values are
377+ the same, or as a text highlight otherwise.
378+
379+ Values set with this event are double-buffered. They must be applied
380+ and reset to initial on the next zwp_text_input_v3.done event.
381+
382+ The initial value of text is an empty string, and cursor_begin,
383+ cursor_end and cursor_hidden are all 0.
384+ </description>
385+ <arg name="text" type="string" allow-null="true"/>
386+ <arg name="cursor_begin" type="int"/>
387+ <arg name="cursor_end" type="int"/>
388+ </event>
389+
390+ <event name="commit_string">
391+ <description summary="text commit">
392+ Notify when text should be inserted into the editor widget. The text to
393+ commit could be either just a single character after a key press or the
394+ result of some composing (pre-edit).
395+
396+ Values set with this event are double-buffered. They must be applied
397+ and reset to initial on the next zwp_text_input_v3.done event.
398+
399+ The initial value of text is an empty string.
400+ </description>
401+ <arg name="text" type="string" allow-null="true"/>
402+ </event>
403+
404+ <event name="delete_surrounding_text">
405+ <description summary="delete surrounding text">
406+ Notify when the text around the current cursor position should be
407+ deleted.
408+
409+ Before_length and after_length are the number of bytes before and after
410+ the current cursor index (excluding the selection) to delete.
411+
412+ If a preedit text is present, in effect before_length is counted from
413+ the beginning of it, and after_length from its end (see done event
414+ sequence).
415+
416+ Values set with this event are double-buffered. They must be applied
417+ and reset to initial on the next zwp_text_input_v3.done event.
418+
419+ The initial values of both before_length and after_length are 0.
420+ </description>
421+ <arg name="before_length" type="uint" summary="length of text before current cursor position"/>
422+ <arg name="after_length" type="uint" summary="length of text after current cursor position"/>
423+ </event>
424+
425+ <event name="done">
426+ <description summary="apply changes">
427+ Instruct the application to apply changes to state requested by the
428+ preedit_string, commit_string delete_surrounding_text, and action
429+ events.
430+
431+ The state relating to these events is double-buffered, and each one
432+ modifies the pending state. This event replaces the current state with
433+ the pending state.
434+
435+ The application must proceed by evaluating the changes in the following
436+ order:
437+
438+ 1. Replace existing preedit string with the cursor.
439+ 2. Delete requested surrounding text.
440+ 3. Insert commit string with the cursor at its end.
441+ 4. Calculate surrounding text to send.
442+ 5. Insert new preedit text in cursor position.
443+ 6. Place cursor inside preedit text.
444+ 7. Perform the requested action.
445+
446+ The serial number reflects the last state of the zwp_text_input_v3
447+ object known to the compositor. The value of the serial argument must
448+ be equal to the number of commit requests already issued on that object.
449+
450+ When the client receives a done event with a serial different than the
451+ number of past commit requests, it must proceed with evaluating and
452+ applying the changes as normal, except it should not change the current
453+ state of the zwp_text_input_v3 object. All pending state requests
454+ (set_surrounding_text, set_content_type and set_cursor_rectangle) on
455+ the zwp_text_input_v3 object should be sent and committed after
456+ receiving a zwp_text_input_v3.done event with a matching serial.
457+ </description>
458+ <arg name="serial" type="uint"/>
459+ </event>
460+
461+ <!-- Version 2 additions -->
462+ <enum name="error" since="2">
463+ <entry name="invalid_action" value="0" summary="an invalid or duplicate action was specified"/>
464+ </enum>
465+
466+ <enum name="action" since="2">
467+ <description summary="action">
468+ A possible action to perform on a text input.
469+
470+ The submit action is intended for input entries that expect some sort of
471+ activation after user interaction, e.g. the URL entry in a browser.
472+ </description>
473+ <entry name="none" value="0" summary="no action"/>
474+ <entry name="submit" value="1" summary="the action is submitted"/>
475+ </enum>
476+
477+ <event name="action" since="2">
478+ <description summary="action performed">
479+ An action was performed on this text input.
480+
481+ Values set with this event are double-buffered. They must be applied
482+ and reset to initial on the next zwp_text_input_v3.done event.
483+
484+ The initial value of action is none.
485+ </description>
486+ <arg name="action" type="uint" enum="action" summary="action performed"/>
487+ <arg name="serial" type="uint" summary="serial number of the action event"/>
488+ </event>
489+
490+ <event name="language" since="2">
491+ <description summary="notify of language selection">
492+ Notify the application of language used by the input method.
493+
494+ This event will be sent on creation if known and for all subsequent changes.
495+
496+ The language should be specified as an IETF BCP 47 tag.
497+ Setting an empty string will reset any known language back to the default unknown state.
498+ </description>
499+ <arg name="language" type="string" summary="new language set by IME"/>
500+ </event>
501+
502+ <request name="set_available_actions" since="2">
503+ <description summary="set the available actions">
504+ Set the actions available for this text input.
505+
506+ Values set with this request are double-buffered. They will get applied
507+ on the next zwp_text_input_v3.commit request.
508+
509+ If the available_actions array contains the none action, or contains the
510+ same action multiple times, the compositor must raise the invalid_action
511+ protocol error.
512+
513+ Initially, no actions are available.
514+ </description>
515+ <arg name="available_actions" type="array" summary="available actions"/>
516+ </request>
517+
518+ <request name="show_input_panel" since="2">
519+ <description summary="show input panel">
520+ Requests an input panel to be shown (e.g. a on-screen keyboard).
521+
522+ This request only hints the desired interaction pattern from the
523+ client side, and its effect may be ignored by compositors given
524+ other environmental factors. Repeated calls will be ignored.
525+ </description>
526+ </request>
527+
528+ <request name="hide_input_panel" since="2">
529+ <description summary="hide input panel">
530+ Requests an input panel to be hidden.
531+
532+ This request only hints the desired interaction pattern from the
533+ client side, and its effect may be ignored by compositors given
534+ other environmental factors. Repeated calls will be ignored.
535+ </description>
536+ </request>
537+
538+ <enum name="preedit_hint">
539+ <description summary="preedit style hint">
540+ Style hints for the preedit string.
541+ </description>
542+ <entry name="whole" value="1" summary="simple pre-edit text style, typically underlined"/>
543+ <entry name="selection" value="2"
544+ summary="hint for a selected piece of text, e.g. per-character navigation and composition"/>
545+ <entry name="prediction" value="3" summary="predicted text, not typed by the user"/>
546+ <entry name="prefix" value="4"
547+ summary="prefixed text not being currently edited, e.g. prior to a 'selection' section"/>
548+ <entry name="suffix" value="5"
549+ summary="suffixed text not being currently edited, e.g. after a 'selection' section"/>
550+ <entry name="spelling_error" value="6" summary="spelling error"/>
551+ <entry name="compose_error" value="7"
552+ summary="wrong composition, e.g. user input that can not be transliterated"/>
553+ </enum>
554+
555+ <event name="preedit_hint" since="2">
556+ <description summary="pre-edit">
557+ Notify of contextual hints for the pre-edit string. This
558+ event is always sent together with a zwp_text_input_v3.preedit_string
559+ event.
560+
561+ The parameters start and end are counted in bytes relative to the
562+ beginning of the text buffer submitted through
563+ zwp_text_input_v3.preedit_string, and represent the substring in the
564+ pre-edit text affected by the hint.
565+
566+ Multiple events may be submitted if the preedit string has different
567+ sections. The extent of hints may overlap. The parts of the preedit
568+ string that are not covered by any zwp_text_input_v3.preedit_hint event,
569+ the text will be considered unhinted. This is also the case if no
570+ preedit_hint event is sent.
571+
572+ Clients should provide recognizable visuals to these hints. if they are
573+ unable to comply with this requisition, it may be preferable for them
574+ keep the preedit_shown content hint disabled.
575+
576+ Values set with this event are double-buffered. They must be applied
577+ and reset on the next zwp_text_input_v3.done event.
578+ </description>
579+ <arg name="start" type="uint" summary="starting point of the affected substring"/>
580+ <arg name="end" type="uint" summary="end point of the affected substring"/>
581+ <arg name="hint" type="uint" enum="preedit_hint" summary="hint to apply"/>
582+ </event>
583+ </interface>
584+
585+ <interface name="zwp_text_input_manager_v3" version="2">
586+ <description summary="text input manager">
587+ A factory for text-input objects. This object is a global singleton.
588+ </description>
589+
590+ <request name="destroy" type="destructor">
591+ <description summary="Destroy the wp_text_input_manager">
592+ Destroy the wp_text_input_manager object.
593+ </description>
594+ </request>
595+
596+ <request name="get_text_input">
597+ <description summary="create a new text input object">
598+ Creates a new text-input object for a given seat.
599+ </description>
600+ <arg name="id" type="new_id" interface="zwp_text_input_v3"/>
601+ <arg name="seat" type="object" interface="wl_seat"/>
602+ </request>
603+ </interface>
604+</protocol>
A protocol/textinput/text-input-unstable-v3_generated.go +643 -0
@@ -0,0 +1,643 @@
1+// Code generated by wlturbo-scanner. DO NOT EDIT.
2+// Protocol: text_input_unstable_v3
3+// Source: text-input-unstable-v3.xml
4+
5+package textinput
6+
7+import (
8+ "sync"
9+
10+ cross_wl_seat "github.com/bnema/wlturbo/protocol/core"
11+ "github.com/bnema/wlturbo/wl"
12+)
13+
14+// CHANGE_CAUSE_INPUT_METHOD is the change_cause input_method value.
15+const CHANGE_CAUSE_INPUT_METHOD = 0
16+
17+// CHANGE_CAUSE_OTHER is the change_cause other value.
18+const CHANGE_CAUSE_OTHER = 1
19+
20+// CONTENT_HINT_NONE is the content_hint none value.
21+const CONTENT_HINT_NONE = 0x0
22+
23+// CONTENT_HINT_COMPLETION is the content_hint completion value.
24+const CONTENT_HINT_COMPLETION = 0x1
25+
26+// CONTENT_HINT_SPELLCHECK is the content_hint spellcheck value.
27+const CONTENT_HINT_SPELLCHECK = 0x2
28+
29+// CONTENT_HINT_AUTO_CAPITALIZATION is the content_hint auto_capitalization value.
30+const CONTENT_HINT_AUTO_CAPITALIZATION = 0x4
31+
32+// CONTENT_HINT_LOWERCASE is the content_hint lowercase value.
33+const CONTENT_HINT_LOWERCASE = 0x8
34+
35+// CONTENT_HINT_UPPERCASE is the content_hint uppercase value.
36+const CONTENT_HINT_UPPERCASE = 0x10
37+
38+// CONTENT_HINT_TITLECASE is the content_hint titlecase value.
39+const CONTENT_HINT_TITLECASE = 0x20
40+
41+// CONTENT_HINT_HIDDEN_TEXT is the content_hint hidden_text value.
42+const CONTENT_HINT_HIDDEN_TEXT = 0x40
43+
44+// CONTENT_HINT_SENSITIVE_DATA is the content_hint sensitive_data value.
45+const CONTENT_HINT_SENSITIVE_DATA = 0x80
46+
47+// CONTENT_HINT_LATIN is the content_hint latin value.
48+const CONTENT_HINT_LATIN = 0x100
49+
50+// CONTENT_HINT_MULTILINE is the content_hint multiline value.
51+const CONTENT_HINT_MULTILINE = 0x200
52+
53+// CONTENT_HINT_ON_SCREEN_INPUT_PROVIDED is the content_hint on_screen_input_provided value.
54+const CONTENT_HINT_ON_SCREEN_INPUT_PROVIDED = 0x400
55+
56+// CONTENT_HINT_NO_EMOJI is the content_hint no_emoji value.
57+const CONTENT_HINT_NO_EMOJI = 0x800
58+
59+// CONTENT_HINT_PREEDIT_SHOWN is the content_hint preedit_shown value.
60+const CONTENT_HINT_PREEDIT_SHOWN = 0x1000
61+
62+// CONTENT_PURPOSE_NORMAL is the content_purpose normal value.
63+const CONTENT_PURPOSE_NORMAL = 0
64+
65+// CONTENT_PURPOSE_ALPHA is the content_purpose alpha value.
66+const CONTENT_PURPOSE_ALPHA = 1
67+
68+// CONTENT_PURPOSE_DIGITS is the content_purpose digits value.
69+const CONTENT_PURPOSE_DIGITS = 2
70+
71+// CONTENT_PURPOSE_NUMBER is the content_purpose number value.
72+const CONTENT_PURPOSE_NUMBER = 3
73+
74+// CONTENT_PURPOSE_PHONE is the content_purpose phone value.
75+const CONTENT_PURPOSE_PHONE = 4
76+
77+// CONTENT_PURPOSE_URL is the content_purpose url value.
78+const CONTENT_PURPOSE_URL = 5
79+
80+// CONTENT_PURPOSE_EMAIL is the content_purpose email value.
81+const CONTENT_PURPOSE_EMAIL = 6
82+
83+// CONTENT_PURPOSE_NAME is the content_purpose name value.
84+const CONTENT_PURPOSE_NAME = 7
85+
86+// CONTENT_PURPOSE_PASSWORD is the content_purpose password value.
87+const CONTENT_PURPOSE_PASSWORD = 8
88+
89+// CONTENT_PURPOSE_PIN is the content_purpose pin value.
90+const CONTENT_PURPOSE_PIN = 9
91+
92+// CONTENT_PURPOSE_DATE is the content_purpose date value.
93+const CONTENT_PURPOSE_DATE = 10
94+
95+// CONTENT_PURPOSE_TIME is the content_purpose time value.
96+const CONTENT_PURPOSE_TIME = 11
97+
98+// CONTENT_PURPOSE_DATETIME is the content_purpose datetime value.
99+const CONTENT_PURPOSE_DATETIME = 12
100+
101+// CONTENT_PURPOSE_TERMINAL is the content_purpose terminal value.
102+const CONTENT_PURPOSE_TERMINAL = 13
103+
104+// ERROR_INVALID_ACTION is the error invalid_action value.
105+const ERROR_INVALID_ACTION = 0
106+
107+// ACTION_NONE is the action none value.
108+const ACTION_NONE = 0
109+
110+// ACTION_SUBMIT is the action submit value.
111+const ACTION_SUBMIT = 1
112+
113+// PREEDIT_HINT_WHOLE is the preedit_hint whole value.
114+const PREEDIT_HINT_WHOLE = 1
115+
116+// PREEDIT_HINT_SELECTION is the preedit_hint selection value.
117+const PREEDIT_HINT_SELECTION = 2
118+
119+// PREEDIT_HINT_PREDICTION is the preedit_hint prediction value.
120+const PREEDIT_HINT_PREDICTION = 3
121+
122+// PREEDIT_HINT_PREFIX is the preedit_hint prefix value.
123+const PREEDIT_HINT_PREFIX = 4
124+
125+// PREEDIT_HINT_SUFFIX is the preedit_hint suffix value.
126+const PREEDIT_HINT_SUFFIX = 5
127+
128+// PREEDIT_HINT_SPELLING_ERROR is the preedit_hint spelling_error value.
129+const PREEDIT_HINT_SPELLING_ERROR = 6
130+
131+// PREEDIT_HINT_COMPOSE_ERROR is the preedit_hint compose_error value.
132+const PREEDIT_HINT_COMPOSE_ERROR = 7
133+
134+// TextInputV3Interface is the protocol interface name.
135+const TextInputV3Interface = "zwp_text_input_v3"
136+
137+// TextInputV3 is the generated binding for zwp_text_input_v3 version 2.
138+type TextInputV3 struct {
139+ wl.BaseProxy
140+ // handlersMu guards the handler slices: a client may register or replace
141+ // handlers while another goroutine dispatches events.
142+ handlersMu sync.Mutex
143+ onEnter []func(surfaceID uint32)
144+ onLeave []func(surfaceID uint32)
145+ onPreeditString []func(text string, cursorBegin int32, cursorEnd int32)
146+ onCommitString []func(text string)
147+ onDeleteSurroundingText []func(beforeLength uint32, afterLength uint32)
148+ onDone []func(serial uint32)
149+ onAction []func(action uint32, serial uint32)
150+ onLanguage []func(language string)
151+ onPreeditHint []func(start uint32, end uint32, hint uint32)
152+}
153+
154+// NewTextInputV3 returns an unbound TextInputV3.
155+func NewTextInputV3(ctx *wl.Context) *TextInputV3 {
156+ obj := &TextInputV3{}
157+ obj.SetContext(ctx)
158+ ctx.Register(obj)
159+ return obj
160+}
161+
162+// Destroy the wp_text_input object. Also disables all surfaces enabled through this wp_text_input object.
163+func (o *TextInputV3) Destroy() error {
164+ if err := o.Context().CheckProxy(o); err != nil {
165+ return err
166+ }
167+ if err := o.Context().SendDestructor(o, 0); err != nil {
168+ return err
169+ }
170+ return nil
171+}
172+
173+// Requests text input on the surface previously obtained from the enter event. This request must be issued every time the focused text input changes to a new one, including within the current surface. Use zwp_text_input_v3.disable when there is no longer any input focus on the current surface. Clients must not enable more than one text input on the single seat and should disable the current text input before enabling the new one. Requests to enable a text input when another text input is enabled on the same seat must be ignored by compositor. This request resets all state associated with previous enable, disable, set_surrounding_text, set_text_change_cause, set_content_type, and set_cursor_rectangle requests, as well as the state associated with preedit_string, commit_string, and delete_surrounding_text events. The set_surrounding_text, set_content_type and set_cursor_rectangle requests must follow if the text input supports the necessary functionality. State set with this request is double-buffered. It will get applied on the next zwp_text_input_v3.commit request, and stay valid until the next committed enable or disable request. The changes must be applied by the compositor after issuing a zwp_text_input_v3.commit request.
174+func (o *TextInputV3) Enable() error {
175+ if err := o.Context().CheckProxy(o); err != nil {
176+ return err
177+ }
178+ if err := o.Context().SendRequest(o, 1); err != nil {
179+ return err
180+ }
181+ return nil
182+}
183+
184+// Explicitly disable text input on the current surface (typically when there is no focus on any text entry inside the surface). State set with this request is double-buffered. It will get applied on the next zwp_text_input_v3.commit request.
185+func (o *TextInputV3) Disable() error {
186+ if err := o.Context().CheckProxy(o); err != nil {
187+ return err
188+ }
189+ if err := o.Context().SendRequest(o, 2); err != nil {
190+ return err
191+ }
192+ return nil
193+}
194+
195+// Sets the surrounding plain text around the input, excluding the preedit text. The client should notify the compositor of any changes in any of the values carried with this request, including changes caused by handling incoming text-input events as well as changes caused by other mechanisms like keyboard typing. If the client is unaware of the text around the cursor, it should not issue this request, to signify lack of support to the compositor. Text is UTF-8 encoded, and should include the cursor position, the complete selection and additional characters before and after them. There is a maximum length of wayland messages, so text can not be longer than 4000 bytes. Cursor is the byte offset of the cursor within text buffer. Anchor is the byte offset of the selection anchor within text buffer. If there is no selected text, anchor is the same as cursor. If any preedit text is present, it is replaced with a cursor for the purpose of this event. Values set with this request are double-buffered. They will get applied on the next zwp_text_input_v3.commit request, and stay valid until the next committed enable or disable request. The initial state for affected fields is empty, meaning that the text input does not support sending surrounding text. If the empty values get applied, subsequent attempts to change them may have no effect.
196+func (o *TextInputV3) SetSurroundingText(text string, cursor int32, anchor int32) error {
197+ if err := o.Context().CheckProxy(o); err != nil {
198+ return err
199+ }
200+ if err := o.Context().SendRequest(o, 3, text, cursor, anchor); err != nil {
201+ return err
202+ }
203+ return nil
204+}
205+
206+// Tells the compositor why the text surrounding the cursor changed. Whenever the client detects an external change in text, cursor, or anchor posision, it must issue this request to the compositor. This request is intended to give the input method a chance to update the preedit text in an appropriate way, e.g. by removing it when the user starts typing with a keyboard. cause describes the source of the change. The value set with this request is double-buffered. It must be applied and reset to initial at the next zwp_text_input_v3.commit request. The initial value of cause is input_method.
207+func (o *TextInputV3) SetTextChangeCause(cause uint32) error {
208+ if err := o.Context().CheckProxy(o); err != nil {
209+ return err
210+ }
211+ if err := o.Context().SendRequest(o, 4, cause); err != nil {
212+ return err
213+ }
214+ return nil
215+}
216+
217+// Sets the content purpose and content hint. While the purpose is the basic purpose of an input field, the hint flags allow to modify some of the behavior. Values set with this request are double-buffered. They will get applied on the next zwp_text_input_v3.commit request. Subsequent attempts to update them may have no effect. The values remain valid until the next committed enable or disable request. The initial value for hint is none, and the initial value for purpose is normal.
218+func (o *TextInputV3) SetContentType(hint uint32, purpose uint32) error {
219+ if err := o.Context().CheckProxy(o); err != nil {
220+ return err
221+ }
222+ if err := o.Context().SendRequest(o, 5, hint, purpose); err != nil {
223+ return err
224+ }
225+ return nil
226+}
227+
228+// Marks an area around the cursor as a x, y, width, height rectangle in surface local coordinates. Allows the compositor to put a window with word suggestions near the cursor, without obstructing the text being input. If the client is unaware of the position of edited text, it should not issue this request, to signify lack of support to the compositor. Values set with this request are double-buffered. They will get applied on the next zwp_text_input_v3.commit request, and stay valid until the next committed enable or disable request. The initial values describing a cursor rectangle are empty. That means the text input does not support describing the cursor area. If the empty values get applied, subsequent attempts to change them may have no effect. As of version 2, the zwp_text_input_v3.commit request does not apply values sent with this request. Instead, it stores them in a separate "committed" area. The committed values, if still valid, get applied on the next wl_surface.commit request on the surface with text-input focus. Both committed and applied values get invalidated on: - the next committed enable or disable request, or - a change of the focused surface of the text-input (leave or enter events). This double stage application allows the compositor to position the input method popup in the same frame as the contents of the text on the surface are updated.
229+func (o *TextInputV3) SetCursorRectangle(x int32, y int32, width int32, height int32) error {
230+ if err := o.Context().CheckProxy(o); err != nil {
231+ return err
232+ }
233+ if err := o.Context().SendRequest(o, 6, x, y, width, height); err != nil {
234+ return err
235+ }
236+ return nil
237+}
238+
239+// Atomically applies state changes recently sent to the compositor. The commit request establishes and updates the state of the client, and must be issued after any changes to apply them. Text input state (enabled status, content purpose, content hint, surrounding text and change cause, cursor rectangle) is conceptually double-buffered within the context of a text input, i.e. between a committed enable request and the following committed enable or disable request. Protocol requests modify the pending state, as opposed to the current state in use by the input method. A commit request atomically applies all pending state, replacing the current state. After commit, the new pending state is as documented for each related request. Requests are applied in the order of arrival. Neither current nor pending state are modified unless noted otherwise. The compositor must count the number of commit requests coming from each zwp_text_input_v3 object and use the count as the serial in done events.
240+func (o *TextInputV3) Commit() error {
241+ if err := o.Context().CheckProxy(o); err != nil {
242+ return err
243+ }
244+ if err := o.Context().SendRequest(o, 7); err != nil {
245+ return err
246+ }
247+ return nil
248+}
249+
250+// Set the actions available for this text input. Values set with this request are double-buffered. They will get applied on the next zwp_text_input_v3.commit request. If the available_actions array contains the none action, or contains the same action multiple times, the compositor must raise the invalid_action protocol error. Initially, no actions are available.
251+func (o *TextInputV3) SetAvailableActions(availableActions []byte) error {
252+ if err := o.Context().CheckProxy(o); err != nil {
253+ return err
254+ }
255+ if err := o.Context().SendRequest(o, 8, availableActions); err != nil {
256+ return err
257+ }
258+ return nil
259+}
260+
261+// Requests an input panel to be shown (e.g. a on-screen keyboard). This request only hints the desired interaction pattern from the client side, and its effect may be ignored by compositors given other environmental factors. Repeated calls will be ignored.
262+func (o *TextInputV3) ShowInputPanel() error {
263+ if err := o.Context().CheckProxy(o); err != nil {
264+ return err
265+ }
266+ if err := o.Context().SendRequest(o, 9); err != nil {
267+ return err
268+ }
269+ return nil
270+}
271+
272+// Requests an input panel to be hidden. This request only hints the desired interaction pattern from the client side, and its effect may be ignored by compositors given other environmental factors. Repeated calls will be ignored.
273+func (o *TextInputV3) HideInputPanel() error {
274+ if err := o.Context().CheckProxy(o); err != nil {
275+ return err
276+ }
277+ if err := o.Context().SendRequest(o, 10); err != nil {
278+ return err
279+ }
280+ return nil
281+}
282+
283+// OnEnter registers a handler for the enter event.
284+//
285+// Handlers are appended, so a second call adds another handler rather than
286+// replacing the first. Registration is safe while another goroutine dispatches.
287+func (o *TextInputV3) OnEnter(handler func(surfaceID uint32)) {
288+ if handler == nil {
289+ return
290+ }
291+ o.handlersMu.Lock()
292+ defer o.handlersMu.Unlock()
293+ o.onEnter = append(o.onEnter, handler)
294+}
295+
296+// handlersForEnter returns the handlers registered for enter, taken
297+// under the lock so a handler may register another handler while events are
298+// being dispatched.
299+func (o *TextInputV3) handlersForEnter() []func(surfaceID uint32) {
300+ o.handlersMu.Lock()
301+ defer o.handlersMu.Unlock()
302+ return o.onEnter
303+}
304+
305+// OnLeave registers a handler for the leave event.
306+//
307+// Handlers are appended, so a second call adds another handler rather than
308+// replacing the first. Registration is safe while another goroutine dispatches.
309+func (o *TextInputV3) OnLeave(handler func(surfaceID uint32)) {
310+ if handler == nil {
311+ return
312+ }
313+ o.handlersMu.Lock()
314+ defer o.handlersMu.Unlock()
315+ o.onLeave = append(o.onLeave, handler)
316+}
317+
318+// handlersForLeave returns the handlers registered for leave, taken
319+// under the lock so a handler may register another handler while events are
320+// being dispatched.
321+func (o *TextInputV3) handlersForLeave() []func(surfaceID uint32) {
322+ o.handlersMu.Lock()
323+ defer o.handlersMu.Unlock()
324+ return o.onLeave
325+}
326+
327+// OnPreeditString registers a handler for the preedit_string event.
328+//
329+// Handlers are appended, so a second call adds another handler rather than
330+// replacing the first. Registration is safe while another goroutine dispatches.
331+func (o *TextInputV3) OnPreeditString(handler func(text string, cursorBegin int32, cursorEnd int32)) {
332+ if handler == nil {
333+ return
334+ }
335+ o.handlersMu.Lock()
336+ defer o.handlersMu.Unlock()
337+ o.onPreeditString = append(o.onPreeditString, handler)
338+}
339+
340+// handlersForPreeditString returns the handlers registered for preedit_string, taken
341+// under the lock so a handler may register another handler while events are
342+// being dispatched.
343+func (o *TextInputV3) handlersForPreeditString() []func(text string, cursorBegin int32, cursorEnd int32) {
344+ o.handlersMu.Lock()
345+ defer o.handlersMu.Unlock()
346+ return o.onPreeditString
347+}
348+
349+// OnCommitString registers a handler for the commit_string event.
350+//
351+// Handlers are appended, so a second call adds another handler rather than
352+// replacing the first. Registration is safe while another goroutine dispatches.
353+func (o *TextInputV3) OnCommitString(handler func(text string)) {
354+ if handler == nil {
355+ return
356+ }
357+ o.handlersMu.Lock()
358+ defer o.handlersMu.Unlock()
359+ o.onCommitString = append(o.onCommitString, handler)
360+}
361+
362+// handlersForCommitString returns the handlers registered for commit_string, taken
363+// under the lock so a handler may register another handler while events are
364+// being dispatched.
365+func (o *TextInputV3) handlersForCommitString() []func(text string) {
366+ o.handlersMu.Lock()
367+ defer o.handlersMu.Unlock()
368+ return o.onCommitString
369+}
370+
371+// OnDeleteSurroundingText registers a handler for the delete_surrounding_text event.
372+//
373+// Handlers are appended, so a second call adds another handler rather than
374+// replacing the first. Registration is safe while another goroutine dispatches.
375+func (o *TextInputV3) OnDeleteSurroundingText(handler func(beforeLength uint32, afterLength uint32)) {
376+ if handler == nil {
377+ return
378+ }
379+ o.handlersMu.Lock()
380+ defer o.handlersMu.Unlock()
381+ o.onDeleteSurroundingText = append(o.onDeleteSurroundingText, handler)
382+}
383+
384+// handlersForDeleteSurroundingText returns the handlers registered for delete_surrounding_text, taken
385+// under the lock so a handler may register another handler while events are
386+// being dispatched.
387+func (o *TextInputV3) handlersForDeleteSurroundingText() []func(beforeLength uint32, afterLength uint32) {
388+ o.handlersMu.Lock()
389+ defer o.handlersMu.Unlock()
390+ return o.onDeleteSurroundingText
391+}
392+
393+// OnDone registers a handler for the done 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 *TextInputV3) OnDone(handler func(serial uint32)) {
398+ if handler == nil {
399+ return
400+ }
401+ o.handlersMu.Lock()
402+ defer o.handlersMu.Unlock()
403+ o.onDone = append(o.onDone, handler)
404+}
405+
406+// handlersForDone returns the handlers registered for done, taken
407+// under the lock so a handler may register another handler while events are
408+// being dispatched.
409+func (o *TextInputV3) handlersForDone() []func(serial uint32) {
410+ o.handlersMu.Lock()
411+ defer o.handlersMu.Unlock()
412+ return o.onDone
413+}
414+
415+// OnAction registers a handler for the action event.
416+//
417+// Handlers are appended, so a second call adds another handler rather than
418+// replacing the first. Registration is safe while another goroutine dispatches.
419+func (o *TextInputV3) OnAction(handler func(action uint32, serial uint32)) {
420+ if handler == nil {
421+ return
422+ }
423+ o.handlersMu.Lock()
424+ defer o.handlersMu.Unlock()
425+ o.onAction = append(o.onAction, handler)
426+}
427+
428+// handlersForAction returns the handlers registered for action, taken
429+// under the lock so a handler may register another handler while events are
430+// being dispatched.
431+func (o *TextInputV3) handlersForAction() []func(action uint32, serial uint32) {
432+ o.handlersMu.Lock()
433+ defer o.handlersMu.Unlock()
434+ return o.onAction
435+}
436+
437+// OnLanguage registers a handler for the language event.
438+//
439+// Handlers are appended, so a second call adds another handler rather than
440+// replacing the first. Registration is safe while another goroutine dispatches.
441+func (o *TextInputV3) OnLanguage(handler func(language string)) {
442+ if handler == nil {
443+ return
444+ }
445+ o.handlersMu.Lock()
446+ defer o.handlersMu.Unlock()
447+ o.onLanguage = append(o.onLanguage, handler)
448+}
449+
450+// handlersForLanguage returns the handlers registered for language, taken
451+// under the lock so a handler may register another handler while events are
452+// being dispatched.
453+func (o *TextInputV3) handlersForLanguage() []func(language string) {
454+ o.handlersMu.Lock()
455+ defer o.handlersMu.Unlock()
456+ return o.onLanguage
457+}
458+
459+// OnPreeditHint registers a handler for the preedit_hint event.
460+//
461+// Handlers are appended, so a second call adds another handler rather than
462+// replacing the first. Registration is safe while another goroutine dispatches.
463+func (o *TextInputV3) OnPreeditHint(handler func(start uint32, end uint32, hint uint32)) {
464+ if handler == nil {
465+ return
466+ }
467+ o.handlersMu.Lock()
468+ defer o.handlersMu.Unlock()
469+ o.onPreeditHint = append(o.onPreeditHint, handler)
470+}
471+
472+// handlersForPreeditHint returns the handlers registered for preedit_hint, taken
473+// under the lock so a handler may register another handler while events are
474+// being dispatched.
475+func (o *TextInputV3) handlersForPreeditHint() []func(start uint32, end uint32, hint uint32) {
476+ o.handlersMu.Lock()
477+ defer o.handlersMu.Unlock()
478+ return o.onPreeditHint
479+}
480+
481+// EventSignature returns the declared event argument types in wire order.
482+func (o *TextInputV3) EventSignature(opcode uint16) (string, bool) {
483+ switch opcode {
484+ case 0:
485+ return "object,", true
486+ case 1:
487+ return "object,", true
488+ case 2:
489+ return "string,int,int,", true
490+ case 3:
491+ return "string,", true
492+ case 4:
493+ return "uint,uint,", true
494+ case 5:
495+ return "uint,", true
496+ case 6:
497+ return "uint,uint,", true
498+ case 7:
499+ return "string,", true
500+ case 8:
501+ return "uint,uint,uint,", true
502+ default:
503+ return "", false
504+ }
505+}
506+
507+// Dispatch decodes one event on zwp_text_input_v3 and calls the registered handlers.
508+func (o *TextInputV3) Dispatch(event *wl.Event) {
509+ switch event.Opcode {
510+ case 0: // enter
511+ surfaceID := event.Uint32()
512+
513+ for i, handler := range o.handlersForEnter() {
514+ _ = i
515+ handler(surfaceID)
516+ }
517+ case 1: // leave
518+ surfaceID := event.Uint32()
519+
520+ for i, handler := range o.handlersForLeave() {
521+ _ = i
522+ handler(surfaceID)
523+ }
524+ case 2: // preedit_string
525+ text := event.String()
526+ cursorBegin := event.Int32()
527+ cursorEnd := event.Int32()
528+
529+ for i, handler := range o.handlersForPreeditString() {
530+ _ = i
531+ handler(text, cursorBegin, cursorEnd)
532+ }
533+ case 3: // commit_string
534+ text := event.String()
535+
536+ for i, handler := range o.handlersForCommitString() {
537+ _ = i
538+ handler(text)
539+ }
540+ case 4: // delete_surrounding_text
541+ beforeLength := event.Uint32()
542+ afterLength := event.Uint32()
543+
544+ for i, handler := range o.handlersForDeleteSurroundingText() {
545+ _ = i
546+ handler(beforeLength, afterLength)
547+ }
548+ case 5: // done
549+ serial := event.Uint32()
550+
551+ for i, handler := range o.handlersForDone() {
552+ _ = i
553+ handler(serial)
554+ }
555+ case 6: // action
556+ action := event.Uint32()
557+ serial := event.Uint32()
558+
559+ for i, handler := range o.handlersForAction() {
560+ _ = i
561+ handler(action, serial)
562+ }
563+ case 7: // language
564+ language := event.String()
565+
566+ for i, handler := range o.handlersForLanguage() {
567+ _ = i
568+ handler(language)
569+ }
570+ case 8: // preedit_hint
571+ start := event.Uint32()
572+ end := event.Uint32()
573+ hint := event.Uint32()
574+
575+ for i, handler := range o.handlersForPreeditHint() {
576+ _ = i
577+ handler(start, end, hint)
578+ }
579+ default:
580+ }
581+}
582+
583+// TextInputManagerV3Interface is the protocol interface name.
584+const TextInputManagerV3Interface = "zwp_text_input_manager_v3"
585+
586+// TextInputManagerV3 is the generated binding for zwp_text_input_manager_v3 version 2.
587+type TextInputManagerV3 struct {
588+ wl.BaseProxy
589+}
590+
591+// NewTextInputManagerV3 returns an unbound TextInputManagerV3.
592+func NewTextInputManagerV3(ctx *wl.Context) *TextInputManagerV3 {
593+ obj := &TextInputManagerV3{}
594+ obj.SetContext(ctx)
595+ ctx.Register(obj)
596+ return obj
597+}
598+
599+// Destroy the wp_text_input_manager object.
600+func (o *TextInputManagerV3) Destroy() error {
601+ if err := o.Context().CheckProxy(o); err != nil {
602+ return err
603+ }
604+ if err := o.Context().SendDestructor(o, 0); err != nil {
605+ return err
606+ }
607+ return nil
608+}
609+
610+// Creates a new text-input object for a given seat.
611+func (o *TextInputManagerV3) GetTextInput(seat *cross_wl_seat.Seat) (*TextInputV3, error) {
612+ if err := o.Context().CheckProxy(o); err != nil {
613+ return nil, err
614+ }
615+ var arg1 wl.Object
616+ if seat != nil {
617+ arg1 = seat
618+ }
619+ child := &TextInputV3{}
620+ child.SetContext(o.Context())
621+ child.SetID(o.Context().AllocateID())
622+ o.Context().Register(child)
623+ if err := o.Context().SendRequest(o, 1, child, arg1); err != nil {
624+ o.Context().Unregister(child)
625+ return nil, err
626+ }
627+ return child, nil
628+}
629+
630+// EventSignature returns the declared event argument types in wire order.
631+func (o *TextInputManagerV3) EventSignature(opcode uint16) (string, bool) {
632+ switch opcode {
633+ default:
634+ return "", false
635+ }
636+}
637+
638+// Dispatch decodes one event on zwp_text_input_manager_v3 and calls the registered handlers.
639+func (o *TextInputManagerV3) Dispatch(event *wl.Event) {
640+ switch event.Opcode {
641+ default:
642+ }
643+}
A protocol/viewporter/viewporter.xml +177 -0
@@ -0,0 +1,177 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<protocol name="viewporter">
3+
4+ <copyright>
5+ Copyright © 2013-2016 Collabora, 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="wp_viewporter" version="1">
28+ <description summary="surface cropping and scaling">
29+ The global interface exposing surface cropping and scaling
30+ capabilities is used to instantiate an interface extension for a
31+ wl_surface object. This extended interface will then allow
32+ cropping and scaling the surface contents, effectively
33+ disconnecting the direct relationship between the buffer and the
34+ surface size.
35+ </description>
36+
37+ <request name="destroy" type="destructor">
38+ <description summary="unbind from the cropping and scaling interface">
39+ Informs the server that the client will not be using this
40+ protocol object anymore. This does not affect any other objects,
41+ wp_viewport objects included.
42+ </description>
43+ </request>
44+
45+ <enum name="error">
46+ <entry name="viewport_exists" value="0"
47+ summary="the surface already has a viewport object associated"/>
48+ </enum>
49+
50+ <request name="get_viewport">
51+ <description summary="extend surface interface for crop and scale">
52+ Instantiate an interface extension for the given wl_surface to
53+ crop and scale its content. If the given wl_surface already has
54+ a wp_viewport object associated, the viewport_exists
55+ protocol error is raised.
56+ </description>
57+ <arg name="id" type="new_id" interface="wp_viewport"
58+ summary="the new viewport interface id"/>
59+ <arg name="surface" type="object" interface="wl_surface"
60+ summary="the surface"/>
61+ </request>
62+ </interface>
63+
64+ <interface name="wp_viewport" version="1">
65+ <description summary="crop and scale interface to a wl_surface">
66+ An additional interface to a wl_surface object, which allows the
67+ client to specify the cropping and scaling of the surface
68+ contents.
69+
70+ This interface works with two concepts: the source rectangle (src_x,
71+ src_y, src_width, src_height), and the destination size (dst_width,
72+ dst_height). The contents of the source rectangle are scaled to the
73+ destination size, and content outside the source rectangle is ignored.
74+ This state is double-buffered, see wl_surface.commit.
75+
76+ The two parts of crop and scale state are independent: the source
77+ rectangle, and the destination size. Initially both are unset, that
78+ is, no scaling is applied. The whole of the current wl_buffer is
79+ used as the source, and the surface size is as defined in
80+ wl_surface.attach.
81+
82+ If the destination size is set, it causes the surface size to become
83+ dst_width, dst_height. The source (rectangle) is scaled to exactly
84+ this size. This overrides whatever the attached wl_buffer size is,
85+ unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface
86+ has no content and therefore no size. Otherwise, the size is always
87+ at least 1x1 in surface local coordinates.
88+
89+ If the source rectangle is set, it defines what area of the wl_buffer is
90+ taken as the source. If the source rectangle is set and the destination
91+ size is not set, then src_width and src_height must be integers, and the
92+ surface size becomes the source rectangle size. This results in cropping
93+ without scaling. If src_width or src_height are not integers and
94+ destination size is not set, the bad_size protocol error is raised when
95+ the surface state is applied.
96+
97+ The coordinate transformations from buffer pixel coordinates up to
98+ the surface-local coordinates happen in the following order:
99+ 1. buffer_transform (wl_surface.set_buffer_transform)
100+ 2. buffer_scale (wl_surface.set_buffer_scale)
101+ 3. crop and scale (wp_viewport.set*)
102+ This means, that the source rectangle coordinates of crop and scale
103+ are given in the coordinates after the buffer transform and scale,
104+ i.e. in the coordinates that would be the surface-local coordinates
105+ if the crop and scale was not applied.
106+
107+ If src_x or src_y are negative, the bad_value protocol error is raised.
108+ Otherwise, if the source rectangle is partially or completely outside of
109+ the non-NULL wl_buffer, then the out_of_buffer protocol error is raised
110+ when the surface state is applied. A NULL wl_buffer does not raise the
111+ out_of_buffer error.
112+
113+ If the wl_surface associated with the wp_viewport is destroyed,
114+ all wp_viewport requests except 'destroy' raise the protocol error
115+ no_surface.
116+
117+ If the wp_viewport object is destroyed, the crop and scale
118+ state is removed from the wl_surface. The change will be applied
119+ on the next wl_surface.commit.
120+ </description>
121+
122+ <request name="destroy" type="destructor">
123+ <description summary="remove scaling and cropping from the surface">
124+ The associated wl_surface's crop and scale state is removed.
125+ The change is applied on the next wl_surface.commit.
126+ </description>
127+ </request>
128+
129+ <enum name="error">
130+ <entry name="bad_value" value="0"
131+ summary="negative or zero values in width or height"/>
132+ <entry name="bad_size" value="1"
133+ summary="destination size is not integer"/>
134+ <entry name="out_of_buffer" value="2"
135+ summary="source rectangle extends outside of the content area"/>
136+ <entry name="no_surface" value="3"
137+ summary="the wl_surface was destroyed"/>
138+ </enum>
139+
140+ <request name="set_source">
141+ <description summary="set the source rectangle for cropping">
142+ Set the source rectangle of the associated wl_surface. See
143+ wp_viewport for the description, and relation to the wl_buffer
144+ size.
145+
146+ If all of x, y, width and height are -1.0, the source rectangle is
147+ unset instead. Any other set of values where width or height are zero
148+ or negative, or x or y are negative, raise the bad_value protocol
149+ error.
150+
151+ The crop and scale state is double-buffered, see wl_surface.commit.
152+ </description>
153+ <arg name="x" type="fixed" summary="source rectangle x"/>
154+ <arg name="y" type="fixed" summary="source rectangle y"/>
155+ <arg name="width" type="fixed" summary="source rectangle width"/>
156+ <arg name="height" type="fixed" summary="source rectangle height"/>
157+ </request>
158+
159+ <request name="set_destination">
160+ <description summary="set the surface size for scaling">
161+ Set the destination size of the associated wl_surface. See
162+ wp_viewport for the description, and relation to the wl_buffer
163+ size.
164+
165+ If width is -1 and height is -1, the destination size is unset
166+ instead. Any other pair of values for width and height that
167+ contains zero or negative values raises the bad_value protocol
168+ error.
169+
170+ The crop and scale state is double-buffered, see wl_surface.commit.
171+ </description>
172+ <arg name="width" type="int" summary="surface width"/>
173+ <arg name="height" type="int" summary="surface height"/>
174+ </request>
175+ </interface>
176+
177+</protocol>
A protocol/viewporter/viewporter_generated.go +151 -0
@@ -0,0 +1,151 @@
1+// Code generated by wlturbo-scanner. DO NOT EDIT.
2+// Protocol: viewporter
3+// Source: viewporter.xml
4+
5+package viewporter
6+
7+import (
8+ cross_wl_surface "github.com/bnema/wlturbo/protocol/core"
9+ "github.com/bnema/wlturbo/wl"
10+)
11+
12+// ERROR_VIEWPORT_EXISTS is the error viewport_exists value.
13+const ERROR_VIEWPORT_EXISTS = 0
14+
15+// ERROR_BAD_VALUE is the error bad_value value.
16+const ERROR_BAD_VALUE = 0
17+
18+// ERROR_BAD_SIZE is the error bad_size value.
19+const ERROR_BAD_SIZE = 1
20+
21+// ERROR_OUT_OF_BUFFER is the error out_of_buffer value.
22+const ERROR_OUT_OF_BUFFER = 2
23+
24+// ERROR_NO_SURFACE is the error no_surface value.
25+const ERROR_NO_SURFACE = 3
26+
27+// WpViewporterInterface is the protocol interface name.
28+const WpViewporterInterface = "wp_viewporter"
29+
30+// WpViewporter is the generated binding for wp_viewporter version 1.
31+type WpViewporter struct {
32+ wl.BaseProxy
33+}
34+
35+// NewWpViewporter returns an unbound WpViewporter.
36+func NewWpViewporter(ctx *wl.Context) *WpViewporter {
37+ obj := &WpViewporter{}
38+ obj.SetContext(ctx)
39+ ctx.Register(obj)
40+ return obj
41+}
42+
43+// Informs the server that the client will not be using this protocol object anymore. This does not affect any other objects, wp_viewport objects included.
44+func (o *WpViewporter) Destroy() error {
45+ if err := o.Context().CheckProxy(o); err != nil {
46+ return err
47+ }
48+ if err := o.Context().SendDestructor(o, 0); err != nil {
49+ return err
50+ }
51+ return nil
52+}
53+
54+// Instantiate an interface extension for the given wl_surface to crop and scale its content. If the given wl_surface already has a wp_viewport object associated, the viewport_exists protocol error is raised.
55+func (o *WpViewporter) GetViewport(surface *cross_wl_surface.Surface) (*WpViewport, error) {
56+ if err := o.Context().CheckProxy(o); err != nil {
57+ return nil, err
58+ }
59+ var arg1 wl.Object
60+ if surface != nil {
61+ arg1 = surface
62+ }
63+ child := &WpViewport{}
64+ child.SetContext(o.Context())
65+ child.SetID(o.Context().AllocateID())
66+ o.Context().Register(child)
67+ if err := o.Context().SendRequest(o, 1, child, arg1); err != nil {
68+ o.Context().Unregister(child)
69+ return nil, err
70+ }
71+ return child, nil
72+}
73+
74+// EventSignature returns the declared event argument types in wire order.
75+func (o *WpViewporter) EventSignature(opcode uint16) (string, bool) {
76+ switch opcode {
77+ default:
78+ return "", false
79+ }
80+}
81+
82+// Dispatch decodes one event on wp_viewporter and calls the registered handlers.
83+func (o *WpViewporter) Dispatch(event *wl.Event) {
84+ switch event.Opcode {
85+ default:
86+ }
87+}
88+
89+// WpViewportInterface is the protocol interface name.
90+const WpViewportInterface = "wp_viewport"
91+
92+// WpViewport is the generated binding for wp_viewport version 1.
93+type WpViewport struct {
94+ wl.BaseProxy
95+}
96+
97+// NewWpViewport returns an unbound WpViewport.
98+func NewWpViewport(ctx *wl.Context) *WpViewport {
99+ obj := &WpViewport{}
100+ obj.SetContext(ctx)
101+ ctx.Register(obj)
102+ return obj
103+}
104+
105+// The associated wl_surface's crop and scale state is removed. The change is applied on the next wl_surface.commit.
106+func (o *WpViewport) Destroy() error {
107+ if err := o.Context().CheckProxy(o); err != nil {
108+ return err
109+ }
110+ if err := o.Context().SendDestructor(o, 0); err != nil {
111+ return err
112+ }
113+ return nil
114+}
115+
116+// Set the source rectangle of the associated wl_surface. See wp_viewport for the description, and relation to the wl_buffer size. If all of x, y, width and height are -1.0, the source rectangle is unset instead. Any other set of values where width or height are zero or negative, or x or y are negative, raise the bad_value protocol error. The crop and scale state is double-buffered, see wl_surface.commit.
117+func (o *WpViewport) SetSource(x wl.Fixed, y wl.Fixed, width wl.Fixed, height wl.Fixed) error {
118+ if err := o.Context().CheckProxy(o); err != nil {
119+ return err
120+ }
121+ if err := o.Context().SendRequest(o, 1, x, y, width, height); err != nil {
122+ return err
123+ }
124+ return nil
125+}
126+
127+// Set the destination size of the associated wl_surface. See wp_viewport for the description, and relation to the wl_buffer size. If width is -1 and height is -1, the destination size is unset instead. Any other pair of values for width and height that contains zero or negative values raises the bad_value protocol error. The crop and scale state is double-buffered, see wl_surface.commit.
128+func (o *WpViewport) SetDestination(width int32, height int32) error {
129+ if err := o.Context().CheckProxy(o); err != nil {
130+ return err
131+ }
132+ if err := o.Context().SendRequest(o, 2, width, height); err != nil {
133+ return err
134+ }
135+ return nil
136+}
137+
138+// EventSignature returns the declared event argument types in wire order.
139+func (o *WpViewport) EventSignature(opcode uint16) (string, bool) {
140+ switch opcode {
141+ default:
142+ return "", false
143+ }
144+}
145+
146+// Dispatch decodes one event on wp_viewport and calls the registered handlers.
147+func (o *WpViewport) Dispatch(event *wl.Event) {
148+ switch event.Opcode {
149+ default:
150+ }
151+}
A protocol/xdgshell/xdg-shell.xml +1420 -0
@@ -0,0 +1,1420 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<protocol name="xdg_shell">
3+
4+ <copyright>
5+ Copyright © 2008-2013 Kristian Høgsberg
6+ Copyright © 2013 Rafael Antognolli
7+ Copyright © 2013 Jasper St. Pierre
8+ Copyright © 2010-2013 Intel Corporation
9+ Copyright © 2015-2017 Samsung Electronics Co., Ltd
10+ Copyright © 2015-2017 Red Hat Inc.
11+
12+ Permission is hereby granted, free of charge, to any person obtaining a
13+ copy of this software and associated documentation files (the "Software"),
14+ to deal in the Software without restriction, including without limitation
15+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
16+ and/or sell copies of the Software, and to permit persons to whom the
17+ Software is furnished to do so, subject to the following conditions:
18+
19+ The above copyright notice and this permission notice (including the next
20+ paragraph) shall be included in all copies or substantial portions of the
21+ Software.
22+
23+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29+ DEALINGS IN THE SOFTWARE.
30+ </copyright>
31+
32+ <interface name="xdg_wm_base" version="7">
33+ <description summary="create desktop-style surfaces">
34+ The xdg_wm_base interface is exposed as a global object enabling clients
35+ to turn their wl_surfaces into windows in a desktop environment. It
36+ defines the basic functionality needed for clients and the compositor to
37+ create windows that can be dragged, resized, maximized, etc, as well as
38+ creating transient windows such as popup menus.
39+ </description>
40+
41+ <enum name="error">
42+ <entry name="role" value="0" summary="given wl_surface has another role"/>
43+ <entry name="defunct_surfaces" value="1"
44+ summary="xdg_wm_base was destroyed before children"/>
45+ <entry name="not_the_topmost_popup" value="2"
46+ summary="the client tried to map or destroy a non-topmost popup"/>
47+ <entry name="invalid_popup_parent" value="3"
48+ summary="the client specified an invalid popup parent surface"/>
49+ <entry name="invalid_surface_state" value="4"
50+ summary="the client provided an invalid surface state"/>
51+ <entry name="invalid_positioner" value="5"
52+ summary="the client provided an invalid positioner"/>
53+ <entry name="unresponsive" value="6"
54+ summary="the client didn’t respond to a ping event in time"/>
55+ </enum>
56+
57+ <request name="destroy" type="destructor">
58+ <description summary="destroy xdg_wm_base">
59+ Destroy this xdg_wm_base object.
60+
61+ Destroying a bound xdg_wm_base object while there are surfaces
62+ still alive created by this xdg_wm_base object instance is illegal
63+ and will result in a defunct_surfaces error.
64+ </description>
65+ </request>
66+
67+ <request name="create_positioner">
68+ <description summary="create a positioner object">
69+ Create a positioner object. A positioner object is used to position
70+ surfaces relative to some parent surface. See the interface description
71+ and xdg_surface.get_popup for details.
72+ </description>
73+ <arg name="id" type="new_id" interface="xdg_positioner"/>
74+ </request>
75+
76+ <request name="get_xdg_surface">
77+ <description summary="create a shell surface from a surface">
78+ This creates an xdg_surface for the given surface. An xdg_surface is
79+ used as basis to define a role to a given surface, such as xdg_toplevel
80+ or xdg_popup. It also manages functionality shared between xdg_surface
81+ based surface roles.
82+
83+ While xdg_surface itself is not a role, the corresponding surface may
84+ only be assigned a role extending xdg_surface, such as xdg_toplevel or
85+ xdg_popup. It is illegal to create an xdg_surface for a wl_surface which
86+ already has anassigned role and this will result in a role error.
87+
88+ See the documentation of xdg_surface for more details about what an
89+ xdg_surface is and how it is used.
90+ </description>
91+ <arg name="id" type="new_id" interface="xdg_surface"/>
92+ <arg name="surface" type="object" interface="wl_surface"/>
93+ </request>
94+
95+ <request name="pong">
96+ <description summary="respond to a ping event">
97+ A client must respond to a ping event with a pong request or
98+ the client may be deemed unresponsive. See xdg_wm_base.ping
99+ and xdg_wm_base.error.unresponsive.
100+ </description>
101+ <arg name="serial" type="uint" summary="serial of the ping event"/>
102+ </request>
103+
104+ <event name="ping">
105+ <description summary="check if the client is alive">
106+ The ping event asks the client if it's still alive. Pass the
107+ serial specified in the event back to the compositor by sending
108+ a "pong" request back with the specified serial. See xdg_wm_base.pong.
109+
110+ Compositors can use this to determine if the client is still
111+ alive. It's unspecified what will happen if the client doesn't
112+ respond to the ping request, or in what timeframe. Clients should
113+ try to respond in a reasonable amount of time. The “unresponsive”
114+ error is provided for compositors that wish to disconnect unresponsive
115+ clients.
116+
117+ A compositor is free to ping in any way it wants, but a client must
118+ always respond to any xdg_wm_base object it created.
119+ </description>
120+ <arg name="serial" type="uint" summary="pass this to the pong request"/>
121+ </event>
122+ </interface>
123+
124+ <interface name="xdg_positioner" version="7">
125+ <description summary="child surface positioner">
126+ The xdg_positioner provides a collection of rules for the placement of a
127+ child surface relative to a parent surface. Rules can be defined to ensure
128+ the child surface remains within the visible area's borders, and to
129+ specify how the child surface changes its position, such as sliding along
130+ an axis, or flipping around a rectangle. These positioner-created rules are
131+ constrained by the requirement that a child surface must intersect with or
132+ be at least partially adjacent to its parent surface.
133+
134+ See the various requests for details about possible rules.
135+
136+ At the time of the request, the compositor makes a copy of the rules
137+ specified by the xdg_positioner. Thus, after the request is complete the
138+ xdg_positioner object can be destroyed or reused; further changes to the
139+ object will have no effect on previous usages.
140+
141+ For an xdg_positioner object to be considered complete, it must have a
142+ non-zero size set by set_size, and a non-zero anchor rectangle set by
143+ set_anchor_rect. Passing an incomplete xdg_positioner object when
144+ positioning a surface raises an invalid_positioner error.
145+ </description>
146+
147+ <enum name="error">
148+ <entry name="invalid_input" value="0" summary="invalid input provided"/>
149+ </enum>
150+
151+ <request name="destroy" type="destructor">
152+ <description summary="destroy the xdg_positioner object">
153+ Notify the compositor that the xdg_positioner will no longer be used.
154+ </description>
155+ </request>
156+
157+ <request name="set_size">
158+ <description summary="set the size of the to-be positioned rectangle">
159+ Set the size of the surface that is to be positioned with the positioner
160+ object. The size is in surface-local coordinates and corresponds to the
161+ window geometry. See xdg_surface.set_window_geometry.
162+
163+ If a zero or negative size is set the invalid_input error is raised.
164+ </description>
165+ <arg name="width" type="int" summary="width of positioned rectangle"/>
166+ <arg name="height" type="int" summary="height of positioned rectangle"/>
167+ </request>
168+
169+ <request name="set_anchor_rect">
170+ <description summary="set the anchor rectangle within the parent surface">
171+ Specify the anchor rectangle within the parent surface that the child
172+ surface will be placed relative to. The rectangle is relative to the
173+ window geometry as defined by xdg_surface.set_window_geometry of the
174+ parent surface.
175+
176+ When the xdg_positioner object is used to position a child surface, the
177+ anchor rectangle may not extend outside the window geometry of the
178+ positioned child's parent surface.
179+
180+ If a negative size is set the invalid_input error is raised.
181+ </description>
182+ <arg name="x" type="int" summary="x position of anchor rectangle"/>
183+ <arg name="y" type="int" summary="y position of anchor rectangle"/>
184+ <arg name="width" type="int" summary="width of anchor rectangle"/>
185+ <arg name="height" type="int" summary="height of anchor rectangle"/>
186+ </request>
187+
188+ <enum name="anchor">
189+ <entry name="none" value="0"/>
190+ <entry name="top" value="1"/>
191+ <entry name="bottom" value="2"/>
192+ <entry name="left" value="3"/>
193+ <entry name="right" value="4"/>
194+ <entry name="top_left" value="5"/>
195+ <entry name="bottom_left" value="6"/>
196+ <entry name="top_right" value="7"/>
197+ <entry name="bottom_right" value="8"/>
198+ </enum>
199+
200+ <request name="set_anchor">
201+ <description summary="set anchor rectangle anchor">
202+ Defines the anchor point for the anchor rectangle. The specified anchor
203+ is used to derive an anchor point that the child surface will be
204+ positioned relative to. If a corner anchor is set (e.g. 'top_left' or
205+ 'bottom_right'), the anchor point will be at the specified corner;
206+ otherwise, the derived anchor point will be centered on the specified
207+ edge, or in the center of the anchor rectangle if no edge is specified.
208+ </description>
209+ <arg name="anchor" type="uint" enum="anchor"
210+ summary="anchor point"/>
211+ </request>
212+
213+ <enum name="gravity">
214+ <entry name="none" value="0"/>
215+ <entry name="top" value="1"/>
216+ <entry name="bottom" value="2"/>
217+ <entry name="left" value="3"/>
218+ <entry name="right" value="4"/>
219+ <entry name="top_left" value="5"/>
220+ <entry name="bottom_left" value="6"/>
221+ <entry name="top_right" value="7"/>
222+ <entry name="bottom_right" value="8"/>
223+ </enum>
224+
225+ <request name="set_gravity">
226+ <description summary="set child surface gravity">
227+ Defines in what direction a surface should be positioned, relative to
228+ the anchor point of the parent surface. If a corner gravity is
229+ specified (e.g. 'bottom_right' or 'top_left'), then the child surface
230+ will be placed towards the specified gravity; otherwise, the child
231+ surface will be centered over the anchor point on any axis that had no
232+ gravity specified. If the gravity is not in the ‘gravity’ enum, an
233+ invalid_input error is raised.
234+ </description>
235+ <arg name="gravity" type="uint" enum="gravity"
236+ summary="gravity direction"/>
237+ </request>
238+
239+ <enum name="constraint_adjustment" bitfield="true">
240+ <description summary="constraint adjustments">
241+ The constraint adjustment value define ways the compositor will adjust
242+ the position of the surface, if the unadjusted position would result
243+ in the surface being partly constrained.
244+
245+ Whether a surface is considered 'constrained' is left to the compositor
246+ to determine. For example, the surface may be partly outside the
247+ compositor's defined 'work area', thus necessitating the child surface's
248+ position be adjusted until it is entirely inside the work area.
249+
250+ The adjustments can be combined, according to a defined precedence: 1)
251+ Flip, 2) Slide, 3) Resize.
252+ </description>
253+ <entry name="none" value="0">
254+ <description summary="don't move the child surface when constrained">
255+ Don't alter the surface position even if it is constrained on some
256+ axis, for example partially outside the edge of an output.
257+ </description>
258+ </entry>
259+ <entry name="slide_x" value="1">
260+ <description summary="move along the x axis until unconstrained">
261+ Slide the surface along the x axis until it is no longer constrained.
262+
263+ First try to slide towards the direction of the gravity on the x axis
264+ until either the edge in the opposite direction of the gravity is
265+ unconstrained or the edge in the direction of the gravity is
266+ constrained.
267+
268+ Then try to slide towards the opposite direction of the gravity on the
269+ x axis until either the edge in the direction of the gravity is
270+ unconstrained or the edge in the opposite direction of the gravity is
271+ constrained.
272+ </description>
273+ </entry>
274+ <entry name="slide_y" value="2">
275+ <description summary="move along the y axis until unconstrained">
276+ Slide the surface along the y axis until it is no longer constrained.
277+
278+ First try to slide towards the direction of the gravity on the y axis
279+ until either the edge in the opposite direction of the gravity is
280+ unconstrained or the edge in the direction of the gravity is
281+ constrained.
282+
283+ Then try to slide towards the opposite direction of the gravity on the
284+ y axis until either the edge in the direction of the gravity is
285+ unconstrained or the edge in the opposite direction of the gravity is
286+ constrained.
287+ </description>
288+ </entry>
289+ <entry name="flip_x" value="4">
290+ <description summary="invert the anchor and gravity on the x axis">
291+ Invert the anchor and gravity on the x axis if the surface is
292+ constrained on the x axis. For example, if the left edge of the
293+ surface is constrained, the gravity is 'left' and the anchor is
294+ 'left', change the gravity to 'right' and the anchor to 'right'.
295+
296+ If the adjusted position also ends up being constrained, the resulting
297+ position of the flip_x adjustment will be the one before the
298+ adjustment.
299+ </description>
300+ </entry>
301+ <entry name="flip_y" value="8">
302+ <description summary="invert the anchor and gravity on the y axis">
303+ Invert the anchor and gravity on the y axis if the surface is
304+ constrained on the y axis. For example, if the bottom edge of the
305+ surface is constrained, the gravity is 'bottom' and the anchor is
306+ 'bottom', change the gravity to 'top' and the anchor to 'top'.
307+
308+ The adjusted position is calculated given the original anchor
309+ rectangle and offset, but with the new flipped anchor and gravity
310+ values.
311+
312+ If the adjusted position also ends up being constrained, the resulting
313+ position of the flip_y adjustment will be the one before the
314+ adjustment.
315+ </description>
316+ </entry>
317+ <entry name="resize_x" value="16">
318+ <description summary="horizontally resize the surface">
319+ Resize the surface horizontally so that it is completely
320+ unconstrained.
321+ </description>
322+ </entry>
323+ <entry name="resize_y" value="32">
324+ <description summary="vertically resize the surface">
325+ Resize the surface vertically so that it is completely unconstrained.
326+ </description>
327+ </entry>
328+ </enum>
329+
330+ <request name="set_constraint_adjustment">
331+ <description summary="set the adjustment to be done when constrained">
332+ Specify how the window should be positioned if the originally intended
333+ position caused the surface to be constrained, meaning at least
334+ partially outside positioning boundaries set by the compositor. The
335+ adjustment is set by constructing a bitmask describing the adjustment to
336+ be made when the surface is constrained on that axis.
337+
338+ If no bit for one axis is set, the compositor will assume that the child
339+ surface should not change its position on that axis when constrained.
340+
341+ If more than one bit for one axis is set, the order of how adjustments
342+ are applied is specified in the corresponding adjustment descriptions.
343+
344+ The default adjustment is none.
345+ </description>
346+ <arg name="constraint_adjustment" type="uint" enum="constraint_adjustment"
347+ summary="bit mask of constraint adjustments"/>
348+ </request>
349+
350+ <request name="set_offset">
351+ <description summary="set surface position offset">
352+ Specify the surface position offset relative to the position of the
353+ anchor on the anchor rectangle and the anchor on the surface. For
354+ example if the anchor of the anchor rectangle is at (x, y), the surface
355+ has the gravity bottom|right, and the offset is (ox, oy), the calculated
356+ surface position will be (x + ox, y + oy). The offset position of the
357+ surface is the one used for constraint testing. See
358+ set_constraint_adjustment.
359+
360+ An example use case is placing a popup menu on top of a user interface
361+ element, while aligning the user interface element of the parent surface
362+ with some user interface element placed somewhere in the popup surface.
363+ </description>
364+ <arg name="x" type="int" summary="surface position x offset"/>
365+ <arg name="y" type="int" summary="surface position y offset"/>
366+ </request>
367+
368+ <!-- Version 3 additions -->
369+
370+ <request name="set_reactive" since="3">
371+ <description summary="continuously reconstrain the surface">
372+ When set reactive, the surface is reconstrained if the conditions used
373+ for constraining changed, e.g. the parent window moved.
374+
375+ If the conditions changed and the popup was reconstrained, an
376+ xdg_popup.configure event is sent with updated geometry, followed by an
377+ xdg_surface.configure event.
378+ </description>
379+ </request>
380+
381+ <request name="set_parent_size" since="3">
382+ <description summary="set parent size">
383+ Set the parent window geometry the compositor should use when
384+ positioning the popup. The compositor may use this information to
385+ determine the future state the popup should be constrained using. If
386+ this doesn't match the dimension of the parent the popup is eventually
387+ positioned against, the behavior is undefined.
388+
389+ The arguments are given in the surface-local coordinate space.
390+ </description>
391+ <arg name="parent_width" type="int"
392+ summary="future window geometry width of parent"/>
393+ <arg name="parent_height" type="int"
394+ summary="future window geometry height of parent"/>
395+ </request>
396+
397+ <request name="set_parent_configure" since="3">
398+ <description summary="set parent configure this is a response to">
399+ Set the serial of an xdg_surface.configure event this positioner will be
400+ used in response to. The compositor may use this information together
401+ with set_parent_size to determine what future state the popup should be
402+ constrained using.
403+ </description>
404+ <arg name="serial" type="uint"
405+ summary="serial of parent configure event"/>
406+ </request>
407+ </interface>
408+
409+ <interface name="xdg_surface" version="7">
410+ <description summary="desktop user interface surface base interface">
411+ An interface that may be implemented by a wl_surface, for
412+ implementations that provide a desktop-style user interface.
413+
414+ It provides a base set of functionality required to construct user
415+ interface elements requiring management by the compositor, such as
416+ toplevel windows, menus, etc. The types of functionality are split into
417+ xdg_surface roles.
418+
419+ Creating an xdg_surface does not set the role for a wl_surface. In order
420+ to map an xdg_surface, the client must create a role-specific object
421+ using, e.g., get_toplevel, get_popup. The wl_surface for any given
422+ xdg_surface can have at most one role, and may not be assigned any role
423+ not based on xdg_surface.
424+
425+ A role must be assigned before any other requests are made to the
426+ xdg_surface object.
427+
428+ The client must call wl_surface.commit on the corresponding wl_surface
429+ for the xdg_surface state to take effect.
430+
431+ Creating an xdg_surface from a wl_surface which has a buffer attached or
432+ committed is a client error, and any attempts by a client to attach or
433+ manipulate a buffer prior to the first xdg_surface.configure call must
434+ also be treated as errors.
435+
436+ After creating a role-specific object and setting it up (e.g. by sending
437+ the title, app ID, size constraints, parent, etc), the client must
438+ perform an initial commit without any buffer attached. The compositor
439+ will reply with initial wl_surface state such as
440+ wl_surface.preferred_buffer_scale followed by an xdg_surface.configure
441+ event. The client must acknowledge it and is then allowed to attach a
442+ buffer to map the surface.
443+
444+ Mapping an xdg_surface-based role surface is defined as making it
445+ possible for the surface to be shown by the compositor. Note that
446+ a mapped surface is not guaranteed to be visible once it is mapped.
447+
448+ For an xdg_surface to be mapped by the compositor, the following
449+ conditions must be met:
450+ (1) the client has assigned an xdg_surface-based role to the surface
451+ (2) the client has set and committed the xdg_surface state and the
452+ role-dependent state to the surface
453+ (3) the client has committed a buffer to the surface
454+
455+ A newly-unmapped surface is considered to have met condition (1) out
456+ of the 3 required conditions for mapping a surface if its role surface
457+ has not been destroyed, i.e. the client must perform the initial commit
458+ again before attaching a buffer.
459+ </description>
460+
461+ <enum name="error">
462+ <entry name="not_constructed" value="1"
463+ summary="Surface was not fully constructed"/>
464+ <entry name="already_constructed" value="2"
465+ summary="Surface was already constructed"/>
466+ <entry name="unconfigured_buffer" value="3"
467+ summary="Attaching a buffer to an unconfigured surface"/>
468+ <entry name="invalid_serial" value="4"
469+ summary="Invalid serial number when acking a configure event"/>
470+ <entry name="invalid_size" value="5"
471+ summary="Width or height was zero or negative"/>
472+ <entry name="defunct_role_object" value="6"
473+ summary="Surface was destroyed before its role object"/>
474+ </enum>
475+
476+ <request name="destroy" type="destructor">
477+ <description summary="destroy the xdg_surface">
478+ Destroy the xdg_surface object. An xdg_surface must only be destroyed
479+ after its role object has been destroyed, otherwise
480+ a defunct_role_object error is raised.
481+ </description>
482+ </request>
483+
484+ <request name="get_toplevel">
485+ <description summary="assign the xdg_toplevel surface role">
486+ This creates an xdg_toplevel object for the given xdg_surface and gives
487+ the associated wl_surface the xdg_toplevel role.
488+
489+ See the documentation of xdg_toplevel for more details about what an
490+ xdg_toplevel is and how it is used.
491+ </description>
492+ <arg name="id" type="new_id" interface="xdg_toplevel"/>
493+ </request>
494+
495+ <request name="get_popup">
496+ <description summary="assign the xdg_popup surface role">
497+ This creates an xdg_popup object for the given xdg_surface and gives
498+ the associated wl_surface the xdg_popup role.
499+
500+ If null is passed as a parent, a parent surface must be specified using
501+ some other protocol, before committing the initial state.
502+
503+ See the documentation of xdg_popup for more details about what an
504+ xdg_popup is and how it is used.
505+ </description>
506+ <arg name="id" type="new_id" interface="xdg_popup"/>
507+ <arg name="parent" type="object" interface="xdg_surface" allow-null="true" summary="parent surface for this popup"/>
508+ <arg name="positioner" type="object" interface="xdg_positioner" summary="positioner for this popup"/>
509+ </request>
510+
511+ <request name="set_window_geometry">
512+ <description summary="set the new window geometry">
513+ The window geometry of a surface is its "visible bounds" from the
514+ user's perspective. Client-side decorations often have invisible
515+ portions like drop-shadows which should be ignored for the
516+ purposes of aligning, placing and constraining windows. Note that
517+ in some situations, compositors may clip rendering to the window
518+ geometry, so the client should avoid putting functional elements
519+ outside of it.
520+
521+ The window geometry is double-buffered state, see wl_surface.commit.
522+
523+ When maintaining a position, the compositor should treat the (x, y)
524+ coordinate of the window geometry as the top left corner of the window.
525+ A client changing the (x, y) window geometry coordinate should in
526+ general not alter the position of the window.
527+
528+ Once the window geometry of the surface is set, it is not possible to
529+ unset it, and it will remain the same until set_window_geometry is
530+ called again, even if a new subsurface or buffer is attached.
531+
532+ If never set, the value is the full bounds of the surface,
533+ including any subsurfaces. This updates dynamically on every
534+ commit. This unset is meant for extremely simple clients.
535+
536+ The arguments are given in the surface-local coordinate space of
537+ the wl_surface associated with this xdg_surface, and may extend outside
538+ of the wl_surface itself to mark parts of the subsurface tree as part of
539+ the window geometry.
540+
541+ When applied, the effective window geometry will be the set window
542+ geometry clamped to the bounding rectangle of the combined
543+ geometry of the surface of the xdg_surface and the associated
544+ subsurfaces.
545+
546+ The effective geometry will not be recalculated unless a new call to
547+ set_window_geometry is done and the new pending surface state is
548+ subsequently applied.
549+
550+ The width and height of the effective window geometry must be
551+ greater than zero. Setting an invalid size will raise an
552+ invalid_size error.
553+ </description>
554+ <arg name="x" type="int" summary="x coordinate of the top-left corner of the window inside this surface"/>
555+ <arg name="y" type="int" summary="y coordinate of the top-left corner of the window inside this surface"/>
556+ <arg name="width" type="int" summary="width of the window"/>
557+ <arg name="height" type="int" summary="height of the window"/>
558+ </request>
559+
560+ <request name="ack_configure">
561+ <description summary="ack a configure event">
562+ When a configure event is received, if a client commits the
563+ surface in response to the configure event, then the client
564+ must make an ack_configure request sometime before the commit
565+ request, passing along the serial of the configure event.
566+
567+ For instance, for toplevel surfaces the compositor might use this
568+ information to move a surface to the top left only when the client has
569+ drawn itself for the maximized or fullscreen state.
570+
571+ If the client receives multiple configure events before it
572+ can respond to one, it only has to ack the last configure event.
573+ Acking a configure event that was never sent raises an invalid_serial
574+ error.
575+
576+ A client is not required to commit immediately after sending
577+ an ack_configure request - it may even ack_configure several times
578+ before its next surface commit.
579+
580+ A client may send multiple ack_configure requests before committing, but
581+ only the last request sent before a commit indicates which configure
582+ event the client really is responding to.
583+
584+ Sending an ack_configure request consumes the serial number sent with
585+ the request, as well as serial numbers sent by all configure events
586+ sent on this xdg_surface prior to the configure event referenced by
587+ the committed serial.
588+
589+ It is an error to issue multiple ack_configure requests referencing a
590+ serial from the same configure event, or to issue an ack_configure
591+ request referencing a serial from a configure event issued before the
592+ event identified by the last ack_configure request for the same
593+ xdg_surface. Doing so will raise an invalid_serial error.
594+ </description>
595+ <arg name="serial" type="uint" summary="the serial from the configure event"/>
596+ </request>
597+
598+ <event name="configure">
599+ <description summary="suggest a surface change">
600+ The configure event marks the end of a configure sequence. A configure
601+ sequence is a set of one or more events configuring the state of the
602+ xdg_surface, including the final xdg_surface.configure event.
603+
604+ Where applicable, xdg_surface surface roles will during a configure
605+ sequence extend this event as a latched state sent as events before the
606+ xdg_surface.configure event. Such events should be considered to make up
607+ a set of atomically applied configuration states, where the
608+ xdg_surface.configure commits the accumulated state.
609+
610+ Clients should arrange their surface for the new states, and then send
611+ an ack_configure request with the serial sent in this configure event at
612+ some point before committing the new surface.
613+
614+ If the client receives multiple configure events before it can respond
615+ to one, it is free to discard all but the last event it received.
616+ </description>
617+ <arg name="serial" type="uint" summary="serial of the configure event"/>
618+ </event>
619+
620+ </interface>
621+
622+ <interface name="xdg_toplevel" version="7">
623+ <description summary="toplevel surface">
624+ This interface defines an xdg_surface role which allows a surface to,
625+ among other things, set window-like properties such as maximize,
626+ fullscreen, and minimize, set application-specific metadata like title and
627+ id, and well as trigger user interactive operations such as interactive
628+ resize and move.
629+
630+ An xdg_toplevel by default is responsible for providing the full intended
631+ visual representation of the toplevel, which depending on the window
632+ state, may mean things like a title bar, window controls and drop shadow.
633+
634+ Unmapping an xdg_toplevel means that the surface cannot be shown
635+ by the compositor until it is explicitly mapped again.
636+ All active operations (e.g., move, resize) are canceled and all
637+ attributes (e.g. title, state, stacking, ...) are discarded for
638+ an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to
639+ the state it had right after xdg_surface.get_toplevel. The client
640+ can re-map the toplevel by performing a commit without any buffer
641+ attached, waiting for a configure event and handling it as usual (see
642+ xdg_surface description).
643+
644+ Attaching a null buffer to a toplevel unmaps the surface.
645+ </description>
646+
647+ <request name="destroy" type="destructor">
648+ <description summary="destroy the xdg_toplevel">
649+ This request destroys the role surface and unmaps the surface;
650+ see "Unmapping" behavior in interface section for details.
651+ </description>
652+ </request>
653+
654+ <enum name="error">
655+ <entry name="invalid_resize_edge" value="0" summary="provided value is
656+ not a valid variant of the resize_edge enum"/>
657+ <entry name="invalid_parent" value="1"
658+ summary="invalid parent toplevel"/>
659+ <entry name="invalid_size" value="2"
660+ summary="client provided an invalid min or max size"/>
661+ </enum>
662+
663+ <request name="set_parent">
664+ <description summary="set the parent of this surface">
665+ Set the "parent" of this surface. This surface should be stacked
666+ above the parent surface and all other ancestor surfaces.
667+
668+ Parent surfaces should be set on dialogs, toolboxes, or other
669+ "auxiliary" surfaces, so that the parent is raised when the dialog
670+ is raised.
671+
672+ Setting a null parent for a child surface unsets its parent. Setting
673+ a null parent for a surface which currently has no parent is a no-op.
674+
675+ Only mapped surfaces can have child surfaces. Setting a parent which
676+ is not mapped is equivalent to setting a null parent. If a surface
677+ becomes unmapped, its children's parent is set to the parent of
678+ the now-unmapped surface. If the now-unmapped surface has no parent,
679+ its children's parent is unset. If the now-unmapped surface becomes
680+ mapped again, its parent-child relationship is not restored.
681+
682+ The parent toplevel must not be one of the child toplevel's
683+ descendants, and the parent must be different from the child toplevel,
684+ otherwise the invalid_parent protocol error is raised.
685+ </description>
686+ <arg name="parent" type="object" interface="xdg_toplevel" allow-null="true" summary="parent surface for this surface"/>
687+ </request>
688+
689+ <request name="set_title">
690+ <description summary="set surface title">
691+ Set a short title for the surface.
692+
693+ This string may be used to identify the surface in a task bar,
694+ window list, or other user interface elements provided by the
695+ compositor.
696+
697+ The string must be encoded in UTF-8.
698+ </description>
699+ <arg name="title" type="string" summary="title of the surface"/>
700+ </request>
701+
702+ <request name="set_app_id">
703+ <description summary="set application ID">
704+ Set an application identifier for the surface.
705+
706+ The app ID identifies the general class of applications to which
707+ the surface belongs. The compositor can use this to group multiple
708+ surfaces together, or to determine how to launch a new application.
709+
710+ For D-Bus activatable applications, the app ID is used as the D-Bus
711+ service name.
712+
713+ The compositor shell will try to group application surfaces together
714+ by their app ID. As a best practice, it is suggested to select app
715+ ID's that match the basename of the application's .desktop file.
716+ For example, "org.freedesktop.FooViewer" where the .desktop file is
717+ "org.freedesktop.FooViewer.desktop".
718+
719+ Like other properties, a set_app_id request can be sent after the
720+ xdg_toplevel has been mapped to update the property.
721+
722+ See the desktop-entry specification [0] for more details on
723+ application identifiers and how they relate to well-known D-Bus
724+ names and .desktop files.
725+
726+ [0] https://standards.freedesktop.org/desktop-entry-spec/
727+ </description>
728+ <arg name="app_id" type="string" summary="application identifier surface belongs to"/>
729+ </request>
730+
731+ <request name="show_window_menu">
732+ <description summary="show the window menu">
733+ Clients implementing client-side decorations might want to show
734+ a context menu when right-clicking on the decorations, giving the
735+ user a menu that they can use to maximize or minimize the window.
736+
737+ This request asks the compositor to pop up such a window menu at
738+ the given position, relative to the local surface coordinates of
739+ the parent surface. There are no guarantees as to what menu items
740+ the window menu contains, or even if a window menu will be drawn
741+ at all.
742+
743+ This request must be used in response to some sort of user action
744+ like a button press, key press, or touch down event.
745+ </description>
746+ <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
747+ <arg name="serial" type="uint" summary="the serial of the user event"/>
748+ <arg name="x" type="int" summary="the x position to pop up the window menu at"/>
749+ <arg name="y" type="int" summary="the y position to pop up the window menu at"/>
750+ </request>
751+
752+ <request name="move">
753+ <description summary="start an interactive move">
754+ Start an interactive, user-driven move of the surface.
755+
756+ This request must be used in response to some sort of user action
757+ like a button press, key press, or touch down event. The passed
758+ serial is used to determine the type of interactive move (touch,
759+ pointer, etc).
760+
761+ The server may ignore move requests depending on the state of
762+ the surface (e.g. fullscreen or maximized), or if the passed serial
763+ is no longer valid.
764+
765+ If triggered, the surface will lose the focus of the device
766+ (wl_pointer, wl_touch, etc) used for the move. It is up to the
767+ compositor to visually indicate that the move is taking place, such as
768+ updating a pointer cursor, during the move. There is no guarantee
769+ that the device focus will return when the move is completed.
770+ </description>
771+ <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
772+ <arg name="serial" type="uint" summary="the serial of the user event"/>
773+ </request>
774+
775+ <enum name="resize_edge">
776+ <description summary="edge values for resizing">
777+ These values are used to indicate which edge of a surface
778+ is being dragged in a resize operation.
779+ </description>
780+ <entry name="none" value="0"/>
781+ <entry name="top" value="1"/>
782+ <entry name="bottom" value="2"/>
783+ <entry name="left" value="4"/>
784+ <entry name="top_left" value="5"/>
785+ <entry name="bottom_left" value="6"/>
786+ <entry name="right" value="8"/>
787+ <entry name="top_right" value="9"/>
788+ <entry name="bottom_right" value="10"/>
789+ </enum>
790+
791+ <request name="resize">
792+ <description summary="start an interactive resize">
793+ Start a user-driven, interactive resize of the surface.
794+
795+ This request must be used in response to some sort of user action
796+ like a button press, key press, or touch down event. The passed
797+ serial is used to determine the type of interactive resize (touch,
798+ pointer, etc).
799+
800+ The server may ignore resize requests depending on the state of
801+ the surface (e.g. fullscreen or maximized).
802+
803+ If triggered, the client will receive configure events with the
804+ "resize" state enum value and the expected sizes. See the "resize"
805+ enum value for more details about what is required. The client
806+ must also acknowledge configure events using "ack_configure". After
807+ the resize is completed, the client will receive another "configure"
808+ event without the resize state.
809+
810+ If triggered, the surface also will lose the focus of the device
811+ (wl_pointer, wl_touch, etc) used for the resize. It is up to the
812+ compositor to visually indicate that the resize is taking place,
813+ such as updating a pointer cursor, during the resize. There is no
814+ guarantee that the device focus will return when the resize is
815+ completed.
816+
817+ The edges parameter specifies how the surface should be resized, and
818+ is one of the values of the resize_edge enum. Values not matching
819+ a variant of the enum will cause the invalid_resize_edge protocol error.
820+ The compositor may use this information to update the surface position
821+ for example when dragging the top left corner. The compositor may also
822+ use this information to adapt its behavior, e.g. choose an appropriate
823+ cursor image.
824+ </description>
825+ <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
826+ <arg name="serial" type="uint" summary="the serial of the user event"/>
827+ <arg name="edges" type="uint" enum="resize_edge" summary="which edge or corner is being dragged"/>
828+ </request>
829+
830+ <enum name="state">
831+ <description summary="types of state on the surface">
832+ The different state values used on the surface. This is designed for
833+ state values like maximized, fullscreen. It is paired with the
834+ configure event to ensure that both the client and the compositor
835+ setting the state can be synchronized.
836+
837+ States set in this way are double-buffered, see wl_surface.commit.
838+ </description>
839+ <entry name="maximized" value="1" summary="the surface is maximized">
840+ <description summary="the surface is maximized">
841+ The surface is maximized. The window geometry specified in the configure
842+ event must be obeyed by the client, or the xdg_wm_base.invalid_surface_state
843+ error is raised.
844+
845+ The client should draw without shadow or other
846+ decoration outside of the window geometry.
847+ </description>
848+ </entry>
849+ <entry name="fullscreen" value="2" summary="the surface is fullscreen">
850+ <description summary="the surface is fullscreen">
851+ The surface is fullscreen. The window geometry specified in the
852+ configure event is a maximum; the client cannot resize beyond it. For
853+ a surface to cover the whole fullscreened area, the geometry
854+ dimensions must be obeyed by the client. For more details, see
855+ xdg_toplevel.set_fullscreen.
856+ </description>
857+ </entry>
858+ <entry name="resizing" value="3" summary="the surface is being resized">
859+ <description summary="the surface is being resized">
860+ The surface is being resized. The window geometry specified in the
861+ configure event is a maximum; the client cannot resize beyond it.
862+ Clients that have aspect ratio or cell sizing configuration can use
863+ a smaller size, however.
864+ </description>
865+ </entry>
866+ <entry name="activated" value="4" summary="the surface is now activated">
867+ <description summary="the surface is now activated">
868+ Client window decorations should be painted as if the window is
869+ active. Do not assume this means that the window actually has
870+ keyboard or pointer focus.
871+ </description>
872+ </entry>
873+ <entry name="tiled_left" value="5" since="2">
874+ <description summary="the surface’s left edge is tiled">
875+ The window is currently in a tiled layout and the left edge is
876+ considered to be adjacent to another part of the tiling grid.
877+
878+ The client should draw without shadow or other decoration outside of
879+ the window geometry on the left edge.
880+ </description>
881+ </entry>
882+ <entry name="tiled_right" value="6" since="2">
883+ <description summary="the surface’s right edge is tiled">
884+ The window is currently in a tiled layout and the right edge is
885+ considered to be adjacent to another part of the tiling grid.
886+
887+ The client should draw without shadow or other decoration outside of
888+ the window geometry on the right edge.
889+ </description>
890+ </entry>
891+ <entry name="tiled_top" value="7" since="2">
892+ <description summary="the surface’s top edge is tiled">
893+ The window is currently in a tiled layout and the top edge is
894+ considered to be adjacent to another part of the tiling grid.
895+
896+ The client should draw without shadow or other decoration outside of
897+ the window geometry on the top edge.
898+ </description>
899+ </entry>
900+ <entry name="tiled_bottom" value="8" since="2">
901+ <description summary="the surface’s bottom edge is tiled">
902+ The window is currently in a tiled layout and the bottom edge is
903+ considered to be adjacent to another part of the tiling grid.
904+
905+ The client should draw without shadow or other decoration outside of
906+ the window geometry on the bottom edge.
907+ </description>
908+ </entry>
909+ <entry name="suspended" value="9" since="6">
910+ <description summary="surface repaint is suspended">
911+ The surface is currently not ordinarily being repainted; for
912+ example because its content is occluded by another window, or its
913+ outputs are switched off due to screen locking.
914+ </description>
915+ </entry>
916+ <entry name="constrained_left" value="10" since="7">
917+ <description summary="the surface’s left edge is constrained">
918+ The left edge of the window is currently constrained, meaning it
919+ shouldn't attempt to resize from that edge. It can for example mean
920+ it's tiled next to a monitor edge on the constrained side of the
921+ window.
922+ </description>
923+ </entry>
924+ <entry name="constrained_right" value="11" since="7">
925+ <description summary="the surface’s right edge is constrained">
926+ The right edge of the window is currently constrained, meaning it
927+ shouldn't attempt to resize from that edge. It can for example mean
928+ it's tiled next to a monitor edge on the constrained side of the
929+ window.
930+ </description>
931+ </entry>
932+ <entry name="constrained_top" value="12" since="7">
933+ <description summary="the surface’s top edge is constrained">
934+ The top edge of the window is currently constrained, meaning it
935+ shouldn't attempt to resize from that edge. It can for example mean
936+ it's tiled next to a monitor edge on the constrained side of the
937+ window.
938+ </description>
939+ </entry>
940+ <entry name="constrained_bottom" value="13" since="7">
941+ <description summary="the surface’s bottom edge is constrained">
942+ The bottom edge of the window is currently constrained, meaning it
943+ shouldn't attempt to resize from that edge. It can for example mean
944+ it's tiled next to a monitor edge on the constrained side of the
945+ window.
946+ </description>
947+ </entry>
948+ </enum>
949+
950+ <request name="set_max_size">
951+ <description summary="set the maximum size">
952+ Set a maximum size for the window.
953+
954+ The client can specify a maximum size so that the compositor does
955+ not try to configure the window beyond this size.
956+
957+ The width and height arguments are in window geometry coordinates.
958+ See xdg_surface.set_window_geometry.
959+
960+ Values set in this way are double-buffered, see wl_surface.commit.
961+
962+ The compositor can use this information to allow or disallow
963+ different states like maximize or fullscreen and draw accurate
964+ animations.
965+
966+ Similarly, a tiling window manager may use this information to
967+ place and resize client windows in a more effective way.
968+
969+ The client should not rely on the compositor to obey the maximum
970+ size. The compositor may decide to ignore the values set by the
971+ client and request a larger size.
972+
973+ If never set, or a value of zero in the request, means that the
974+ client has no expected maximum size in the given dimension.
975+ As a result, a client wishing to reset the maximum size
976+ to an unspecified state can use zero for width and height in the
977+ request.
978+
979+ Requesting a maximum size to be smaller than the minimum size of
980+ a surface is illegal and will result in an invalid_size error.
981+
982+ The width and height must be greater than or equal to zero. Using
983+ strictly negative values for width or height will result in an
984+ invalid_size error.
985+ </description>
986+ <arg name="width" type="int" summary="maximum width of the window"/>
987+ <arg name="height" type="int" summary="maximum height of the window"/>
988+ </request>
989+
990+ <request name="set_min_size">
991+ <description summary="set the minimum size">
992+ Set a minimum size for the window.
993+
994+ The client can specify a minimum size so that the compositor does
995+ not try to configure the window below this size.
996+
997+ The width and height arguments are in window geometry coordinates.
998+ See xdg_surface.set_window_geometry.
999+
1000+ Values set in this way are double-buffered, see wl_surface.commit.
1001+
1002+ The compositor can use this information to allow or disallow
1003+ different states like maximize or fullscreen and draw accurate
1004+ animations.
1005+
1006+ Similarly, a tiling window manager may use this information to
1007+ place and resize client windows in a more effective way.
1008+
1009+ The client should not rely on the compositor to obey the minimum
1010+ size. The compositor may decide to ignore the values set by the
1011+ client and request a smaller size.
1012+
1013+ If never set, or a value of zero in the request, means that the
1014+ client has no expected minimum size in the given dimension.
1015+ As a result, a client wishing to reset the minimum size
1016+ to an unspecified state can use zero for width and height in the
1017+ request.
1018+
1019+ Requesting a minimum size to be larger than the maximum size of
1020+ a surface is illegal and will result in an invalid_size error.
1021+
1022+ The width and height must be greater than or equal to zero. Using
1023+ strictly negative values for width and height will result in an
1024+ invalid_size error.
1025+ </description>
1026+ <arg name="width" type="int" summary="minimum width of the window"/>
1027+ <arg name="height" type="int" summary="minimum height of the window"/>
1028+ </request>
1029+
1030+ <request name="set_maximized">
1031+ <description summary="maximize the window">
1032+ Maximize the surface.
1033+
1034+ After requesting that the surface should be maximized, the compositor
1035+ will respond by emitting a configure event. Whether this configure
1036+ actually sets the window maximized is subject to compositor policies.
1037+ The client must then update its content, drawing in the configured
1038+ state. The client must also acknowledge the configure when committing
1039+ the new content (see ack_configure).
1040+
1041+ It is up to the compositor to decide how and where to maximize the
1042+ surface, for example which output and what region of the screen should
1043+ be used.
1044+
1045+ If the surface was already maximized, the compositor will still emit
1046+ a configure event with the "maximized" state.
1047+
1048+ If the surface is in a fullscreen state, this request has no direct
1049+ effect. It may alter the state the surface is returned to when
1050+ unmaximized unless overridden by the compositor.
1051+ </description>
1052+ </request>
1053+
1054+ <request name="unset_maximized">
1055+ <description summary="unmaximize the window">
1056+ Unmaximize the surface.
1057+
1058+ After requesting that the surface should be unmaximized, the compositor
1059+ will respond by emitting a configure event. Whether this actually
1060+ un-maximizes the window is subject to compositor policies.
1061+ If available and applicable, the compositor will include the window
1062+ geometry dimensions the window had prior to being maximized in the
1063+ configure event. The client must then update its content, drawing it in
1064+ the configured state. The client must also acknowledge the configure
1065+ when committing the new content (see ack_configure).
1066+
1067+ It is up to the compositor to position the surface after it was
1068+ unmaximized; usually the position the surface had before maximizing, if
1069+ applicable.
1070+
1071+ If the surface was already not maximized, the compositor will still
1072+ emit a configure event without the "maximized" state.
1073+
1074+ If the surface is in a fullscreen state, this request has no direct
1075+ effect. It may alter the state the surface is returned to when
1076+ unmaximized unless overridden by the compositor.
1077+ </description>
1078+ </request>
1079+
1080+ <request name="set_fullscreen">
1081+ <description summary="set the window as fullscreen on an output">
1082+ Make the surface fullscreen.
1083+
1084+ After requesting that the surface should be fullscreened, the
1085+ compositor will respond by emitting a configure event. Whether the
1086+ client is actually put into a fullscreen state is subject to compositor
1087+ policies. The client must also acknowledge the configure when
1088+ committing the new content (see ack_configure).
1089+
1090+ The output passed by the request indicates the client's preference as
1091+ to which display it should be set fullscreen on. If this value is NULL,
1092+ it's up to the compositor to choose which display will be used to map
1093+ this surface.
1094+
1095+ If the surface doesn't cover the whole output, the compositor will
1096+ position the surface in the center of the output and compensate with
1097+ border fill covering the rest of the output. The content of the
1098+ border fill is undefined, but should be assumed to be in some way that
1099+ attempts to blend into the surrounding area (e.g. solid black).
1100+
1101+ If the fullscreened surface is not opaque, the compositor must make
1102+ sure that other screen content not part of the same surface tree (made
1103+ up of subsurfaces, popups or similarly coupled surfaces) are not
1104+ visible below the fullscreened surface.
1105+ </description>
1106+ <arg name="output" type="object" interface="wl_output" allow-null="true" summary="preferred output to place surface on"/>
1107+ </request>
1108+
1109+ <request name="unset_fullscreen">
1110+ <description summary="unset the window as fullscreen">
1111+ Make the surface no longer fullscreen.
1112+
1113+ After requesting that the surface should be unfullscreened, the
1114+ compositor will respond by emitting a configure event.
1115+ Whether this actually removes the fullscreen state of the client is
1116+ subject to compositor policies.
1117+
1118+ Making a surface unfullscreen sets states for the surface based on the following:
1119+ * the state(s) it may have had before becoming fullscreen
1120+ * any state(s) decided by the compositor
1121+ * any state(s) requested by the client while the surface was fullscreen
1122+
1123+ The compositor may include the previous window geometry dimensions in
1124+ the configure event, if applicable.
1125+
1126+ The client must also acknowledge the configure when committing the new
1127+ content (see ack_configure).
1128+ </description>
1129+ </request>
1130+
1131+ <request name="set_minimized">
1132+ <description summary="set the window as minimized">
1133+ Request that the compositor minimize your surface. There is no
1134+ way to know if the surface is currently minimized, nor is there
1135+ any way to unset minimization on this surface.
1136+
1137+ If you are looking to throttle redrawing when minimized, please
1138+ instead use the wl_surface.frame event for this, as this will
1139+ also work with live previews on windows in Alt-Tab, Expose or
1140+ similar compositor features.
1141+ </description>
1142+ </request>
1143+
1144+ <event name="configure">
1145+ <description summary="suggest a surface change">
1146+ This configure event asks the client to resize its toplevel surface or
1147+ to change its state. The configured state should not be applied
1148+ immediately. See xdg_surface.configure for details.
1149+
1150+ The width and height arguments specify a hint to the window
1151+ about how its surface should be resized in window geometry
1152+ coordinates. See set_window_geometry.
1153+
1154+ If the width or height arguments are zero, it means the client
1155+ should decide its own window dimension. This may happen when the
1156+ compositor needs to configure the state of the surface but doesn't
1157+ have any information about any previous or expected dimension.
1158+
1159+ The states listed in the event specify how the width/height
1160+ arguments should be interpreted, and possibly how it should be
1161+ drawn.
1162+
1163+ The states are sent as an array of 32-bit unsigned integers in
1164+ native endianness. State values are defined in the state enum.
1165+
1166+ Clients must send an ack_configure in response to this event. See
1167+ xdg_surface.configure and xdg_surface.ack_configure for details.
1168+ </description>
1169+ <arg name="width" type="int" summary="suggested width of window"/>
1170+ <arg name="height" type="int" summary="suggested height of window"/>
1171+ <arg name="states" type="array" summary="suggested states of the window"/>
1172+ </event>
1173+
1174+ <event name="close">
1175+ <description summary="surface wants to be closed">
1176+ The close event is sent by the compositor when the user
1177+ wants the surface to be closed. This should be equivalent to
1178+ the user clicking the close button in client-side decorations,
1179+ if your application has any.
1180+
1181+ This is only a request that the user intends to close the
1182+ window. The client may choose to ignore this request, or show
1183+ a dialog to ask the user to save their data, etc.
1184+ </description>
1185+ </event>
1186+
1187+ <!-- Version 4 additions -->
1188+
1189+ <event name="configure_bounds" since="4">
1190+ <description summary="recommended window geometry bounds">
1191+ The configure_bounds event may be sent prior to a xdg_toplevel.configure
1192+ event to communicate the bounds a window geometry size is recommended
1193+ to constrain to.
1194+
1195+ The passed width and height are in surface coordinate space. If width
1196+ and height are 0, it means bounds is unknown and equivalent to as if no
1197+ configure_bounds event was ever sent for this surface.
1198+
1199+ The bounds can for example correspond to the size of a monitor excluding
1200+ any panels or other shell components, so that a surface isn't created in
1201+ a way that it cannot fit.
1202+
1203+ The bounds may change at any point, and in such a case, a new
1204+ xdg_toplevel.configure_bounds will be sent, followed by
1205+ xdg_toplevel.configure and xdg_surface.configure.
1206+ </description>
1207+ <arg name="width" type="int" summary="suggested maximum width of surface"/>
1208+ <arg name="height" type="int" summary="suggested maximum height of surface"/>
1209+ </event>
1210+
1211+ <!-- Version 5 additions -->
1212+
1213+ <enum name="wm_capabilities" since="5">
1214+ <entry name="window_menu" value="1" summary="show_window_menu is available"/>
1215+ <entry name="maximize" value="2" summary="set_maximized and unset_maximized are available"/>
1216+ <entry name="fullscreen" value="3" summary="set_fullscreen and unset_fullscreen are available"/>
1217+ <entry name="minimize" value="4" summary="set_minimized is available"/>
1218+ </enum>
1219+
1220+ <event name="wm_capabilities" since="5">
1221+ <description summary="compositor capabilities">
1222+ This event advertises the capabilities supported by the compositor. If
1223+ a capability isn't supported, clients should hide or disable the UI
1224+ elements that expose this functionality. For instance, if the
1225+ compositor doesn't advertise support for minimized toplevels, a button
1226+ triggering the set_minimized request should not be displayed.
1227+
1228+ The compositor will ignore requests it doesn't support. For instance,
1229+ a compositor which doesn't advertise support for minimized will ignore
1230+ set_minimized requests.
1231+
1232+ Compositors must send this event once before the first
1233+ xdg_surface.configure event. When the capabilities change, compositors
1234+ must send this event again and then send an xdg_surface.configure
1235+ event.
1236+
1237+ The configured state should not be applied immediately. See
1238+ xdg_surface.configure for details.
1239+
1240+ The capabilities are sent as an array of 32-bit unsigned integers in
1241+ native endianness. Capability values are defined in the wm_capabilities enum.
1242+ </description>
1243+ <arg name="capabilities" type="array" summary="array of 32-bit capabilities"/>
1244+ </event>
1245+ </interface>
1246+
1247+ <interface name="xdg_popup" version="7">
1248+ <description summary="short-lived, popup surfaces for menus">
1249+ A popup surface is a short-lived, temporary surface. It can be used to
1250+ implement for example menus, popovers, tooltips and other similar user
1251+ interface concepts.
1252+
1253+ A popup can be made to take an explicit grab. See xdg_popup.grab for
1254+ details.
1255+
1256+ When the popup is dismissed, a popup_done event will be sent out, and at
1257+ the same time the surface will be unmapped. See the xdg_popup.popup_done
1258+ event for details.
1259+
1260+ Explicitly destroying the xdg_popup object will also dismiss the popup and
1261+ unmap the surface. Clients that want to dismiss the popup when another
1262+ surface of their own is clicked should dismiss the popup using the destroy
1263+ request.
1264+
1265+ A newly created xdg_popup will be stacked on top of all previously created
1266+ xdg_popup surfaces associated with the same xdg_toplevel.
1267+
1268+ The parent of an xdg_popup must be mapped (see the xdg_surface
1269+ description) before the xdg_popup itself.
1270+
1271+ The client must call wl_surface.commit on the corresponding wl_surface
1272+ for the xdg_popup state to take effect.
1273+ </description>
1274+
1275+ <enum name="error">
1276+ <entry name="invalid_grab" value="0"
1277+ summary="tried to grab after being mapped"/>
1278+ </enum>
1279+
1280+ <request name="destroy" type="destructor">
1281+ <description summary="remove xdg_popup interface">
1282+ This destroys the popup. Explicitly destroying the xdg_popup
1283+ object will also dismiss the popup, and unmap the surface.
1284+
1285+ If this xdg_popup is not the "topmost" popup, the
1286+ xdg_wm_base.not_the_topmost_popup protocol error will be sent.
1287+ </description>
1288+ </request>
1289+
1290+ <request name="grab">
1291+ <description summary="make the popup take an explicit grab">
1292+ This request makes the created popup take an explicit grab. An explicit
1293+ grab will be dismissed when the user dismisses the popup, or when the
1294+ client destroys the xdg_popup. This can be done by the user clicking
1295+ outside the surface, using the keyboard, or even locking the screen
1296+ through closing the lid or a timeout.
1297+
1298+ If the compositor denies the grab, the popup will be immediately
1299+ dismissed.
1300+
1301+ This request must be used in response to some sort of user action like a
1302+ button press, key press, or touch down event. The serial number of the
1303+ event should be passed as 'serial'.
1304+
1305+ The parent of a grabbing popup must either be an xdg_toplevel surface or
1306+ another xdg_popup with an explicit grab. If the parent is another
1307+ xdg_popup it means that the popups are nested, with this popup now being
1308+ the topmost popup.
1309+
1310+ Nested popups must be destroyed in the reverse order they were created
1311+ in, e.g. the only popup you are allowed to destroy at all times is the
1312+ topmost one.
1313+
1314+ When compositors choose to dismiss a popup, they may dismiss every
1315+ nested grabbing popup as well. When a compositor dismisses popups, it
1316+ will follow the same dismissing order as required from the client.
1317+
1318+ If the topmost grabbing popup is destroyed, the grab will be returned to
1319+ the parent of the popup, if that parent previously had an explicit grab.
1320+
1321+ If the parent is a grabbing popup which has already been dismissed, this
1322+ popup will be immediately dismissed. If the parent is a popup that did
1323+ not take an explicit grab, an error will be raised.
1324+
1325+ During a popup grab, the client owning the grab will receive pointer
1326+ and touch events for all their surfaces as normal (similar to an
1327+ "owner-events" grab in X11 parlance), while the top most grabbing popup
1328+ will always have keyboard focus.
1329+ </description>
1330+ <arg name="seat" type="object" interface="wl_seat"
1331+ summary="the wl_seat of the user event"/>
1332+ <arg name="serial" type="uint" summary="the serial of the user event"/>
1333+ </request>
1334+
1335+ <event name="configure">
1336+ <description summary="configure the popup surface">
1337+ This event asks the popup surface to configure itself given the
1338+ configuration. The configured state should not be applied immediately.
1339+ See xdg_surface.configure for details.
1340+
1341+ The x and y arguments represent the position the popup was placed at
1342+ given the xdg_positioner rule, relative to the upper left corner of the
1343+ window geometry of the parent surface.
1344+
1345+ For version 2 or older, the configure event for an xdg_popup is only
1346+ ever sent once for the initial configuration. Starting with version 3,
1347+ it may be sent again if the popup is setup with an xdg_positioner with
1348+ set_reactive requested, or in response to xdg_popup.reposition requests.
1349+ </description>
1350+ <arg name="x" type="int"
1351+ summary="x position relative to parent surface window geometry"/>
1352+ <arg name="y" type="int"
1353+ summary="y position relative to parent surface window geometry"/>
1354+ <arg name="width" type="int" summary="window geometry width"/>
1355+ <arg name="height" type="int" summary="window geometry height"/>
1356+ </event>
1357+
1358+ <event name="popup_done">
1359+ <description summary="popup interaction is done">
1360+ The popup_done event is sent out when a popup is dismissed by the
1361+ compositor. The client should destroy the xdg_popup object at this
1362+ point.
1363+ </description>
1364+ </event>
1365+
1366+ <!-- Version 3 additions -->
1367+
1368+ <request name="reposition" since="3">
1369+ <description summary="recalculate the popup's location">
1370+ Reposition an already-mapped popup. The popup will be placed given the
1371+ details in the passed xdg_positioner object, and a
1372+ xdg_popup.repositioned followed by xdg_popup.configure and
1373+ xdg_surface.configure will be emitted in response. Any parameters set
1374+ by the previous positioner will be discarded.
1375+
1376+ The passed token will be sent in the corresponding
1377+ xdg_popup.repositioned event. The new popup position will not take
1378+ effect until the corresponding configure event is acknowledged by the
1379+ client. See xdg_popup.repositioned for details. The token itself is
1380+ opaque, and has no other special meaning.
1381+
1382+ If multiple reposition requests are sent, the compositor may skip all
1383+ but the last one.
1384+
1385+ If the popup is repositioned in response to a configure event for its
1386+ parent, the client should send an xdg_positioner.set_parent_configure
1387+ and possibly an xdg_positioner.set_parent_size request to allow the
1388+ compositor to properly constrain the popup.
1389+
1390+ If the popup is repositioned together with a parent that is being
1391+ resized, but not in response to a configure event, the client should
1392+ send an xdg_positioner.set_parent_size request.
1393+ </description>
1394+ <arg name="positioner" type="object" interface="xdg_positioner"/>
1395+ <arg name="token" type="uint" summary="reposition request token"/>
1396+ </request>
1397+
1398+ <event name="repositioned" since="3">
1399+ <description summary="signal the completion of a repositioned request">
1400+ The repositioned event is sent as part of a popup configuration
1401+ sequence, together with xdg_popup.configure and lastly
1402+ xdg_surface.configure to notify the completion of a reposition request.
1403+
1404+ The repositioned event is to notify about the completion of a
1405+ xdg_popup.reposition request. The token argument is the token passed
1406+ in the xdg_popup.reposition request.
1407+
1408+ Immediately after this event is emitted, xdg_popup.configure and
1409+ xdg_surface.configure will be sent with the updated size and position,
1410+ as well as a new configure serial.
1411+
1412+ The client should optionally update the content of the popup, but must
1413+ acknowledge the new popup configuration for the new position to take
1414+ effect. See xdg_surface.ack_configure for details.
1415+ </description>
1416+ <arg name="token" type="uint" summary="reposition request token"/>
1417+ </event>
1418+
1419+ </interface>
1420+</protocol>
A protocol/xdgshell/xdg-shell_generated.go +1136 -0
@@ -0,0 +1,1136 @@
1+// Code generated by wlturbo-scanner. DO NOT EDIT.
2+// Protocol: xdg_shell
3+// Source: xdg-shell.xml
4+
5+package xdgshell
6+
7+import (
8+ "sync"
9+
10+ cross_wl_output "github.com/bnema/wlturbo/protocol/core"
11+ cross_wl_seat "github.com/bnema/wlturbo/protocol/core"
12+ cross_wl_surface "github.com/bnema/wlturbo/protocol/core"
13+ "github.com/bnema/wlturbo/wl"
14+)
15+
16+// ERROR_ROLE is the error role value.
17+const ERROR_ROLE = 0
18+
19+// ERROR_DEFUNCT_SURFACES is the error defunct_surfaces value.
20+const ERROR_DEFUNCT_SURFACES = 1
21+
22+// ERROR_NOT_THE_TOPMOST_POPUP is the error not_the_topmost_popup value.
23+const ERROR_NOT_THE_TOPMOST_POPUP = 2
24+
25+// ERROR_INVALID_POPUP_PARENT is the error invalid_popup_parent value.
26+const ERROR_INVALID_POPUP_PARENT = 3
27+
28+// ERROR_INVALID_SURFACE_STATE is the error invalid_surface_state value.
29+const ERROR_INVALID_SURFACE_STATE = 4
30+
31+// ERROR_INVALID_POSITIONER is the error invalid_positioner value.
32+const ERROR_INVALID_POSITIONER = 5
33+
34+// ERROR_UNRESPONSIVE is the error unresponsive value.
35+const ERROR_UNRESPONSIVE = 6
36+
37+// ERROR_INVALID_INPUT is the error invalid_input value.
38+const ERROR_INVALID_INPUT = 0
39+
40+// ANCHOR_NONE is the anchor none value.
41+const ANCHOR_NONE = 0
42+
43+// ANCHOR_TOP is the anchor top value.
44+const ANCHOR_TOP = 1
45+
46+// ANCHOR_BOTTOM is the anchor bottom value.
47+const ANCHOR_BOTTOM = 2
48+
49+// ANCHOR_LEFT is the anchor left value.
50+const ANCHOR_LEFT = 3
51+
52+// ANCHOR_RIGHT is the anchor right value.
53+const ANCHOR_RIGHT = 4
54+
55+// ANCHOR_TOP_LEFT is the anchor top_left value.
56+const ANCHOR_TOP_LEFT = 5
57+
58+// ANCHOR_BOTTOM_LEFT is the anchor bottom_left value.
59+const ANCHOR_BOTTOM_LEFT = 6
60+
61+// ANCHOR_TOP_RIGHT is the anchor top_right value.
62+const ANCHOR_TOP_RIGHT = 7
63+
64+// ANCHOR_BOTTOM_RIGHT is the anchor bottom_right value.
65+const ANCHOR_BOTTOM_RIGHT = 8
66+
67+// GRAVITY_NONE is the gravity none value.
68+const GRAVITY_NONE = 0
69+
70+// GRAVITY_TOP is the gravity top value.
71+const GRAVITY_TOP = 1
72+
73+// GRAVITY_BOTTOM is the gravity bottom value.
74+const GRAVITY_BOTTOM = 2
75+
76+// GRAVITY_LEFT is the gravity left value.
77+const GRAVITY_LEFT = 3
78+
79+// GRAVITY_RIGHT is the gravity right value.
80+const GRAVITY_RIGHT = 4
81+
82+// GRAVITY_TOP_LEFT is the gravity top_left value.
83+const GRAVITY_TOP_LEFT = 5
84+
85+// GRAVITY_BOTTOM_LEFT is the gravity bottom_left value.
86+const GRAVITY_BOTTOM_LEFT = 6
87+
88+// GRAVITY_TOP_RIGHT is the gravity top_right value.
89+const GRAVITY_TOP_RIGHT = 7
90+
91+// GRAVITY_BOTTOM_RIGHT is the gravity bottom_right value.
92+const GRAVITY_BOTTOM_RIGHT = 8
93+
94+// CONSTRAINT_ADJUSTMENT_NONE is the constraint_adjustment none value.
95+const CONSTRAINT_ADJUSTMENT_NONE = 0
96+
97+// CONSTRAINT_ADJUSTMENT_SLIDE_X is the constraint_adjustment slide_x value.
98+const CONSTRAINT_ADJUSTMENT_SLIDE_X = 1
99+
100+// CONSTRAINT_ADJUSTMENT_SLIDE_Y is the constraint_adjustment slide_y value.
101+const CONSTRAINT_ADJUSTMENT_SLIDE_Y = 2
102+
103+// CONSTRAINT_ADJUSTMENT_FLIP_X is the constraint_adjustment flip_x value.
104+const CONSTRAINT_ADJUSTMENT_FLIP_X = 4
105+
106+// CONSTRAINT_ADJUSTMENT_FLIP_Y is the constraint_adjustment flip_y value.
107+const CONSTRAINT_ADJUSTMENT_FLIP_Y = 8
108+
109+// CONSTRAINT_ADJUSTMENT_RESIZE_X is the constraint_adjustment resize_x value.
110+const CONSTRAINT_ADJUSTMENT_RESIZE_X = 16
111+
112+// CONSTRAINT_ADJUSTMENT_RESIZE_Y is the constraint_adjustment resize_y value.
113+const CONSTRAINT_ADJUSTMENT_RESIZE_Y = 32
114+
115+// ERROR_NOT_CONSTRUCTED is the error not_constructed value.
116+const ERROR_NOT_CONSTRUCTED = 1
117+
118+// ERROR_ALREADY_CONSTRUCTED is the error already_constructed value.
119+const ERROR_ALREADY_CONSTRUCTED = 2
120+
121+// ERROR_UNCONFIGURED_BUFFER is the error unconfigured_buffer value.
122+const ERROR_UNCONFIGURED_BUFFER = 3
123+
124+// ERROR_INVALID_SERIAL is the error invalid_serial value.
125+const ERROR_INVALID_SERIAL = 4
126+
127+// XDG_SURFACE_ERROR_INVALID_SIZE is the error invalid_size value.
128+const XDG_SURFACE_ERROR_INVALID_SIZE = 5
129+
130+// ERROR_DEFUNCT_ROLE_OBJECT is the error defunct_role_object value.
131+const ERROR_DEFUNCT_ROLE_OBJECT = 6
132+
133+// ERROR_INVALID_RESIZE_EDGE is the error invalid_resize_edge value.
134+const ERROR_INVALID_RESIZE_EDGE = 0
135+
136+// ERROR_INVALID_PARENT is the error invalid_parent value.
137+const ERROR_INVALID_PARENT = 1
138+
139+// XDG_TOPLEVEL_ERROR_INVALID_SIZE is the error invalid_size value.
140+const XDG_TOPLEVEL_ERROR_INVALID_SIZE = 2
141+
142+// RESIZE_EDGE_NONE is the resize_edge none value.
143+const RESIZE_EDGE_NONE = 0
144+
145+// RESIZE_EDGE_TOP is the resize_edge top value.
146+const RESIZE_EDGE_TOP = 1
147+
148+// RESIZE_EDGE_BOTTOM is the resize_edge bottom value.
149+const RESIZE_EDGE_BOTTOM = 2
150+
151+// RESIZE_EDGE_LEFT is the resize_edge left value.
152+const RESIZE_EDGE_LEFT = 4
153+
154+// RESIZE_EDGE_TOP_LEFT is the resize_edge top_left value.
155+const RESIZE_EDGE_TOP_LEFT = 5
156+
157+// RESIZE_EDGE_BOTTOM_LEFT is the resize_edge bottom_left value.
158+const RESIZE_EDGE_BOTTOM_LEFT = 6
159+
160+// RESIZE_EDGE_RIGHT is the resize_edge right value.
161+const RESIZE_EDGE_RIGHT = 8
162+
163+// RESIZE_EDGE_TOP_RIGHT is the resize_edge top_right value.
164+const RESIZE_EDGE_TOP_RIGHT = 9
165+
166+// RESIZE_EDGE_BOTTOM_RIGHT is the resize_edge bottom_right value.
167+const RESIZE_EDGE_BOTTOM_RIGHT = 10
168+
169+// STATE_MAXIMIZED is the state maximized value.
170+const STATE_MAXIMIZED = 1
171+
172+// STATE_FULLSCREEN is the state fullscreen value.
173+const STATE_FULLSCREEN = 2
174+
175+// STATE_RESIZING is the state resizing value.
176+const STATE_RESIZING = 3
177+
178+// STATE_ACTIVATED is the state activated value.
179+const STATE_ACTIVATED = 4
180+
181+// STATE_TILED_LEFT is the state tiled_left value.
182+const STATE_TILED_LEFT = 5
183+
184+// STATE_TILED_RIGHT is the state tiled_right value.
185+const STATE_TILED_RIGHT = 6
186+
187+// STATE_TILED_TOP is the state tiled_top value.
188+const STATE_TILED_TOP = 7
189+
190+// STATE_TILED_BOTTOM is the state tiled_bottom value.
191+const STATE_TILED_BOTTOM = 8
192+
193+// STATE_SUSPENDED is the state suspended value.
194+const STATE_SUSPENDED = 9
195+
196+// STATE_CONSTRAINED_LEFT is the state constrained_left value.
197+const STATE_CONSTRAINED_LEFT = 10
198+
199+// STATE_CONSTRAINED_RIGHT is the state constrained_right value.
200+const STATE_CONSTRAINED_RIGHT = 11
201+
202+// STATE_CONSTRAINED_TOP is the state constrained_top value.
203+const STATE_CONSTRAINED_TOP = 12
204+
205+// STATE_CONSTRAINED_BOTTOM is the state constrained_bottom value.
206+const STATE_CONSTRAINED_BOTTOM = 13
207+
208+// WM_CAPABILITIES_WINDOW_MENU is the wm_capabilities window_menu value.
209+const WM_CAPABILITIES_WINDOW_MENU = 1
210+
211+// WM_CAPABILITIES_MAXIMIZE is the wm_capabilities maximize value.
212+const WM_CAPABILITIES_MAXIMIZE = 2
213+
214+// WM_CAPABILITIES_FULLSCREEN is the wm_capabilities fullscreen value.
215+const WM_CAPABILITIES_FULLSCREEN = 3
216+
217+// WM_CAPABILITIES_MINIMIZE is the wm_capabilities minimize value.
218+const WM_CAPABILITIES_MINIMIZE = 4
219+
220+// ERROR_INVALID_GRAB is the error invalid_grab value.
221+const ERROR_INVALID_GRAB = 0
222+
223+// XdgWmBaseInterface is the protocol interface name.
224+const XdgWmBaseInterface = "xdg_wm_base"
225+
226+// XdgWmBase is the generated binding for xdg_wm_base version 7.
227+type XdgWmBase 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+ onPing []func(serial uint32)
233+}
234+
235+// NewXdgWmBase returns an unbound XdgWmBase.
236+func NewXdgWmBase(ctx *wl.Context) *XdgWmBase {
237+ obj := &XdgWmBase{}
238+ obj.SetContext(ctx)
239+ ctx.Register(obj)
240+ return obj
241+}
242+
243+// Destroy this xdg_wm_base object. Destroying a bound xdg_wm_base object while there are surfaces still alive created by this xdg_wm_base object instance is illegal and will result in a defunct_surfaces error.
244+func (o *XdgWmBase) Destroy() error {
245+ if err := o.Context().CheckProxy(o); err != nil {
246+ return err
247+ }
248+ if err := o.Context().SendDestructor(o, 0); err != nil {
249+ return err
250+ }
251+ return nil
252+}
253+
254+// Create a positioner object. A positioner object is used to position surfaces relative to some parent surface. See the interface description and xdg_surface.get_popup for details.
255+func (o *XdgWmBase) CreatePositioner() (*XdgPositioner, error) {
256+ if err := o.Context().CheckProxy(o); err != nil {
257+ return nil, err
258+ }
259+ child := &XdgPositioner{}
260+ child.SetContext(o.Context())
261+ child.SetID(o.Context().AllocateID())
262+ o.Context().Register(child)
263+ if err := o.Context().SendRequest(o, 1, child); err != nil {
264+ o.Context().Unregister(child)
265+ return nil, err
266+ }
267+ return child, nil
268+}
269+
270+// This creates an xdg_surface for the given surface. An xdg_surface is used as basis to define a role to a given surface, such as xdg_toplevel or xdg_popup. It also manages functionality shared between xdg_surface based surface roles. While xdg_surface itself is not a role, the corresponding surface may only be assigned a role extending xdg_surface, such as xdg_toplevel or xdg_popup. It is illegal to create an xdg_surface for a wl_surface which already has anassigned role and this will result in a role error. See the documentation of xdg_surface for more details about what an xdg_surface is and how it is used.
271+func (o *XdgWmBase) GetXdgSurface(surface *cross_wl_surface.Surface) (*XdgSurface, error) {
272+ if err := o.Context().CheckProxy(o); err != nil {
273+ return nil, err
274+ }
275+ var arg1 wl.Object
276+ if surface != nil {
277+ arg1 = surface
278+ }
279+ child := &XdgSurface{}
280+ child.SetContext(o.Context())
281+ child.SetID(o.Context().AllocateID())
282+ o.Context().Register(child)
283+ if err := o.Context().SendRequest(o, 2, child, arg1); err != nil {
284+ o.Context().Unregister(child)
285+ return nil, err
286+ }
287+ return child, nil
288+}
289+
290+// A client must respond to a ping event with a pong request or the client may be deemed unresponsive. See xdg_wm_base.ping and xdg_wm_base.error.unresponsive.
291+func (o *XdgWmBase) Pong(serial uint32) error {
292+ if err := o.Context().CheckProxy(o); err != nil {
293+ return err
294+ }
295+ if err := o.Context().SendRequest(o, 3, serial); err != nil {
296+ return err
297+ }
298+ return nil
299+}
300+
301+// OnPing registers a handler for the ping event.
302+//
303+// Handlers are appended, so a second call adds another handler rather than
304+// replacing the first. Registration is safe while another goroutine dispatches.
305+func (o *XdgWmBase) OnPing(handler func(serial uint32)) {
306+ if handler == nil {
307+ return
308+ }
309+ o.handlersMu.Lock()
310+ defer o.handlersMu.Unlock()
311+ o.onPing = append(o.onPing, handler)
312+}
313+
314+// handlersForPing returns the handlers registered for ping, taken
315+// under the lock so a handler may register another handler while events are
316+// being dispatched.
317+func (o *XdgWmBase) handlersForPing() []func(serial uint32) {
318+ o.handlersMu.Lock()
319+ defer o.handlersMu.Unlock()
320+ return o.onPing
321+}
322+
323+// EventSignature returns the declared event argument types in wire order.
324+func (o *XdgWmBase) EventSignature(opcode uint16) (string, bool) {
325+ switch opcode {
326+ case 0:
327+ return "uint,", true
328+ default:
329+ return "", false
330+ }
331+}
332+
333+// Dispatch decodes one event on xdg_wm_base and calls the registered handlers.
334+func (o *XdgWmBase) Dispatch(event *wl.Event) {
335+ switch event.Opcode {
336+ case 0: // ping
337+ serial := event.Uint32()
338+
339+ for i, handler := range o.handlersForPing() {
340+ _ = i
341+ handler(serial)
342+ }
343+ default:
344+ }
345+}
346+
347+// XdgPositionerInterface is the protocol interface name.
348+const XdgPositionerInterface = "xdg_positioner"
349+
350+// XdgPositioner is the generated binding for xdg_positioner version 7.
351+type XdgPositioner struct {
352+ wl.BaseProxy
353+}
354+
355+// NewXdgPositioner returns an unbound XdgPositioner.
356+func NewXdgPositioner(ctx *wl.Context) *XdgPositioner {
357+ obj := &XdgPositioner{}
358+ obj.SetContext(ctx)
359+ ctx.Register(obj)
360+ return obj
361+}
362+
363+// Notify the compositor that the xdg_positioner will no longer be used.
364+func (o *XdgPositioner) Destroy() error {
365+ if err := o.Context().CheckProxy(o); err != nil {
366+ return err
367+ }
368+ if err := o.Context().SendDestructor(o, 0); err != nil {
369+ return err
370+ }
371+ return nil
372+}
373+
374+// Set the size of the surface that is to be positioned with the positioner object. The size is in surface-local coordinates and corresponds to the window geometry. See xdg_surface.set_window_geometry. If a zero or negative size is set the invalid_input error is raised.
375+func (o *XdgPositioner) SetSize(width int32, height int32) error {
376+ if err := o.Context().CheckProxy(o); err != nil {
377+ return err
378+ }
379+ if err := o.Context().SendRequest(o, 1, width, height); err != nil {
380+ return err
381+ }
382+ return nil
383+}
384+
385+// Specify the anchor rectangle within the parent surface that the child surface will be placed relative to. The rectangle is relative to the window geometry as defined by xdg_surface.set_window_geometry of the parent surface. When the xdg_positioner object is used to position a child surface, the anchor rectangle may not extend outside the window geometry of the positioned child's parent surface. If a negative size is set the invalid_input error is raised.
386+func (o *XdgPositioner) SetAnchorRect(x int32, y int32, width int32, height int32) error {
387+ if err := o.Context().CheckProxy(o); err != nil {
388+ return err
389+ }
390+ if err := o.Context().SendRequest(o, 2, x, y, width, height); err != nil {
391+ return err
392+ }
393+ return nil
394+}
395+
396+// Defines the anchor point for the anchor rectangle. The specified anchor is used to derive an anchor point that the child surface will be positioned relative to. If a corner anchor is set (e.g. 'top_left' or 'bottom_right'), the anchor point will be at the specified corner; otherwise, the derived anchor point will be centered on the specified edge, or in the center of the anchor rectangle if no edge is specified.
397+func (o *XdgPositioner) SetAnchor(anchor uint32) error {
398+ if err := o.Context().CheckProxy(o); err != nil {
399+ return err
400+ }
401+ if err := o.Context().SendRequest(o, 3, anchor); err != nil {
402+ return err
403+ }
404+ return nil
405+}
406+
407+// Defines in what direction a surface should be positioned, relative to the anchor point of the parent surface. If a corner gravity is specified (e.g. 'bottom_right' or 'top_left'), then the child surface will be placed towards the specified gravity; otherwise, the child surface will be centered over the anchor point on any axis that had no gravity specified. If the gravity is not in the ‘gravity’ enum, an invalid_input error is raised.
408+func (o *XdgPositioner) SetGravity(gravity uint32) error {
409+ if err := o.Context().CheckProxy(o); err != nil {
410+ return err
411+ }
412+ if err := o.Context().SendRequest(o, 4, gravity); err != nil {
413+ return err
414+ }
415+ return nil
416+}
417+
418+// Specify how the window should be positioned if the originally intended position caused the surface to be constrained, meaning at least partially outside positioning boundaries set by the compositor. The adjustment is set by constructing a bitmask describing the adjustment to be made when the surface is constrained on that axis. If no bit for one axis is set, the compositor will assume that the child surface should not change its position on that axis when constrained. If more than one bit for one axis is set, the order of how adjustments are applied is specified in the corresponding adjustment descriptions. The default adjustment is none.
419+func (o *XdgPositioner) SetConstraintAdjustment(constraintAdjustment uint32) error {
420+ if err := o.Context().CheckProxy(o); err != nil {
421+ return err
422+ }
423+ if err := o.Context().SendRequest(o, 5, constraintAdjustment); err != nil {
424+ return err
425+ }
426+ return nil
427+}
428+
429+// Specify the surface position offset relative to the position of the anchor on the anchor rectangle and the anchor on the surface. For example if the anchor of the anchor rectangle is at (x, y), the surface has the gravity bottom|right, and the offset is (ox, oy), the calculated surface position will be (x + ox, y + oy). The offset position of the surface is the one used for constraint testing. See set_constraint_adjustment. An example use case is placing a popup menu on top of a user interface element, while aligning the user interface element of the parent surface with some user interface element placed somewhere in the popup surface.
430+func (o *XdgPositioner) SetOffset(x int32, y int32) error {
431+ if err := o.Context().CheckProxy(o); err != nil {
432+ return err
433+ }
434+ if err := o.Context().SendRequest(o, 6, x, y); err != nil {
435+ return err
436+ }
437+ return nil
438+}
439+
440+// When set reactive, the surface is reconstrained if the conditions used for constraining changed, e.g. the parent window moved. If the conditions changed and the popup was reconstrained, an xdg_popup.configure event is sent with updated geometry, followed by an xdg_surface.configure event.
441+func (o *XdgPositioner) SetReactive() error {
442+ if err := o.Context().CheckProxy(o); err != nil {
443+ return err
444+ }
445+ if err := o.Context().SendRequest(o, 7); err != nil {
446+ return err
447+ }
448+ return nil
449+}
450+
451+// Set the parent window geometry the compositor should use when positioning the popup. The compositor may use this information to determine the future state the popup should be constrained using. If this doesn't match the dimension of the parent the popup is eventually positioned against, the behavior is undefined. The arguments are given in the surface-local coordinate space.
452+func (o *XdgPositioner) SetParentSize(parentWidth int32, parentHeight int32) error {
453+ if err := o.Context().CheckProxy(o); err != nil {
454+ return err
455+ }
456+ if err := o.Context().SendRequest(o, 8, parentWidth, parentHeight); err != nil {
457+ return err
458+ }
459+ return nil
460+}
461+
462+// Set the serial of an xdg_surface.configure event this positioner will be used in response to. The compositor may use this information together with set_parent_size to determine what future state the popup should be constrained using.
463+func (o *XdgPositioner) SetParentConfigure(serial uint32) error {
464+ if err := o.Context().CheckProxy(o); err != nil {
465+ return err
466+ }
467+ if err := o.Context().SendRequest(o, 9, serial); err != nil {
468+ return err
469+ }
470+ return nil
471+}
472+
473+// EventSignature returns the declared event argument types in wire order.
474+func (o *XdgPositioner) EventSignature(opcode uint16) (string, bool) {
475+ switch opcode {
476+ default:
477+ return "", false
478+ }
479+}
480+
481+// Dispatch decodes one event on xdg_positioner and calls the registered handlers.
482+func (o *XdgPositioner) Dispatch(event *wl.Event) {
483+ switch event.Opcode {
484+ default:
485+ }
486+}
487+
488+// XdgSurfaceInterface is the protocol interface name.
489+const XdgSurfaceInterface = "xdg_surface"
490+
491+// XdgSurface is the generated binding for xdg_surface version 7.
492+type XdgSurface struct {
493+ wl.BaseProxy
494+ // handlersMu guards the handler slices: a client may register or replace
495+ // handlers while another goroutine dispatches events.
496+ handlersMu sync.Mutex
497+ onConfigure []func(serial uint32)
498+}
499+
500+// NewXdgSurface returns an unbound XdgSurface.
501+func NewXdgSurface(ctx *wl.Context) *XdgSurface {
502+ obj := &XdgSurface{}
503+ obj.SetContext(ctx)
504+ ctx.Register(obj)
505+ return obj
506+}
507+
508+// Destroy the xdg_surface object. An xdg_surface must only be destroyed after its role object has been destroyed, otherwise a defunct_role_object error is raised.
509+func (o *XdgSurface) Destroy() error {
510+ if err := o.Context().CheckProxy(o); err != nil {
511+ return err
512+ }
513+ if err := o.Context().SendDestructor(o, 0); err != nil {
514+ return err
515+ }
516+ return nil
517+}
518+
519+// This creates an xdg_toplevel object for the given xdg_surface and gives the associated wl_surface the xdg_toplevel role. See the documentation of xdg_toplevel for more details about what an xdg_toplevel is and how it is used.
520+func (o *XdgSurface) GetToplevel() (*XdgToplevel, error) {
521+ if err := o.Context().CheckProxy(o); err != nil {
522+ return nil, err
523+ }
524+ child := &XdgToplevel{}
525+ child.SetContext(o.Context())
526+ child.SetID(o.Context().AllocateID())
527+ o.Context().Register(child)
528+ if err := o.Context().SendRequest(o, 1, child); err != nil {
529+ o.Context().Unregister(child)
530+ return nil, err
531+ }
532+ return child, nil
533+}
534+
535+// This creates an xdg_popup object for the given xdg_surface and gives the associated wl_surface the xdg_popup role. If null is passed as a parent, a parent surface must be specified using some other protocol, before committing the initial state. See the documentation of xdg_popup for more details about what an xdg_popup is and how it is used.
536+func (o *XdgSurface) GetPopup(parent *XdgSurface, positioner *XdgPositioner) (*XdgPopup, error) {
537+ if err := o.Context().CheckProxy(o); err != nil {
538+ return nil, err
539+ }
540+ var arg1 wl.Object
541+ if parent != nil {
542+ arg1 = parent
543+ }
544+ var arg2 wl.Object
545+ if positioner != nil {
546+ arg2 = positioner
547+ }
548+ child := &XdgPopup{}
549+ child.SetContext(o.Context())
550+ child.SetID(o.Context().AllocateID())
551+ o.Context().Register(child)
552+ if err := o.Context().SendRequest(o, 2, child, arg1, arg2); err != nil {
553+ o.Context().Unregister(child)
554+ return nil, err
555+ }
556+ return child, nil
557+}
558+
559+// The window geometry of a surface is its "visible bounds" from the user's perspective. Client-side decorations often have invisible portions like drop-shadows which should be ignored for the purposes of aligning, placing and constraining windows. Note that in some situations, compositors may clip rendering to the window geometry, so the client should avoid putting functional elements outside of it. The window geometry is double-buffered state, see wl_surface.commit. When maintaining a position, the compositor should treat the (x, y) coordinate of the window geometry as the top left corner of the window. A client changing the (x, y) window geometry coordinate should in general not alter the position of the window. Once the window geometry of the surface is set, it is not possible to unset it, and it will remain the same until set_window_geometry is called again, even if a new subsurface or buffer is attached. If never set, the value is the full bounds of the surface, including any subsurfaces. This updates dynamically on every commit. This unset is meant for extremely simple clients. The arguments are given in the surface-local coordinate space of the wl_surface associated with this xdg_surface, and may extend outside of the wl_surface itself to mark parts of the subsurface tree as part of the window geometry. When applied, the effective window geometry will be the set window geometry clamped to the bounding rectangle of the combined geometry of the surface of the xdg_surface and the associated subsurfaces. The effective geometry will not be recalculated unless a new call to set_window_geometry is done and the new pending surface state is subsequently applied. The width and height of the effective window geometry must be greater than zero. Setting an invalid size will raise an invalid_size error.
560+func (o *XdgSurface) SetWindowGeometry(x int32, y int32, width int32, height int32) error {
561+ if err := o.Context().CheckProxy(o); err != nil {
562+ return err
563+ }
564+ if err := o.Context().SendRequest(o, 3, x, y, width, height); err != nil {
565+ return err
566+ }
567+ return nil
568+}
569+
570+// 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. For instance, for toplevel surfaces the compositor might use this information to move a surface to the top left only when the client has drawn itself for the maximized or fullscreen state. If the client receives multiple configure events before it can respond to one, it only has to ack the last configure event. Acking a configure event that was never sent raises an invalid_serial error. 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. Sending an ack_configure request consumes the serial number sent with the request, as well as serial numbers sent by all configure events sent on this xdg_surface prior to the configure event referenced by the committed serial. It is an error to issue multiple ack_configure requests referencing a serial from the same configure event, or to issue an ack_configure request referencing a serial from a configure event issued before the event identified by the last ack_configure request for the same xdg_surface. Doing so will raise an invalid_serial error.
571+func (o *XdgSurface) AckConfigure(serial uint32) error {
572+ if err := o.Context().CheckProxy(o); err != nil {
573+ return err
574+ }
575+ if err := o.Context().SendRequest(o, 4, serial); err != nil {
576+ return err
577+ }
578+ return nil
579+}
580+
581+// OnConfigure registers a handler for the configure event.
582+//
583+// Handlers are appended, so a second call adds another handler rather than
584+// replacing the first. Registration is safe while another goroutine dispatches.
585+func (o *XdgSurface) OnConfigure(handler func(serial uint32)) {
586+ if handler == nil {
587+ return
588+ }
589+ o.handlersMu.Lock()
590+ defer o.handlersMu.Unlock()
591+ o.onConfigure = append(o.onConfigure, handler)
592+}
593+
594+// handlersForConfigure returns the handlers registered for configure, taken
595+// under the lock so a handler may register another handler while events are
596+// being dispatched.
597+func (o *XdgSurface) handlersForConfigure() []func(serial uint32) {
598+ o.handlersMu.Lock()
599+ defer o.handlersMu.Unlock()
600+ return o.onConfigure
601+}
602+
603+// EventSignature returns the declared event argument types in wire order.
604+func (o *XdgSurface) EventSignature(opcode uint16) (string, bool) {
605+ switch opcode {
606+ case 0:
607+ return "uint,", true
608+ default:
609+ return "", false
610+ }
611+}
612+
613+// Dispatch decodes one event on xdg_surface and calls the registered handlers.
614+func (o *XdgSurface) Dispatch(event *wl.Event) {
615+ switch event.Opcode {
616+ case 0: // configure
617+ serial := event.Uint32()
618+
619+ for i, handler := range o.handlersForConfigure() {
620+ _ = i
621+ handler(serial)
622+ }
623+ default:
624+ }
625+}
626+
627+// XdgToplevelInterface is the protocol interface name.
628+const XdgToplevelInterface = "xdg_toplevel"
629+
630+// XdgToplevel is the generated binding for xdg_toplevel version 7.
631+type XdgToplevel struct {
632+ wl.BaseProxy
633+ // handlersMu guards the handler slices: a client may register or replace
634+ // handlers while another goroutine dispatches events.
635+ handlersMu sync.Mutex
636+ onConfigure []func(width int32, height int32, states []byte)
637+ onClose []func()
638+ onConfigureBounds []func(width int32, height int32)
639+ onWmCapabilities []func(capabilities []byte)
640+}
641+
642+// NewXdgToplevel returns an unbound XdgToplevel.
643+func NewXdgToplevel(ctx *wl.Context) *XdgToplevel {
644+ obj := &XdgToplevel{}
645+ obj.SetContext(ctx)
646+ ctx.Register(obj)
647+ return obj
648+}
649+
650+// This request destroys the role surface and unmaps the surface; see "Unmapping" behavior in interface section for details.
651+func (o *XdgToplevel) Destroy() error {
652+ if err := o.Context().CheckProxy(o); err != nil {
653+ return err
654+ }
655+ if err := o.Context().SendDestructor(o, 0); err != nil {
656+ return err
657+ }
658+ return nil
659+}
660+
661+// Set the "parent" of this surface. This surface should be stacked above the parent surface and all other ancestor surfaces. Parent surfaces should be set on dialogs, toolboxes, or other "auxiliary" surfaces, so that the parent is raised when the dialog is raised. Setting a null parent for a child surface unsets its parent. Setting a null parent for a surface which currently has no parent is a no-op. Only mapped surfaces can have child surfaces. Setting a parent which is not mapped is equivalent to setting a null parent. If a surface becomes unmapped, its children's parent is set to the parent of the now-unmapped surface. If the now-unmapped surface has no parent, its children's parent is unset. If the now-unmapped surface becomes mapped again, its parent-child relationship is not restored. The parent toplevel must not be one of the child toplevel's descendants, and the parent must be different from the child toplevel, otherwise the invalid_parent protocol error is raised.
662+func (o *XdgToplevel) SetParent(parent *XdgToplevel) error {
663+ if err := o.Context().CheckProxy(o); err != nil {
664+ return err
665+ }
666+ var arg0 wl.Object
667+ if parent != nil {
668+ arg0 = parent
669+ }
670+ if err := o.Context().SendRequest(o, 1, arg0); err != nil {
671+ return err
672+ }
673+ return nil
674+}
675+
676+// 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.
677+func (o *XdgToplevel) SetTitle(title string) error {
678+ if err := o.Context().CheckProxy(o); err != nil {
679+ return err
680+ }
681+ if err := o.Context().SendRequest(o, 2, title); err != nil {
682+ return err
683+ }
684+ return nil
685+}
686+
687+// Set an application identifier for the surface. The app ID identifies the general class of applications to which the surface belongs. The compositor can use this to group multiple surfaces together, or to determine how to launch a new application. For D-Bus activatable applications, the app ID is used as the D-Bus service name. The compositor shell will try to group application surfaces together by their app ID. As a best practice, it is suggested to select app ID's that match the basename of the application's .desktop file. For example, "org.freedesktop.FooViewer" where the .desktop file is "org.freedesktop.FooViewer.desktop". Like other properties, a set_app_id request can be sent after the xdg_toplevel has been mapped to update the property. See the desktop-entry specification [0] for more details on application identifiers and how they relate to well-known D-Bus names and .desktop files. [0] https://standards.freedesktop.org/desktop-entry-spec/
688+func (o *XdgToplevel) SetAppId(appId string) error {
689+ if err := o.Context().CheckProxy(o); err != nil {
690+ return err
691+ }
692+ if err := o.Context().SendRequest(o, 3, appId); err != nil {
693+ return err
694+ }
695+ return nil
696+}
697+
698+// Clients implementing client-side decorations might want to show a context menu when right-clicking on the decorations, giving the user a menu that they can use to maximize or minimize the window. This request asks the compositor to pop up such a window menu at the given position, relative to the local surface coordinates of the parent surface. There are no guarantees as to what menu items the window menu contains, or even if a window menu will be drawn at all. This request must be used in response to some sort of user action like a button press, key press, or touch down event.
699+func (o *XdgToplevel) ShowWindowMenu(seat *cross_wl_seat.Seat, serial uint32, x int32, y int32) error {
700+ if err := o.Context().CheckProxy(o); err != nil {
701+ return err
702+ }
703+ var arg0 wl.Object
704+ if seat != nil {
705+ arg0 = seat
706+ }
707+ if err := o.Context().SendRequest(o, 4, arg0, serial, x, y); err != nil {
708+ return err
709+ }
710+ return nil
711+}
712+
713+// Start an interactive, user-driven move of the surface. This request must be used in response to some sort of user action like a button press, key press, or touch down event. The passed serial is used to determine the type of interactive move (touch, pointer, etc). The server may ignore move requests depending on the state of the surface (e.g. fullscreen or maximized), or if the passed serial is no longer valid. If triggered, the surface will lose the focus of the device (wl_pointer, wl_touch, etc) used for the move. It is up to the compositor to visually indicate that the move is taking place, such as updating a pointer cursor, during the move. There is no guarantee that the device focus will return when the move is completed.
714+func (o *XdgToplevel) Move(seat *cross_wl_seat.Seat, serial uint32) error {
715+ if err := o.Context().CheckProxy(o); err != nil {
716+ return err
717+ }
718+ var arg0 wl.Object
719+ if seat != nil {
720+ arg0 = seat
721+ }
722+ if err := o.Context().SendRequest(o, 5, arg0, serial); err != nil {
723+ return err
724+ }
725+ return nil
726+}
727+
728+// Start a user-driven, interactive resize of the surface. This request must be used in response to some sort of user action like a button press, key press, or touch down event. The passed serial is used to determine the type of interactive resize (touch, pointer, etc). The server may ignore resize requests depending on the state of the surface (e.g. fullscreen or maximized). If triggered, the client will receive configure events with the "resize" state enum value and the expected sizes. See the "resize" enum value for more details about what is required. The client must also acknowledge configure events using "ack_configure". After the resize is completed, the client will receive another "configure" event without the resize state. If triggered, the surface also will lose the focus of the device (wl_pointer, wl_touch, etc) used for the resize. It is up to the compositor to visually indicate that the resize is taking place, such as updating a pointer cursor, during the resize. There is no guarantee that the device focus will return when the resize is completed. The edges parameter specifies how the surface should be resized, and is one of the values of the resize_edge enum. Values not matching a variant of the enum will cause the invalid_resize_edge protocol error. The compositor may use this information to update the surface position for example when dragging the top left corner. The compositor may also use this information to adapt its behavior, e.g. choose an appropriate cursor image.
729+func (o *XdgToplevel) Resize(seat *cross_wl_seat.Seat, serial uint32, edges uint32) error {
730+ if err := o.Context().CheckProxy(o); err != nil {
731+ return err
732+ }
733+ var arg0 wl.Object
734+ if seat != nil {
735+ arg0 = seat
736+ }
737+ if err := o.Context().SendRequest(o, 6, arg0, serial, edges); err != nil {
738+ return err
739+ }
740+ return nil
741+}
742+
743+// Set a maximum size for the window. The client can specify a maximum size so that the compositor does not try to configure the window beyond this size. The width and height arguments are in window geometry coordinates. See xdg_surface.set_window_geometry. Values set in this way are double-buffered, see wl_surface.commit. The compositor can use this information to allow or disallow different states like maximize or fullscreen and draw accurate animations. Similarly, a tiling window manager may use this information to place and resize client windows in a more effective way. The client should not rely on the compositor to obey the maximum size. The compositor may decide to ignore the values set by the client and request a larger size. If never set, or a value of zero in the request, means that the client has no expected maximum size in the given dimension. As a result, a client wishing to reset the maximum size to an unspecified state can use zero for width and height in the request. Requesting a maximum size to be smaller than the minimum size of a surface is illegal and will result in an invalid_size error. The width and height must be greater than or equal to zero. Using strictly negative values for width or height will result in an invalid_size error.
744+func (o *XdgToplevel) SetMaxSize(width int32, height int32) error {
745+ if err := o.Context().CheckProxy(o); err != nil {
746+ return err
747+ }
748+ if err := o.Context().SendRequest(o, 7, width, height); err != nil {
749+ return err
750+ }
751+ return nil
752+}
753+
754+// Set a minimum size for the window. The client can specify a minimum size so that the compositor does not try to configure the window below this size. The width and height arguments are in window geometry coordinates. See xdg_surface.set_window_geometry. Values set in this way are double-buffered, see wl_surface.commit. The compositor can use this information to allow or disallow different states like maximize or fullscreen and draw accurate animations. Similarly, a tiling window manager may use this information to place and resize client windows in a more effective way. The client should not rely on the compositor to obey the minimum size. The compositor may decide to ignore the values set by the client and request a smaller size. If never set, or a value of zero in the request, means that the client has no expected minimum size in the given dimension. As a result, a client wishing to reset the minimum size to an unspecified state can use zero for width and height in the request. Requesting a minimum size to be larger than the maximum size of a surface is illegal and will result in an invalid_size error. The width and height must be greater than or equal to zero. Using strictly negative values for width and height will result in an invalid_size error.
755+func (o *XdgToplevel) SetMinSize(width int32, height int32) error {
756+ if err := o.Context().CheckProxy(o); err != nil {
757+ return err
758+ }
759+ if err := o.Context().SendRequest(o, 8, width, height); err != nil {
760+ return err
761+ }
762+ return nil
763+}
764+
765+// Maximize the surface. After requesting that the surface should be maximized, the compositor will respond by emitting a configure event. Whether this configure actually sets the window maximized is subject to compositor policies. The client must then update its content, drawing in the configured state. The client must also acknowledge the configure when committing the new content (see ack_configure). It is up to the compositor to decide how and where to maximize the surface, for example which output and what region of the screen should be used. If the surface was already maximized, the compositor will still emit a configure event with the "maximized" state. If the surface is in a fullscreen state, this request has no direct effect. It may alter the state the surface is returned to when unmaximized unless overridden by the compositor.
766+func (o *XdgToplevel) SetMaximized() error {
767+ if err := o.Context().CheckProxy(o); err != nil {
768+ return err
769+ }
770+ if err := o.Context().SendRequest(o, 9); err != nil {
771+ return err
772+ }
773+ return nil
774+}
775+
776+// Unmaximize the surface. After requesting that the surface should be unmaximized, the compositor will respond by emitting a configure event. Whether this actually un-maximizes the window is subject to compositor policies. If available and applicable, the compositor will include the window geometry dimensions the window had prior to being maximized in the configure event. The client must then update its content, drawing it in the configured state. The client must also acknowledge the configure when committing the new content (see ack_configure). It is up to the compositor to position the surface after it was unmaximized; usually the position the surface had before maximizing, if applicable. If the surface was already not maximized, the compositor will still emit a configure event without the "maximized" state. If the surface is in a fullscreen state, this request has no direct effect. It may alter the state the surface is returned to when unmaximized unless overridden by the compositor.
777+func (o *XdgToplevel) UnsetMaximized() error {
778+ if err := o.Context().CheckProxy(o); err != nil {
779+ return err
780+ }
781+ if err := o.Context().SendRequest(o, 10); err != nil {
782+ return err
783+ }
784+ return nil
785+}
786+
787+// Make the surface fullscreen. After requesting that the surface should be fullscreened, the compositor will respond by emitting a configure event. Whether the client is actually put into a fullscreen state is subject to compositor policies. The client must also acknowledge the configure when committing the new content (see ack_configure). The output passed by the request indicates the client's preference as to which display it should be set fullscreen on. If this value is NULL, it's up to the compositor to choose which display will be used to map this surface. If the surface doesn't cover the whole output, the compositor will position the surface in the center of the output and compensate with border fill covering the rest of the output. The content of the border fill is undefined, but should be assumed to be in some way that attempts to blend into the surrounding area (e.g. solid black). If the fullscreened surface is not opaque, the compositor must make sure that other screen content not part of the same surface tree (made up of subsurfaces, popups or similarly coupled surfaces) are not visible below the fullscreened surface.
788+func (o *XdgToplevel) SetFullscreen(output *cross_wl_output.Output) error {
789+ if err := o.Context().CheckProxy(o); err != nil {
790+ return err
791+ }
792+ var arg0 wl.Object
793+ if output != nil {
794+ arg0 = output
795+ }
796+ if err := o.Context().SendRequest(o, 11, arg0); err != nil {
797+ return err
798+ }
799+ return nil
800+}
801+
802+// Make the surface no longer fullscreen. After requesting that the surface should be unfullscreened, the compositor will respond by emitting a configure event. Whether this actually removes the fullscreen state of the client is subject to compositor policies. Making a surface unfullscreen sets states for the surface based on the following: * the state(s) it may have had before becoming fullscreen * any state(s) decided by the compositor * any state(s) requested by the client while the surface was fullscreen The compositor may include the previous window geometry dimensions in the configure event, if applicable. The client must also acknowledge the configure when committing the new content (see ack_configure).
803+func (o *XdgToplevel) UnsetFullscreen() error {
804+ if err := o.Context().CheckProxy(o); err != nil {
805+ return err
806+ }
807+ if err := o.Context().SendRequest(o, 12); err != nil {
808+ return err
809+ }
810+ return nil
811+}
812+
813+// Request that the compositor minimize your surface. There is no way to know if the surface is currently minimized, nor is there any way to unset minimization on this surface. If you are looking to throttle redrawing when minimized, please instead use the wl_surface.frame event for this, as this will also work with live previews on windows in Alt-Tab, Expose or similar compositor features.
814+func (o *XdgToplevel) SetMinimized() error {
815+ if err := o.Context().CheckProxy(o); err != nil {
816+ return err
817+ }
818+ if err := o.Context().SendRequest(o, 13); err != nil {
819+ return err
820+ }
821+ return nil
822+}
823+
824+// OnConfigure registers a handler for the configure event.
825+//
826+// Handlers are appended, so a second call adds another handler rather than
827+// replacing the first. Registration is safe while another goroutine dispatches.
828+func (o *XdgToplevel) OnConfigure(handler func(width int32, height int32, states []byte)) {
829+ if handler == nil {
830+ return
831+ }
832+ o.handlersMu.Lock()
833+ defer o.handlersMu.Unlock()
834+ o.onConfigure = append(o.onConfigure, handler)
835+}
836+
837+// handlersForConfigure returns the handlers registered for configure, taken
838+// under the lock so a handler may register another handler while events are
839+// being dispatched.
840+func (o *XdgToplevel) handlersForConfigure() []func(width int32, height int32, states []byte) {
841+ o.handlersMu.Lock()
842+ defer o.handlersMu.Unlock()
843+ return o.onConfigure
844+}
845+
846+// OnClose registers a handler for the close event.
847+//
848+// Handlers are appended, so a second call adds another handler rather than
849+// replacing the first. Registration is safe while another goroutine dispatches.
850+func (o *XdgToplevel) OnClose(handler func()) {
851+ if handler == nil {
852+ return
853+ }
854+ o.handlersMu.Lock()
855+ defer o.handlersMu.Unlock()
856+ o.onClose = append(o.onClose, handler)
857+}
858+
859+// handlersForClose returns the handlers registered for close, taken
860+// under the lock so a handler may register another handler while events are
861+// being dispatched.
862+func (o *XdgToplevel) handlersForClose() []func() {
863+ o.handlersMu.Lock()
864+ defer o.handlersMu.Unlock()
865+ return o.onClose
866+}
867+
868+// OnConfigureBounds registers a handler for the configure_bounds event.
869+//
870+// Handlers are appended, so a second call adds another handler rather than
871+// replacing the first. Registration is safe while another goroutine dispatches.
872+func (o *XdgToplevel) OnConfigureBounds(handler func(width int32, height int32)) {
873+ if handler == nil {
874+ return
875+ }
876+ o.handlersMu.Lock()
877+ defer o.handlersMu.Unlock()
878+ o.onConfigureBounds = append(o.onConfigureBounds, handler)
879+}
880+
881+// handlersForConfigureBounds returns the handlers registered for configure_bounds, taken
882+// under the lock so a handler may register another handler while events are
883+// being dispatched.
884+func (o *XdgToplevel) handlersForConfigureBounds() []func(width int32, height int32) {
885+ o.handlersMu.Lock()
886+ defer o.handlersMu.Unlock()
887+ return o.onConfigureBounds
888+}
889+
890+// OnWmCapabilities registers a handler for the wm_capabilities event.
891+//
892+// Handlers are appended, so a second call adds another handler rather than
893+// replacing the first. Registration is safe while another goroutine dispatches.
894+func (o *XdgToplevel) OnWmCapabilities(handler func(capabilities []byte)) {
895+ if handler == nil {
896+ return
897+ }
898+ o.handlersMu.Lock()
899+ defer o.handlersMu.Unlock()
900+ o.onWmCapabilities = append(o.onWmCapabilities, handler)
901+}
902+
903+// handlersForWmCapabilities returns the handlers registered for wm_capabilities, taken
904+// under the lock so a handler may register another handler while events are
905+// being dispatched.
906+func (o *XdgToplevel) handlersForWmCapabilities() []func(capabilities []byte) {
907+ o.handlersMu.Lock()
908+ defer o.handlersMu.Unlock()
909+ return o.onWmCapabilities
910+}
911+
912+// EventSignature returns the declared event argument types in wire order.
913+func (o *XdgToplevel) EventSignature(opcode uint16) (string, bool) {
914+ switch opcode {
915+ case 0:
916+ return "int,int,array,", true
917+ case 1:
918+ return "", true
919+ case 2:
920+ return "int,int,", true
921+ case 3:
922+ return "array,", true
923+ default:
924+ return "", false
925+ }
926+}
927+
928+// Dispatch decodes one event on xdg_toplevel and calls the registered handlers.
929+func (o *XdgToplevel) Dispatch(event *wl.Event) {
930+ switch event.Opcode {
931+ case 0: // configure
932+ width := event.Int32()
933+ height := event.Int32()
934+ states := event.Array()
935+
936+ for i, handler := range o.handlersForConfigure() {
937+ _ = i
938+ handler(width, height, states)
939+ }
940+ case 1: // close
941+
942+ for i, handler := range o.handlersForClose() {
943+ _ = i
944+ handler()
945+ }
946+ case 2: // configure_bounds
947+ width := event.Int32()
948+ height := event.Int32()
949+
950+ for i, handler := range o.handlersForConfigureBounds() {
951+ _ = i
952+ handler(width, height)
953+ }
954+ case 3: // wm_capabilities
955+ capabilities := event.Array()
956+
957+ for i, handler := range o.handlersForWmCapabilities() {
958+ _ = i
959+ handler(capabilities)
960+ }
961+ default:
962+ }
963+}
964+
965+// XdgPopupInterface is the protocol interface name.
966+const XdgPopupInterface = "xdg_popup"
967+
968+// XdgPopup is the generated binding for xdg_popup version 7.
969+type XdgPopup struct {
970+ wl.BaseProxy
971+ // handlersMu guards the handler slices: a client may register or replace
972+ // handlers while another goroutine dispatches events.
973+ handlersMu sync.Mutex
974+ onConfigure []func(x int32, y int32, width int32, height int32)
975+ onPopupDone []func()
976+ onRepositioned []func(token uint32)
977+}
978+
979+// NewXdgPopup returns an unbound XdgPopup.
980+func NewXdgPopup(ctx *wl.Context) *XdgPopup {
981+ obj := &XdgPopup{}
982+ obj.SetContext(ctx)
983+ ctx.Register(obj)
984+ return obj
985+}
986+
987+// This destroys the popup. Explicitly destroying the xdg_popup object will also dismiss the popup, and unmap the surface. If this xdg_popup is not the "topmost" popup, the xdg_wm_base.not_the_topmost_popup protocol error will be sent.
988+func (o *XdgPopup) Destroy() error {
989+ if err := o.Context().CheckProxy(o); err != nil {
990+ return err
991+ }
992+ if err := o.Context().SendDestructor(o, 0); err != nil {
993+ return err
994+ }
995+ return nil
996+}
997+
998+// This request makes the created popup take an explicit grab. An explicit grab will be dismissed when the user dismisses the popup, or when the client destroys the xdg_popup. This can be done by the user clicking outside the surface, using the keyboard, or even locking the screen through closing the lid or a timeout. If the compositor denies the grab, the popup will be immediately dismissed. This request must be used in response to some sort of user action like a button press, key press, or touch down event. The serial number of the event should be passed as 'serial'. The parent of a grabbing popup must either be an xdg_toplevel surface or another xdg_popup with an explicit grab. If the parent is another xdg_popup it means that the popups are nested, with this popup now being the topmost popup. Nested popups must be destroyed in the reverse order they were created in, e.g. the only popup you are allowed to destroy at all times is the topmost one. When compositors choose to dismiss a popup, they may dismiss every nested grabbing popup as well. When a compositor dismisses popups, it will follow the same dismissing order as required from the client. If the topmost grabbing popup is destroyed, the grab will be returned to the parent of the popup, if that parent previously had an explicit grab. If the parent is a grabbing popup which has already been dismissed, this popup will be immediately dismissed. If the parent is a popup that did not take an explicit grab, an error will be raised. During a popup grab, the client owning the grab will receive pointer and touch events for all their surfaces as normal (similar to an "owner-events" grab in X11 parlance), while the top most grabbing popup will always have keyboard focus.
999+func (o *XdgPopup) Grab(seat *cross_wl_seat.Seat, serial uint32) error {
1000+ if err := o.Context().CheckProxy(o); err != nil {
1001+ return err
1002+ }
1003+ var arg0 wl.Object
1004+ if seat != nil {
1005+ arg0 = seat
1006+ }
1007+ if err := o.Context().SendRequest(o, 1, arg0, serial); err != nil {
1008+ return err
1009+ }
1010+ return nil
1011+}
1012+
1013+// Reposition an already-mapped popup. The popup will be placed given the details in the passed xdg_positioner object, and a xdg_popup.repositioned followed by xdg_popup.configure and xdg_surface.configure will be emitted in response. Any parameters set by the previous positioner will be discarded. The passed token will be sent in the corresponding xdg_popup.repositioned event. The new popup position will not take effect until the corresponding configure event is acknowledged by the client. See xdg_popup.repositioned for details. The token itself is opaque, and has no other special meaning. If multiple reposition requests are sent, the compositor may skip all but the last one. If the popup is repositioned in response to a configure event for its parent, the client should send an xdg_positioner.set_parent_configure and possibly an xdg_positioner.set_parent_size request to allow the compositor to properly constrain the popup. If the popup is repositioned together with a parent that is being resized, but not in response to a configure event, the client should send an xdg_positioner.set_parent_size request.
1014+func (o *XdgPopup) Reposition(positioner *XdgPositioner, token uint32) error {
1015+ if err := o.Context().CheckProxy(o); err != nil {
1016+ return err
1017+ }
1018+ var arg0 wl.Object
1019+ if positioner != nil {
1020+ arg0 = positioner
1021+ }
1022+ if err := o.Context().SendRequest(o, 2, arg0, token); err != nil {
1023+ return err
1024+ }
1025+ return nil
1026+}
1027+
1028+// OnConfigure registers a handler for the configure event.
1029+//
1030+// Handlers are appended, so a second call adds another handler rather than
1031+// replacing the first. Registration is safe while another goroutine dispatches.
1032+func (o *XdgPopup) OnConfigure(handler func(x int32, y int32, width int32, height int32)) {
1033+ if handler == nil {
1034+ return
1035+ }
1036+ o.handlersMu.Lock()
1037+ defer o.handlersMu.Unlock()
1038+ o.onConfigure = append(o.onConfigure, handler)
1039+}
1040+
1041+// handlersForConfigure returns the handlers registered for configure, taken
1042+// under the lock so a handler may register another handler while events are
1043+// being dispatched.
1044+func (o *XdgPopup) handlersForConfigure() []func(x int32, y int32, width int32, height int32) {
1045+ o.handlersMu.Lock()
1046+ defer o.handlersMu.Unlock()
1047+ return o.onConfigure
1048+}
1049+
1050+// OnPopupDone registers a handler for the popup_done event.
1051+//
1052+// Handlers are appended, so a second call adds another handler rather than
1053+// replacing the first. Registration is safe while another goroutine dispatches.
1054+func (o *XdgPopup) OnPopupDone(handler func()) {
1055+ if handler == nil {
1056+ return
1057+ }
1058+ o.handlersMu.Lock()
1059+ defer o.handlersMu.Unlock()
1060+ o.onPopupDone = append(o.onPopupDone, handler)
1061+}
1062+
1063+// handlersForPopupDone returns the handlers registered for popup_done, taken
1064+// under the lock so a handler may register another handler while events are
1065+// being dispatched.
1066+func (o *XdgPopup) handlersForPopupDone() []func() {
1067+ o.handlersMu.Lock()
1068+ defer o.handlersMu.Unlock()
1069+ return o.onPopupDone
1070+}
1071+
1072+// OnRepositioned registers a handler for the repositioned event.
1073+//
1074+// Handlers are appended, so a second call adds another handler rather than
1075+// replacing the first. Registration is safe while another goroutine dispatches.
1076+func (o *XdgPopup) OnRepositioned(handler func(token uint32)) {
1077+ if handler == nil {
1078+ return
1079+ }
1080+ o.handlersMu.Lock()
1081+ defer o.handlersMu.Unlock()
1082+ o.onRepositioned = append(o.onRepositioned, handler)
1083+}
1084+
1085+// handlersForRepositioned returns the handlers registered for repositioned, taken
1086+// under the lock so a handler may register another handler while events are
1087+// being dispatched.
1088+func (o *XdgPopup) handlersForRepositioned() []func(token uint32) {
1089+ o.handlersMu.Lock()
1090+ defer o.handlersMu.Unlock()
1091+ return o.onRepositioned
1092+}
1093+
1094+// EventSignature returns the declared event argument types in wire order.
1095+func (o *XdgPopup) EventSignature(opcode uint16) (string, bool) {
1096+ switch opcode {
1097+ case 0:
1098+ return "int,int,int,int,", true
1099+ case 1:
1100+ return "", true
1101+ case 2:
1102+ return "uint,", true
1103+ default:
1104+ return "", false
1105+ }
1106+}
1107+
1108+// Dispatch decodes one event on xdg_popup and calls the registered handlers.
1109+func (o *XdgPopup) Dispatch(event *wl.Event) {
1110+ switch event.Opcode {
1111+ case 0: // configure
1112+ x := event.Int32()
1113+ y := event.Int32()
1114+ width := event.Int32()
1115+ height := event.Int32()
1116+
1117+ for i, handler := range o.handlersForConfigure() {
1118+ _ = i
1119+ handler(x, y, width, height)
1120+ }
1121+ case 1: // popup_done
1122+
1123+ for i, handler := range o.handlersForPopupDone() {
1124+ _ = i
1125+ handler()
1126+ }
1127+ case 2: // repositioned
1128+ token := event.Uint32()
1129+
1130+ for i, handler := range o.handlersForRepositioned() {
1131+ _ = i
1132+ handler(token)
1133+ }
1134+ default:
1135+ }
1136+}

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