detached 96f3aeb

merge: harden core transport, object lifecycle and request generation

Harden core transport, object lifecycle and request generation
commit
96f3aeb878c7264d6890bc8110935cf969f8774b
author
bnema · · 2026-09-29 16:02 UTC
committer
GitHub · · 2026-09-29 16:02 UTC
merge of
a2cb70a + 1a9db3b · diff against the first parent
signature
GPG UnverifiedB5690EEEBB952194 The key is unknown
refs
tag: v0.3.0
22 files · +719 -1428
A .github/workflows/ci.yml +28 -0
@@ -0,0 +1,28 @@
1+name: ci
2+
3+on:
4+ push:
5+ branches: [main]
6+ pull_request:
7+
8+permissions:
9+ contents: read
10+
11+jobs:
12+ test:
13+ runs-on: ubuntu-latest
14+ steps:
15+ - uses: actions/checkout@v4
16+ - uses: actions/setup-go@v5
17+ with:
18+ go-version-file: go.mod
19+ - name: Vet
20+ run: go vet ./...
21+ - name: Staticcheck
22+ run: go run honnef.co/go/tools/cmd/staticcheck@latest ./...
23+ - name: Test (race)
24+ run: go test -race -count=1 ./...
25+ - name: Generated code is up to date
26+ run: |
27+ GOWORK=off go generate ./...
28+ git diff --exit-code -- protocol
@@ -0,0 +1,28 @@
1+name: ci
2+
3+on:
4+ push:
5+ branches: [main]
6+ pull_request:
7+
8+permissions:
9+ contents: read
10+
11+jobs:
12+ test:
13+ runs-on: ubuntu-latest
14+ steps:
15+ - uses: actions/checkout@v4
16+ - uses: actions/setup-go@v5
17+ with:
18+ go-version-file: go.mod
19+ - name: Vet
20+ run: go vet ./...
21+ - name: Staticcheck
22+ run: go run honnef.co/go/tools/cmd/staticcheck@latest ./...
23+ - name: Test (race)
24+ run: go test -race -count=1 ./...
25+ - name: Generated code is up to date
26+ run: |
27+ GOWORK=off go generate ./...
28+ git diff --exit-code -- protocol
M README.md +8 -36
@@ -25,21 +25,11 @@ After `display.Roundtrip()` discovers globals, call `display.Registry().BindNego
2525
2626 ## Features
2727
28-### Performance Optimizations
29-
30-- **Zero-allocation event handling**: For messages under 4KB
31-- **Lock-free dispatcher**: For object IDs < 1024 using atomic operations
32-- **Pre-allocated buffers**: Reusable buffers to minimize allocations
33-- **Direct array indexing**: Fast opcode lookup for common cases
34-- **Buffer pooling**: sync.Pool for temporary allocations
35-- **File descriptor passing**: Efficient shared memory via SCM_RIGHTS
36-
37-### Design Goals
38-
39-- Minimal allocations in hot paths
40-- Efficient event dispatching
41-- Clean API for protocol extensions
42-- Foundation for high-performance Wayland applications
28+- **Stream framing**: messages split across or coalesced within socket reads are framed exactly; event bodies are not copied.
29+- **Descriptor ownership**: received FDs belong to the event that declares them and are closed if a handler does not take them.
30+- **Object lifecycle**: destroyed objects stay as zombies until `delete_id`, so events already in flight are dropped instead of failing the connection.
31+- **Version checks**: generated requests newer than the bound object version return `ErrVersionTooLow` before anything is sent.
32+- **Allocation-free requests**: marshaling fixed-size requests does not allocate.
4333
4434 ## Quick Start
4535
@@ -58,7 +48,8 @@ func main() {
5848 }
5949 defer display.Close()
6050
61- // Basic event loop
51+ // Basic event loop. Handlers run inside Dispatch and must not call
52+ // Dispatch or Roundtrip on the same display.
6253 for {
6354 if err := display.Dispatch(); err != nil {
6455 break
@@ -69,28 +60,9 @@ func main() {
6960
7061 For device control and input injection, use [libwldevices-go](https://github.com/bnema/libwldevices-go) which builds on top of WLTurbo.
7162
72-## Implementation Status
73-
74-### Core Protocol ✅
75-- Display, Registry, Compositor, Surface, Seat, Region
76-- Event dispatching and handler registration
77-- File descriptor passing for shared memory
78-- Context-based proxy management
79-
80-### Optimizations ✅
81-- Zero-allocation event handling (messages < 4KB)
82-- Lock-free dispatcher for common cases
83-- Pre-allocated and pooled buffers
84-- Efficient event routing
85-
86-### Future Improvements
87-- Performance benchmarks and validation
88-- Additional optimizations based on profiling
89-- Extended protocol object support as needed
90-
9163 ## Requirements
9264
93-- **Go 1.21+**
65+- **Go 1.27+**
9466 - **Linux** with Wayland compositor
9567 - **Unix sockets** support
9668
@@ -25,21 +25,11 @@ After `display.Roundtrip()` discovers globals, call `display.Registry().BindNego
25 25
26 ## Features26 ## Features
27 27
28-### Performance Optimizations28+- **Stream framing**: messages split across or coalesced within socket reads are framed exactly; event bodies are not copied.
29-29+- **Descriptor ownership**: received FDs belong to the event that declares them and are closed if a handler does not take them.
30-- **Zero-allocation event handling**: For messages under 4KB30+- **Object lifecycle**: destroyed objects stay as zombies until `delete_id`, so events already in flight are dropped instead of failing the connection.
31-- **Lock-free dispatcher**: For object IDs < 1024 using atomic operations 31+- **Version checks**: generated requests newer than the bound object version return `ErrVersionTooLow` before anything is sent.
32-- **Pre-allocated buffers**: Reusable buffers to minimize allocations32+- **Allocation-free requests**: marshaling fixed-size requests does not allocate.
33-- **Direct array indexing**: Fast opcode lookup for common cases
34-- **Buffer pooling**: sync.Pool for temporary allocations
35-- **File descriptor passing**: Efficient shared memory via SCM_RIGHTS
36-
37-### Design Goals
38-
39-- Minimal allocations in hot paths
40-- Efficient event dispatching
41-- Clean API for protocol extensions
42-- Foundation for high-performance Wayland applications
43 33
44 ## Quick Start34 ## Quick Start
45 35
@@ -58,7 +48,8 @@ func main() {
58 }48 }
59 defer display.Close()49 defer display.Close()
60 50
61- // Basic event loop51+ // Basic event loop. Handlers run inside Dispatch and must not call
52+ // Dispatch or Roundtrip on the same display.
62 for {53 for {
63 if err := display.Dispatch(); err != nil {54 if err := display.Dispatch(); err != nil {
64 break55 break
@@ -69,28 +60,9 @@ func main() {
69 60
70 For device control and input injection, use [libwldevices-go](https://github.com/bnema/libwldevices-go) which builds on top of WLTurbo.61 For device control and input injection, use [libwldevices-go](https://github.com/bnema/libwldevices-go) which builds on top of WLTurbo.
71 62
72-## Implementation Status
73-
74-### Core Protocol ✅
75-- Display, Registry, Compositor, Surface, Seat, Region
76-- Event dispatching and handler registration
77-- File descriptor passing for shared memory
78-- Context-based proxy management
79-
80-### Optimizations ✅
81-- Zero-allocation event handling (messages < 4KB)
82-- Lock-free dispatcher for common cases
83-- Pre-allocated and pooled buffers
84-- Efficient event routing
85-
86-### Future Improvements
87-- Performance benchmarks and validation
88-- Additional optimizations based on profiling
89-- Extended protocol object support as needed
90-
91 ## Requirements63 ## Requirements
92 64
93-- **Go 1.21+**65+- **Go 1.27+**
94 - **Linux** with Wayland compositor66 - **Linux** with Wayland compositor
95 - **Unix sockets** support67 - **Unix sockets** support
96 68
M benchmark_test.go +34 -0
@@ -17,6 +17,29 @@ func BenchmarkWireDispatch(b *testing.B) {
1717 }
1818 }
1919
20+// BenchmarkDispatchCoalesced measures framing when one read carries many
21+// messages; per-frame cost must not grow with the amount buffered.
22+func BenchmarkDispatchCoalesced(b *testing.B) {
23+ var chunk []byte
24+ for len(chunk)+12 <= readChunkSize {
25+ chunk = append(chunk, message(7, 0, []byte{1, 0, 0, 0})...)
26+ }
27+ frames := len(chunk) / 12
28+ b.ReportAllocs()
29+ for i := 0; i < b.N; i++ {
30+ b.StopTimer()
31+ d := newDisplay(&chunkConn{chunks: [][]byte{append([]byte(nil), chunk...)}})
32+ d.context.Register(&benchProxy{BaseProxy: BaseProxy{id: 7, context: d.context}})
33+ b.StartTimer()
34+ for j := 0; j < frames; j++ {
35+ if err := d.Dispatch(); err != nil {
36+ b.Fatal(err)
37+ }
38+ }
39+ }
40+ b.ReportMetric(float64(b.Elapsed().Nanoseconds())/float64(b.N*frames), "ns/frame")
41+}
42+
2043 type benchProxy struct {
2144 BaseProxy
2245 value uint32
@@ -24,3 +47,14 @@ type benchProxy struct {
2447
2548 func (p *benchProxy) EventSignature(op uint16) (string, bool) { return "uint,", op == 0 }
2649 func (p *benchProxy) Dispatch(e *Event) { p.value = e.Uint32() }
50+
51+// BenchmarkSendRequest measures marshaling a typical fixed-size request.
52+func BenchmarkSendRequest(b *testing.B) {
53+ d := newDisplay(&chunkConn{})
54+ b.ReportAllocs()
55+ for i := 0; i < b.N; i++ {
56+ if err := d.SendRequest(9, 0, uint32(1), int32(2), Fixed(3)); err != nil {
57+ b.Fatal(err)
58+ }
59+ }
60+}
@@ -17,6 +17,29 @@ func BenchmarkWireDispatch(b *testing.B) {
17 }17 }
18 }18 }
19 19
20+// BenchmarkDispatchCoalesced measures framing when one read carries many
21+// messages; per-frame cost must not grow with the amount buffered.
22+func BenchmarkDispatchCoalesced(b *testing.B) {
23+ var chunk []byte
24+ for len(chunk)+12 <= readChunkSize {
25+ chunk = append(chunk, message(7, 0, []byte{1, 0, 0, 0})...)
26+ }
27+ frames := len(chunk) / 12
28+ b.ReportAllocs()
29+ for i := 0; i < b.N; i++ {
30+ b.StopTimer()
31+ d := newDisplay(&chunkConn{chunks: [][]byte{append([]byte(nil), chunk...)}})
32+ d.context.Register(&benchProxy{BaseProxy: BaseProxy{id: 7, context: d.context}})
33+ b.StartTimer()
34+ for j := 0; j < frames; j++ {
35+ if err := d.Dispatch(); err != nil {
36+ b.Fatal(err)
37+ }
38+ }
39+ }
40+ b.ReportMetric(float64(b.Elapsed().Nanoseconds())/float64(b.N*frames), "ns/frame")
41+}
42+
20 type benchProxy struct {43 type benchProxy struct {
21 BaseProxy44 BaseProxy
22 value uint3245 value uint32
@@ -24,3 +47,14 @@ type benchProxy struct {
24 47
25 func (p *benchProxy) EventSignature(op uint16) (string, bool) { return "uint,", op == 0 }48 func (p *benchProxy) EventSignature(op uint16) (string, bool) { return "uint,", op == 0 }
26 func (p *benchProxy) Dispatch(e *Event) { p.value = e.Uint32() }49 func (p *benchProxy) Dispatch(e *Event) { p.value = e.Uint32() }
50+
51+// BenchmarkSendRequest measures marshaling a typical fixed-size request.
52+func BenchmarkSendRequest(b *testing.B) {
53+ d := newDisplay(&chunkConn{})
54+ b.ReportAllocs()
55+ for i := 0; i < b.N; i++ {
56+ if err := d.SendRequest(9, 0, uint32(1), int32(2), Fixed(3)); err != nil {
57+ b.Fatal(err)
58+ }
59+ }
60+}
M client.go +137 -210
@@ -1,7 +1,6 @@
1-// Package wlturbo provides a high-performance Wayland client implementation optimized for gaming and real-time applications.
2-//
3-// This package delivers sub-microsecond latency, zero-allocation hot paths, and support for 8000Hz gaming devices.
4-// It's designed for video game engines, competitive gaming, and other performance-critical applications.
1+// Package wlturbo is a Wayland client transport for Go: connection, framing,
2+// descriptor passing, object lifecycle and the bootstrap registry. Protocol
3+// bindings are generated into the protocol/ packages.
54 package wlturbo
65
76 import (
@@ -56,26 +55,17 @@ type Display struct {
5655 recvMu sync.Mutex
5756 dispatchMu sync.Mutex // serialize readers without holding receive state across handlers
5857 signatures sync.Map
59- listenerMu sync.Mutex
60- listeners sync.Map // map[uint32]map[uint16][]func([]byte)
61-
62- // High-performance event dispatcher
63- dispatcher *EventDispatcher
6458
6559 // Core objects
6660 registry *Registry
6761 context *Context // Store context once
6862
69- // Error state
70- lastError error
71- lastErrorCode uint32
72- lastErrorObj uint32
73-
74- // Connection-local receive state. rbuf holds bytes read from the socket
75- // that do not yet form a complete frame; recvBuf is the scratch buffer
76- // used for a single read. pendingFDs holds ancillary descriptors that
77- // arrived with those bytes and have not been consumed yet.
63+ // Connection-local receive state. rbuf[rpos:] holds bytes read from the
64+ // socket that have not been framed yet; recvBuf is the scratch buffer used
65+ // for a single read. pendingFDs holds ancillary descriptors that arrived
66+ // with those bytes and have not been consumed yet.
7867 rbuf []byte
68+ rpos int
7969 recvBuf []byte
8070 readErr error
8171 maxMsgLen uint32
@@ -86,9 +76,8 @@ type Display struct {
8676 // newDisplay builds a Display over an established connection.
8777 func newDisplay(conn net.Conn) *Display {
8878 d := &Display{
89- conn: conn,
90- nextID: 2, // 1 is reserved for wl_display
91- dispatcher: NewEventDispatcher(),
79+ conn: conn,
80+ nextID: 2, // 1 is reserved for wl_display
9281 }
9382 if uc, ok := conn.(*net.UnixConn); ok {
9483 d.unix = uc
@@ -101,7 +90,7 @@ func newDisplay(conn net.Conn) *Display {
10190 id: d.allocateID(),
10291 display: d,
10392 globals: make(map[uint32]Global),
104- handlers: make(map[string]GlobalHandler),
93+ handlers: make(map[string][]GlobalHandler),
10594 }
10695 d.objects.Store(d.registry.id, d.registry)
10796 return d
@@ -113,7 +102,7 @@ type Registry struct {
113102 display *Display
114103 globals map[uint32]Global
115104 mu sync.RWMutex
116- handlers map[string]GlobalHandler
105+ handlers map[string][]GlobalHandler
117106 removeHandlers []RegistryGlobalRemoveHandler
118107 }
119108
@@ -138,7 +127,6 @@ func (c *callbackObject) Dispatch(event *Event) {
138127 if event.Opcode != 0 { // done event
139128 return
140129 }
141- c.display.notifyListeners(c.id, 0, event.data)
142130 c.display.context.Unregister(c)
143131 }
144132
@@ -212,11 +200,6 @@ func (d *Display) ID() uint32 {
212200 return 1
213201 }
214202
215-// RegisterEventHandler registers a high-performance event handler
216-func (d *Display) RegisterEventHandler(objectID uint32, opcode uint16, handler EventHandler) {
217- d.dispatcher.RegisterHandler(objectID, opcode, handler)
218-}
219-
220203 // allocateID allocates a new object ID
221204 func (d *Display) allocateID() uint32 {
222205 d.idMu.Lock()
@@ -261,8 +244,8 @@ func (d *Display) sendRequest(objectID uint32, opcode uint16, fds []int, guard f
261244 }()
262245
263246 // Write header placeholder
264- header := make([]byte, 8)
265- _, _ = buf.Write(header)
247+ var header [HeaderSize]byte
248+ _, _ = buf.Write(header[:])
266249
267250 // Marshal arguments
268251 for _, arg := range args {
@@ -283,30 +266,35 @@ func (d *Display) sendRequest(objectID uint32, opcode uint16, fds []int, guard f
283266
284267 // Update buffer with correct header
285268 data := buf.Bytes()
286- copy(data[0:8], header)
269+ copy(data[0:8], header[:])
287270
288271 // Send message with optional file descriptors
289272 return d.sendmsgWithFDs(data, fds, guard)
290273 }
291274
275+// putUint32 appends one little-endian wire word without allocating.
276+func putUint32(buf *bytes.Buffer, v uint32) {
277+ var w [4]byte
278+ binary.LittleEndian.PutUint32(w[:], v)
279+ _, _ = buf.Write(w[:])
280+}
281+
292282 // marshalArg marshals a single argument
293283 func (d *Display) marshalArg(buf *bytes.Buffer, arg interface{}) error {
294284 switch v := arg.(type) {
295285 case uint32:
296- return binary.Write(buf, binary.LittleEndian, v)
286+ putUint32(buf, v)
297287 case int32:
298- return binary.Write(buf, binary.LittleEndian, v)
288+ putUint32(buf, uint32(v))
299289 case Fixed:
300- return binary.Write(buf, binary.LittleEndian, int32(v))
290+ putUint32(buf, uint32(v))
301291 case string:
302292 // String format: length (including null) + string + null + padding
303293 strlen := len(v) + 1
304294 if strlen > 0xffff-HeaderSize {
305295 return fmt.Errorf("string too long: %d bytes", strlen)
306296 }
307- if err := binary.Write(buf, binary.LittleEndian, uint32(strlen)); err != nil { // Safe: checked above
308- return err
309- }
297+ putUint32(buf, uint32(strlen)) // Safe: checked above
310298 _, _ = buf.WriteString(v)
311299 _ = buf.WriteByte(0)
312300 // Pad to 32-bit boundary
@@ -320,9 +308,7 @@ func (d *Display) marshalArg(buf *bytes.Buffer, arg interface{}) error {
320308 if arrlen > 0xffff-HeaderSize {
321309 return fmt.Errorf("array too long: %d bytes", arrlen)
322310 }
323- if err := binary.Write(buf, binary.LittleEndian, uint32(arrlen)); err != nil {
324- return err
325- }
311+ putUint32(buf, uint32(arrlen))
326312 _, _ = buf.Write(v)
327313 // Pad to 32-bit boundary
328314 padding := (4 - (arrlen % 4)) % 4
@@ -331,16 +317,13 @@ func (d *Display) marshalArg(buf *bytes.Buffer, arg interface{}) error {
331317 }
332318 case Object:
333319 if v != nil {
334- return binary.Write(buf, binary.LittleEndian, v.ID())
320+ putUint32(buf, v.ID())
321+ } else {
322+ putUint32(buf, 0)
335323 }
336- return binary.Write(buf, binary.LittleEndian, uint32(0))
337324 case nil:
338325 // Null object
339- return binary.Write(buf, binary.LittleEndian, uint32(0))
340- case int:
341- // File descriptor - write placeholder in message
342- // Actual FD will be sent via SCM_RIGHTS
343- return binary.Write(buf, binary.LittleEndian, uint32(0))
326+ putUint32(buf, 0)
344327 case uintptr:
345328 // File descriptor as uintptr - NO placeholder in message for neurlang compatibility
346329 // FD is ONLY sent via SCM_RIGHTS, not in the message body
@@ -357,7 +340,12 @@ func (d *Display) marshalArg(buf *bytes.Buffer, arg interface{}) error {
357340 // Read boundaries never define message boundaries: a header split across
358341 // several reads and several messages arriving in one read are both handled.
359342 // Dispatch returns net.ErrClosed after Close, a typed ProtocolError for a
360-// malformed frame, and io.ErrUnexpectedEOF when the peer closes mid-frame.
343+// malformed frame, io.ErrUnexpectedEOF when the peer closes mid-frame, and
344+// os.ErrDeadlineExceeded (not sticky) when a read deadline expires.
345+//
346+// Event handlers run while Dispatch holds the dispatch lock, so a handler must
347+// not call Dispatch or Roundtrip on the same Display: that call deadlocks.
348+// Hand work that needs a roundtrip to another goroutine instead.
361349 func (d *Display) Dispatch() error {
362350 d.dispatchMu.Lock()
363351 defer d.dispatchMu.Unlock()
@@ -409,18 +397,20 @@ func (d *Display) maxMessageSize() uint32 {
409397 // nextFrame returns the next complete frame, reading more bytes as needed.
410398 func (d *Display) nextFrame() (receivedFrame, error) {
411399 for {
412- if len(d.rbuf) >= HeaderSize {
413- object, opcode, size, err := parseHeader(d.rbuf[:HeaderSize], d.maxMessageSize())
400+ buf := d.rbuf[d.rpos:]
401+ if len(buf) >= HeaderSize {
402+ object, opcode, size, err := parseHeader(buf[:HeaderSize], d.maxMessageSize())
414403 if err != nil {
415404 return receivedFrame{}, err
416405 }
417- if uint32(len(d.rbuf)) >= size {
406+ if uint32(len(buf)) >= size {
407+ // The body aliases the receive buffer. It stays valid until
408+ // the next fill, which only happens in a later Dispatch.
418409 frame := receivedFrame{object: object, opcode: opcode}
419410 if size > HeaderSize {
420- frame.body = make([]byte, size-HeaderSize)
421- copy(frame.body, d.rbuf[HeaderSize:size])
411+ frame.body = buf[HeaderSize:size:size]
422412 }
423- d.consume(size)
413+ d.rpos += int(size)
424414 return frame, nil
425415 }
426416 }
@@ -433,11 +423,8 @@ func (d *Display) nextFrame() (receivedFrame, error) {
433423 }
434424 }
435425
436-// consume removes the first n bytes from the receive buffer.
437-func (d *Display) consume(n uint32) {
438- rest := copy(d.rbuf, d.rbuf[n:])
439- d.rbuf = d.rbuf[:rest]
440-}
426+// unread reports whether received bytes remain that have not been framed.
427+func (d *Display) unread() bool { return d.rpos < len(d.rbuf) }
441428
442429 // fill reads one chunk from the connection into the receive buffer. Bytes that
443430 // arrive together with an error are kept so they are still parsed before the
@@ -449,6 +436,12 @@ func (d *Display) fill() error {
449436 if d.recvBuf == nil {
450437 d.recvBuf = make([]byte, readChunkSize)
451438 }
439+ // Compact once per read rather than once per frame, so framing cost does
440+ // not grow with the number of buffered messages.
441+ if d.rpos > 0 {
442+ d.rbuf = d.rbuf[:copy(d.rbuf, d.rbuf[d.rpos:])]
443+ d.rpos = 0
444+ }
452445 n, err := d.readChunk()
453446 if n > 0 {
454447 d.rbuf = append(d.rbuf, d.recvBuf[:n]...)
@@ -457,6 +450,11 @@ func (d *Display) fill() error {
457450 if errors.Is(err, io.EOF) {
458451 err = io.ErrUnexpectedEOF
459452 }
453+ // A missed deadline is not a broken stream: report it without making
454+ // it sticky, so a later Dispatch can read again.
455+ if errors.Is(err, os.ErrDeadlineExceeded) {
456+ return err
457+ }
460458 d.readErr = err
461459 // A control-message failure corrupts the descriptor stream, so it is
462460 // reported immediately instead of after the buffered bytes are used.
@@ -475,17 +473,13 @@ type signatureProvider interface{ EventSignature(uint16) (string, bool) }
475473 // dispatchFrame delivers one complete frame with precisely its signature's FDs.
476474 func (d *Display) dispatchFrame(f receivedFrame) error {
477475 d.recvMu.Lock()
478- obj, ev, kind, err := d.prepareFrame(f)
476+ obj, ev, err := d.prepareFrame(f)
479477 d.recvMu.Unlock()
480478 if err != nil {
481479 return err
482480 }
483- switch kind {
484- case 1:
481+ if obj == nil {
485482 return d.handleDisplayEvent(f.opcode, f.body)
486- case 2:
487- d.notifyListeners(f.object, f.opcode, f.body)
488- return nil
489483 }
490484 defer func() {
491485 for _, fd := range ev.fds {
@@ -494,50 +488,47 @@ func (d *Display) dispatchFrame(f receivedFrame) error {
494488 *ev = Event{}
495489 eventPool.Put(ev)
496490 }()
497- if proxy, ok := obj.(Proxy); ok {
498- proxy.Dispatch(ev)
499- } else {
500- d.dispatcher.Dispatch(f.object, f.opcode, f.body)
501- d.notifyListeners(f.object, f.opcode, f.body)
491+ if _, isZombie := obj.(*zombie); isZombie {
492+ return nil
493+ }
494+ // Another goroutine may have destroyed the object after prepareFrame
495+ // looked it up; a destroyed object receives no further events.
496+ if current, _ := d.objects.Load(f.object); current != obj {
497+ return nil
498+ }
499+ if r, ok := obj.(eventReceiver); ok {
500+ r.Dispatch(ev)
502501 }
503502 return nil
504503 }
505504
505+// eventReceiver is any registered object that handles its own events:
506+// generated proxies, callbacks and the registry.
507+type eventReceiver interface{ Dispatch(*Event) }
508+
506509 // prepareFrame assigns owned descriptors under recvMu, but never calls user code.
507-func (d *Display) prepareFrame(f receivedFrame) (Object, *Event, uint8, error) {
510+// A nil object with a nil error means the frame targets wl_display.
511+func (d *Display) prepareFrame(f receivedFrame) (Object, *Event, error) {
508512 if d.closed.Load() {
509- return nil, nil, 0, net.ErrClosed
513+ return nil, nil, net.ErrClosed
510514 }
511515 if f.object == displayObjectID {
512- if len(d.pendingFDs) != 0 && len(d.rbuf) == 0 {
513- return nil, nil, 0, &ProtocolError{Kind: "extra_fd", Err: ErrMalformedFrame}
514- }
515- return nil, nil, 1, nil
516- }
517- if f.object == d.registry.id {
518- var sig string
519- switch f.opcode {
520- case 0:
521- sig = "uint,string,uint,"
522- case 1:
523- sig = "uint,"
524- default:
525- return nil, nil, 0, &ProtocolError{Kind: "unknown_opcode", Object: f.object, Opcode: f.opcode, Err: ErrUnknownOpcode}
526- }
527- if err := validateEventBody(sig, f.body); err != nil {
528- return nil, nil, 0, &ProtocolError{Kind: "malformed_payload", Object: f.object, Opcode: f.opcode, Err: err}
529- }
530- if len(d.pendingFDs) != 0 && len(d.rbuf) == 0 {
531- return nil, nil, 0, &ProtocolError{Kind: "extra_fd", Object: f.object, Opcode: f.opcode, Err: ErrMalformedFrame}
516+ if len(d.pendingFDs) != 0 && !d.unread() {
517+ return nil, nil, &ProtocolError{Kind: "extra_fd", Err: ErrMalformedFrame}
532518 }
533- return nil, nil, 2, nil
519+ return nil, nil, nil
534520 }
535521 obj, ok := d.objects.Load(f.object)
536522 if !ok {
537- return nil, nil, 0, &ProtocolError{Kind: "unknown_object", Object: f.object, Opcode: f.opcode, Err: ErrUnknownObject}
523+ return nil, nil, &ProtocolError{Kind: "unknown_object", Object: f.object, Opcode: f.opcode, Err: ErrUnknownObject}
524+ }
525+ sigObj := obj
526+ z, isZombie := obj.(*zombie)
527+ if isZombie {
528+ sigObj = z.object
538529 }
539530 sig, valid := "", false
540- p, isGenerated := obj.(signatureProvider)
531+ p, isGenerated := sigObj.(signatureProvider)
541532 if isGenerated {
542533 sig, valid = p.EventSignature(f.opcode)
543534 }
@@ -548,14 +539,14 @@ func (d *Display) prepareFrame(f receivedFrame) (Object, *Event, uint8, error) {
548539 }
549540 }
550541 if !valid {
551- return nil, nil, 0, &ProtocolError{Kind: "unknown_opcode", Object: f.object, Opcode: f.opcode, Err: ErrUnknownOpcode}
542+ return nil, nil, &ProtocolError{Kind: "unknown_opcode", Object: f.object, Opcode: f.opcode, Err: ErrUnknownOpcode}
552543 }
553544 if err := validateEventBody(sig, f.body); err != nil {
554- return nil, nil, 0, &ProtocolError{Kind: "malformed_payload", Object: f.object, Opcode: f.opcode, Err: err}
545+ return nil, nil, &ProtocolError{Kind: "malformed_payload", Object: f.object, Opcode: f.opcode, Err: err}
555546 }
556547 count := strings.Count(sig, "fd,")
557548 if len(d.pendingFDs) < count {
558- return nil, nil, 0, &ProtocolError{Kind: "missing_fd", Object: f.object, Opcode: f.opcode, Err: ErrMalformedFrame}
549+ return nil, nil, &ProtocolError{Kind: "missing_fd", Object: f.object, Opcode: f.opcode, Err: ErrMalformedFrame}
559550 }
560551 ev := eventPool.Get().(*Event)
561552 *ev = Event{ProxyID: f.object, Opcode: f.opcode, data: f.body, display: d}
@@ -568,15 +559,17 @@ func (d *Display) prepareFrame(f receivedFrame) (Object, *Event, uint8, error) {
568559 }
569560 // FDs from a single recvmsg can accompany multiple coalesced frames. Once
570561 // all buffered bytes have been framed, surplus descriptors are not legal.
571- if len(d.rbuf) == 0 && len(d.pendingFDs) != 0 {
562+ if !d.unread() && len(d.pendingFDs) != 0 {
572563 for _, fd := range ev.fds {
573564 _ = fd.Close()
574565 }
575566 *ev = Event{}
576567 eventPool.Put(ev)
577- return nil, nil, 0, &ProtocolError{Kind: "extra_fd", Object: f.object, Opcode: f.opcode, Err: ErrMalformedFrame}
568+ return nil, nil, &ProtocolError{Kind: "extra_fd", Object: f.object, Opcode: f.opcode, Err: ErrMalformedFrame}
578569 }
579- return obj.(Object), ev, 0, nil
570+ // For a zombie the descriptors were still consumed above so the stream
571+ // stays aligned; dispatchFrame closes them without running any handler.
572+ return obj.(Object), ev, nil
580573 }
581574
582575 type signatureKey struct {
@@ -593,27 +586,6 @@ func (d *Display) RegisterEventSignature(object uint32, opcode uint16, signature
593586 d.signatures.Store(signatureKey{object, opcode}, signature)
594587 }
595588
596-// notifyListeners runs the listeners registered for an object and opcode.
597-func (d *Display) notifyListeners(objectID uint32, opcode uint16, body []byte) {
598- listeners, ok := d.listeners.Load(objectID)
599- if !ok {
600- return
601- }
602- opcodeMap, ok := listeners.(*sync.Map)
603- if !ok {
604- return
605- }
606- handlers, ok := opcodeMap.Load(opcode)
607- if !ok {
608- return
609- }
610- for _, handler := range handlers.([]func([]byte)) {
611- if handler != nil {
612- handler(body)
613- }
614- }
615-}
616-
617589 // handleDisplayEvent handles events on the display object
618590 func (d *Display) handleDisplayEvent(opcode uint16, data []byte) error {
619591 switch opcode {
@@ -624,12 +596,7 @@ func (d *Display) handleDisplayEvent(opcode uint16, data []byte) error {
624596 event := &Event{ProxyID: displayObjectID, Opcode: opcode, data: data, display: d}
625597 objectID := event.Uint32()
626598 code := event.Uint32()
627- message := event.String()
628-
629- d.lastErrorCode = code
630- d.lastErrorObj = objectID
631- d.lastError = &DisplayError{ObjectID: objectID, Code: code, Message: message}
632- return d.lastError
599+ return &DisplayError{ObjectID: objectID, Code: code, Message: event.String()}
633600
634601 case 1: // delete_id
635602 if len(data) != 4 {
@@ -637,7 +604,11 @@ func (d *Display) handleDisplayEvent(opcode uint16, data []byte) error {
637604 }
638605 id := binary.LittleEndian.Uint32(data[0:4])
639606 d.idMu.Lock()
640- _, live := d.objects.Load(id)
607+ obj, live := d.objects.Load(id)
608+ if _, isZombie := obj.(*zombie); isZombie {
609+ d.objects.CompareAndDelete(id, obj)
610+ live = false
611+ }
641612 if id < 2 || id >= 0xff000000 || id >= d.nextID || live || d.retiredIDs[id] {
642613 d.idMu.Unlock()
643614 return &ProtocolError{Kind: "invalid_delete_id", Object: id, Err: ErrMalformedFrame}
@@ -672,35 +643,9 @@ func (d *Display) Roundtrip() error {
672643 }
673644 }
674645
675-// AddListener adds an event listener for an object
676-func (d *Display) AddListener(objectID uint32, opcode uint16, handler func([]byte)) {
677- if handler == nil {
678- return
679- }
680- // Load or create listener map for object
681- listeners, _ := d.listeners.LoadOrStore(objectID, &sync.Map{})
682- opcodeMap := listeners.(*sync.Map)
683-
684- d.listenerMu.Lock()
685- defer d.listenerMu.Unlock()
686- var handlers []func([]byte)
687- if old, ok := opcodeMap.Load(opcode); ok {
688- handlers = old.([]func([]byte))
689- }
690- next := make([]func([]byte), len(handlers)+1)
691- copy(next, handlers)
692- next[len(handlers)] = handler
693- opcodeMap.Store(opcode, next)
694-}
695-
696-// getRegistry gets the global registry
646+// getRegistry sends wl_display.get_registry for the bootstrap registry.
697647 func (d *Display) getRegistry() error {
698- // Add registry listeners
699- d.AddListener(d.registry.id, 0, d.registry.handleGlobal)
700- d.AddListener(d.registry.id, 1, d.registry.handleGlobalRemove)
701-
702- // Send get_registry request (opcode 1)
703- return d.SendRequest(1, 1, d.registry.id)
648+ return d.SendRequest(displayObjectID, 1, d.registry.id)
704649 }
705650
706651 // Registry returns the global registry
@@ -713,66 +658,40 @@ func (r *Registry) ID() uint32 {
713658 return r.id
714659 }
715660
716-// handleGlobal handles global announcements
717-func (r *Registry) handleGlobal(data []byte) {
718- if len(data) < 8 {
719- return
720- }
721-
722- name := binary.LittleEndian.Uint32(data[0:4])
723- ifaceLen := binary.LittleEndian.Uint32(data[4:8])
724-
725- if ifaceLen == 0 || uint64(ifaceLen)+12 > uint64(len(data)) || data[8+ifaceLen-1] != 0 {
726- return
661+// EventSignature reports the wl_registry event signatures.
662+func (r *Registry) EventSignature(opcode uint16) (string, bool) {
663+ switch opcode {
664+ case 0:
665+ return "uint,string,uint,", true
666+ case 1:
667+ return "uint,", true
727668 }
669+ return "", false
670+}
728671
729- // String includes null terminator in length
730- iface := string(data[8 : 8+ifaceLen-1]) // -1 to remove null terminator
731-
732- // Calculate padding for 32-bit alignment
733- padding := (4 - (ifaceLen % 4)) % 4
734- versionOffset := 8 + int(ifaceLen) + int(padding)
735-
736- if len(data) != versionOffset+4 {
737- return
672+// Dispatch handles wl_registry.global and wl_registry.global_remove. The
673+// transport has already validated the body against EventSignature.
674+func (r *Registry) Dispatch(event *Event) {
675+ switch event.Opcode {
676+ case 0:
677+ r.handleGlobal(event.Uint32(), event.String(), event.Uint32())
678+ case 1:
679+ r.handleGlobalRemove(event.Uint32())
738680 }
681+}
739682
740- version := binary.LittleEndian.Uint32(data[versionOffset:])
741-
742- // Store global
683+func (r *Registry) handleGlobal(name uint32, iface string, version uint32) {
743684 r.mu.Lock()
744- r.globals[name] = Global{
745- Name: name,
746- Interface: iface,
747- Version: version,
748- }
685+ r.globals[name] = Global{Name: name, Interface: iface, Version: version}
686+ handlers := append([]GlobalHandler(nil), r.handlers[iface]...)
687+ handlers = append(handlers, r.handlers["*"]...)
749688 r.mu.Unlock()
750-
751- // Call specific handler if registered
752- r.mu.RLock()
753- handler, specific := r.handlers[iface]
754- wildcard, all := r.handlers["*"]
755- r.mu.RUnlock()
756- if specific {
757-
689+ for _, handler := range handlers {
758690 handler(r, name, version)
759691 }
760-
761- // Call wildcard handler if registered
762- if all {
763-
764- wildcard(r, name, version)
765- }
766692 }
767693
768-// handleGlobalRemove handles global removal
769-func (r *Registry) handleGlobalRemove(data []byte) {
770- if len(data) < 4 {
771- return
772- }
773-
774- name := binary.LittleEndian.Uint32(data[0:4])
775-
694+func (r *Registry) handleGlobalRemove(name uint32) {
776695 r.mu.Lock()
777696 delete(r.globals, name)
778697 handlers := append([]RegistryGlobalRemoveHandler(nil), r.removeHandlers...)
@@ -782,11 +701,16 @@ func (r *Registry) handleGlobalRemove(data []byte) {
782701 }
783702 }
784703
785-// AddHandler adds a handler for a specific interface
704+// AddHandler adds a handler for a specific interface, or "*" for every
705+// interface. Handlers accumulate; each announced global calls all of them in
706+// registration order.
786707 func (r *Registry) AddHandler(iface string, handler GlobalHandler) {
708+ if handler == nil {
709+ return
710+ }
787711 r.mu.Lock()
788712 defer r.mu.Unlock()
789- r.handlers[iface] = handler
713+ r.handlers[iface] = append(r.handlers[iface], handler)
790714 }
791715
792716 // ErrGlobalNotFound reports that the compositor does not announce a global.
@@ -838,6 +762,9 @@ func (r *Registry) Bind(name uint32, iface string, version uint32, proxy Proxy)
838762 if old, exists := r.display.objects.Load(proxy.ID()); exists && old != proxy {
839763 return fmt.Errorf("object ID %d already registered", proxy.ID())
840764 }
765+ if v, ok := proxy.(interface{ SetVersion(uint32) }); ok {
766+ v.SetVersion(version)
767+ }
841768 // Register the proxy
842769 proxy.Context().Register(proxy)
843770
@@ -1,7 +1,6 @@
1-// Package wlturbo provides a high-performance Wayland client implementation optimized for gaming and real-time applications.1+// Package wlturbo is a Wayland client transport for Go: connection, framing,
2-//2+// descriptor passing, object lifecycle and the bootstrap registry. Protocol
3-// This package delivers sub-microsecond latency, zero-allocation hot paths, and support for 8000Hz gaming devices.3+// bindings are generated into the protocol/ packages.
4-// It's designed for video game engines, competitive gaming, and other performance-critical applications.
5 package wlturbo4 package wlturbo
6 5
7 import (6 import (
@@ -56,26 +55,17 @@ type Display struct {
56 recvMu sync.Mutex55 recvMu sync.Mutex
57 dispatchMu sync.Mutex // serialize readers without holding receive state across handlers56 dispatchMu sync.Mutex // serialize readers without holding receive state across handlers
58 signatures sync.Map57 signatures sync.Map
59- listenerMu sync.Mutex
60- listeners sync.Map // map[uint32]map[uint16][]func([]byte)
61-
62- // High-performance event dispatcher
63- dispatcher *EventDispatcher
64 58
65 // Core objects59 // Core objects
66 registry *Registry60 registry *Registry
67 context *Context // Store context once61 context *Context // Store context once
68 62
69- // Error state63+ // Connection-local receive state. rbuf[rpos:] holds bytes read from the
70- lastError error64+ // socket that have not been framed yet; recvBuf is the scratch buffer used
71- lastErrorCode uint3265+ // for a single read. pendingFDs holds ancillary descriptors that arrived
72- lastErrorObj uint3266+ // with those bytes and have not been consumed yet.
73-
74- // Connection-local receive state. rbuf holds bytes read from the socket
75- // that do not yet form a complete frame; recvBuf is the scratch buffer
76- // used for a single read. pendingFDs holds ancillary descriptors that
77- // arrived with those bytes and have not been consumed yet.
78 rbuf []byte67 rbuf []byte
68+ rpos int
79 recvBuf []byte69 recvBuf []byte
80 readErr error70 readErr error
81 maxMsgLen uint3271 maxMsgLen uint32
@@ -86,9 +76,8 @@ type Display struct {
86 // newDisplay builds a Display over an established connection.76 // newDisplay builds a Display over an established connection.
87 func newDisplay(conn net.Conn) *Display {77 func newDisplay(conn net.Conn) *Display {
88 d := &Display{78 d := &Display{
89- conn: conn,79+ conn: conn,
90- nextID: 2, // 1 is reserved for wl_display80+ nextID: 2, // 1 is reserved for wl_display
91- dispatcher: NewEventDispatcher(),
92 }81 }
93 if uc, ok := conn.(*net.UnixConn); ok {82 if uc, ok := conn.(*net.UnixConn); ok {
94 d.unix = uc83 d.unix = uc
@@ -101,7 +90,7 @@ func newDisplay(conn net.Conn) *Display {
101 id: d.allocateID(),90 id: d.allocateID(),
102 display: d,91 display: d,
103 globals: make(map[uint32]Global),92 globals: make(map[uint32]Global),
104- handlers: make(map[string]GlobalHandler),93+ handlers: make(map[string][]GlobalHandler),
105 }94 }
106 d.objects.Store(d.registry.id, d.registry)95 d.objects.Store(d.registry.id, d.registry)
107 return d96 return d
@@ -113,7 +102,7 @@ type Registry struct {
113 display *Display102 display *Display
114 globals map[uint32]Global103 globals map[uint32]Global
115 mu sync.RWMutex104 mu sync.RWMutex
116- handlers map[string]GlobalHandler105+ handlers map[string][]GlobalHandler
117 removeHandlers []RegistryGlobalRemoveHandler106 removeHandlers []RegistryGlobalRemoveHandler
118 }107 }
119 108
@@ -138,7 +127,6 @@ func (c *callbackObject) Dispatch(event *Event) {
138 if event.Opcode != 0 { // done event127 if event.Opcode != 0 { // done event
139 return128 return
140 }129 }
141- c.display.notifyListeners(c.id, 0, event.data)
142 c.display.context.Unregister(c)130 c.display.context.Unregister(c)
143 }131 }
144 132
@@ -212,11 +200,6 @@ func (d *Display) ID() uint32 {
212 return 1200 return 1
213 }201 }
214 202
215-// RegisterEventHandler registers a high-performance event handler
216-func (d *Display) RegisterEventHandler(objectID uint32, opcode uint16, handler EventHandler) {
217- d.dispatcher.RegisterHandler(objectID, opcode, handler)
218-}
219-
220 // allocateID allocates a new object ID203 // allocateID allocates a new object ID
221 func (d *Display) allocateID() uint32 {204 func (d *Display) allocateID() uint32 {
222 d.idMu.Lock()205 d.idMu.Lock()
@@ -261,8 +244,8 @@ func (d *Display) sendRequest(objectID uint32, opcode uint16, fds []int, guard f
261 }()244 }()
262 245
263 // Write header placeholder246 // Write header placeholder
264- header := make([]byte, 8)247+ var header [HeaderSize]byte
265- _, _ = buf.Write(header)248+ _, _ = buf.Write(header[:])
266 249
267 // Marshal arguments250 // Marshal arguments
268 for _, arg := range args {251 for _, arg := range args {
@@ -283,30 +266,35 @@ func (d *Display) sendRequest(objectID uint32, opcode uint16, fds []int, guard f
283 266
284 // Update buffer with correct header267 // Update buffer with correct header
285 data := buf.Bytes()268 data := buf.Bytes()
286- copy(data[0:8], header)269+ copy(data[0:8], header[:])
287 270
288 // Send message with optional file descriptors271 // Send message with optional file descriptors
289 return d.sendmsgWithFDs(data, fds, guard)272 return d.sendmsgWithFDs(data, fds, guard)
290 }273 }
291 274
275+// putUint32 appends one little-endian wire word without allocating.
276+func putUint32(buf *bytes.Buffer, v uint32) {
277+ var w [4]byte
278+ binary.LittleEndian.PutUint32(w[:], v)
279+ _, _ = buf.Write(w[:])
280+}
281+
292 // marshalArg marshals a single argument282 // marshalArg marshals a single argument
293 func (d *Display) marshalArg(buf *bytes.Buffer, arg interface{}) error {283 func (d *Display) marshalArg(buf *bytes.Buffer, arg interface{}) error {
294 switch v := arg.(type) {284 switch v := arg.(type) {
295 case uint32:285 case uint32:
296- return binary.Write(buf, binary.LittleEndian, v)286+ putUint32(buf, v)
297 case int32:287 case int32:
298- return binary.Write(buf, binary.LittleEndian, v)288+ putUint32(buf, uint32(v))
299 case Fixed:289 case Fixed:
300- return binary.Write(buf, binary.LittleEndian, int32(v))290+ putUint32(buf, uint32(v))
301 case string:291 case string:
302 // String format: length (including null) + string + null + padding292 // String format: length (including null) + string + null + padding
303 strlen := len(v) + 1293 strlen := len(v) + 1
304 if strlen > 0xffff-HeaderSize {294 if strlen > 0xffff-HeaderSize {
305 return fmt.Errorf("string too long: %d bytes", strlen)295 return fmt.Errorf("string too long: %d bytes", strlen)
306 }296 }
307- if err := binary.Write(buf, binary.LittleEndian, uint32(strlen)); err != nil { // Safe: checked above297+ putUint32(buf, uint32(strlen)) // Safe: checked above
308- return err
309- }
310 _, _ = buf.WriteString(v)298 _, _ = buf.WriteString(v)
311 _ = buf.WriteByte(0)299 _ = buf.WriteByte(0)
312 // Pad to 32-bit boundary300 // Pad to 32-bit boundary
@@ -320,9 +308,7 @@ func (d *Display) marshalArg(buf *bytes.Buffer, arg interface{}) error {
320 if arrlen > 0xffff-HeaderSize {308 if arrlen > 0xffff-HeaderSize {
321 return fmt.Errorf("array too long: %d bytes", arrlen)309 return fmt.Errorf("array too long: %d bytes", arrlen)
322 }310 }
323- if err := binary.Write(buf, binary.LittleEndian, uint32(arrlen)); err != nil {311+ putUint32(buf, uint32(arrlen))
324- return err
325- }
326 _, _ = buf.Write(v)312 _, _ = buf.Write(v)
327 // Pad to 32-bit boundary313 // Pad to 32-bit boundary
328 padding := (4 - (arrlen % 4)) % 4314 padding := (4 - (arrlen % 4)) % 4
@@ -331,16 +317,13 @@ func (d *Display) marshalArg(buf *bytes.Buffer, arg interface{}) error {
331 }317 }
332 case Object:318 case Object:
333 if v != nil {319 if v != nil {
334- return binary.Write(buf, binary.LittleEndian, v.ID())320+ putUint32(buf, v.ID())
321+ } else {
322+ putUint32(buf, 0)
335 }323 }
336- return binary.Write(buf, binary.LittleEndian, uint32(0))
337 case nil:324 case nil:
338 // Null object325 // Null object
339- return binary.Write(buf, binary.LittleEndian, uint32(0))326+ putUint32(buf, 0)
340- case int:
341- // File descriptor - write placeholder in message
342- // Actual FD will be sent via SCM_RIGHTS
343- return binary.Write(buf, binary.LittleEndian, uint32(0))
344 case uintptr:327 case uintptr:
345 // File descriptor as uintptr - NO placeholder in message for neurlang compatibility328 // File descriptor as uintptr - NO placeholder in message for neurlang compatibility
346 // FD is ONLY sent via SCM_RIGHTS, not in the message body329 // FD is ONLY sent via SCM_RIGHTS, not in the message body
@@ -357,7 +340,12 @@ func (d *Display) marshalArg(buf *bytes.Buffer, arg interface{}) error {
357 // Read boundaries never define message boundaries: a header split across340 // Read boundaries never define message boundaries: a header split across
358 // several reads and several messages arriving in one read are both handled.341 // several reads and several messages arriving in one read are both handled.
359 // Dispatch returns net.ErrClosed after Close, a typed ProtocolError for a342 // Dispatch returns net.ErrClosed after Close, a typed ProtocolError for a
360-// malformed frame, and io.ErrUnexpectedEOF when the peer closes mid-frame.343+// malformed frame, io.ErrUnexpectedEOF when the peer closes mid-frame, and
344+// os.ErrDeadlineExceeded (not sticky) when a read deadline expires.
345+//
346+// Event handlers run while Dispatch holds the dispatch lock, so a handler must
347+// not call Dispatch or Roundtrip on the same Display: that call deadlocks.
348+// Hand work that needs a roundtrip to another goroutine instead.
361 func (d *Display) Dispatch() error {349 func (d *Display) Dispatch() error {
362 d.dispatchMu.Lock()350 d.dispatchMu.Lock()
363 defer d.dispatchMu.Unlock()351 defer d.dispatchMu.Unlock()
@@ -409,18 +397,20 @@ func (d *Display) maxMessageSize() uint32 {
409 // nextFrame returns the next complete frame, reading more bytes as needed.397 // nextFrame returns the next complete frame, reading more bytes as needed.
410 func (d *Display) nextFrame() (receivedFrame, error) {398 func (d *Display) nextFrame() (receivedFrame, error) {
411 for {399 for {
412- if len(d.rbuf) >= HeaderSize {400+ buf := d.rbuf[d.rpos:]
413- object, opcode, size, err := parseHeader(d.rbuf[:HeaderSize], d.maxMessageSize())401+ if len(buf) >= HeaderSize {
402+ object, opcode, size, err := parseHeader(buf[:HeaderSize], d.maxMessageSize())
414 if err != nil {403 if err != nil {
415 return receivedFrame{}, err404 return receivedFrame{}, err
416 }405 }
417- if uint32(len(d.rbuf)) >= size {406+ if uint32(len(buf)) >= size {
407+ // The body aliases the receive buffer. It stays valid until
408+ // the next fill, which only happens in a later Dispatch.
418 frame := receivedFrame{object: object, opcode: opcode}409 frame := receivedFrame{object: object, opcode: opcode}
419 if size > HeaderSize {410 if size > HeaderSize {
420- frame.body = make([]byte, size-HeaderSize)411+ frame.body = buf[HeaderSize:size:size]
421- copy(frame.body, d.rbuf[HeaderSize:size])
422 }412 }
423- d.consume(size)413+ d.rpos += int(size)
424 return frame, nil414 return frame, nil
425 }415 }
426 }416 }
@@ -433,11 +423,8 @@ func (d *Display) nextFrame() (receivedFrame, error) {
433 }423 }
434 }424 }
435 425
436-// consume removes the first n bytes from the receive buffer.426+// unread reports whether received bytes remain that have not been framed.
437-func (d *Display) consume(n uint32) {427+func (d *Display) unread() bool { return d.rpos < len(d.rbuf) }
438- rest := copy(d.rbuf, d.rbuf[n:])
439- d.rbuf = d.rbuf[:rest]
440-}
441 428
442 // fill reads one chunk from the connection into the receive buffer. Bytes that429 // fill reads one chunk from the connection into the receive buffer. Bytes that
443 // arrive together with an error are kept so they are still parsed before the430 // arrive together with an error are kept so they are still parsed before the
@@ -449,6 +436,12 @@ func (d *Display) fill() error {
449 if d.recvBuf == nil {436 if d.recvBuf == nil {
450 d.recvBuf = make([]byte, readChunkSize)437 d.recvBuf = make([]byte, readChunkSize)
451 }438 }
439+ // Compact once per read rather than once per frame, so framing cost does
440+ // not grow with the number of buffered messages.
441+ if d.rpos > 0 {
442+ d.rbuf = d.rbuf[:copy(d.rbuf, d.rbuf[d.rpos:])]
443+ d.rpos = 0
444+ }
452 n, err := d.readChunk()445 n, err := d.readChunk()
453 if n > 0 {446 if n > 0 {
454 d.rbuf = append(d.rbuf, d.recvBuf[:n]...)447 d.rbuf = append(d.rbuf, d.recvBuf[:n]...)
@@ -457,6 +450,11 @@ func (d *Display) fill() error {
457 if errors.Is(err, io.EOF) {450 if errors.Is(err, io.EOF) {
458 err = io.ErrUnexpectedEOF451 err = io.ErrUnexpectedEOF
459 }452 }
453+ // A missed deadline is not a broken stream: report it without making
454+ // it sticky, so a later Dispatch can read again.
455+ if errors.Is(err, os.ErrDeadlineExceeded) {
456+ return err
457+ }
460 d.readErr = err458 d.readErr = err
461 // A control-message failure corrupts the descriptor stream, so it is459 // A control-message failure corrupts the descriptor stream, so it is
462 // reported immediately instead of after the buffered bytes are used.460 // reported immediately instead of after the buffered bytes are used.
@@ -475,17 +473,13 @@ type signatureProvider interface{ EventSignature(uint16) (string, bool) }
475 // dispatchFrame delivers one complete frame with precisely its signature's FDs.473 // dispatchFrame delivers one complete frame with precisely its signature's FDs.
476 func (d *Display) dispatchFrame(f receivedFrame) error {474 func (d *Display) dispatchFrame(f receivedFrame) error {
477 d.recvMu.Lock()475 d.recvMu.Lock()
478- obj, ev, kind, err := d.prepareFrame(f)476+ obj, ev, err := d.prepareFrame(f)
479 d.recvMu.Unlock()477 d.recvMu.Unlock()
480 if err != nil {478 if err != nil {
481 return err479 return err
482 }480 }
483- switch kind {481+ if obj == nil {
484- case 1:
485 return d.handleDisplayEvent(f.opcode, f.body)482 return d.handleDisplayEvent(f.opcode, f.body)
486- case 2:
487- d.notifyListeners(f.object, f.opcode, f.body)
488- return nil
489 }483 }
490 defer func() {484 defer func() {
491 for _, fd := range ev.fds {485 for _, fd := range ev.fds {
@@ -494,50 +488,47 @@ func (d *Display) dispatchFrame(f receivedFrame) error {
494 *ev = Event{}488 *ev = Event{}
495 eventPool.Put(ev)489 eventPool.Put(ev)
496 }()490 }()
497- if proxy, ok := obj.(Proxy); ok {491+ if _, isZombie := obj.(*zombie); isZombie {
498- proxy.Dispatch(ev)492+ return nil
499- } else {493+ }
500- d.dispatcher.Dispatch(f.object, f.opcode, f.body)494+ // Another goroutine may have destroyed the object after prepareFrame
501- d.notifyListeners(f.object, f.opcode, f.body)495+ // looked it up; a destroyed object receives no further events.
496+ if current, _ := d.objects.Load(f.object); current != obj {
497+ return nil
498+ }
499+ if r, ok := obj.(eventReceiver); ok {
500+ r.Dispatch(ev)
502 }501 }
503 return nil502 return nil
504 }503 }
505 504
505+// eventReceiver is any registered object that handles its own events:
506+// generated proxies, callbacks and the registry.
507+type eventReceiver interface{ Dispatch(*Event) }
508+
506 // prepareFrame assigns owned descriptors under recvMu, but never calls user code.509 // prepareFrame assigns owned descriptors under recvMu, but never calls user code.
507-func (d *Display) prepareFrame(f receivedFrame) (Object, *Event, uint8, error) {510+// A nil object with a nil error means the frame targets wl_display.
511+func (d *Display) prepareFrame(f receivedFrame) (Object, *Event, error) {
508 if d.closed.Load() {512 if d.closed.Load() {
509- return nil, nil, 0, net.ErrClosed513+ return nil, nil, net.ErrClosed
510 }514 }
511 if f.object == displayObjectID {515 if f.object == displayObjectID {
512- if len(d.pendingFDs) != 0 && len(d.rbuf) == 0 {516+ if len(d.pendingFDs) != 0 && !d.unread() {
513- return nil, nil, 0, &ProtocolError{Kind: "extra_fd", Err: ErrMalformedFrame}517+ return nil, nil, &ProtocolError{Kind: "extra_fd", Err: ErrMalformedFrame}
514- }
515- return nil, nil, 1, nil
516- }
517- if f.object == d.registry.id {
518- var sig string
519- switch f.opcode {
520- case 0:
521- sig = "uint,string,uint,"
522- case 1:
523- sig = "uint,"
524- default:
525- return nil, nil, 0, &ProtocolError{Kind: "unknown_opcode", Object: f.object, Opcode: f.opcode, Err: ErrUnknownOpcode}
526- }
527- if err := validateEventBody(sig, f.body); err != nil {
528- return nil, nil, 0, &ProtocolError{Kind: "malformed_payload", Object: f.object, Opcode: f.opcode, Err: err}
529- }
530- if len(d.pendingFDs) != 0 && len(d.rbuf) == 0 {
531- return nil, nil, 0, &ProtocolError{Kind: "extra_fd", Object: f.object, Opcode: f.opcode, Err: ErrMalformedFrame}
532 }518 }
533- return nil, nil, 2, nil519+ return nil, nil, nil
534 }520 }
535 obj, ok := d.objects.Load(f.object)521 obj, ok := d.objects.Load(f.object)
536 if !ok {522 if !ok {
537- return nil, nil, 0, &ProtocolError{Kind: "unknown_object", Object: f.object, Opcode: f.opcode, Err: ErrUnknownObject}523+ return nil, nil, &ProtocolError{Kind: "unknown_object", Object: f.object, Opcode: f.opcode, Err: ErrUnknownObject}
524+ }
525+ sigObj := obj
526+ z, isZombie := obj.(*zombie)
527+ if isZombie {
528+ sigObj = z.object
538 }529 }
539 sig, valid := "", false530 sig, valid := "", false
540- p, isGenerated := obj.(signatureProvider)531+ p, isGenerated := sigObj.(signatureProvider)
541 if isGenerated {532 if isGenerated {
542 sig, valid = p.EventSignature(f.opcode)533 sig, valid = p.EventSignature(f.opcode)
543 }534 }
@@ -548,14 +539,14 @@ func (d *Display) prepareFrame(f receivedFrame) (Object, *Event, uint8, error) {
548 }539 }
549 }540 }
550 if !valid {541 if !valid {
551- return nil, nil, 0, &ProtocolError{Kind: "unknown_opcode", Object: f.object, Opcode: f.opcode, Err: ErrUnknownOpcode}542+ return nil, nil, &ProtocolError{Kind: "unknown_opcode", Object: f.object, Opcode: f.opcode, Err: ErrUnknownOpcode}
552 }543 }
553 if err := validateEventBody(sig, f.body); err != nil {544 if err := validateEventBody(sig, f.body); err != nil {
554- return nil, nil, 0, &ProtocolError{Kind: "malformed_payload", Object: f.object, Opcode: f.opcode, Err: err}545+ return nil, nil, &ProtocolError{Kind: "malformed_payload", Object: f.object, Opcode: f.opcode, Err: err}
555 }546 }
556 count := strings.Count(sig, "fd,")547 count := strings.Count(sig, "fd,")
557 if len(d.pendingFDs) < count {548 if len(d.pendingFDs) < count {
558- return nil, nil, 0, &ProtocolError{Kind: "missing_fd", Object: f.object, Opcode: f.opcode, Err: ErrMalformedFrame}549+ return nil, nil, &ProtocolError{Kind: "missing_fd", Object: f.object, Opcode: f.opcode, Err: ErrMalformedFrame}
559 }550 }
560 ev := eventPool.Get().(*Event)551 ev := eventPool.Get().(*Event)
561 *ev = Event{ProxyID: f.object, Opcode: f.opcode, data: f.body, display: d}552 *ev = Event{ProxyID: f.object, Opcode: f.opcode, data: f.body, display: d}
@@ -568,15 +559,17 @@ func (d *Display) prepareFrame(f receivedFrame) (Object, *Event, uint8, error) {
568 }559 }
569 // FDs from a single recvmsg can accompany multiple coalesced frames. Once560 // FDs from a single recvmsg can accompany multiple coalesced frames. Once
570 // all buffered bytes have been framed, surplus descriptors are not legal.561 // all buffered bytes have been framed, surplus descriptors are not legal.
571- if len(d.rbuf) == 0 && len(d.pendingFDs) != 0 {562+ if !d.unread() && len(d.pendingFDs) != 0 {
572 for _, fd := range ev.fds {563 for _, fd := range ev.fds {
573 _ = fd.Close()564 _ = fd.Close()
574 }565 }
575 *ev = Event{}566 *ev = Event{}
576 eventPool.Put(ev)567 eventPool.Put(ev)
577- return nil, nil, 0, &ProtocolError{Kind: "extra_fd", Object: f.object, Opcode: f.opcode, Err: ErrMalformedFrame}568+ return nil, nil, &ProtocolError{Kind: "extra_fd", Object: f.object, Opcode: f.opcode, Err: ErrMalformedFrame}
578 }569 }
579- return obj.(Object), ev, 0, nil570+ // For a zombie the descriptors were still consumed above so the stream
571+ // stays aligned; dispatchFrame closes them without running any handler.
572+ return obj.(Object), ev, nil
580 }573 }
581 574
582 type signatureKey struct {575 type signatureKey struct {
@@ -593,27 +586,6 @@ func (d *Display) RegisterEventSignature(object uint32, opcode uint16, signature
593 d.signatures.Store(signatureKey{object, opcode}, signature)586 d.signatures.Store(signatureKey{object, opcode}, signature)
594 }587 }
595 588
596-// notifyListeners runs the listeners registered for an object and opcode.
597-func (d *Display) notifyListeners(objectID uint32, opcode uint16, body []byte) {
598- listeners, ok := d.listeners.Load(objectID)
599- if !ok {
600- return
601- }
602- opcodeMap, ok := listeners.(*sync.Map)
603- if !ok {
604- return
605- }
606- handlers, ok := opcodeMap.Load(opcode)
607- if !ok {
608- return
609- }
610- for _, handler := range handlers.([]func([]byte)) {
611- if handler != nil {
612- handler(body)
613- }
614- }
615-}
616-
617 // handleDisplayEvent handles events on the display object589 // handleDisplayEvent handles events on the display object
618 func (d *Display) handleDisplayEvent(opcode uint16, data []byte) error {590 func (d *Display) handleDisplayEvent(opcode uint16, data []byte) error {
619 switch opcode {591 switch opcode {
@@ -624,12 +596,7 @@ func (d *Display) handleDisplayEvent(opcode uint16, data []byte) error {
624 event := &Event{ProxyID: displayObjectID, Opcode: opcode, data: data, display: d}596 event := &Event{ProxyID: displayObjectID, Opcode: opcode, data: data, display: d}
625 objectID := event.Uint32()597 objectID := event.Uint32()
626 code := event.Uint32()598 code := event.Uint32()
627- message := event.String()599+ return &DisplayError{ObjectID: objectID, Code: code, Message: event.String()}
628-
629- d.lastErrorCode = code
630- d.lastErrorObj = objectID
631- d.lastError = &DisplayError{ObjectID: objectID, Code: code, Message: message}
632- return d.lastError
633 600
634 case 1: // delete_id601 case 1: // delete_id
635 if len(data) != 4 {602 if len(data) != 4 {
@@ -637,7 +604,11 @@ func (d *Display) handleDisplayEvent(opcode uint16, data []byte) error {
637 }604 }
638 id := binary.LittleEndian.Uint32(data[0:4])605 id := binary.LittleEndian.Uint32(data[0:4])
639 d.idMu.Lock()606 d.idMu.Lock()
640- _, live := d.objects.Load(id)607+ obj, live := d.objects.Load(id)
608+ if _, isZombie := obj.(*zombie); isZombie {
609+ d.objects.CompareAndDelete(id, obj)
610+ live = false
611+ }
641 if id < 2 || id >= 0xff000000 || id >= d.nextID || live || d.retiredIDs[id] {612 if id < 2 || id >= 0xff000000 || id >= d.nextID || live || d.retiredIDs[id] {
642 d.idMu.Unlock()613 d.idMu.Unlock()
643 return &ProtocolError{Kind: "invalid_delete_id", Object: id, Err: ErrMalformedFrame}614 return &ProtocolError{Kind: "invalid_delete_id", Object: id, Err: ErrMalformedFrame}
@@ -672,35 +643,9 @@ func (d *Display) Roundtrip() error {
672 }643 }
673 }644 }
674 645
675-// AddListener adds an event listener for an object646+// getRegistry sends wl_display.get_registry for the bootstrap registry.
676-func (d *Display) AddListener(objectID uint32, opcode uint16, handler func([]byte)) {
677- if handler == nil {
678- return
679- }
680- // Load or create listener map for object
681- listeners, _ := d.listeners.LoadOrStore(objectID, &sync.Map{})
682- opcodeMap := listeners.(*sync.Map)
683-
684- d.listenerMu.Lock()
685- defer d.listenerMu.Unlock()
686- var handlers []func([]byte)
687- if old, ok := opcodeMap.Load(opcode); ok {
688- handlers = old.([]func([]byte))
689- }
690- next := make([]func([]byte), len(handlers)+1)
691- copy(next, handlers)
692- next[len(handlers)] = handler
693- opcodeMap.Store(opcode, next)
694-}
695-
696-// getRegistry gets the global registry
697 func (d *Display) getRegistry() error {647 func (d *Display) getRegistry() error {
698- // Add registry listeners648+ return d.SendRequest(displayObjectID, 1, d.registry.id)
699- d.AddListener(d.registry.id, 0, d.registry.handleGlobal)
700- d.AddListener(d.registry.id, 1, d.registry.handleGlobalRemove)
701-
702- // Send get_registry request (opcode 1)
703- return d.SendRequest(1, 1, d.registry.id)
704 }649 }
705 650
706 // Registry returns the global registry651 // Registry returns the global registry
@@ -713,66 +658,40 @@ func (r *Registry) ID() uint32 {
713 return r.id658 return r.id
714 }659 }
715 660
716-// handleGlobal handles global announcements661+// EventSignature reports the wl_registry event signatures.
717-func (r *Registry) handleGlobal(data []byte) {662+func (r *Registry) EventSignature(opcode uint16) (string, bool) {
718- if len(data) < 8 {663+ switch opcode {
719- return664+ case 0:
720- }665+ return "uint,string,uint,", true
721-666+ case 1:
722- name := binary.LittleEndian.Uint32(data[0:4])667+ return "uint,", true
723- ifaceLen := binary.LittleEndian.Uint32(data[4:8])
724-
725- if ifaceLen == 0 || uint64(ifaceLen)+12 > uint64(len(data)) || data[8+ifaceLen-1] != 0 {
726- return
727 }668 }
669+ return "", false
670+}
728 671
729- // String includes null terminator in length672+// Dispatch handles wl_registry.global and wl_registry.global_remove. The
730- iface := string(data[8 : 8+ifaceLen-1]) // -1 to remove null terminator673+// transport has already validated the body against EventSignature.
731-674+func (r *Registry) Dispatch(event *Event) {
732- // Calculate padding for 32-bit alignment675+ switch event.Opcode {
733- padding := (4 - (ifaceLen % 4)) % 4676+ case 0:
734- versionOffset := 8 + int(ifaceLen) + int(padding)677+ r.handleGlobal(event.Uint32(), event.String(), event.Uint32())
735-678+ case 1:
736- if len(data) != versionOffset+4 {679+ r.handleGlobalRemove(event.Uint32())
737- return
738 }680 }
681+}
739 682
740- version := binary.LittleEndian.Uint32(data[versionOffset:])683+func (r *Registry) handleGlobal(name uint32, iface string, version uint32) {
741-
742- // Store global
743 r.mu.Lock()684 r.mu.Lock()
744- r.globals[name] = Global{685+ r.globals[name] = Global{Name: name, Interface: iface, Version: version}
745- Name: name,686+ handlers := append([]GlobalHandler(nil), r.handlers[iface]...)
746- Interface: iface,687+ handlers = append(handlers, r.handlers["*"]...)
747- Version: version,
748- }
749 r.mu.Unlock()688 r.mu.Unlock()
750-689+ for _, handler := range handlers {
751- // Call specific handler if registered
752- r.mu.RLock()
753- handler, specific := r.handlers[iface]
754- wildcard, all := r.handlers["*"]
755- r.mu.RUnlock()
756- if specific {
757-
758 handler(r, name, version)690 handler(r, name, version)
759 }691 }
760-
761- // Call wildcard handler if registered
762- if all {
763-
764- wildcard(r, name, version)
765- }
766 }692 }
767 693
768-// handleGlobalRemove handles global removal694+func (r *Registry) handleGlobalRemove(name uint32) {
769-func (r *Registry) handleGlobalRemove(data []byte) {
770- if len(data) < 4 {
771- return
772- }
773-
774- name := binary.LittleEndian.Uint32(data[0:4])
775-
776 r.mu.Lock()695 r.mu.Lock()
777 delete(r.globals, name)696 delete(r.globals, name)
778 handlers := append([]RegistryGlobalRemoveHandler(nil), r.removeHandlers...)697 handlers := append([]RegistryGlobalRemoveHandler(nil), r.removeHandlers...)
@@ -782,11 +701,16 @@ func (r *Registry) handleGlobalRemove(data []byte) {
782 }701 }
783 }702 }
784 703
785-// AddHandler adds a handler for a specific interface704+// AddHandler adds a handler for a specific interface, or "*" for every
705+// interface. Handlers accumulate; each announced global calls all of them in
706+// registration order.
786 func (r *Registry) AddHandler(iface string, handler GlobalHandler) {707 func (r *Registry) AddHandler(iface string, handler GlobalHandler) {
708+ if handler == nil {
709+ return
710+ }
787 r.mu.Lock()711 r.mu.Lock()
788 defer r.mu.Unlock()712 defer r.mu.Unlock()
789- r.handlers[iface] = handler713+ r.handlers[iface] = append(r.handlers[iface], handler)
790 }714 }
791 715
792 // ErrGlobalNotFound reports that the compositor does not announce a global.716 // ErrGlobalNotFound reports that the compositor does not announce a global.
@@ -838,6 +762,9 @@ func (r *Registry) Bind(name uint32, iface string, version uint32, proxy Proxy)
838 if old, exists := r.display.objects.Load(proxy.ID()); exists && old != proxy {762 if old, exists := r.display.objects.Load(proxy.ID()); exists && old != proxy {
839 return fmt.Errorf("object ID %d already registered", proxy.ID())763 return fmt.Errorf("object ID %d already registered", proxy.ID())
840 }764 }
765+ if v, ok := proxy.(interface{ SetVersion(uint32) }); ok {
766+ v.SetVersion(version)
767+ }
841 // Register the proxy768 // Register the proxy
842 proxy.Context().Register(proxy)769 proxy.Context().Register(proxy)
843 770
M client_test.go +0 -98
@@ -40,86 +40,6 @@ func TestFixed(t *testing.T) {
4040 }
4141 }
4242
43-func TestEventPool(t *testing.T) {
44- // Test that the global event pool works without requiring a compositor
45- // Get an event
46- event := eventPool.Get().(*Event)
47- if event == nil {
48- t.Fatal("Expected event from pool, got nil")
49- }
50-
51- // Set some data
52- event.ProxyID = 123
53- event.Opcode = 456
54-
55- // Return to pool
56- eventPool.Put(event)
57-
58- // Get another event - should be reused
59- event2 := eventPool.Get().(*Event)
60- if event2 == nil {
61- t.Fatal("Expected reused event from pool, got nil")
62- }
63-
64- // The pool might return a clean event or the same one, both are valid
65- t.Logf("Event2: ProxyID=%d, Opcode=%d", event2.ProxyID, event2.Opcode)
66-
67- // Clean up
68- eventPool.Put(event2)
69-}
70-
71-func TestEventDispatcher(t *testing.T) {
72- dispatcher := NewEventDispatcher()
73-
74- called := false
75- handler := func(event *Event) {
76- called = true
77- if event.ProxyID != 123 || event.Opcode != 1 {
78- t.Errorf("Expected ProxyID=123, Opcode=1, got ProxyID=%d, Opcode=%d", event.ProxyID, event.Opcode)
79- }
80- }
81-
82- // Register handler
83- dispatcher.RegisterHandler(123, 1, handler)
84-
85- // Dispatch event
86- dispatcher.Dispatch(123, 1, []byte{})
87-
88- if !called {
89- t.Error("Handler should have been called")
90- }
91-}
92-
93-func TestEventDispatcherMultipleHandlers(t *testing.T) {
94- dispatcher := NewEventDispatcher()
95-
96- called1 := false
97- called2 := false
98-
99- handler1 := func(event *Event) {
100- called1 = true
101- }
102-
103- handler2 := func(event *Event) {
104- called2 = true
105- }
106-
107- // Register handlers for different opcodes
108- dispatcher.RegisterHandler(123, 1, handler1)
109- dispatcher.RegisterHandler(123, 2, handler2)
110-
111- // Dispatch different events
112- dispatcher.Dispatch(123, 1, []byte{})
113- dispatcher.Dispatch(123, 2, []byte{})
114-
115- if !called1 {
116- t.Error("Handler1 should have been called")
117- }
118- if !called2 {
119- t.Error("Handler2 should have been called")
120- }
121-}
122-
12343 func TestMessageMarshalingBasic(t *testing.T) {
12444 // Create a display to test marshaling (without connecting)
12545 d := &Display{
@@ -339,24 +259,6 @@ func TestRegistryGlobalStorage(t *testing.T) {
339259 }
340260 }
341261
342-func BenchmarkEventDispatch(b *testing.B) {
343- dispatcher := NewEventDispatcher()
344-
345- handler := func(event *Event) {
346- // Minimal handler for benchmarking
347- }
348-
349- // Register handler
350- dispatcher.RegisterHandler(123, 1, handler)
351-
352- data := []byte{0x01, 0x02, 0x03, 0x04}
353-
354- b.ResetTimer()
355- for i := 0; i < b.N; i++ {
356- dispatcher.Dispatch(123, 1, data)
357- }
358-}
359-
360262 func BenchmarkFixedConversion(b *testing.B) {
361263 values := []float64{1.0, 0.5, 123.456, -1.5, 256.789}
362264
@@ -40,86 +40,6 @@ func TestFixed(t *testing.T) {
40 }40 }
41 }41 }
42 42
43-func TestEventPool(t *testing.T) {
44- // Test that the global event pool works without requiring a compositor
45- // Get an event
46- event := eventPool.Get().(*Event)
47- if event == nil {
48- t.Fatal("Expected event from pool, got nil")
49- }
50-
51- // Set some data
52- event.ProxyID = 123
53- event.Opcode = 456
54-
55- // Return to pool
56- eventPool.Put(event)
57-
58- // Get another event - should be reused
59- event2 := eventPool.Get().(*Event)
60- if event2 == nil {
61- t.Fatal("Expected reused event from pool, got nil")
62- }
63-
64- // The pool might return a clean event or the same one, both are valid
65- t.Logf("Event2: ProxyID=%d, Opcode=%d", event2.ProxyID, event2.Opcode)
66-
67- // Clean up
68- eventPool.Put(event2)
69-}
70-
71-func TestEventDispatcher(t *testing.T) {
72- dispatcher := NewEventDispatcher()
73-
74- called := false
75- handler := func(event *Event) {
76- called = true
77- if event.ProxyID != 123 || event.Opcode != 1 {
78- t.Errorf("Expected ProxyID=123, Opcode=1, got ProxyID=%d, Opcode=%d", event.ProxyID, event.Opcode)
79- }
80- }
81-
82- // Register handler
83- dispatcher.RegisterHandler(123, 1, handler)
84-
85- // Dispatch event
86- dispatcher.Dispatch(123, 1, []byte{})
87-
88- if !called {
89- t.Error("Handler should have been called")
90- }
91-}
92-
93-func TestEventDispatcherMultipleHandlers(t *testing.T) {
94- dispatcher := NewEventDispatcher()
95-
96- called1 := false
97- called2 := false
98-
99- handler1 := func(event *Event) {
100- called1 = true
101- }
102-
103- handler2 := func(event *Event) {
104- called2 = true
105- }
106-
107- // Register handlers for different opcodes
108- dispatcher.RegisterHandler(123, 1, handler1)
109- dispatcher.RegisterHandler(123, 2, handler2)
110-
111- // Dispatch different events
112- dispatcher.Dispatch(123, 1, []byte{})
113- dispatcher.Dispatch(123, 2, []byte{})
114-
115- if !called1 {
116- t.Error("Handler1 should have been called")
117- }
118- if !called2 {
119- t.Error("Handler2 should have been called")
120- }
121-}
122-
123 func TestMessageMarshalingBasic(t *testing.T) {43 func TestMessageMarshalingBasic(t *testing.T) {
124 // Create a display to test marshaling (without connecting)44 // Create a display to test marshaling (without connecting)
125 d := &Display{45 d := &Display{
@@ -339,24 +259,6 @@ func TestRegistryGlobalStorage(t *testing.T) {
339 }259 }
340 }260 }
341 261
342-func BenchmarkEventDispatch(b *testing.B) {
343- dispatcher := NewEventDispatcher()
344-
345- handler := func(event *Event) {
346- // Minimal handler for benchmarking
347- }
348-
349- // Register handler
350- dispatcher.RegisterHandler(123, 1, handler)
351-
352- data := []byte{0x01, 0x02, 0x03, 0x04}
353-
354- b.ResetTimer()
355- for i := 0; i < b.N; i++ {
356- dispatcher.Dispatch(123, 1, data)
357- }
358-}
359-
360 func BenchmarkFixedConversion(b *testing.B) {262 func BenchmarkFixedConversion(b *testing.B) {
361 values := []float64{1.0, 0.5, 123.456, -1.5, 256.789}263 values := []float64{1.0, 0.5, 123.456, -1.5, 256.789}
362 264
M core.go +98 -4
@@ -3,6 +3,7 @@ package wlturbo
33 import (
44 "encoding/binary"
55 "errors"
6+ "fmt"
67 "sync"
78 "sync/atomic"
89
@@ -28,8 +29,13 @@ type Proxy interface {
2829 type BaseProxy struct {
2930 id uint32
3031 context *Context
32+ version uint32
3133 }
3234
35+// eventPool recycles Events across dispatches; an Event is only valid for
36+// the duration of the handler call.
37+var eventPool = sync.Pool{New: func() any { return &Event{} }}
38+
3339 // Event represents a Wayland protocol event
3440 type Event struct {
3541 ProxyID uint32
@@ -41,7 +47,8 @@ type Event struct {
4147 fdIndex int
4248 }
4349
44-// Data returns the raw event data
50+// Data returns the raw event body. It aliases the connection's receive buffer
51+// and is only valid until the handler returns; copy it to keep it.
4552 func (e *Event) Data() []byte {
4653 return e.data
4754 }
@@ -89,6 +96,58 @@ func (c *Context) CheckProxy(proxy Proxy) error {
8996 return nil
9097 }
9198
99+// Request describes one protocol request for Context.Request.
100+type Request struct {
101+ Proxy Proxy
102+ Opcode uint32
103+ Name string // interface.request, used in errors
104+ Since uint32 // version that introduced the request; 0 or 1 means always
105+ Destructor bool // claim the proxy exactly once, as SendDestructor does
106+ Child Proxy // new_id object created by this request, or nil
107+ FDs []int // descriptors to attach; closed after a successful send
108+}
109+
110+// Request runs one request with its whole lifecycle: it checks the proxy and
111+// version, allocates and registers Child (inheriting the parent's version),
112+// sends, and then either closes the sent descriptors or, on error,
113+// unregisters Child and leaves the descriptors with the caller. Child must
114+// already have this context; it is passed in args at its wire position.
115+func (c *Context) Request(r Request, args ...interface{}) error {
116+ if err := c.CheckProxy(r.Proxy); err != nil {
117+ return err
118+ }
119+ if v, ok := r.Proxy.(interface{ Version() uint32 }); ok {
120+ if err := CheckVersion(v.Version(), r.Since, r.Name); err != nil {
121+ return err
122+ }
123+ }
124+ if r.Child != nil {
125+ r.Child.SetID(c.AllocateID())
126+ if v, ok := r.Proxy.(interface{ Version() uint32 }); ok {
127+ if s, ok := r.Child.(interface{ SetVersion(uint32) }); ok {
128+ s.SetVersion(v.Version())
129+ }
130+ }
131+ c.Register(r.Child)
132+ }
133+ var err error
134+ if r.Destructor {
135+ err = c.SendDestructorWithFDs(r.Proxy, r.Opcode, r.FDs, args...)
136+ } else {
137+ err = c.SendRequestWithFDs(r.Proxy, r.Opcode, r.FDs, args...)
138+ }
139+ if err != nil {
140+ if r.Child != nil {
141+ c.Unregister(r.Child)
142+ }
143+ return err
144+ }
145+ for _, fd := range r.FDs {
146+ _ = CloseSentFD(fd)
147+ }
148+ return nil
149+}
150+
92151 // SendDestructor sends a destructor request exactly once. The proxy is
93152 // claimed (unregistered) under the connection send lock, after marshaling
94153 // and immediately before the write: concurrent destructors and later requests
@@ -115,10 +174,19 @@ func (c *Context) claimDestroy(proxy Proxy) error {
115174 if !c.proxies.CompareAndDelete(proxy.ID(), proxy) {
116175 return errors.New("proxy is not registered")
117176 }
118- c.display.objects.CompareAndDelete(proxy.ID(), proxy)
177+ // The compositor may already have sent events for this object. Keep a
178+ // zombie until delete_id so those events are dropped, not fatal.
179+ c.display.objects.CompareAndSwap(proxy.ID(), proxy, &zombie{object: proxy})
119180 return nil
120181 }
121182
183+// zombie stands in for an object the client destroyed until the compositor
184+// acknowledges the destruction with wl_display.delete_id. Events that were in
185+// flight for it are discarded; their descriptors are closed.
186+type zombie struct{ object Object }
187+
188+func (z *zombie) ID() uint32 { return z.object.ID() }
189+
122190 // Register registers a proxy object
123191 func (c *Context) Register(proxy Proxy) {
124192 if proxy != nil && proxy.ID() != 0 && !c.closed.Load() {
@@ -131,10 +199,12 @@ func (c *Context) Register(proxy Proxy) {
131199 }
132200
133201 // Unregister removes a proxy object
202+// Only this proxy is removed: a zombie or a newer object that took the ID
203+// is left in place.
134204 func (c *Context) Unregister(proxy Proxy) {
135205 if proxy != nil {
136- c.proxies.Delete(proxy.ID())
137- c.display.objects.Delete(proxy.ID())
206+ c.proxies.CompareAndDelete(proxy.ID(), proxy)
207+ c.display.objects.CompareAndDelete(proxy.ID(), proxy)
138208 }
139209 }
140210
@@ -203,6 +273,30 @@ func (p *BaseProxy) SetContext(ctx *Context) {
203273 p.context = ctx
204274 }
205275
276+// Version returns the protocol version the object was bound or created at,
277+// or 0 when it is unknown (for example after Registry.BindID).
278+func (p *BaseProxy) Version() uint32 {
279+ return p.version
280+}
281+
282+// SetVersion records the object's protocol version. Registry.Bind sets it for
283+// globals and generated requests copy it from parent to child.
284+func (p *BaseProxy) SetVersion(v uint32) {
285+ p.version = v
286+}
287+
288+// ErrVersionTooLow reports a request the bound object version does not have.
289+var ErrVersionTooLow = errors.New("wlturbo: request needs a newer object version")
290+
291+// CheckVersion rejects a request introduced in version since when the
292+// object's known version is lower. An unknown version (0) is not checked.
293+func CheckVersion(version, since uint32, request string) error {
294+ if version != 0 && version < since {
295+ return fmt.Errorf("%w: %s needs version %d, object has %d", ErrVersionTooLow, request, since, version)
296+ }
297+ return nil
298+}
299+
206300 // Dispatch default implementation (does nothing)
207301 func (p *BaseProxy) Dispatch(event *Event) {
208302 // Default implementation does nothing
@@ -3,6 +3,7 @@ package wlturbo
3 import (3 import (
4 "encoding/binary"4 "encoding/binary"
5 "errors"5 "errors"
6+ "fmt"
6 "sync"7 "sync"
7 "sync/atomic"8 "sync/atomic"
8 9
@@ -28,8 +29,13 @@ type Proxy interface {
28 type BaseProxy struct {29 type BaseProxy struct {
29 id uint3230 id uint32
30 context *Context31 context *Context
32+ version uint32
31 }33 }
32 34
35+// eventPool recycles Events across dispatches; an Event is only valid for
36+// the duration of the handler call.
37+var eventPool = sync.Pool{New: func() any { return &Event{} }}
38+
33 // Event represents a Wayland protocol event39 // Event represents a Wayland protocol event
34 type Event struct {40 type Event struct {
35 ProxyID uint3241 ProxyID uint32
@@ -41,7 +47,8 @@ type Event struct {
41 fdIndex int47 fdIndex int
42 }48 }
43 49
44-// Data returns the raw event data50+// Data returns the raw event body. It aliases the connection's receive buffer
51+// and is only valid until the handler returns; copy it to keep it.
45 func (e *Event) Data() []byte {52 func (e *Event) Data() []byte {
46 return e.data53 return e.data
47 }54 }
@@ -89,6 +96,58 @@ func (c *Context) CheckProxy(proxy Proxy) error {
89 return nil96 return nil
90 }97 }
91 98
99+// Request describes one protocol request for Context.Request.
100+type Request struct {
101+ Proxy Proxy
102+ Opcode uint32
103+ Name string // interface.request, used in errors
104+ Since uint32 // version that introduced the request; 0 or 1 means always
105+ Destructor bool // claim the proxy exactly once, as SendDestructor does
106+ Child Proxy // new_id object created by this request, or nil
107+ FDs []int // descriptors to attach; closed after a successful send
108+}
109+
110+// Request runs one request with its whole lifecycle: it checks the proxy and
111+// version, allocates and registers Child (inheriting the parent's version),
112+// sends, and then either closes the sent descriptors or, on error,
113+// unregisters Child and leaves the descriptors with the caller. Child must
114+// already have this context; it is passed in args at its wire position.
115+func (c *Context) Request(r Request, args ...interface{}) error {
116+ if err := c.CheckProxy(r.Proxy); err != nil {
117+ return err
118+ }
119+ if v, ok := r.Proxy.(interface{ Version() uint32 }); ok {
120+ if err := CheckVersion(v.Version(), r.Since, r.Name); err != nil {
121+ return err
122+ }
123+ }
124+ if r.Child != nil {
125+ r.Child.SetID(c.AllocateID())
126+ if v, ok := r.Proxy.(interface{ Version() uint32 }); ok {
127+ if s, ok := r.Child.(interface{ SetVersion(uint32) }); ok {
128+ s.SetVersion(v.Version())
129+ }
130+ }
131+ c.Register(r.Child)
132+ }
133+ var err error
134+ if r.Destructor {
135+ err = c.SendDestructorWithFDs(r.Proxy, r.Opcode, r.FDs, args...)
136+ } else {
137+ err = c.SendRequestWithFDs(r.Proxy, r.Opcode, r.FDs, args...)
138+ }
139+ if err != nil {
140+ if r.Child != nil {
141+ c.Unregister(r.Child)
142+ }
143+ return err
144+ }
145+ for _, fd := range r.FDs {
146+ _ = CloseSentFD(fd)
147+ }
148+ return nil
149+}
150+
92 // SendDestructor sends a destructor request exactly once. The proxy is151 // SendDestructor sends a destructor request exactly once. The proxy is
93 // claimed (unregistered) under the connection send lock, after marshaling152 // claimed (unregistered) under the connection send lock, after marshaling
94 // and immediately before the write: concurrent destructors and later requests153 // and immediately before the write: concurrent destructors and later requests
@@ -115,10 +174,19 @@ func (c *Context) claimDestroy(proxy Proxy) error {
115 if !c.proxies.CompareAndDelete(proxy.ID(), proxy) {174 if !c.proxies.CompareAndDelete(proxy.ID(), proxy) {
116 return errors.New("proxy is not registered")175 return errors.New("proxy is not registered")
117 }176 }
118- c.display.objects.CompareAndDelete(proxy.ID(), proxy)177+ // The compositor may already have sent events for this object. Keep a
178+ // zombie until delete_id so those events are dropped, not fatal.
179+ c.display.objects.CompareAndSwap(proxy.ID(), proxy, &zombie{object: proxy})
119 return nil180 return nil
120 }181 }
121 182
183+// zombie stands in for an object the client destroyed until the compositor
184+// acknowledges the destruction with wl_display.delete_id. Events that were in
185+// flight for it are discarded; their descriptors are closed.
186+type zombie struct{ object Object }
187+
188+func (z *zombie) ID() uint32 { return z.object.ID() }
189+
122 // Register registers a proxy object190 // Register registers a proxy object
123 func (c *Context) Register(proxy Proxy) {191 func (c *Context) Register(proxy Proxy) {
124 if proxy != nil && proxy.ID() != 0 && !c.closed.Load() {192 if proxy != nil && proxy.ID() != 0 && !c.closed.Load() {
@@ -131,10 +199,12 @@ func (c *Context) Register(proxy Proxy) {
131 }199 }
132 200
133 // Unregister removes a proxy object201 // Unregister removes a proxy object
202+// Only this proxy is removed: a zombie or a newer object that took the ID
203+// is left in place.
134 func (c *Context) Unregister(proxy Proxy) {204 func (c *Context) Unregister(proxy Proxy) {
135 if proxy != nil {205 if proxy != nil {
136- c.proxies.Delete(proxy.ID())206+ c.proxies.CompareAndDelete(proxy.ID(), proxy)
137- c.display.objects.Delete(proxy.ID())207+ c.display.objects.CompareAndDelete(proxy.ID(), proxy)
138 }208 }
139 }209 }
140 210
@@ -203,6 +273,30 @@ func (p *BaseProxy) SetContext(ctx *Context) {
203 p.context = ctx273 p.context = ctx
204 }274 }
205 275
276+// Version returns the protocol version the object was bound or created at,
277+// or 0 when it is unknown (for example after Registry.BindID).
278+func (p *BaseProxy) Version() uint32 {
279+ return p.version
280+}
281+
282+// SetVersion records the object's protocol version. Registry.Bind sets it for
283+// globals and generated requests copy it from parent to child.
284+func (p *BaseProxy) SetVersion(v uint32) {
285+ p.version = v
286+}
287+
288+// ErrVersionTooLow reports a request the bound object version does not have.
289+var ErrVersionTooLow = errors.New("wlturbo: request needs a newer object version")
290+
291+// CheckVersion rejects a request introduced in version since when the
292+// object's known version is lower. An unknown version (0) is not checked.
293+func CheckVersion(version, since uint32, request string) error {
294+ if version != 0 && version < since {
295+ return fmt.Errorf("%w: %s needs version %d, object has %d", ErrVersionTooLow, request, since, version)
296+ }
297+ return nil
298+}
299+
206 // Dispatch default implementation (does nothing)300 // Dispatch default implementation (does nothing)
207 func (p *BaseProxy) Dispatch(event *Event) {301 func (p *BaseProxy) Dispatch(event *Event) {
208 // Default implementation does nothing302 // Default implementation does nothing
D docs/operational-baseline.md +0 -121
@@ -1,121 +0,0 @@
1-# WLTurbo failure baseline (Task 1 Step 1)
2-
3-Evidence ledger for `github.com/bnema/wlturbo` at the start of `phase1/operational-health`. It records what the current checkout *does*; it is not a claim that the package is operational. Nothing was fixed.
4-
5-## 1. Run metadata
6-
7-- Repo: `/home/brice/dev/projects/wlturbo` — `git rev-parse HEAD` = `111649b1f3def6ff216191aa04d00eecbe14b435`, branch `phase1/operational-health`.
8-- Date of run: 2026-09-13T08:10:00+02:00. `go version` = `go version go1.27.1-X:nodwarf5 linux/amd64`. Platform `Linux x86_64`.
9-- Module `github.com/bnema/wlturbo`, `go 1.24`; only dependency `golang.org/x/sys v0.28.0`. `git status --porcelain` was empty at capture.
10-- File hashes at capture: `client.go` 25622cd3…, `core.go` 9507202e…, `scm_linux.go` 0a2344a5…, `client_test.go` a60e484a….
11-- A concurrent rewrite of framing/FD handling was expected; the tree was clean at the commit above when these commands ran, so line numbers are pinned there and may shift.
12-
13-## 2. Command evidence (verbatim, trimmed)
14-
15-### 2.1 `go test ./...` → exit 1
16-
17-```
18-# github.com/bnema/wlturbo [github.com/bnema/wlturbo.test]
19-./client_test.go:50:8: event.ProxyId undefined (type *Event has no field or method ProxyId, but does have field ProxyID)
20-./client_test.go:63:49: event2.ProxyId undefined (type *Event has no field or method ProxyId, but does have field ProxyID)
21-./client_test.go:75:12: event.ProxyId undefined (type *Event has no field or method ProxyId, but does have field ProxyID)
22-./client_test.go:76:80: event.ProxyId undefined (type *Event has no field or method ProxyId, but does have field ProxyID)
23-FAIL github.com/bnema/wlturbo [build failed]
24-? github.com/bnema/wlturbo/wl [no test files]
25-FAIL
26-```
27-
28-### 2.2 `go test -race ./...` → exit 1
29-
30-Output is byte-identical to 2.1; the compiler lines are:
31-
32-```
33-./client_test.go:50:8: event.ProxyId undefined (type *Event has no field or method ProxyId, but does have field ProxyID)
34-./client_test.go:63:49: event2.ProxyId undefined (type *Event has no field or method ProxyId, but does have field ProxyID)
35-./client_test.go:75:12: event.ProxyId undefined (type *Event has no field or method ProxyId, but does have field ProxyID)
36-./client_test.go:76:80: event.ProxyId undefined (type *Event has no field or method ProxyId, but does have field ProxyID)
37-FAIL github.com/bnema/wlturbo [build failed]
38-```
39-
40-### 2.3 `go vet ./...` → exit 1
41-
42-```
43-# github.com/bnema/wlturbo
44-# [github.com/bnema/wlturbo]
45-vet: ./client_test.go:50:8: event.ProxyId undefined (type *Event has no field or method ProxyId, but does have field ProxyID)
46-```
47-
48-Reproduction confirmed: this is a **build failure**, so no test body runs (with or without `-race`). The real field is `ProxyID` (`core.go:35`), and `client_test.go` still uses the old name `ProxyId` at four sites.
49-
50-## 3. Transport inspection (`client.go`)
51-
52-### 3.1 Message read path — `Display.Dispatch` (`client.go:345`)
53-
54-- `client.go:346-347`: holds `d.recvMu` for the whole read (mutual exclusion between concurrent dispatchers).
55-- `client.go:350`: **single** `recvmsgWithFDs(d.headerBuf[:])` for the 8-byte header (`headerBuf [8]byte`, `client.go:71`).
56-- `client.go:353-355`: `n < 8` → `incomplete header: got %d bytes`; a short read is an error, never retried.
57-- `client.go:358-362`: `objectID` little-endian, `size = sizeOpcode >> 16`, `opcode = sizeOpcode & 0xffff`.
58-- `client.go:367-369`: `if opcode > 0xFFFF` → error. **Unreachable**: `opcode` was just masked with `0xffff`.
59-- `client.go:372-397`: if `size > 8`, a **second** `recvmsgWithFDs(body)` reads `size-8` bytes; if still short, `io.ReadFull(d.conn, remaining)` (`client.go:392`) is the only path that guarantees a full body.
60-- FDs from both reads are appended to a local slice (`client.go:396`); that slice is then **never used** in `Dispatch`.
61-
62-### 3.2 Header validation present / missing
63-
64-Present: the short-read check (`client.go:353`) and the unreachable opcode check (`client.go:367`). Missing, by inspection of `Dispatch`:
65-
66-- no **maximum message size** check; `size` is 16-bit so ≤ 65535, but nothing states or enforces that bound;
67-- no **4-byte alignment** check on `size`;
68-- no **unknown object ID** rejection — `client.go:431` only logs `WARNING: No object found for ID %d` and falls through to `d.dispatcher.Dispatch` (`client.go:439`);
69-- no **unknown opcode** rejection per object.
70-
71-### 3.3 Buffering
72-
73-`headerBuf [8]byte` (`client.go:71`) and `eventBodyBuf [4096]byte` (`client.go:74`) live on the `Display` and are reused for every event (`client.go:378-379`); larger bodies are allocated fresh (`client.go:381`). So the receive buffers are connection-local, but the small-body path returns a sub-slice of `d.eventBodyBuf` with no copy — a handler retaining the body sees it overwritten by the next `Dispatch`. `Event`s are likewise allocated fresh at `client.go:418` although a pool exists (`event_pool.go:12`).
74-
75-### 3.4 Lifecycle
76-
77-- `Display.Close` (`client.go:213-215`) is a bare `return d.conn.Close()` with no closed flag, so it is **not idempotent**. External probe (socketpair + `net.FileConn`, run outside the repo): `first Close: <nil>`, `second Close: "close unix @->@: use of closed network connection"`.
78-- `Dispatch` after close: `recvmsgWithFDs` → `ReadMsgUnix` returns the closed error (`scm_linux.go:97`), wrapped as `failed to read header: %w` (`client.go:351`). Same probe: `ReadMsgUnix after close: "read unix @->@: use of closed network connection"`. It errors rather than panics, but there is no guard or sentinel.
79-- `Connect` (`client.go:145`) calls `conn.(*net.UnixConn).File()` (`client.go:170`), stores the fd (`client.go:175`) and closes the `*os.File` immediately (`client.go:177`); `d.fd` is **never read again** anywhere (verified by grep).
80-
81-### 3.5 Hot-path `log.Printf`
82-
83-Unconditional per event / per allocation, using the default logger to stderr: `client.go:408` (every non-registry event), `:413` (server-created object), `:425` (proxied dispatch), `:431` (unknown object), `:230` (every `allocateID()`), `:795` and `:836` (`OutputHead.Dispatch`, `OutputMode.Dispatch`).
84-
85-## 4. File-descriptor handling (`scm_linux.go`, `core.go`)
86-
87-### 4.1 `globalFDQueue`
88-
89-- Package-global `globalFDQueue = &fdQueue{}` (`scm_linux.go:29`), shared by every `Display` in the process.
90-- `items [256]atomic.Pointer[fdItem]` with monotonic `head`/`tail` counters; slot index is `counter & 255` (`scm_linux.go:52`, `:76`). The wraparound risk is capacity, not the counters: a producer 256 descriptors ahead of the consumer revisits an occupied slot.
91-- `enqueueFD` (`scm_linux.go:47`) spins on `q.items[next].CompareAndSwap(nil, item)`; when the slot is occupied it **spins forever** — no bound, no lossy path.
92-- `dequeueFD` (`scm_linux.go:65`) is single-consumer; when the slot loads `nil` despite `head < tail` it `continue`s (unbounded busy spin). On success it CASes `head`, reads `item.fd`, clears the slot and returns the item to `fdItemPool`.
93-
94-### 4.2 Queueing — `recvmsgWithFDs` (`scm_linux.go:91`)
95-
96-- The pooled control buffer is `unix.CmsgSpace(4*4)` — **space for only 4 FDs** (`scm_linux.go:41`); `ReadMsgUnix`'s flags are discarded (`scm_linux.go:97`), so `MSG_CTRUNC` is never detected and excess FDs are lost.
97-- On `SCM_RIGHTS` (`scm_linux.go:112-123`) every FD is **enqueued into the global queue** (`:119`) *and* also returned in the `fds` slice (`:122`); `Dispatch` discards the returned copy. Neither copy is closed or accounted for.
98-- Parse errors (`scm_linux.go:104`, `:110`) return without closing any FD already parsed from the same control message.
99-- `d` is otherwise unused for FDs: `sendmsgWithFDs` (`scm_linux.go:131`) writes via `d.conn`, and `d.fd` is never consulted.
100-
101-### 4.3 Consumption & lifetime — `Event.Fd` (`core.go:224`)
102-
103-- `Event.Fd()` ignores `e.data` and pops the **global** queue via `GetNextFD()` (`core.go:227`, `scm_linux.go:150`); only on an empty queue does it read a placeholder `uint32` and return `0` (`core.go:232`). The descriptor is therefore not tied to this event, this `Display`, or even this connection — only to global FIFO order.
104-- No path closes received FDs: not `Close` (`client.go:213`), not `Dispatch` error paths, not `recvmsgWithFDs` errors. The only `unix.Close` calls found are for SHM buffers (`shm.go:49`) and inside `CreateAnonymousFile` (`scm_linux.go`).
105-- `d.fd` (from `conn.(*net.UnixConn).File()`, `client.go:170-177`) is **dead**: the `*os.File` is closed immediately, so the stored int is a stale, unowned descriptor number; the read/send paths use `d.conn`.
106-
107-## 5. Test coverage inventory (`client_test.go`)
108-
109-Covered (10 functions: 8 tests + 2 benchmarks; none execute today): `TestFixed` (11), `TestEventPool` (41, uses the old name `ProxyId`), `TestEventDispatcher` (69), `TestEventDispatcherMultipleHandlers` (91), `TestMessageMarshalingBasic` (121), `TestMessageHeaderParsing` (178 — re-implements the header arithmetic locally and does **not** call `Display.Dispatch`), `TestAllocateID` (227), `TestRegistryGlobalStorage` (248), `BenchmarkEventDispatch` (292), `BenchmarkFixedConversion` (310).
110-
111-Untested (no test touches these): `Dispatch` framing (single header read, second body read, `io.ReadFull` fallback, short reads); `recvmsgWithFDs` / `sendmsgWithFDs` / `SCM_RIGHTS` / `globalFDQueue` / `Event.Fd` and FD lifetime; lifecycle (`Connect`, `Close`, double-close, use-after-close); concurrency (`recvMu`, `sendMu`, parallel `Dispatch`, `-race` paths); `handleDisplayEvent`, `handleServerObject`, `Roundtrip`.
112-
113-Live compositor: **no** test needs one — `client_test.go:8` states this, and a grep for `Connect`/`Dial`/`WAYLAND_DISPLAY`/`SCM_RIGHTS` in the file finds nothing. The blocker is purely the compile error.
114-
115-## 6. Classification
116-
117-**Reproduced (executed):** (1) `go test ./...` build failure on `ProxyId`, lines 50/63/75/76 — §2.1, exit 1; (2) `go test -race ./...` identical — §2.2, exit 1; (3) `go vet ./...` same symbol — §2.3, exit 1; (4) `Close` is not idempotent — §3.4, external probe result `close unix @->@: use of closed network connection`.
118-
119-**Verified (read from code, with `file:line`):** `Event.ProxyID` exists (`core.go:35`); header read is one `ReadMsgUnix`, body is a second read plus `io.ReadFull` fallback (`client.go:350`, `:385`, `:392`); the `opcode > 0xFFFF` check is unreachable (`client.go:362` vs `:367`); unknown object IDs are only logged (`client.go:431`, `:439`); no max-size or alignment check exists in `Dispatch`; receive buffers are per-`Display` and reused (`client.go:71`, `:74`, `:379`); `d.fd` is set and never used (`client.go:170-177`); `globalFDQueue` is package-global (`scm_linux.go:29`); `enqueueFD`/`dequeueFD` can spin unbounded (`scm_linux.go:47-88`); control buffer holds 4 FDs and truncation flags are ignored (`scm_linux.go:41`, `:97`); hot-path logs (`client.go:230`, `:408`, `:413`, `:425`, `:431`, `:795`, `:836`); fresh `&Event{}` bypasses the pool (`client.go:418` vs `event_pool.go:12`); no test covers framing/SCM/lifecycle/concurrency and none needs a compositor (§5).
120-
121-**Suspected (derived from code, not executed because the package does not build):** the retained body sub-slice is clobbered by the next `Dispatch` (`client.go:379`); received FDs leak on parse error or shutdown (no `close` on the queue path — `scm_linux.go:104-122`, `core.go:227`); `Event.Fd` can return a descriptor belonging to another event or connection because the queue is global (`core.go:227`); FD loss on `MSG_CTRUNC` (`scm_linux.go:41`, `:97`); `Dispatch` after close returns a wrapped error with no sentinel (`client.go:351`).
@@ -1,121 +0,0 @@
1-# WLTurbo failure baseline (Task 1 Step 1)
2-
3-Evidence ledger for `github.com/bnema/wlturbo` at the start of `phase1/operational-health`. It records what the current checkout *does*; it is not a claim that the package is operational. Nothing was fixed.
4-
5-## 1. Run metadata
6-
7-- Repo: `/home/brice/dev/projects/wlturbo` — `git rev-parse HEAD` = `111649b1f3def6ff216191aa04d00eecbe14b435`, branch `phase1/operational-health`.
8-- Date of run: 2026-09-13T08:10:00+02:00. `go version` = `go version go1.27.1-X:nodwarf5 linux/amd64`. Platform `Linux x86_64`.
9-- Module `github.com/bnema/wlturbo`, `go 1.24`; only dependency `golang.org/x/sys v0.28.0`. `git status --porcelain` was empty at capture.
10-- File hashes at capture: `client.go` 25622cd3…, `core.go` 9507202e…, `scm_linux.go` 0a2344a5…, `client_test.go` a60e484a….
11-- A concurrent rewrite of framing/FD handling was expected; the tree was clean at the commit above when these commands ran, so line numbers are pinned there and may shift.
12-
13-## 2. Command evidence (verbatim, trimmed)
14-
15-### 2.1 `go test ./...` → exit 1
16-
17-```
18-# github.com/bnema/wlturbo [github.com/bnema/wlturbo.test]
19-./client_test.go:50:8: event.ProxyId undefined (type *Event has no field or method ProxyId, but does have field ProxyID)
20-./client_test.go:63:49: event2.ProxyId undefined (type *Event has no field or method ProxyId, but does have field ProxyID)
21-./client_test.go:75:12: event.ProxyId undefined (type *Event has no field or method ProxyId, but does have field ProxyID)
22-./client_test.go:76:80: event.ProxyId undefined (type *Event has no field or method ProxyId, but does have field ProxyID)
23-FAIL github.com/bnema/wlturbo [build failed]
24-? github.com/bnema/wlturbo/wl [no test files]
25-FAIL
26-```
27-
28-### 2.2 `go test -race ./...` → exit 1
29-
30-Output is byte-identical to 2.1; the compiler lines are:
31-
32-```
33-./client_test.go:50:8: event.ProxyId undefined (type *Event has no field or method ProxyId, but does have field ProxyID)
34-./client_test.go:63:49: event2.ProxyId undefined (type *Event has no field or method ProxyId, but does have field ProxyID)
35-./client_test.go:75:12: event.ProxyId undefined (type *Event has no field or method ProxyId, but does have field ProxyID)
36-./client_test.go:76:80: event.ProxyId undefined (type *Event has no field or method ProxyId, but does have field ProxyID)
37-FAIL github.com/bnema/wlturbo [build failed]
38-```
39-
40-### 2.3 `go vet ./...` → exit 1
41-
42-```
43-# github.com/bnema/wlturbo
44-# [github.com/bnema/wlturbo]
45-vet: ./client_test.go:50:8: event.ProxyId undefined (type *Event has no field or method ProxyId, but does have field ProxyID)
46-```
47-
48-Reproduction confirmed: this is a **build failure**, so no test body runs (with or without `-race`). The real field is `ProxyID` (`core.go:35`), and `client_test.go` still uses the old name `ProxyId` at four sites.
49-
50-## 3. Transport inspection (`client.go`)
51-
52-### 3.1 Message read path — `Display.Dispatch` (`client.go:345`)
53-
54-- `client.go:346-347`: holds `d.recvMu` for the whole read (mutual exclusion between concurrent dispatchers).
55-- `client.go:350`: **single** `recvmsgWithFDs(d.headerBuf[:])` for the 8-byte header (`headerBuf [8]byte`, `client.go:71`).
56-- `client.go:353-355`: `n < 8` → `incomplete header: got %d bytes`; a short read is an error, never retried.
57-- `client.go:358-362`: `objectID` little-endian, `size = sizeOpcode >> 16`, `opcode = sizeOpcode & 0xffff`.
58-- `client.go:367-369`: `if opcode > 0xFFFF` → error. **Unreachable**: `opcode` was just masked with `0xffff`.
59-- `client.go:372-397`: if `size > 8`, a **second** `recvmsgWithFDs(body)` reads `size-8` bytes; if still short, `io.ReadFull(d.conn, remaining)` (`client.go:392`) is the only path that guarantees a full body.
60-- FDs from both reads are appended to a local slice (`client.go:396`); that slice is then **never used** in `Dispatch`.
61-
62-### 3.2 Header validation present / missing
63-
64-Present: the short-read check (`client.go:353`) and the unreachable opcode check (`client.go:367`). Missing, by inspection of `Dispatch`:
65-
66-- no **maximum message size** check; `size` is 16-bit so ≤ 65535, but nothing states or enforces that bound;
67-- no **4-byte alignment** check on `size`;
68-- no **unknown object ID** rejection — `client.go:431` only logs `WARNING: No object found for ID %d` and falls through to `d.dispatcher.Dispatch` (`client.go:439`);
69-- no **unknown opcode** rejection per object.
70-
71-### 3.3 Buffering
72-
73-`headerBuf [8]byte` (`client.go:71`) and `eventBodyBuf [4096]byte` (`client.go:74`) live on the `Display` and are reused for every event (`client.go:378-379`); larger bodies are allocated fresh (`client.go:381`). So the receive buffers are connection-local, but the small-body path returns a sub-slice of `d.eventBodyBuf` with no copy — a handler retaining the body sees it overwritten by the next `Dispatch`. `Event`s are likewise allocated fresh at `client.go:418` although a pool exists (`event_pool.go:12`).
74-
75-### 3.4 Lifecycle
76-
77-- `Display.Close` (`client.go:213-215`) is a bare `return d.conn.Close()` with no closed flag, so it is **not idempotent**. External probe (socketpair + `net.FileConn`, run outside the repo): `first Close: <nil>`, `second Close: "close unix @->@: use of closed network connection"`.
78-- `Dispatch` after close: `recvmsgWithFDs` → `ReadMsgUnix` returns the closed error (`scm_linux.go:97`), wrapped as `failed to read header: %w` (`client.go:351`). Same probe: `ReadMsgUnix after close: "read unix @->@: use of closed network connection"`. It errors rather than panics, but there is no guard or sentinel.
79-- `Connect` (`client.go:145`) calls `conn.(*net.UnixConn).File()` (`client.go:170`), stores the fd (`client.go:175`) and closes the `*os.File` immediately (`client.go:177`); `d.fd` is **never read again** anywhere (verified by grep).
80-
81-### 3.5 Hot-path `log.Printf`
82-
83-Unconditional per event / per allocation, using the default logger to stderr: `client.go:408` (every non-registry event), `:413` (server-created object), `:425` (proxied dispatch), `:431` (unknown object), `:230` (every `allocateID()`), `:795` and `:836` (`OutputHead.Dispatch`, `OutputMode.Dispatch`).
84-
85-## 4. File-descriptor handling (`scm_linux.go`, `core.go`)
86-
87-### 4.1 `globalFDQueue`
88-
89-- Package-global `globalFDQueue = &fdQueue{}` (`scm_linux.go:29`), shared by every `Display` in the process.
90-- `items [256]atomic.Pointer[fdItem]` with monotonic `head`/`tail` counters; slot index is `counter & 255` (`scm_linux.go:52`, `:76`). The wraparound risk is capacity, not the counters: a producer 256 descriptors ahead of the consumer revisits an occupied slot.
91-- `enqueueFD` (`scm_linux.go:47`) spins on `q.items[next].CompareAndSwap(nil, item)`; when the slot is occupied it **spins forever** — no bound, no lossy path.
92-- `dequeueFD` (`scm_linux.go:65`) is single-consumer; when the slot loads `nil` despite `head < tail` it `continue`s (unbounded busy spin). On success it CASes `head`, reads `item.fd`, clears the slot and returns the item to `fdItemPool`.
93-
94-### 4.2 Queueing — `recvmsgWithFDs` (`scm_linux.go:91`)
95-
96-- The pooled control buffer is `unix.CmsgSpace(4*4)` — **space for only 4 FDs** (`scm_linux.go:41`); `ReadMsgUnix`'s flags are discarded (`scm_linux.go:97`), so `MSG_CTRUNC` is never detected and excess FDs are lost.
97-- On `SCM_RIGHTS` (`scm_linux.go:112-123`) every FD is **enqueued into the global queue** (`:119`) *and* also returned in the `fds` slice (`:122`); `Dispatch` discards the returned copy. Neither copy is closed or accounted for.
98-- Parse errors (`scm_linux.go:104`, `:110`) return without closing any FD already parsed from the same control message.
99-- `d` is otherwise unused for FDs: `sendmsgWithFDs` (`scm_linux.go:131`) writes via `d.conn`, and `d.fd` is never consulted.
100-
101-### 4.3 Consumption & lifetime — `Event.Fd` (`core.go:224`)
102-
103-- `Event.Fd()` ignores `e.data` and pops the **global** queue via `GetNextFD()` (`core.go:227`, `scm_linux.go:150`); only on an empty queue does it read a placeholder `uint32` and return `0` (`core.go:232`). The descriptor is therefore not tied to this event, this `Display`, or even this connection — only to global FIFO order.
104-- No path closes received FDs: not `Close` (`client.go:213`), not `Dispatch` error paths, not `recvmsgWithFDs` errors. The only `unix.Close` calls found are for SHM buffers (`shm.go:49`) and inside `CreateAnonymousFile` (`scm_linux.go`).
105-- `d.fd` (from `conn.(*net.UnixConn).File()`, `client.go:170-177`) is **dead**: the `*os.File` is closed immediately, so the stored int is a stale, unowned descriptor number; the read/send paths use `d.conn`.
106-
107-## 5. Test coverage inventory (`client_test.go`)
108-
109-Covered (10 functions: 8 tests + 2 benchmarks; none execute today): `TestFixed` (11), `TestEventPool` (41, uses the old name `ProxyId`), `TestEventDispatcher` (69), `TestEventDispatcherMultipleHandlers` (91), `TestMessageMarshalingBasic` (121), `TestMessageHeaderParsing` (178 — re-implements the header arithmetic locally and does **not** call `Display.Dispatch`), `TestAllocateID` (227), `TestRegistryGlobalStorage` (248), `BenchmarkEventDispatch` (292), `BenchmarkFixedConversion` (310).
110-
111-Untested (no test touches these): `Dispatch` framing (single header read, second body read, `io.ReadFull` fallback, short reads); `recvmsgWithFDs` / `sendmsgWithFDs` / `SCM_RIGHTS` / `globalFDQueue` / `Event.Fd` and FD lifetime; lifecycle (`Connect`, `Close`, double-close, use-after-close); concurrency (`recvMu`, `sendMu`, parallel `Dispatch`, `-race` paths); `handleDisplayEvent`, `handleServerObject`, `Roundtrip`.
112-
113-Live compositor: **no** test needs one — `client_test.go:8` states this, and a grep for `Connect`/`Dial`/`WAYLAND_DISPLAY`/`SCM_RIGHTS` in the file finds nothing. The blocker is purely the compile error.
114-
115-## 6. Classification
116-
117-**Reproduced (executed):** (1) `go test ./...` build failure on `ProxyId`, lines 50/63/75/76 — §2.1, exit 1; (2) `go test -race ./...` identical — §2.2, exit 1; (3) `go vet ./...` same symbol — §2.3, exit 1; (4) `Close` is not idempotent — §3.4, external probe result `close unix @->@: use of closed network connection`.
118-
119-**Verified (read from code, with `file:line`):** `Event.ProxyID` exists (`core.go:35`); header read is one `ReadMsgUnix`, body is a second read plus `io.ReadFull` fallback (`client.go:350`, `:385`, `:392`); the `opcode > 0xFFFF` check is unreachable (`client.go:362` vs `:367`); unknown object IDs are only logged (`client.go:431`, `:439`); no max-size or alignment check exists in `Dispatch`; receive buffers are per-`Display` and reused (`client.go:71`, `:74`, `:379`); `d.fd` is set and never used (`client.go:170-177`); `globalFDQueue` is package-global (`scm_linux.go:29`); `enqueueFD`/`dequeueFD` can spin unbounded (`scm_linux.go:47-88`); control buffer holds 4 FDs and truncation flags are ignored (`scm_linux.go:41`, `:97`); hot-path logs (`client.go:230`, `:408`, `:413`, `:425`, `:431`, `:795`, `:836`); fresh `&Event{}` bypasses the pool (`client.go:418` vs `event_pool.go:12`); no test covers framing/SCM/lifecycle/concurrency and none needs a compositor (§5).
120-
121-**Suspected (derived from code, not executed because the package does not build):** the retained body sub-slice is clobbered by the next `Dispatch` (`client.go:379`); received FDs leak on parse error or shutdown (no `close` on the queue path — `scm_linux.go:104-122`, `core.go:227`); `Event.Fd` can return a descriptor belonging to another event or connection because the queue is global (`core.go:227`); FD loss on `MSG_CTRUNC` (`scm_linux.go:41`, `:97`); `Dispatch` after close returns a wrapped error with no sentinel (`client.go:351`).
D event_pool.go +0 -185
@@ -1,185 +0,0 @@
1-//go:build linux
2-// +build linux
3-
4-package wlturbo
5-
6-import (
7- "sync"
8- "sync/atomic"
9-)
10-
11-// Event pool for zero-allocation event handling
12-var eventPool = sync.Pool{
13- New: func() interface{} {
14- return &Event{
15- data: make([]byte, 0, 4096), // Pre-allocate 4KB
16- }
17- },
18-}
19-
20-// EventHandler is a function type for handling events with zero allocations
21-type EventHandler func(event *Event)
22-
23-// EventDispatcher handles high-performance event dispatching
24-type EventDispatcher struct {
25- // Lock-free handler lookup using atomic operations
26- handlers [1024]atomic.Pointer[handlerEntry] // Fixed-size array for object IDs 0-1023
27-
28- // Extended handlers for object IDs >= 1024 (rare case)
29- extHandlers sync.Map
30-}
31-
32-// handlerEntry stores handlers for a specific object
33-type handlerEntry struct {
34- // Array of handlers indexed by opcode (most objects have < 16 opcodes)
35- handlers [32]EventHandler
36-
37- // Extended handlers for opcodes >= 32 (very rare)
38- extHandlers *sync.Map
39-}
40-
41-// NewEventDispatcher creates a high-performance event dispatcher
42-func NewEventDispatcher() *EventDispatcher {
43- return &EventDispatcher{}
44-}
45-
46-// RegisterHandler registers an event handler with zero allocation in common case
47-func (d *EventDispatcher) RegisterHandler(objectID uint32, opcode uint16, handler EventHandler) {
48- if objectID < 1024 {
49- // Fast path: use lock-free array
50- for {
51- entry := d.handlers[objectID].Load()
52- if entry == nil {
53- // Create new entry
54- newEntry := &handlerEntry{}
55- if opcode < 32 {
56- newEntry.handlers[opcode] = handler
57- } else {
58- newEntry.extHandlers = &sync.Map{}
59- newEntry.extHandlers.Store(opcode, handler)
60- }
61-
62- // Try to set atomically
63- if d.handlers[objectID].CompareAndSwap(nil, newEntry) {
64- return
65- }
66- // Retry if someone else created it
67- continue
68- }
69-
70- // Entry exists, update it
71- if opcode < 32 {
72- // Direct array access (no locking needed for write)
73- entry.handlers[opcode] = handler
74- } else {
75- // Extended handlers
76- if entry.extHandlers == nil {
77- entry.extHandlers = &sync.Map{}
78- }
79- entry.extHandlers.Store(opcode, handler)
80- }
81- return
82- }
83- } else {
84- // Slow path: use sync.Map for large object IDs
85- entry, _ := d.extHandlers.LoadOrStore(objectID, &handlerEntry{})
86- h := entry.(*handlerEntry)
87-
88- if opcode < 32 {
89- h.handlers[opcode] = handler
90- } else {
91- if h.extHandlers == nil {
92- h.extHandlers = &sync.Map{}
93- }
94- h.extHandlers.Store(opcode, handler)
95- }
96- }
97-}
98-
99-// Dispatch dispatches an event with minimal overhead
100-//
101-//go:inline
102-func (d *EventDispatcher) Dispatch(objectID uint32, opcode uint16, data []byte) {
103- var handler EventHandler
104-
105- // Fast lookup path
106- if objectID < 1024 {
107- entry := d.handlers[objectID].Load()
108- if entry != nil {
109- if opcode < 32 {
110- handler = entry.handlers[opcode]
111- } else if entry.extHandlers != nil {
112- if h, ok := entry.extHandlers.Load(opcode); ok {
113- handler = h.(EventHandler)
114- }
115- }
116- }
117- } else {
118- // Slow path for large object IDs
119- if entry, ok := d.extHandlers.Load(objectID); ok {
120- h := entry.(*handlerEntry)
121- if opcode < 32 {
122- handler = h.handlers[opcode]
123- } else if h.extHandlers != nil {
124- if fn, ok := h.extHandlers.Load(opcode); ok {
125- handler = fn.(EventHandler)
126- }
127- }
128- }
129- }
130-
131- if handler == nil {
132- return
133- }
134-
135- // Get event from pool
136- event := eventPool.Get().(*Event)
137- event.ProxyID = objectID
138- event.Opcode = opcode
139- event.data = append(event.data[:0], data...) // Reuse backing array
140- event.offset = 0
141-
142- // Call handler
143- handler(event)
144-
145- // Return to pool
146- eventPool.Put(event)
147-}
148-
149-// BatchDispatch processes multiple events in a batch for better cache locality
150-func (d *EventDispatcher) BatchDispatch(events []RawEvent) {
151- // Process events in batches to improve cache performance
152- for i := range events {
153- e := &events[i]
154- d.Dispatch(e.ObjectID, e.Opcode, e.Data)
155- }
156-}
157-
158-// RawEvent represents a raw event before dispatch
159-type RawEvent struct {
160- ObjectID uint32
161- Opcode uint16
162- Data []byte
163-}
164-
165-// Ensure cache line alignment for hot data structures
166-type cacheLinePad [64]byte
167-
168-// PerformanceStats tracks dispatcher performance
169-type PerformanceStats struct {
170- EventsDispatched atomic.Uint64
171- _ cacheLinePad
172- NanosecondsSpent atomic.Uint64
173- _ cacheLinePad
174- CacheMisses atomic.Uint64
175- _ cacheLinePad
176-}
177-
178-// GetAverageLatency returns average dispatch latency in nanoseconds
179-func (s *PerformanceStats) GetAverageLatency() uint64 {
180- events := s.EventsDispatched.Load()
181- if events == 0 {
182- return 0
183- }
184- return s.NanosecondsSpent.Load() / events
185-}
@@ -1,185 +0,0 @@
1-//go:build linux
2-// +build linux
3-
4-package wlturbo
5-
6-import (
7- "sync"
8- "sync/atomic"
9-)
10-
11-// Event pool for zero-allocation event handling
12-var eventPool = sync.Pool{
13- New: func() interface{} {
14- return &Event{
15- data: make([]byte, 0, 4096), // Pre-allocate 4KB
16- }
17- },
18-}
19-
20-// EventHandler is a function type for handling events with zero allocations
21-type EventHandler func(event *Event)
22-
23-// EventDispatcher handles high-performance event dispatching
24-type EventDispatcher struct {
25- // Lock-free handler lookup using atomic operations
26- handlers [1024]atomic.Pointer[handlerEntry] // Fixed-size array for object IDs 0-1023
27-
28- // Extended handlers for object IDs >= 1024 (rare case)
29- extHandlers sync.Map
30-}
31-
32-// handlerEntry stores handlers for a specific object
33-type handlerEntry struct {
34- // Array of handlers indexed by opcode (most objects have < 16 opcodes)
35- handlers [32]EventHandler
36-
37- // Extended handlers for opcodes >= 32 (very rare)
38- extHandlers *sync.Map
39-}
40-
41-// NewEventDispatcher creates a high-performance event dispatcher
42-func NewEventDispatcher() *EventDispatcher {
43- return &EventDispatcher{}
44-}
45-
46-// RegisterHandler registers an event handler with zero allocation in common case
47-func (d *EventDispatcher) RegisterHandler(objectID uint32, opcode uint16, handler EventHandler) {
48- if objectID < 1024 {
49- // Fast path: use lock-free array
50- for {
51- entry := d.handlers[objectID].Load()
52- if entry == nil {
53- // Create new entry
54- newEntry := &handlerEntry{}
55- if opcode < 32 {
56- newEntry.handlers[opcode] = handler
57- } else {
58- newEntry.extHandlers = &sync.Map{}
59- newEntry.extHandlers.Store(opcode, handler)
60- }
61-
62- // Try to set atomically
63- if d.handlers[objectID].CompareAndSwap(nil, newEntry) {
64- return
65- }
66- // Retry if someone else created it
67- continue
68- }
69-
70- // Entry exists, update it
71- if opcode < 32 {
72- // Direct array access (no locking needed for write)
73- entry.handlers[opcode] = handler
74- } else {
75- // Extended handlers
76- if entry.extHandlers == nil {
77- entry.extHandlers = &sync.Map{}
78- }
79- entry.extHandlers.Store(opcode, handler)
80- }
81- return
82- }
83- } else {
84- // Slow path: use sync.Map for large object IDs
85- entry, _ := d.extHandlers.LoadOrStore(objectID, &handlerEntry{})
86- h := entry.(*handlerEntry)
87-
88- if opcode < 32 {
89- h.handlers[opcode] = handler
90- } else {
91- if h.extHandlers == nil {
92- h.extHandlers = &sync.Map{}
93- }
94- h.extHandlers.Store(opcode, handler)
95- }
96- }
97-}
98-
99-// Dispatch dispatches an event with minimal overhead
100-//
101-//go:inline
102-func (d *EventDispatcher) Dispatch(objectID uint32, opcode uint16, data []byte) {
103- var handler EventHandler
104-
105- // Fast lookup path
106- if objectID < 1024 {
107- entry := d.handlers[objectID].Load()
108- if entry != nil {
109- if opcode < 32 {
110- handler = entry.handlers[opcode]
111- } else if entry.extHandlers != nil {
112- if h, ok := entry.extHandlers.Load(opcode); ok {
113- handler = h.(EventHandler)
114- }
115- }
116- }
117- } else {
118- // Slow path for large object IDs
119- if entry, ok := d.extHandlers.Load(objectID); ok {
120- h := entry.(*handlerEntry)
121- if opcode < 32 {
122- handler = h.handlers[opcode]
123- } else if h.extHandlers != nil {
124- if fn, ok := h.extHandlers.Load(opcode); ok {
125- handler = fn.(EventHandler)
126- }
127- }
128- }
129- }
130-
131- if handler == nil {
132- return
133- }
134-
135- // Get event from pool
136- event := eventPool.Get().(*Event)
137- event.ProxyID = objectID
138- event.Opcode = opcode
139- event.data = append(event.data[:0], data...) // Reuse backing array
140- event.offset = 0
141-
142- // Call handler
143- handler(event)
144-
145- // Return to pool
146- eventPool.Put(event)
147-}
148-
149-// BatchDispatch processes multiple events in a batch for better cache locality
150-func (d *EventDispatcher) BatchDispatch(events []RawEvent) {
151- // Process events in batches to improve cache performance
152- for i := range events {
153- e := &events[i]
154- d.Dispatch(e.ObjectID, e.Opcode, e.Data)
155- }
156-}
157-
158-// RawEvent represents a raw event before dispatch
159-type RawEvent struct {
160- ObjectID uint32
161- Opcode uint16
162- Data []byte
163-}
164-
165-// Ensure cache line alignment for hot data structures
166-type cacheLinePad [64]byte
167-
168-// PerformanceStats tracks dispatcher performance
169-type PerformanceStats struct {
170- EventsDispatched atomic.Uint64
171- _ cacheLinePad
172- NanosecondsSpent atomic.Uint64
173- _ cacheLinePad
174- CacheMisses atomic.Uint64
175- _ cacheLinePad
176-}
177-
178-// GetAverageLatency returns average dispatch latency in nanoseconds
179-func (s *PerformanceStats) GetAverageLatency() uint64 {
180- events := s.EventsDispatched.Load()
181- if events == 0 {
182- return 0
183- }
184- return s.NanosecondsSpent.Load() / events
185-}
A hardening_test.go +214 -0
@@ -0,0 +1,214 @@
1+package wlturbo
2+
3+import (
4+ "bytes"
5+ "encoding/binary"
6+ "errors"
7+ "io"
8+ "net"
9+ "os"
10+ "testing"
11+ "time"
12+)
13+
14+// A read deadline must not leave the Display permanently broken.
15+func TestDispatchDeadlineIsNotSticky(t *testing.T) {
16+ client, server := net.Pipe()
17+ defer client.Close()
18+ defer server.Close()
19+ d := newDisplay(client)
20+ records := []EventRecord{}
21+ p := &recordingProxy{BaseProxy: BaseProxy{id: 7, context: d.context}, records: &records}
22+ d.objects.Store(uint32(7), p)
23+ d.RegisterEventSignature(7, 4, "uint,")
24+
25+ if err := client.SetReadDeadline(time.Now().Add(20 * time.Millisecond)); err != nil {
26+ t.Fatal(err)
27+ }
28+ if err := d.Dispatch(); !errors.Is(err, os.ErrDeadlineExceeded) {
29+ t.Fatalf("Dispatch = %v, want deadline exceeded", err)
30+ }
31+ if err := client.SetReadDeadline(time.Time{}); err != nil {
32+ t.Fatal(err)
33+ }
34+ go func() { _, _ = server.Write(message(7, 4, []byte{1, 0, 0, 0})) }()
35+ if err := d.Dispatch(); err != nil {
36+ t.Fatalf("Dispatch after clearing deadline = %v", err)
37+ }
38+ if len(records) != 1 {
39+ t.Fatalf("records = %d, want 1", len(records))
40+ }
41+}
42+
43+type countingGlobalHandler struct{ n *int }
44+
45+func (h countingGlobalHandler) HandleRegistryGlobal(RegistryGlobalEvent) { *h.n++ }
46+
47+// Every registered global handler runs, not only the last one.
48+func TestRegistryGlobalHandlersAccumulate(t *testing.T) {
49+ d := newDisplay(&chunkConn{})
50+ var a, b, specific int
51+ d.registry.AddGlobalHandler(countingGlobalHandler{&a})
52+ d.registry.AddGlobalHandler(countingGlobalHandler{&b})
53+ d.registry.AddHandler("abc", func(*Registry, uint32, uint32) { specific++ })
54+ d.registry.handleGlobal(1, "abc", 1)
55+ if a != 1 || b != 1 || specific != 1 {
56+ t.Fatalf("calls a=%d b=%d specific=%d, want 1 each", a, b, specific)
57+ }
58+}
59+
60+type fdSigProxy struct {
61+ BaseProxy
62+ calls int
63+}
64+
65+func (p *fdSigProxy) EventSignature(op uint16) (string, bool) {
66+ switch op {
67+ case 0:
68+ return "uint,", true
69+ case 1:
70+ return "fd,", true
71+ }
72+ return "", false
73+}
74+func (p *fdSigProxy) Dispatch(*Event) { p.calls++ }
75+
76+// Events already in flight for an object the client destroyed are dropped,
77+// with their descriptors closed, until the compositor sends delete_id.
78+func TestDestroyedObjectEventsAreDroppedUntilDeleteID(t *testing.T) {
79+ client, peer := unixSocketPair(t)
80+ d := newDisplay(client)
81+ p := &fdSigProxy{BaseProxy: BaseProxy{id: d.AllocateID(), context: d.context}}
82+ d.context.Register(p)
83+ if err := d.context.SendDestructor(p, 0); err != nil {
84+ t.Fatal(err)
85+ }
86+ if err := d.context.SendRequest(p, 1); err == nil {
87+ t.Fatal("request on destroyed proxy succeeded")
88+ }
89+
90+ r, w, err := os.Pipe()
91+ if err != nil {
92+ t.Fatal(err)
93+ }
94+ defer r.Close()
95+ sendMessageWithFDs(t, peer, message(p.ID(), 0, []byte{1, 0, 0, 0}), nil)
96+ sendMessageWithFDs(t, peer, message(p.ID(), 1, nil), []int{int(w.Fd())})
97+ w.Close()
98+ for i := 0; i < 2; i++ {
99+ if err := d.Dispatch(); err != nil {
100+ t.Fatalf("in-flight event %d: %v", i, err)
101+ }
102+ }
103+ if p.calls != 0 {
104+ t.Fatalf("destroyed proxy received %d events", p.calls)
105+ }
106+ if err := r.SetReadDeadline(time.Now().Add(2 * time.Second)); err != nil {
107+ t.Fatal(err)
108+ }
109+ if _, err := r.Read(make([]byte, 1)); !errors.Is(err, io.EOF) {
110+ t.Fatalf("descriptor for destroyed object not closed: %v", err)
111+ }
112+
113+ body := make([]byte, 4)
114+ binary.LittleEndian.PutUint32(body, p.ID())
115+ sendMessageWithFDs(t, peer, message(displayObjectID, 1, body), nil)
116+ if err := d.Dispatch(); err != nil {
117+ t.Fatalf("delete_id for zombie: %v", err)
118+ }
119+ sendMessageWithFDs(t, peer, message(p.ID(), 0, []byte{1, 0, 0, 0}), nil)
120+ if err := d.Dispatch(); !errors.Is(err, ErrUnknownObject) {
121+ t.Fatalf("event after delete_id = %v, want ErrUnknownObject", err)
122+ }
123+ if got := d.AllocateID(); got != p.ID() {
124+ t.Fatalf("ID %d not reused after delete_id (got %d)", p.ID(), got)
125+ }
126+}
127+
128+// A plain Go int is ambiguous (value or descriptor) and must be rejected
129+// instead of being written as zero.
130+func TestMarshalRejectsPlainInt(t *testing.T) {
131+ d := newDisplay(&chunkConn{})
132+ if err := d.marshalArg(&bytes.Buffer{}, 42); err == nil {
133+ t.Fatal("marshalArg(int) succeeded, want error")
134+ }
135+ if err := d.SendRequest(9, 0, 42); err == nil {
136+ t.Fatal("SendRequest with int argument succeeded, want error")
137+ }
138+}
139+
140+func TestCheckVersion(t *testing.T) {
141+ if err := CheckVersion(0, 5, "x.y"); err != nil {
142+ t.Fatalf("unknown version rejected: %v", err)
143+ }
144+ if err := CheckVersion(5, 5, "x.y"); err != nil {
145+ t.Fatalf("exact version rejected: %v", err)
146+ }
147+ if err := CheckVersion(4, 5, "x.y"); !errors.Is(err, ErrVersionTooLow) {
148+ t.Fatalf("older version = %v, want ErrVersionTooLow", err)
149+ }
150+}
151+
152+// Bind records the negotiated version so generated requests can check it.
153+func TestBindRecordsVersion(t *testing.T) {
154+ d := newDisplay(&chunkConn{})
155+ p := &BaseProxy{}
156+ if err := d.Registry().Bind(1, "wl_seat", 3, p); err != nil {
157+ t.Fatal(err)
158+ }
159+ if p.Version() != 3 {
160+ t.Fatalf("version = %d, want 3", p.Version())
161+ }
162+}
163+
164+// A late Unregister of a destroyed proxy (for example from a handler that was
165+// already running) must not remove its zombie.
166+func TestUnregisterKeepsZombie(t *testing.T) {
167+ d := newDisplay(&chunkConn{})
168+ p := &fdSigProxy{BaseProxy: BaseProxy{id: d.AllocateID(), context: d.context}}
169+ d.context.Register(p)
170+ if err := d.context.SendDestructor(p, 0); err != nil {
171+ t.Fatal(err)
172+ }
173+ d.context.Unregister(p)
174+ if obj, _ := d.objects.Load(p.ID()); obj == nil {
175+ t.Fatal("Unregister removed the zombie")
176+ } else if _, ok := obj.(*zombie); !ok {
177+ t.Fatalf("object = %T, want *zombie", obj)
178+ }
179+}
180+
181+// Context.Request owns the request lifecycle generated code relies on.
182+func TestContextRequestLifecycle(t *testing.T) {
183+ d := newDisplay(&chunkConn{})
184+ parent := &BaseProxy{id: d.AllocateID(), context: d.context, version: 2}
185+ d.context.Register(parent)
186+
187+ child := &BaseProxy{context: d.context}
188+ if err := d.context.Request(Request{Proxy: parent, Opcode: 0, Name: "x.make", Child: child}, child); err != nil {
189+ t.Fatal(err)
190+ }
191+ if child.ID() == 0 || child.Version() != 2 {
192+ t.Fatalf("child id=%d version=%d, want allocated id and version 2", child.ID(), child.Version())
193+ }
194+ if _, ok := d.objects.Load(child.ID()); !ok {
195+ t.Fatal("child not registered")
196+ }
197+
198+ late := &BaseProxy{context: d.context}
199+ err := d.context.Request(Request{Proxy: parent, Opcode: 1, Name: "x.late", Since: 3, Child: late}, late)
200+ if !errors.Is(err, ErrVersionTooLow) {
201+ t.Fatalf("since=3 on v2 = %v, want ErrVersionTooLow", err)
202+ }
203+ if late.ID() != 0 {
204+ t.Fatal("child allocated for a refused request")
205+ }
206+
207+ bad := &BaseProxy{context: d.context}
208+ if err := d.context.Request(Request{Proxy: parent, Opcode: 2, Name: "x.bad", Child: bad}, bad, 42); err == nil {
209+ t.Fatal("marshal error not reported")
210+ }
211+ if _, ok := d.objects.Load(bad.ID()); ok {
212+ t.Fatal("child left registered after a failed send")
213+ }
214+}
@@ -0,0 +1,214 @@
1+package wlturbo
2+
3+import (
4+ "bytes"
5+ "encoding/binary"
6+ "errors"
7+ "io"
8+ "net"
9+ "os"
10+ "testing"
11+ "time"
12+)
13+
14+// A read deadline must not leave the Display permanently broken.
15+func TestDispatchDeadlineIsNotSticky(t *testing.T) {
16+ client, server := net.Pipe()
17+ defer client.Close()
18+ defer server.Close()
19+ d := newDisplay(client)
20+ records := []EventRecord{}
21+ p := &recordingProxy{BaseProxy: BaseProxy{id: 7, context: d.context}, records: &records}
22+ d.objects.Store(uint32(7), p)
23+ d.RegisterEventSignature(7, 4, "uint,")
24+
25+ if err := client.SetReadDeadline(time.Now().Add(20 * time.Millisecond)); err != nil {
26+ t.Fatal(err)
27+ }
28+ if err := d.Dispatch(); !errors.Is(err, os.ErrDeadlineExceeded) {
29+ t.Fatalf("Dispatch = %v, want deadline exceeded", err)
30+ }
31+ if err := client.SetReadDeadline(time.Time{}); err != nil {
32+ t.Fatal(err)
33+ }
34+ go func() { _, _ = server.Write(message(7, 4, []byte{1, 0, 0, 0})) }()
35+ if err := d.Dispatch(); err != nil {
36+ t.Fatalf("Dispatch after clearing deadline = %v", err)
37+ }
38+ if len(records) != 1 {
39+ t.Fatalf("records = %d, want 1", len(records))
40+ }
41+}
42+
43+type countingGlobalHandler struct{ n *int }
44+
45+func (h countingGlobalHandler) HandleRegistryGlobal(RegistryGlobalEvent) { *h.n++ }
46+
47+// Every registered global handler runs, not only the last one.
48+func TestRegistryGlobalHandlersAccumulate(t *testing.T) {
49+ d := newDisplay(&chunkConn{})
50+ var a, b, specific int
51+ d.registry.AddGlobalHandler(countingGlobalHandler{&a})
52+ d.registry.AddGlobalHandler(countingGlobalHandler{&b})
53+ d.registry.AddHandler("abc", func(*Registry, uint32, uint32) { specific++ })
54+ d.registry.handleGlobal(1, "abc", 1)
55+ if a != 1 || b != 1 || specific != 1 {
56+ t.Fatalf("calls a=%d b=%d specific=%d, want 1 each", a, b, specific)
57+ }
58+}
59+
60+type fdSigProxy struct {
61+ BaseProxy
62+ calls int
63+}
64+
65+func (p *fdSigProxy) EventSignature(op uint16) (string, bool) {
66+ switch op {
67+ case 0:
68+ return "uint,", true
69+ case 1:
70+ return "fd,", true
71+ }
72+ return "", false
73+}
74+func (p *fdSigProxy) Dispatch(*Event) { p.calls++ }
75+
76+// Events already in flight for an object the client destroyed are dropped,
77+// with their descriptors closed, until the compositor sends delete_id.
78+func TestDestroyedObjectEventsAreDroppedUntilDeleteID(t *testing.T) {
79+ client, peer := unixSocketPair(t)
80+ d := newDisplay(client)
81+ p := &fdSigProxy{BaseProxy: BaseProxy{id: d.AllocateID(), context: d.context}}
82+ d.context.Register(p)
83+ if err := d.context.SendDestructor(p, 0); err != nil {
84+ t.Fatal(err)
85+ }
86+ if err := d.context.SendRequest(p, 1); err == nil {
87+ t.Fatal("request on destroyed proxy succeeded")
88+ }
89+
90+ r, w, err := os.Pipe()
91+ if err != nil {
92+ t.Fatal(err)
93+ }
94+ defer r.Close()
95+ sendMessageWithFDs(t, peer, message(p.ID(), 0, []byte{1, 0, 0, 0}), nil)
96+ sendMessageWithFDs(t, peer, message(p.ID(), 1, nil), []int{int(w.Fd())})
97+ w.Close()
98+ for i := 0; i < 2; i++ {
99+ if err := d.Dispatch(); err != nil {
100+ t.Fatalf("in-flight event %d: %v", i, err)
101+ }
102+ }
103+ if p.calls != 0 {
104+ t.Fatalf("destroyed proxy received %d events", p.calls)
105+ }
106+ if err := r.SetReadDeadline(time.Now().Add(2 * time.Second)); err != nil {
107+ t.Fatal(err)
108+ }
109+ if _, err := r.Read(make([]byte, 1)); !errors.Is(err, io.EOF) {
110+ t.Fatalf("descriptor for destroyed object not closed: %v", err)
111+ }
112+
113+ body := make([]byte, 4)
114+ binary.LittleEndian.PutUint32(body, p.ID())
115+ sendMessageWithFDs(t, peer, message(displayObjectID, 1, body), nil)
116+ if err := d.Dispatch(); err != nil {
117+ t.Fatalf("delete_id for zombie: %v", err)
118+ }
119+ sendMessageWithFDs(t, peer, message(p.ID(), 0, []byte{1, 0, 0, 0}), nil)
120+ if err := d.Dispatch(); !errors.Is(err, ErrUnknownObject) {
121+ t.Fatalf("event after delete_id = %v, want ErrUnknownObject", err)
122+ }
123+ if got := d.AllocateID(); got != p.ID() {
124+ t.Fatalf("ID %d not reused after delete_id (got %d)", p.ID(), got)
125+ }
126+}
127+
128+// A plain Go int is ambiguous (value or descriptor) and must be rejected
129+// instead of being written as zero.
130+func TestMarshalRejectsPlainInt(t *testing.T) {
131+ d := newDisplay(&chunkConn{})
132+ if err := d.marshalArg(&bytes.Buffer{}, 42); err == nil {
133+ t.Fatal("marshalArg(int) succeeded, want error")
134+ }
135+ if err := d.SendRequest(9, 0, 42); err == nil {
136+ t.Fatal("SendRequest with int argument succeeded, want error")
137+ }
138+}
139+
140+func TestCheckVersion(t *testing.T) {
141+ if err := CheckVersion(0, 5, "x.y"); err != nil {
142+ t.Fatalf("unknown version rejected: %v", err)
143+ }
144+ if err := CheckVersion(5, 5, "x.y"); err != nil {
145+ t.Fatalf("exact version rejected: %v", err)
146+ }
147+ if err := CheckVersion(4, 5, "x.y"); !errors.Is(err, ErrVersionTooLow) {
148+ t.Fatalf("older version = %v, want ErrVersionTooLow", err)
149+ }
150+}
151+
152+// Bind records the negotiated version so generated requests can check it.
153+func TestBindRecordsVersion(t *testing.T) {
154+ d := newDisplay(&chunkConn{})
155+ p := &BaseProxy{}
156+ if err := d.Registry().Bind(1, "wl_seat", 3, p); err != nil {
157+ t.Fatal(err)
158+ }
159+ if p.Version() != 3 {
160+ t.Fatalf("version = %d, want 3", p.Version())
161+ }
162+}
163+
164+// A late Unregister of a destroyed proxy (for example from a handler that was
165+// already running) must not remove its zombie.
166+func TestUnregisterKeepsZombie(t *testing.T) {
167+ d := newDisplay(&chunkConn{})
168+ p := &fdSigProxy{BaseProxy: BaseProxy{id: d.AllocateID(), context: d.context}}
169+ d.context.Register(p)
170+ if err := d.context.SendDestructor(p, 0); err != nil {
171+ t.Fatal(err)
172+ }
173+ d.context.Unregister(p)
174+ if obj, _ := d.objects.Load(p.ID()); obj == nil {
175+ t.Fatal("Unregister removed the zombie")
176+ } else if _, ok := obj.(*zombie); !ok {
177+ t.Fatalf("object = %T, want *zombie", obj)
178+ }
179+}
180+
181+// Context.Request owns the request lifecycle generated code relies on.
182+func TestContextRequestLifecycle(t *testing.T) {
183+ d := newDisplay(&chunkConn{})
184+ parent := &BaseProxy{id: d.AllocateID(), context: d.context, version: 2}
185+ d.context.Register(parent)
186+
187+ child := &BaseProxy{context: d.context}
188+ if err := d.context.Request(Request{Proxy: parent, Opcode: 0, Name: "x.make", Child: child}, child); err != nil {
189+ t.Fatal(err)
190+ }
191+ if child.ID() == 0 || child.Version() != 2 {
192+ t.Fatalf("child id=%d version=%d, want allocated id and version 2", child.ID(), child.Version())
193+ }
194+ if _, ok := d.objects.Load(child.ID()); !ok {
195+ t.Fatal("child not registered")
196+ }
197+
198+ late := &BaseProxy{context: d.context}
199+ err := d.context.Request(Request{Proxy: parent, Opcode: 1, Name: "x.late", Since: 3, Child: late}, late)
200+ if !errors.Is(err, ErrVersionTooLow) {
201+ t.Fatalf("since=3 on v2 = %v, want ErrVersionTooLow", err)
202+ }
203+ if late.ID() != 0 {
204+ t.Fatal("child allocated for a refused request")
205+ }
206+
207+ bad := &BaseProxy{context: d.context}
208+ if err := d.context.Request(Request{Proxy: parent, Opcode: 2, Name: "x.bad", Child: bad}, bad, 42); err == nil {
209+ t.Fatal("marshal error not reported")
210+ }
211+ if _, ok := d.objects.Load(bad.ID()); ok {
212+ t.Fatal("child left registered after a failed send")
213+ }
214+}
M internal/scanner/scanner.go +11 -17
@@ -187,18 +187,18 @@ type requestData struct {
187187 Doc string
188188 Opcode int
189189 Destructor bool
190+ Since int
190191 Params string
191192 Results string
192193 ArgPreparations []string
193- ArgExprs []string
194194 CreatesChild bool
195195 ChildVar string
196196 ChildType string
197197 ChildFactory string
198198 ErrorReturn string
199- FDArgs []string
200199 HasFDs bool
201- SendCall string
200+ FDList string
201+ ArgList string
202202 }
203203
204204 // argSlot is one positional argument of a request, in declaration order. A
@@ -407,6 +407,7 @@ func (s *Scanner) processRequest(iface Interface, req Request, opcode int) (requ
407407 Doc: s.formatDescription(req.Description),
408408 Opcode: opcode,
409409 Destructor: req.Type == "destructor",
410+ Since: req.Since,
410411 ChildVar: "child",
411412 }
412413
@@ -455,7 +456,6 @@ func (s *Scanner) processRequest(iface Interface, req Request, opcode int) (requ
455456 // them, and the descriptor list is attached to the request.
456457 params = append(params, name+" int")
457458 fdExprs = append(fdExprs, name)
458- data.FDArgs = append(data.FDArgs, name)
459459 expr = "uintptr(" + name + ")"
460460
461461 default:
@@ -486,23 +486,16 @@ func (s *Scanner) processRequest(iface Interface, req Request, opcode int) (requ
486486 }
487487
488488 data.Params = strings.Join(params, ", ")
489- data.ArgExprs = argExprs
490489 args := ""
491490 if len(argExprs) > 0 {
492491 args = ", " + strings.Join(argExprs, ", ")
493492 }
494- // Destructors claim the proxy atomically before sending so a concurrent
495- // second destroy cannot reach the wire.
496- send := "SendRequest"
497- if data.Destructor {
498- send = "SendDestructor"
499- }
500- if len(fdExprs) > 0 {
501- data.HasFDs = true
502- data.SendCall = fmt.Sprintf("%sWithFDs(o, %d, []int{%s}%s)", send, opcode, strings.Join(fdExprs, ", "), args)
503- } else {
504- data.SendCall = fmt.Sprintf("%s(o, %d%s)", send, opcode, args)
505- }
493+ // Context.Request owns the lifecycle: destructors claim the proxy
494+ // atomically, children are registered before the send and descriptors are
495+ // closed only after a successful send.
496+ data.ArgList = args
497+ data.FDList = strings.Join(fdExprs, ", ")
498+ data.HasFDs = len(fdExprs) > 0
506499 if data.CreatesChild {
507500 data.Results = "(*" + data.ChildType + ", error)"
508501 data.ErrorReturn = "nil, err"
@@ -549,6 +542,7 @@ func (s *Scanner) processEvent(event Event, opcode int) (eventData, error) {
549542 }
550543 data.DecodeLines = append(data.DecodeLines,
551544 fmt.Sprintf("%s.SetID(%sID)", child, name),
545+ fmt.Sprintf("%s.SetVersion(o.Version())", child),
552546 fmt.Sprintf("o.Context().Register(%s)", child),
553547 )
554548 params = append(params, child+" *"+childType)
@@ -187,18 +187,18 @@ type requestData struct {
187 Doc string187 Doc string
188 Opcode int188 Opcode int
189 Destructor bool189 Destructor bool
190+ Since int
190 Params string191 Params string
191 Results string192 Results string
192 ArgPreparations []string193 ArgPreparations []string
193- ArgExprs []string
194 CreatesChild bool194 CreatesChild bool
195 ChildVar string195 ChildVar string
196 ChildType string196 ChildType string
197 ChildFactory string197 ChildFactory string
198 ErrorReturn string198 ErrorReturn string
199- FDArgs []string
200 HasFDs bool199 HasFDs bool
201- SendCall string200+ FDList string
201+ ArgList string
202 }202 }
203 203
204 // argSlot is one positional argument of a request, in declaration order. A204 // argSlot is one positional argument of a request, in declaration order. A
@@ -407,6 +407,7 @@ func (s *Scanner) processRequest(iface Interface, req Request, opcode int) (requ
407 Doc: s.formatDescription(req.Description),407 Doc: s.formatDescription(req.Description),
408 Opcode: opcode,408 Opcode: opcode,
409 Destructor: req.Type == "destructor",409 Destructor: req.Type == "destructor",
410+ Since: req.Since,
410 ChildVar: "child",411 ChildVar: "child",
411 }412 }
412 413
@@ -455,7 +456,6 @@ func (s *Scanner) processRequest(iface Interface, req Request, opcode int) (requ
455 // them, and the descriptor list is attached to the request.456 // them, and the descriptor list is attached to the request.
456 params = append(params, name+" int")457 params = append(params, name+" int")
457 fdExprs = append(fdExprs, name)458 fdExprs = append(fdExprs, name)
458- data.FDArgs = append(data.FDArgs, name)
459 expr = "uintptr(" + name + ")"459 expr = "uintptr(" + name + ")"
460 460
461 default:461 default:
@@ -486,23 +486,16 @@ func (s *Scanner) processRequest(iface Interface, req Request, opcode int) (requ
486 }486 }
487 487
488 data.Params = strings.Join(params, ", ")488 data.Params = strings.Join(params, ", ")
489- data.ArgExprs = argExprs
490 args := ""489 args := ""
491 if len(argExprs) > 0 {490 if len(argExprs) > 0 {
492 args = ", " + strings.Join(argExprs, ", ")491 args = ", " + strings.Join(argExprs, ", ")
493 }492 }
494- // Destructors claim the proxy atomically before sending so a concurrent493+ // Context.Request owns the lifecycle: destructors claim the proxy
495- // second destroy cannot reach the wire.494+ // atomically, children are registered before the send and descriptors are
496- send := "SendRequest"495+ // closed only after a successful send.
497- if data.Destructor {496+ data.ArgList = args
498- send = "SendDestructor"497+ data.FDList = strings.Join(fdExprs, ", ")
499- }498+ data.HasFDs = len(fdExprs) > 0
500- if len(fdExprs) > 0 {
501- data.HasFDs = true
502- data.SendCall = fmt.Sprintf("%sWithFDs(o, %d, []int{%s}%s)", send, opcode, strings.Join(fdExprs, ", "), args)
503- } else {
504- data.SendCall = fmt.Sprintf("%s(o, %d%s)", send, opcode, args)
505- }
506 if data.CreatesChild {499 if data.CreatesChild {
507 data.Results = "(*" + data.ChildType + ", error)"500 data.Results = "(*" + data.ChildType + ", error)"
508 data.ErrorReturn = "nil, err"501 data.ErrorReturn = "nil, err"
@@ -549,6 +542,7 @@ func (s *Scanner) processEvent(event Event, opcode int) (eventData, error) {
549 }542 }
550 data.DecodeLines = append(data.DecodeLines,543 data.DecodeLines = append(data.DecodeLines,
551 fmt.Sprintf("%s.SetID(%sID)", child, name),544 fmt.Sprintf("%s.SetID(%sID)", child, name),
545+ fmt.Sprintf("%s.SetVersion(o.Version())", child),
552 fmt.Sprintf("o.Context().Register(%s)", child),546 fmt.Sprintf("o.Context().Register(%s)", child),
553 )547 )
554 params = append(params, child+" *"+childType)548 params = append(params, child+" *"+childType)
M internal/scanner/template.go +8 -12
@@ -2,8 +2,9 @@ package scanner
22
33 // protocolTemplate is the template for generating WLTurbo-backed Go bindings.
44 //
5-// Generated objects embed wl.BaseProxy, allocate and register child objects
6-// through the wl.Context, send requests through that context, and dispatch
5+// Generated objects embed wl.BaseProxy, send every request through
6+// wl.Context.Request (which owns version checks, child registration and FD
7+// cleanup), and dispatch
78 // typed events to registered handlers. Nothing in the generated code opens a
89 // socket or frames messages itself: that is the transport's job.
910 const protocolTemplate = `// Code generated by wlturbo-scanner. DO NOT EDIT.
@@ -50,7 +51,6 @@ func New{{$iface.GoName}}(ctx *wl.Context) *{{$iface.GoName}} {
5051 // {{.Doc}}
5152 {{- end}}
5253 func (o *{{$iface.GoName}}) {{.GoName}}({{.Params}}) {{.Results}} {
53-if err := o.Context().CheckProxy(o); err != nil { return {{.ErrorReturn}} }
5454 {{- range .ArgPreparations}}
5555 {{.}}
5656 {{- end}}
@@ -61,18 +61,14 @@ if err := o.Context().CheckProxy(o); err != nil { return {{.ErrorReturn}} }
6161 {{.ChildVar}} := &{{.ChildType}}{}
6262 {{.ChildVar}}.SetContext(o.Context())
6363 {{- end}}
64- {{.ChildVar}}.SetID(o.Context().AllocateID())
65- o.Context().Register({{.ChildVar}})
66-{{- end}}
67- if err := o.Context().{{.SendCall}}; err != nil {
68-{{- if .CreatesChild}}
69- o.Context().Unregister({{.ChildVar}})
7064 {{- end}}
65+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: {{.Opcode}}, Name: "{{$iface.Name}}.{{.Name}}"
66+ {{- if gt .Since 1}}, Since: {{.Since}}{{end}}
67+ {{- if .Destructor}}, Destructor: true{{end}}
68+ {{- if .CreatesChild}}, Child: {{.ChildVar}}{{end}}
69+ {{- if .HasFDs}}, FDs: []int{ {{- .FDList -}} }{{end}}}{{.ArgList}}); err != nil {
7170 return {{.ErrorReturn}}
7271 }
73-{{- range .FDArgs}}
74- _ = wl.CloseSentFD({{.}})
75-{{- end}}
7672 {{- if .CreatesChild}}
7773 return {{.ChildVar}}, nil
7874 {{- else}}
@@ -2,8 +2,9 @@ package scanner
2 2
3 // protocolTemplate is the template for generating WLTurbo-backed Go bindings.3 // protocolTemplate is the template for generating WLTurbo-backed Go bindings.
4 //4 //
5-// Generated objects embed wl.BaseProxy, allocate and register child objects5+// Generated objects embed wl.BaseProxy, send every request through
6-// through the wl.Context, send requests through that context, and dispatch6+// wl.Context.Request (which owns version checks, child registration and FD
7+// cleanup), and dispatch
7 // typed events to registered handlers. Nothing in the generated code opens a8 // typed events to registered handlers. Nothing in the generated code opens a
8 // socket or frames messages itself: that is the transport's job.9 // socket or frames messages itself: that is the transport's job.
9 const protocolTemplate = `// Code generated by wlturbo-scanner. DO NOT EDIT.10 const protocolTemplate = `// Code generated by wlturbo-scanner. DO NOT EDIT.
@@ -50,7 +51,6 @@ func New{{$iface.GoName}}(ctx *wl.Context) *{{$iface.GoName}} {
50 // {{.Doc}}51 // {{.Doc}}
51 {{- end}}52 {{- end}}
52 func (o *{{$iface.GoName}}) {{.GoName}}({{.Params}}) {{.Results}} {53 func (o *{{$iface.GoName}}) {{.GoName}}({{.Params}}) {{.Results}} {
53-if err := o.Context().CheckProxy(o); err != nil { return {{.ErrorReturn}} }
54 {{- range .ArgPreparations}}54 {{- range .ArgPreparations}}
55 {{.}}55 {{.}}
56 {{- end}}56 {{- end}}
@@ -61,18 +61,14 @@ if err := o.Context().CheckProxy(o); err != nil { return {{.ErrorReturn}} }
61 {{.ChildVar}} := &{{.ChildType}}{}61 {{.ChildVar}} := &{{.ChildType}}{}
62 {{.ChildVar}}.SetContext(o.Context())62 {{.ChildVar}}.SetContext(o.Context())
63 {{- end}}63 {{- end}}
64- {{.ChildVar}}.SetID(o.Context().AllocateID())
65- o.Context().Register({{.ChildVar}})
66-{{- end}}
67- if err := o.Context().{{.SendCall}}; err != nil {
68-{{- if .CreatesChild}}
69- o.Context().Unregister({{.ChildVar}})
70 {{- end}}64 {{- end}}
65+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: {{.Opcode}}, Name: "{{$iface.Name}}.{{.Name}}"
66+ {{- if gt .Since 1}}, Since: {{.Since}}{{end}}
67+ {{- if .Destructor}}, Destructor: true{{end}}
68+ {{- if .CreatesChild}}, Child: {{.ChildVar}}{{end}}
69+ {{- if .HasFDs}}, FDs: []int{ {{- .FDList -}} }{{end}}}{{.ArgList}}); err != nil {
71 return {{.ErrorReturn}}70 return {{.ErrorReturn}}
72 }71 }
73-{{- range .FDArgs}}
74- _ = wl.CloseSentFD({{.}})
75-{{- end}}
76 {{- if .CreatesChild}}72 {{- if .CreatesChild}}
77 return {{.ChildVar}}, nil73 return {{.ChildVar}}, nil
78 {{- else}}74 {{- else}}
M protocol/core/wayland_generated.go +70 -317
@@ -773,15 +773,9 @@ func NewCompositor(ctx *wl.Context) *Compositor {
773773
774774 // Ask the compositor to create a new surface.
775775 func (o *Compositor) CreateSurface() (*Surface, error) {
776- if err := o.Context().CheckProxy(o); err != nil {
777- return nil, err
778- }
779776 child := &Surface{}
780777 child.SetContext(o.Context())
781- child.SetID(o.Context().AllocateID())
782- o.Context().Register(child)
783- if err := o.Context().SendRequest(o, 0, child); err != nil {
784- o.Context().Unregister(child)
778+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_compositor.create_surface", Child: child}, child); err != nil {
785779 return nil, err
786780 }
787781 return child, nil
@@ -789,15 +783,9 @@ func (o *Compositor) CreateSurface() (*Surface, error) {
789783
790784 // Ask the compositor to create a new region.
791785 func (o *Compositor) CreateRegion() (*Region, error) {
792- if err := o.Context().CheckProxy(o); err != nil {
793- return nil, err
794- }
795786 child := &Region{}
796787 child.SetContext(o.Context())
797- child.SetID(o.Context().AllocateID())
798- o.Context().Register(child)
799- if err := o.Context().SendRequest(o, 1, child); err != nil {
800- o.Context().Unregister(child)
788+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_compositor.create_region", Child: child}, child); err != nil {
801789 return nil, err
802790 }
803791 return child, nil
@@ -805,10 +793,7 @@ func (o *Compositor) CreateRegion() (*Region, error) {
805793
806794 // This request destroys the wl_compositor. This has no effect on any other objects.
807795 func (o *Compositor) Release() error {
808- if err := o.Context().CheckProxy(o); err != nil {
809- return err
810- }
811- if err := o.Context().SendDestructor(o, 2); err != nil {
796+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_compositor.release", Since: 7, Destructor: true}); err != nil {
812797 return err
813798 }
814799 return nil
@@ -847,15 +832,9 @@ func NewShmPool(ctx *wl.Context) *ShmPool {
847832
848833 // Create a wl_buffer object from the pool. The buffer is created offset bytes into the pool and has width and height as specified. The stride argument specifies the number of bytes from the beginning of one row to the beginning of the next. The format is the pixel format of the buffer and must be one of those advertised through the wl_shm.format event. A buffer will keep a reference to the pool it was created from so it is valid to destroy the pool immediately after creating a buffer from it.
849834 func (o *ShmPool) CreateBuffer(offset int32, width int32, height int32, stride int32, format uint32) (*Buffer, error) {
850- if err := o.Context().CheckProxy(o); err != nil {
851- return nil, err
852- }
853835 child := &Buffer{}
854836 child.SetContext(o.Context())
855- child.SetID(o.Context().AllocateID())
856- o.Context().Register(child)
857- if err := o.Context().SendRequest(o, 0, child, offset, width, height, stride, format); err != nil {
858- o.Context().Unregister(child)
837+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_shm_pool.create_buffer", Child: child}, child, offset, width, height, stride, format); err != nil {
859838 return nil, err
860839 }
861840 return child, nil
@@ -863,10 +842,7 @@ func (o *ShmPool) CreateBuffer(offset int32, width int32, height int32, stride i
863842
864843 // Destroy the shared memory pool. The mmapped memory will be released when all buffers that have been created from this pool are gone.
865844 func (o *ShmPool) Destroy() error {
866- if err := o.Context().CheckProxy(o); err != nil {
867- return err
868- }
869- if err := o.Context().SendDestructor(o, 1); err != nil {
845+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_shm_pool.destroy", Destructor: true}); err != nil {
870846 return err
871847 }
872848 return nil
@@ -874,10 +850,7 @@ func (o *ShmPool) Destroy() error {
874850
875851 // This request will cause the server to remap the backing memory for the pool from the file descriptor passed when the pool was created, but using the new size. This request can only be used to make the pool bigger. This request only changes the amount of bytes that are mmapped by the server and does not touch the file corresponding to the file descriptor passed at creation time. It is the client's responsibility to ensure that the file is at least as big as the new pool size.
876852 func (o *ShmPool) Resize(size int32) error {
877- if err := o.Context().CheckProxy(o); err != nil {
878- return err
879- }
880- if err := o.Context().SendRequest(o, 2, size); err != nil {
853+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_shm_pool.resize"}, size); err != nil {
881854 return err
882855 }
883856 return nil
@@ -920,27 +893,17 @@ func NewShm(ctx *wl.Context) *Shm {
920893
921894 // Create a new wl_shm_pool object. The pool can be used to create shared memory based buffer objects. The server will mmap size bytes of the passed file descriptor, to use as backing memory for the pool.
922895 func (o *Shm) CreatePool(fd int, size int32) (*ShmPool, error) {
923- if err := o.Context().CheckProxy(o); err != nil {
924- return nil, err
925- }
926896 child := &ShmPool{}
927897 child.SetContext(o.Context())
928- child.SetID(o.Context().AllocateID())
929- o.Context().Register(child)
930- if err := o.Context().SendRequestWithFDs(o, 0, []int{fd}, child, uintptr(fd), size); err != nil {
931- o.Context().Unregister(child)
898+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_shm.create_pool", Child: child, FDs: []int{fd}}, child, uintptr(fd), size); err != nil {
932899 return nil, err
933900 }
934- _ = wl.CloseSentFD(fd)
935901 return child, nil
936902 }
937903
938904 // Using this request a client can tell the server that it is not going to use the shm object anymore. Objects created via this interface remain unaffected.
939905 func (o *Shm) Release() error {
940- if err := o.Context().CheckProxy(o); err != nil {
941- return err
942- }
943- if err := o.Context().SendDestructor(o, 1); err != nil {
906+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_shm.release", Since: 2, Destructor: true}); err != nil {
944907 return err
945908 }
946909 return nil
@@ -1014,10 +977,7 @@ func NewBuffer(ctx *wl.Context) *Buffer {
1014977
1015978 // Destroy a buffer. If and how you need to release the backing storage is defined by the buffer factory interface. For possible side-effects to a surface, see wl_surface.attach.
1016979 func (o *Buffer) Destroy() error {
1017- if err := o.Context().CheckProxy(o); err != nil {
1018- return err
1019- }
1020- if err := o.Context().SendDestructor(o, 0); err != nil {
980+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_buffer.destroy", Destructor: true}); err != nil {
1021981 return err
1022982 }
1023983 return nil
@@ -1092,10 +1052,7 @@ func NewDataOffer(ctx *wl.Context) *DataOffer {
10921052
10931053 // Indicate that the client can accept the given mime type, or NULL for not accepted. For objects of version 2 or older, this request is used by the client to give feedback whether the client can receive the given mime type, or NULL if none is accepted; the feedback does not determine whether the drag-and-drop operation succeeds or not. For objects of version 3 or newer, this request determines the final result of the drag-and-drop operation. If the end result is that no mime types were accepted, the drag-and-drop operation will be cancelled and the corresponding drag source will receive wl_data_source.cancelled. Clients may still use this event in conjunction with wl_data_source.action for feedback.
10941054 func (o *DataOffer) Accept(serial uint32, mimeType string) error {
1095- if err := o.Context().CheckProxy(o); err != nil {
1096- return err
1097- }
1098- if err := o.Context().SendRequest(o, 0, serial, mimeType); err != nil {
1055+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_data_offer.accept"}, serial, mimeType); err != nil {
10991056 return err
11001057 }
11011058 return nil
@@ -1103,22 +1060,15 @@ func (o *DataOffer) Accept(serial uint32, mimeType string) error {
11031060
11041061 // To transfer the offered data, the client issues this request and indicates the mime type it wants to receive. The transfer happens through the passed file descriptor (typically created with the pipe system call). The source client writes the data in the mime type representation requested and then closes the file descriptor. The receiving client reads from the read end of the pipe until EOF and then closes its end, at which point the transfer is complete. This request may happen multiple times for different mime types, both before and after wl_data_device.drop. Drag-and-drop destination clients may preemptively fetch data or examine it more closely to determine acceptance.
11051062 func (o *DataOffer) Receive(mimeType string, fd int) error {
1106- if err := o.Context().CheckProxy(o); err != nil {
1063+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_data_offer.receive", FDs: []int{fd}}, mimeType, uintptr(fd)); err != nil {
11071064 return err
11081065 }
1109- if err := o.Context().SendRequestWithFDs(o, 1, []int{fd}, mimeType, uintptr(fd)); err != nil {
1110- return err
1111- }
1112- _ = wl.CloseSentFD(fd)
11131066 return nil
11141067 }
11151068
11161069 // Destroy the data offer.
11171070 func (o *DataOffer) Destroy() error {
1118- if err := o.Context().CheckProxy(o); err != nil {
1119- return err
1120- }
1121- if err := o.Context().SendDestructor(o, 2); err != nil {
1071+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_data_offer.destroy", Destructor: true}); err != nil {
11221072 return err
11231073 }
11241074 return nil
@@ -1126,10 +1076,7 @@ func (o *DataOffer) Destroy() error {
11261076
11271077 // Notifies the compositor that the drag destination successfully finished the drag-and-drop operation. Upon receiving this request, the compositor will emit wl_data_source.dnd_finished on the drag source client. It is a client error to perform other requests than wl_data_offer.destroy after this one. It is also an error to perform this request after a NULL mime type has been set in wl_data_offer.accept or no action was received through wl_data_offer.action. If wl_data_offer.finish request is received for a non drag and drop operation, the invalid_finish protocol error is raised.
11281078 func (o *DataOffer) Finish() error {
1129- if err := o.Context().CheckProxy(o); err != nil {
1130- return err
1131- }
1132- if err := o.Context().SendRequest(o, 3); err != nil {
1079+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "wl_data_offer.finish", Since: 3}); err != nil {
11331080 return err
11341081 }
11351082 return nil
@@ -1137,10 +1084,7 @@ func (o *DataOffer) Finish() error {
11371084
11381085 // Sets the actions that the destination side client supports for this operation. This request may trigger the emission of wl_data_source.action and wl_data_offer.action events if the compositor needs to change the selected action. This request can be called multiple times throughout the drag-and-drop operation, typically in response to wl_data_device.enter or wl_data_device.motion events. This request determines the final result of the drag-and-drop operation. If the end result is that no action is accepted, the drag source will receive wl_data_source.cancelled. The dnd_actions argument must contain only values expressed in the wl_data_device_manager.dnd_actions enum, and the preferred_action argument must only contain one of those values set, otherwise it will result in a protocol error. While managing an "ask" action, the destination drag-and-drop client may perform further wl_data_offer.receive requests, and is expected to perform one last wl_data_offer.set_actions request with a preferred action other than "ask" (and optionally wl_data_offer.accept) before requesting wl_data_offer.finish, in order to convey the action selected by the user. If the preferred action is not in the wl_data_offer.source_actions mask, an error will be raised. If the "ask" action is dismissed (e.g. user cancellation), the client is expected to perform wl_data_offer.destroy right away. This request can only be made on drag-and-drop offers, a protocol error will be raised otherwise.
11391086 func (o *DataOffer) SetActions(dndActions uint32, preferredAction uint32) error {
1140- if err := o.Context().CheckProxy(o); err != nil {
1141- return err
1142- }
1143- if err := o.Context().SendRequest(o, 4, dndActions, preferredAction); err != nil {
1087+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "wl_data_offer.set_actions", Since: 3}, dndActions, preferredAction); err != nil {
11441088 return err
11451089 }
11461090 return nil
@@ -1281,10 +1225,7 @@ func NewDataSource(ctx *wl.Context) *DataSource {
12811225
12821226 // This request adds a mime type to the set of mime types advertised to targets. Can be called several times to offer multiple types.
12831227 func (o *DataSource) Offer(mimeType string) error {
1284- if err := o.Context().CheckProxy(o); err != nil {
1285- return err
1286- }
1287- if err := o.Context().SendRequest(o, 0, mimeType); err != nil {
1228+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_data_source.offer"}, mimeType); err != nil {
12881229 return err
12891230 }
12901231 return nil
@@ -1292,10 +1233,7 @@ func (o *DataSource) Offer(mimeType string) error {
12921233
12931234 // Destroy the data source.
12941235 func (o *DataSource) Destroy() error {
1295- if err := o.Context().CheckProxy(o); err != nil {
1296- return err
1297- }
1298- if err := o.Context().SendDestructor(o, 1); err != nil {
1236+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_data_source.destroy", Destructor: true}); err != nil {
12991237 return err
13001238 }
13011239 return nil
@@ -1303,10 +1241,7 @@ func (o *DataSource) Destroy() error {
13031241
13041242 // Sets the actions that the source side client supports for this operation. This request may trigger wl_data_source.action and wl_data_offer.action events if the compositor needs to change the selected action. The dnd_actions argument must contain only values expressed in the wl_data_device_manager.dnd_actions enum, otherwise it will result in a protocol error. This request must be made once only, and can only be made on sources used in drag-and-drop, so it must be performed before wl_data_device.start_drag. Attempting to use the source other than for drag-and-drop will raise a protocol error.
13051243 func (o *DataSource) SetActions(dndActions uint32) error {
1306- if err := o.Context().CheckProxy(o); err != nil {
1307- return err
1308- }
1309- if err := o.Context().SendRequest(o, 2, dndActions); err != nil {
1244+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_data_source.set_actions", Since: 3}, dndActions); err != nil {
13101245 return err
13111246 }
13121247 return nil
@@ -1542,9 +1477,6 @@ func NewDataDevice(ctx *wl.Context) *DataDevice {
15421477
15431478 // This request asks the compositor to start a drag-and-drop operation on behalf of the client. The source argument is the data source that provides the data for the eventual data transfer. If source is NULL, enter, leave and motion events are sent only to the client that initiated the drag and the client is expected to handle the data passing internally. If source is destroyed, the drag-and-drop session will be cancelled. The origin surface is the surface where the drag originates and the client must have an active implicit grab that matches the serial. The icon surface is an optional (can be NULL) surface that provides an icon to be moved around with the cursor. Initially, the top-left corner of the icon surface is placed at the cursor hotspot, but subsequent wl_surface.offset requests can move the relative position. Attach requests must be confirmed with wl_surface.commit as usual. The icon surface is given the role of a drag-and-drop icon. If the icon surface already has another role, it raises a protocol error. The input region is ignored for wl_surfaces with the role of a drag-and-drop icon. The given source may not be used in any further set_selection or start_drag requests. Attempting to reuse a previously-used source may send a used_source error.
15441479 func (o *DataDevice) StartDrag(source *DataSource, origin *Surface, icon *Surface, serial uint32) error {
1545- if err := o.Context().CheckProxy(o); err != nil {
1546- return err
1547- }
15481480 var arg0 wl.Object
15491481 if source != nil {
15501482 arg0 = source
@@ -1557,7 +1489,7 @@ func (o *DataDevice) StartDrag(source *DataSource, origin *Surface, icon *Surfac
15571489 if icon != nil {
15581490 arg2 = icon
15591491 }
1560- if err := o.Context().SendRequest(o, 0, arg0, arg1, arg2, serial); err != nil {
1492+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_data_device.start_drag"}, arg0, arg1, arg2, serial); err != nil {
15611493 return err
15621494 }
15631495 return nil
@@ -1565,14 +1497,11 @@ func (o *DataDevice) StartDrag(source *DataSource, origin *Surface, icon *Surfac
15651497
15661498 // This request asks the compositor to set the selection to the data from the source on behalf of the client. To unset the selection, set the source to NULL. The given source may not be used in any further set_selection or start_drag requests. Attempting to reuse a previously-used source may send a used_source error.
15671499 func (o *DataDevice) SetSelection(source *DataSource, serial uint32) error {
1568- if err := o.Context().CheckProxy(o); err != nil {
1569- return err
1570- }
15711500 var arg0 wl.Object
15721501 if source != nil {
15731502 arg0 = source
15741503 }
1575- if err := o.Context().SendRequest(o, 1, arg0, serial); err != nil {
1504+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_data_device.set_selection"}, arg0, serial); err != nil {
15761505 return err
15771506 }
15781507 return nil
@@ -1580,10 +1509,7 @@ func (o *DataDevice) SetSelection(source *DataSource, serial uint32) error {
15801509
15811510 // This request destroys the data device.
15821511 func (o *DataDevice) Release() error {
1583- if err := o.Context().CheckProxy(o); err != nil {
1584- return err
1585- }
1586- if err := o.Context().SendDestructor(o, 2); err != nil {
1512+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_data_device.release", Since: 2, Destructor: true}); err != nil {
15871513 return err
15881514 }
15891515 return nil
@@ -1749,6 +1675,7 @@ func (o *DataDevice) Dispatch(event *wl.Event) {
17491675 idObject := &DataOffer{}
17501676 idObject.SetContext(o.Context())
17511677 idObject.SetID(idID)
1678+ idObject.SetVersion(o.Version())
17521679 o.Context().Register(idObject)
17531680
17541681 for i, handler := range o.handlersForDataOffer() {
@@ -1816,15 +1743,9 @@ func NewDataDeviceManager(ctx *wl.Context) *DataDeviceManager {
18161743
18171744 // Create a new data source.
18181745 func (o *DataDeviceManager) CreateDataSource() (*DataSource, error) {
1819- if err := o.Context().CheckProxy(o); err != nil {
1820- return nil, err
1821- }
18221746 child := &DataSource{}
18231747 child.SetContext(o.Context())
1824- child.SetID(o.Context().AllocateID())
1825- o.Context().Register(child)
1826- if err := o.Context().SendRequest(o, 0, child); err != nil {
1827- o.Context().Unregister(child)
1748+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_data_device_manager.create_data_source", Child: child}, child); err != nil {
18281749 return nil, err
18291750 }
18301751 return child, nil
@@ -1832,19 +1753,13 @@ func (o *DataDeviceManager) CreateDataSource() (*DataSource, error) {
18321753
18331754 // Create a new data device for a given seat.
18341755 func (o *DataDeviceManager) GetDataDevice(seat *Seat) (*DataDevice, error) {
1835- if err := o.Context().CheckProxy(o); err != nil {
1836- return nil, err
1837- }
18381756 var arg1 wl.Object
18391757 if seat != nil {
18401758 arg1 = seat
18411759 }
18421760 child := &DataDevice{}
18431761 child.SetContext(o.Context())
1844- child.SetID(o.Context().AllocateID())
1845- o.Context().Register(child)
1846- if err := o.Context().SendRequest(o, 1, child, arg1); err != nil {
1847- o.Context().Unregister(child)
1762+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_data_device_manager.get_data_device", Child: child}, child, arg1); err != nil {
18481763 return nil, err
18491764 }
18501765 return child, nil
@@ -1852,10 +1767,7 @@ func (o *DataDeviceManager) GetDataDevice(seat *Seat) (*DataDevice, error) {
18521767
18531768 // This request destroys the wl_data_device_manager. This has no effect on any other objects.
18541769 func (o *DataDeviceManager) Release() error {
1855- if err := o.Context().CheckProxy(o); err != nil {
1856- return err
1857- }
1858- if err := o.Context().SendDestructor(o, 2); err != nil {
1770+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_data_device_manager.release", Since: 4, Destructor: true}); err != nil {
18591771 return err
18601772 }
18611773 return nil
@@ -1894,19 +1806,13 @@ func NewShell(ctx *wl.Context) *Shell {
18941806
18951807 // Create a shell surface for an existing surface. This gives the wl_surface the role of a shell surface. If the wl_surface already has another role, it raises a protocol error. Only one shell surface can be associated with a given surface.
18961808 func (o *Shell) GetShellSurface(surface *Surface) (*ShellSurface, error) {
1897- if err := o.Context().CheckProxy(o); err != nil {
1898- return nil, err
1899- }
19001809 var arg1 wl.Object
19011810 if surface != nil {
19021811 arg1 = surface
19031812 }
19041813 child := &ShellSurface{}
19051814 child.SetContext(o.Context())
1906- child.SetID(o.Context().AllocateID())
1907- o.Context().Register(child)
1908- if err := o.Context().SendRequest(o, 0, child, arg1); err != nil {
1909- o.Context().Unregister(child)
1815+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_shell.get_shell_surface", Child: child}, child, arg1); err != nil {
19101816 return nil, err
19111817 }
19121818 return child, nil
@@ -1951,10 +1857,7 @@ func NewShellSurface(ctx *wl.Context) *ShellSurface {
19511857
19521858 // A client must respond to a ping event with a pong request or the client may be deemed unresponsive.
19531859 func (o *ShellSurface) Pong(serial uint32) error {
1954- if err := o.Context().CheckProxy(o); err != nil {
1955- return err
1956- }
1957- if err := o.Context().SendRequest(o, 0, serial); err != nil {
1860+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_shell_surface.pong"}, serial); err != nil {
19581861 return err
19591862 }
19601863 return nil
@@ -1962,14 +1865,11 @@ func (o *ShellSurface) Pong(serial uint32) error {
19621865
19631866 // Start a pointer-driven move of the surface. This request must be used in response to a button press event. The server may ignore move requests depending on the state of the surface (e.g. fullscreen or maximized).
19641867 func (o *ShellSurface) Move(seat *Seat, serial uint32) error {
1965- if err := o.Context().CheckProxy(o); err != nil {
1966- return err
1967- }
19681868 var arg0 wl.Object
19691869 if seat != nil {
19701870 arg0 = seat
19711871 }
1972- if err := o.Context().SendRequest(o, 1, arg0, serial); err != nil {
1872+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_shell_surface.move"}, arg0, serial); err != nil {
19731873 return err
19741874 }
19751875 return nil
@@ -1977,14 +1877,11 @@ func (o *ShellSurface) Move(seat *Seat, serial uint32) error {
19771877
19781878 // Start a pointer-driven resizing of the surface. This request must be used in response to a button press event. The server may ignore resize requests depending on the state of the surface (e.g. fullscreen or maximized).
19791879 func (o *ShellSurface) Resize(seat *Seat, serial uint32, edges uint32) error {
1980- if err := o.Context().CheckProxy(o); err != nil {
1981- return err
1982- }
19831880 var arg0 wl.Object
19841881 if seat != nil {
19851882 arg0 = seat
19861883 }
1987- if err := o.Context().SendRequest(o, 2, arg0, serial, edges); err != nil {
1884+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_shell_surface.resize"}, arg0, serial, edges); err != nil {
19881885 return err
19891886 }
19901887 return nil
@@ -1992,10 +1889,7 @@ func (o *ShellSurface) Resize(seat *Seat, serial uint32, edges uint32) error {
19921889
19931890 // Map the surface as a toplevel surface. A toplevel surface is not fullscreen, maximized or transient.
19941891 func (o *ShellSurface) SetToplevel() error {
1995- if err := o.Context().CheckProxy(o); err != nil {
1996- return err
1997- }
1998- if err := o.Context().SendRequest(o, 3); err != nil {
1892+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "wl_shell_surface.set_toplevel"}); err != nil {
19991893 return err
20001894 }
20011895 return nil
@@ -2003,14 +1897,11 @@ func (o *ShellSurface) SetToplevel() error {
20031897
20041898 // Map the surface relative to an existing surface. The x and y arguments specify the location of the upper left corner of the surface relative to the upper left corner of the parent surface, in surface-local coordinates. The flags argument controls details of the transient behaviour.
20051899 func (o *ShellSurface) SetTransient(parent *Surface, x int32, y int32, flags uint32) error {
2006- if err := o.Context().CheckProxy(o); err != nil {
2007- return err
2008- }
20091900 var arg0 wl.Object
20101901 if parent != nil {
20111902 arg0 = parent
20121903 }
2013- if err := o.Context().SendRequest(o, 4, arg0, x, y, flags); err != nil {
1904+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "wl_shell_surface.set_transient"}, arg0, x, y, flags); err != nil {
20141905 return err
20151906 }
20161907 return nil
@@ -2018,14 +1909,11 @@ func (o *ShellSurface) SetTransient(parent *Surface, x int32, y int32, flags uin
20181909
20191910 // Map the surface as a fullscreen surface. If an output parameter is given then the surface will be made fullscreen on that output. If the client does not specify the output then the compositor will apply its policy - usually choosing the output on which the surface has the biggest surface area. The client may specify a method to resolve a size conflict between the output size and the surface size - this is provided through the method parameter. The framerate parameter is used only when the method is set to "driver", to indicate the preferred framerate. A value of 0 indicates that the client does not care about framerate. The framerate is specified in mHz, that is framerate of 60000 is 60Hz. A method of "scale" or "driver" implies a scaling operation of the surface, either via a direct scaling operation or a change of the output mode. This will override any kind of output scaling, so that mapping a surface with a buffer size equal to the mode can fill the screen independent of buffer_scale. A method of "fill" means we don't scale up the buffer, however any output scale is applied. This means that you may run into an edge case where the application maps a buffer with the same size of the output mode but buffer_scale 1 (thus making a surface larger than the output). In this case it is allowed to downscale the results to fit the screen. The compositor must reply to this request with a configure event with the dimensions for the output on which the surface will be made fullscreen.
20201911 func (o *ShellSurface) SetFullscreen(method uint32, framerate uint32, output *Output) error {
2021- if err := o.Context().CheckProxy(o); err != nil {
2022- return err
2023- }
20241912 var arg2 wl.Object
20251913 if output != nil {
20261914 arg2 = output
20271915 }
2028- if err := o.Context().SendRequest(o, 5, method, framerate, arg2); err != nil {
1916+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 5, Name: "wl_shell_surface.set_fullscreen"}, method, framerate, arg2); err != nil {
20291917 return err
20301918 }
20311919 return nil
@@ -2033,9 +1921,6 @@ func (o *ShellSurface) SetFullscreen(method uint32, framerate uint32, output *Ou
20331921
20341922 // Map the surface as a popup. A popup surface is a transient surface with an added pointer grab. An existing implicit grab will be changed to owner-events mode, and the popup grab will continue after the implicit grab ends (i.e. releasing the mouse button does not cause the popup to be unmapped). The popup grab continues until the window is destroyed or a mouse button is pressed in any other client's window. A click in any of the client's surfaces is reported as normal, however, clicks in other clients' surfaces will be discarded and trigger the callback. The x and y arguments specify the location of the upper left corner of the surface relative to the upper left corner of the parent surface, in surface-local coordinates.
20351923 func (o *ShellSurface) SetPopup(seat *Seat, serial uint32, parent *Surface, x int32, y int32, flags uint32) error {
2036- if err := o.Context().CheckProxy(o); err != nil {
2037- return err
2038- }
20391924 var arg0 wl.Object
20401925 if seat != nil {
20411926 arg0 = seat
@@ -2044,7 +1929,7 @@ func (o *ShellSurface) SetPopup(seat *Seat, serial uint32, parent *Surface, x in
20441929 if parent != nil {
20451930 arg2 = parent
20461931 }
2047- if err := o.Context().SendRequest(o, 6, arg0, serial, arg2, x, y, flags); err != nil {
1932+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 6, Name: "wl_shell_surface.set_popup"}, arg0, serial, arg2, x, y, flags); err != nil {
20481933 return err
20491934 }
20501935 return nil
@@ -2052,14 +1937,11 @@ func (o *ShellSurface) SetPopup(seat *Seat, serial uint32, parent *Surface, x in
20521937
20531938 // Map the surface as a maximized surface. If an output parameter is given then the surface will be maximized on that output. If the client does not specify the output then the compositor will apply its policy - usually choosing the output on which the surface has the biggest surface area. The compositor will reply with a configure event telling the expected new surface size. The operation is completed on the next buffer attach to this surface. A maximized surface typically fills the entire output it is bound to, except for desktop elements such as panels. This is the main difference between a maximized shell surface and a fullscreen shell surface. The details depend on the compositor implementation.
20541939 func (o *ShellSurface) SetMaximized(output *Output) error {
2055- if err := o.Context().CheckProxy(o); err != nil {
2056- return err
2057- }
20581940 var arg0 wl.Object
20591941 if output != nil {
20601942 arg0 = output
20611943 }
2062- if err := o.Context().SendRequest(o, 7, arg0); err != nil {
1944+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 7, Name: "wl_shell_surface.set_maximized"}, arg0); err != nil {
20631945 return err
20641946 }
20651947 return nil
@@ -2067,10 +1949,7 @@ func (o *ShellSurface) SetMaximized(output *Output) error {
20671949
20681950 // 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.
20691951 func (o *ShellSurface) SetTitle(title string) error {
2070- if err := o.Context().CheckProxy(o); err != nil {
2071- return err
2072- }
2073- if err := o.Context().SendRequest(o, 8, title); err != nil {
1952+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 8, Name: "wl_shell_surface.set_title"}, title); err != nil {
20741953 return err
20751954 }
20761955 return nil
@@ -2078,10 +1957,7 @@ func (o *ShellSurface) SetTitle(title string) error {
20781957
20791958 // Set a class for the surface. The surface class identifies the general class of applications to which the surface belongs. A common convention is to use the file name (or the full path if it is a non-standard location) of the application's .desktop file as the class.
20801959 func (o *ShellSurface) SetClass(class string) error {
2081- if err := o.Context().CheckProxy(o); err != nil {
2082- return err
2083- }
2084- if err := o.Context().SendRequest(o, 9, class); err != nil {
1960+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 9, Name: "wl_shell_surface.set_class"}, class); err != nil {
20851961 return err
20861962 }
20871963 return nil
@@ -2221,10 +2097,7 @@ func NewSurface(ctx *wl.Context) *Surface {
22212097
22222098 // Deletes the surface and invalidates its object ID.
22232099 func (o *Surface) Destroy() error {
2224- if err := o.Context().CheckProxy(o); err != nil {
2225- return err
2226- }
2227- if err := o.Context().SendDestructor(o, 0); err != nil {
2100+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_surface.destroy", Destructor: true}); err != nil {
22282101 return err
22292102 }
22302103 return nil
@@ -2232,14 +2105,11 @@ func (o *Surface) Destroy() error {
22322105
22332106 // Set a buffer as the content of this surface. The new size of the surface is calculated based on the buffer size transformed by the inverse buffer_transform and the inverse buffer_scale. This means that at commit time the supplied buffer size must be an integer multiple of the buffer_scale. If that's not the case, an invalid_size error is sent. The x and y arguments specify the location of the new pending buffer's upper left corner, relative to the current buffer's upper left corner, in surface-local coordinates. In other words, the x and y, combined with the new surface size define in which directions the surface's size changes. Setting anything other than 0 as x and y arguments is discouraged, and should instead be replaced with using the separate wl_surface.offset request. When the bound wl_surface version is 5 or higher, passing any non-zero x or y is a protocol violation, and will result in an 'invalid_offset' error being raised. The x and y arguments are ignored and do not change the pending state. To achieve equivalent semantics, use wl_surface.offset. Surface contents are double-buffered state, see wl_surface.commit. The initial surface contents are void; there is no content. wl_surface.attach assigns the given wl_buffer as the pending wl_buffer. wl_surface.commit makes the pending wl_buffer the new surface contents, and the size of the surface becomes the size calculated from the wl_buffer, as described above. After commit, there is no pending buffer until the next attach. Committing a pending wl_buffer allows the compositor to read the pixels in the wl_buffer. The compositor may access the pixels at any time after the wl_surface.commit request. When the compositor will not access the pixels anymore, it will send the wl_buffer.release event. Only after receiving wl_buffer.release, the client may reuse the wl_buffer. A wl_buffer that has been attached and then replaced by another attach instead of committed will not receive a release event, and is not used by the compositor. If a pending wl_buffer has been committed to more than one wl_surface, the delivery of wl_buffer.release events becomes undefined. A well behaved client should not rely on wl_buffer.release events in this case. Instead, clients hitting this case should use wl_surface.get_release or use a protocol extension providing per-commit release notifications (if none of these options are available, a fallback can be implemented by creating multiple wl_buffer objects from the same backing storage). Destroying the wl_buffer after wl_buffer.release does not change the surface contents. Destroying the wl_buffer before wl_buffer.release is allowed as long as the underlying buffer storage isn't re-used (this can happen e.g. on client process termination). However, if the client destroys the wl_buffer before receiving the wl_buffer.release event and mutates the underlying buffer storage, the surface contents become undefined immediately. If wl_surface.attach is sent with a NULL wl_buffer, the following wl_surface.commit will remove the surface content. If a pending wl_buffer has been destroyed, the result is not specified. Many compositors are known to remove the surface content on the following wl_surface.commit, but this behaviour is not universal. Clients seeking to maximise compatibility should not destroy pending buffers and should ensure that they explicitly remove content from surfaces, even after destroying buffers.
22342107 func (o *Surface) Attach(buffer *Buffer, x int32, y int32) error {
2235- if err := o.Context().CheckProxy(o); err != nil {
2236- return err
2237- }
22382108 var arg0 wl.Object
22392109 if buffer != nil {
22402110 arg0 = buffer
22412111 }
2242- if err := o.Context().SendRequest(o, 1, arg0, x, y); err != nil {
2112+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_surface.attach"}, arg0, x, y); err != nil {
22432113 return err
22442114 }
22452115 return nil
@@ -2247,10 +2117,7 @@ func (o *Surface) Attach(buffer *Buffer, x int32, y int32) error {
22472117
22482118 // This request is used to describe the regions where the pending buffer is different from the current surface contents, and where the surface therefore needs to be repainted. The compositor ignores the parts of the damage that fall outside of the surface. Damage is double-buffered state, see wl_surface.commit. The damage rectangle is specified in surface-local coordinates, where x and y specify the upper left corner of the damage rectangle. The initial value for pending damage is empty: no damage. wl_surface.damage adds pending damage: the new pending damage is the union of old pending damage and the given rectangle. wl_surface.commit assigns pending damage as the current damage, and clears pending damage. The server will clear the current damage as it repaints the surface. Note! New clients should not use this request. Instead damage can be posted with wl_surface.damage_buffer which uses buffer coordinates instead of surface coordinates.
22492119 func (o *Surface) Damage(x int32, y int32, width int32, height int32) error {
2250- if err := o.Context().CheckProxy(o); err != nil {
2251- return err
2252- }
2253- if err := o.Context().SendRequest(o, 2, x, y, width, height); err != nil {
2120+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_surface.damage"}, x, y, width, height); err != nil {
22542121 return err
22552122 }
22562123 return nil
@@ -2258,15 +2125,9 @@ func (o *Surface) Damage(x int32, y int32, width int32, height int32) error {
22582125
22592126 // Request a notification when it is a good time to start drawing a new frame, by creating a frame callback. This is useful for throttling redrawing operations, and driving animations. When a client is animating on a wl_surface, it can use the 'frame' request to get notified when it is a good time to draw and commit the next frame of animation. If the client commits an update earlier than that, it is likely that some updates will not make it to the display, and the client is wasting resources by drawing too often. The frame request will take effect on the next wl_surface.commit. The notification will only be posted for one frame unless requested again. For a wl_surface, the notifications are posted in the order the frame requests were committed. The server must send the notifications so that a client will not send excessive updates, while still allowing the highest possible update rate for clients that wait for the reply before drawing again. The server should give some time for the client to draw and commit after sending the frame callback events to let it hit the next output refresh. A server should avoid signaling the frame callbacks if the surface is not visible in any way, e.g. the surface is off-screen, or completely obscured by other opaque surfaces. The object returned by this request will be destroyed by the compositor after the callback is fired and as such the client must not attempt to use it after that point. The callback_data passed in the callback is the current time, in milliseconds, with an undefined base.
22602127 func (o *Surface) Frame() (*Callback, error) {
2261- if err := o.Context().CheckProxy(o); err != nil {
2262- return nil, err
2263- }
22642128 child := &Callback{}
22652129 child.SetContext(o.Context())
2266- child.SetID(o.Context().AllocateID())
2267- o.Context().Register(child)
2268- if err := o.Context().SendRequest(o, 3, child); err != nil {
2269- o.Context().Unregister(child)
2130+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "wl_surface.frame", Child: child}, child); err != nil {
22702131 return nil, err
22712132 }
22722133 return child, nil
@@ -2274,14 +2135,11 @@ func (o *Surface) Frame() (*Callback, error) {
22742135
22752136 // This request sets the region of the surface that contains opaque content. The opaque region is an optimization hint for the compositor that lets it optimize the redrawing of content behind opaque regions. Setting an opaque region is not required for correct behaviour, but marking transparent content as opaque will result in repaint artifacts. The opaque region is specified in surface-local coordinates. The compositor ignores the parts of the opaque region that fall outside of the surface. Opaque region is double-buffered state, see wl_surface.commit. wl_surface.set_opaque_region changes the pending opaque region. wl_surface.commit copies the pending region to the current region. Otherwise, the pending and current regions are never changed. The initial value for an opaque region is empty. Setting the pending opaque region has copy semantics, and the wl_region object can be destroyed immediately. A NULL wl_region causes the pending opaque region to be set to empty.
22762137 func (o *Surface) SetOpaqueRegion(region *Region) error {
2277- if err := o.Context().CheckProxy(o); err != nil {
2278- return err
2279- }
22802138 var arg0 wl.Object
22812139 if region != nil {
22822140 arg0 = region
22832141 }
2284- if err := o.Context().SendRequest(o, 4, arg0); err != nil {
2142+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "wl_surface.set_opaque_region"}, arg0); err != nil {
22852143 return err
22862144 }
22872145 return nil
@@ -2289,14 +2147,11 @@ func (o *Surface) SetOpaqueRegion(region *Region) error {
22892147
22902148 // This request sets the region of the surface that can receive pointer and touch events. Input events happening outside of this region will try the next surface in the server surface stack. The compositor ignores the parts of the input region that fall outside of the surface. The input region is specified in surface-local coordinates. Input region is double-buffered state, see wl_surface.commit. wl_surface.set_input_region changes the pending input region. wl_surface.commit copies the pending region to the current region. Otherwise the pending and current regions are never changed, except cursor and icon surfaces are special cases, see wl_pointer.set_cursor and wl_data_device.start_drag. The initial value for an input region is infinite. That means the whole surface will accept input. Setting the pending input region has copy semantics, and the wl_region object can be destroyed immediately. A NULL wl_region causes the input region to be set to infinite.
22912149 func (o *Surface) SetInputRegion(region *Region) error {
2292- if err := o.Context().CheckProxy(o); err != nil {
2293- return err
2294- }
22952150 var arg0 wl.Object
22962151 if region != nil {
22972152 arg0 = region
22982153 }
2299- if err := o.Context().SendRequest(o, 5, arg0); err != nil {
2154+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 5, Name: "wl_surface.set_input_region"}, arg0); err != nil {
23002155 return err
23012156 }
23022157 return nil
@@ -2304,10 +2159,7 @@ func (o *Surface) SetInputRegion(region *Region) error {
23042159
23052160 // Surface state (input, opaque, and damage regions, attached buffers, etc.) is double-buffered. Protocol requests modify the pending state, as opposed to the active state in use by the compositor. All requests that need a commit to become effective are documented to affect double-buffered state. Other interfaces may add further double-buffered surface state. A commit request atomically creates a Content Update (CU) from the pending state, even if the pending state has not been touched. The content update is placed at the end of a per-surface queue until it becomes active. After commit, the new pending state is as documented for each related request. A CU is either a Desync Content Update (DCU) or a Sync Content Update (SCU). If the surface is effectively synchronized at the commit request, it is a SCU, otherwise a DCU. When a surface transitions from effectively synchronized to effectively desynchronized, all SCUs in its queue which are not reachable by any DCU become DCUs and dependency edges from outside the queue to these CUs are removed. See wl_subsurface for the definition of 'effectively synchronized' and 'effectively desynchronized'. When a CU is placed in the queue, the CU has a dependency on the CU in front of it and to the SCU at end of the queue of every direct child surface if that SCU exists and does not have another dependent. This can form a directed acyclic graph of CUs with dependencies as edges. In addition to surface state, the CU can have constraints that must be satisfied before it can be applied. Other interfaces may add CU constraints. All DCUs which do not have a SCU in front of themselves in their queue, are candidates. If the graph that's reachable by a candidate does not have any unsatisfied constraints, the entire graph must be applied atomically. When a CU is applied, the wl_buffer is applied before all other state. This means that all coordinates in double-buffered state are relative to the newly attached wl_buffers, except for wl_surface.attach itself. If there is no newly attached wl_buffer, the coordinates are relative to the previous content update.
23062161 func (o *Surface) Commit() error {
2307- if err := o.Context().CheckProxy(o); err != nil {
2308- return err
2309- }
2310- if err := o.Context().SendRequest(o, 6); err != nil {
2162+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 6, Name: "wl_surface.commit"}); err != nil {
23112163 return err
23122164 }
23132165 return nil
@@ -2315,10 +2167,7 @@ func (o *Surface) Commit() error {
23152167
23162168 // This request sets the transformation that the client has already applied to the content of the buffer. The accepted values for the transform parameter are the values for wl_output.transform. The compositor applies the inverse of this transformation whenever it uses the buffer contents. Buffer transform is double-buffered state, see wl_surface.commit. A newly created surface has its buffer transformation set to normal. wl_surface.set_buffer_transform changes the pending buffer transformation. wl_surface.commit copies the pending buffer transformation to the current one. Otherwise, the pending and current values are never changed. The purpose of this request is to allow clients to render content according to the output transform, thus permitting the compositor to use certain optimizations even if the display is rotated. Using hardware overlays and scanning out a client buffer for fullscreen surfaces are examples of such optimizations. Those optimizations are highly dependent on the compositor implementation, so the use of this request should be considered on a case-by-case basis. Note that if the transform value includes 90 or 270 degree rotation, the width of the buffer will become the surface height and the height of the buffer will become the surface width. If transform is not one of the values from the wl_output.transform enum the invalid_transform protocol error is raised.
23172169 func (o *Surface) SetBufferTransform(transform int32) error {
2318- if err := o.Context().CheckProxy(o); err != nil {
2319- return err
2320- }
2321- if err := o.Context().SendRequest(o, 7, transform); err != nil {
2170+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 7, Name: "wl_surface.set_buffer_transform", Since: 2}, transform); err != nil {
23222171 return err
23232172 }
23242173 return nil
@@ -2326,10 +2175,7 @@ func (o *Surface) SetBufferTransform(transform int32) error {
23262175
23272176 // This request sets an optional scaling factor on how the compositor interprets the contents of the buffer attached to the window. Buffer scale is double-buffered state, see wl_surface.commit. A newly created surface has its buffer scale set to 1. wl_surface.set_buffer_scale changes the pending buffer scale. wl_surface.commit copies the pending buffer scale to the current one. Otherwise, the pending and current values are never changed. The purpose of this request is to allow clients to supply higher resolution buffer data for use on high resolution outputs. It is intended that you pick the same buffer scale as the scale of the output that the surface is displayed on. This means the compositor can avoid scaling when rendering the surface on that output. Note that if the scale is larger than 1, then you have to attach a buffer that is larger (by a factor of scale in each dimension) than the desired surface size. If scale is not greater than 0 the invalid_scale protocol error is raised.
23282177 func (o *Surface) SetBufferScale(scale int32) error {
2329- if err := o.Context().CheckProxy(o); err != nil {
2330- return err
2331- }
2332- if err := o.Context().SendRequest(o, 8, scale); err != nil {
2178+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 8, Name: "wl_surface.set_buffer_scale", Since: 3}, scale); err != nil {
23332179 return err
23342180 }
23352181 return nil
@@ -2337,10 +2183,7 @@ func (o *Surface) SetBufferScale(scale int32) error {
23372183
23382184 // This request is used to describe the regions where the pending buffer is different from the current surface contents, and where the surface therefore needs to be repainted. The compositor ignores the parts of the damage that fall outside of the surface. Damage is double-buffered state, see wl_surface.commit. The damage rectangle is specified in buffer coordinates, where x and y specify the upper left corner of the damage rectangle. The initial value for pending damage is empty: no damage. wl_surface.damage_buffer adds pending damage: the new pending damage is the union of old pending damage and the given rectangle. wl_surface.commit assigns pending damage as the current damage, and clears pending damage. The server will clear the current damage as it repaints the surface. This request differs from wl_surface.damage in only one way - it takes damage in buffer coordinates instead of surface-local coordinates. While this generally is more intuitive than surface coordinates, it is especially desirable when using wp_viewport or when a drawing library (like EGL) is unaware of buffer scale and buffer transform. Note: Because buffer transformation changes and damage requests may be interleaved in the protocol stream, it is impossible to determine the actual mapping between surface and buffer damage until wl_surface.commit time. Therefore, compositors wishing to take both kinds of damage into account will have to accumulate damage from the two requests separately and only transform from one to the other after receiving the wl_surface.commit.
23392185 func (o *Surface) DamageBuffer(x int32, y int32, width int32, height int32) error {
2340- if err := o.Context().CheckProxy(o); err != nil {
2341- return err
2342- }
2343- if err := o.Context().SendRequest(o, 9, x, y, width, height); err != nil {
2186+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 9, Name: "wl_surface.damage_buffer", Since: 4}, x, y, width, height); err != nil {
23442187 return err
23452188 }
23462189 return nil
@@ -2348,10 +2191,7 @@ func (o *Surface) DamageBuffer(x int32, y int32, width int32, height int32) erro
23482191
23492192 // The x and y arguments specify the location of the new pending buffer's upper left corner, relative to the current buffer's upper left corner, in surface-local coordinates. In other words, the x and y, combined with the new surface size define in which directions the surface's size changes. The exact semantics of wl_surface.offset are role-specific. Refer to the documentation of specific roles for more information. Surface location offset is double-buffered state, see wl_surface.commit. This request is semantically equivalent to and the replaces the x and y arguments in the wl_surface.attach request in wl_surface versions prior to 5. See wl_surface.attach for details.
23502193 func (o *Surface) Offset(x int32, y int32) error {
2351- if err := o.Context().CheckProxy(o); err != nil {
2352- return err
2353- }
2354- if err := o.Context().SendRequest(o, 10, x, y); err != nil {
2194+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 10, Name: "wl_surface.offset", Since: 5}, x, y); err != nil {
23552195 return err
23562196 }
23572197 return nil
@@ -2359,15 +2199,9 @@ func (o *Surface) Offset(x int32, y int32) error {
23592199
23602200 // Create a callback for the release of the buffer attached by the client with wl_surface.attach. The compositor will release the buffer when it has finished its usage of the underlying storage for the relevant commit. Once the client receives this event, and assuming the associated buffer is not pending release from other wl_surface.commit requests, the client can safely re-use the buffer. Release callbacks are double-buffered state, and will be associated with the pending buffer at wl_surface.commit time. The callback_data passed in the wl_callback.done event is unused and is always zero. Sending this request without attaching a non-null buffer in the same content update is a protocol error. The compositor will send the no_buffer error in this case.
23612201 func (o *Surface) GetRelease() (*Callback, error) {
2362- if err := o.Context().CheckProxy(o); err != nil {
2363- return nil, err
2364- }
23652202 child := &Callback{}
23662203 child.SetContext(o.Context())
2367- child.SetID(o.Context().AllocateID())
2368- o.Context().Register(child)
2369- if err := o.Context().SendRequest(o, 11, child); err != nil {
2370- o.Context().Unregister(child)
2204+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 11, Name: "wl_surface.get_release", Since: 7, Child: child}, child); err != nil {
23712205 return nil, err
23722206 }
23732207 return child, nil
@@ -2535,15 +2369,9 @@ func NewSeat(ctx *wl.Context) *Seat {
25352369
25362370 // The ID provided will be initialized to the wl_pointer interface for this seat. This request only takes effect if the seat has the pointer capability, or has had the pointer capability in the past. It is a protocol violation to issue this request on a seat that has never had the pointer capability. The missing_capability error will be sent in this case.
25372371 func (o *Seat) GetPointer() (*Pointer, error) {
2538- if err := o.Context().CheckProxy(o); err != nil {
2539- return nil, err
2540- }
25412372 child := &Pointer{}
25422373 child.SetContext(o.Context())
2543- child.SetID(o.Context().AllocateID())
2544- o.Context().Register(child)
2545- if err := o.Context().SendRequest(o, 0, child); err != nil {
2546- o.Context().Unregister(child)
2374+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_seat.get_pointer", Child: child}, child); err != nil {
25472375 return nil, err
25482376 }
25492377 return child, nil
@@ -2551,15 +2379,9 @@ func (o *Seat) GetPointer() (*Pointer, error) {
25512379
25522380 // The ID provided will be initialized to the wl_keyboard interface for this seat. This request only takes effect if the seat has the keyboard capability, or has had the keyboard capability in the past. It is a protocol violation to issue this request on a seat that has never had the keyboard capability. The missing_capability error will be sent in this case.
25532381 func (o *Seat) GetKeyboard() (*Keyboard, error) {
2554- if err := o.Context().CheckProxy(o); err != nil {
2555- return nil, err
2556- }
25572382 child := &Keyboard{}
25582383 child.SetContext(o.Context())
2559- child.SetID(o.Context().AllocateID())
2560- o.Context().Register(child)
2561- if err := o.Context().SendRequest(o, 1, child); err != nil {
2562- o.Context().Unregister(child)
2384+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_seat.get_keyboard", Child: child}, child); err != nil {
25632385 return nil, err
25642386 }
25652387 return child, nil
@@ -2567,15 +2389,9 @@ func (o *Seat) GetKeyboard() (*Keyboard, error) {
25672389
25682390 // The ID provided will be initialized to the wl_touch interface for this seat. This request only takes effect if the seat has the touch capability, or has had the touch capability in the past. It is a protocol violation to issue this request on a seat that has never had the touch capability. The missing_capability error will be sent in this case.
25692391 func (o *Seat) GetTouch() (*Touch, error) {
2570- if err := o.Context().CheckProxy(o); err != nil {
2571- return nil, err
2572- }
25732392 child := &Touch{}
25742393 child.SetContext(o.Context())
2575- child.SetID(o.Context().AllocateID())
2576- o.Context().Register(child)
2577- if err := o.Context().SendRequest(o, 2, child); err != nil {
2578- o.Context().Unregister(child)
2394+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_seat.get_touch", Child: child}, child); err != nil {
25792395 return nil, err
25802396 }
25812397 return child, nil
@@ -2583,10 +2399,7 @@ func (o *Seat) GetTouch() (*Touch, error) {
25832399
25842400 // Using this request a client can tell the server that it is not going to use the seat object anymore.
25852401 func (o *Seat) Release() error {
2586- if err := o.Context().CheckProxy(o); err != nil {
2587- return err
2588- }
2589- if err := o.Context().SendDestructor(o, 3); err != nil {
2402+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "wl_seat.release", Since: 5, Destructor: true}); err != nil {
25902403 return err
25912404 }
25922405 return nil
@@ -2702,14 +2515,11 @@ func NewPointer(ctx *wl.Context) *Pointer {
27022515
27032516 // Set the pointer surface, i.e., the surface that contains the pointer image (cursor). This request gives the surface the role of a cursor. If the surface already has another role, it raises a protocol error. The cursor actually changes only if the pointer focus for this device is one of the requesting client's surfaces or the surface parameter is the current pointer surface. If there was a previous surface set with this request it is replaced. If surface is NULL, the pointer image is hidden. The parameters hotspot_x and hotspot_y define the position of the pointer surface relative to the pointer location. Its top-left corner is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the coordinates of the pointer location, in surface-local coordinates. On wl_surface.offset requests to the pointer surface, hotspot_x and hotspot_y are decremented by the x and y parameters passed to the request. The offset must be applied by wl_surface.commit as usual. The hotspot can also be updated by passing the currently set pointer surface to this request with new values for hotspot_x and hotspot_y. The input region is ignored for wl_surfaces with the role of a cursor. When the use as a cursor ends, the wl_surface is unmapped. The serial parameter must match the latest wl_pointer.enter serial number sent to the client. Otherwise the request will be ignored.
27042517 func (o *Pointer) SetCursor(serial uint32, surface *Surface, hotspotX int32, hotspotY int32) error {
2705- if err := o.Context().CheckProxy(o); err != nil {
2706- return err
2707- }
27082518 var arg1 wl.Object
27092519 if surface != nil {
27102520 arg1 = surface
27112521 }
2712- if err := o.Context().SendRequest(o, 0, serial, arg1, hotspotX, hotspotY); err != nil {
2522+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_pointer.set_cursor"}, serial, arg1, hotspotX, hotspotY); err != nil {
27132523 return err
27142524 }
27152525 return nil
@@ -2717,10 +2527,7 @@ func (o *Pointer) SetCursor(serial uint32, surface *Surface, hotspotX int32, hot
27172527
27182528 // Using this request a client can tell the server that it is not going to use the pointer object anymore. This request destroys the pointer proxy object, so clients must not call wl_pointer_destroy() after using this request.
27192529 func (o *Pointer) Release() error {
2720- if err := o.Context().CheckProxy(o); err != nil {
2721- return err
2722- }
2723- if err := o.Context().SendDestructor(o, 1); err != nil {
2530+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_pointer.release", Since: 3, Destructor: true}); err != nil {
27242531 return err
27252532 }
27262533 return nil
@@ -3155,10 +2962,7 @@ func NewKeyboard(ctx *wl.Context) *Keyboard {
31552962
31562963 // release the keyboard object
31572964 func (o *Keyboard) Release() error {
3158- if err := o.Context().CheckProxy(o); err != nil {
3159- return err
3160- }
3161- if err := o.Context().SendDestructor(o, 0); err != nil {
2965+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_keyboard.release", Since: 3, Destructor: true}); err != nil {
31622966 return err
31632967 }
31642968 return nil
@@ -3410,10 +3214,7 @@ func NewTouch(ctx *wl.Context) *Touch {
34103214
34113215 // release the touch object
34123216 func (o *Touch) Release() error {
3413- if err := o.Context().CheckProxy(o); err != nil {
3414- return err
3415- }
3416- if err := o.Context().SendDestructor(o, 0); err != nil {
3217+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_touch.release", Since: 3, Destructor: true}); err != nil {
34173218 return err
34183219 }
34193220 return nil
@@ -3689,10 +3490,7 @@ func NewOutput(ctx *wl.Context) *Output {
36893490
36903491 // Using this request a client can tell the server that it is not going to use the output object anymore.
36913492 func (o *Output) Release() error {
3692- if err := o.Context().CheckProxy(o); err != nil {
3693- return err
3694- }
3695- if err := o.Context().SendDestructor(o, 0); err != nil {
3493+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_output.release", Since: 3, Destructor: true}); err != nil {
36963494 return err
36973495 }
36983496 return nil
@@ -3926,10 +3724,7 @@ func NewRegion(ctx *wl.Context) *Region {
39263724
39273725 // Destroy the region. This will invalidate the object ID.
39283726 func (o *Region) Destroy() error {
3929- if err := o.Context().CheckProxy(o); err != nil {
3930- return err
3931- }
3932- if err := o.Context().SendDestructor(o, 0); err != nil {
3727+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_region.destroy", Destructor: true}); err != nil {
39333728 return err
39343729 }
39353730 return nil
@@ -3937,10 +3732,7 @@ func (o *Region) Destroy() error {
39373732
39383733 // Add the specified rectangle to the region.
39393734 func (o *Region) Add(x int32, y int32, width int32, height int32) error {
3940- if err := o.Context().CheckProxy(o); err != nil {
3941- return err
3942- }
3943- if err := o.Context().SendRequest(o, 1, x, y, width, height); err != nil {
3735+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_region.add"}, x, y, width, height); err != nil {
39443736 return err
39453737 }
39463738 return nil
@@ -3948,10 +3740,7 @@ func (o *Region) Add(x int32, y int32, width int32, height int32) error {
39483740
39493741 // Subtract the specified rectangle from the region.
39503742 func (o *Region) Subtract(x int32, y int32, width int32, height int32) error {
3951- if err := o.Context().CheckProxy(o); err != nil {
3952- return err
3953- }
3954- if err := o.Context().SendRequest(o, 2, x, y, width, height); err != nil {
3743+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_region.subtract"}, x, y, width, height); err != nil {
39553744 return err
39563745 }
39573746 return nil
@@ -3990,10 +3779,7 @@ func NewSubcompositor(ctx *wl.Context) *Subcompositor {
39903779
39913780 // Informs the server that the client will not be using this protocol object anymore. This does not affect any other objects, wl_subsurface objects included.
39923781 func (o *Subcompositor) Destroy() error {
3993- if err := o.Context().CheckProxy(o); err != nil {
3994- return err
3995- }
3996- if err := o.Context().SendDestructor(o, 0); err != nil {
3782+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_subcompositor.destroy", Destructor: true}); err != nil {
39973783 return err
39983784 }
39993785 return nil
@@ -4001,9 +3787,6 @@ func (o *Subcompositor) Destroy() error {
40013787
40023788 // Create a sub-surface interface for the given surface, and associate it with the given parent surface. This turns a plain wl_surface into a sub-surface. The to-be sub-surface must not already have another role, and it must not have an existing wl_subsurface object. Otherwise the bad_surface protocol error is raised. Adding sub-surfaces to a parent is a double-buffered operation on the parent (see wl_surface.commit). The effect of adding a sub-surface becomes visible on the next time the state of the parent surface is applied. The parent surface must not be one of the child surface's descendants, and the parent must be different from the child surface, otherwise the bad_parent protocol error is raised. This request modifies the behaviour of wl_surface.commit request on the sub-surface, see the documentation on wl_subsurface interface.
40033789 func (o *Subcompositor) GetSubsurface(surface *Surface, parent *Surface) (*Subsurface, error) {
4004- if err := o.Context().CheckProxy(o); err != nil {
4005- return nil, err
4006- }
40073790 var arg1 wl.Object
40083791 if surface != nil {
40093792 arg1 = surface
@@ -4014,10 +3797,7 @@ func (o *Subcompositor) GetSubsurface(surface *Surface, parent *Surface) (*Subsu
40143797 }
40153798 child := &Subsurface{}
40163799 child.SetContext(o.Context())
4017- child.SetID(o.Context().AllocateID())
4018- o.Context().Register(child)
4019- if err := o.Context().SendRequest(o, 1, child, arg1, arg2); err != nil {
4020- o.Context().Unregister(child)
3800+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_subcompositor.get_subsurface", Child: child}, child, arg1, arg2); err != nil {
40213801 return nil, err
40223802 }
40233803 return child, nil
@@ -4056,10 +3836,7 @@ func NewSubsurface(ctx *wl.Context) *Subsurface {
40563836
40573837 // The sub-surface interface is removed from the wl_surface object that was turned into a sub-surface with a wl_subcompositor.get_subsurface request. The wl_surface's association to the parent is deleted. The wl_surface is unmapped immediately.
40583838 func (o *Subsurface) Destroy() error {
4059- if err := o.Context().CheckProxy(o); err != nil {
4060- return err
4061- }
4062- if err := o.Context().SendDestructor(o, 0); err != nil {
3839+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_subsurface.destroy", Destructor: true}); err != nil {
40633840 return err
40643841 }
40653842 return nil
@@ -4067,10 +3844,7 @@ func (o *Subsurface) Destroy() error {
40673844
40683845 // This sets the position of the sub-surface, relative to the parent surface. The sub-surface will be moved so that its origin (top left corner pixel) will be at the location x, y of the parent surface coordinate system. The coordinates are not restricted to the parent surface area. Negative values are allowed. The initial position is 0, 0. Position is double-buffered state on the parent surface, see wl_subsurface and wl_surface.commit for more information.
40693846 func (o *Subsurface) SetPosition(x int32, y int32) error {
4070- if err := o.Context().CheckProxy(o); err != nil {
4071- return err
4072- }
4073- if err := o.Context().SendRequest(o, 1, x, y); err != nil {
3847+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_subsurface.set_position"}, x, y); err != nil {
40743848 return err
40753849 }
40763850 return nil
@@ -4078,14 +3852,11 @@ func (o *Subsurface) SetPosition(x int32, y int32) error {
40783852
40793853 // This sub-surface is taken from the stack, and put back just above the reference surface, changing the z-order of the sub-surfaces. The reference surface must be one of the sibling surfaces, or the parent surface. Using any other surface, including this sub-surface, will cause a protocol error. A new sub-surface is initially added as the top-most in the stack of its siblings and parent. Z-order is double-buffered state on the parent surface, see wl_subsurface and wl_surface.commit for more information.
40803854 func (o *Subsurface) PlaceAbove(sibling *Surface) error {
4081- if err := o.Context().CheckProxy(o); err != nil {
4082- return err
4083- }
40843855 var arg0 wl.Object
40853856 if sibling != nil {
40863857 arg0 = sibling
40873858 }
4088- if err := o.Context().SendRequest(o, 2, arg0); err != nil {
3859+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_subsurface.place_above"}, arg0); err != nil {
40893860 return err
40903861 }
40913862 return nil
@@ -4093,14 +3864,11 @@ func (o *Subsurface) PlaceAbove(sibling *Surface) error {
40933864
40943865 // The sub-surface is placed just below the reference surface. See wl_subsurface.place_above.
40953866 func (o *Subsurface) PlaceBelow(sibling *Surface) error {
4096- if err := o.Context().CheckProxy(o); err != nil {
4097- return err
4098- }
40993867 var arg0 wl.Object
41003868 if sibling != nil {
41013869 arg0 = sibling
41023870 }
4103- if err := o.Context().SendRequest(o, 3, arg0); err != nil {
3871+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "wl_subsurface.place_below"}, arg0); err != nil {
41043872 return err
41053873 }
41063874 return nil
@@ -4108,10 +3876,7 @@ func (o *Subsurface) PlaceBelow(sibling *Surface) error {
41083876
41093877 // Change the commit behaviour of the sub-surface to synchronized mode. See wl_subsurface and wl_surface.commit for more information.
41103878 func (o *Subsurface) SetSync() error {
4111- if err := o.Context().CheckProxy(o); err != nil {
4112- return err
4113- }
4114- if err := o.Context().SendRequest(o, 4); err != nil {
3879+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "wl_subsurface.set_sync"}); err != nil {
41153880 return err
41163881 }
41173882 return nil
@@ -4119,10 +3884,7 @@ func (o *Subsurface) SetSync() error {
41193884
41203885 // Change the commit behaviour of the sub-surface to desynchronized mode. See wl_subsurface and wl_surface.commit for more information.
41213886 func (o *Subsurface) SetDesync() error {
4122- if err := o.Context().CheckProxy(o); err != nil {
4123- return err
4124- }
4125- if err := o.Context().SendRequest(o, 5); err != nil {
3887+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 5, Name: "wl_subsurface.set_desync"}); err != nil {
41263888 return err
41273889 }
41283890 return nil
@@ -4161,10 +3923,7 @@ func NewFixes(ctx *wl.Context) *Fixes {
41613923
41623924 // destroys this object
41633925 func (o *Fixes) Destroy() error {
4164- if err := o.Context().CheckProxy(o); err != nil {
4165- return err
4166- }
4167- if err := o.Context().SendDestructor(o, 0); err != nil {
3926+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_fixes.destroy", Destructor: true}); err != nil {
41683927 return err
41693928 }
41703929 return nil
@@ -4172,14 +3931,11 @@ func (o *Fixes) Destroy() error {
41723931
41733932 // This request destroys a wl_registry object. The client should no longer use the wl_registry after making this request. The compositor will emit a wl_display.delete_id event with the object ID of the registry and will no longer emit any events on the registry. The client should re-use the object ID once it receives the wl_display.delete_id event.
41743933 func (o *Fixes) DestroyRegistry(registry *wl.Registry) error {
4175- if err := o.Context().CheckProxy(o); err != nil {
4176- return err
4177- }
41783934 var arg0 wl.Object
41793935 if registry != nil {
41803936 arg0 = registry
41813937 }
4182- if err := o.Context().SendRequest(o, 1, arg0); err != nil {
3938+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_fixes.destroy_registry"}, arg0); err != nil {
41833939 return err
41843940 }
41853941 return nil
@@ -4187,14 +3943,11 @@ func (o *Fixes) DestroyRegistry(registry *wl.Registry) error {
41873943
41883944 // Acknowledge the removal of the specified global. If no global with the specified name exists or the global is not removed, the wl_fixes.invalid_ack_remove protocol error will be posted. Due to the Wayland protocol being asynchronous, the wl_global objects cannot be destroyed immediately. For example, if a wl_global is removed and a client attempts to bind that global around same time, it can result in a protocol error due to an unknown global name in the bind request. In order to avoid crashing clients, the compositor should remove the wl_global once it is guaranteed that no more bind requests will come. The wl_fixes.ack_global_remove() request is used to signal to the compositor that the client will not bind the given global anymore. After all clients acknowledge the removal of the global, the compositor can safely destroy it. The client must call the wl_fixes.ack_global_remove() request in response to a wl_registry.global_remove() event even if it did not bind the corresponding global.
41893945 func (o *Fixes) AckGlobalRemove(registry *wl.Registry, name uint32) error {
4190- if err := o.Context().CheckProxy(o); err != nil {
4191- return err
4192- }
41933946 var arg0 wl.Object
41943947 if registry != nil {
41953948 arg0 = registry
41963949 }
4197- if err := o.Context().SendRequest(o, 2, arg0, name); err != nil {
3950+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_fixes.ack_global_remove", Since: 2}, arg0, name); err != nil {
41983951 return err
41993952 }
42003953 return nil
@@ -773,15 +773,9 @@ func NewCompositor(ctx *wl.Context) *Compositor {
773 773
774 // Ask the compositor to create a new surface.774 // Ask the compositor to create a new surface.
775 func (o *Compositor) CreateSurface() (*Surface, error) {775 func (o *Compositor) CreateSurface() (*Surface, error) {
776- if err := o.Context().CheckProxy(o); err != nil {
777- return nil, err
778- }
779 child := &Surface{}776 child := &Surface{}
780 child.SetContext(o.Context())777 child.SetContext(o.Context())
781- child.SetID(o.Context().AllocateID())778+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_compositor.create_surface", Child: child}, child); err != nil {
782- o.Context().Register(child)
783- if err := o.Context().SendRequest(o, 0, child); err != nil {
784- o.Context().Unregister(child)
785 return nil, err779 return nil, err
786 }780 }
787 return child, nil781 return child, nil
@@ -789,15 +783,9 @@ func (o *Compositor) CreateSurface() (*Surface, error) {
789 783
790 // Ask the compositor to create a new region.784 // Ask the compositor to create a new region.
791 func (o *Compositor) CreateRegion() (*Region, error) {785 func (o *Compositor) CreateRegion() (*Region, error) {
792- if err := o.Context().CheckProxy(o); err != nil {
793- return nil, err
794- }
795 child := &Region{}786 child := &Region{}
796 child.SetContext(o.Context())787 child.SetContext(o.Context())
797- child.SetID(o.Context().AllocateID())788+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_compositor.create_region", Child: child}, child); err != nil {
798- o.Context().Register(child)
799- if err := o.Context().SendRequest(o, 1, child); err != nil {
800- o.Context().Unregister(child)
801 return nil, err789 return nil, err
802 }790 }
803 return child, nil791 return child, nil
@@ -805,10 +793,7 @@ func (o *Compositor) CreateRegion() (*Region, error) {
805 793
806 // This request destroys the wl_compositor. This has no effect on any other objects.794 // This request destroys the wl_compositor. This has no effect on any other objects.
807 func (o *Compositor) Release() error {795 func (o *Compositor) Release() error {
808- if err := o.Context().CheckProxy(o); err != nil {796+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_compositor.release", Since: 7, Destructor: true}); err != nil {
809- return err
810- }
811- if err := o.Context().SendDestructor(o, 2); err != nil {
812 return err797 return err
813 }798 }
814 return nil799 return nil
@@ -847,15 +832,9 @@ func NewShmPool(ctx *wl.Context) *ShmPool {
847 832
848 // Create a wl_buffer object from the pool. The buffer is created offset bytes into the pool and has width and height as specified. The stride argument specifies the number of bytes from the beginning of one row to the beginning of the next. The format is the pixel format of the buffer and must be one of those advertised through the wl_shm.format event. A buffer will keep a reference to the pool it was created from so it is valid to destroy the pool immediately after creating a buffer from it.833 // Create a wl_buffer object from the pool. The buffer is created offset bytes into the pool and has width and height as specified. The stride argument specifies the number of bytes from the beginning of one row to the beginning of the next. The format is the pixel format of the buffer and must be one of those advertised through the wl_shm.format event. A buffer will keep a reference to the pool it was created from so it is valid to destroy the pool immediately after creating a buffer from it.
849 func (o *ShmPool) CreateBuffer(offset int32, width int32, height int32, stride int32, format uint32) (*Buffer, error) {834 func (o *ShmPool) CreateBuffer(offset int32, width int32, height int32, stride int32, format uint32) (*Buffer, error) {
850- if err := o.Context().CheckProxy(o); err != nil {
851- return nil, err
852- }
853 child := &Buffer{}835 child := &Buffer{}
854 child.SetContext(o.Context())836 child.SetContext(o.Context())
855- child.SetID(o.Context().AllocateID())837+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_shm_pool.create_buffer", Child: child}, child, offset, width, height, stride, format); err != nil {
856- o.Context().Register(child)
857- if err := o.Context().SendRequest(o, 0, child, offset, width, height, stride, format); err != nil {
858- o.Context().Unregister(child)
859 return nil, err838 return nil, err
860 }839 }
861 return child, nil840 return child, nil
@@ -863,10 +842,7 @@ func (o *ShmPool) CreateBuffer(offset int32, width int32, height int32, stride i
863 842
864 // Destroy the shared memory pool. The mmapped memory will be released when all buffers that have been created from this pool are gone.843 // Destroy the shared memory pool. The mmapped memory will be released when all buffers that have been created from this pool are gone.
865 func (o *ShmPool) Destroy() error {844 func (o *ShmPool) Destroy() error {
866- if err := o.Context().CheckProxy(o); err != nil {845+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_shm_pool.destroy", Destructor: true}); err != nil {
867- return err
868- }
869- if err := o.Context().SendDestructor(o, 1); err != nil {
870 return err846 return err
871 }847 }
872 return nil848 return nil
@@ -874,10 +850,7 @@ func (o *ShmPool) Destroy() error {
874 850
875 // This request will cause the server to remap the backing memory for the pool from the file descriptor passed when the pool was created, but using the new size. This request can only be used to make the pool bigger. This request only changes the amount of bytes that are mmapped by the server and does not touch the file corresponding to the file descriptor passed at creation time. It is the client's responsibility to ensure that the file is at least as big as the new pool size.851 // This request will cause the server to remap the backing memory for the pool from the file descriptor passed when the pool was created, but using the new size. This request can only be used to make the pool bigger. This request only changes the amount of bytes that are mmapped by the server and does not touch the file corresponding to the file descriptor passed at creation time. It is the client's responsibility to ensure that the file is at least as big as the new pool size.
876 func (o *ShmPool) Resize(size int32) error {852 func (o *ShmPool) Resize(size int32) error {
877- if err := o.Context().CheckProxy(o); err != nil {853+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_shm_pool.resize"}, size); err != nil {
878- return err
879- }
880- if err := o.Context().SendRequest(o, 2, size); err != nil {
881 return err854 return err
882 }855 }
883 return nil856 return nil
@@ -920,27 +893,17 @@ func NewShm(ctx *wl.Context) *Shm {
920 893
921 // Create a new wl_shm_pool object. The pool can be used to create shared memory based buffer objects. The server will mmap size bytes of the passed file descriptor, to use as backing memory for the pool.894 // Create a new wl_shm_pool object. The pool can be used to create shared memory based buffer objects. The server will mmap size bytes of the passed file descriptor, to use as backing memory for the pool.
922 func (o *Shm) CreatePool(fd int, size int32) (*ShmPool, error) {895 func (o *Shm) CreatePool(fd int, size int32) (*ShmPool, error) {
923- if err := o.Context().CheckProxy(o); err != nil {
924- return nil, err
925- }
926 child := &ShmPool{}896 child := &ShmPool{}
927 child.SetContext(o.Context())897 child.SetContext(o.Context())
928- child.SetID(o.Context().AllocateID())898+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_shm.create_pool", Child: child, FDs: []int{fd}}, child, uintptr(fd), size); err != nil {
929- o.Context().Register(child)
930- if err := o.Context().SendRequestWithFDs(o, 0, []int{fd}, child, uintptr(fd), size); err != nil {
931- o.Context().Unregister(child)
932 return nil, err899 return nil, err
933 }900 }
934- _ = wl.CloseSentFD(fd)
935 return child, nil901 return child, nil
936 }902 }
937 903
938 // Using this request a client can tell the server that it is not going to use the shm object anymore. Objects created via this interface remain unaffected.904 // Using this request a client can tell the server that it is not going to use the shm object anymore. Objects created via this interface remain unaffected.
939 func (o *Shm) Release() error {905 func (o *Shm) Release() error {
940- if err := o.Context().CheckProxy(o); err != nil {906+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_shm.release", Since: 2, Destructor: true}); err != nil {
941- return err
942- }
943- if err := o.Context().SendDestructor(o, 1); err != nil {
944 return err907 return err
945 }908 }
946 return nil909 return nil
@@ -1014,10 +977,7 @@ func NewBuffer(ctx *wl.Context) *Buffer {
1014 977
1015 // Destroy a buffer. If and how you need to release the backing storage is defined by the buffer factory interface. For possible side-effects to a surface, see wl_surface.attach.978 // Destroy a buffer. If and how you need to release the backing storage is defined by the buffer factory interface. For possible side-effects to a surface, see wl_surface.attach.
1016 func (o *Buffer) Destroy() error {979 func (o *Buffer) Destroy() error {
1017- if err := o.Context().CheckProxy(o); err != nil {980+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_buffer.destroy", Destructor: true}); err != nil {
1018- return err
1019- }
1020- if err := o.Context().SendDestructor(o, 0); err != nil {
1021 return err981 return err
1022 }982 }
1023 return nil983 return nil
@@ -1092,10 +1052,7 @@ func NewDataOffer(ctx *wl.Context) *DataOffer {
1092 1052
1093 // Indicate that the client can accept the given mime type, or NULL for not accepted. For objects of version 2 or older, this request is used by the client to give feedback whether the client can receive the given mime type, or NULL if none is accepted; the feedback does not determine whether the drag-and-drop operation succeeds or not. For objects of version 3 or newer, this request determines the final result of the drag-and-drop operation. If the end result is that no mime types were accepted, the drag-and-drop operation will be cancelled and the corresponding drag source will receive wl_data_source.cancelled. Clients may still use this event in conjunction with wl_data_source.action for feedback.1053 // Indicate that the client can accept the given mime type, or NULL for not accepted. For objects of version 2 or older, this request is used by the client to give feedback whether the client can receive the given mime type, or NULL if none is accepted; the feedback does not determine whether the drag-and-drop operation succeeds or not. For objects of version 3 or newer, this request determines the final result of the drag-and-drop operation. If the end result is that no mime types were accepted, the drag-and-drop operation will be cancelled and the corresponding drag source will receive wl_data_source.cancelled. Clients may still use this event in conjunction with wl_data_source.action for feedback.
1094 func (o *DataOffer) Accept(serial uint32, mimeType string) error {1054 func (o *DataOffer) Accept(serial uint32, mimeType string) error {
1095- if err := o.Context().CheckProxy(o); err != nil {1055+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_data_offer.accept"}, serial, mimeType); err != nil {
1096- return err
1097- }
1098- if err := o.Context().SendRequest(o, 0, serial, mimeType); err != nil {
1099 return err1056 return err
1100 }1057 }
1101 return nil1058 return nil
@@ -1103,22 +1060,15 @@ func (o *DataOffer) Accept(serial uint32, mimeType string) error {
1103 1060
1104 // To transfer the offered data, the client issues this request and indicates the mime type it wants to receive. The transfer happens through the passed file descriptor (typically created with the pipe system call). The source client writes the data in the mime type representation requested and then closes the file descriptor. The receiving client reads from the read end of the pipe until EOF and then closes its end, at which point the transfer is complete. This request may happen multiple times for different mime types, both before and after wl_data_device.drop. Drag-and-drop destination clients may preemptively fetch data or examine it more closely to determine acceptance.1061 // To transfer the offered data, the client issues this request and indicates the mime type it wants to receive. The transfer happens through the passed file descriptor (typically created with the pipe system call). The source client writes the data in the mime type representation requested and then closes the file descriptor. The receiving client reads from the read end of the pipe until EOF and then closes its end, at which point the transfer is complete. This request may happen multiple times for different mime types, both before and after wl_data_device.drop. Drag-and-drop destination clients may preemptively fetch data or examine it more closely to determine acceptance.
1105 func (o *DataOffer) Receive(mimeType string, fd int) error {1062 func (o *DataOffer) Receive(mimeType string, fd int) error {
1106- if err := o.Context().CheckProxy(o); err != nil {1063+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_data_offer.receive", FDs: []int{fd}}, mimeType, uintptr(fd)); err != nil {
1107 return err1064 return err
1108 }1065 }
1109- if err := o.Context().SendRequestWithFDs(o, 1, []int{fd}, mimeType, uintptr(fd)); err != nil {
1110- return err
1111- }
1112- _ = wl.CloseSentFD(fd)
1113 return nil1066 return nil
1114 }1067 }
1115 1068
1116 // Destroy the data offer.1069 // Destroy the data offer.
1117 func (o *DataOffer) Destroy() error {1070 func (o *DataOffer) Destroy() error {
1118- if err := o.Context().CheckProxy(o); err != nil {1071+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_data_offer.destroy", Destructor: true}); err != nil {
1119- return err
1120- }
1121- if err := o.Context().SendDestructor(o, 2); err != nil {
1122 return err1072 return err
1123 }1073 }
1124 return nil1074 return nil
@@ -1126,10 +1076,7 @@ func (o *DataOffer) Destroy() error {
1126 1076
1127 // Notifies the compositor that the drag destination successfully finished the drag-and-drop operation. Upon receiving this request, the compositor will emit wl_data_source.dnd_finished on the drag source client. It is a client error to perform other requests than wl_data_offer.destroy after this one. It is also an error to perform this request after a NULL mime type has been set in wl_data_offer.accept or no action was received through wl_data_offer.action. If wl_data_offer.finish request is received for a non drag and drop operation, the invalid_finish protocol error is raised.1077 // Notifies the compositor that the drag destination successfully finished the drag-and-drop operation. Upon receiving this request, the compositor will emit wl_data_source.dnd_finished on the drag source client. It is a client error to perform other requests than wl_data_offer.destroy after this one. It is also an error to perform this request after a NULL mime type has been set in wl_data_offer.accept or no action was received through wl_data_offer.action. If wl_data_offer.finish request is received for a non drag and drop operation, the invalid_finish protocol error is raised.
1128 func (o *DataOffer) Finish() error {1078 func (o *DataOffer) Finish() error {
1129- if err := o.Context().CheckProxy(o); err != nil {1079+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "wl_data_offer.finish", Since: 3}); err != nil {
1130- return err
1131- }
1132- if err := o.Context().SendRequest(o, 3); err != nil {
1133 return err1080 return err
1134 }1081 }
1135 return nil1082 return nil
@@ -1137,10 +1084,7 @@ func (o *DataOffer) Finish() error {
1137 1084
1138 // Sets the actions that the destination side client supports for this operation. This request may trigger the emission of wl_data_source.action and wl_data_offer.action events if the compositor needs to change the selected action. This request can be called multiple times throughout the drag-and-drop operation, typically in response to wl_data_device.enter or wl_data_device.motion events. This request determines the final result of the drag-and-drop operation. If the end result is that no action is accepted, the drag source will receive wl_data_source.cancelled. The dnd_actions argument must contain only values expressed in the wl_data_device_manager.dnd_actions enum, and the preferred_action argument must only contain one of those values set, otherwise it will result in a protocol error. While managing an "ask" action, the destination drag-and-drop client may perform further wl_data_offer.receive requests, and is expected to perform one last wl_data_offer.set_actions request with a preferred action other than "ask" (and optionally wl_data_offer.accept) before requesting wl_data_offer.finish, in order to convey the action selected by the user. If the preferred action is not in the wl_data_offer.source_actions mask, an error will be raised. If the "ask" action is dismissed (e.g. user cancellation), the client is expected to perform wl_data_offer.destroy right away. This request can only be made on drag-and-drop offers, a protocol error will be raised otherwise.1085 // Sets the actions that the destination side client supports for this operation. This request may trigger the emission of wl_data_source.action and wl_data_offer.action events if the compositor needs to change the selected action. This request can be called multiple times throughout the drag-and-drop operation, typically in response to wl_data_device.enter or wl_data_device.motion events. This request determines the final result of the drag-and-drop operation. If the end result is that no action is accepted, the drag source will receive wl_data_source.cancelled. The dnd_actions argument must contain only values expressed in the wl_data_device_manager.dnd_actions enum, and the preferred_action argument must only contain one of those values set, otherwise it will result in a protocol error. While managing an "ask" action, the destination drag-and-drop client may perform further wl_data_offer.receive requests, and is expected to perform one last wl_data_offer.set_actions request with a preferred action other than "ask" (and optionally wl_data_offer.accept) before requesting wl_data_offer.finish, in order to convey the action selected by the user. If the preferred action is not in the wl_data_offer.source_actions mask, an error will be raised. If the "ask" action is dismissed (e.g. user cancellation), the client is expected to perform wl_data_offer.destroy right away. This request can only be made on drag-and-drop offers, a protocol error will be raised otherwise.
1139 func (o *DataOffer) SetActions(dndActions uint32, preferredAction uint32) error {1086 func (o *DataOffer) SetActions(dndActions uint32, preferredAction uint32) error {
1140- if err := o.Context().CheckProxy(o); err != nil {1087+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "wl_data_offer.set_actions", Since: 3}, dndActions, preferredAction); err != nil {
1141- return err
1142- }
1143- if err := o.Context().SendRequest(o, 4, dndActions, preferredAction); err != nil {
1144 return err1088 return err
1145 }1089 }
1146 return nil1090 return nil
@@ -1281,10 +1225,7 @@ func NewDataSource(ctx *wl.Context) *DataSource {
1281 1225
1282 // This request adds a mime type to the set of mime types advertised to targets. Can be called several times to offer multiple types.1226 // This request adds a mime type to the set of mime types advertised to targets. Can be called several times to offer multiple types.
1283 func (o *DataSource) Offer(mimeType string) error {1227 func (o *DataSource) Offer(mimeType string) error {
1284- if err := o.Context().CheckProxy(o); err != nil {1228+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_data_source.offer"}, mimeType); err != nil {
1285- return err
1286- }
1287- if err := o.Context().SendRequest(o, 0, mimeType); err != nil {
1288 return err1229 return err
1289 }1230 }
1290 return nil1231 return nil
@@ -1292,10 +1233,7 @@ func (o *DataSource) Offer(mimeType string) error {
1292 1233
1293 // Destroy the data source.1234 // Destroy the data source.
1294 func (o *DataSource) Destroy() error {1235 func (o *DataSource) Destroy() error {
1295- if err := o.Context().CheckProxy(o); err != nil {1236+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_data_source.destroy", Destructor: true}); err != nil {
1296- return err
1297- }
1298- if err := o.Context().SendDestructor(o, 1); err != nil {
1299 return err1237 return err
1300 }1238 }
1301 return nil1239 return nil
@@ -1303,10 +1241,7 @@ func (o *DataSource) Destroy() error {
1303 1241
1304 // Sets the actions that the source side client supports for this operation. This request may trigger wl_data_source.action and wl_data_offer.action events if the compositor needs to change the selected action. The dnd_actions argument must contain only values expressed in the wl_data_device_manager.dnd_actions enum, otherwise it will result in a protocol error. This request must be made once only, and can only be made on sources used in drag-and-drop, so it must be performed before wl_data_device.start_drag. Attempting to use the source other than for drag-and-drop will raise a protocol error.1242 // Sets the actions that the source side client supports for this operation. This request may trigger wl_data_source.action and wl_data_offer.action events if the compositor needs to change the selected action. The dnd_actions argument must contain only values expressed in the wl_data_device_manager.dnd_actions enum, otherwise it will result in a protocol error. This request must be made once only, and can only be made on sources used in drag-and-drop, so it must be performed before wl_data_device.start_drag. Attempting to use the source other than for drag-and-drop will raise a protocol error.
1305 func (o *DataSource) SetActions(dndActions uint32) error {1243 func (o *DataSource) SetActions(dndActions uint32) error {
1306- if err := o.Context().CheckProxy(o); err != nil {1244+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_data_source.set_actions", Since: 3}, dndActions); err != nil {
1307- return err
1308- }
1309- if err := o.Context().SendRequest(o, 2, dndActions); err != nil {
1310 return err1245 return err
1311 }1246 }
1312 return nil1247 return nil
@@ -1542,9 +1477,6 @@ func NewDataDevice(ctx *wl.Context) *DataDevice {
1542 1477
1543 // This request asks the compositor to start a drag-and-drop operation on behalf of the client. The source argument is the data source that provides the data for the eventual data transfer. If source is NULL, enter, leave and motion events are sent only to the client that initiated the drag and the client is expected to handle the data passing internally. If source is destroyed, the drag-and-drop session will be cancelled. The origin surface is the surface where the drag originates and the client must have an active implicit grab that matches the serial. The icon surface is an optional (can be NULL) surface that provides an icon to be moved around with the cursor. Initially, the top-left corner of the icon surface is placed at the cursor hotspot, but subsequent wl_surface.offset requests can move the relative position. Attach requests must be confirmed with wl_surface.commit as usual. The icon surface is given the role of a drag-and-drop icon. If the icon surface already has another role, it raises a protocol error. The input region is ignored for wl_surfaces with the role of a drag-and-drop icon. The given source may not be used in any further set_selection or start_drag requests. Attempting to reuse a previously-used source may send a used_source error.1478 // This request asks the compositor to start a drag-and-drop operation on behalf of the client. The source argument is the data source that provides the data for the eventual data transfer. If source is NULL, enter, leave and motion events are sent only to the client that initiated the drag and the client is expected to handle the data passing internally. If source is destroyed, the drag-and-drop session will be cancelled. The origin surface is the surface where the drag originates and the client must have an active implicit grab that matches the serial. The icon surface is an optional (can be NULL) surface that provides an icon to be moved around with the cursor. Initially, the top-left corner of the icon surface is placed at the cursor hotspot, but subsequent wl_surface.offset requests can move the relative position. Attach requests must be confirmed with wl_surface.commit as usual. The icon surface is given the role of a drag-and-drop icon. If the icon surface already has another role, it raises a protocol error. The input region is ignored for wl_surfaces with the role of a drag-and-drop icon. The given source may not be used in any further set_selection or start_drag requests. Attempting to reuse a previously-used source may send a used_source error.
1544 func (o *DataDevice) StartDrag(source *DataSource, origin *Surface, icon *Surface, serial uint32) error {1479 func (o *DataDevice) StartDrag(source *DataSource, origin *Surface, icon *Surface, serial uint32) error {
1545- if err := o.Context().CheckProxy(o); err != nil {
1546- return err
1547- }
1548 var arg0 wl.Object1480 var arg0 wl.Object
1549 if source != nil {1481 if source != nil {
1550 arg0 = source1482 arg0 = source
@@ -1557,7 +1489,7 @@ func (o *DataDevice) StartDrag(source *DataSource, origin *Surface, icon *Surfac
1557 if icon != nil {1489 if icon != nil {
1558 arg2 = icon1490 arg2 = icon
1559 }1491 }
1560- if err := o.Context().SendRequest(o, 0, arg0, arg1, arg2, serial); err != nil {1492+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_data_device.start_drag"}, arg0, arg1, arg2, serial); err != nil {
1561 return err1493 return err
1562 }1494 }
1563 return nil1495 return nil
@@ -1565,14 +1497,11 @@ func (o *DataDevice) StartDrag(source *DataSource, origin *Surface, icon *Surfac
1565 1497
1566 // This request asks the compositor to set the selection to the data from the source on behalf of the client. To unset the selection, set the source to NULL. The given source may not be used in any further set_selection or start_drag requests. Attempting to reuse a previously-used source may send a used_source error.1498 // This request asks the compositor to set the selection to the data from the source on behalf of the client. To unset the selection, set the source to NULL. The given source may not be used in any further set_selection or start_drag requests. Attempting to reuse a previously-used source may send a used_source error.
1567 func (o *DataDevice) SetSelection(source *DataSource, serial uint32) error {1499 func (o *DataDevice) SetSelection(source *DataSource, serial uint32) error {
1568- if err := o.Context().CheckProxy(o); err != nil {
1569- return err
1570- }
1571 var arg0 wl.Object1500 var arg0 wl.Object
1572 if source != nil {1501 if source != nil {
1573 arg0 = source1502 arg0 = source
1574 }1503 }
1575- if err := o.Context().SendRequest(o, 1, arg0, serial); err != nil {1504+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_data_device.set_selection"}, arg0, serial); err != nil {
1576 return err1505 return err
1577 }1506 }
1578 return nil1507 return nil
@@ -1580,10 +1509,7 @@ func (o *DataDevice) SetSelection(source *DataSource, serial uint32) error {
1580 1509
1581 // This request destroys the data device.1510 // This request destroys the data device.
1582 func (o *DataDevice) Release() error {1511 func (o *DataDevice) Release() error {
1583- if err := o.Context().CheckProxy(o); err != nil {1512+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_data_device.release", Since: 2, Destructor: true}); err != nil {
1584- return err
1585- }
1586- if err := o.Context().SendDestructor(o, 2); err != nil {
1587 return err1513 return err
1588 }1514 }
1589 return nil1515 return nil
@@ -1749,6 +1675,7 @@ func (o *DataDevice) Dispatch(event *wl.Event) {
1749 idObject := &DataOffer{}1675 idObject := &DataOffer{}
1750 idObject.SetContext(o.Context())1676 idObject.SetContext(o.Context())
1751 idObject.SetID(idID)1677 idObject.SetID(idID)
1678+ idObject.SetVersion(o.Version())
1752 o.Context().Register(idObject)1679 o.Context().Register(idObject)
1753 1680
1754 for i, handler := range o.handlersForDataOffer() {1681 for i, handler := range o.handlersForDataOffer() {
@@ -1816,15 +1743,9 @@ func NewDataDeviceManager(ctx *wl.Context) *DataDeviceManager {
1816 1743
1817 // Create a new data source.1744 // Create a new data source.
1818 func (o *DataDeviceManager) CreateDataSource() (*DataSource, error) {1745 func (o *DataDeviceManager) CreateDataSource() (*DataSource, error) {
1819- if err := o.Context().CheckProxy(o); err != nil {
1820- return nil, err
1821- }
1822 child := &DataSource{}1746 child := &DataSource{}
1823 child.SetContext(o.Context())1747 child.SetContext(o.Context())
1824- child.SetID(o.Context().AllocateID())1748+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_data_device_manager.create_data_source", Child: child}, child); err != nil {
1825- o.Context().Register(child)
1826- if err := o.Context().SendRequest(o, 0, child); err != nil {
1827- o.Context().Unregister(child)
1828 return nil, err1749 return nil, err
1829 }1750 }
1830 return child, nil1751 return child, nil
@@ -1832,19 +1753,13 @@ func (o *DataDeviceManager) CreateDataSource() (*DataSource, error) {
1832 1753
1833 // Create a new data device for a given seat.1754 // Create a new data device for a given seat.
1834 func (o *DataDeviceManager) GetDataDevice(seat *Seat) (*DataDevice, error) {1755 func (o *DataDeviceManager) GetDataDevice(seat *Seat) (*DataDevice, error) {
1835- if err := o.Context().CheckProxy(o); err != nil {
1836- return nil, err
1837- }
1838 var arg1 wl.Object1756 var arg1 wl.Object
1839 if seat != nil {1757 if seat != nil {
1840 arg1 = seat1758 arg1 = seat
1841 }1759 }
1842 child := &DataDevice{}1760 child := &DataDevice{}
1843 child.SetContext(o.Context())1761 child.SetContext(o.Context())
1844- child.SetID(o.Context().AllocateID())1762+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_data_device_manager.get_data_device", Child: child}, child, arg1); err != nil {
1845- o.Context().Register(child)
1846- if err := o.Context().SendRequest(o, 1, child, arg1); err != nil {
1847- o.Context().Unregister(child)
1848 return nil, err1763 return nil, err
1849 }1764 }
1850 return child, nil1765 return child, nil
@@ -1852,10 +1767,7 @@ func (o *DataDeviceManager) GetDataDevice(seat *Seat) (*DataDevice, error) {
1852 1767
1853 // This request destroys the wl_data_device_manager. This has no effect on any other objects.1768 // This request destroys the wl_data_device_manager. This has no effect on any other objects.
1854 func (o *DataDeviceManager) Release() error {1769 func (o *DataDeviceManager) Release() error {
1855- if err := o.Context().CheckProxy(o); err != nil {1770+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_data_device_manager.release", Since: 4, Destructor: true}); err != nil {
1856- return err
1857- }
1858- if err := o.Context().SendDestructor(o, 2); err != nil {
1859 return err1771 return err
1860 }1772 }
1861 return nil1773 return nil
@@ -1894,19 +1806,13 @@ func NewShell(ctx *wl.Context) *Shell {
1894 1806
1895 // Create a shell surface for an existing surface. This gives the wl_surface the role of a shell surface. If the wl_surface already has another role, it raises a protocol error. Only one shell surface can be associated with a given surface.1807 // Create a shell surface for an existing surface. This gives the wl_surface the role of a shell surface. If the wl_surface already has another role, it raises a protocol error. Only one shell surface can be associated with a given surface.
1896 func (o *Shell) GetShellSurface(surface *Surface) (*ShellSurface, error) {1808 func (o *Shell) GetShellSurface(surface *Surface) (*ShellSurface, error) {
1897- if err := o.Context().CheckProxy(o); err != nil {
1898- return nil, err
1899- }
1900 var arg1 wl.Object1809 var arg1 wl.Object
1901 if surface != nil {1810 if surface != nil {
1902 arg1 = surface1811 arg1 = surface
1903 }1812 }
1904 child := &ShellSurface{}1813 child := &ShellSurface{}
1905 child.SetContext(o.Context())1814 child.SetContext(o.Context())
1906- child.SetID(o.Context().AllocateID())1815+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_shell.get_shell_surface", Child: child}, child, arg1); err != nil {
1907- o.Context().Register(child)
1908- if err := o.Context().SendRequest(o, 0, child, arg1); err != nil {
1909- o.Context().Unregister(child)
1910 return nil, err1816 return nil, err
1911 }1817 }
1912 return child, nil1818 return child, nil
@@ -1951,10 +1857,7 @@ func NewShellSurface(ctx *wl.Context) *ShellSurface {
1951 1857
1952 // A client must respond to a ping event with a pong request or the client may be deemed unresponsive.1858 // A client must respond to a ping event with a pong request or the client may be deemed unresponsive.
1953 func (o *ShellSurface) Pong(serial uint32) error {1859 func (o *ShellSurface) Pong(serial uint32) error {
1954- if err := o.Context().CheckProxy(o); err != nil {1860+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_shell_surface.pong"}, serial); err != nil {
1955- return err
1956- }
1957- if err := o.Context().SendRequest(o, 0, serial); err != nil {
1958 return err1861 return err
1959 }1862 }
1960 return nil1863 return nil
@@ -1962,14 +1865,11 @@ func (o *ShellSurface) Pong(serial uint32) error {
1962 1865
1963 // Start a pointer-driven move of the surface. This request must be used in response to a button press event. The server may ignore move requests depending on the state of the surface (e.g. fullscreen or maximized).1866 // Start a pointer-driven move of the surface. This request must be used in response to a button press event. The server may ignore move requests depending on the state of the surface (e.g. fullscreen or maximized).
1964 func (o *ShellSurface) Move(seat *Seat, serial uint32) error {1867 func (o *ShellSurface) Move(seat *Seat, serial uint32) error {
1965- if err := o.Context().CheckProxy(o); err != nil {
1966- return err
1967- }
1968 var arg0 wl.Object1868 var arg0 wl.Object
1969 if seat != nil {1869 if seat != nil {
1970 arg0 = seat1870 arg0 = seat
1971 }1871 }
1972- if err := o.Context().SendRequest(o, 1, arg0, serial); err != nil {1872+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_shell_surface.move"}, arg0, serial); err != nil {
1973 return err1873 return err
1974 }1874 }
1975 return nil1875 return nil
@@ -1977,14 +1877,11 @@ func (o *ShellSurface) Move(seat *Seat, serial uint32) error {
1977 1877
1978 // Start a pointer-driven resizing of the surface. This request must be used in response to a button press event. The server may ignore resize requests depending on the state of the surface (e.g. fullscreen or maximized).1878 // Start a pointer-driven resizing of the surface. This request must be used in response to a button press event. The server may ignore resize requests depending on the state of the surface (e.g. fullscreen or maximized).
1979 func (o *ShellSurface) Resize(seat *Seat, serial uint32, edges uint32) error {1879 func (o *ShellSurface) Resize(seat *Seat, serial uint32, edges uint32) error {
1980- if err := o.Context().CheckProxy(o); err != nil {
1981- return err
1982- }
1983 var arg0 wl.Object1880 var arg0 wl.Object
1984 if seat != nil {1881 if seat != nil {
1985 arg0 = seat1882 arg0 = seat
1986 }1883 }
1987- if err := o.Context().SendRequest(o, 2, arg0, serial, edges); err != nil {1884+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_shell_surface.resize"}, arg0, serial, edges); err != nil {
1988 return err1885 return err
1989 }1886 }
1990 return nil1887 return nil
@@ -1992,10 +1889,7 @@ func (o *ShellSurface) Resize(seat *Seat, serial uint32, edges uint32) error {
1992 1889
1993 // Map the surface as a toplevel surface. A toplevel surface is not fullscreen, maximized or transient.1890 // Map the surface as a toplevel surface. A toplevel surface is not fullscreen, maximized or transient.
1994 func (o *ShellSurface) SetToplevel() error {1891 func (o *ShellSurface) SetToplevel() error {
1995- if err := o.Context().CheckProxy(o); err != nil {1892+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "wl_shell_surface.set_toplevel"}); err != nil {
1996- return err
1997- }
1998- if err := o.Context().SendRequest(o, 3); err != nil {
1999 return err1893 return err
2000 }1894 }
2001 return nil1895 return nil
@@ -2003,14 +1897,11 @@ func (o *ShellSurface) SetToplevel() error {
2003 1897
2004 // Map the surface relative to an existing surface. The x and y arguments specify the location of the upper left corner of the surface relative to the upper left corner of the parent surface, in surface-local coordinates. The flags argument controls details of the transient behaviour.1898 // Map the surface relative to an existing surface. The x and y arguments specify the location of the upper left corner of the surface relative to the upper left corner of the parent surface, in surface-local coordinates. The flags argument controls details of the transient behaviour.
2005 func (o *ShellSurface) SetTransient(parent *Surface, x int32, y int32, flags uint32) error {1899 func (o *ShellSurface) SetTransient(parent *Surface, x int32, y int32, flags uint32) error {
2006- if err := o.Context().CheckProxy(o); err != nil {
2007- return err
2008- }
2009 var arg0 wl.Object1900 var arg0 wl.Object
2010 if parent != nil {1901 if parent != nil {
2011 arg0 = parent1902 arg0 = parent
2012 }1903 }
2013- if err := o.Context().SendRequest(o, 4, arg0, x, y, flags); err != nil {1904+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "wl_shell_surface.set_transient"}, arg0, x, y, flags); err != nil {
2014 return err1905 return err
2015 }1906 }
2016 return nil1907 return nil
@@ -2018,14 +1909,11 @@ func (o *ShellSurface) SetTransient(parent *Surface, x int32, y int32, flags uin
2018 1909
2019 // Map the surface as a fullscreen surface. If an output parameter is given then the surface will be made fullscreen on that output. If the client does not specify the output then the compositor will apply its policy - usually choosing the output on which the surface has the biggest surface area. The client may specify a method to resolve a size conflict between the output size and the surface size - this is provided through the method parameter. The framerate parameter is used only when the method is set to "driver", to indicate the preferred framerate. A value of 0 indicates that the client does not care about framerate. The framerate is specified in mHz, that is framerate of 60000 is 60Hz. A method of "scale" or "driver" implies a scaling operation of the surface, either via a direct scaling operation or a change of the output mode. This will override any kind of output scaling, so that mapping a surface with a buffer size equal to the mode can fill the screen independent of buffer_scale. A method of "fill" means we don't scale up the buffer, however any output scale is applied. This means that you may run into an edge case where the application maps a buffer with the same size of the output mode but buffer_scale 1 (thus making a surface larger than the output). In this case it is allowed to downscale the results to fit the screen. The compositor must reply to this request with a configure event with the dimensions for the output on which the surface will be made fullscreen.1910 // Map the surface as a fullscreen surface. If an output parameter is given then the surface will be made fullscreen on that output. If the client does not specify the output then the compositor will apply its policy - usually choosing the output on which the surface has the biggest surface area. The client may specify a method to resolve a size conflict between the output size and the surface size - this is provided through the method parameter. The framerate parameter is used only when the method is set to "driver", to indicate the preferred framerate. A value of 0 indicates that the client does not care about framerate. The framerate is specified in mHz, that is framerate of 60000 is 60Hz. A method of "scale" or "driver" implies a scaling operation of the surface, either via a direct scaling operation or a change of the output mode. This will override any kind of output scaling, so that mapping a surface with a buffer size equal to the mode can fill the screen independent of buffer_scale. A method of "fill" means we don't scale up the buffer, however any output scale is applied. This means that you may run into an edge case where the application maps a buffer with the same size of the output mode but buffer_scale 1 (thus making a surface larger than the output). In this case it is allowed to downscale the results to fit the screen. The compositor must reply to this request with a configure event with the dimensions for the output on which the surface will be made fullscreen.
2020 func (o *ShellSurface) SetFullscreen(method uint32, framerate uint32, output *Output) error {1911 func (o *ShellSurface) SetFullscreen(method uint32, framerate uint32, output *Output) error {
2021- if err := o.Context().CheckProxy(o); err != nil {
2022- return err
2023- }
2024 var arg2 wl.Object1912 var arg2 wl.Object
2025 if output != nil {1913 if output != nil {
2026 arg2 = output1914 arg2 = output
2027 }1915 }
2028- if err := o.Context().SendRequest(o, 5, method, framerate, arg2); err != nil {1916+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 5, Name: "wl_shell_surface.set_fullscreen"}, method, framerate, arg2); err != nil {
2029 return err1917 return err
2030 }1918 }
2031 return nil1919 return nil
@@ -2033,9 +1921,6 @@ func (o *ShellSurface) SetFullscreen(method uint32, framerate uint32, output *Ou
2033 1921
2034 // Map the surface as a popup. A popup surface is a transient surface with an added pointer grab. An existing implicit grab will be changed to owner-events mode, and the popup grab will continue after the implicit grab ends (i.e. releasing the mouse button does not cause the popup to be unmapped). The popup grab continues until the window is destroyed or a mouse button is pressed in any other client's window. A click in any of the client's surfaces is reported as normal, however, clicks in other clients' surfaces will be discarded and trigger the callback. The x and y arguments specify the location of the upper left corner of the surface relative to the upper left corner of the parent surface, in surface-local coordinates.1922 // Map the surface as a popup. A popup surface is a transient surface with an added pointer grab. An existing implicit grab will be changed to owner-events mode, and the popup grab will continue after the implicit grab ends (i.e. releasing the mouse button does not cause the popup to be unmapped). The popup grab continues until the window is destroyed or a mouse button is pressed in any other client's window. A click in any of the client's surfaces is reported as normal, however, clicks in other clients' surfaces will be discarded and trigger the callback. The x and y arguments specify the location of the upper left corner of the surface relative to the upper left corner of the parent surface, in surface-local coordinates.
2035 func (o *ShellSurface) SetPopup(seat *Seat, serial uint32, parent *Surface, x int32, y int32, flags uint32) error {1923 func (o *ShellSurface) SetPopup(seat *Seat, serial uint32, parent *Surface, x int32, y int32, flags uint32) error {
2036- if err := o.Context().CheckProxy(o); err != nil {
2037- return err
2038- }
2039 var arg0 wl.Object1924 var arg0 wl.Object
2040 if seat != nil {1925 if seat != nil {
2041 arg0 = seat1926 arg0 = seat
@@ -2044,7 +1929,7 @@ func (o *ShellSurface) SetPopup(seat *Seat, serial uint32, parent *Surface, x in
2044 if parent != nil {1929 if parent != nil {
2045 arg2 = parent1930 arg2 = parent
2046 }1931 }
2047- if err := o.Context().SendRequest(o, 6, arg0, serial, arg2, x, y, flags); err != nil {1932+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 6, Name: "wl_shell_surface.set_popup"}, arg0, serial, arg2, x, y, flags); err != nil {
2048 return err1933 return err
2049 }1934 }
2050 return nil1935 return nil
@@ -2052,14 +1937,11 @@ func (o *ShellSurface) SetPopup(seat *Seat, serial uint32, parent *Surface, x in
2052 1937
2053 // Map the surface as a maximized surface. If an output parameter is given then the surface will be maximized on that output. If the client does not specify the output then the compositor will apply its policy - usually choosing the output on which the surface has the biggest surface area. The compositor will reply with a configure event telling the expected new surface size. The operation is completed on the next buffer attach to this surface. A maximized surface typically fills the entire output it is bound to, except for desktop elements such as panels. This is the main difference between a maximized shell surface and a fullscreen shell surface. The details depend on the compositor implementation.1938 // Map the surface as a maximized surface. If an output parameter is given then the surface will be maximized on that output. If the client does not specify the output then the compositor will apply its policy - usually choosing the output on which the surface has the biggest surface area. The compositor will reply with a configure event telling the expected new surface size. The operation is completed on the next buffer attach to this surface. A maximized surface typically fills the entire output it is bound to, except for desktop elements such as panels. This is the main difference between a maximized shell surface and a fullscreen shell surface. The details depend on the compositor implementation.
2054 func (o *ShellSurface) SetMaximized(output *Output) error {1939 func (o *ShellSurface) SetMaximized(output *Output) error {
2055- if err := o.Context().CheckProxy(o); err != nil {
2056- return err
2057- }
2058 var arg0 wl.Object1940 var arg0 wl.Object
2059 if output != nil {1941 if output != nil {
2060 arg0 = output1942 arg0 = output
2061 }1943 }
2062- if err := o.Context().SendRequest(o, 7, arg0); err != nil {1944+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 7, Name: "wl_shell_surface.set_maximized"}, arg0); err != nil {
2063 return err1945 return err
2064 }1946 }
2065 return nil1947 return nil
@@ -2067,10 +1949,7 @@ func (o *ShellSurface) SetMaximized(output *Output) error {
2067 1949
2068 // 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.1950 // 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.
2069 func (o *ShellSurface) SetTitle(title string) error {1951 func (o *ShellSurface) SetTitle(title string) error {
2070- if err := o.Context().CheckProxy(o); err != nil {1952+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 8, Name: "wl_shell_surface.set_title"}, title); err != nil {
2071- return err
2072- }
2073- if err := o.Context().SendRequest(o, 8, title); err != nil {
2074 return err1953 return err
2075 }1954 }
2076 return nil1955 return nil
@@ -2078,10 +1957,7 @@ func (o *ShellSurface) SetTitle(title string) error {
2078 1957
2079 // Set a class for the surface. The surface class identifies the general class of applications to which the surface belongs. A common convention is to use the file name (or the full path if it is a non-standard location) of the application's .desktop file as the class.1958 // Set a class for the surface. The surface class identifies the general class of applications to which the surface belongs. A common convention is to use the file name (or the full path if it is a non-standard location) of the application's .desktop file as the class.
2080 func (o *ShellSurface) SetClass(class string) error {1959 func (o *ShellSurface) SetClass(class string) error {
2081- if err := o.Context().CheckProxy(o); err != nil {1960+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 9, Name: "wl_shell_surface.set_class"}, class); err != nil {
2082- return err
2083- }
2084- if err := o.Context().SendRequest(o, 9, class); err != nil {
2085 return err1961 return err
2086 }1962 }
2087 return nil1963 return nil
@@ -2221,10 +2097,7 @@ func NewSurface(ctx *wl.Context) *Surface {
2221 2097
2222 // Deletes the surface and invalidates its object ID.2098 // Deletes the surface and invalidates its object ID.
2223 func (o *Surface) Destroy() error {2099 func (o *Surface) Destroy() error {
2224- if err := o.Context().CheckProxy(o); err != nil {2100+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_surface.destroy", Destructor: true}); err != nil {
2225- return err
2226- }
2227- if err := o.Context().SendDestructor(o, 0); err != nil {
2228 return err2101 return err
2229 }2102 }
2230 return nil2103 return nil
@@ -2232,14 +2105,11 @@ func (o *Surface) Destroy() error {
2232 2105
2233 // Set a buffer as the content of this surface. The new size of the surface is calculated based on the buffer size transformed by the inverse buffer_transform and the inverse buffer_scale. This means that at commit time the supplied buffer size must be an integer multiple of the buffer_scale. If that's not the case, an invalid_size error is sent. The x and y arguments specify the location of the new pending buffer's upper left corner, relative to the current buffer's upper left corner, in surface-local coordinates. In other words, the x and y, combined with the new surface size define in which directions the surface's size changes. Setting anything other than 0 as x and y arguments is discouraged, and should instead be replaced with using the separate wl_surface.offset request. When the bound wl_surface version is 5 or higher, passing any non-zero x or y is a protocol violation, and will result in an 'invalid_offset' error being raised. The x and y arguments are ignored and do not change the pending state. To achieve equivalent semantics, use wl_surface.offset. Surface contents are double-buffered state, see wl_surface.commit. The initial surface contents are void; there is no content. wl_surface.attach assigns the given wl_buffer as the pending wl_buffer. wl_surface.commit makes the pending wl_buffer the new surface contents, and the size of the surface becomes the size calculated from the wl_buffer, as described above. After commit, there is no pending buffer until the next attach. Committing a pending wl_buffer allows the compositor to read the pixels in the wl_buffer. The compositor may access the pixels at any time after the wl_surface.commit request. When the compositor will not access the pixels anymore, it will send the wl_buffer.release event. Only after receiving wl_buffer.release, the client may reuse the wl_buffer. A wl_buffer that has been attached and then replaced by another attach instead of committed will not receive a release event, and is not used by the compositor. If a pending wl_buffer has been committed to more than one wl_surface, the delivery of wl_buffer.release events becomes undefined. A well behaved client should not rely on wl_buffer.release events in this case. Instead, clients hitting this case should use wl_surface.get_release or use a protocol extension providing per-commit release notifications (if none of these options are available, a fallback can be implemented by creating multiple wl_buffer objects from the same backing storage). Destroying the wl_buffer after wl_buffer.release does not change the surface contents. Destroying the wl_buffer before wl_buffer.release is allowed as long as the underlying buffer storage isn't re-used (this can happen e.g. on client process termination). However, if the client destroys the wl_buffer before receiving the wl_buffer.release event and mutates the underlying buffer storage, the surface contents become undefined immediately. If wl_surface.attach is sent with a NULL wl_buffer, the following wl_surface.commit will remove the surface content. If a pending wl_buffer has been destroyed, the result is not specified. Many compositors are known to remove the surface content on the following wl_surface.commit, but this behaviour is not universal. Clients seeking to maximise compatibility should not destroy pending buffers and should ensure that they explicitly remove content from surfaces, even after destroying buffers.2106 // Set a buffer as the content of this surface. The new size of the surface is calculated based on the buffer size transformed by the inverse buffer_transform and the inverse buffer_scale. This means that at commit time the supplied buffer size must be an integer multiple of the buffer_scale. If that's not the case, an invalid_size error is sent. The x and y arguments specify the location of the new pending buffer's upper left corner, relative to the current buffer's upper left corner, in surface-local coordinates. In other words, the x and y, combined with the new surface size define in which directions the surface's size changes. Setting anything other than 0 as x and y arguments is discouraged, and should instead be replaced with using the separate wl_surface.offset request. When the bound wl_surface version is 5 or higher, passing any non-zero x or y is a protocol violation, and will result in an 'invalid_offset' error being raised. The x and y arguments are ignored and do not change the pending state. To achieve equivalent semantics, use wl_surface.offset. Surface contents are double-buffered state, see wl_surface.commit. The initial surface contents are void; there is no content. wl_surface.attach assigns the given wl_buffer as the pending wl_buffer. wl_surface.commit makes the pending wl_buffer the new surface contents, and the size of the surface becomes the size calculated from the wl_buffer, as described above. After commit, there is no pending buffer until the next attach. Committing a pending wl_buffer allows the compositor to read the pixels in the wl_buffer. The compositor may access the pixels at any time after the wl_surface.commit request. When the compositor will not access the pixels anymore, it will send the wl_buffer.release event. Only after receiving wl_buffer.release, the client may reuse the wl_buffer. A wl_buffer that has been attached and then replaced by another attach instead of committed will not receive a release event, and is not used by the compositor. If a pending wl_buffer has been committed to more than one wl_surface, the delivery of wl_buffer.release events becomes undefined. A well behaved client should not rely on wl_buffer.release events in this case. Instead, clients hitting this case should use wl_surface.get_release or use a protocol extension providing per-commit release notifications (if none of these options are available, a fallback can be implemented by creating multiple wl_buffer objects from the same backing storage). Destroying the wl_buffer after wl_buffer.release does not change the surface contents. Destroying the wl_buffer before wl_buffer.release is allowed as long as the underlying buffer storage isn't re-used (this can happen e.g. on client process termination). However, if the client destroys the wl_buffer before receiving the wl_buffer.release event and mutates the underlying buffer storage, the surface contents become undefined immediately. If wl_surface.attach is sent with a NULL wl_buffer, the following wl_surface.commit will remove the surface content. If a pending wl_buffer has been destroyed, the result is not specified. Many compositors are known to remove the surface content on the following wl_surface.commit, but this behaviour is not universal. Clients seeking to maximise compatibility should not destroy pending buffers and should ensure that they explicitly remove content from surfaces, even after destroying buffers.
2234 func (o *Surface) Attach(buffer *Buffer, x int32, y int32) error {2107 func (o *Surface) Attach(buffer *Buffer, x int32, y int32) error {
2235- if err := o.Context().CheckProxy(o); err != nil {
2236- return err
2237- }
2238 var arg0 wl.Object2108 var arg0 wl.Object
2239 if buffer != nil {2109 if buffer != nil {
2240 arg0 = buffer2110 arg0 = buffer
2241 }2111 }
2242- if err := o.Context().SendRequest(o, 1, arg0, x, y); err != nil {2112+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_surface.attach"}, arg0, x, y); err != nil {
2243 return err2113 return err
2244 }2114 }
2245 return nil2115 return nil
@@ -2247,10 +2117,7 @@ func (o *Surface) Attach(buffer *Buffer, x int32, y int32) error {
2247 2117
2248 // This request is used to describe the regions where the pending buffer is different from the current surface contents, and where the surface therefore needs to be repainted. The compositor ignores the parts of the damage that fall outside of the surface. Damage is double-buffered state, see wl_surface.commit. The damage rectangle is specified in surface-local coordinates, where x and y specify the upper left corner of the damage rectangle. The initial value for pending damage is empty: no damage. wl_surface.damage adds pending damage: the new pending damage is the union of old pending damage and the given rectangle. wl_surface.commit assigns pending damage as the current damage, and clears pending damage. The server will clear the current damage as it repaints the surface. Note! New clients should not use this request. Instead damage can be posted with wl_surface.damage_buffer which uses buffer coordinates instead of surface coordinates.2118 // This request is used to describe the regions where the pending buffer is different from the current surface contents, and where the surface therefore needs to be repainted. The compositor ignores the parts of the damage that fall outside of the surface. Damage is double-buffered state, see wl_surface.commit. The damage rectangle is specified in surface-local coordinates, where x and y specify the upper left corner of the damage rectangle. The initial value for pending damage is empty: no damage. wl_surface.damage adds pending damage: the new pending damage is the union of old pending damage and the given rectangle. wl_surface.commit assigns pending damage as the current damage, and clears pending damage. The server will clear the current damage as it repaints the surface. Note! New clients should not use this request. Instead damage can be posted with wl_surface.damage_buffer which uses buffer coordinates instead of surface coordinates.
2249 func (o *Surface) Damage(x int32, y int32, width int32, height int32) error {2119 func (o *Surface) Damage(x int32, y int32, width int32, height int32) error {
2250- if err := o.Context().CheckProxy(o); err != nil {2120+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_surface.damage"}, x, y, width, height); err != nil {
2251- return err
2252- }
2253- if err := o.Context().SendRequest(o, 2, x, y, width, height); err != nil {
2254 return err2121 return err
2255 }2122 }
2256 return nil2123 return nil
@@ -2258,15 +2125,9 @@ func (o *Surface) Damage(x int32, y int32, width int32, height int32) error {
2258 2125
2259 // Request a notification when it is a good time to start drawing a new frame, by creating a frame callback. This is useful for throttling redrawing operations, and driving animations. When a client is animating on a wl_surface, it can use the 'frame' request to get notified when it is a good time to draw and commit the next frame of animation. If the client commits an update earlier than that, it is likely that some updates will not make it to the display, and the client is wasting resources by drawing too often. The frame request will take effect on the next wl_surface.commit. The notification will only be posted for one frame unless requested again. For a wl_surface, the notifications are posted in the order the frame requests were committed. The server must send the notifications so that a client will not send excessive updates, while still allowing the highest possible update rate for clients that wait for the reply before drawing again. The server should give some time for the client to draw and commit after sending the frame callback events to let it hit the next output refresh. A server should avoid signaling the frame callbacks if the surface is not visible in any way, e.g. the surface is off-screen, or completely obscured by other opaque surfaces. The object returned by this request will be destroyed by the compositor after the callback is fired and as such the client must not attempt to use it after that point. The callback_data passed in the callback is the current time, in milliseconds, with an undefined base.2126 // Request a notification when it is a good time to start drawing a new frame, by creating a frame callback. This is useful for throttling redrawing operations, and driving animations. When a client is animating on a wl_surface, it can use the 'frame' request to get notified when it is a good time to draw and commit the next frame of animation. If the client commits an update earlier than that, it is likely that some updates will not make it to the display, and the client is wasting resources by drawing too often. The frame request will take effect on the next wl_surface.commit. The notification will only be posted for one frame unless requested again. For a wl_surface, the notifications are posted in the order the frame requests were committed. The server must send the notifications so that a client will not send excessive updates, while still allowing the highest possible update rate for clients that wait for the reply before drawing again. The server should give some time for the client to draw and commit after sending the frame callback events to let it hit the next output refresh. A server should avoid signaling the frame callbacks if the surface is not visible in any way, e.g. the surface is off-screen, or completely obscured by other opaque surfaces. The object returned by this request will be destroyed by the compositor after the callback is fired and as such the client must not attempt to use it after that point. The callback_data passed in the callback is the current time, in milliseconds, with an undefined base.
2260 func (o *Surface) Frame() (*Callback, error) {2127 func (o *Surface) Frame() (*Callback, error) {
2261- if err := o.Context().CheckProxy(o); err != nil {
2262- return nil, err
2263- }
2264 child := &Callback{}2128 child := &Callback{}
2265 child.SetContext(o.Context())2129 child.SetContext(o.Context())
2266- child.SetID(o.Context().AllocateID())2130+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "wl_surface.frame", Child: child}, child); err != nil {
2267- o.Context().Register(child)
2268- if err := o.Context().SendRequest(o, 3, child); err != nil {
2269- o.Context().Unregister(child)
2270 return nil, err2131 return nil, err
2271 }2132 }
2272 return child, nil2133 return child, nil
@@ -2274,14 +2135,11 @@ func (o *Surface) Frame() (*Callback, error) {
2274 2135
2275 // This request sets the region of the surface that contains opaque content. The opaque region is an optimization hint for the compositor that lets it optimize the redrawing of content behind opaque regions. Setting an opaque region is not required for correct behaviour, but marking transparent content as opaque will result in repaint artifacts. The opaque region is specified in surface-local coordinates. The compositor ignores the parts of the opaque region that fall outside of the surface. Opaque region is double-buffered state, see wl_surface.commit. wl_surface.set_opaque_region changes the pending opaque region. wl_surface.commit copies the pending region to the current region. Otherwise, the pending and current regions are never changed. The initial value for an opaque region is empty. Setting the pending opaque region has copy semantics, and the wl_region object can be destroyed immediately. A NULL wl_region causes the pending opaque region to be set to empty.2136 // This request sets the region of the surface that contains opaque content. The opaque region is an optimization hint for the compositor that lets it optimize the redrawing of content behind opaque regions. Setting an opaque region is not required for correct behaviour, but marking transparent content as opaque will result in repaint artifacts. The opaque region is specified in surface-local coordinates. The compositor ignores the parts of the opaque region that fall outside of the surface. Opaque region is double-buffered state, see wl_surface.commit. wl_surface.set_opaque_region changes the pending opaque region. wl_surface.commit copies the pending region to the current region. Otherwise, the pending and current regions are never changed. The initial value for an opaque region is empty. Setting the pending opaque region has copy semantics, and the wl_region object can be destroyed immediately. A NULL wl_region causes the pending opaque region to be set to empty.
2276 func (o *Surface) SetOpaqueRegion(region *Region) error {2137 func (o *Surface) SetOpaqueRegion(region *Region) error {
2277- if err := o.Context().CheckProxy(o); err != nil {
2278- return err
2279- }
2280 var arg0 wl.Object2138 var arg0 wl.Object
2281 if region != nil {2139 if region != nil {
2282 arg0 = region2140 arg0 = region
2283 }2141 }
2284- if err := o.Context().SendRequest(o, 4, arg0); err != nil {2142+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "wl_surface.set_opaque_region"}, arg0); err != nil {
2285 return err2143 return err
2286 }2144 }
2287 return nil2145 return nil
@@ -2289,14 +2147,11 @@ func (o *Surface) SetOpaqueRegion(region *Region) error {
2289 2147
2290 // This request sets the region of the surface that can receive pointer and touch events. Input events happening outside of this region will try the next surface in the server surface stack. The compositor ignores the parts of the input region that fall outside of the surface. The input region is specified in surface-local coordinates. Input region is double-buffered state, see wl_surface.commit. wl_surface.set_input_region changes the pending input region. wl_surface.commit copies the pending region to the current region. Otherwise the pending and current regions are never changed, except cursor and icon surfaces are special cases, see wl_pointer.set_cursor and wl_data_device.start_drag. The initial value for an input region is infinite. That means the whole surface will accept input. Setting the pending input region has copy semantics, and the wl_region object can be destroyed immediately. A NULL wl_region causes the input region to be set to infinite.2148 // This request sets the region of the surface that can receive pointer and touch events. Input events happening outside of this region will try the next surface in the server surface stack. The compositor ignores the parts of the input region that fall outside of the surface. The input region is specified in surface-local coordinates. Input region is double-buffered state, see wl_surface.commit. wl_surface.set_input_region changes the pending input region. wl_surface.commit copies the pending region to the current region. Otherwise the pending and current regions are never changed, except cursor and icon surfaces are special cases, see wl_pointer.set_cursor and wl_data_device.start_drag. The initial value for an input region is infinite. That means the whole surface will accept input. Setting the pending input region has copy semantics, and the wl_region object can be destroyed immediately. A NULL wl_region causes the input region to be set to infinite.
2291 func (o *Surface) SetInputRegion(region *Region) error {2149 func (o *Surface) SetInputRegion(region *Region) error {
2292- if err := o.Context().CheckProxy(o); err != nil {
2293- return err
2294- }
2295 var arg0 wl.Object2150 var arg0 wl.Object
2296 if region != nil {2151 if region != nil {
2297 arg0 = region2152 arg0 = region
2298 }2153 }
2299- if err := o.Context().SendRequest(o, 5, arg0); err != nil {2154+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 5, Name: "wl_surface.set_input_region"}, arg0); err != nil {
2300 return err2155 return err
2301 }2156 }
2302 return nil2157 return nil
@@ -2304,10 +2159,7 @@ func (o *Surface) SetInputRegion(region *Region) error {
2304 2159
2305 // Surface state (input, opaque, and damage regions, attached buffers, etc.) is double-buffered. Protocol requests modify the pending state, as opposed to the active state in use by the compositor. All requests that need a commit to become effective are documented to affect double-buffered state. Other interfaces may add further double-buffered surface state. A commit request atomically creates a Content Update (CU) from the pending state, even if the pending state has not been touched. The content update is placed at the end of a per-surface queue until it becomes active. After commit, the new pending state is as documented for each related request. A CU is either a Desync Content Update (DCU) or a Sync Content Update (SCU). If the surface is effectively synchronized at the commit request, it is a SCU, otherwise a DCU. When a surface transitions from effectively synchronized to effectively desynchronized, all SCUs in its queue which are not reachable by any DCU become DCUs and dependency edges from outside the queue to these CUs are removed. See wl_subsurface for the definition of 'effectively synchronized' and 'effectively desynchronized'. When a CU is placed in the queue, the CU has a dependency on the CU in front of it and to the SCU at end of the queue of every direct child surface if that SCU exists and does not have another dependent. This can form a directed acyclic graph of CUs with dependencies as edges. In addition to surface state, the CU can have constraints that must be satisfied before it can be applied. Other interfaces may add CU constraints. All DCUs which do not have a SCU in front of themselves in their queue, are candidates. If the graph that's reachable by a candidate does not have any unsatisfied constraints, the entire graph must be applied atomically. When a CU is applied, the wl_buffer is applied before all other state. This means that all coordinates in double-buffered state are relative to the newly attached wl_buffers, except for wl_surface.attach itself. If there is no newly attached wl_buffer, the coordinates are relative to the previous content update.2160 // Surface state (input, opaque, and damage regions, attached buffers, etc.) is double-buffered. Protocol requests modify the pending state, as opposed to the active state in use by the compositor. All requests that need a commit to become effective are documented to affect double-buffered state. Other interfaces may add further double-buffered surface state. A commit request atomically creates a Content Update (CU) from the pending state, even if the pending state has not been touched. The content update is placed at the end of a per-surface queue until it becomes active. After commit, the new pending state is as documented for each related request. A CU is either a Desync Content Update (DCU) or a Sync Content Update (SCU). If the surface is effectively synchronized at the commit request, it is a SCU, otherwise a DCU. When a surface transitions from effectively synchronized to effectively desynchronized, all SCUs in its queue which are not reachable by any DCU become DCUs and dependency edges from outside the queue to these CUs are removed. See wl_subsurface for the definition of 'effectively synchronized' and 'effectively desynchronized'. When a CU is placed in the queue, the CU has a dependency on the CU in front of it and to the SCU at end of the queue of every direct child surface if that SCU exists and does not have another dependent. This can form a directed acyclic graph of CUs with dependencies as edges. In addition to surface state, the CU can have constraints that must be satisfied before it can be applied. Other interfaces may add CU constraints. All DCUs which do not have a SCU in front of themselves in their queue, are candidates. If the graph that's reachable by a candidate does not have any unsatisfied constraints, the entire graph must be applied atomically. When a CU is applied, the wl_buffer is applied before all other state. This means that all coordinates in double-buffered state are relative to the newly attached wl_buffers, except for wl_surface.attach itself. If there is no newly attached wl_buffer, the coordinates are relative to the previous content update.
2306 func (o *Surface) Commit() error {2161 func (o *Surface) Commit() error {
2307- if err := o.Context().CheckProxy(o); err != nil {2162+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 6, Name: "wl_surface.commit"}); err != nil {
2308- return err
2309- }
2310- if err := o.Context().SendRequest(o, 6); err != nil {
2311 return err2163 return err
2312 }2164 }
2313 return nil2165 return nil
@@ -2315,10 +2167,7 @@ func (o *Surface) Commit() error {
2315 2167
2316 // This request sets the transformation that the client has already applied to the content of the buffer. The accepted values for the transform parameter are the values for wl_output.transform. The compositor applies the inverse of this transformation whenever it uses the buffer contents. Buffer transform is double-buffered state, see wl_surface.commit. A newly created surface has its buffer transformation set to normal. wl_surface.set_buffer_transform changes the pending buffer transformation. wl_surface.commit copies the pending buffer transformation to the current one. Otherwise, the pending and current values are never changed. The purpose of this request is to allow clients to render content according to the output transform, thus permitting the compositor to use certain optimizations even if the display is rotated. Using hardware overlays and scanning out a client buffer for fullscreen surfaces are examples of such optimizations. Those optimizations are highly dependent on the compositor implementation, so the use of this request should be considered on a case-by-case basis. Note that if the transform value includes 90 or 270 degree rotation, the width of the buffer will become the surface height and the height of the buffer will become the surface width. If transform is not one of the values from the wl_output.transform enum the invalid_transform protocol error is raised.2168 // This request sets the transformation that the client has already applied to the content of the buffer. The accepted values for the transform parameter are the values for wl_output.transform. The compositor applies the inverse of this transformation whenever it uses the buffer contents. Buffer transform is double-buffered state, see wl_surface.commit. A newly created surface has its buffer transformation set to normal. wl_surface.set_buffer_transform changes the pending buffer transformation. wl_surface.commit copies the pending buffer transformation to the current one. Otherwise, the pending and current values are never changed. The purpose of this request is to allow clients to render content according to the output transform, thus permitting the compositor to use certain optimizations even if the display is rotated. Using hardware overlays and scanning out a client buffer for fullscreen surfaces are examples of such optimizations. Those optimizations are highly dependent on the compositor implementation, so the use of this request should be considered on a case-by-case basis. Note that if the transform value includes 90 or 270 degree rotation, the width of the buffer will become the surface height and the height of the buffer will become the surface width. If transform is not one of the values from the wl_output.transform enum the invalid_transform protocol error is raised.
2317 func (o *Surface) SetBufferTransform(transform int32) error {2169 func (o *Surface) SetBufferTransform(transform int32) error {
2318- if err := o.Context().CheckProxy(o); err != nil {2170+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 7, Name: "wl_surface.set_buffer_transform", Since: 2}, transform); err != nil {
2319- return err
2320- }
2321- if err := o.Context().SendRequest(o, 7, transform); err != nil {
2322 return err2171 return err
2323 }2172 }
2324 return nil2173 return nil
@@ -2326,10 +2175,7 @@ func (o *Surface) SetBufferTransform(transform int32) error {
2326 2175
2327 // This request sets an optional scaling factor on how the compositor interprets the contents of the buffer attached to the window. Buffer scale is double-buffered state, see wl_surface.commit. A newly created surface has its buffer scale set to 1. wl_surface.set_buffer_scale changes the pending buffer scale. wl_surface.commit copies the pending buffer scale to the current one. Otherwise, the pending and current values are never changed. The purpose of this request is to allow clients to supply higher resolution buffer data for use on high resolution outputs. It is intended that you pick the same buffer scale as the scale of the output that the surface is displayed on. This means the compositor can avoid scaling when rendering the surface on that output. Note that if the scale is larger than 1, then you have to attach a buffer that is larger (by a factor of scale in each dimension) than the desired surface size. If scale is not greater than 0 the invalid_scale protocol error is raised.2176 // This request sets an optional scaling factor on how the compositor interprets the contents of the buffer attached to the window. Buffer scale is double-buffered state, see wl_surface.commit. A newly created surface has its buffer scale set to 1. wl_surface.set_buffer_scale changes the pending buffer scale. wl_surface.commit copies the pending buffer scale to the current one. Otherwise, the pending and current values are never changed. The purpose of this request is to allow clients to supply higher resolution buffer data for use on high resolution outputs. It is intended that you pick the same buffer scale as the scale of the output that the surface is displayed on. This means the compositor can avoid scaling when rendering the surface on that output. Note that if the scale is larger than 1, then you have to attach a buffer that is larger (by a factor of scale in each dimension) than the desired surface size. If scale is not greater than 0 the invalid_scale protocol error is raised.
2328 func (o *Surface) SetBufferScale(scale int32) error {2177 func (o *Surface) SetBufferScale(scale int32) error {
2329- if err := o.Context().CheckProxy(o); err != nil {2178+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 8, Name: "wl_surface.set_buffer_scale", Since: 3}, scale); err != nil {
2330- return err
2331- }
2332- if err := o.Context().SendRequest(o, 8, scale); err != nil {
2333 return err2179 return err
2334 }2180 }
2335 return nil2181 return nil
@@ -2337,10 +2183,7 @@ func (o *Surface) SetBufferScale(scale int32) error {
2337 2183
2338 // This request is used to describe the regions where the pending buffer is different from the current surface contents, and where the surface therefore needs to be repainted. The compositor ignores the parts of the damage that fall outside of the surface. Damage is double-buffered state, see wl_surface.commit. The damage rectangle is specified in buffer coordinates, where x and y specify the upper left corner of the damage rectangle. The initial value for pending damage is empty: no damage. wl_surface.damage_buffer adds pending damage: the new pending damage is the union of old pending damage and the given rectangle. wl_surface.commit assigns pending damage as the current damage, and clears pending damage. The server will clear the current damage as it repaints the surface. This request differs from wl_surface.damage in only one way - it takes damage in buffer coordinates instead of surface-local coordinates. While this generally is more intuitive than surface coordinates, it is especially desirable when using wp_viewport or when a drawing library (like EGL) is unaware of buffer scale and buffer transform. Note: Because buffer transformation changes and damage requests may be interleaved in the protocol stream, it is impossible to determine the actual mapping between surface and buffer damage until wl_surface.commit time. Therefore, compositors wishing to take both kinds of damage into account will have to accumulate damage from the two requests separately and only transform from one to the other after receiving the wl_surface.commit.2184 // This request is used to describe the regions where the pending buffer is different from the current surface contents, and where the surface therefore needs to be repainted. The compositor ignores the parts of the damage that fall outside of the surface. Damage is double-buffered state, see wl_surface.commit. The damage rectangle is specified in buffer coordinates, where x and y specify the upper left corner of the damage rectangle. The initial value for pending damage is empty: no damage. wl_surface.damage_buffer adds pending damage: the new pending damage is the union of old pending damage and the given rectangle. wl_surface.commit assigns pending damage as the current damage, and clears pending damage. The server will clear the current damage as it repaints the surface. This request differs from wl_surface.damage in only one way - it takes damage in buffer coordinates instead of surface-local coordinates. While this generally is more intuitive than surface coordinates, it is especially desirable when using wp_viewport or when a drawing library (like EGL) is unaware of buffer scale and buffer transform. Note: Because buffer transformation changes and damage requests may be interleaved in the protocol stream, it is impossible to determine the actual mapping between surface and buffer damage until wl_surface.commit time. Therefore, compositors wishing to take both kinds of damage into account will have to accumulate damage from the two requests separately and only transform from one to the other after receiving the wl_surface.commit.
2339 func (o *Surface) DamageBuffer(x int32, y int32, width int32, height int32) error {2185 func (o *Surface) DamageBuffer(x int32, y int32, width int32, height int32) error {
2340- if err := o.Context().CheckProxy(o); err != nil {2186+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 9, Name: "wl_surface.damage_buffer", Since: 4}, x, y, width, height); err != nil {
2341- return err
2342- }
2343- if err := o.Context().SendRequest(o, 9, x, y, width, height); err != nil {
2344 return err2187 return err
2345 }2188 }
2346 return nil2189 return nil
@@ -2348,10 +2191,7 @@ func (o *Surface) DamageBuffer(x int32, y int32, width int32, height int32) erro
2348 2191
2349 // The x and y arguments specify the location of the new pending buffer's upper left corner, relative to the current buffer's upper left corner, in surface-local coordinates. In other words, the x and y, combined with the new surface size define in which directions the surface's size changes. The exact semantics of wl_surface.offset are role-specific. Refer to the documentation of specific roles for more information. Surface location offset is double-buffered state, see wl_surface.commit. This request is semantically equivalent to and the replaces the x and y arguments in the wl_surface.attach request in wl_surface versions prior to 5. See wl_surface.attach for details.2192 // The x and y arguments specify the location of the new pending buffer's upper left corner, relative to the current buffer's upper left corner, in surface-local coordinates. In other words, the x and y, combined with the new surface size define in which directions the surface's size changes. The exact semantics of wl_surface.offset are role-specific. Refer to the documentation of specific roles for more information. Surface location offset is double-buffered state, see wl_surface.commit. This request is semantically equivalent to and the replaces the x and y arguments in the wl_surface.attach request in wl_surface versions prior to 5. See wl_surface.attach for details.
2350 func (o *Surface) Offset(x int32, y int32) error {2193 func (o *Surface) Offset(x int32, y int32) error {
2351- if err := o.Context().CheckProxy(o); err != nil {2194+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 10, Name: "wl_surface.offset", Since: 5}, x, y); err != nil {
2352- return err
2353- }
2354- if err := o.Context().SendRequest(o, 10, x, y); err != nil {
2355 return err2195 return err
2356 }2196 }
2357 return nil2197 return nil
@@ -2359,15 +2199,9 @@ func (o *Surface) Offset(x int32, y int32) error {
2359 2199
2360 // Create a callback for the release of the buffer attached by the client with wl_surface.attach. The compositor will release the buffer when it has finished its usage of the underlying storage for the relevant commit. Once the client receives this event, and assuming the associated buffer is not pending release from other wl_surface.commit requests, the client can safely re-use the buffer. Release callbacks are double-buffered state, and will be associated with the pending buffer at wl_surface.commit time. The callback_data passed in the wl_callback.done event is unused and is always zero. Sending this request without attaching a non-null buffer in the same content update is a protocol error. The compositor will send the no_buffer error in this case.2200 // Create a callback for the release of the buffer attached by the client with wl_surface.attach. The compositor will release the buffer when it has finished its usage of the underlying storage for the relevant commit. Once the client receives this event, and assuming the associated buffer is not pending release from other wl_surface.commit requests, the client can safely re-use the buffer. Release callbacks are double-buffered state, and will be associated with the pending buffer at wl_surface.commit time. The callback_data passed in the wl_callback.done event is unused and is always zero. Sending this request without attaching a non-null buffer in the same content update is a protocol error. The compositor will send the no_buffer error in this case.
2361 func (o *Surface) GetRelease() (*Callback, error) {2201 func (o *Surface) GetRelease() (*Callback, error) {
2362- if err := o.Context().CheckProxy(o); err != nil {
2363- return nil, err
2364- }
2365 child := &Callback{}2202 child := &Callback{}
2366 child.SetContext(o.Context())2203 child.SetContext(o.Context())
2367- child.SetID(o.Context().AllocateID())2204+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 11, Name: "wl_surface.get_release", Since: 7, Child: child}, child); err != nil {
2368- o.Context().Register(child)
2369- if err := o.Context().SendRequest(o, 11, child); err != nil {
2370- o.Context().Unregister(child)
2371 return nil, err2205 return nil, err
2372 }2206 }
2373 return child, nil2207 return child, nil
@@ -2535,15 +2369,9 @@ func NewSeat(ctx *wl.Context) *Seat {
2535 2369
2536 // The ID provided will be initialized to the wl_pointer interface for this seat. This request only takes effect if the seat has the pointer capability, or has had the pointer capability in the past. It is a protocol violation to issue this request on a seat that has never had the pointer capability. The missing_capability error will be sent in this case.2370 // The ID provided will be initialized to the wl_pointer interface for this seat. This request only takes effect if the seat has the pointer capability, or has had the pointer capability in the past. It is a protocol violation to issue this request on a seat that has never had the pointer capability. The missing_capability error will be sent in this case.
2537 func (o *Seat) GetPointer() (*Pointer, error) {2371 func (o *Seat) GetPointer() (*Pointer, error) {
2538- if err := o.Context().CheckProxy(o); err != nil {
2539- return nil, err
2540- }
2541 child := &Pointer{}2372 child := &Pointer{}
2542 child.SetContext(o.Context())2373 child.SetContext(o.Context())
2543- child.SetID(o.Context().AllocateID())2374+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_seat.get_pointer", Child: child}, child); err != nil {
2544- o.Context().Register(child)
2545- if err := o.Context().SendRequest(o, 0, child); err != nil {
2546- o.Context().Unregister(child)
2547 return nil, err2375 return nil, err
2548 }2376 }
2549 return child, nil2377 return child, nil
@@ -2551,15 +2379,9 @@ func (o *Seat) GetPointer() (*Pointer, error) {
2551 2379
2552 // The ID provided will be initialized to the wl_keyboard interface for this seat. This request only takes effect if the seat has the keyboard capability, or has had the keyboard capability in the past. It is a protocol violation to issue this request on a seat that has never had the keyboard capability. The missing_capability error will be sent in this case.2380 // The ID provided will be initialized to the wl_keyboard interface for this seat. This request only takes effect if the seat has the keyboard capability, or has had the keyboard capability in the past. It is a protocol violation to issue this request on a seat that has never had the keyboard capability. The missing_capability error will be sent in this case.
2553 func (o *Seat) GetKeyboard() (*Keyboard, error) {2381 func (o *Seat) GetKeyboard() (*Keyboard, error) {
2554- if err := o.Context().CheckProxy(o); err != nil {
2555- return nil, err
2556- }
2557 child := &Keyboard{}2382 child := &Keyboard{}
2558 child.SetContext(o.Context())2383 child.SetContext(o.Context())
2559- child.SetID(o.Context().AllocateID())2384+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_seat.get_keyboard", Child: child}, child); err != nil {
2560- o.Context().Register(child)
2561- if err := o.Context().SendRequest(o, 1, child); err != nil {
2562- o.Context().Unregister(child)
2563 return nil, err2385 return nil, err
2564 }2386 }
2565 return child, nil2387 return child, nil
@@ -2567,15 +2389,9 @@ func (o *Seat) GetKeyboard() (*Keyboard, error) {
2567 2389
2568 // The ID provided will be initialized to the wl_touch interface for this seat. This request only takes effect if the seat has the touch capability, or has had the touch capability in the past. It is a protocol violation to issue this request on a seat that has never had the touch capability. The missing_capability error will be sent in this case.2390 // The ID provided will be initialized to the wl_touch interface for this seat. This request only takes effect if the seat has the touch capability, or has had the touch capability in the past. It is a protocol violation to issue this request on a seat that has never had the touch capability. The missing_capability error will be sent in this case.
2569 func (o *Seat) GetTouch() (*Touch, error) {2391 func (o *Seat) GetTouch() (*Touch, error) {
2570- if err := o.Context().CheckProxy(o); err != nil {
2571- return nil, err
2572- }
2573 child := &Touch{}2392 child := &Touch{}
2574 child.SetContext(o.Context())2393 child.SetContext(o.Context())
2575- child.SetID(o.Context().AllocateID())2394+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_seat.get_touch", Child: child}, child); err != nil {
2576- o.Context().Register(child)
2577- if err := o.Context().SendRequest(o, 2, child); err != nil {
2578- o.Context().Unregister(child)
2579 return nil, err2395 return nil, err
2580 }2396 }
2581 return child, nil2397 return child, nil
@@ -2583,10 +2399,7 @@ func (o *Seat) GetTouch() (*Touch, error) {
2583 2399
2584 // Using this request a client can tell the server that it is not going to use the seat object anymore.2400 // Using this request a client can tell the server that it is not going to use the seat object anymore.
2585 func (o *Seat) Release() error {2401 func (o *Seat) Release() error {
2586- if err := o.Context().CheckProxy(o); err != nil {2402+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "wl_seat.release", Since: 5, Destructor: true}); err != nil {
2587- return err
2588- }
2589- if err := o.Context().SendDestructor(o, 3); err != nil {
2590 return err2403 return err
2591 }2404 }
2592 return nil2405 return nil
@@ -2702,14 +2515,11 @@ func NewPointer(ctx *wl.Context) *Pointer {
2702 2515
2703 // Set the pointer surface, i.e., the surface that contains the pointer image (cursor). This request gives the surface the role of a cursor. If the surface already has another role, it raises a protocol error. The cursor actually changes only if the pointer focus for this device is one of the requesting client's surfaces or the surface parameter is the current pointer surface. If there was a previous surface set with this request it is replaced. If surface is NULL, the pointer image is hidden. The parameters hotspot_x and hotspot_y define the position of the pointer surface relative to the pointer location. Its top-left corner is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the coordinates of the pointer location, in surface-local coordinates. On wl_surface.offset requests to the pointer surface, hotspot_x and hotspot_y are decremented by the x and y parameters passed to the request. The offset must be applied by wl_surface.commit as usual. The hotspot can also be updated by passing the currently set pointer surface to this request with new values for hotspot_x and hotspot_y. The input region is ignored for wl_surfaces with the role of a cursor. When the use as a cursor ends, the wl_surface is unmapped. The serial parameter must match the latest wl_pointer.enter serial number sent to the client. Otherwise the request will be ignored.2516 // Set the pointer surface, i.e., the surface that contains the pointer image (cursor). This request gives the surface the role of a cursor. If the surface already has another role, it raises a protocol error. The cursor actually changes only if the pointer focus for this device is one of the requesting client's surfaces or the surface parameter is the current pointer surface. If there was a previous surface set with this request it is replaced. If surface is NULL, the pointer image is hidden. The parameters hotspot_x and hotspot_y define the position of the pointer surface relative to the pointer location. Its top-left corner is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the coordinates of the pointer location, in surface-local coordinates. On wl_surface.offset requests to the pointer surface, hotspot_x and hotspot_y are decremented by the x and y parameters passed to the request. The offset must be applied by wl_surface.commit as usual. The hotspot can also be updated by passing the currently set pointer surface to this request with new values for hotspot_x and hotspot_y. The input region is ignored for wl_surfaces with the role of a cursor. When the use as a cursor ends, the wl_surface is unmapped. The serial parameter must match the latest wl_pointer.enter serial number sent to the client. Otherwise the request will be ignored.
2704 func (o *Pointer) SetCursor(serial uint32, surface *Surface, hotspotX int32, hotspotY int32) error {2517 func (o *Pointer) SetCursor(serial uint32, surface *Surface, hotspotX int32, hotspotY int32) error {
2705- if err := o.Context().CheckProxy(o); err != nil {
2706- return err
2707- }
2708 var arg1 wl.Object2518 var arg1 wl.Object
2709 if surface != nil {2519 if surface != nil {
2710 arg1 = surface2520 arg1 = surface
2711 }2521 }
2712- if err := o.Context().SendRequest(o, 0, serial, arg1, hotspotX, hotspotY); err != nil {2522+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_pointer.set_cursor"}, serial, arg1, hotspotX, hotspotY); err != nil {
2713 return err2523 return err
2714 }2524 }
2715 return nil2525 return nil
@@ -2717,10 +2527,7 @@ func (o *Pointer) SetCursor(serial uint32, surface *Surface, hotspotX int32, hot
2717 2527
2718 // Using this request a client can tell the server that it is not going to use the pointer object anymore. This request destroys the pointer proxy object, so clients must not call wl_pointer_destroy() after using this request.2528 // Using this request a client can tell the server that it is not going to use the pointer object anymore. This request destroys the pointer proxy object, so clients must not call wl_pointer_destroy() after using this request.
2719 func (o *Pointer) Release() error {2529 func (o *Pointer) Release() error {
2720- if err := o.Context().CheckProxy(o); err != nil {2530+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_pointer.release", Since: 3, Destructor: true}); err != nil {
2721- return err
2722- }
2723- if err := o.Context().SendDestructor(o, 1); err != nil {
2724 return err2531 return err
2725 }2532 }
2726 return nil2533 return nil
@@ -3155,10 +2962,7 @@ func NewKeyboard(ctx *wl.Context) *Keyboard {
3155 2962
3156 // release the keyboard object2963 // release the keyboard object
3157 func (o *Keyboard) Release() error {2964 func (o *Keyboard) Release() error {
3158- if err := o.Context().CheckProxy(o); err != nil {2965+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_keyboard.release", Since: 3, Destructor: true}); err != nil {
3159- return err
3160- }
3161- if err := o.Context().SendDestructor(o, 0); err != nil {
3162 return err2966 return err
3163 }2967 }
3164 return nil2968 return nil
@@ -3410,10 +3214,7 @@ func NewTouch(ctx *wl.Context) *Touch {
3410 3214
3411 // release the touch object3215 // release the touch object
3412 func (o *Touch) Release() error {3216 func (o *Touch) Release() error {
3413- if err := o.Context().CheckProxy(o); err != nil {3217+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_touch.release", Since: 3, Destructor: true}); err != nil {
3414- return err
3415- }
3416- if err := o.Context().SendDestructor(o, 0); err != nil {
3417 return err3218 return err
3418 }3219 }
3419 return nil3220 return nil
@@ -3689,10 +3490,7 @@ func NewOutput(ctx *wl.Context) *Output {
3689 3490
3690 // Using this request a client can tell the server that it is not going to use the output object anymore.3491 // Using this request a client can tell the server that it is not going to use the output object anymore.
3691 func (o *Output) Release() error {3492 func (o *Output) Release() error {
3692- if err := o.Context().CheckProxy(o); err != nil {3493+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_output.release", Since: 3, Destructor: true}); err != nil {
3693- return err
3694- }
3695- if err := o.Context().SendDestructor(o, 0); err != nil {
3696 return err3494 return err
3697 }3495 }
3698 return nil3496 return nil
@@ -3926,10 +3724,7 @@ func NewRegion(ctx *wl.Context) *Region {
3926 3724
3927 // Destroy the region. This will invalidate the object ID.3725 // Destroy the region. This will invalidate the object ID.
3928 func (o *Region) Destroy() error {3726 func (o *Region) Destroy() error {
3929- if err := o.Context().CheckProxy(o); err != nil {3727+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_region.destroy", Destructor: true}); err != nil {
3930- return err
3931- }
3932- if err := o.Context().SendDestructor(o, 0); err != nil {
3933 return err3728 return err
3934 }3729 }
3935 return nil3730 return nil
@@ -3937,10 +3732,7 @@ func (o *Region) Destroy() error {
3937 3732
3938 // Add the specified rectangle to the region.3733 // Add the specified rectangle to the region.
3939 func (o *Region) Add(x int32, y int32, width int32, height int32) error {3734 func (o *Region) Add(x int32, y int32, width int32, height int32) error {
3940- if err := o.Context().CheckProxy(o); err != nil {3735+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_region.add"}, x, y, width, height); err != nil {
3941- return err
3942- }
3943- if err := o.Context().SendRequest(o, 1, x, y, width, height); err != nil {
3944 return err3736 return err
3945 }3737 }
3946 return nil3738 return nil
@@ -3948,10 +3740,7 @@ func (o *Region) Add(x int32, y int32, width int32, height int32) error {
3948 3740
3949 // Subtract the specified rectangle from the region.3741 // Subtract the specified rectangle from the region.
3950 func (o *Region) Subtract(x int32, y int32, width int32, height int32) error {3742 func (o *Region) Subtract(x int32, y int32, width int32, height int32) error {
3951- if err := o.Context().CheckProxy(o); err != nil {3743+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_region.subtract"}, x, y, width, height); err != nil {
3952- return err
3953- }
3954- if err := o.Context().SendRequest(o, 2, x, y, width, height); err != nil {
3955 return err3744 return err
3956 }3745 }
3957 return nil3746 return nil
@@ -3990,10 +3779,7 @@ func NewSubcompositor(ctx *wl.Context) *Subcompositor {
3990 3779
3991 // Informs the server that the client will not be using this protocol object anymore. This does not affect any other objects, wl_subsurface objects included.3780 // Informs the server that the client will not be using this protocol object anymore. This does not affect any other objects, wl_subsurface objects included.
3992 func (o *Subcompositor) Destroy() error {3781 func (o *Subcompositor) Destroy() error {
3993- if err := o.Context().CheckProxy(o); err != nil {3782+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_subcompositor.destroy", Destructor: true}); err != nil {
3994- return err
3995- }
3996- if err := o.Context().SendDestructor(o, 0); err != nil {
3997 return err3783 return err
3998 }3784 }
3999 return nil3785 return nil
@@ -4001,9 +3787,6 @@ func (o *Subcompositor) Destroy() error {
4001 3787
4002 // Create a sub-surface interface for the given surface, and associate it with the given parent surface. This turns a plain wl_surface into a sub-surface. The to-be sub-surface must not already have another role, and it must not have an existing wl_subsurface object. Otherwise the bad_surface protocol error is raised. Adding sub-surfaces to a parent is a double-buffered operation on the parent (see wl_surface.commit). The effect of adding a sub-surface becomes visible on the next time the state of the parent surface is applied. The parent surface must not be one of the child surface's descendants, and the parent must be different from the child surface, otherwise the bad_parent protocol error is raised. This request modifies the behaviour of wl_surface.commit request on the sub-surface, see the documentation on wl_subsurface interface.3788 // Create a sub-surface interface for the given surface, and associate it with the given parent surface. This turns a plain wl_surface into a sub-surface. The to-be sub-surface must not already have another role, and it must not have an existing wl_subsurface object. Otherwise the bad_surface protocol error is raised. Adding sub-surfaces to a parent is a double-buffered operation on the parent (see wl_surface.commit). The effect of adding a sub-surface becomes visible on the next time the state of the parent surface is applied. The parent surface must not be one of the child surface's descendants, and the parent must be different from the child surface, otherwise the bad_parent protocol error is raised. This request modifies the behaviour of wl_surface.commit request on the sub-surface, see the documentation on wl_subsurface interface.
4003 func (o *Subcompositor) GetSubsurface(surface *Surface, parent *Surface) (*Subsurface, error) {3789 func (o *Subcompositor) GetSubsurface(surface *Surface, parent *Surface) (*Subsurface, error) {
4004- if err := o.Context().CheckProxy(o); err != nil {
4005- return nil, err
4006- }
4007 var arg1 wl.Object3790 var arg1 wl.Object
4008 if surface != nil {3791 if surface != nil {
4009 arg1 = surface3792 arg1 = surface
@@ -4014,10 +3797,7 @@ func (o *Subcompositor) GetSubsurface(surface *Surface, parent *Surface) (*Subsu
4014 }3797 }
4015 child := &Subsurface{}3798 child := &Subsurface{}
4016 child.SetContext(o.Context())3799 child.SetContext(o.Context())
4017- child.SetID(o.Context().AllocateID())3800+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_subcompositor.get_subsurface", Child: child}, child, arg1, arg2); err != nil {
4018- o.Context().Register(child)
4019- if err := o.Context().SendRequest(o, 1, child, arg1, arg2); err != nil {
4020- o.Context().Unregister(child)
4021 return nil, err3801 return nil, err
4022 }3802 }
4023 return child, nil3803 return child, nil
@@ -4056,10 +3836,7 @@ func NewSubsurface(ctx *wl.Context) *Subsurface {
4056 3836
4057 // The sub-surface interface is removed from the wl_surface object that was turned into a sub-surface with a wl_subcompositor.get_subsurface request. The wl_surface's association to the parent is deleted. The wl_surface is unmapped immediately.3837 // The sub-surface interface is removed from the wl_surface object that was turned into a sub-surface with a wl_subcompositor.get_subsurface request. The wl_surface's association to the parent is deleted. The wl_surface is unmapped immediately.
4058 func (o *Subsurface) Destroy() error {3838 func (o *Subsurface) Destroy() error {
4059- if err := o.Context().CheckProxy(o); err != nil {3839+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_subsurface.destroy", Destructor: true}); err != nil {
4060- return err
4061- }
4062- if err := o.Context().SendDestructor(o, 0); err != nil {
4063 return err3840 return err
4064 }3841 }
4065 return nil3842 return nil
@@ -4067,10 +3844,7 @@ func (o *Subsurface) Destroy() error {
4067 3844
4068 // This sets the position of the sub-surface, relative to the parent surface. The sub-surface will be moved so that its origin (top left corner pixel) will be at the location x, y of the parent surface coordinate system. The coordinates are not restricted to the parent surface area. Negative values are allowed. The initial position is 0, 0. Position is double-buffered state on the parent surface, see wl_subsurface and wl_surface.commit for more information.3845 // This sets the position of the sub-surface, relative to the parent surface. The sub-surface will be moved so that its origin (top left corner pixel) will be at the location x, y of the parent surface coordinate system. The coordinates are not restricted to the parent surface area. Negative values are allowed. The initial position is 0, 0. Position is double-buffered state on the parent surface, see wl_subsurface and wl_surface.commit for more information.
4069 func (o *Subsurface) SetPosition(x int32, y int32) error {3846 func (o *Subsurface) SetPosition(x int32, y int32) error {
4070- if err := o.Context().CheckProxy(o); err != nil {3847+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_subsurface.set_position"}, x, y); err != nil {
4071- return err
4072- }
4073- if err := o.Context().SendRequest(o, 1, x, y); err != nil {
4074 return err3848 return err
4075 }3849 }
4076 return nil3850 return nil
@@ -4078,14 +3852,11 @@ func (o *Subsurface) SetPosition(x int32, y int32) error {
4078 3852
4079 // This sub-surface is taken from the stack, and put back just above the reference surface, changing the z-order of the sub-surfaces. The reference surface must be one of the sibling surfaces, or the parent surface. Using any other surface, including this sub-surface, will cause a protocol error. A new sub-surface is initially added as the top-most in the stack of its siblings and parent. Z-order is double-buffered state on the parent surface, see wl_subsurface and wl_surface.commit for more information.3853 // This sub-surface is taken from the stack, and put back just above the reference surface, changing the z-order of the sub-surfaces. The reference surface must be one of the sibling surfaces, or the parent surface. Using any other surface, including this sub-surface, will cause a protocol error. A new sub-surface is initially added as the top-most in the stack of its siblings and parent. Z-order is double-buffered state on the parent surface, see wl_subsurface and wl_surface.commit for more information.
4080 func (o *Subsurface) PlaceAbove(sibling *Surface) error {3854 func (o *Subsurface) PlaceAbove(sibling *Surface) error {
4081- if err := o.Context().CheckProxy(o); err != nil {
4082- return err
4083- }
4084 var arg0 wl.Object3855 var arg0 wl.Object
4085 if sibling != nil {3856 if sibling != nil {
4086 arg0 = sibling3857 arg0 = sibling
4087 }3858 }
4088- if err := o.Context().SendRequest(o, 2, arg0); err != nil {3859+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_subsurface.place_above"}, arg0); err != nil {
4089 return err3860 return err
4090 }3861 }
4091 return nil3862 return nil
@@ -4093,14 +3864,11 @@ func (o *Subsurface) PlaceAbove(sibling *Surface) error {
4093 3864
4094 // The sub-surface is placed just below the reference surface. See wl_subsurface.place_above.3865 // The sub-surface is placed just below the reference surface. See wl_subsurface.place_above.
4095 func (o *Subsurface) PlaceBelow(sibling *Surface) error {3866 func (o *Subsurface) PlaceBelow(sibling *Surface) error {
4096- if err := o.Context().CheckProxy(o); err != nil {
4097- return err
4098- }
4099 var arg0 wl.Object3867 var arg0 wl.Object
4100 if sibling != nil {3868 if sibling != nil {
4101 arg0 = sibling3869 arg0 = sibling
4102 }3870 }
4103- if err := o.Context().SendRequest(o, 3, arg0); err != nil {3871+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "wl_subsurface.place_below"}, arg0); err != nil {
4104 return err3872 return err
4105 }3873 }
4106 return nil3874 return nil
@@ -4108,10 +3876,7 @@ func (o *Subsurface) PlaceBelow(sibling *Surface) error {
4108 3876
4109 // Change the commit behaviour of the sub-surface to synchronized mode. See wl_subsurface and wl_surface.commit for more information.3877 // Change the commit behaviour of the sub-surface to synchronized mode. See wl_subsurface and wl_surface.commit for more information.
4110 func (o *Subsurface) SetSync() error {3878 func (o *Subsurface) SetSync() error {
4111- if err := o.Context().CheckProxy(o); err != nil {3879+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "wl_subsurface.set_sync"}); err != nil {
4112- return err
4113- }
4114- if err := o.Context().SendRequest(o, 4); err != nil {
4115 return err3880 return err
4116 }3881 }
4117 return nil3882 return nil
@@ -4119,10 +3884,7 @@ func (o *Subsurface) SetSync() error {
4119 3884
4120 // Change the commit behaviour of the sub-surface to desynchronized mode. See wl_subsurface and wl_surface.commit for more information.3885 // Change the commit behaviour of the sub-surface to desynchronized mode. See wl_subsurface and wl_surface.commit for more information.
4121 func (o *Subsurface) SetDesync() error {3886 func (o *Subsurface) SetDesync() error {
4122- if err := o.Context().CheckProxy(o); err != nil {3887+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 5, Name: "wl_subsurface.set_desync"}); err != nil {
4123- return err
4124- }
4125- if err := o.Context().SendRequest(o, 5); err != nil {
4126 return err3888 return err
4127 }3889 }
4128 return nil3890 return nil
@@ -4161,10 +3923,7 @@ func NewFixes(ctx *wl.Context) *Fixes {
4161 3923
4162 // destroys this object3924 // destroys this object
4163 func (o *Fixes) Destroy() error {3925 func (o *Fixes) Destroy() error {
4164- if err := o.Context().CheckProxy(o); err != nil {3926+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wl_fixes.destroy", Destructor: true}); err != nil {
4165- return err
4166- }
4167- if err := o.Context().SendDestructor(o, 0); err != nil {
4168 return err3927 return err
4169 }3928 }
4170 return nil3929 return nil
@@ -4172,14 +3931,11 @@ func (o *Fixes) Destroy() error {
4172 3931
4173 // This request destroys a wl_registry object. The client should no longer use the wl_registry after making this request. The compositor will emit a wl_display.delete_id event with the object ID of the registry and will no longer emit any events on the registry. The client should re-use the object ID once it receives the wl_display.delete_id event.3932 // This request destroys a wl_registry object. The client should no longer use the wl_registry after making this request. The compositor will emit a wl_display.delete_id event with the object ID of the registry and will no longer emit any events on the registry. The client should re-use the object ID once it receives the wl_display.delete_id event.
4174 func (o *Fixes) DestroyRegistry(registry *wl.Registry) error {3933 func (o *Fixes) DestroyRegistry(registry *wl.Registry) error {
4175- if err := o.Context().CheckProxy(o); err != nil {
4176- return err
4177- }
4178 var arg0 wl.Object3934 var arg0 wl.Object
4179 if registry != nil {3935 if registry != nil {
4180 arg0 = registry3936 arg0 = registry
4181 }3937 }
4182- if err := o.Context().SendRequest(o, 1, arg0); err != nil {3938+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wl_fixes.destroy_registry"}, arg0); err != nil {
4183 return err3939 return err
4184 }3940 }
4185 return nil3941 return nil
@@ -4187,14 +3943,11 @@ func (o *Fixes) DestroyRegistry(registry *wl.Registry) error {
4187 3943
4188 // Acknowledge the removal of the specified global. If no global with the specified name exists or the global is not removed, the wl_fixes.invalid_ack_remove protocol error will be posted. Due to the Wayland protocol being asynchronous, the wl_global objects cannot be destroyed immediately. For example, if a wl_global is removed and a client attempts to bind that global around same time, it can result in a protocol error due to an unknown global name in the bind request. In order to avoid crashing clients, the compositor should remove the wl_global once it is guaranteed that no more bind requests will come. The wl_fixes.ack_global_remove() request is used to signal to the compositor that the client will not bind the given global anymore. After all clients acknowledge the removal of the global, the compositor can safely destroy it. The client must call the wl_fixes.ack_global_remove() request in response to a wl_registry.global_remove() event even if it did not bind the corresponding global.3944 // Acknowledge the removal of the specified global. If no global with the specified name exists or the global is not removed, the wl_fixes.invalid_ack_remove protocol error will be posted. Due to the Wayland protocol being asynchronous, the wl_global objects cannot be destroyed immediately. For example, if a wl_global is removed and a client attempts to bind that global around same time, it can result in a protocol error due to an unknown global name in the bind request. In order to avoid crashing clients, the compositor should remove the wl_global once it is guaranteed that no more bind requests will come. The wl_fixes.ack_global_remove() request is used to signal to the compositor that the client will not bind the given global anymore. After all clients acknowledge the removal of the global, the compositor can safely destroy it. The client must call the wl_fixes.ack_global_remove() request in response to a wl_registry.global_remove() event even if it did not bind the corresponding global.
4189 func (o *Fixes) AckGlobalRemove(registry *wl.Registry, name uint32) error {3945 func (o *Fixes) AckGlobalRemove(registry *wl.Registry, name uint32) error {
4190- if err := o.Context().CheckProxy(o); err != nil {
4191- return err
4192- }
4193 var arg0 wl.Object3946 var arg0 wl.Object
4194 if registry != nil {3947 if registry != nil {
4195 arg0 = registry3948 arg0 = registry
4196 }3949 }
4197- if err := o.Context().SendRequest(o, 2, arg0, name); err != nil {3950+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wl_fixes.ack_global_remove", Since: 2}, arg0, name); err != nil {
4198 return err3951 return err
4199 }3952 }
4200 return nil3953 return nil
M protocol/cursorshape/cursor-shape-v1_generated.go +5 -26
@@ -139,10 +139,7 @@ func NewWpCursorShapeManager(ctx *wl.Context) *WpCursorShapeManager {
139139
140140 // Destroy the cursor shape manager.
141141 func (o *WpCursorShapeManager) Destroy() error {
142- if err := o.Context().CheckProxy(o); err != nil {
143- return err
144- }
145- if err := o.Context().SendDestructor(o, 0); err != nil {
142+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_cursor_shape_manager_v1.destroy", Destructor: true}); err != nil {
146143 return err
147144 }
148145 return nil
@@ -150,19 +147,13 @@ func (o *WpCursorShapeManager) Destroy() error {
150147
151148 // Obtain a wp_cursor_shape_device_v1 for a wl_pointer object. When the pointer capability is removed from the wl_seat, the wp_cursor_shape_device_v1 object becomes inert.
152149 func (o *WpCursorShapeManager) GetPointer(pointer *cross_wl_pointer.Pointer) (*WpCursorShapeDevice, error) {
153- if err := o.Context().CheckProxy(o); err != nil {
154- return nil, err
155- }
156150 var arg1 wl.Object
157151 if pointer != nil {
158152 arg1 = pointer
159153 }
160154 child := &WpCursorShapeDevice{}
161155 child.SetContext(o.Context())
162- child.SetID(o.Context().AllocateID())
163- o.Context().Register(child)
164- if err := o.Context().SendRequest(o, 1, child, arg1); err != nil {
165- o.Context().Unregister(child)
156+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wp_cursor_shape_manager_v1.get_pointer", Child: child}, child, arg1); err != nil {
166157 return nil, err
167158 }
168159 return child, nil
@@ -170,19 +161,13 @@ func (o *WpCursorShapeManager) GetPointer(pointer *cross_wl_pointer.Pointer) (*W
170161
171162 // Obtain a wp_cursor_shape_device_v1 for a zwp_tablet_tool_v2 object. When the zwp_tablet_tool_v2 is removed, the wp_cursor_shape_device_v1 object becomes inert.
172163 func (o *WpCursorShapeManager) GetTabletTool(tabletTool *cross_zwp_tablet_tool_v2.TabletTool) (*WpCursorShapeDevice, error) {
173- if err := o.Context().CheckProxy(o); err != nil {
174- return nil, err
175- }
176164 var arg1 wl.Object
177165 if tabletTool != nil {
178166 arg1 = tabletTool
179167 }
180168 child := &WpCursorShapeDevice{}
181169 child.SetContext(o.Context())
182- child.SetID(o.Context().AllocateID())
183- o.Context().Register(child)
184- if err := o.Context().SendRequest(o, 2, child, arg1); err != nil {
185- o.Context().Unregister(child)
170+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wp_cursor_shape_manager_v1.get_tablet_tool_v2", Child: child}, child, arg1); err != nil {
186171 return nil, err
187172 }
188173 return child, nil
@@ -221,10 +206,7 @@ func NewWpCursorShapeDevice(ctx *wl.Context) *WpCursorShapeDevice {
221206
222207 // Destroy the cursor shape device. The device cursor shape remains unchanged.
223208 func (o *WpCursorShapeDevice) Destroy() error {
224- if err := o.Context().CheckProxy(o); err != nil {
225- return err
226- }
227- if err := o.Context().SendDestructor(o, 0); err != nil {
209+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_cursor_shape_device_v1.destroy", Destructor: true}); err != nil {
228210 return err
229211 }
230212 return nil
@@ -232,10 +214,7 @@ func (o *WpCursorShapeDevice) Destroy() error {
232214
233215 // Sets the device cursor to the specified shape. The compositor will change the cursor image based on the specified shape. The cursor actually changes only if the input device focus is one of the requesting client's surfaces. If any, the previous cursor image (surface or shape) is replaced. The "shape" argument must be a valid enum entry, otherwise the invalid_shape protocol error is raised. This is similar to the wl_pointer.set_cursor and zwp_tablet_tool_v2.set_cursor requests, but this request accepts a shape instead of contents in the form of a surface. Clients can mix set_cursor and set_shape requests. The serial parameter must match the latest wl_pointer.enter or zwp_tablet_tool_v2.proximity_in serial number sent to the client. Otherwise the request will be ignored.
234216 func (o *WpCursorShapeDevice) SetShape(serial uint32, shape uint32) error {
235- if err := o.Context().CheckProxy(o); err != nil {
236- return err
237- }
238- if err := o.Context().SendRequest(o, 1, serial, shape); err != nil {
217+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wp_cursor_shape_device_v1.set_shape"}, serial, shape); err != nil {
239218 return err
240219 }
241220 return nil
@@ -139,10 +139,7 @@ func NewWpCursorShapeManager(ctx *wl.Context) *WpCursorShapeManager {
139 139
140 // Destroy the cursor shape manager.140 // Destroy the cursor shape manager.
141 func (o *WpCursorShapeManager) Destroy() error {141 func (o *WpCursorShapeManager) Destroy() error {
142- if err := o.Context().CheckProxy(o); err != nil {142+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_cursor_shape_manager_v1.destroy", Destructor: true}); err != nil {
143- return err
144- }
145- if err := o.Context().SendDestructor(o, 0); err != nil {
146 return err143 return err
147 }144 }
148 return nil145 return nil
@@ -150,19 +147,13 @@ func (o *WpCursorShapeManager) Destroy() error {
150 147
151 // Obtain a wp_cursor_shape_device_v1 for a wl_pointer object. When the pointer capability is removed from the wl_seat, the wp_cursor_shape_device_v1 object becomes inert.148 // Obtain a wp_cursor_shape_device_v1 for a wl_pointer object. When the pointer capability is removed from the wl_seat, the wp_cursor_shape_device_v1 object becomes inert.
152 func (o *WpCursorShapeManager) GetPointer(pointer *cross_wl_pointer.Pointer) (*WpCursorShapeDevice, error) {149 func (o *WpCursorShapeManager) GetPointer(pointer *cross_wl_pointer.Pointer) (*WpCursorShapeDevice, error) {
153- if err := o.Context().CheckProxy(o); err != nil {
154- return nil, err
155- }
156 var arg1 wl.Object150 var arg1 wl.Object
157 if pointer != nil {151 if pointer != nil {
158 arg1 = pointer152 arg1 = pointer
159 }153 }
160 child := &WpCursorShapeDevice{}154 child := &WpCursorShapeDevice{}
161 child.SetContext(o.Context())155 child.SetContext(o.Context())
162- child.SetID(o.Context().AllocateID())156+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wp_cursor_shape_manager_v1.get_pointer", Child: child}, child, arg1); err != nil {
163- o.Context().Register(child)
164- if err := o.Context().SendRequest(o, 1, child, arg1); err != nil {
165- o.Context().Unregister(child)
166 return nil, err157 return nil, err
167 }158 }
168 return child, nil159 return child, nil
@@ -170,19 +161,13 @@ func (o *WpCursorShapeManager) GetPointer(pointer *cross_wl_pointer.Pointer) (*W
170 161
171 // Obtain a wp_cursor_shape_device_v1 for a zwp_tablet_tool_v2 object. When the zwp_tablet_tool_v2 is removed, the wp_cursor_shape_device_v1 object becomes inert.162 // Obtain a wp_cursor_shape_device_v1 for a zwp_tablet_tool_v2 object. When the zwp_tablet_tool_v2 is removed, the wp_cursor_shape_device_v1 object becomes inert.
172 func (o *WpCursorShapeManager) GetTabletTool(tabletTool *cross_zwp_tablet_tool_v2.TabletTool) (*WpCursorShapeDevice, error) {163 func (o *WpCursorShapeManager) GetTabletTool(tabletTool *cross_zwp_tablet_tool_v2.TabletTool) (*WpCursorShapeDevice, error) {
173- if err := o.Context().CheckProxy(o); err != nil {
174- return nil, err
175- }
176 var arg1 wl.Object164 var arg1 wl.Object
177 if tabletTool != nil {165 if tabletTool != nil {
178 arg1 = tabletTool166 arg1 = tabletTool
179 }167 }
180 child := &WpCursorShapeDevice{}168 child := &WpCursorShapeDevice{}
181 child.SetContext(o.Context())169 child.SetContext(o.Context())
182- child.SetID(o.Context().AllocateID())170+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wp_cursor_shape_manager_v1.get_tablet_tool_v2", Child: child}, child, arg1); err != nil {
183- o.Context().Register(child)
184- if err := o.Context().SendRequest(o, 2, child, arg1); err != nil {
185- o.Context().Unregister(child)
186 return nil, err171 return nil, err
187 }172 }
188 return child, nil173 return child, nil
@@ -221,10 +206,7 @@ func NewWpCursorShapeDevice(ctx *wl.Context) *WpCursorShapeDevice {
221 206
222 // Destroy the cursor shape device. The device cursor shape remains unchanged.207 // Destroy the cursor shape device. The device cursor shape remains unchanged.
223 func (o *WpCursorShapeDevice) Destroy() error {208 func (o *WpCursorShapeDevice) Destroy() error {
224- if err := o.Context().CheckProxy(o); err != nil {209+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_cursor_shape_device_v1.destroy", Destructor: true}); err != nil {
225- return err
226- }
227- if err := o.Context().SendDestructor(o, 0); err != nil {
228 return err210 return err
229 }211 }
230 return nil212 return nil
@@ -232,10 +214,7 @@ func (o *WpCursorShapeDevice) Destroy() error {
232 214
233 // Sets the device cursor to the specified shape. The compositor will change the cursor image based on the specified shape. The cursor actually changes only if the input device focus is one of the requesting client's surfaces. If any, the previous cursor image (surface or shape) is replaced. The "shape" argument must be a valid enum entry, otherwise the invalid_shape protocol error is raised. This is similar to the wl_pointer.set_cursor and zwp_tablet_tool_v2.set_cursor requests, but this request accepts a shape instead of contents in the form of a surface. Clients can mix set_cursor and set_shape requests. The serial parameter must match the latest wl_pointer.enter or zwp_tablet_tool_v2.proximity_in serial number sent to the client. Otherwise the request will be ignored.215 // Sets the device cursor to the specified shape. The compositor will change the cursor image based on the specified shape. The cursor actually changes only if the input device focus is one of the requesting client's surfaces. If any, the previous cursor image (surface or shape) is replaced. The "shape" argument must be a valid enum entry, otherwise the invalid_shape protocol error is raised. This is similar to the wl_pointer.set_cursor and zwp_tablet_tool_v2.set_cursor requests, but this request accepts a shape instead of contents in the form of a surface. Clients can mix set_cursor and set_shape requests. The serial parameter must match the latest wl_pointer.enter or zwp_tablet_tool_v2.proximity_in serial number sent to the client. Otherwise the request will be ignored.
234 func (o *WpCursorShapeDevice) SetShape(serial uint32, shape uint32) error {216 func (o *WpCursorShapeDevice) SetShape(serial uint32, shape uint32) error {
235- if err := o.Context().CheckProxy(o); err != nil {217+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wp_cursor_shape_device_v1.set_shape"}, serial, shape); err != nil {
236- return err
237- }
238- if err := o.Context().SendRequest(o, 1, serial, shape); err != nil {
239 return err218 return err
240 }219 }
241 return nil220 return nil
M protocol/drmsyncobj/linux-drm-syncobj-v1_generated.go +7 -35
@@ -51,10 +51,7 @@ func NewWpLinuxDrmSyncobjManager(ctx *wl.Context) *WpLinuxDrmSyncobjManager {
5151
5252 // Destroy this explicit synchronization factory object. Other objects shall not be affected by this request.
5353 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 {
54+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_linux_drm_syncobj_manager_v1.destroy", Destructor: true}); err != nil {
5855 return err
5956 }
6057 return nil
@@ -62,19 +59,13 @@ func (o *WpLinuxDrmSyncobjManager) Destroy() error {
6259
6360 // 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.
6461 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- }
6862 var arg1 wl.Object
6963 if surface != nil {
7064 arg1 = surface
7165 }
7266 child := &WpLinuxDrmSyncobjSurface{}
7367 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)
68+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wp_linux_drm_syncobj_manager_v1.get_surface", Child: child}, child, arg1); err != nil {
7869 return nil, err
7970 }
8071 return child, nil
@@ -82,18 +73,11 @@ func (o *WpLinuxDrmSyncobjManager) GetSurface(surface *cross_wl_surface.Surface)
8273
8374 // Import a DRM synchronization object timeline. If the FD cannot be imported, the invalid_timeline error is raised.
8475 func (o *WpLinuxDrmSyncobjManager) ImportTimeline(fd int) (*WpLinuxDrmSyncobjTimeline, error) {
85- if err := o.Context().CheckProxy(o); err != nil {
86- return nil, err
87- }
8876 child := &WpLinuxDrmSyncobjTimeline{}
8977 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)
78+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wp_linux_drm_syncobj_manager_v1.import_timeline", Child: child, FDs: []int{fd}}, child, uintptr(fd)); err != nil {
9479 return nil, err
9580 }
96- _ = wl.CloseSentFD(fd)
9781 return child, nil
9882 }
9983
@@ -130,10 +114,7 @@ func NewWpLinuxDrmSyncobjTimeline(ctx *wl.Context) *WpLinuxDrmSyncobjTimeline {
130114
131115 // 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.
132116 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 {
117+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_linux_drm_syncobj_timeline_v1.destroy", Destructor: true}); err != nil {
137118 return err
138119 }
139120 return nil
@@ -172,10 +153,7 @@ func NewWpLinuxDrmSyncobjSurface(ctx *wl.Context) *WpLinuxDrmSyncobjSurface {
172153
173154 // 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.
174155 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 {
156+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_linux_drm_syncobj_surface_v1.destroy", Destructor: true}); err != nil {
179157 return err
180158 }
181159 return nil
@@ -183,14 +161,11 @@ func (o *WpLinuxDrmSyncobjSurface) Destroy() error {
183161
184162 // 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.
185163 func (o *WpLinuxDrmSyncobjSurface) SetAcquirePoint(timeline *WpLinuxDrmSyncobjTimeline, pointHi uint32, pointLo uint32) error {
186- if err := o.Context().CheckProxy(o); err != nil {
187- return err
188- }
189164 var arg0 wl.Object
190165 if timeline != nil {
191166 arg0 = timeline
192167 }
193- if err := o.Context().SendRequest(o, 1, arg0, pointHi, pointLo); err != nil {
168+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wp_linux_drm_syncobj_surface_v1.set_acquire_point"}, arg0, pointHi, pointLo); err != nil {
194169 return err
195170 }
196171 return nil
@@ -198,14 +173,11 @@ func (o *WpLinuxDrmSyncobjSurface) SetAcquirePoint(timeline *WpLinuxDrmSyncobjTi
198173
199174 // 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.
200175 func (o *WpLinuxDrmSyncobjSurface) SetReleasePoint(timeline *WpLinuxDrmSyncobjTimeline, pointHi uint32, pointLo uint32) error {
201- if err := o.Context().CheckProxy(o); err != nil {
202- return err
203- }
204176 var arg0 wl.Object
205177 if timeline != nil {
206178 arg0 = timeline
207179 }
208- if err := o.Context().SendRequest(o, 2, arg0, pointHi, pointLo); err != nil {
180+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wp_linux_drm_syncobj_surface_v1.set_release_point"}, arg0, pointHi, pointLo); err != nil {
209181 return err
210182 }
211183 return nil
@@ -51,10 +51,7 @@ func NewWpLinuxDrmSyncobjManager(ctx *wl.Context) *WpLinuxDrmSyncobjManager {
51 51
52 // Destroy this explicit synchronization factory object. Other objects shall not be affected by this request.52 // Destroy this explicit synchronization factory object. Other objects shall not be affected by this request.
53 func (o *WpLinuxDrmSyncobjManager) Destroy() error {53 func (o *WpLinuxDrmSyncobjManager) Destroy() error {
54- if err := o.Context().CheckProxy(o); err != nil {54+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_linux_drm_syncobj_manager_v1.destroy", Destructor: true}); err != nil {
55- return err
56- }
57- if err := o.Context().SendDestructor(o, 0); err != nil {
58 return err55 return err
59 }56 }
60 return nil57 return nil
@@ -62,19 +59,13 @@ func (o *WpLinuxDrmSyncobjManager) Destroy() error {
62 59
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.60 // 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) {61 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.Object62 var arg1 wl.Object
69 if surface != nil {63 if surface != nil {
70 arg1 = surface64 arg1 = surface
71 }65 }
72 child := &WpLinuxDrmSyncobjSurface{}66 child := &WpLinuxDrmSyncobjSurface{}
73 child.SetContext(o.Context())67 child.SetContext(o.Context())
74- child.SetID(o.Context().AllocateID())68+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wp_linux_drm_syncobj_manager_v1.get_surface", Child: child}, child, arg1); err != nil {
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, err69 return nil, err
79 }70 }
80 return child, nil71 return child, nil
@@ -82,18 +73,11 @@ func (o *WpLinuxDrmSyncobjManager) GetSurface(surface *cross_wl_surface.Surface)
82 73
83 // Import a DRM synchronization object timeline. If the FD cannot be imported, the invalid_timeline error is raised.74 // 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) {75 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{}76 child := &WpLinuxDrmSyncobjTimeline{}
89 child.SetContext(o.Context())77 child.SetContext(o.Context())
90- child.SetID(o.Context().AllocateID())78+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wp_linux_drm_syncobj_manager_v1.import_timeline", Child: child, FDs: []int{fd}}, child, uintptr(fd)); err != nil {
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, err79 return nil, err
95 }80 }
96- _ = wl.CloseSentFD(fd)
97 return child, nil81 return child, nil
98 }82 }
99 83
@@ -130,10 +114,7 @@ func NewWpLinuxDrmSyncobjTimeline(ctx *wl.Context) *WpLinuxDrmSyncobjTimeline {
130 114
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.115 // 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 {116 func (o *WpLinuxDrmSyncobjTimeline) Destroy() error {
133- if err := o.Context().CheckProxy(o); err != nil {117+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_linux_drm_syncobj_timeline_v1.destroy", Destructor: true}); err != nil {
134- return err
135- }
136- if err := o.Context().SendDestructor(o, 0); err != nil {
137 return err118 return err
138 }119 }
139 return nil120 return nil
@@ -172,10 +153,7 @@ func NewWpLinuxDrmSyncobjSurface(ctx *wl.Context) *WpLinuxDrmSyncobjSurface {
172 153
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.154 // 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 {155 func (o *WpLinuxDrmSyncobjSurface) Destroy() error {
175- if err := o.Context().CheckProxy(o); err != nil {156+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_linux_drm_syncobj_surface_v1.destroy", Destructor: true}); err != nil {
176- return err
177- }
178- if err := o.Context().SendDestructor(o, 0); err != nil {
179 return err157 return err
180 }158 }
181 return nil159 return nil
@@ -183,14 +161,11 @@ func (o *WpLinuxDrmSyncobjSurface) Destroy() error {
183 161
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.162 // 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 {163 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.Object164 var arg0 wl.Object
190 if timeline != nil {165 if timeline != nil {
191 arg0 = timeline166 arg0 = timeline
192 }167 }
193- if err := o.Context().SendRequest(o, 1, arg0, pointHi, pointLo); err != nil {168+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wp_linux_drm_syncobj_surface_v1.set_acquire_point"}, arg0, pointHi, pointLo); err != nil {
194 return err169 return err
195 }170 }
196 return nil171 return nil
@@ -198,14 +173,11 @@ func (o *WpLinuxDrmSyncobjSurface) SetAcquirePoint(timeline *WpLinuxDrmSyncobjTi
198 173
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.174 // 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 {175 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.Object176 var arg0 wl.Object
205 if timeline != nil {177 if timeline != nil {
206 arg0 = timeline178 arg0 = timeline
207 }179 }
208- if err := o.Context().SendRequest(o, 2, arg0, pointHi, pointLo); err != nil {180+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wp_linux_drm_syncobj_surface_v1.set_release_point"}, arg0, pointHi, pointLo); err != nil {
209 return err181 return err
210 }182 }
211 return nil183 return nil
M protocol/extensions_test.go +6 -2
@@ -4,6 +4,7 @@ package protocol_test
44
55 import (
66 "encoding/binary"
7+ "errors"
78 "net"
89 "os"
910 "strings"
@@ -412,8 +413,11 @@ func TestExtensionsOverSocketpair(t *testing.T) {
412413 request(t, p)
413414 noerr(t, device.Release())
414415 request(t, p)
415- noerr(t, mgr.Release())
416- request(t, p)
416+ // release is a version 4 request; the manager was negotiated at 3, so it
417+ // must be refused locally instead of reaching the compositor.
418+ if err := mgr.Release(); !errors.Is(err, wlturbo.ErrVersionTooLow) {
419+ t.Fatalf("release at v3 = %v, want ErrVersionTooLow", err)
420+ }
417421 // Cursor shape: get a device for a wl_pointer and set a shape at an
418422 // enter serial; check the exact wire arguments.
419423 pointer := core.NewPointer(d.Context())
@@ -4,6 +4,7 @@ package protocol_test
4 4
5 import (5 import (
6 "encoding/binary"6 "encoding/binary"
7+ "errors"
7 "net"8 "net"
8 "os"9 "os"
9 "strings"10 "strings"
@@ -412,8 +413,11 @@ func TestExtensionsOverSocketpair(t *testing.T) {
412 request(t, p)413 request(t, p)
413 noerr(t, device.Release())414 noerr(t, device.Release())
414 request(t, p)415 request(t, p)
415- noerr(t, mgr.Release())416+ // release is a version 4 request; the manager was negotiated at 3, so it
416- request(t, p)417+ // must be refused locally instead of reaching the compositor.
418+ if err := mgr.Release(); !errors.Is(err, wlturbo.ErrVersionTooLow) {
419+ t.Fatalf("release at v3 = %v, want ErrVersionTooLow", err)
420+ }
417 // Cursor shape: get a device for a wl_pointer and set a shape at an421 // Cursor shape: get a device for a wl_pointer and set a shape at an
418 // enter serial; check the exact wire arguments.422 // enter serial; check the exact wire arguments.
419 pointer := core.NewPointer(d.Context())423 pointer := core.NewPointer(d.Context())
M protocol/fractionalscale/fractional-scale-v1_generated.go +3 -15
@@ -32,10 +32,7 @@ func NewWpFractionalScaleManager(ctx *wl.Context) *WpFractionalScaleManager {
3232
3333 // 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.
3434 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 {
35+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_fractional_scale_manager_v1.destroy", Destructor: true}); err != nil {
3936 return err
4037 }
4138 return nil
@@ -43,19 +40,13 @@ func (o *WpFractionalScaleManager) Destroy() error {
4340
4441 // 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.
4542 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- }
4943 var arg1 wl.Object
5044 if surface != nil {
5145 arg1 = surface
5246 }
5347 child := &WpFractionalScale{}
5448 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)
49+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wp_fractional_scale_manager_v1.get_fractional_scale", Child: child}, child, arg1); err != nil {
5950 return nil, err
6051 }
6152 return child, nil
@@ -98,10 +89,7 @@ func NewWpFractionalScale(ctx *wl.Context) *WpFractionalScale {
9889
9990 // Destroy the fractional scale object. When this object is destroyed, preferred_scale events will no longer be sent.
10091 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 {
92+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_fractional_scale_v1.destroy", Destructor: true}); err != nil {
10593 return err
10694 }
10795 return nil
@@ -32,10 +32,7 @@ func NewWpFractionalScaleManager(ctx *wl.Context) *WpFractionalScaleManager {
32 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.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 {34 func (o *WpFractionalScaleManager) Destroy() error {
35- if err := o.Context().CheckProxy(o); err != nil {35+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_fractional_scale_manager_v1.destroy", Destructor: true}); err != nil {
36- return err
37- }
38- if err := o.Context().SendDestructor(o, 0); err != nil {
39 return err36 return err
40 }37 }
41 return nil38 return nil
@@ -43,19 +40,13 @@ func (o *WpFractionalScaleManager) Destroy() error {
43 40
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.41 // 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) {42 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.Object43 var arg1 wl.Object
50 if surface != nil {44 if surface != nil {
51 arg1 = surface45 arg1 = surface
52 }46 }
53 child := &WpFractionalScale{}47 child := &WpFractionalScale{}
54 child.SetContext(o.Context())48 child.SetContext(o.Context())
55- child.SetID(o.Context().AllocateID())49+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wp_fractional_scale_manager_v1.get_fractional_scale", Child: child}, child, arg1); err != nil {
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, err50 return nil, err
60 }51 }
61 return child, nil52 return child, nil
@@ -98,10 +89,7 @@ func NewWpFractionalScale(ctx *wl.Context) *WpFractionalScale {
98 89
99 // Destroy the fractional scale object. When this object is destroyed, preferred_scale events will no longer be sent.90 // Destroy the fractional scale object. When this object is destroyed, preferred_scale events will no longer be sent.
100 func (o *WpFractionalScale) Destroy() error {91 func (o *WpFractionalScale) Destroy() error {
101- if err := o.Context().CheckProxy(o); err != nil {92+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_fractional_scale_v1.destroy", Destructor: true}); err != nil {
102- return err
103- }
104- if err := o.Context().SendDestructor(o, 0); err != nil {
105 return err93 return err
106 }94 }
107 return nil95 return nil
M protocol/linuxdmabuf/linux-dmabuf-v1_generated.go +11 -53
@@ -77,10 +77,7 @@ func NewLinuxDmabuf(ctx *wl.Context) *LinuxDmabuf {
7777
7878 // Objects created through this interface, especially wl_buffers, will remain valid.
7979 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 {
80+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_linux_dmabuf_v1.destroy", Destructor: true}); err != nil {
8481 return err
8582 }
8683 return nil
@@ -88,15 +85,9 @@ func (o *LinuxDmabuf) Destroy() error {
8885
8986 // 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.
9087 func (o *LinuxDmabuf) CreateParams() (*LinuxBufferParams, error) {
91- if err := o.Context().CheckProxy(o); err != nil {
92- return nil, err
93- }
9488 child := &LinuxBufferParams{}
9589 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)
90+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_linux_dmabuf_v1.create_params", Child: child}, child); err != nil {
10091 return nil, err
10192 }
10293 return child, nil
@@ -104,15 +95,9 @@ func (o *LinuxDmabuf) CreateParams() (*LinuxBufferParams, error) {
10495
10596 // 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).
10697 func (o *LinuxDmabuf) GetDefaultFeedback() (*LinuxDmabufFeedback, error) {
107- if err := o.Context().CheckProxy(o); err != nil {
108- return nil, err
109- }
11098 child := &LinuxDmabufFeedback{}
11199 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)
100+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_linux_dmabuf_v1.get_default_feedback", Since: 4, Child: child}, child); err != nil {
116101 return nil, err
117102 }
118103 return child, nil
@@ -120,19 +105,13 @@ func (o *LinuxDmabuf) GetDefaultFeedback() (*LinuxDmabufFeedback, error) {
120105
121106 // 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.
122107 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- }
126108 var arg1 wl.Object
127109 if surface != nil {
128110 arg1 = surface
129111 }
130112 child := &LinuxDmabufFeedback{}
131113 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)
114+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "zwp_linux_dmabuf_v1.get_surface_feedback", Since: 4, Child: child}, child, arg1); err != nil {
136115 return nil, err
137116 }
138117 return child, nil
@@ -240,10 +219,7 @@ func NewLinuxBufferParams(ctx *wl.Context) *LinuxBufferParams {
240219
241220 // Cleans up the temporary data sent to the server for dmabuf-based wl_buffer creation.
242221 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 {
222+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_linux_buffer_params_v1.destroy", Destructor: true}); err != nil {
247223 return err
248224 }
249225 return nil
@@ -251,22 +227,15 @@ func (o *LinuxBufferParams) Destroy() error {
251227
252228 // 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.
253229 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 {
230+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_linux_buffer_params_v1.add", FDs: []int{fd}}, uintptr(fd), planeIdx, offset, stride, modifierHi, modifierLo); err != nil {
255231 return err
256232 }
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)
261233 return nil
262234 }
263235
264236 // 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.
265237 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 {
238+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_linux_buffer_params_v1.create"}, width, height, format, flags); err != nil {
270239 return err
271240 }
272241 return nil
@@ -274,14 +243,8 @@ func (o *LinuxBufferParams) Create(width int32, height int32, format uint32, fla
274243
275244 // 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.
276245 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- }
280246 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)
247+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "zwp_linux_buffer_params_v1.create_immed", Since: 2, Child: child}, child, width, height, format, flags); err != nil {
285248 return nil, err
286249 }
287250 return child, nil
@@ -289,10 +252,7 @@ func (o *LinuxBufferParams) CreateImmed(width int32, height int32, format uint32
289252
290253 // 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.
291254 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 {
255+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "zwp_linux_buffer_params_v1.set_sampling_device", Since: 6}, device); err != nil {
296256 return err
297257 }
298258 return nil
@@ -361,6 +321,7 @@ func (o *LinuxBufferParams) Dispatch(event *wl.Event) {
361321 bufferID := event.Uint32()
362322 bufferObject := cross_wl_buffer.NewBuffer(o.Context())
363323 bufferObject.SetID(bufferID)
324+ bufferObject.SetVersion(o.Version())
364325 o.Context().Register(bufferObject)
365326
366327 for i, handler := range o.handlersForCreated() {
@@ -405,10 +366,7 @@ func NewLinuxDmabufFeedback(ctx *wl.Context) *LinuxDmabufFeedback {
405366
406367 // Using this request a client can tell the server that it is not going to use the zwp_linux_dmabuf_feedback_v1 object anymore.
407368 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 {
369+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_linux_dmabuf_feedback_v1.destroy", Destructor: true}); err != nil {
412370 return err
413371 }
414372 return nil
@@ -77,10 +77,7 @@ func NewLinuxDmabuf(ctx *wl.Context) *LinuxDmabuf {
77 77
78 // Objects created through this interface, especially wl_buffers, will remain valid.78 // Objects created through this interface, especially wl_buffers, will remain valid.
79 func (o *LinuxDmabuf) Destroy() error {79 func (o *LinuxDmabuf) Destroy() error {
80- if err := o.Context().CheckProxy(o); err != nil {80+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_linux_dmabuf_v1.destroy", Destructor: true}); err != nil {
81- return err
82- }
83- if err := o.Context().SendDestructor(o, 0); err != nil {
84 return err81 return err
85 }82 }
86 return nil83 return nil
@@ -88,15 +85,9 @@ func (o *LinuxDmabuf) Destroy() error {
88 85
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.86 // 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) {87 func (o *LinuxDmabuf) CreateParams() (*LinuxBufferParams, error) {
91- if err := o.Context().CheckProxy(o); err != nil {
92- return nil, err
93- }
94 child := &LinuxBufferParams{}88 child := &LinuxBufferParams{}
95 child.SetContext(o.Context())89 child.SetContext(o.Context())
96- child.SetID(o.Context().AllocateID())90+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_linux_dmabuf_v1.create_params", Child: child}, child); err != nil {
97- o.Context().Register(child)
98- if err := o.Context().SendRequest(o, 1, child); err != nil {
99- o.Context().Unregister(child)
100 return nil, err91 return nil, err
101 }92 }
102 return child, nil93 return child, nil
@@ -104,15 +95,9 @@ func (o *LinuxDmabuf) CreateParams() (*LinuxBufferParams, error) {
104 95
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).96 // 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) {97 func (o *LinuxDmabuf) GetDefaultFeedback() (*LinuxDmabufFeedback, error) {
107- if err := o.Context().CheckProxy(o); err != nil {
108- return nil, err
109- }
110 child := &LinuxDmabufFeedback{}98 child := &LinuxDmabufFeedback{}
111 child.SetContext(o.Context())99 child.SetContext(o.Context())
112- child.SetID(o.Context().AllocateID())100+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_linux_dmabuf_v1.get_default_feedback", Since: 4, Child: child}, child); err != nil {
113- o.Context().Register(child)
114- if err := o.Context().SendRequest(o, 2, child); err != nil {
115- o.Context().Unregister(child)
116 return nil, err101 return nil, err
117 }102 }
118 return child, nil103 return child, nil
@@ -120,19 +105,13 @@ func (o *LinuxDmabuf) GetDefaultFeedback() (*LinuxDmabufFeedback, error) {
120 105
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.106 // 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) {107 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.Object108 var arg1 wl.Object
127 if surface != nil {109 if surface != nil {
128 arg1 = surface110 arg1 = surface
129 }111 }
130 child := &LinuxDmabufFeedback{}112 child := &LinuxDmabufFeedback{}
131 child.SetContext(o.Context())113 child.SetContext(o.Context())
132- child.SetID(o.Context().AllocateID())114+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "zwp_linux_dmabuf_v1.get_surface_feedback", Since: 4, Child: child}, child, arg1); err != nil {
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, err115 return nil, err
137 }116 }
138 return child, nil117 return child, nil
@@ -240,10 +219,7 @@ func NewLinuxBufferParams(ctx *wl.Context) *LinuxBufferParams {
240 219
241 // Cleans up the temporary data sent to the server for dmabuf-based wl_buffer creation.220 // Cleans up the temporary data sent to the server for dmabuf-based wl_buffer creation.
242 func (o *LinuxBufferParams) Destroy() error {221 func (o *LinuxBufferParams) Destroy() error {
243- if err := o.Context().CheckProxy(o); err != nil {222+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_linux_buffer_params_v1.destroy", Destructor: true}); err != nil {
244- return err
245- }
246- if err := o.Context().SendDestructor(o, 0); err != nil {
247 return err223 return err
248 }224 }
249 return nil225 return nil
@@ -251,22 +227,15 @@ func (o *LinuxBufferParams) Destroy() error {
251 227
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.228 // 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 {229 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 {230+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_linux_buffer_params_v1.add", FDs: []int{fd}}, uintptr(fd), planeIdx, offset, stride, modifierHi, modifierLo); err != nil {
255 return err231 return err
256 }232 }
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 nil233 return nil
262 }234 }
263 235
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.236 // 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 {237 func (o *LinuxBufferParams) Create(width int32, height int32, format uint32, flags uint32) error {
266- if err := o.Context().CheckProxy(o); err != nil {238+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_linux_buffer_params_v1.create"}, width, height, format, flags); err != nil {
267- return err
268- }
269- if err := o.Context().SendRequest(o, 2, width, height, format, flags); err != nil {
270 return err239 return err
271 }240 }
272 return nil241 return nil
@@ -274,14 +243,8 @@ func (o *LinuxBufferParams) Create(width int32, height int32, format uint32, fla
274 243
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.244 // 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) {245 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())246 child := cross_wl_buffer.NewBuffer(o.Context())
281- child.SetID(o.Context().AllocateID())247+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "zwp_linux_buffer_params_v1.create_immed", Since: 2, Child: child}, child, width, height, format, flags); err != nil {
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, err248 return nil, err
286 }249 }
287 return child, nil250 return child, nil
@@ -289,10 +252,7 @@ func (o *LinuxBufferParams) CreateImmed(width int32, height int32, format uint32
289 252
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.253 // 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 {254 func (o *LinuxBufferParams) SetSamplingDevice(device []byte) error {
292- if err := o.Context().CheckProxy(o); err != nil {255+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "zwp_linux_buffer_params_v1.set_sampling_device", Since: 6}, device); err != nil {
293- return err
294- }
295- if err := o.Context().SendRequest(o, 4, device); err != nil {
296 return err256 return err
297 }257 }
298 return nil258 return nil
@@ -361,6 +321,7 @@ func (o *LinuxBufferParams) Dispatch(event *wl.Event) {
361 bufferID := event.Uint32()321 bufferID := event.Uint32()
362 bufferObject := cross_wl_buffer.NewBuffer(o.Context())322 bufferObject := cross_wl_buffer.NewBuffer(o.Context())
363 bufferObject.SetID(bufferID)323 bufferObject.SetID(bufferID)
324+ bufferObject.SetVersion(o.Version())
364 o.Context().Register(bufferObject)325 o.Context().Register(bufferObject)
365 326
366 for i, handler := range o.handlersForCreated() {327 for i, handler := range o.handlersForCreated() {
@@ -405,10 +366,7 @@ func NewLinuxDmabufFeedback(ctx *wl.Context) *LinuxDmabufFeedback {
405 366
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.367 // 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 {368 func (o *LinuxDmabufFeedback) Destroy() error {
408- if err := o.Context().CheckProxy(o); err != nil {369+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_linux_dmabuf_feedback_v1.destroy", Destructor: true}); err != nil {
409- return err
410- }
411- if err := o.Context().SendDestructor(o, 0); err != nil {
412 return err370 return err
413 }371 }
414 return nil372 return nil
M protocol/tablet/tablet-v2_generated.go +22 -63
@@ -108,19 +108,13 @@ func NewTabletManager(ctx *wl.Context) *TabletManager {
108108
109109 // Get the zwp_tablet_seat_v2 object for the given seat. This object provides access to all graphics tablets in this seat.
110110 func (o *TabletManager) GetTabletSeat(seat *cross_wl_seat.Seat) (*TabletSeat, error) {
111- if err := o.Context().CheckProxy(o); err != nil {
112- return nil, err
113- }
114111 var arg1 wl.Object
115112 if seat != nil {
116113 arg1 = seat
117114 }
118115 child := &TabletSeat{}
119116 child.SetContext(o.Context())
120- child.SetID(o.Context().AllocateID())
121- o.Context().Register(child)
122- if err := o.Context().SendRequest(o, 0, child, arg1); err != nil {
123- o.Context().Unregister(child)
117+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_manager_v2.get_tablet_seat", Child: child}, child, arg1); err != nil {
124118 return nil, err
125119 }
126120 return child, nil
@@ -128,10 +122,7 @@ func (o *TabletManager) GetTabletSeat(seat *cross_wl_seat.Seat) (*TabletSeat, er
128122
129123 // Destroy the zwp_tablet_manager_v2 object. Objects created from this object are unaffected and should be destroyed separately.
130124 func (o *TabletManager) Destroy() error {
131- if err := o.Context().CheckProxy(o); err != nil {
132- return err
133- }
134- if err := o.Context().SendDestructor(o, 1); err != nil {
125+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_manager_v2.destroy", Destructor: true}); err != nil {
135126 return err
136127 }
137128 return nil
@@ -176,10 +167,7 @@ func NewTabletSeat(ctx *wl.Context) *TabletSeat {
176167
177168 // Destroy the zwp_tablet_seat_v2 object. Objects created from this object are unaffected and should be destroyed separately.
178169 func (o *TabletSeat) Destroy() error {
179- if err := o.Context().CheckProxy(o); err != nil {
180- return err
181- }
182- if err := o.Context().SendDestructor(o, 0); err != nil {
170+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_seat_v2.destroy", Destructor: true}); err != nil {
183171 return err
184172 }
185173 return nil
@@ -273,6 +261,7 @@ func (o *TabletSeat) Dispatch(event *wl.Event) {
273261 idObject := &Tablet{}
274262 idObject.SetContext(o.Context())
275263 idObject.SetID(idID)
264+ idObject.SetVersion(o.Version())
276265 o.Context().Register(idObject)
277266
278267 for i, handler := range o.handlersForTabletAdded() {
@@ -284,6 +273,7 @@ func (o *TabletSeat) Dispatch(event *wl.Event) {
284273 idObject := &TabletTool{}
285274 idObject.SetContext(o.Context())
286275 idObject.SetID(idID)
276+ idObject.SetVersion(o.Version())
287277 o.Context().Register(idObject)
288278
289279 for i, handler := range o.handlersForToolAdded() {
@@ -295,6 +285,7 @@ func (o *TabletSeat) Dispatch(event *wl.Event) {
295285 idObject := &TabletPad{}
296286 idObject.SetContext(o.Context())
297287 idObject.SetID(idID)
288+ idObject.SetVersion(o.Version())
298289 o.Context().Register(idObject)
299290
300291 for i, handler := range o.handlersForPadAdded() {
@@ -345,14 +336,11 @@ func NewTabletTool(ctx *wl.Context) *TabletTool {
345336
346337 // Sets the surface of the cursor used for this tool on the given tablet. This request only takes effect if the tool is in proximity of one of the requesting client's surfaces or the surface parameter is the current pointer surface. If there was a previous surface set with this request it is replaced. If surface is NULL, the cursor image is hidden. The parameters hotspot_x and hotspot_y define the position of the pointer surface relative to the pointer location. Its top-left corner is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the coordinates of the pointer location, in surface-local coordinates. On surface.attach requests to the pointer surface, hotspot_x and hotspot_y are decremented by the x and y parameters passed to the request. Attach must be confirmed by wl_surface.commit as usual. The hotspot can also be updated by passing the currently set pointer surface to this request with new values for hotspot_x and hotspot_y. The current and pending input regions of the wl_surface are cleared, and wl_surface.set_input_region is ignored until the wl_surface is no longer used as the cursor. When the use as a cursor ends, the current and pending input regions become undefined, and the wl_surface is unmapped. This request gives the surface the role of a zwp_tablet_tool_v2 cursor. A surface may only ever be used as the cursor surface for one zwp_tablet_tool_v2. If the surface already has another role or has previously been used as cursor surface for a different tool, a protocol error is raised.
347338 func (o *TabletTool) SetCursor(serial uint32, surface *cross_wl_surface.Surface, hotspotX int32, hotspotY int32) error {
348- if err := o.Context().CheckProxy(o); err != nil {
349- return err
350- }
351339 var arg1 wl.Object
352340 if surface != nil {
353341 arg1 = surface
354342 }
355- if err := o.Context().SendRequest(o, 0, serial, arg1, hotspotX, hotspotY); err != nil {
343+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_tool_v2.set_cursor"}, serial, arg1, hotspotX, hotspotY); err != nil {
356344 return err
357345 }
358346 return nil
@@ -360,10 +348,7 @@ func (o *TabletTool) SetCursor(serial uint32, surface *cross_wl_surface.Surface,
360348
361349 // This destroys the client's resource for this tool object.
362350 func (o *TabletTool) Destroy() error {
363- if err := o.Context().CheckProxy(o); err != nil {
364- return err
365- }
366- if err := o.Context().SendDestructor(o, 1); err != nil {
351+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_tool_v2.destroy", Destructor: true}); err != nil {
367352 return err
368353 }
369354 return nil
@@ -1005,10 +990,7 @@ func NewTablet(ctx *wl.Context) *Tablet {
1005990
1006991 // This destroys the client's resource for this tablet object.
1007992 func (o *Tablet) Destroy() error {
1008- if err := o.Context().CheckProxy(o); err != nil {
1009- return err
1010- }
1011- if err := o.Context().SendDestructor(o, 0); err != nil {
993+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_v2.destroy", Destructor: true}); err != nil {
1012994 return err
1013995 }
1014996 return nil
@@ -1239,10 +1221,7 @@ func NewTabletPadRing(ctx *wl.Context) *TabletPadRing {
12391221
12401222 // Request that the compositor use the provided feedback string associated with this ring. This request should be issued immediately after a zwp_tablet_pad_group_v2.mode_switch event from the corresponding group is received, or whenever the ring is mapped to a different action. See zwp_tablet_pad_group_v2.mode_switch for more details. Clients are encouraged to provide context-aware descriptions for the actions associated with the ring; compositors may use this information to offer visual feedback about the button layout (eg. on-screen displays). The provided string 'description' is a UTF-8 encoded string to be associated with this ring, and is considered user-visible; general internationalization rules apply. The serial argument will be that of the last zwp_tablet_pad_group_v2.mode_switch event received for the group of this ring. Requests providing other serials than the most recent one will be ignored.
12411223 func (o *TabletPadRing) SetFeedback(description string, serial uint32) error {
1242- if err := o.Context().CheckProxy(o); err != nil {
1243- return err
1244- }
1245- if err := o.Context().SendRequest(o, 0, description, serial); err != nil {
1224+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_pad_ring_v2.set_feedback"}, description, serial); err != nil {
12461225 return err
12471226 }
12481227 return nil
@@ -1250,10 +1229,7 @@ func (o *TabletPadRing) SetFeedback(description string, serial uint32) error {
12501229
12511230 // This destroys the client's resource for this ring object.
12521231 func (o *TabletPadRing) Destroy() error {
1253- if err := o.Context().CheckProxy(o); err != nil {
1254- return err
1255- }
1256- if err := o.Context().SendDestructor(o, 1); err != nil {
1232+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_pad_ring_v2.destroy", Destructor: true}); err != nil {
12571233 return err
12581234 }
12591235 return nil
@@ -1422,10 +1398,7 @@ func NewTabletPadStrip(ctx *wl.Context) *TabletPadStrip {
14221398
14231399 // Requests the compositor to use the provided feedback string associated with this strip. This request should be issued immediately after a zwp_tablet_pad_group_v2.mode_switch event from the corresponding group is received, or whenever the strip is mapped to a different action. See zwp_tablet_pad_group_v2.mode_switch for more details. Clients are encouraged to provide context-aware descriptions for the actions associated with the strip, and compositors may use this information to offer visual feedback about the button layout (eg. on-screen displays). The provided string 'description' is a UTF-8 encoded string to be associated with this ring, and is considered user-visible; general internationalization rules apply. The serial argument will be that of the last zwp_tablet_pad_group_v2.mode_switch event received for the group of this strip. Requests providing other serials than the most recent one will be ignored.
14241400 func (o *TabletPadStrip) SetFeedback(description string, serial uint32) error {
1425- if err := o.Context().CheckProxy(o); err != nil {
1426- return err
1427- }
1428- if err := o.Context().SendRequest(o, 0, description, serial); err != nil {
1401+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_pad_strip_v2.set_feedback"}, description, serial); err != nil {
14291402 return err
14301403 }
14311404 return nil
@@ -1433,10 +1406,7 @@ func (o *TabletPadStrip) SetFeedback(description string, serial uint32) error {
14331406
14341407 // This destroys the client's resource for this strip object.
14351408 func (o *TabletPadStrip) Destroy() error {
1436- if err := o.Context().CheckProxy(o); err != nil {
1437- return err
1438- }
1439- if err := o.Context().SendDestructor(o, 1); err != nil {
1409+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_pad_strip_v2.destroy", Destructor: true}); err != nil {
14401410 return err
14411411 }
14421412 return nil
@@ -1608,10 +1578,7 @@ func NewTabletPadGroup(ctx *wl.Context) *TabletPadGroup {
16081578
16091579 // Destroy the zwp_tablet_pad_group_v2 object. Objects created from this object are unaffected and should be destroyed separately.
16101580 func (o *TabletPadGroup) Destroy() error {
1611- if err := o.Context().CheckProxy(o); err != nil {
1612- return err
1613- }
1614- if err := o.Context().SendDestructor(o, 0); err != nil {
1581+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_pad_group_v2.destroy", Destructor: true}); err != nil {
16151582 return err
16161583 }
16171584 return nil
@@ -1808,6 +1775,7 @@ func (o *TabletPadGroup) Dispatch(event *wl.Event) {
18081775 ringObject := &TabletPadRing{}
18091776 ringObject.SetContext(o.Context())
18101777 ringObject.SetID(ringID)
1778+ ringObject.SetVersion(o.Version())
18111779 o.Context().Register(ringObject)
18121780
18131781 for i, handler := range o.handlersForRing() {
@@ -1819,6 +1787,7 @@ func (o *TabletPadGroup) Dispatch(event *wl.Event) {
18191787 stripObject := &TabletPadStrip{}
18201788 stripObject.SetContext(o.Context())
18211789 stripObject.SetID(stripID)
1790+ stripObject.SetVersion(o.Version())
18221791 o.Context().Register(stripObject)
18231792
18241793 for i, handler := range o.handlersForStrip() {
@@ -1852,6 +1821,7 @@ func (o *TabletPadGroup) Dispatch(event *wl.Event) {
18521821 dialObject := &TabletPadDial{}
18531822 dialObject.SetContext(o.Context())
18541823 dialObject.SetID(dialID)
1824+ dialObject.SetVersion(o.Version())
18551825 o.Context().Register(dialObject)
18561826
18571827 for i, handler := range o.handlersForDial() {
@@ -1891,10 +1861,7 @@ func NewTabletPad(ctx *wl.Context) *TabletPad {
18911861
18921862 // Requests the compositor to use the provided feedback string associated with this button. This request should be issued immediately after a zwp_tablet_pad_group_v2.mode_switch event from the corresponding group is received, or whenever a button is mapped to a different action. See zwp_tablet_pad_group_v2.mode_switch for more details. Clients are encouraged to provide context-aware descriptions for the actions associated with each button, and compositors may use this information to offer visual feedback on the button layout (e.g. on-screen displays). Button indices start at 0. Setting the feedback string on a button that is reserved by the compositor (i.e. not belonging to any zwp_tablet_pad_group_v2) does not generate an error but the compositor is free to ignore the request. The provided string 'description' is a UTF-8 encoded string to be associated with this ring, and is considered user-visible; general internationalization rules apply. The serial argument will be that of the last zwp_tablet_pad_group_v2.mode_switch event received for the group of this button. Requests providing other serials than the most recent one will be ignored.
18931863 func (o *TabletPad) SetFeedback(button uint32, description string, serial uint32) error {
1894- if err := o.Context().CheckProxy(o); err != nil {
1895- return err
1896- }
1897- if err := o.Context().SendRequest(o, 0, button, description, serial); err != nil {
1864+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_pad_v2.set_feedback"}, button, description, serial); err != nil {
18981865 return err
18991866 }
19001867 return nil
@@ -1902,10 +1869,7 @@ func (o *TabletPad) SetFeedback(button uint32, description string, serial uint32
19021869
19031870 // Destroy the zwp_tablet_pad_v2 object. Objects created from this object are unaffected and should be destroyed separately.
19041871 func (o *TabletPad) Destroy() error {
1905- if err := o.Context().CheckProxy(o); err != nil {
1906- return err
1907- }
1908- if err := o.Context().SendDestructor(o, 1); err != nil {
1872+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_pad_v2.destroy", Destructor: true}); err != nil {
19091873 return err
19101874 }
19111875 return nil
@@ -2119,6 +2083,7 @@ func (o *TabletPad) Dispatch(event *wl.Event) {
21192083 padGroupObject := &TabletPadGroup{}
21202084 padGroupObject.SetContext(o.Context())
21212085 padGroupObject.SetID(padGroupID)
2086+ padGroupObject.SetVersion(o.Version())
21222087 o.Context().Register(padGroupObject)
21232088
21242089 for i, handler := range o.handlersForGroup() {
@@ -2204,10 +2169,7 @@ func NewTabletPadDial(ctx *wl.Context) *TabletPadDial {
22042169
22052170 // Requests the compositor to use the provided feedback string associated with this dial. This request should be issued immediately after a zwp_tablet_pad_group_v2.mode_switch event from the corresponding group is received, or whenever the dial is mapped to a different action. See zwp_tablet_pad_group_v2.mode_switch for more details. Clients are encouraged to provide context-aware descriptions for the actions associated with the dial, and compositors may use this information to offer visual feedback about the button layout (eg. on-screen displays). The provided string 'description' is a UTF-8 encoded string to be associated with this ring, and is considered user-visible; general internationalization rules apply. The serial argument will be that of the last zwp_tablet_pad_group_v2.mode_switch event received for the group of this dial. Requests providing other serials than the most recent one will be ignored.
22062171 func (o *TabletPadDial) SetFeedback(description string, serial uint32) error {
2207- if err := o.Context().CheckProxy(o); err != nil {
2208- return err
2209- }
2210- if err := o.Context().SendRequest(o, 0, description, serial); err != nil {
2172+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_pad_dial_v2.set_feedback"}, description, serial); err != nil {
22112173 return err
22122174 }
22132175 return nil
@@ -2215,10 +2177,7 @@ func (o *TabletPadDial) SetFeedback(description string, serial uint32) error {
22152177
22162178 // This destroys the client's resource for this dial object.
22172179 func (o *TabletPadDial) Destroy() error {
2218- if err := o.Context().CheckProxy(o); err != nil {
2219- return err
2220- }
2221- if err := o.Context().SendDestructor(o, 1); err != nil {
2180+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_pad_dial_v2.destroy", Destructor: true}); err != nil {
22222181 return err
22232182 }
22242183 return nil
@@ -108,19 +108,13 @@ func NewTabletManager(ctx *wl.Context) *TabletManager {
108 108
109 // Get the zwp_tablet_seat_v2 object for the given seat. This object provides access to all graphics tablets in this seat.109 // Get the zwp_tablet_seat_v2 object for the given seat. This object provides access to all graphics tablets in this seat.
110 func (o *TabletManager) GetTabletSeat(seat *cross_wl_seat.Seat) (*TabletSeat, error) {110 func (o *TabletManager) GetTabletSeat(seat *cross_wl_seat.Seat) (*TabletSeat, error) {
111- if err := o.Context().CheckProxy(o); err != nil {
112- return nil, err
113- }
114 var arg1 wl.Object111 var arg1 wl.Object
115 if seat != nil {112 if seat != nil {
116 arg1 = seat113 arg1 = seat
117 }114 }
118 child := &TabletSeat{}115 child := &TabletSeat{}
119 child.SetContext(o.Context())116 child.SetContext(o.Context())
120- child.SetID(o.Context().AllocateID())117+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_manager_v2.get_tablet_seat", Child: child}, child, arg1); err != nil {
121- o.Context().Register(child)
122- if err := o.Context().SendRequest(o, 0, child, arg1); err != nil {
123- o.Context().Unregister(child)
124 return nil, err118 return nil, err
125 }119 }
126 return child, nil120 return child, nil
@@ -128,10 +122,7 @@ func (o *TabletManager) GetTabletSeat(seat *cross_wl_seat.Seat) (*TabletSeat, er
128 122
129 // Destroy the zwp_tablet_manager_v2 object. Objects created from this object are unaffected and should be destroyed separately.123 // Destroy the zwp_tablet_manager_v2 object. Objects created from this object are unaffected and should be destroyed separately.
130 func (o *TabletManager) Destroy() error {124 func (o *TabletManager) Destroy() error {
131- if err := o.Context().CheckProxy(o); err != nil {125+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_manager_v2.destroy", Destructor: true}); err != nil {
132- return err
133- }
134- if err := o.Context().SendDestructor(o, 1); err != nil {
135 return err126 return err
136 }127 }
137 return nil128 return nil
@@ -176,10 +167,7 @@ func NewTabletSeat(ctx *wl.Context) *TabletSeat {
176 167
177 // Destroy the zwp_tablet_seat_v2 object. Objects created from this object are unaffected and should be destroyed separately.168 // Destroy the zwp_tablet_seat_v2 object. Objects created from this object are unaffected and should be destroyed separately.
178 func (o *TabletSeat) Destroy() error {169 func (o *TabletSeat) Destroy() error {
179- if err := o.Context().CheckProxy(o); err != nil {170+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_seat_v2.destroy", Destructor: true}); err != nil {
180- return err
181- }
182- if err := o.Context().SendDestructor(o, 0); err != nil {
183 return err171 return err
184 }172 }
185 return nil173 return nil
@@ -273,6 +261,7 @@ func (o *TabletSeat) Dispatch(event *wl.Event) {
273 idObject := &Tablet{}261 idObject := &Tablet{}
274 idObject.SetContext(o.Context())262 idObject.SetContext(o.Context())
275 idObject.SetID(idID)263 idObject.SetID(idID)
264+ idObject.SetVersion(o.Version())
276 o.Context().Register(idObject)265 o.Context().Register(idObject)
277 266
278 for i, handler := range o.handlersForTabletAdded() {267 for i, handler := range o.handlersForTabletAdded() {
@@ -284,6 +273,7 @@ func (o *TabletSeat) Dispatch(event *wl.Event) {
284 idObject := &TabletTool{}273 idObject := &TabletTool{}
285 idObject.SetContext(o.Context())274 idObject.SetContext(o.Context())
286 idObject.SetID(idID)275 idObject.SetID(idID)
276+ idObject.SetVersion(o.Version())
287 o.Context().Register(idObject)277 o.Context().Register(idObject)
288 278
289 for i, handler := range o.handlersForToolAdded() {279 for i, handler := range o.handlersForToolAdded() {
@@ -295,6 +285,7 @@ func (o *TabletSeat) Dispatch(event *wl.Event) {
295 idObject := &TabletPad{}285 idObject := &TabletPad{}
296 idObject.SetContext(o.Context())286 idObject.SetContext(o.Context())
297 idObject.SetID(idID)287 idObject.SetID(idID)
288+ idObject.SetVersion(o.Version())
298 o.Context().Register(idObject)289 o.Context().Register(idObject)
299 290
300 for i, handler := range o.handlersForPadAdded() {291 for i, handler := range o.handlersForPadAdded() {
@@ -345,14 +336,11 @@ func NewTabletTool(ctx *wl.Context) *TabletTool {
345 336
346 // Sets the surface of the cursor used for this tool on the given tablet. This request only takes effect if the tool is in proximity of one of the requesting client's surfaces or the surface parameter is the current pointer surface. If there was a previous surface set with this request it is replaced. If surface is NULL, the cursor image is hidden. The parameters hotspot_x and hotspot_y define the position of the pointer surface relative to the pointer location. Its top-left corner is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the coordinates of the pointer location, in surface-local coordinates. On surface.attach requests to the pointer surface, hotspot_x and hotspot_y are decremented by the x and y parameters passed to the request. Attach must be confirmed by wl_surface.commit as usual. The hotspot can also be updated by passing the currently set pointer surface to this request with new values for hotspot_x and hotspot_y. The current and pending input regions of the wl_surface are cleared, and wl_surface.set_input_region is ignored until the wl_surface is no longer used as the cursor. When the use as a cursor ends, the current and pending input regions become undefined, and the wl_surface is unmapped. This request gives the surface the role of a zwp_tablet_tool_v2 cursor. A surface may only ever be used as the cursor surface for one zwp_tablet_tool_v2. If the surface already has another role or has previously been used as cursor surface for a different tool, a protocol error is raised.337 // Sets the surface of the cursor used for this tool on the given tablet. This request only takes effect if the tool is in proximity of one of the requesting client's surfaces or the surface parameter is the current pointer surface. If there was a previous surface set with this request it is replaced. If surface is NULL, the cursor image is hidden. The parameters hotspot_x and hotspot_y define the position of the pointer surface relative to the pointer location. Its top-left corner is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the coordinates of the pointer location, in surface-local coordinates. On surface.attach requests to the pointer surface, hotspot_x and hotspot_y are decremented by the x and y parameters passed to the request. Attach must be confirmed by wl_surface.commit as usual. The hotspot can also be updated by passing the currently set pointer surface to this request with new values for hotspot_x and hotspot_y. The current and pending input regions of the wl_surface are cleared, and wl_surface.set_input_region is ignored until the wl_surface is no longer used as the cursor. When the use as a cursor ends, the current and pending input regions become undefined, and the wl_surface is unmapped. This request gives the surface the role of a zwp_tablet_tool_v2 cursor. A surface may only ever be used as the cursor surface for one zwp_tablet_tool_v2. If the surface already has another role or has previously been used as cursor surface for a different tool, a protocol error is raised.
347 func (o *TabletTool) SetCursor(serial uint32, surface *cross_wl_surface.Surface, hotspotX int32, hotspotY int32) error {338 func (o *TabletTool) SetCursor(serial uint32, surface *cross_wl_surface.Surface, hotspotX int32, hotspotY int32) error {
348- if err := o.Context().CheckProxy(o); err != nil {
349- return err
350- }
351 var arg1 wl.Object339 var arg1 wl.Object
352 if surface != nil {340 if surface != nil {
353 arg1 = surface341 arg1 = surface
354 }342 }
355- if err := o.Context().SendRequest(o, 0, serial, arg1, hotspotX, hotspotY); err != nil {343+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_tool_v2.set_cursor"}, serial, arg1, hotspotX, hotspotY); err != nil {
356 return err344 return err
357 }345 }
358 return nil346 return nil
@@ -360,10 +348,7 @@ func (o *TabletTool) SetCursor(serial uint32, surface *cross_wl_surface.Surface,
360 348
361 // This destroys the client's resource for this tool object.349 // This destroys the client's resource for this tool object.
362 func (o *TabletTool) Destroy() error {350 func (o *TabletTool) Destroy() error {
363- if err := o.Context().CheckProxy(o); err != nil {351+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_tool_v2.destroy", Destructor: true}); err != nil {
364- return err
365- }
366- if err := o.Context().SendDestructor(o, 1); err != nil {
367 return err352 return err
368 }353 }
369 return nil354 return nil
@@ -1005,10 +990,7 @@ func NewTablet(ctx *wl.Context) *Tablet {
1005 990
1006 // This destroys the client's resource for this tablet object.991 // This destroys the client's resource for this tablet object.
1007 func (o *Tablet) Destroy() error {992 func (o *Tablet) Destroy() error {
1008- if err := o.Context().CheckProxy(o); err != nil {993+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_v2.destroy", Destructor: true}); err != nil {
1009- return err
1010- }
1011- if err := o.Context().SendDestructor(o, 0); err != nil {
1012 return err994 return err
1013 }995 }
1014 return nil996 return nil
@@ -1239,10 +1221,7 @@ func NewTabletPadRing(ctx *wl.Context) *TabletPadRing {
1239 1221
1240 // Request that the compositor use the provided feedback string associated with this ring. This request should be issued immediately after a zwp_tablet_pad_group_v2.mode_switch event from the corresponding group is received, or whenever the ring is mapped to a different action. See zwp_tablet_pad_group_v2.mode_switch for more details. Clients are encouraged to provide context-aware descriptions for the actions associated with the ring; compositors may use this information to offer visual feedback about the button layout (eg. on-screen displays). The provided string 'description' is a UTF-8 encoded string to be associated with this ring, and is considered user-visible; general internationalization rules apply. The serial argument will be that of the last zwp_tablet_pad_group_v2.mode_switch event received for the group of this ring. Requests providing other serials than the most recent one will be ignored.1222 // Request that the compositor use the provided feedback string associated with this ring. This request should be issued immediately after a zwp_tablet_pad_group_v2.mode_switch event from the corresponding group is received, or whenever the ring is mapped to a different action. See zwp_tablet_pad_group_v2.mode_switch for more details. Clients are encouraged to provide context-aware descriptions for the actions associated with the ring; compositors may use this information to offer visual feedback about the button layout (eg. on-screen displays). The provided string 'description' is a UTF-8 encoded string to be associated with this ring, and is considered user-visible; general internationalization rules apply. The serial argument will be that of the last zwp_tablet_pad_group_v2.mode_switch event received for the group of this ring. Requests providing other serials than the most recent one will be ignored.
1241 func (o *TabletPadRing) SetFeedback(description string, serial uint32) error {1223 func (o *TabletPadRing) SetFeedback(description string, serial uint32) error {
1242- if err := o.Context().CheckProxy(o); err != nil {1224+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_pad_ring_v2.set_feedback"}, description, serial); err != nil {
1243- return err
1244- }
1245- if err := o.Context().SendRequest(o, 0, description, serial); err != nil {
1246 return err1225 return err
1247 }1226 }
1248 return nil1227 return nil
@@ -1250,10 +1229,7 @@ func (o *TabletPadRing) SetFeedback(description string, serial uint32) error {
1250 1229
1251 // This destroys the client's resource for this ring object.1230 // This destroys the client's resource for this ring object.
1252 func (o *TabletPadRing) Destroy() error {1231 func (o *TabletPadRing) Destroy() error {
1253- if err := o.Context().CheckProxy(o); err != nil {1232+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_pad_ring_v2.destroy", Destructor: true}); err != nil {
1254- return err
1255- }
1256- if err := o.Context().SendDestructor(o, 1); err != nil {
1257 return err1233 return err
1258 }1234 }
1259 return nil1235 return nil
@@ -1422,10 +1398,7 @@ func NewTabletPadStrip(ctx *wl.Context) *TabletPadStrip {
1422 1398
1423 // Requests the compositor to use the provided feedback string associated with this strip. This request should be issued immediately after a zwp_tablet_pad_group_v2.mode_switch event from the corresponding group is received, or whenever the strip is mapped to a different action. See zwp_tablet_pad_group_v2.mode_switch for more details. Clients are encouraged to provide context-aware descriptions for the actions associated with the strip, and compositors may use this information to offer visual feedback about the button layout (eg. on-screen displays). The provided string 'description' is a UTF-8 encoded string to be associated with this ring, and is considered user-visible; general internationalization rules apply. The serial argument will be that of the last zwp_tablet_pad_group_v2.mode_switch event received for the group of this strip. Requests providing other serials than the most recent one will be ignored.1399 // Requests the compositor to use the provided feedback string associated with this strip. This request should be issued immediately after a zwp_tablet_pad_group_v2.mode_switch event from the corresponding group is received, or whenever the strip is mapped to a different action. See zwp_tablet_pad_group_v2.mode_switch for more details. Clients are encouraged to provide context-aware descriptions for the actions associated with the strip, and compositors may use this information to offer visual feedback about the button layout (eg. on-screen displays). The provided string 'description' is a UTF-8 encoded string to be associated with this ring, and is considered user-visible; general internationalization rules apply. The serial argument will be that of the last zwp_tablet_pad_group_v2.mode_switch event received for the group of this strip. Requests providing other serials than the most recent one will be ignored.
1424 func (o *TabletPadStrip) SetFeedback(description string, serial uint32) error {1400 func (o *TabletPadStrip) SetFeedback(description string, serial uint32) error {
1425- if err := o.Context().CheckProxy(o); err != nil {1401+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_pad_strip_v2.set_feedback"}, description, serial); err != nil {
1426- return err
1427- }
1428- if err := o.Context().SendRequest(o, 0, description, serial); err != nil {
1429 return err1402 return err
1430 }1403 }
1431 return nil1404 return nil
@@ -1433,10 +1406,7 @@ func (o *TabletPadStrip) SetFeedback(description string, serial uint32) error {
1433 1406
1434 // This destroys the client's resource for this strip object.1407 // This destroys the client's resource for this strip object.
1435 func (o *TabletPadStrip) Destroy() error {1408 func (o *TabletPadStrip) Destroy() error {
1436- if err := o.Context().CheckProxy(o); err != nil {1409+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_pad_strip_v2.destroy", Destructor: true}); err != nil {
1437- return err
1438- }
1439- if err := o.Context().SendDestructor(o, 1); err != nil {
1440 return err1410 return err
1441 }1411 }
1442 return nil1412 return nil
@@ -1608,10 +1578,7 @@ func NewTabletPadGroup(ctx *wl.Context) *TabletPadGroup {
1608 1578
1609 // Destroy the zwp_tablet_pad_group_v2 object. Objects created from this object are unaffected and should be destroyed separately.1579 // Destroy the zwp_tablet_pad_group_v2 object. Objects created from this object are unaffected and should be destroyed separately.
1610 func (o *TabletPadGroup) Destroy() error {1580 func (o *TabletPadGroup) Destroy() error {
1611- if err := o.Context().CheckProxy(o); err != nil {1581+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_pad_group_v2.destroy", Destructor: true}); err != nil {
1612- return err
1613- }
1614- if err := o.Context().SendDestructor(o, 0); err != nil {
1615 return err1582 return err
1616 }1583 }
1617 return nil1584 return nil
@@ -1808,6 +1775,7 @@ func (o *TabletPadGroup) Dispatch(event *wl.Event) {
1808 ringObject := &TabletPadRing{}1775 ringObject := &TabletPadRing{}
1809 ringObject.SetContext(o.Context())1776 ringObject.SetContext(o.Context())
1810 ringObject.SetID(ringID)1777 ringObject.SetID(ringID)
1778+ ringObject.SetVersion(o.Version())
1811 o.Context().Register(ringObject)1779 o.Context().Register(ringObject)
1812 1780
1813 for i, handler := range o.handlersForRing() {1781 for i, handler := range o.handlersForRing() {
@@ -1819,6 +1787,7 @@ func (o *TabletPadGroup) Dispatch(event *wl.Event) {
1819 stripObject := &TabletPadStrip{}1787 stripObject := &TabletPadStrip{}
1820 stripObject.SetContext(o.Context())1788 stripObject.SetContext(o.Context())
1821 stripObject.SetID(stripID)1789 stripObject.SetID(stripID)
1790+ stripObject.SetVersion(o.Version())
1822 o.Context().Register(stripObject)1791 o.Context().Register(stripObject)
1823 1792
1824 for i, handler := range o.handlersForStrip() {1793 for i, handler := range o.handlersForStrip() {
@@ -1852,6 +1821,7 @@ func (o *TabletPadGroup) Dispatch(event *wl.Event) {
1852 dialObject := &TabletPadDial{}1821 dialObject := &TabletPadDial{}
1853 dialObject.SetContext(o.Context())1822 dialObject.SetContext(o.Context())
1854 dialObject.SetID(dialID)1823 dialObject.SetID(dialID)
1824+ dialObject.SetVersion(o.Version())
1855 o.Context().Register(dialObject)1825 o.Context().Register(dialObject)
1856 1826
1857 for i, handler := range o.handlersForDial() {1827 for i, handler := range o.handlersForDial() {
@@ -1891,10 +1861,7 @@ func NewTabletPad(ctx *wl.Context) *TabletPad {
1891 1861
1892 // Requests the compositor to use the provided feedback string associated with this button. This request should be issued immediately after a zwp_tablet_pad_group_v2.mode_switch event from the corresponding group is received, or whenever a button is mapped to a different action. See zwp_tablet_pad_group_v2.mode_switch for more details. Clients are encouraged to provide context-aware descriptions for the actions associated with each button, and compositors may use this information to offer visual feedback on the button layout (e.g. on-screen displays). Button indices start at 0. Setting the feedback string on a button that is reserved by the compositor (i.e. not belonging to any zwp_tablet_pad_group_v2) does not generate an error but the compositor is free to ignore the request. The provided string 'description' is a UTF-8 encoded string to be associated with this ring, and is considered user-visible; general internationalization rules apply. The serial argument will be that of the last zwp_tablet_pad_group_v2.mode_switch event received for the group of this button. Requests providing other serials than the most recent one will be ignored.1862 // Requests the compositor to use the provided feedback string associated with this button. This request should be issued immediately after a zwp_tablet_pad_group_v2.mode_switch event from the corresponding group is received, or whenever a button is mapped to a different action. See zwp_tablet_pad_group_v2.mode_switch for more details. Clients are encouraged to provide context-aware descriptions for the actions associated with each button, and compositors may use this information to offer visual feedback on the button layout (e.g. on-screen displays). Button indices start at 0. Setting the feedback string on a button that is reserved by the compositor (i.e. not belonging to any zwp_tablet_pad_group_v2) does not generate an error but the compositor is free to ignore the request. The provided string 'description' is a UTF-8 encoded string to be associated with this ring, and is considered user-visible; general internationalization rules apply. The serial argument will be that of the last zwp_tablet_pad_group_v2.mode_switch event received for the group of this button. Requests providing other serials than the most recent one will be ignored.
1893 func (o *TabletPad) SetFeedback(button uint32, description string, serial uint32) error {1863 func (o *TabletPad) SetFeedback(button uint32, description string, serial uint32) error {
1894- if err := o.Context().CheckProxy(o); err != nil {1864+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_pad_v2.set_feedback"}, button, description, serial); err != nil {
1895- return err
1896- }
1897- if err := o.Context().SendRequest(o, 0, button, description, serial); err != nil {
1898 return err1865 return err
1899 }1866 }
1900 return nil1867 return nil
@@ -1902,10 +1869,7 @@ func (o *TabletPad) SetFeedback(button uint32, description string, serial uint32
1902 1869
1903 // Destroy the zwp_tablet_pad_v2 object. Objects created from this object are unaffected and should be destroyed separately.1870 // Destroy the zwp_tablet_pad_v2 object. Objects created from this object are unaffected and should be destroyed separately.
1904 func (o *TabletPad) Destroy() error {1871 func (o *TabletPad) Destroy() error {
1905- if err := o.Context().CheckProxy(o); err != nil {1872+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_pad_v2.destroy", Destructor: true}); err != nil {
1906- return err
1907- }
1908- if err := o.Context().SendDestructor(o, 1); err != nil {
1909 return err1873 return err
1910 }1874 }
1911 return nil1875 return nil
@@ -2119,6 +2083,7 @@ func (o *TabletPad) Dispatch(event *wl.Event) {
2119 padGroupObject := &TabletPadGroup{}2083 padGroupObject := &TabletPadGroup{}
2120 padGroupObject.SetContext(o.Context())2084 padGroupObject.SetContext(o.Context())
2121 padGroupObject.SetID(padGroupID)2085 padGroupObject.SetID(padGroupID)
2086+ padGroupObject.SetVersion(o.Version())
2122 o.Context().Register(padGroupObject)2087 o.Context().Register(padGroupObject)
2123 2088
2124 for i, handler := range o.handlersForGroup() {2089 for i, handler := range o.handlersForGroup() {
@@ -2204,10 +2169,7 @@ func NewTabletPadDial(ctx *wl.Context) *TabletPadDial {
2204 2169
2205 // Requests the compositor to use the provided feedback string associated with this dial. This request should be issued immediately after a zwp_tablet_pad_group_v2.mode_switch event from the corresponding group is received, or whenever the dial is mapped to a different action. See zwp_tablet_pad_group_v2.mode_switch for more details. Clients are encouraged to provide context-aware descriptions for the actions associated with the dial, and compositors may use this information to offer visual feedback about the button layout (eg. on-screen displays). The provided string 'description' is a UTF-8 encoded string to be associated with this ring, and is considered user-visible; general internationalization rules apply. The serial argument will be that of the last zwp_tablet_pad_group_v2.mode_switch event received for the group of this dial. Requests providing other serials than the most recent one will be ignored.2170 // Requests the compositor to use the provided feedback string associated with this dial. This request should be issued immediately after a zwp_tablet_pad_group_v2.mode_switch event from the corresponding group is received, or whenever the dial is mapped to a different action. See zwp_tablet_pad_group_v2.mode_switch for more details. Clients are encouraged to provide context-aware descriptions for the actions associated with the dial, and compositors may use this information to offer visual feedback about the button layout (eg. on-screen displays). The provided string 'description' is a UTF-8 encoded string to be associated with this ring, and is considered user-visible; general internationalization rules apply. The serial argument will be that of the last zwp_tablet_pad_group_v2.mode_switch event received for the group of this dial. Requests providing other serials than the most recent one will be ignored.
2206 func (o *TabletPadDial) SetFeedback(description string, serial uint32) error {2171 func (o *TabletPadDial) SetFeedback(description string, serial uint32) error {
2207- if err := o.Context().CheckProxy(o); err != nil {2172+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_tablet_pad_dial_v2.set_feedback"}, description, serial); err != nil {
2208- return err
2209- }
2210- if err := o.Context().SendRequest(o, 0, description, serial); err != nil {
2211 return err2173 return err
2212 }2174 }
2213 return nil2175 return nil
@@ -2215,10 +2177,7 @@ func (o *TabletPadDial) SetFeedback(description string, serial uint32) error {
2215 2177
2216 // This destroys the client's resource for this dial object.2178 // This destroys the client's resource for this dial object.
2217 func (o *TabletPadDial) Destroy() error {2179 func (o *TabletPadDial) Destroy() error {
2218- if err := o.Context().CheckProxy(o); err != nil {2180+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_tablet_pad_dial_v2.destroy", Destructor: true}); err != nil {
2219- return err
2220- }
2221- if err := o.Context().SendDestructor(o, 1); err != nil {
2222 return err2181 return err
2223 }2182 }
2224 return nil2183 return nil
M protocol/textinput/text-input-unstable-v3_generated.go +13 -55
@@ -161,10 +161,7 @@ func NewTextInputV3(ctx *wl.Context) *TextInputV3 {
161161
162162 // Destroy the wp_text_input object. Also disables all surfaces enabled through this wp_text_input object.
163163 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 {
164+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_text_input_v3.destroy", Destructor: true}); err != nil {
168165 return err
169166 }
170167 return nil
@@ -172,10 +169,7 @@ func (o *TextInputV3) Destroy() error {
172169
173170 // 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.
174171 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 {
172+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_text_input_v3.enable"}); err != nil {
179173 return err
180174 }
181175 return nil
@@ -183,10 +177,7 @@ func (o *TextInputV3) Enable() error {
183177
184178 // 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.
185179 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 {
180+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_text_input_v3.disable"}); err != nil {
190181 return err
191182 }
192183 return nil
@@ -194,10 +185,7 @@ func (o *TextInputV3) Disable() error {
194185
195186 // 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.
196187 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 {
188+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "zwp_text_input_v3.set_surrounding_text"}, text, cursor, anchor); err != nil {
201189 return err
202190 }
203191 return nil
@@ -205,10 +193,7 @@ func (o *TextInputV3) SetSurroundingText(text string, cursor int32, anchor int32
205193
206194 // 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.
207195 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 {
196+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "zwp_text_input_v3.set_text_change_cause"}, cause); err != nil {
212197 return err
213198 }
214199 return nil
@@ -216,10 +201,7 @@ func (o *TextInputV3) SetTextChangeCause(cause uint32) error {
216201
217202 // 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.
218203 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 {
204+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 5, Name: "zwp_text_input_v3.set_content_type"}, hint, purpose); err != nil {
223205 return err
224206 }
225207 return nil
@@ -227,10 +209,7 @@ func (o *TextInputV3) SetContentType(hint uint32, purpose uint32) error {
227209
228210 // 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.
229211 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 {
212+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 6, Name: "zwp_text_input_v3.set_cursor_rectangle"}, x, y, width, height); err != nil {
234213 return err
235214 }
236215 return nil
@@ -238,10 +217,7 @@ func (o *TextInputV3) SetCursorRectangle(x int32, y int32, width int32, height i
238217
239218 // 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.
240219 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 {
220+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 7, Name: "zwp_text_input_v3.commit"}); err != nil {
245221 return err
246222 }
247223 return nil
@@ -249,10 +225,7 @@ func (o *TextInputV3) Commit() error {
249225
250226 // 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.
251227 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 {
228+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 8, Name: "zwp_text_input_v3.set_available_actions", Since: 2}, availableActions); err != nil {
256229 return err
257230 }
258231 return nil
@@ -260,10 +233,7 @@ func (o *TextInputV3) SetAvailableActions(availableActions []byte) error {
260233
261234 // 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.
262235 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 {
236+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 9, Name: "zwp_text_input_v3.show_input_panel", Since: 2}); err != nil {
267237 return err
268238 }
269239 return nil
@@ -271,10 +241,7 @@ func (o *TextInputV3) ShowInputPanel() error {
271241
272242 // 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.
273243 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 {
244+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 10, Name: "zwp_text_input_v3.hide_input_panel", Since: 2}); err != nil {
278245 return err
279246 }
280247 return nil
@@ -598,10 +565,7 @@ func NewTextInputManagerV3(ctx *wl.Context) *TextInputManagerV3 {
598565
599566 // Destroy the wp_text_input_manager object.
600567 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 {
568+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_text_input_manager_v3.destroy", Destructor: true}); err != nil {
605569 return err
606570 }
607571 return nil
@@ -609,19 +573,13 @@ func (o *TextInputManagerV3) Destroy() error {
609573
610574 // Creates a new text-input object for a given seat.
611575 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- }
615576 var arg1 wl.Object
616577 if seat != nil {
617578 arg1 = seat
618579 }
619580 child := &TextInputV3{}
620581 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)
582+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_text_input_manager_v3.get_text_input", Child: child}, child, arg1); err != nil {
625583 return nil, err
626584 }
627585 return child, nil
@@ -161,10 +161,7 @@ func NewTextInputV3(ctx *wl.Context) *TextInputV3 {
161 161
162 // Destroy the wp_text_input object. Also disables all surfaces enabled through this wp_text_input object.162 // Destroy the wp_text_input object. Also disables all surfaces enabled through this wp_text_input object.
163 func (o *TextInputV3) Destroy() error {163 func (o *TextInputV3) Destroy() error {
164- if err := o.Context().CheckProxy(o); err != nil {164+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_text_input_v3.destroy", Destructor: true}); err != nil {
165- return err
166- }
167- if err := o.Context().SendDestructor(o, 0); err != nil {
168 return err165 return err
169 }166 }
170 return nil167 return nil
@@ -172,10 +169,7 @@ func (o *TextInputV3) Destroy() error {
172 169
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.170 // 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 {171 func (o *TextInputV3) Enable() error {
175- if err := o.Context().CheckProxy(o); err != nil {172+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_text_input_v3.enable"}); err != nil {
176- return err
177- }
178- if err := o.Context().SendRequest(o, 1); err != nil {
179 return err173 return err
180 }174 }
181 return nil175 return nil
@@ -183,10 +177,7 @@ func (o *TextInputV3) Enable() error {
183 177
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.178 // 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 {179 func (o *TextInputV3) Disable() error {
186- if err := o.Context().CheckProxy(o); err != nil {180+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "zwp_text_input_v3.disable"}); err != nil {
187- return err
188- }
189- if err := o.Context().SendRequest(o, 2); err != nil {
190 return err181 return err
191 }182 }
192 return nil183 return nil
@@ -194,10 +185,7 @@ func (o *TextInputV3) Disable() error {
194 185
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.186 // 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 {187 func (o *TextInputV3) SetSurroundingText(text string, cursor int32, anchor int32) error {
197- if err := o.Context().CheckProxy(o); err != nil {188+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "zwp_text_input_v3.set_surrounding_text"}, text, cursor, anchor); err != nil {
198- return err
199- }
200- if err := o.Context().SendRequest(o, 3, text, cursor, anchor); err != nil {
201 return err189 return err
202 }190 }
203 return nil191 return nil
@@ -205,10 +193,7 @@ func (o *TextInputV3) SetSurroundingText(text string, cursor int32, anchor int32
205 193
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.194 // 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 {195 func (o *TextInputV3) SetTextChangeCause(cause uint32) error {
208- if err := o.Context().CheckProxy(o); err != nil {196+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "zwp_text_input_v3.set_text_change_cause"}, cause); err != nil {
209- return err
210- }
211- if err := o.Context().SendRequest(o, 4, cause); err != nil {
212 return err197 return err
213 }198 }
214 return nil199 return nil
@@ -216,10 +201,7 @@ func (o *TextInputV3) SetTextChangeCause(cause uint32) error {
216 201
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.202 // 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 {203 func (o *TextInputV3) SetContentType(hint uint32, purpose uint32) error {
219- if err := o.Context().CheckProxy(o); err != nil {204+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 5, Name: "zwp_text_input_v3.set_content_type"}, hint, purpose); err != nil {
220- return err
221- }
222- if err := o.Context().SendRequest(o, 5, hint, purpose); err != nil {
223 return err205 return err
224 }206 }
225 return nil207 return nil
@@ -227,10 +209,7 @@ func (o *TextInputV3) SetContentType(hint uint32, purpose uint32) error {
227 209
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.210 // 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 {211 func (o *TextInputV3) SetCursorRectangle(x int32, y int32, width int32, height int32) error {
230- if err := o.Context().CheckProxy(o); err != nil {212+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 6, Name: "zwp_text_input_v3.set_cursor_rectangle"}, x, y, width, height); err != nil {
231- return err
232- }
233- if err := o.Context().SendRequest(o, 6, x, y, width, height); err != nil {
234 return err213 return err
235 }214 }
236 return nil215 return nil
@@ -238,10 +217,7 @@ func (o *TextInputV3) SetCursorRectangle(x int32, y int32, width int32, height i
238 217
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.218 // 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 {219 func (o *TextInputV3) Commit() error {
241- if err := o.Context().CheckProxy(o); err != nil {220+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 7, Name: "zwp_text_input_v3.commit"}); err != nil {
242- return err
243- }
244- if err := o.Context().SendRequest(o, 7); err != nil {
245 return err221 return err
246 }222 }
247 return nil223 return nil
@@ -249,10 +225,7 @@ func (o *TextInputV3) Commit() error {
249 225
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.226 // 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 {227 func (o *TextInputV3) SetAvailableActions(availableActions []byte) error {
252- if err := o.Context().CheckProxy(o); err != nil {228+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 8, Name: "zwp_text_input_v3.set_available_actions", Since: 2}, availableActions); err != nil {
253- return err
254- }
255- if err := o.Context().SendRequest(o, 8, availableActions); err != nil {
256 return err229 return err
257 }230 }
258 return nil231 return nil
@@ -260,10 +233,7 @@ func (o *TextInputV3) SetAvailableActions(availableActions []byte) error {
260 233
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.234 // 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 {235 func (o *TextInputV3) ShowInputPanel() error {
263- if err := o.Context().CheckProxy(o); err != nil {236+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 9, Name: "zwp_text_input_v3.show_input_panel", Since: 2}); err != nil {
264- return err
265- }
266- if err := o.Context().SendRequest(o, 9); err != nil {
267 return err237 return err
268 }238 }
269 return nil239 return nil
@@ -271,10 +241,7 @@ func (o *TextInputV3) ShowInputPanel() error {
271 241
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.242 // 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 {243 func (o *TextInputV3) HideInputPanel() error {
274- if err := o.Context().CheckProxy(o); err != nil {244+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 10, Name: "zwp_text_input_v3.hide_input_panel", Since: 2}); err != nil {
275- return err
276- }
277- if err := o.Context().SendRequest(o, 10); err != nil {
278 return err245 return err
279 }246 }
280 return nil247 return nil
@@ -598,10 +565,7 @@ func NewTextInputManagerV3(ctx *wl.Context) *TextInputManagerV3 {
598 565
599 // Destroy the wp_text_input_manager object.566 // Destroy the wp_text_input_manager object.
600 func (o *TextInputManagerV3) Destroy() error {567 func (o *TextInputManagerV3) Destroy() error {
601- if err := o.Context().CheckProxy(o); err != nil {568+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "zwp_text_input_manager_v3.destroy", Destructor: true}); err != nil {
602- return err
603- }
604- if err := o.Context().SendDestructor(o, 0); err != nil {
605 return err569 return err
606 }570 }
607 return nil571 return nil
@@ -609,19 +573,13 @@ func (o *TextInputManagerV3) Destroy() error {
609 573
610 // Creates a new text-input object for a given seat.574 // Creates a new text-input object for a given seat.
611 func (o *TextInputManagerV3) GetTextInput(seat *cross_wl_seat.Seat) (*TextInputV3, error) {575 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.Object576 var arg1 wl.Object
616 if seat != nil {577 if seat != nil {
617 arg1 = seat578 arg1 = seat
618 }579 }
619 child := &TextInputV3{}580 child := &TextInputV3{}
620 child.SetContext(o.Context())581 child.SetContext(o.Context())
621- child.SetID(o.Context().AllocateID())582+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "zwp_text_input_manager_v3.get_text_input", Child: child}, child, arg1); err != nil {
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, err583 return nil, err
626 }584 }
627 return child, nil585 return child, nil
M protocol/viewporter/viewporter_generated.go +5 -23
@@ -42,10 +42,7 @@ func NewWpViewporter(ctx *wl.Context) *WpViewporter {
4242
4343 // 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.
4444 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 {
45+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_viewporter.destroy", Destructor: true}); err != nil {
4946 return err
5047 }
5148 return nil
@@ -53,19 +50,13 @@ func (o *WpViewporter) Destroy() error {
5350
5451 // 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.
5552 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- }
5953 var arg1 wl.Object
6054 if surface != nil {
6155 arg1 = surface
6256 }
6357 child := &WpViewport{}
6458 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)
59+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wp_viewporter.get_viewport", Child: child}, child, arg1); err != nil {
6960 return nil, err
7061 }
7162 return child, nil
@@ -104,10 +95,7 @@ func NewWpViewport(ctx *wl.Context) *WpViewport {
10495
10596 // The associated wl_surface's crop and scale state is removed. The change is applied on the next wl_surface.commit.
10697 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 {
98+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_viewport.destroy", Destructor: true}); err != nil {
11199 return err
112100 }
113101 return nil
@@ -115,10 +103,7 @@ func (o *WpViewport) Destroy() error {
115103
116104 // 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.
117105 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 {
106+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wp_viewport.set_source"}, x, y, width, height); err != nil {
122107 return err
123108 }
124109 return nil
@@ -126,10 +111,7 @@ func (o *WpViewport) SetSource(x wl.Fixed, y wl.Fixed, width wl.Fixed, height wl
126111
127112 // 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.
128113 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 {
114+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wp_viewport.set_destination"}, width, height); err != nil {
133115 return err
134116 }
135117 return nil
@@ -42,10 +42,7 @@ func NewWpViewporter(ctx *wl.Context) *WpViewporter {
42 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.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 {44 func (o *WpViewporter) Destroy() error {
45- if err := o.Context().CheckProxy(o); err != nil {45+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_viewporter.destroy", Destructor: true}); err != nil {
46- return err
47- }
48- if err := o.Context().SendDestructor(o, 0); err != nil {
49 return err46 return err
50 }47 }
51 return nil48 return nil
@@ -53,19 +50,13 @@ func (o *WpViewporter) Destroy() error {
53 50
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.51 // 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) {52 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.Object53 var arg1 wl.Object
60 if surface != nil {54 if surface != nil {
61 arg1 = surface55 arg1 = surface
62 }56 }
63 child := &WpViewport{}57 child := &WpViewport{}
64 child.SetContext(o.Context())58 child.SetContext(o.Context())
65- child.SetID(o.Context().AllocateID())59+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wp_viewporter.get_viewport", Child: child}, child, arg1); err != nil {
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, err60 return nil, err
70 }61 }
71 return child, nil62 return child, nil
@@ -104,10 +95,7 @@ func NewWpViewport(ctx *wl.Context) *WpViewport {
104 95
105 // The associated wl_surface's crop and scale state is removed. The change is applied on the next wl_surface.commit.96 // 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 {97 func (o *WpViewport) Destroy() error {
107- if err := o.Context().CheckProxy(o); err != nil {98+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "wp_viewport.destroy", Destructor: true}); err != nil {
108- return err
109- }
110- if err := o.Context().SendDestructor(o, 0); err != nil {
111 return err99 return err
112 }100 }
113 return nil101 return nil
@@ -115,10 +103,7 @@ func (o *WpViewport) Destroy() error {
115 103
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.104 // 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 {105 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 {106+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "wp_viewport.set_source"}, x, y, width, height); err != nil {
119- return err
120- }
121- if err := o.Context().SendRequest(o, 1, x, y, width, height); err != nil {
122 return err107 return err
123 }108 }
124 return nil109 return nil
@@ -126,10 +111,7 @@ func (o *WpViewport) SetSource(x wl.Fixed, y wl.Fixed, width wl.Fixed, height wl
126 111
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.112 // 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 {113 func (o *WpViewport) SetDestination(width int32, height int32) error {
129- if err := o.Context().CheckProxy(o); err != nil {114+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "wp_viewport.set_destination"}, width, height); err != nil {
130- return err
131- }
132- if err := o.Context().SendRequest(o, 2, width, height); err != nil {
133 return err115 return err
134 }116 }
135 return nil117 return nil
M protocol/xdgshell/xdg-shell_generated.go +36 -156
@@ -242,10 +242,7 @@ func NewXdgWmBase(ctx *wl.Context) *XdgWmBase {
242242
243243 // 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.
244244 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 {
245+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "xdg_wm_base.destroy", Destructor: true}); err != nil {
249246 return err
250247 }
251248 return nil
@@ -253,15 +250,9 @@ func (o *XdgWmBase) Destroy() error {
253250
254251 // 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.
255252 func (o *XdgWmBase) CreatePositioner() (*XdgPositioner, error) {
256- if err := o.Context().CheckProxy(o); err != nil {
257- return nil, err
258- }
259253 child := &XdgPositioner{}
260254 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)
255+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "xdg_wm_base.create_positioner", Child: child}, child); err != nil {
265256 return nil, err
266257 }
267258 return child, nil
@@ -269,19 +260,13 @@ func (o *XdgWmBase) CreatePositioner() (*XdgPositioner, error) {
269260
270261 // 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.
271262 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- }
275263 var arg1 wl.Object
276264 if surface != nil {
277265 arg1 = surface
278266 }
279267 child := &XdgSurface{}
280268 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)
269+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "xdg_wm_base.get_xdg_surface", Child: child}, child, arg1); err != nil {
285270 return nil, err
286271 }
287272 return child, nil
@@ -289,10 +274,7 @@ func (o *XdgWmBase) GetXdgSurface(surface *cross_wl_surface.Surface) (*XdgSurfac
289274
290275 // 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.
291276 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 {
277+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "xdg_wm_base.pong"}, serial); err != nil {
296278 return err
297279 }
298280 return nil
@@ -362,10 +344,7 @@ func NewXdgPositioner(ctx *wl.Context) *XdgPositioner {
362344
363345 // Notify the compositor that the xdg_positioner will no longer be used.
364346 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 {
347+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "xdg_positioner.destroy", Destructor: true}); err != nil {
369348 return err
370349 }
371350 return nil
@@ -373,10 +352,7 @@ func (o *XdgPositioner) Destroy() error {
373352
374353 // 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.
375354 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 {
355+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "xdg_positioner.set_size"}, width, height); err != nil {
380356 return err
381357 }
382358 return nil
@@ -384,10 +360,7 @@ func (o *XdgPositioner) SetSize(width int32, height int32) error {
384360
385361 // 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.
386362 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 {
363+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "xdg_positioner.set_anchor_rect"}, x, y, width, height); err != nil {
391364 return err
392365 }
393366 return nil
@@ -395,10 +368,7 @@ func (o *XdgPositioner) SetAnchorRect(x int32, y int32, width int32, height int3
395368
396369 // 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.
397370 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 {
371+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "xdg_positioner.set_anchor"}, anchor); err != nil {
402372 return err
403373 }
404374 return nil
@@ -406,10 +376,7 @@ func (o *XdgPositioner) SetAnchor(anchor uint32) error {
406376
407377 // 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.
408378 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 {
379+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "xdg_positioner.set_gravity"}, gravity); err != nil {
413380 return err
414381 }
415382 return nil
@@ -417,10 +384,7 @@ func (o *XdgPositioner) SetGravity(gravity uint32) error {
417384
418385 // 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.
419386 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 {
387+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 5, Name: "xdg_positioner.set_constraint_adjustment"}, constraintAdjustment); err != nil {
424388 return err
425389 }
426390 return nil
@@ -428,10 +392,7 @@ func (o *XdgPositioner) SetConstraintAdjustment(constraintAdjustment uint32) err
428392
429393 // 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.
430394 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 {
395+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 6, Name: "xdg_positioner.set_offset"}, x, y); err != nil {
435396 return err
436397 }
437398 return nil
@@ -439,10 +400,7 @@ func (o *XdgPositioner) SetOffset(x int32, y int32) error {
439400
440401 // 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.
441402 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 {
403+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 7, Name: "xdg_positioner.set_reactive", Since: 3}); err != nil {
446404 return err
447405 }
448406 return nil
@@ -450,10 +408,7 @@ func (o *XdgPositioner) SetReactive() error {
450408
451409 // 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.
452410 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 {
411+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 8, Name: "xdg_positioner.set_parent_size", Since: 3}, parentWidth, parentHeight); err != nil {
457412 return err
458413 }
459414 return nil
@@ -461,10 +416,7 @@ func (o *XdgPositioner) SetParentSize(parentWidth int32, parentHeight int32) err
461416
462417 // 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.
463418 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 {
419+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 9, Name: "xdg_positioner.set_parent_configure", Since: 3}, serial); err != nil {
468420 return err
469421 }
470422 return nil
@@ -507,10 +459,7 @@ func NewXdgSurface(ctx *wl.Context) *XdgSurface {
507459
508460 // 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.
509461 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 {
462+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "xdg_surface.destroy", Destructor: true}); err != nil {
514463 return err
515464 }
516465 return nil
@@ -518,15 +467,9 @@ func (o *XdgSurface) Destroy() error {
518467
519468 // 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.
520469 func (o *XdgSurface) GetToplevel() (*XdgToplevel, error) {
521- if err := o.Context().CheckProxy(o); err != nil {
522- return nil, err
523- }
524470 child := &XdgToplevel{}
525471 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)
472+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "xdg_surface.get_toplevel", Child: child}, child); err != nil {
530473 return nil, err
531474 }
532475 return child, nil
@@ -534,9 +477,6 @@ func (o *XdgSurface) GetToplevel() (*XdgToplevel, error) {
534477
535478 // 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.
536479 func (o *XdgSurface) GetPopup(parent *XdgSurface, positioner *XdgPositioner) (*XdgPopup, error) {
537- if err := o.Context().CheckProxy(o); err != nil {
538- return nil, err
539- }
540480 var arg1 wl.Object
541481 if parent != nil {
542482 arg1 = parent
@@ -547,10 +487,7 @@ func (o *XdgSurface) GetPopup(parent *XdgSurface, positioner *XdgPositioner) (*X
547487 }
548488 child := &XdgPopup{}
549489 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)
490+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "xdg_surface.get_popup", Child: child}, child, arg1, arg2); err != nil {
554491 return nil, err
555492 }
556493 return child, nil
@@ -558,10 +495,7 @@ func (o *XdgSurface) GetPopup(parent *XdgSurface, positioner *XdgPositioner) (*X
558495
559496 // 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.
560497 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 {
498+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "xdg_surface.set_window_geometry"}, x, y, width, height); err != nil {
565499 return err
566500 }
567501 return nil
@@ -569,10 +503,7 @@ func (o *XdgSurface) SetWindowGeometry(x int32, y int32, width int32, height int
569503
570504 // 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.
571505 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 {
506+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "xdg_surface.ack_configure"}, serial); err != nil {
576507 return err
577508 }
578509 return nil
@@ -649,10 +580,7 @@ func NewXdgToplevel(ctx *wl.Context) *XdgToplevel {
649580
650581 // This request destroys the role surface and unmaps the surface; see "Unmapping" behavior in interface section for details.
651582 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 {
583+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "xdg_toplevel.destroy", Destructor: true}); err != nil {
656584 return err
657585 }
658586 return nil
@@ -660,14 +588,11 @@ func (o *XdgToplevel) Destroy() error {
660588
661589 // 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.
662590 func (o *XdgToplevel) SetParent(parent *XdgToplevel) error {
663- if err := o.Context().CheckProxy(o); err != nil {
664- return err
665- }
666591 var arg0 wl.Object
667592 if parent != nil {
668593 arg0 = parent
669594 }
670- if err := o.Context().SendRequest(o, 1, arg0); err != nil {
595+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "xdg_toplevel.set_parent"}, arg0); err != nil {
671596 return err
672597 }
673598 return nil
@@ -675,10 +600,7 @@ func (o *XdgToplevel) SetParent(parent *XdgToplevel) error {
675600
676601 // 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.
677602 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 {
603+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "xdg_toplevel.set_title"}, title); err != nil {
682604 return err
683605 }
684606 return nil
@@ -686,10 +608,7 @@ func (o *XdgToplevel) SetTitle(title string) error {
686608
687609 // 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/
688610 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 {
611+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "xdg_toplevel.set_app_id"}, appId); err != nil {
693612 return err
694613 }
695614 return nil
@@ -697,14 +616,11 @@ func (o *XdgToplevel) SetAppId(appId string) error {
697616
698617 // 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.
699618 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- }
703619 var arg0 wl.Object
704620 if seat != nil {
705621 arg0 = seat
706622 }
707- if err := o.Context().SendRequest(o, 4, arg0, serial, x, y); err != nil {
623+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "xdg_toplevel.show_window_menu"}, arg0, serial, x, y); err != nil {
708624 return err
709625 }
710626 return nil
@@ -712,14 +628,11 @@ func (o *XdgToplevel) ShowWindowMenu(seat *cross_wl_seat.Seat, serial uint32, x
712628
713629 // 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.
714630 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- }
718631 var arg0 wl.Object
719632 if seat != nil {
720633 arg0 = seat
721634 }
722- if err := o.Context().SendRequest(o, 5, arg0, serial); err != nil {
635+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 5, Name: "xdg_toplevel.move"}, arg0, serial); err != nil {
723636 return err
724637 }
725638 return nil
@@ -727,14 +640,11 @@ func (o *XdgToplevel) Move(seat *cross_wl_seat.Seat, serial uint32) error {
727640
728641 // 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.
729642 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- }
733643 var arg0 wl.Object
734644 if seat != nil {
735645 arg0 = seat
736646 }
737- if err := o.Context().SendRequest(o, 6, arg0, serial, edges); err != nil {
647+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 6, Name: "xdg_toplevel.resize"}, arg0, serial, edges); err != nil {
738648 return err
739649 }
740650 return nil
@@ -742,10 +652,7 @@ func (o *XdgToplevel) Resize(seat *cross_wl_seat.Seat, serial uint32, edges uint
742652
743653 // 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.
744654 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 {
655+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 7, Name: "xdg_toplevel.set_max_size"}, width, height); err != nil {
749656 return err
750657 }
751658 return nil
@@ -753,10 +660,7 @@ func (o *XdgToplevel) SetMaxSize(width int32, height int32) error {
753660
754661 // 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.
755662 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 {
663+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 8, Name: "xdg_toplevel.set_min_size"}, width, height); err != nil {
760664 return err
761665 }
762666 return nil
@@ -764,10 +668,7 @@ func (o *XdgToplevel) SetMinSize(width int32, height int32) error {
764668
765669 // 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.
766670 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 {
671+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 9, Name: "xdg_toplevel.set_maximized"}); err != nil {
771672 return err
772673 }
773674 return nil
@@ -775,10 +676,7 @@ func (o *XdgToplevel) SetMaximized() error {
775676
776677 // 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.
777678 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 {
679+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 10, Name: "xdg_toplevel.unset_maximized"}); err != nil {
782680 return err
783681 }
784682 return nil
@@ -786,14 +684,11 @@ func (o *XdgToplevel) UnsetMaximized() error {
786684
787685 // 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.
788686 func (o *XdgToplevel) SetFullscreen(output *cross_wl_output.Output) error {
789- if err := o.Context().CheckProxy(o); err != nil {
790- return err
791- }
792687 var arg0 wl.Object
793688 if output != nil {
794689 arg0 = output
795690 }
796- if err := o.Context().SendRequest(o, 11, arg0); err != nil {
691+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 11, Name: "xdg_toplevel.set_fullscreen"}, arg0); err != nil {
797692 return err
798693 }
799694 return nil
@@ -801,10 +696,7 @@ func (o *XdgToplevel) SetFullscreen(output *cross_wl_output.Output) error {
801696
802697 // 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).
803698 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 {
699+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 12, Name: "xdg_toplevel.unset_fullscreen"}); err != nil {
808700 return err
809701 }
810702 return nil
@@ -812,10 +704,7 @@ func (o *XdgToplevel) UnsetFullscreen() error {
812704
813705 // 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.
814706 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 {
707+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 13, Name: "xdg_toplevel.set_minimized"}); err != nil {
819708 return err
820709 }
821710 return nil
@@ -986,10 +875,7 @@ func NewXdgPopup(ctx *wl.Context) *XdgPopup {
986875
987876 // 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.
988877 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 {
878+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "xdg_popup.destroy", Destructor: true}); err != nil {
993879 return err
994880 }
995881 return nil
@@ -997,14 +883,11 @@ func (o *XdgPopup) Destroy() error {
997883
998884 // 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.
999885 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- }
1003886 var arg0 wl.Object
1004887 if seat != nil {
1005888 arg0 = seat
1006889 }
1007- if err := o.Context().SendRequest(o, 1, arg0, serial); err != nil {
890+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "xdg_popup.grab"}, arg0, serial); err != nil {
1008891 return err
1009892 }
1010893 return nil
@@ -1012,14 +895,11 @@ func (o *XdgPopup) Grab(seat *cross_wl_seat.Seat, serial uint32) error {
1012895
1013896 // 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.
1014897 func (o *XdgPopup) Reposition(positioner *XdgPositioner, token uint32) error {
1015- if err := o.Context().CheckProxy(o); err != nil {
1016- return err
1017- }
1018898 var arg0 wl.Object
1019899 if positioner != nil {
1020900 arg0 = positioner
1021901 }
1022- if err := o.Context().SendRequest(o, 2, arg0, token); err != nil {
902+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "xdg_popup.reposition", Since: 3}, arg0, token); err != nil {
1023903 return err
1024904 }
1025905 return nil
@@ -242,10 +242,7 @@ func NewXdgWmBase(ctx *wl.Context) *XdgWmBase {
242 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.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 {244 func (o *XdgWmBase) Destroy() error {
245- if err := o.Context().CheckProxy(o); err != nil {245+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "xdg_wm_base.destroy", Destructor: true}); err != nil {
246- return err
247- }
248- if err := o.Context().SendDestructor(o, 0); err != nil {
249 return err246 return err
250 }247 }
251 return nil248 return nil
@@ -253,15 +250,9 @@ func (o *XdgWmBase) Destroy() error {
253 250
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.251 // 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) {252 func (o *XdgWmBase) CreatePositioner() (*XdgPositioner, error) {
256- if err := o.Context().CheckProxy(o); err != nil {
257- return nil, err
258- }
259 child := &XdgPositioner{}253 child := &XdgPositioner{}
260 child.SetContext(o.Context())254 child.SetContext(o.Context())
261- child.SetID(o.Context().AllocateID())255+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "xdg_wm_base.create_positioner", Child: child}, child); err != nil {
262- o.Context().Register(child)
263- if err := o.Context().SendRequest(o, 1, child); err != nil {
264- o.Context().Unregister(child)
265 return nil, err256 return nil, err
266 }257 }
267 return child, nil258 return child, nil
@@ -269,19 +260,13 @@ func (o *XdgWmBase) CreatePositioner() (*XdgPositioner, error) {
269 260
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.261 // 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) {262 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.Object263 var arg1 wl.Object
276 if surface != nil {264 if surface != nil {
277 arg1 = surface265 arg1 = surface
278 }266 }
279 child := &XdgSurface{}267 child := &XdgSurface{}
280 child.SetContext(o.Context())268 child.SetContext(o.Context())
281- child.SetID(o.Context().AllocateID())269+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "xdg_wm_base.get_xdg_surface", Child: child}, child, arg1); err != nil {
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, err270 return nil, err
286 }271 }
287 return child, nil272 return child, nil
@@ -289,10 +274,7 @@ func (o *XdgWmBase) GetXdgSurface(surface *cross_wl_surface.Surface) (*XdgSurfac
289 274
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.275 // 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 {276 func (o *XdgWmBase) Pong(serial uint32) error {
292- if err := o.Context().CheckProxy(o); err != nil {277+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "xdg_wm_base.pong"}, serial); err != nil {
293- return err
294- }
295- if err := o.Context().SendRequest(o, 3, serial); err != nil {
296 return err278 return err
297 }279 }
298 return nil280 return nil
@@ -362,10 +344,7 @@ func NewXdgPositioner(ctx *wl.Context) *XdgPositioner {
362 344
363 // Notify the compositor that the xdg_positioner will no longer be used.345 // Notify the compositor that the xdg_positioner will no longer be used.
364 func (o *XdgPositioner) Destroy() error {346 func (o *XdgPositioner) Destroy() error {
365- if err := o.Context().CheckProxy(o); err != nil {347+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "xdg_positioner.destroy", Destructor: true}); err != nil {
366- return err
367- }
368- if err := o.Context().SendDestructor(o, 0); err != nil {
369 return err348 return err
370 }349 }
371 return nil350 return nil
@@ -373,10 +352,7 @@ func (o *XdgPositioner) Destroy() error {
373 352
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.353 // 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 {354 func (o *XdgPositioner) SetSize(width int32, height int32) error {
376- if err := o.Context().CheckProxy(o); err != nil {355+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "xdg_positioner.set_size"}, width, height); err != nil {
377- return err
378- }
379- if err := o.Context().SendRequest(o, 1, width, height); err != nil {
380 return err356 return err
381 }357 }
382 return nil358 return nil
@@ -384,10 +360,7 @@ func (o *XdgPositioner) SetSize(width int32, height int32) error {
384 360
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.361 // 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 {362 func (o *XdgPositioner) SetAnchorRect(x int32, y int32, width int32, height int32) error {
387- if err := o.Context().CheckProxy(o); err != nil {363+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "xdg_positioner.set_anchor_rect"}, x, y, width, height); err != nil {
388- return err
389- }
390- if err := o.Context().SendRequest(o, 2, x, y, width, height); err != nil {
391 return err364 return err
392 }365 }
393 return nil366 return nil
@@ -395,10 +368,7 @@ func (o *XdgPositioner) SetAnchorRect(x int32, y int32, width int32, height int3
395 368
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.369 // 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 {370 func (o *XdgPositioner) SetAnchor(anchor uint32) error {
398- if err := o.Context().CheckProxy(o); err != nil {371+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "xdg_positioner.set_anchor"}, anchor); err != nil {
399- return err
400- }
401- if err := o.Context().SendRequest(o, 3, anchor); err != nil {
402 return err372 return err
403 }373 }
404 return nil374 return nil
@@ -406,10 +376,7 @@ func (o *XdgPositioner) SetAnchor(anchor uint32) error {
406 376
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.377 // 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 {378 func (o *XdgPositioner) SetGravity(gravity uint32) error {
409- if err := o.Context().CheckProxy(o); err != nil {379+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "xdg_positioner.set_gravity"}, gravity); err != nil {
410- return err
411- }
412- if err := o.Context().SendRequest(o, 4, gravity); err != nil {
413 return err380 return err
414 }381 }
415 return nil382 return nil
@@ -417,10 +384,7 @@ func (o *XdgPositioner) SetGravity(gravity uint32) error {
417 384
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.385 // 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 {386 func (o *XdgPositioner) SetConstraintAdjustment(constraintAdjustment uint32) error {
420- if err := o.Context().CheckProxy(o); err != nil {387+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 5, Name: "xdg_positioner.set_constraint_adjustment"}, constraintAdjustment); err != nil {
421- return err
422- }
423- if err := o.Context().SendRequest(o, 5, constraintAdjustment); err != nil {
424 return err388 return err
425 }389 }
426 return nil390 return nil
@@ -428,10 +392,7 @@ func (o *XdgPositioner) SetConstraintAdjustment(constraintAdjustment uint32) err
428 392
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.393 // 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 {394 func (o *XdgPositioner) SetOffset(x int32, y int32) error {
431- if err := o.Context().CheckProxy(o); err != nil {395+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 6, Name: "xdg_positioner.set_offset"}, x, y); err != nil {
432- return err
433- }
434- if err := o.Context().SendRequest(o, 6, x, y); err != nil {
435 return err396 return err
436 }397 }
437 return nil398 return nil
@@ -439,10 +400,7 @@ func (o *XdgPositioner) SetOffset(x int32, y int32) error {
439 400
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.401 // 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 {402 func (o *XdgPositioner) SetReactive() error {
442- if err := o.Context().CheckProxy(o); err != nil {403+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 7, Name: "xdg_positioner.set_reactive", Since: 3}); err != nil {
443- return err
444- }
445- if err := o.Context().SendRequest(o, 7); err != nil {
446 return err404 return err
447 }405 }
448 return nil406 return nil
@@ -450,10 +408,7 @@ func (o *XdgPositioner) SetReactive() error {
450 408
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.409 // 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 {410 func (o *XdgPositioner) SetParentSize(parentWidth int32, parentHeight int32) error {
453- if err := o.Context().CheckProxy(o); err != nil {411+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 8, Name: "xdg_positioner.set_parent_size", Since: 3}, parentWidth, parentHeight); err != nil {
454- return err
455- }
456- if err := o.Context().SendRequest(o, 8, parentWidth, parentHeight); err != nil {
457 return err412 return err
458 }413 }
459 return nil414 return nil
@@ -461,10 +416,7 @@ func (o *XdgPositioner) SetParentSize(parentWidth int32, parentHeight int32) err
461 416
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.417 // 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 {418 func (o *XdgPositioner) SetParentConfigure(serial uint32) error {
464- if err := o.Context().CheckProxy(o); err != nil {419+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 9, Name: "xdg_positioner.set_parent_configure", Since: 3}, serial); err != nil {
465- return err
466- }
467- if err := o.Context().SendRequest(o, 9, serial); err != nil {
468 return err420 return err
469 }421 }
470 return nil422 return nil
@@ -507,10 +459,7 @@ func NewXdgSurface(ctx *wl.Context) *XdgSurface {
507 459
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.460 // 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 {461 func (o *XdgSurface) Destroy() error {
510- if err := o.Context().CheckProxy(o); err != nil {462+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "xdg_surface.destroy", Destructor: true}); err != nil {
511- return err
512- }
513- if err := o.Context().SendDestructor(o, 0); err != nil {
514 return err463 return err
515 }464 }
516 return nil465 return nil
@@ -518,15 +467,9 @@ func (o *XdgSurface) Destroy() error {
518 467
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.468 // 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) {469 func (o *XdgSurface) GetToplevel() (*XdgToplevel, error) {
521- if err := o.Context().CheckProxy(o); err != nil {
522- return nil, err
523- }
524 child := &XdgToplevel{}470 child := &XdgToplevel{}
525 child.SetContext(o.Context())471 child.SetContext(o.Context())
526- child.SetID(o.Context().AllocateID())472+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "xdg_surface.get_toplevel", Child: child}, child); err != nil {
527- o.Context().Register(child)
528- if err := o.Context().SendRequest(o, 1, child); err != nil {
529- o.Context().Unregister(child)
530 return nil, err473 return nil, err
531 }474 }
532 return child, nil475 return child, nil
@@ -534,9 +477,6 @@ func (o *XdgSurface) GetToplevel() (*XdgToplevel, error) {
534 477
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.478 // 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) {479 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.Object480 var arg1 wl.Object
541 if parent != nil {481 if parent != nil {
542 arg1 = parent482 arg1 = parent
@@ -547,10 +487,7 @@ func (o *XdgSurface) GetPopup(parent *XdgSurface, positioner *XdgPositioner) (*X
547 }487 }
548 child := &XdgPopup{}488 child := &XdgPopup{}
549 child.SetContext(o.Context())489 child.SetContext(o.Context())
550- child.SetID(o.Context().AllocateID())490+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "xdg_surface.get_popup", Child: child}, child, arg1, arg2); err != nil {
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, err491 return nil, err
555 }492 }
556 return child, nil493 return child, nil
@@ -558,10 +495,7 @@ func (o *XdgSurface) GetPopup(parent *XdgSurface, positioner *XdgPositioner) (*X
558 495
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.496 // 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 {497 func (o *XdgSurface) SetWindowGeometry(x int32, y int32, width int32, height int32) error {
561- if err := o.Context().CheckProxy(o); err != nil {498+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "xdg_surface.set_window_geometry"}, x, y, width, height); err != nil {
562- return err
563- }
564- if err := o.Context().SendRequest(o, 3, x, y, width, height); err != nil {
565 return err499 return err
566 }500 }
567 return nil501 return nil
@@ -569,10 +503,7 @@ func (o *XdgSurface) SetWindowGeometry(x int32, y int32, width int32, height int
569 503
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.504 // 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 {505 func (o *XdgSurface) AckConfigure(serial uint32) error {
572- if err := o.Context().CheckProxy(o); err != nil {506+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "xdg_surface.ack_configure"}, serial); err != nil {
573- return err
574- }
575- if err := o.Context().SendRequest(o, 4, serial); err != nil {
576 return err507 return err
577 }508 }
578 return nil509 return nil
@@ -649,10 +580,7 @@ func NewXdgToplevel(ctx *wl.Context) *XdgToplevel {
649 580
650 // This request destroys the role surface and unmaps the surface; see "Unmapping" behavior in interface section for details.581 // This request destroys the role surface and unmaps the surface; see "Unmapping" behavior in interface section for details.
651 func (o *XdgToplevel) Destroy() error {582 func (o *XdgToplevel) Destroy() error {
652- if err := o.Context().CheckProxy(o); err != nil {583+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "xdg_toplevel.destroy", Destructor: true}); err != nil {
653- return err
654- }
655- if err := o.Context().SendDestructor(o, 0); err != nil {
656 return err584 return err
657 }585 }
658 return nil586 return nil
@@ -660,14 +588,11 @@ func (o *XdgToplevel) Destroy() error {
660 588
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.589 // 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 {590 func (o *XdgToplevel) SetParent(parent *XdgToplevel) error {
663- if err := o.Context().CheckProxy(o); err != nil {
664- return err
665- }
666 var arg0 wl.Object591 var arg0 wl.Object
667 if parent != nil {592 if parent != nil {
668 arg0 = parent593 arg0 = parent
669 }594 }
670- if err := o.Context().SendRequest(o, 1, arg0); err != nil {595+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "xdg_toplevel.set_parent"}, arg0); err != nil {
671 return err596 return err
672 }597 }
673 return nil598 return nil
@@ -675,10 +600,7 @@ func (o *XdgToplevel) SetParent(parent *XdgToplevel) error {
675 600
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.601 // 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 {602 func (o *XdgToplevel) SetTitle(title string) error {
678- if err := o.Context().CheckProxy(o); err != nil {603+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "xdg_toplevel.set_title"}, title); err != nil {
679- return err
680- }
681- if err := o.Context().SendRequest(o, 2, title); err != nil {
682 return err604 return err
683 }605 }
684 return nil606 return nil
@@ -686,10 +608,7 @@ func (o *XdgToplevel) SetTitle(title string) error {
686 608
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/609 // 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 {610 func (o *XdgToplevel) SetAppId(appId string) error {
689- if err := o.Context().CheckProxy(o); err != nil {611+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 3, Name: "xdg_toplevel.set_app_id"}, appId); err != nil {
690- return err
691- }
692- if err := o.Context().SendRequest(o, 3, appId); err != nil {
693 return err612 return err
694 }613 }
695 return nil614 return nil
@@ -697,14 +616,11 @@ func (o *XdgToplevel) SetAppId(appId string) error {
697 616
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.617 // 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 {618 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.Object619 var arg0 wl.Object
704 if seat != nil {620 if seat != nil {
705 arg0 = seat621 arg0 = seat
706 }622 }
707- if err := o.Context().SendRequest(o, 4, arg0, serial, x, y); err != nil {623+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 4, Name: "xdg_toplevel.show_window_menu"}, arg0, serial, x, y); err != nil {
708 return err624 return err
709 }625 }
710 return nil626 return nil
@@ -712,14 +628,11 @@ func (o *XdgToplevel) ShowWindowMenu(seat *cross_wl_seat.Seat, serial uint32, x
712 628
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.629 // 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 {630 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.Object631 var arg0 wl.Object
719 if seat != nil {632 if seat != nil {
720 arg0 = seat633 arg0 = seat
721 }634 }
722- if err := o.Context().SendRequest(o, 5, arg0, serial); err != nil {635+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 5, Name: "xdg_toplevel.move"}, arg0, serial); err != nil {
723 return err636 return err
724 }637 }
725 return nil638 return nil
@@ -727,14 +640,11 @@ func (o *XdgToplevel) Move(seat *cross_wl_seat.Seat, serial uint32) error {
727 640
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.641 // 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 {642 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.Object643 var arg0 wl.Object
734 if seat != nil {644 if seat != nil {
735 arg0 = seat645 arg0 = seat
736 }646 }
737- if err := o.Context().SendRequest(o, 6, arg0, serial, edges); err != nil {647+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 6, Name: "xdg_toplevel.resize"}, arg0, serial, edges); err != nil {
738 return err648 return err
739 }649 }
740 return nil650 return nil
@@ -742,10 +652,7 @@ func (o *XdgToplevel) Resize(seat *cross_wl_seat.Seat, serial uint32, edges uint
742 652
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.653 // 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 {654 func (o *XdgToplevel) SetMaxSize(width int32, height int32) error {
745- if err := o.Context().CheckProxy(o); err != nil {655+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 7, Name: "xdg_toplevel.set_max_size"}, width, height); err != nil {
746- return err
747- }
748- if err := o.Context().SendRequest(o, 7, width, height); err != nil {
749 return err656 return err
750 }657 }
751 return nil658 return nil
@@ -753,10 +660,7 @@ func (o *XdgToplevel) SetMaxSize(width int32, height int32) error {
753 660
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.661 // 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 {662 func (o *XdgToplevel) SetMinSize(width int32, height int32) error {
756- if err := o.Context().CheckProxy(o); err != nil {663+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 8, Name: "xdg_toplevel.set_min_size"}, width, height); err != nil {
757- return err
758- }
759- if err := o.Context().SendRequest(o, 8, width, height); err != nil {
760 return err664 return err
761 }665 }
762 return nil666 return nil
@@ -764,10 +668,7 @@ func (o *XdgToplevel) SetMinSize(width int32, height int32) error {
764 668
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.669 // 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 {670 func (o *XdgToplevel) SetMaximized() error {
767- if err := o.Context().CheckProxy(o); err != nil {671+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 9, Name: "xdg_toplevel.set_maximized"}); err != nil {
768- return err
769- }
770- if err := o.Context().SendRequest(o, 9); err != nil {
771 return err672 return err
772 }673 }
773 return nil674 return nil
@@ -775,10 +676,7 @@ func (o *XdgToplevel) SetMaximized() error {
775 676
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.677 // 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 {678 func (o *XdgToplevel) UnsetMaximized() error {
778- if err := o.Context().CheckProxy(o); err != nil {679+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 10, Name: "xdg_toplevel.unset_maximized"}); err != nil {
779- return err
780- }
781- if err := o.Context().SendRequest(o, 10); err != nil {
782 return err680 return err
783 }681 }
784 return nil682 return nil
@@ -786,14 +684,11 @@ func (o *XdgToplevel) UnsetMaximized() error {
786 684
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.685 // 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 {686 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.Object687 var arg0 wl.Object
793 if output != nil {688 if output != nil {
794 arg0 = output689 arg0 = output
795 }690 }
796- if err := o.Context().SendRequest(o, 11, arg0); err != nil {691+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 11, Name: "xdg_toplevel.set_fullscreen"}, arg0); err != nil {
797 return err692 return err
798 }693 }
799 return nil694 return nil
@@ -801,10 +696,7 @@ func (o *XdgToplevel) SetFullscreen(output *cross_wl_output.Output) error {
801 696
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).697 // 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 {698 func (o *XdgToplevel) UnsetFullscreen() error {
804- if err := o.Context().CheckProxy(o); err != nil {699+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 12, Name: "xdg_toplevel.unset_fullscreen"}); err != nil {
805- return err
806- }
807- if err := o.Context().SendRequest(o, 12); err != nil {
808 return err700 return err
809 }701 }
810 return nil702 return nil
@@ -812,10 +704,7 @@ func (o *XdgToplevel) UnsetFullscreen() error {
812 704
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.705 // 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 {706 func (o *XdgToplevel) SetMinimized() error {
815- if err := o.Context().CheckProxy(o); err != nil {707+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 13, Name: "xdg_toplevel.set_minimized"}); err != nil {
816- return err
817- }
818- if err := o.Context().SendRequest(o, 13); err != nil {
819 return err708 return err
820 }709 }
821 return nil710 return nil
@@ -986,10 +875,7 @@ func NewXdgPopup(ctx *wl.Context) *XdgPopup {
986 875
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.876 // 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 {877 func (o *XdgPopup) Destroy() error {
989- if err := o.Context().CheckProxy(o); err != nil {878+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 0, Name: "xdg_popup.destroy", Destructor: true}); err != nil {
990- return err
991- }
992- if err := o.Context().SendDestructor(o, 0); err != nil {
993 return err879 return err
994 }880 }
995 return nil881 return nil
@@ -997,14 +883,11 @@ func (o *XdgPopup) Destroy() error {
997 883
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.884 // 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 {885 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.Object886 var arg0 wl.Object
1004 if seat != nil {887 if seat != nil {
1005 arg0 = seat888 arg0 = seat
1006 }889 }
1007- if err := o.Context().SendRequest(o, 1, arg0, serial); err != nil {890+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 1, Name: "xdg_popup.grab"}, arg0, serial); err != nil {
1008 return err891 return err
1009 }892 }
1010 return nil893 return nil
@@ -1012,14 +895,11 @@ func (o *XdgPopup) Grab(seat *cross_wl_seat.Seat, serial uint32) error {
1012 895
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.896 // 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 {897 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.Object898 var arg0 wl.Object
1019 if positioner != nil {899 if positioner != nil {
1020 arg0 = positioner900 arg0 = positioner
1021 }901 }
1022- if err := o.Context().SendRequest(o, 2, arg0, token); err != nil {902+ if err := o.Context().Request(wl.Request{Proxy: o, Opcode: 2, Name: "xdg_popup.reposition", Since: 3}, arg0, token); err != nil {
1023 return err903 return err
1024 }904 }
1025 return nil905 return nil
M wl/wl.go +3 -0
@@ -22,6 +22,7 @@ type (
2222 RegistryGlobalEvent = wlturbo.RegistryGlobalEvent
2323 RegistryGlobalRemoveEvent = wlturbo.RegistryGlobalRemoveEvent
2424 OwnedFD = wlturbo.OwnedFD
25+ Request = wlturbo.Request
2526
2627 // Transport failures. Without these, a caller that imports this shim has to
2728 // import the root package as well just to classify an error.
@@ -35,6 +36,7 @@ var (
3536 NewFixed = wlturbo.NewFixed
3637 NewContext = wlturbo.NewContext
3738 CloseSentFD = wlturbo.CloseSentFD
39+ CheckVersion = wlturbo.CheckVersion
3840 CreateAnonymousFile = wlturbo.CreateAnonymousFile
3941 MapMemory = wlturbo.MapMemory
4042 UnmapMemory = wlturbo.UnmapMemory
@@ -47,4 +49,5 @@ var (
4749 ErrUnknownObject = wlturbo.ErrUnknownObject
4850 ErrUnknownOpcode = wlturbo.ErrUnknownOpcode
4951 ErrDisplayError = wlturbo.ErrDisplayError
52+ ErrVersionTooLow = wlturbo.ErrVersionTooLow
5053 )
@@ -22,6 +22,7 @@ type (
22 RegistryGlobalEvent = wlturbo.RegistryGlobalEvent22 RegistryGlobalEvent = wlturbo.RegistryGlobalEvent
23 RegistryGlobalRemoveEvent = wlturbo.RegistryGlobalRemoveEvent23 RegistryGlobalRemoveEvent = wlturbo.RegistryGlobalRemoveEvent
24 OwnedFD = wlturbo.OwnedFD24 OwnedFD = wlturbo.OwnedFD
25+ Request = wlturbo.Request
25 26
26 // Transport failures. Without these, a caller that imports this shim has to27 // Transport failures. Without these, a caller that imports this shim has to
27 // import the root package as well just to classify an error.28 // import the root package as well just to classify an error.
@@ -35,6 +36,7 @@ var (
35 NewFixed = wlturbo.NewFixed36 NewFixed = wlturbo.NewFixed
36 NewContext = wlturbo.NewContext37 NewContext = wlturbo.NewContext
37 CloseSentFD = wlturbo.CloseSentFD38 CloseSentFD = wlturbo.CloseSentFD
39+ CheckVersion = wlturbo.CheckVersion
38 CreateAnonymousFile = wlturbo.CreateAnonymousFile40 CreateAnonymousFile = wlturbo.CreateAnonymousFile
39 MapMemory = wlturbo.MapMemory41 MapMemory = wlturbo.MapMemory
40 UnmapMemory = wlturbo.UnmapMemory42 UnmapMemory = wlturbo.UnmapMemory
@@ -47,4 +49,5 @@ var (
47 ErrUnknownObject = wlturbo.ErrUnknownObject49 ErrUnknownObject = wlturbo.ErrUnknownObject
48 ErrUnknownOpcode = wlturbo.ErrUnknownOpcode50 ErrUnknownOpcode = wlturbo.ErrUnknownOpcode
49 ErrDisplayError = wlturbo.ErrDisplayError51 ErrDisplayError = wlturbo.ErrDisplayError
52+ ErrVersionTooLow = wlturbo.ErrVersionTooLow
50 )53 )

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