detached 1852b82

Merge d08e09740c9dfda20d9091dd6605af9de66a9a00 into ba4ad521151d3500de111a037937f8e1dd3922d2

commit
1852b8267cab66879ec14234f52c340eee68c152
author
ermite · · 2026-10-22 07:06 UTC
merge of
ba4ad52 + d08e097 · diff against the first parent
signature
unsigned
102 files · +16959 -1
A bigreq/replies_fuzz_test.go +21 -0
@@ -0,0 +1,21 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package bigreq
3+
4+import "testing"
5+
6+func FuzzParseEnableReply(f *testing.F) {
7+ f.Add(make([]byte, 32))
8+ f.Fuzz(func(t *testing.T, raw []byte) {
9+ r, ok := ParseEnableReply(raw)
10+ if !ok {
11+ if len(raw) >= 32 {
12+ t.Fatal("rejected a complete fixed-size reply")
13+ }
14+ return
15+ }
16+ if len(r.Raw()) != len(raw) {
17+ t.Fatal("Raw must return the parsed bytes")
18+ }
19+ _ = r.MaximumRequestLength()
20+ })
21+}
A bigreq/replies_generated.go +21 -0
@@ -0,0 +1,21 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package bigreq
3+
4+import "encoding/binary"
5+
6+// EnableReply is a zero-copy view over a Enable reply; offsets count from reply byte 0.
7+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
8+type EnableReply struct{ raw []byte }
9+
10+// ParseEnableReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
11+func ParseEnableReply(raw []byte) (EnableReply, bool) {
12+ if len(raw) < 32 {
13+ return EnableReply{}, false
14+ }
15+ r := EnableReply{raw: raw}
16+ return r, true
17+}
18+func (r EnableReply) Raw() []byte { return r.raw }
19+func (r EnableReply) MaximumRequestLength() uint32 {
20+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
21+}
A bigreq/requests_generated.go +21 -0
@@ -0,0 +1,21 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package bigreq
3+
4+import "bnema.dev/xturbo"
5+
6+func Enable(b *xturbo.Buf) xturbo.Seq {
7+ if b.Ext == nil {
8+ b.Fail(xturbo.ErrExtMissing)
9+ return 0
10+ }
11+ major := b.Ext.Major(xturbo.ExtBigRequests)
12+ if major == 0 {
13+ b.Fail(xturbo.ErrExtMissing)
14+ return 0
15+ }
16+ p, seq := b.Request(major, 0, 0)
17+ if p == nil {
18+ return 0
19+ }
20+ return seq
21+}
A bigreq/sizes_test.go +11 -0
@@ -0,0 +1,11 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package bigreq
3+
4+import "testing"
5+
6+func TestWireSizes(t *testing.T) {
7+ if got := 32; got != 32 {
8+ t.Errorf("reply Enable fixed size = %d", got)
9+ }
10+
11+}
A bigreq/types_generated.go +2 -0
@@ -0,0 +1,2 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package bigreq
A buf.go +92 -0
@@ -0,0 +1,92 @@
1+package xturbo
2+
3+import (
4+ "encoding/binary"
5+ "errors"
6+)
7+
8+// Seq identifies a request; zero is invalid.
9+type Seq uint64
10+
11+var (
12+ ErrRequestTooLarge = errors.New("xturbo: request too large")
13+ ErrExtMissing = errors.New("xturbo: extension missing")
14+ ErrBadLength = errors.New("xturbo: bad length")
15+ ErrSeqOverflow = errors.New("xturbo: sequence overflow")
16+)
17+
18+// Buf is the caller-owned request encoder. The transport will own flushing and
19+// acknowledgment in Phase 3. It is not safe for concurrent use.
20+type Buf struct {
21+ Ext *ExtTable
22+ b []byte
23+ flushed int
24+ next, acked Seq
25+ maxReq uint32
26+ err error
27+}
28+
29+func NewBuf(size int) *Buf {
30+ if size <= 0 {
31+ size = 64 << 10
32+ }
33+ return &Buf{b: make([]byte, 0, size), next: 1, maxReq: 262140}
34+}
35+func (b *Buf) Fail(err error) {
36+ if b.err == nil {
37+ b.err = err
38+ }
39+}
40+func (b *Buf) Err() error { return b.err }
41+func (b *Buf) Reset() { b.b = b.b[:0]; b.flushed = 0 }
42+func (b *Buf) Bytes() []byte { return b.b[b.flushed:] }
43+func (b *Buf) Len() int { return len(b.b) - b.flushed }
44+func (b *Buf) Next() Seq { return b.next }
45+
46+// Request reserves a zeroed, four-byte-aligned body after the wire header.
47+// BIG-REQUESTS enablement is transport-owned; maxReq starts at the core limit.
48+func (b *Buf) Request(major, data uint8, body int) ([]byte, Seq) {
49+ if b.err != nil {
50+ return nil, 0
51+ }
52+ if body < 0 || body&3 != 0 {
53+ b.Fail(ErrBadLength)
54+ return nil, 0
55+ }
56+ if uint64(body)+4 > uint64(b.maxReq) {
57+ b.Fail(ErrRequestTooLarge)
58+ return nil, 0
59+ }
60+ if b.next-b.acked >= 0xffff {
61+ b.Fail(ErrSeqOverflow)
62+ return nil, 0
63+ }
64+ header := 4
65+ if (body+4)/4 > 0xffff {
66+ header = 8
67+ }
68+ total := body + header
69+ start := len(b.b)
70+ if total > cap(b.b)-start {
71+ capacity := cap(b.b) * 2
72+ if capacity < start+total {
73+ capacity = start + total
74+ }
75+ grown := make([]byte, start, capacity)
76+ copy(grown, b.b)
77+ b.b = grown
78+ }
79+ b.b = b.b[:start+total]
80+ p := b.b[start:]
81+ clear(p)
82+ p[0] = major
83+ p[1] = data
84+ if header == 4 {
85+ binary.LittleEndian.PutUint16(p[2:], uint16(total/4))
86+ } else {
87+ binary.LittleEndian.PutUint32(p[4:], uint32(total/4))
88+ }
89+ seq := b.next
90+ b.next++
91+ return p[header:], seq
92+}
A buf_test.go +69 -0
@@ -0,0 +1,69 @@
1+package xturbo
2+
3+import (
4+ "bytes"
5+ "encoding/binary"
6+ "errors"
7+ "testing"
8+)
9+
10+func TestBufRequest(t *testing.T) {
11+ b := NewBuf(4)
12+ p, seq := b.Request(8, 2, 4)
13+ if seq != 1 || len(p) != 4 || !bytes.Equal(b.Bytes(), []byte{8, 2, 2, 0, 0, 0, 0, 0}) {
14+ t.Fatalf("%x %d", b.Bytes(), seq)
15+ }
16+ p[0] = 255
17+ b.Reset()
18+ p, seq = b.Request(14, 0, 4)
19+ if seq != 2 || p[0] != 0 || b.Next() != 3 || b.Len() != 8 {
20+ t.Fatal("reset sequence/zeroing")
21+ }
22+ first := errors.New("first")
23+ b.Fail(first)
24+ b.Fail(ErrBadLength)
25+ p, seq = b.Request(1, 0, 0)
26+ if p != nil || seq != 0 || b.Err() != first {
27+ t.Fatal("sticky error")
28+ }
29+}
30+func TestBufLimits(t *testing.T) {
31+ for _, body := range []int{-1, 1, 262140} {
32+ b := NewBuf(0)
33+ p, s := b.Request(1, 0, body)
34+ if p != nil || s != 0 || b.Err() == nil || b.Len() != 0 {
35+ t.Fatal(body)
36+ }
37+ }
38+ b := NewBuf(0)
39+ b.next = 0xffff
40+ if p, s := b.Request(1, 0, 0); p != nil || s != 0 || b.Err() != ErrSeqOverflow {
41+ t.Fatal("overflow")
42+ }
43+ b = NewBuf(0)
44+ b.maxReq = 1 << 20
45+ p, s := b.Request(1, 0, 262140)
46+ if s != 1 || len(p) != 262140 || binary.LittleEndian.Uint16(b.Bytes()[2:]) != 0 || binary.LittleEndian.Uint32(b.Bytes()[4:]) != 65537 {
47+ t.Fatal("BIG-REQUESTS header")
48+ }
49+}
50+func TestAllocBufRequest(t *testing.T) {
51+ for _, body := range []int{4, 65536} {
52+ b := NewBuf(128 << 10)
53+ if n := testing.AllocsPerRun(1000, func() { b.Reset(); b.Request(1, 0, body) }); n != 0 {
54+ t.Fatal(n)
55+ }
56+ if b.Err() != nil {
57+ t.Fatal(b.Err())
58+ }
59+ }
60+}
61+func BenchmarkBufRequest(b *testing.B) {
62+ buf := NewBuf(0)
63+ b.ReportAllocs()
64+ for b.Loop() {
65+ buf.Reset()
66+ buf.acked = buf.next
67+ buf.Request(1, 0, 4)
68+ }
69+}
A cmd/xtgen/emit.go +252 -0
@@ -0,0 +1,252 @@
1+package main
2+
3+import (
4+ "bytes"
5+ "embed"
6+ "fmt"
7+ "go/format"
8+ "os"
9+ "path/filepath"
10+ "sort"
11+ "strings"
12+ "text/template"
13+)
14+
15+//go:embed templates/*.tmpl
16+var templates embed.FS
17+
18+func writeTemplate(path, name string, data any) error {
19+ t, err := template.ParseFS(templates, "templates/"+name+".tmpl")
20+ if err != nil {
21+ return err
22+ }
23+ var b bytes.Buffer
24+ if err = t.Execute(&b, data); err != nil {
25+ return err
26+ }
27+ code, err := format.Source(b.Bytes())
28+ if err != nil {
29+ return fmt.Errorf("format %s: %w\n%s", path, err, b.String())
30+ }
31+ if err = os.MkdirAll(filepath.Dir(path), 0755); err != nil {
32+ return err
33+ }
34+ return os.WriteFile(path, code, 0644)
35+}
36+func putScalar(t *Type, src, dst string) string {
37+ if t.Base == "bool" {
38+ if t.Size == 1 {
39+ return fmt.Sprintf("if %s { %s[0]=1 } else { %s[0]=0 };", src, dst, dst)
40+ }
41+ return fmt.Sprintf("if %s { binary.LittleEndian.PutUint32(%s,1) } else { binary.LittleEndian.PutUint32(%s,0) };", src, dst, dst)
42+ }
43+ if t.Size == 1 {
44+ return fmt.Sprintf("%s[0]=byte(%s);", dst, src)
45+ }
46+ return fmt.Sprintf("binary.LittleEndian.PutUint%d(%s,uint%d(%s));", 8*t.Size, dst, 8*t.Size, src)
47+}
48+func getScalar(t *Type, goType, src string) string {
49+ value := src + "[0]"
50+ if t.Size > 1 {
51+ value = fmt.Sprintf("binary.LittleEndian.Uint%d(%s)", 8*t.Size, src)
52+ }
53+ if t.Base == "bool" {
54+ return "(" + value + "!=0)"
55+ }
56+ return goType + "(" + value + ")"
57+}
58+func isScalar(t *Type) bool { return t.Base != "" }
59+func typeDecl(t *Type) (string, error) {
60+ if isScalar(t) {
61+ return fmt.Sprintf("type %s %s", t.GoType, t.Base), nil
62+ }
63+ var b strings.Builder
64+ if t.Kind == "union" {
65+ fmt.Fprintf(&b, "type %s struct { raw []byte }; const %sSize=%d;\n", t.GoType, t.GoType, t.Size)
66+ fmt.Fprintf(&b, "func Get%s(p []byte) %s { return %s{raw:p[:%d]} };\n", t.GoType, t.GoType, t.GoType, t.Size)
67+ fmt.Fprintf(&b, "func (v %s) Put(p []byte) { copy(p[:%d],v.raw) };\n", t.GoType, t.Size)
68+ for _, f := range t.Fields {
69+ if f.Kind == "pad" {
70+ continue
71+ }
72+ if f.Kind == "list" {
73+ fmt.Fprintf(&b, "func (v %s) %s() (out %s) { for i:=range out { out[i]=%s }; return };\n", t.GoType, f.Name, f.GoType, getScalar(f.Type, qualified(t.Module, f.Type.Module, f.Type.GoType), fmt.Sprintf("v.raw[i*%d:]", f.Type.Size)))
74+ } else {
75+ fmt.Fprintf(&b, "func (v %s) %s() %s { return %s };\n", t.GoType, f.Name, f.GoType, getScalar(f.Type, f.GoType, "v.raw"))
76+ }
77+ }
78+ return b.String(), nil
79+ }
80+ fmt.Fprintf(&b, "type %s struct {\n", t.GoType)
81+ for _, f := range t.Fields {
82+ if f.Kind != "pad" {
83+ name := f.Name
84+ if name == "Size" || name == "Put" {
85+ name += "_"
86+ }
87+ fmt.Fprintf(&b, "%s %s\n", name, f.GoType)
88+ }
89+ }
90+ b.WriteString("}\n")
91+ fmt.Fprintf(&b, "const %sSize=%d;\n", t.GoType, t.Size)
92+ if t.Variable {
93+ fmt.Fprintf(&b, "func (v %s) Size() int { off:=0;", t.GoType)
94+ for _, f := range t.Fields {
95+ name := f.Name
96+ if name == "Size" || name == "Put" {
97+ name += "_"
98+ }
99+ if f.Align > 0 {
100+ fmt.Fprintf(&b, "off=(off+%d)&^%d;", f.Align-1, f.Align-1)
101+ } else if f.Kind == "list" && f.Count == 0 {
102+ if f.Type.Variable {
103+ fmt.Fprintf(&b, "for i:=range v.%s { off+=v.%s[i].Size() };", name, name)
104+ } else {
105+ fmt.Fprintf(&b, "off+=len(v.%s)*%d;", name, f.Type.Size)
106+ }
107+ } else {
108+ fmt.Fprintf(&b, "off+=%d;", f.Size)
109+ }
110+ }
111+ b.WriteString("return off };\n")
112+ }
113+ fmt.Fprintf(&b, "func (v %s) Put(p []byte) { ", t.GoType)
114+ if t.Variable {
115+ b.WriteString("off:=0;")
116+ } else {
117+ fmt.Fprintf(&b, "clear(p[:%d]);", t.Size)
118+ }
119+ for _, f := range t.Fields {
120+ name := f.Name
121+ if name == "Size" || name == "Put" {
122+ name += "_"
123+ }
124+ off := fmt.Sprint(f.Off)
125+ if t.Variable {
126+ off = "off"
127+ }
128+ if f.Kind == "pad" {
129+ if t.Variable {
130+ if f.Align > 0 {
131+ fmt.Fprintf(&b, "{ next:=(off+%d)&^%d; clear(p[off:next]); off=next };", f.Align-1, f.Align-1)
132+ } else {
133+ fmt.Fprintf(&b, "clear(p[off:off+%d]); off+=%d;", f.Size, f.Size)
134+ }
135+ }
136+ continue
137+ }
138+ src := "v." + name
139+ dst := "p[" + off + ":]"
140+ if f.Kind == "list" {
141+ fmt.Fprintf(&b, "for i:=range %s {", src)
142+ item := src + "[i]"
143+ target := fmt.Sprintf("p[%s+i*%d:]", off, f.Type.Size)
144+ if f.Type.Variable {
145+ target = "p[off:]"
146+ }
147+ if isScalar(f.Type) {
148+ b.WriteString(putScalar(f.Type, item, target))
149+ } else {
150+ fmt.Fprintf(&b, "%s.Put(%s);", item, target)
151+ }
152+ if f.Type.Variable {
153+ fmt.Fprintf(&b, "off+=%s.Size();", item)
154+ }
155+ b.WriteString("};")
156+ if t.Variable && !f.Type.Variable {
157+ fmt.Fprintf(&b, "off+=len(%s)*%d;", src, f.Type.Size)
158+ }
159+ } else {
160+ if isScalar(f.Type) {
161+ b.WriteString(putScalar(f.Type, src, dst))
162+ } else {
163+ fmt.Fprintf(&b, "%s.Put(%s);", src, dst)
164+ }
165+ if t.Variable {
166+ fmt.Fprintf(&b, "off+=%d;", f.Size)
167+ }
168+ }
169+ }
170+ b.WriteString("}\n")
171+ if !t.Variable {
172+ fmt.Fprintf(&b, "func Get%s(p []byte) (v %s) { _=p[%d];", t.GoType, t.GoType, t.Size-1)
173+ for _, f := range t.Fields {
174+ if f.Kind == "pad" {
175+ continue
176+ }
177+ dst := "v." + f.Name
178+ src := fmt.Sprintf("p[%d:]", f.Off)
179+ if f.Kind == "list" {
180+ fmt.Fprintf(&b, "for i:=range %s { %s[i]=%s };", dst, dst, getScalar(f.Type, qualified(t.Module, f.Type.Module, f.Type.GoType), fmt.Sprintf("p[%d+i*%d:]", f.Off, f.Type.Size)))
181+ } else if isScalar(f.Type) {
182+ fmt.Fprintf(&b, "%s=%s;", dst, getScalar(f.Type, f.GoType, src))
183+ } else {
184+ fmt.Fprintf(&b, "%s=%s(%s);", dst, qualified(t.Module, f.Type.Module, "Get"+f.Type.GoType), src)
185+ }
186+ }
187+ b.WriteString("return };\n")
188+ }
189+ return b.String(), nil
190+}
191+func importsFor(m *Module, decls string) string {
192+ paths := map[string]string{"binary.": "encoding/binary", "bits.": "math/bits"}
193+ for _, dep := range m.Imports {
194+ paths[dep.Pkg+"."] = "bnema.dev/xturbo/" + dep.Pkg
195+ }
196+ var imports []string
197+ for prefix, path := range paths {
198+ if strings.Contains(decls, prefix) {
199+ imports = append(imports, fmt.Sprintf("import %q", path))
200+ }
201+ }
202+ sort.Strings(imports)
203+ return strings.Join(imports, "\n")
204+}
205+func emitTypes(modules []*Module) error {
206+ for _, m := range modules {
207+ for _, t := range m.Types {
208+ decl, err := typeDecl(t)
209+ if err != nil {
210+ return err
211+ }
212+ m.Decls = append(m.Decls, decl)
213+ }
214+ for _, e := range m.Enums {
215+ var b strings.Builder
216+ if !e.Existing {
217+ fmt.Fprintf(&b, "type %s %s;\n", e.Name, e.Base)
218+ }
219+ for _, item := range e.Items {
220+ fmt.Fprintf(&b, "const %s %s = %d;\n", item.Name, e.Name, item.Value)
221+ }
222+ m.Decls = append(m.Decls, b.String())
223+ }
224+ imp := importsFor(m, strings.Join(m.Decls, "\n"))
225+ m.Decls = append([]string{imp}, m.Decls...)
226+ if err := writeTemplate(filepath.Join(m.Pkg, "types_generated.go"), "types", m); err != nil {
227+ return err
228+ }
229+ for _, t := range m.Types {
230+ if t.Kind == "struct" || t.Kind == "union" {
231+ m.SizeChecks = append(m.SizeChecks, fmt.Sprintf("if %sSize != %d { t.Errorf(%q, %sSize) }", t.GoType, t.Size, t.GoType+" fixed prefix = %d", t.GoType))
232+ }
233+ }
234+ if err := packetSizeChecks(m); err != nil {
235+ return err
236+ }
237+ if err := writeTemplate(filepath.Join(m.Pkg, "sizes_test.go"), "sizes", m); err != nil {
238+ return err
239+ }
240+ }
241+ var extensions []*Module
242+ for _, m := range modules {
243+ if m.ExtName != "" {
244+ extensions = append(extensions, m)
245+ }
246+ }
247+ return writeTemplate("ext_generated.go", "ext", extensions)
248+}
249+
250+func sizeCheck(name string, got, want int) string {
251+ return fmt.Sprintf("if got:= %d; got != %d { t.Errorf(%q,got) }", got, want, name+" fixed size = %d")
252+}
A cmd/xtgen/expr.go +43 -0
@@ -0,0 +1,43 @@
1+package main
2+
3+import "fmt"
4+
5+// renderExpr centralizes expression lowering; callers supply parameter, owned
6+// field, or getter references. No expression decisions are left to templates.
7+func renderExpr(n *Node, ref func(string) string, m *Module) (string, error) {
8+ if n == nil {
9+ return "", nil
10+ }
11+ switch n.Kind {
12+ case "value":
13+ return n.Text, nil
14+ case "fieldref":
15+ return ref(n.Text), nil
16+ case "enumref":
17+ e, owner := findEnum(m, n.Attr["ref"])
18+ if e == nil {
19+ return "", n.fail("unknown enum %s", n.Attr["ref"])
20+ }
21+ return "int(" + qualified(m, owner, e.Name+goName(n.Text)) + ")", nil
22+ case "op", "unop", "popcount":
23+ var parts []string
24+ for _, c := range n.Children {
25+ s, err := renderExpr(c, ref, m)
26+ if err != nil {
27+ return "", err
28+ }
29+ parts = append(parts, s)
30+ }
31+ if n.Kind == "popcount" {
32+ return "bits.OnesCount(uint(" + parts[0] + "))", nil
33+ }
34+ if n.Kind == "unop" {
35+ return "(^" + parts[0] + ")", nil
36+ }
37+ if len(parts) != 2 {
38+ return "", n.fail("invalid binary expression")
39+ }
40+ return "(" + parts[0] + " " + n.Attr["op"] + " " + parts[1] + ")", nil
41+ }
42+ return "", fmt.Errorf("%s:%d: unsupported expression %s", n.File, n.Line, n.Kind)
43+}
A cmd/xtgen/ir.go +39 -0
@@ -0,0 +1,39 @@
1+package main
2+
3+// Type is a resolved wire type. Size is the fixed prefix, not Go's memory size.
4+type Type struct {
5+ Name, GoType, Base, Kind string
6+ Size int
7+ Variable bool
8+ Node *Node
9+ Module *Module
10+ Fields []Field
11+ Resolving, Resolved bool
12+}
13+type Field struct {
14+ Name, Param, GoType, Kind string
15+ Off, Size, Count, Align int
16+ Type *Type
17+ Node *Node
18+ Expr *Node
19+}
20+type Enum struct {
21+ Name, Base string
22+ Existing bool
23+ Items []EnumItem
24+ Node *Node
25+}
26+type EnumItem struct {
27+ Name string
28+ Value int64
29+}
30+type Module struct {
31+ Pkg, Header, XName, ExtName string
32+ Root *Node
33+ Imports []*Module
34+ Types []*Type
35+ Enums []Enum
36+ Symbols map[string]*Type
37+ Names map[string]*Node
38+ Decls, SizeChecks []string
39+}
A cmd/xtgen/layout.go +103 -0
@@ -0,0 +1,103 @@
1+package main
2+
3+import "strconv"
4+
5+// packetFixed computes the minimum complete packet size. The first XML byte
6+// occupies byte 1; the implicit sequence/length header follows that byte.
7+func packetFixed(m *Module, n *Node, reply bool) (int, error) {
8+ off := 1
9+ if n.Attr["no-sequence-number"] == "true" {
10+ off = 1
11+ }
12+ for _, f := range n.Children {
13+ if f.Kind == "doc" {
14+ continue
15+ }
16+ size := 0
17+ switch f.Kind {
18+ case "pad":
19+ if a := f.Attr["align"]; a != "" {
20+ align, _ := strconv.Atoi(a)
21+ size = (-off) & (align - 1)
22+ } else {
23+ size, _ = strconv.Atoi(f.Attr["bytes"])
24+ }
25+ case "field", "exprfield":
26+ typ, err := lookup(m, f.Attr["type"])
27+ if err != nil {
28+ return 0, err
29+ }
30+ size = typ.Size
31+ case "list":
32+ if len(f.Children) == 1 && f.Children[0].Kind == "value" {
33+ count, _ := strconv.Atoi(f.Children[0].Text)
34+ typ, err := lookup(m, f.Attr["type"])
35+ if err != nil {
36+ return 0, err
37+ }
38+ size = count * typ.Size
39+ } else {
40+ goto done
41+ }
42+ default:
43+ return 0, f.fail("unsupported packet member %s", f.Kind)
44+ }
45+ off += size
46+ if off == 2 && n.Attr["no-sequence-number"] != "true" {
47+ if reply {
48+ off = 8
49+ } else {
50+ off = 4
51+ }
52+ }
53+ }
54+done:
55+ if off < 32 {
56+ off = 32
57+ }
58+ return off, nil
59+}
60+func packetSizeChecks(m *Module) error {
61+ for _, n := range m.Root.Children {
62+ if n.Kind == "event" || n.Kind == "eventcopy" {
63+ size := 32
64+ if n.Kind == "event" {
65+ var err error
66+ size, err = packetFixed(m, n, false)
67+ if err != nil {
68+ return err
69+ }
70+ }
71+ if size != 32 {
72+ return n.fail("event fixed size %d, expected 32", size)
73+ }
74+ m.SizeChecks = append(m.SizeChecks, sizeCheck("event "+n.Attr["name"], size, 32))
75+ }
76+ if n.Kind == "request" {
77+ for _, r := range n.Children {
78+ if r.Kind != "reply" {
79+ continue
80+ }
81+ size, err := packetFixed(m, r, true)
82+ if err != nil {
83+ return err
84+ }
85+ expected := 32
86+ if m.Header == "xproto" {
87+ switch n.Attr["name"] {
88+ case "QueryKeymap":
89+ expected = 40
90+ case "GetKeyboardControl":
91+ expected = 52
92+ case "GetWindowAttributes":
93+ expected = 44
94+ case "QueryFont", "ListFontsWithInfo":
95+ expected = 60
96+ }
97+ }
98+ m.SizeChecks = append(m.SizeChecks, sizeCheck("reply "+n.Attr["name"], size, expected))
99+ }
100+ }
101+ }
102+ return nil
103+}
M cmd/xtgen/main.go +47 -1
@@ -1,4 +1,50 @@
11 // Command xtgen generates bindings from the pinned xcb-proto XML.
22 package main
33
4-func main() {}
4+import (
5+ "flag"
6+ "fmt"
7+ "os"
8+ "path/filepath"
9+)
10+
11+func main() {
12+ all := flag.Bool("all", false, "process all vendored modules")
13+ flag.Parse()
14+ paths := flag.Args()
15+ if *all {
16+ var err error
17+ paths, err = filepath.Glob("spec/xml/*.xml")
18+ if err != nil {
19+ fmt.Fprintln(os.Stderr, err)
20+ os.Exit(1)
21+ }
22+ }
23+ if len(paths) == 0 {
24+ fmt.Fprintln(os.Stderr, "xtgen: supply XML paths or -all")
25+ os.Exit(1)
26+ }
27+ if *all {
28+ modules, err := loadModules()
29+ if err == nil {
30+ err = emitTypes(modules)
31+ }
32+ if err == nil {
33+ err = emitRequests(modules)
34+ }
35+ if err == nil {
36+ err = emitReplies(modules)
37+ }
38+ if err != nil {
39+ fmt.Fprintln(os.Stderr, err)
40+ os.Exit(1)
41+ }
42+ return
43+ }
44+ for _, path := range paths {
45+ if _, err := parseFile(path); err != nil {
46+ fmt.Fprintln(os.Stderr, err)
47+ os.Exit(1)
48+ }
49+ }
50+}
A cmd/xtgen/naming.go +43 -0
@@ -0,0 +1,43 @@
1+package main
2+
3+import (
4+ "go/token"
5+ "strings"
6+ "unicode"
7+)
8+
9+func goName(s string) string {
10+ var out strings.Builder
11+ for _, part := range strings.Split(s, "_") {
12+ if part == "" {
13+ continue
14+ }
15+ if part == strings.ToUpper(part) {
16+ part = strings.ToLower(part)
17+ }
18+ r := []rune(part)
19+ r[0] = unicode.ToUpper(r[0])
20+ out.WriteString(string(r))
21+ }
22+ name := out.String()
23+ if name != "" && name[0] >= '0' && name[0] <= '9' {
24+ name = "X" + name
25+ }
26+ if token.Lookup(name).IsKeyword() {
27+ name += "_"
28+ }
29+ return name
30+}
31+func paramName(s string) string {
32+ name := goName(s)
33+ if name == "" {
34+ return name
35+ }
36+ r := []rune(name)
37+ r[0] = unicode.ToLower(r[0])
38+ name = string(r)
39+ if token.Lookup(name).IsKeyword() {
40+ name += "_"
41+ }
42+ return name
43+}
A cmd/xtgen/parse.go +292 -0
@@ -0,0 +1,292 @@
1+package main
2+
3+import (
4+ "encoding/xml"
5+ "fmt"
6+ "io"
7+ "os"
8+ "strconv"
9+ "strings"
10+)
11+
12+// Node retains XML order and source locations, including expressions. Resolution
13+// turns this syntax tree into the flat, typed emission IR; parsing makes no Go
14+// naming or layout choices.
15+type Node struct {
16+ Kind string
17+ Attr map[string]string
18+ Text string
19+ Children []*Node
20+ File string
21+ Line int
22+}
23+
24+func (n *Node) fail(format string, args ...any) error {
25+ return fmt.Errorf("%s:%d: %s", n.File, n.Line, fmt.Sprintf(format, args...))
26+}
27+
28+// Attribute and child whitelists are per element, not global: a known attribute
29+// or element used in the wrong place is also an error. Documentation is ignored.
30+var attributes = map[string]string{
31+ "xcb": "header extension-name extension-xname extension-multiword major-version minor-version",
32+ "import": "", "typedef": "oldname newname", "xidtype": "name", "xidunion": "name", "type": "",
33+ "enum": "name", "item": "name", "value": "", "bit": "", "struct": "name", "union": "name",
34+ "request": "name opcode combine-adjacent", "reply": "", "event": "name number no-sequence-number xge",
35+ "eventcopy": "name number ref", "error": "name number type", "errorcopy": "name number ref",
36+ "field": "name type enum altenum mask", "pad": "bytes align", "list": "name type enum",
37+ "exprfield": "name type", "switch": "name", "bitcase": "", "fieldref": "", "enumref": "ref",
38+ "op": "op", "unop": "op", "popcount": "", "doc": "",
39+}
40+var children = map[string]string{
41+ "xcb": "import typedef xidtype xidunion enum struct union request event eventcopy error errorcopy doc",
42+ "xidunion": "type", "enum": "item doc", "item": "value bit doc",
43+ "struct": "field pad list doc", "union": "field pad list doc",
44+ "request": "field pad list exprfield switch reply doc", "reply": "field pad list exprfield doc",
45+ "event": "field pad list exprfield doc", "error": "field pad doc",
46+ "list": "value fieldref op unop popcount enumref", "exprfield": "value fieldref op unop popcount enumref",
47+ "switch": "fieldref op unop popcount enumref bitcase", "bitcase": "enumref value field pad doc",
48+ "op": "value fieldref op unop popcount enumref", "unop": "value fieldref op unop popcount enumref",
49+ "popcount": "value fieldref op unop popcount enumref",
50+}
51+
52+func contains(words, word string) bool {
53+ for _, s := range strings.Fields(words) {
54+ if s == word {
55+ return true
56+ }
57+ }
58+ return false
59+}
60+
61+func parseFile(path string) (*Node, error) {
62+ f, err := os.Open(path)
63+ if err != nil {
64+ return nil, err
65+ }
66+ defer f.Close()
67+ return parseXML(path, f)
68+}
69+func parseXML(file string, r io.Reader) (*Node, error) {
70+ d := xml.NewDecoder(r)
71+ var root *Node
72+ var stack []*Node
73+ for {
74+ token, err := d.Token()
75+ if err == io.EOF {
76+ break
77+ }
78+ if err != nil {
79+ line, _ := d.InputPos()
80+ return nil, fmt.Errorf("%s:%d: %w", file, line, err)
81+ }
82+ switch t := token.(type) {
83+ case xml.StartElement:
84+ line, _ := d.InputPos()
85+ n := &Node{Kind: t.Name.Local, Attr: make(map[string]string), File: file, Line: line}
86+ allowed, ok := attributes[n.Kind]
87+ if !ok || t.Name.Space != "" {
88+ return nil, n.fail("unsupported element <%s>", t.Name.Local)
89+ }
90+ if len(stack) == 0 {
91+ if root != nil || n.Kind != "xcb" {
92+ return nil, n.fail("expected a single <xcb> root")
93+ }
94+ root = n
95+ } else {
96+ parent := stack[len(stack)-1]
97+ if !contains(children[parent.Kind], n.Kind) {
98+ return nil, n.fail("unsupported <%s> in <%s>", n.Kind, parent.Kind)
99+ }
100+ parent.Children = append(parent.Children, n)
101+ }
102+ if n.Kind == "doc" {
103+ if err := d.Skip(); err != nil {
104+ return nil, n.fail("invalid doc: %v", err)
105+ }
106+ continue
107+ }
108+ for _, a := range t.Attr {
109+ if a.Name.Space != "" || !contains(allowed, a.Name.Local) {
110+ return nil, n.fail("unknown attribute %q on <%s>", a.Name.Local, n.Kind)
111+ }
112+ if _, ok := n.Attr[a.Name.Local]; ok {
113+ return nil, n.fail("duplicate attribute %q", a.Name.Local)
114+ }
115+ n.Attr[a.Name.Local] = a.Value
116+ }
117+ stack = append(stack, n)
118+ case xml.EndElement:
119+ if len(stack) == 0 {
120+ return nil, fmt.Errorf("%s: unexpected closing element", file)
121+ }
122+ n := stack[len(stack)-1]
123+ n.Text = strings.TrimSpace(n.Text)
124+ if err := validateNode(n); err != nil {
125+ return nil, err
126+ }
127+ stack = stack[:len(stack)-1]
128+ case xml.CharData:
129+ if len(stack) > 0 {
130+ stack[len(stack)-1].Text += string(t)
131+ } else if strings.TrimSpace(string(t)) != "" {
132+ return nil, fmt.Errorf("%s: text outside root", file)
133+ }
134+ case xml.Directive:
135+ return nil, fmt.Errorf("%s: XML directives are unsupported", file)
136+ }
137+ }
138+ if root == nil {
139+ return nil, fmt.Errorf("%s:1: missing <xcb> root", file)
140+ }
141+ return root, nil
142+}
143+func require(n *Node, names string) error {
144+ for _, name := range strings.Fields(names) {
145+ if n.Attr[name] == "" {
146+ return n.fail("missing %s on <%s>", name, n.Kind)
147+ }
148+ }
149+ return nil
150+}
151+func number(n *Node, attr string, bits int) error {
152+ _, err := strconv.ParseUint(n.Attr[attr], 0, bits)
153+ if err != nil {
154+ return n.fail("invalid %s %q", attr, n.Attr[attr])
155+ }
156+ return nil
157+}
158+func exprCount(n *Node) int {
159+ count := 0
160+ for _, c := range n.Children {
161+ if c.Kind != "doc" {
162+ count++
163+ }
164+ }
165+ return count
166+}
167+func validateNode(n *Node) error {
168+ required := map[string]string{
169+ "xcb": "header", "typedef": "oldname newname", "xidtype": "name", "xidunion": "name",
170+ "enum": "name", "item": "name", "struct": "name", "union": "name", "request": "name opcode",
171+ "event": "name number", "eventcopy": "name number ref", "error": "name number", "errorcopy": "name number ref",
172+ "field": "name type", "list": "name type", "exprfield": "name type", "switch": "name", "enumref": "ref", "op": "op", "unop": "op",
173+ }
174+ if err := require(n, required[n.Kind]); err != nil {
175+ return err
176+ }
177+ switch n.Kind {
178+ case "import", "type", "fieldref", "enumref":
179+ if n.Text == "" {
180+ return n.fail("empty <%s>", n.Kind)
181+ }
182+ case "value", "bit":
183+ if _, err := strconv.ParseInt(n.Text, 0, 64); err != nil {
184+ return n.fail("invalid <%s> integer %q", n.Kind, n.Text)
185+ }
186+ case "pad":
187+ _, b := n.Attr["bytes"]
188+ _, a := n.Attr["align"]
189+ if b == a {
190+ return n.fail("pad requires exactly one of bytes or align")
191+ }
192+ key := "bytes"
193+ if a {
194+ key = "align"
195+ }
196+ if err := number(n, key, 31); err != nil {
197+ return err
198+ }
199+ if a {
200+ v, _ := strconv.Atoi(n.Attr[key])
201+ if v == 0 || v&(v-1) != 0 {
202+ return n.fail("pad alignment must be a positive power of two")
203+ }
204+ }
205+ case "request":
206+ if err := number(n, "opcode", 8); err != nil {
207+ return err
208+ }
209+ case "event", "eventcopy", "error", "errorcopy":
210+ if err := number(n, "number", 8); err != nil {
211+ return err
212+ }
213+ if n.Attr["xge"] == "true" {
214+ v, _ := strconv.Atoi(n.Attr["number"])
215+ if v >= 128 {
216+ return n.fail("xge evtype must be < 128")
217+ }
218+ }
219+ case "op":
220+ if !contains("+ - * / & | << >>", n.Attr["op"]) {
221+ return n.fail("unsupported operator %q", n.Attr["op"])
222+ }
223+ if exprCount(n) != 2 {
224+ return n.fail("op requires two operands")
225+ }
226+ case "unop":
227+ if n.Attr["op"] != "~" {
228+ return n.fail("unsupported unary operator %q", n.Attr["op"])
229+ }
230+ if exprCount(n) != 1 {
231+ return n.fail("unop requires one operand")
232+ }
233+ case "popcount", "exprfield", "item":
234+ if exprCount(n) != 1 {
235+ return n.fail("<%s> requires one expression", n.Kind)
236+ }
237+ case "list":
238+ if exprCount(n) > 1 {
239+ return n.fail("list has multiple length expressions")
240+ }
241+ case "bitcase":
242+ fields := 0
243+ for _, c := range n.Children {
244+ if c.Kind == "field" {
245+ fields++
246+ if contains("CARD8 CARD16 INT8 INT16 BOOL char BYTE void", c.Attr["type"]) {
247+ return c.fail("value-list bitcase requires a 4-byte field")
248+ }
249+ }
250+ }
251+ if fields != 1 {
252+ return n.fail("value-list bitcase requires exactly one field")
253+ }
254+ }
255+ for _, key := range []string{"xge", "no-sequence-number", "combine-adjacent", "extension-multiword"} {
256+ if v, ok := n.Attr[key]; ok && v != "true" && v != "false" {
257+ return n.fail("invalid boolean %s=%q", key, v)
258+ }
259+ }
260+ // Forward references cannot be laid out in one pass. Reject at the length
261+ // expression's location rather than failing later while emitting Go.
262+ declared := map[string]bool{}
263+ for _, c := range n.Children {
264+ if c.Kind == "field" || c.Kind == "exprfield" {
265+ declared[c.Attr["name"]] = true
266+ }
267+ }
268+ seen := map[string]bool{}
269+ for _, c := range n.Children {
270+ if c.Kind == "list" {
271+ var visit func(*Node) error
272+ visit = func(e *Node) error {
273+ if e.Kind == "fieldref" && declared[e.Text] && !seen[e.Text] {
274+ return e.fail("list length references later field %q", e.Text)
275+ }
276+ for _, child := range e.Children {
277+ if err := visit(child); err != nil {
278+ return err
279+ }
280+ }
281+ return nil
282+ }
283+ if err := visit(c); err != nil {
284+ return err
285+ }
286+ }
287+ if c.Kind == "field" || c.Kind == "exprfield" {
288+ seen[c.Attr["name"]] = true
289+ }
290+ }
291+ return nil
292+}
A cmd/xtgen/parse_test.go +74 -0
@@ -0,0 +1,74 @@
1+package main
2+
3+import (
4+ "path/filepath"
5+ "strings"
6+ "testing"
7+)
8+
9+func TestParseVendored(t *testing.T) {
10+ files, err := filepath.Glob("../../spec/xml/*.xml")
11+ if err != nil {
12+ t.Fatal(err)
13+ }
14+ if len(files) != 9 {
15+ t.Fatalf("got %d XML files, want 9", len(files))
16+ }
17+ for _, file := range files {
18+ t.Run(filepath.Base(file), func(t *testing.T) {
19+ n, err := parseFile(file)
20+ if err != nil {
21+ t.Fatal(err)
22+ }
23+ if n.Kind != "xcb" || len(n.Children) == 0 {
24+ t.Fatal("missing module AST")
25+ }
26+ })
27+ }
28+}
29+func TestParseRejects(t *testing.T) {
30+ cases := []struct{ name, body, want string }{
31+ {"unknown element", "<surprise/>", "unsupported element"},
32+ {"unknown attribute", `<xidtype name="WINDOW" surprise="yes"/>`, "unknown attribute"},
33+ {"misplaced known element", `<struct name="S"><reply/></struct>`, "unsupported <reply>"},
34+ {"sumof", `<request name="R" opcode="1"><list name="a" type="CARD8"><sumof ref="a"/></list></request>`, "sumof"},
35+ {"paramref", `<request name="R" opcode="1"><list name="a" type="CARD8"><paramref type="CARD8">a</paramref></list></request>`, "paramref"},
36+ {"case", `<request name="R" opcode="1"><switch name="s"><case/></switch></request>`, "case"},
37+ {"struct switch", `<struct name="S"><switch name="s"/></struct>`, "unsupported <switch>"},
38+ {"reply switch", `<request name="R" opcode="1"><reply><switch name="s"/></reply></request>`, "unsupported <switch>"},
39+ {"nested switch", `<request name="R" opcode="1"><switch name="s"><bitcase><switch name="s"/></bitcase></switch></request>`, "unsupported <switch>"},
40+ {"fd", `<request name="R" opcode="1"><fd name="fd"/></request>`, "fd"},
41+ {"eventstruct", `<eventstruct name="E"/>`, "eventstruct"},
42+ {"required alignment", `<struct name="S"><required_start_align align="4"/></struct>`, "required_start_align"},
43+ {"forward length", `<struct name="S"><list name="a" type="CARD8"><fieldref>n</fieldref></list><field name="n" type="CARD8"/></struct>`, "later field"},
44+ {"xge code", `<event name="E" number="128" xge="true"/>`, "evtype"},
45+ {"bad opcode", `<request name="R" opcode="256"/>`, "invalid opcode"},
46+ {"bad operator", `<request name="R" opcode="1"><exprfield name="x" type="CARD32"><op op="%"><value>1</value><value>2</value></op></exprfield></request>`, "unsupported operator"},
47+ {"wrong operands", `<request name="R" opcode="1"><exprfield name="x" type="CARD32"><op op="+"><value>1</value></op></exprfield></request>`, "two operands"},
48+ {"bad pad", `<struct name="S"><pad align="3"/></struct>`, "power of two"},
49+ {"namespace", `<xidtype xmlns="other" name="X"/>`, "unsupported element"},
50+ {"duplicate attr", `<xidtype name="X" name="Y"/>`, "duplicate attribute"},
51+ }
52+ for _, tc := range cases {
53+ t.Run(tc.name, func(t *testing.T) {
54+ _, err := parseXML("bad.xml", strings.NewReader("<xcb header=\"test\">\n"+tc.body+"\n</xcb>"))
55+ if err == nil || !strings.Contains(err.Error(), tc.want) || !strings.Contains(err.Error(), "bad.xml:2:") {
56+ t.Fatalf("got %v, want file:line and %q", err, tc.want)
57+ }
58+ })
59+ }
60+}
61+func TestParseAST(t *testing.T) {
62+ n, err := parseXML("ok.xml", strings.NewReader(`<xcb header="a"><doc><arbitrary/></doc><request name="R" opcode="1"><field type="CARD32" name="n"/><list type="CARD8" name="data"><op op="*"><fieldref>n</fieldref><value>4</value></op></list></request></xcb>`))
63+ if err != nil {
64+ t.Fatal(err)
65+ }
66+ r := n.Children[1]
67+ if r.Attr["name"] != "R" || r.Children[1].Children[0].Children[0].Text != "n" {
68+ t.Fatal("AST lost order or expression")
69+ }
70+}
71+func FuzzParseXML(f *testing.F) {
72+ f.Add(`<xcb header="test"/>`)
73+ f.Fuzz(func(t *testing.T, raw string) { _, _ = parseXML("fuzz.xml", strings.NewReader(raw)) })
74+}
A cmd/xtgen/replies.go +554 -0
@@ -0,0 +1,554 @@
1+package main
2+
3+import (
4+ "fmt"
5+ "path/filepath"
6+ "sort"
7+ "strconv"
8+ "strings"
9+)
10+
11+// member is one wire member of a decoded container (reply or variable struct
12+// view). Static is the offset from the container's byte 0, or -1 when it
13+// follows a variable-length list and must be recomputed from earlier members.
14+type member struct {
15+ XName, Method, Kind, GoType string
16+ Elem string // annotated element Go type for list views
17+ Type *Type
18+ Size, Align, Static int
19+ Count *Node
20+ ListKind string // bytes, scalar, struct, iter
21+}
22+
23+// container is the lowered layout shared by replies and variable struct views.
24+type container struct {
25+ Name, Recv string
26+ Members []member
27+ Fixed int // minimum byte length (static prefix)
28+ Dynamic int // index of the first variable list, -1 when none
29+ Reply bool
30+ Module *Module
31+}
32+
33+const replyLifetime = "It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep."
34+
35+func isByteElem(xml string) bool {
36+ return xml == "void" || xml == "BYTE" || xml == "CARD8" || xml == "char"
37+}
38+
39+func annotatedType(m *Module, n *Node, typ *Type) (string, error) {
40+ goType := qualified(m, typ.Module, typ.GoType)
41+ for _, attr := range []string{"enum", "mask"} {
42+ if name := n.Attr[attr]; name != "" {
43+ e, owner := findEnum(m, name)
44+ if e == nil {
45+ return "", n.fail("unknown %s %s", attr, name)
46+ }
47+ goType = qualified(m, owner, e.Name)
48+ }
49+ }
50+ return goType, nil
51+}
52+
53+// elemName names the per-package list view for an element type.
54+func elemName(goType string) string {
55+ if i := strings.LastIndex(goType, "."); i >= 0 {
56+ goType = goType[i+1:]
57+ }
58+ return strings.ToUpper(goType[:1]) + goType[1:]
59+}
60+
61+// buildContainer lowers XML members. Replies start at byte 1 (the first XML
62+// member occupies the header data byte) and continue at byte 8.
63+func buildContainer(m *Module, name, recv string, nodes []*Node, reply bool, reserved string) (*container, error) {
64+ c := &container{Name: name, Recv: recv, Reply: reply, Dynamic: -1, Module: m}
65+ off := 0
66+ if reply {
67+ off = 1
68+ }
69+ first := true
70+ methods := map[string]bool{}
71+ for _, n := range nodes {
72+ if n.Kind == "doc" {
73+ continue
74+ }
75+ mem := member{XName: n.Attr["name"], Kind: n.Kind, Static: off}
76+ if c.Dynamic >= 0 {
77+ mem.Static = -1
78+ }
79+ switch n.Kind {
80+ case "pad":
81+ if a := n.Attr["align"]; a != "" {
82+ mem.Align, _ = strconv.Atoi(a)
83+ if c.Dynamic < 0 {
84+ mem.Size = (-off) & (mem.Align - 1)
85+ }
86+ } else {
87+ mem.Size, _ = strconv.Atoi(n.Attr["bytes"])
88+ }
89+ case "field", "list":
90+ typ, err := lookup(m, n.Attr["type"])
91+ if err != nil {
92+ return nil, n.fail("%v", err)
93+ }
94+ mem.Type = typ
95+ mem.Method = goName(mem.XName)
96+ if contains(reserved, mem.Method) {
97+ mem.Method += "_"
98+ }
99+ if methods[mem.Method] {
100+ return nil, n.fail("duplicate getter %s", mem.Method)
101+ }
102+ methods[mem.Method] = true
103+ elem, err := annotatedType(m, n, typ)
104+ if err != nil {
105+ return nil, err
106+ }
107+ mem.Elem = elem
108+ if n.Kind == "field" {
109+ if typ.Variable {
110+ return nil, n.fail("variable-size field outside a list is unsupported")
111+ }
112+ mem.GoType = elem
113+ mem.Size = typ.Size
114+ break
115+ }
116+ if len(n.Children) != 1 {
117+ return nil, n.fail("reply-side list requires a length expression")
118+ }
119+ mem.Count = n.Children[0]
120+ switch {
121+ case isByteElem(n.Attr["type"]):
122+ mem.ListKind, mem.GoType = "bytes", "[]byte"
123+ case typ.Variable:
124+ if typ.Size == 0 {
125+ return nil, n.fail("variable struct %s has an empty fixed prefix", typ.Name)
126+ }
127+ mem.ListKind, mem.GoType = "iter", qualified(m, typ.Module, typ.GoType+"Iter")
128+ case isScalar(typ):
129+ mem.ListKind, mem.GoType = "scalar", elemName(elem)+"List"
130+ default:
131+ mem.ListKind, mem.GoType = "struct", elemName(elem)+"List"
132+ }
133+ constant := mem.Count.Kind == "value" && !typ.Variable
134+ if constant {
135+ count, _ := strconv.Atoi(mem.Count.Text)
136+ mem.Size = count * typ.Size
137+ } else if c.Dynamic < 0 {
138+ c.Dynamic = len(c.Members)
139+ }
140+ default:
141+ return nil, n.fail("unsupported %s member %s", map[bool]string{true: "reply", false: "struct"}[reply], n.Kind)
142+ }
143+ if reply && first {
144+ if mem.Size != 1 {
145+ return nil, n.fail("first reply member must occupy the header data byte")
146+ }
147+ off = 8
148+ first = false
149+ c.Members = append(c.Members, mem)
150+ continue
151+ }
152+ first = false
153+ if c.Dynamic < 0 {
154+ off += mem.Size
155+ }
156+ c.Members = append(c.Members, mem)
157+ }
158+ if c.Dynamic >= 0 {
159+ c.Fixed = c.Members[c.Dynamic].Static
160+ } else {
161+ c.Fixed = off
162+ }
163+ return c, nil
164+}
165+
166+// ref renders a field reference as a getter call on the receiver. Replies may
167+// refer to the implicit header length word.
168+func (c *container) ref(s string) string {
169+ for _, mem := range c.Members {
170+ if mem.Kind == "field" && mem.XName == s {
171+ return "int(" + c.Recv + "." + mem.Method + "())"
172+ }
173+ }
174+ if c.Reply && s == "length" {
175+ return "int(binary.LittleEndian.Uint32(" + c.Recv + ".raw[4:]))"
176+ }
177+ return "<unresolved " + s + ">"
178+}
179+
180+func (c *container) count(mem member) (string, error) {
181+ s, err := renderExpr(mem.Count, c.ref, c.Module)
182+ if err != nil {
183+ return "", err
184+ }
185+ if strings.Contains(s, "<unresolved") {
186+ return "", mem.Count.fail("list length references an unknown field")
187+ }
188+ return s, nil
189+}
190+
191+// advance emits code moving off past member i. With fail != "" every step is
192+// bounds-checked against raw.
193+func (c *container) advance(b *strings.Builder, i int, fail string) error {
194+ mem := c.Members[i]
195+ raw := c.Recv + ".raw"
196+ switch mem.Kind {
197+ case "pad":
198+ if mem.Align > 0 {
199+ fmt.Fprintf(b, "off=(off+%d)&^%d;", mem.Align-1, mem.Align-1)
200+ } else {
201+ fmt.Fprintf(b, "off+=%d;", mem.Size)
202+ }
203+ case "field":
204+ fmt.Fprintf(b, "off+=%d;", mem.Size)
205+ case "list":
206+ n, err := c.count(mem)
207+ if err != nil {
208+ return err
209+ }
210+ if mem.ListKind == "iter" {
211+ fmt.Fprintf(b, "{ n:=%s;", n)
212+ if fail != "" {
213+ fmt.Fprintf(b, "if off>len(%s) || n<0 || n>len(%s) { %s };", raw, raw, fail)
214+ }
215+ fmt.Fprintf(b, "it:=%s(%s[off:],n); for it.Next() { off+=it.Value().Size() };", qualified(c.Module, mem.Type.Module, "New"+mem.Type.GoType+"Iter"), raw)
216+ if fail != "" {
217+ fmt.Fprintf(b, "if it.Err() { %s };", fail)
218+ }
219+ b.WriteString("};")
220+ return nil
221+ }
222+ fmt.Fprintf(b, "{ n:=%s;", n)
223+ if fail != "" {
224+ fmt.Fprintf(b, "if n<0 || n>len(%s) { %s };", raw, fail)
225+ }
226+ fmt.Fprintf(b, "off+=n*%d };", mem.Type.Size)
227+ if fail != "" {
228+ fmt.Fprintf(b, "if off>len(%s) { %s };", raw, fail)
229+ }
230+ }
231+ return nil
232+}
233+
234+// offset emits statements leaving member i's offset in off.
235+func (c *container) offset(b *strings.Builder, i int) error {
236+ if c.Members[i].Static >= 0 {
237+ fmt.Fprintf(b, "off:=%d;", c.Members[i].Static)
238+ return nil
239+ }
240+ fmt.Fprintf(b, "off:=%d;", c.Fixed)
241+ for j := c.Dynamic; j < i; j++ {
242+ if err := c.advance(b, j, ""); err != nil {
243+ return err
244+ }
245+ }
246+ return nil
247+}
248+
249+// validate emits the full-length walk used by Parse and Iter.Next.
250+func (c *container) validate(b *strings.Builder, fail string) error {
251+ if c.Dynamic < 0 {
252+ return nil
253+ }
254+ fmt.Fprintf(b, "off:=%d;", c.Fixed)
255+ for j := c.Dynamic; j < len(c.Members); j++ {
256+ if err := c.advance(b, j, fail); err != nil {
257+ return err
258+ }
259+ }
260+ fmt.Fprintf(b, "if off>len(%s.raw) { %s };", c.Recv, fail)
261+ return nil
262+}
263+
264+// getters emits one method per field and list.
265+func (c *container) getters(b *strings.Builder, typ string, lists map[string]string) error {
266+ r := c.Recv
267+ for i, mem := range c.Members {
268+ if mem.Kind == "pad" {
269+ continue
270+ }
271+ fmt.Fprintf(b, "func (%s %s) %s() %s {", r, typ, mem.Method, mem.GoType)
272+ static := mem.Static >= 0
273+ at := fmt.Sprintf("%s.raw[%d:]", r, mem.Static)
274+ if !static {
275+ if err := c.offset(b, i); err != nil {
276+ return err
277+ }
278+ at = r + ".raw[off:]"
279+ }
280+ if mem.Kind == "field" {
281+ if isScalar(mem.Type) {
282+ fmt.Fprintf(b, "return %s };\n", getScalar(mem.Type, mem.GoType, at))
283+ } else {
284+ fmt.Fprintf(b, "return %s(%s) };\n", qualified(c.Module, mem.Type.Module, "Get"+mem.Type.GoType), at)
285+ }
286+ continue
287+ }
288+ if static {
289+ fmt.Fprintf(b, "off:=%d;", mem.Static)
290+ }
291+ n, err := c.count(mem)
292+ if err != nil {
293+ return err
294+ }
295+ switch mem.ListKind {
296+ case "iter":
297+ fmt.Fprintf(b, "return %s(%s.raw[off:],%s) };\n", qualified(c.Module, mem.Type.Module, "New"+mem.Type.GoType+"Iter"), r, n)
298+ case "bytes":
299+ fmt.Fprintf(b, "end:=off+%s; return %s.raw[off:end:end] };\n", n, r)
300+ default:
301+ fmt.Fprintf(b, "end:=off+(%s)*%d; return %s{b:%s.raw[off:end:end]} };\n", n, mem.Type.Size, mem.GoType, r)
302+ lists[mem.GoType] = listDecl(c.Module, mem.GoType, mem.Elem, mem.Type)
303+ }
304+ }
305+ return nil
306+}
307+
308+func listDecl(m *Module, name, goType string, elem *Type) string {
309+ var b strings.Builder
310+ fmt.Fprintf(&b, "// %s is a borrowed view over a wire list of %s. %s\n", name, goType, "It shares the lifetime of the bytes it was taken from; copy what you keep.")
311+ fmt.Fprintf(&b, "type %s struct { b []byte };\n", name)
312+ fmt.Fprintf(&b, "func (l %s) Len() int { return len(l.b)/%d };\n", name, elem.Size)
313+ src := fmt.Sprintf("l.b[i*%d:]", elem.Size)
314+ if isScalar(elem) {
315+ fmt.Fprintf(&b, "func (l %s) At(i int) %s { return %s };\n", name, goType, getScalar(elem, goType, src))
316+ } else {
317+ fmt.Fprintf(&b, "func (l %s) At(i int) %s { return %s(%s) };\n", name, goType, qualified(m, elem.Module, "Get"+elem.GoType), src)
318+ }
319+ return b.String()
320+}
321+
322+type replyIR struct {
323+ Req string
324+ C *container
325+}
326+
327+func resolveReplies(m *Module) ([]replyIR, []*container, error) {
328+ var replies []replyIR
329+ for _, n := range m.Root.Children {
330+ if n.Kind != "request" {
331+ continue
332+ }
333+ for _, r := range n.Children {
334+ if r.Kind != "reply" {
335+ continue
336+ }
337+ name := goName(n.Attr["name"])
338+ for _, s := range []string{name + "Reply", "Parse" + name + "Reply"} {
339+ if err := m.claim(s, r); err != nil {
340+ return nil, nil, err
341+ }
342+ }
343+ c, err := buildContainer(m, name+"Reply", "r", r.Children, true, "Raw")
344+ if err != nil {
345+ return nil, nil, err
346+ }
347+ replies = append(replies, replyIR{Req: name, C: c})
348+ }
349+ }
350+ var views []*container
351+ for _, t := range m.Types {
352+ if t.Kind != "struct" || !t.Variable {
353+ continue
354+ }
355+ for _, s := range []string{t.GoType + "View", t.GoType + "Iter", "New" + t.GoType + "Iter"} {
356+ if err := m.claim(s, t.Node); err != nil {
357+ return nil, nil, err
358+ }
359+ }
360+ c, err := buildContainer(m, t.GoType+"View", "v", t.Node.Children, false, "Raw Size")
361+ if err != nil {
362+ return nil, nil, err
363+ }
364+ views = append(views, c)
365+ }
366+ return replies, views, nil
367+}
368+
369+func replyDecl(r replyIR, lists map[string]string) (string, error) {
370+ c := r.C
371+ var b strings.Builder
372+ fmt.Fprintf(&b, "// %s is a zero-copy view over a %s reply; offsets count from reply byte 0.\n// %s\n", c.Name, r.Req, replyLifetime)
373+ fmt.Fprintf(&b, "type %s struct { raw []byte };\n", c.Name)
374+ fmt.Fprintf(&b, "// Parse%s validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.\n", c.Name)
375+ fmt.Fprintf(&b, "func Parse%s(raw []byte) (%s, bool) {", c.Name, c.Name)
376+ fixed := max(c.Fixed, 32)
377+ fmt.Fprintf(&b, "if len(raw)<%d { return %s{}, false };", fixed, c.Name)
378+ fmt.Fprintf(&b, "r:=%s{raw:raw};", c.Name)
379+ if err := c.validate(&b, "return "+c.Name+"{}, false"); err != nil {
380+ return "", err
381+ }
382+ b.WriteString("return r, true };\n")
383+ fmt.Fprintf(&b, "func (r %s) Raw() []byte { return r.raw };\n", c.Name)
384+ if err := c.getters(&b, c.Name, lists); err != nil {
385+ return "", err
386+ }
387+ return b.String(), nil
388+}
389+
390+func viewDecl(c *container, lists map[string]string) (string, error) {
391+ base := strings.TrimSuffix(c.Name, "View")
392+ iter := base + "Iter"
393+ var b strings.Builder
394+ fmt.Fprintf(&b, "// %s is a zero-copy view over one wire-encoded %s, yielded by %s.\n// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.\n", c.Name, base, iter)
395+ fmt.Fprintf(&b, "type %s struct { raw []byte };\n", c.Name)
396+ fmt.Fprintf(&b, "func (v %s) Raw() []byte { return v.raw };\n", c.Name)
397+ fmt.Fprintf(&b, "// Size is the element's wire size, including trailing alignment.\nfunc (v %s) Size() int { return len(v.raw) };\n", c.Name)
398+ // size%s returns the element's wire size at the start of p, -1 when malformed.
399+ fmt.Fprintf(&b, "func size%s(p []byte) int { if len(p)<%d { return -1 }; v:=%s{raw:p}; _=v;", base, c.Fixed, c.Name)
400+ if c.Dynamic < 0 {
401+ fmt.Fprintf(&b, "return %d };\n", c.Fixed)
402+ } else {
403+ if err := c.validate(&b, "return -1"); err != nil {
404+ return "", err
405+ }
406+ b.WriteString("return off };\n")
407+ }
408+ if err := c.getters(&b, c.Name, lists); err != nil {
409+ return "", err
410+ }
411+ fmt.Fprintf(&b, "// %s walks n consecutive %s elements; Err reports a malformed length.\n// It shares the lifetime of the bytes it walks.\n", iter, base)
412+ fmt.Fprintf(&b, "type %s struct { b []byte; n int; v %s; err bool };\n", iter, c.Name)
413+ fmt.Fprintf(&b, "// New%s iterates n elements encoded at the start of b.\nfunc New%s(b []byte, n int) %s { return %s{b:b, n:n} };\n", iter, iter, iter, iter)
414+ fmt.Fprintf(&b, "func (it *%s) Next() bool { if it.n<=0 || it.err { return false }; s:=size%s(it.b); if s<0 { it.err=true; it.n=0; return false }; it.v=%s{raw:it.b[:s:s]}; it.b=it.b[s:]; it.n--; return true };\n", iter, base, c.Name)
415+ fmt.Fprintf(&b, "func (it *%s) Value() %s { return it.v };\n", iter, c.Name)
416+ fmt.Fprintf(&b, "func (it *%s) Err() bool { return it.err };\n", iter)
417+ return b.String(), nil
418+}
419+
420+// touch emits fuzz statements calling every getter and walking every list,
421+// recursing into variable struct views.
422+func touch(b *strings.Builder, c *container, expr string, depth int, all map[*Type]*container, failIter string) {
423+ for _, mem := range c.Members {
424+ switch {
425+ case mem.Kind == "field":
426+ fmt.Fprintf(b, "_ = %s.%s();", expr, mem.Method)
427+ case mem.Kind == "list" && mem.ListKind == "bytes":
428+ fmt.Fprintf(b, "_ = len(%s.%s());", expr, mem.Method)
429+ case mem.Kind == "list" && mem.ListKind == "iter":
430+ it := fmt.Sprintf("it%d", depth)
431+ fmt.Fprintf(b, "{ %s := %s.%s(); for %s.Next() {", it, expr, mem.Method, it)
432+ if child := all[mem.Type]; child != nil {
433+ touch(b, child, it+".Value()", depth+1, all, failIter)
434+ }
435+ fmt.Fprintf(b, "}; if %s.Err() { %s } };", it, failIter)
436+ case mem.Kind == "list":
437+ l := fmt.Sprintf("l%d", depth)
438+ fmt.Fprintf(b, "{ %s := %s.%s(); for i := 0; i < %s.Len(); i++ { _ = %s.At(i) } };", l, expr, mem.Method, l, l)
439+ }
440+ }
441+}
442+
443+func emitReplies(modules []*Module) error {
444+ type pending struct {
445+ m *Module
446+ replies []replyIR
447+ views []*container
448+ }
449+ var all []pending
450+ views := map[*Type]*container{}
451+ for _, m := range modules {
452+ replies, vs, err := resolveReplies(m)
453+ if err != nil {
454+ return err
455+ }
456+ for _, v := range vs {
457+ for _, t := range m.Types {
458+ if t.GoType+"View" == v.Name {
459+ views[t] = v
460+ }
461+ }
462+ }
463+ all = append(all, pending{m, replies, vs})
464+ }
465+ for _, p := range all {
466+ m := p.m
467+ lists := map[string]string{}
468+ var decls []string
469+ for _, r := range p.replies {
470+ d, err := replyDecl(r, lists)
471+ if err != nil {
472+ return err
473+ }
474+ decls = append(decls, d)
475+ }
476+ for _, v := range p.views {
477+ d, err := viewDecl(v, lists)
478+ if err != nil {
479+ return err
480+ }
481+ decls = append(decls, d)
482+ }
483+ var names []string
484+ for name := range lists {
485+ if err := m.claim(name, m.Root); err != nil {
486+ return err
487+ }
488+ names = append(names, name)
489+ }
490+ sort.Strings(names)
491+ for _, name := range names {
492+ decls = append(decls, lists[name])
493+ }
494+ if len(decls) == 0 {
495+ continue
496+ }
497+ decls = append([]string{importsFor(m, strings.Join(decls, "\n"))}, decls...)
498+ data := struct {
499+ Pkg string
500+ Decls []string
501+ }{Pkg: m.Pkg, Decls: decls}
502+ if err := writeTemplate(filepath.Join(m.Pkg, "replies_generated.go"), "replies", data); err != nil {
503+ return err
504+ }
505+ if err := emitReplyFuzz(m, p.replies, views); err != nil {
506+ return err
507+ }
508+ }
509+ return nil
510+}
511+
512+// emitReplyFuzz writes FuzzParse<Req>Reply for every reply. Seeds are the
513+// zero-filled fixed prefix plus any captured goldens <Req>*.reply.hex.
514+func emitReplyFuzz(m *Module, replies []replyIR, views map[*Type]*container) error {
515+ var decls []string
516+ usesGolden := false
517+ for _, r := range replies {
518+ var b strings.Builder
519+ c := r.C
520+ fmt.Fprintf(&b, "func FuzzParse%s(f *testing.F) {\n", c.Name)
521+ fmt.Fprintf(&b, "f.Add(make([]byte, %d));\n", (max(c.Fixed, 32)+3)&^3)
522+ goldens, _ := filepath.Glob(filepath.Join("testdata/golden", m.Pkg, r.Req+"*.reply.hex"))
523+ sort.Strings(goldens)
524+ for _, g := range goldens {
525+ base := filepath.Base(g)
526+ if strings.TrimSuffix(base, ".reply.hex") != r.Req && !startsUpper(strings.TrimPrefix(strings.TrimSuffix(base, ".reply.hex"), r.Req)) {
527+ continue
528+ }
529+ usesGolden = true
530+ fmt.Fprintf(&b, "if raw, err := xtest.LoadHex(%q); err != nil { f.Fatal(err) } else { f.Add(raw) };\n", "../"+filepath.ToSlash(g))
531+ }
532+ fmt.Fprintf(&b, "f.Fuzz(func(t *testing.T, raw []byte) {\nr, ok := Parse%s(raw);\nif !ok {", c.Name)
533+ if c.Dynamic < 0 {
534+ fmt.Fprintf(&b, "if len(raw) >= %d { t.Fatal(\"rejected a complete fixed-size reply\") };", max(c.Fixed, 32))
535+ }
536+ b.WriteString("return };\n")
537+ b.WriteString("if len(r.Raw()) != len(raw) { t.Fatal(\"Raw must return the parsed bytes\") };\n")
538+ touch(&b, c, "r", 0, views, `t.Fatal("iterator error after successful Parse")`)
539+ b.WriteString("\n})\n}\n")
540+ decls = append(decls, b.String())
541+ }
542+ imports := "import \"testing\""
543+ if usesGolden {
544+ imports += "\nimport \"bnema.dev/xturbo/internal/xtest\""
545+ }
546+ decls = append([]string{imports}, decls...)
547+ data := struct {
548+ Pkg string
549+ Decls []string
550+ }{Pkg: m.Pkg, Decls: decls}
551+ return writeTemplate(filepath.Join(m.Pkg, "replies_fuzz_test.go"), "replies", data)
552+}
553+
554+func startsUpper(s string) bool { return s != "" && s[0] >= 'A' && s[0] <= 'Z' }
A cmd/xtgen/replies_test.go +70 -0
@@ -0,0 +1,70 @@
1+package main
2+
3+import "testing"
4+
5+// TestReplyLayouts checks reply containers against the independent packet-size
6+// walker and pins list-view classification for representative replies.
7+func TestReplyLayouts(t *testing.T) {
8+ kinds := map[string]map[string]string{
9+ "xproto.GetPropertyReply": {"Value": "bytes"},
10+ "xproto.QueryTreeReply": {"Children": "scalar"},
11+ "xproto.ListExtensionsReply": {"Names": "iter"},
12+ "xproto.QueryFontReply": {"Properties": "struct", "CharInfos": "struct"},
13+ "xproto.ListHostsReply": {"Hosts": "iter"},
14+ "render.QueryPictFormatsReply": {"Formats": "struct", "Screens": "iter", "Subpixels": "scalar"},
15+ "xfixes.GetCursorImageAndNameReply": {"CursorImage": "scalar", "Name": "bytes"},
16+ }
17+ for _, m := range testModules(t) {
18+ replies, _, err := resolveReplies(m)
19+ if err != nil {
20+ t.Fatal(err)
21+ }
22+ for _, r := range replies {
23+ var node *Node
24+ for _, n := range m.Root.Children {
25+ if n.Kind == "request" && goName(n.Attr["name"]) == r.Req {
26+ for _, c := range n.Children {
27+ if c.Kind == "reply" {
28+ node = c
29+ }
30+ }
31+ }
32+ }
33+ want, err := packetFixed(m, node, true)
34+ if err != nil {
35+ t.Fatal(err)
36+ }
37+ if got := max(r.C.Fixed, 32); got != want {
38+ t.Errorf("%s.%s fixed %d, packet walker %d", m.Pkg, r.C.Name, got, want)
39+ }
40+ for _, mem := range r.C.Members {
41+ if exp, ok := kinds[m.Pkg+"."+r.C.Name]; ok && mem.Kind == "list" {
42+ if exp[mem.Method] != mem.ListKind {
43+ t.Errorf("%s.%s.%s kind %s want %s", m.Pkg, r.C.Name, mem.Method, mem.ListKind, exp[mem.Method])
44+ }
45+ delete(exp, mem.Method)
46+ }
47+ }
48+ }
49+ }
50+ for name, rest := range kinds {
51+ if len(rest) != 0 {
52+ t.Errorf("%s: unchecked lists %v", name, rest)
53+ }
54+ }
55+}
56+
57+func TestReplyReservedGetter(t *testing.T) {
58+ m := &Module{Pkg: "x", Symbols: map[string]*Type{}, Names: map[string]*Node{}}
59+ nodes := []*Node{
60+ {Kind: "pad", Attr: map[string]string{"bytes": "1"}},
61+ {Kind: "field", Attr: map[string]string{"name": "raw", "type": "CARD32"}},
62+ }
63+ c, err := buildContainer(m, "XReply", "r", nodes, true, "Raw")
64+ if err != nil {
65+ t.Fatal(err)
66+ }
67+ if c.Members[1].Method != "Raw_" || c.Members[1].Static != 8 || c.Fixed != 12 {
68+ t.Fatalf("%+v", c.Members[1])
69+ }
70+}
A cmd/xtgen/requests.go +359 -0
@@ -0,0 +1,359 @@
1+package main
2+
3+import (
4+ "fmt"
5+ "path/filepath"
6+ "strconv"
7+ "strings"
8+)
9+
10+type Request struct {
11+ Name string
12+ Opcode uint8
13+ DataByte *Field
14+ Fixed int
15+ Params, Fields []Field
16+ Node *Node
17+ Derived map[string]string
18+ Lists []Field
19+ Values *ValueList
20+}
21+
22+// resolveRequests lowers scalar, list and mask-bitcase value-list requests.
23+func resolveRequests(m *Module) ([]Request, error) {
24+ var out []Request
25+ for _, n := range m.Root.Children {
26+ if n.Kind != "request" {
27+ continue
28+ }
29+ name := goName(n.Attr["name"])
30+ if err := m.claim(name, n); err != nil {
31+ return nil, err
32+ }
33+ opcode, _ := strconv.Atoi(n.Attr["opcode"])
34+ r := Request{Name: name, Opcode: uint8(opcode), Node: n, Derived: map[string]string{}}
35+ var err error
36+ r.Values, err = resolveValues(m, n, name)
37+ if err != nil {
38+ return nil, err
39+ }
40+ refs := map[string]int{}
41+ var countRefs func(*Node)
42+ countRefs = func(x *Node) {
43+ if x.Kind == "reply" || x.Kind == "doc" {
44+ return
45+ }
46+ if x.Kind == "fieldref" {
47+ refs[x.Text]++
48+ }
49+ for _, c := range x.Children {
50+ countRefs(c)
51+ }
52+ }
53+ countRefs(n)
54+ for _, x := range n.Children {
55+ if x.Kind == "list" && len(x.Children) == 1 && x.Children[0].Kind == "fieldref" && refs[x.Children[0].Text] == 1 {
56+ r.Derived[x.Children[0].Text] = paramName(x.Attr["name"])
57+ }
58+ }
59+ dynamic := false
60+ off := 4
61+ first := true
62+ for _, n := range n.Children {
63+ if n.Kind == "reply" || n.Kind == "doc" {
64+ continue
65+ }
66+ if n.Kind == "switch" {
67+ r.Params = append(r.Params, Field{Param: "v", GoType: "*" + name + "Values"})
68+ continue
69+ }
70+ f := Field{Name: goName(n.Attr["name"]), Param: paramName(n.Attr["name"]), Kind: n.Kind, Node: n, Off: off - 4}
71+ if n.Kind == "pad" {
72+ if n.Attr["align"] != "" {
73+ a, _ := strconv.Atoi(n.Attr["align"])
74+ f.Size = (-off) & (a - 1)
75+ } else {
76+ f.Size, _ = strconv.Atoi(n.Attr["bytes"])
77+ }
78+ } else {
79+ typ, err := lookup(m, n.Attr["type"])
80+ if err != nil {
81+ return nil, n.fail("%v", err)
82+ }
83+ if typ.Variable && n.Kind != "list" {
84+ return nil, n.fail("variable field requires list support")
85+ }
86+ f.Type = typ
87+ f.Size = typ.Size
88+ f.GoType = qualified(m, typ.Module, typ.GoType)
89+ if enum := n.Attr["enum"]; enum != "" {
90+ e, owner := findEnum(m, enum)
91+ if e == nil {
92+ return nil, n.fail("unknown enum %s", enum)
93+ }
94+ f.GoType = qualified(m, owner, e.Name)
95+ }
96+ if mask := n.Attr["mask"]; mask != "" {
97+ e, owner := findEnum(m, mask)
98+ if e == nil {
99+ return nil, n.fail("unknown mask %s", mask)
100+ }
101+ f.GoType = qualified(m, owner, e.Name)
102+ }
103+ if n.Kind == "list" {
104+ f.Size = 0
105+ f.GoType = "[]" + f.GoType
106+ if n.Attr["type"] == "char" {
107+ f.GoType = "string"
108+ }
109+ if n.Attr["type"] == "void" || n.Attr["type"] == "BYTE" || n.Attr["type"] == "CARD8" {
110+ f.GoType = "[]byte"
111+ }
112+ if len(n.Children) > 0 {
113+ f.Expr = n.Children[0]
114+ }
115+ if m.Header == "xproto" && r.Name == "SendEvent" {
116+ f.GoType = "*[32]byte"
117+ }
118+ r.Lists = append(r.Lists, f)
119+ r.Params = append(r.Params, f)
120+ } else if n.Kind == "field" && r.Derived[n.Attr["name"]] == "" {
121+ if r.Values != nil && n == r.Values.Mask.Node {
122+ f.Param = "v.Mask"
123+ } else {
124+ r.Params = append(r.Params, f)
125+ }
126+ }
127+ if n.Kind == "exprfield" {
128+ f.Expr = n.Children[0]
129+ }
130+ }
131+ // Core's first XML byte is header byte 1; extensions have no data byte.
132+ if first && m.ExtName == "" {
133+ if f.Size != 1 {
134+ return nil, n.fail("core request first member must occupy header data byte")
135+ }
136+ if f.Kind != "pad" {
137+ copy := f
138+ r.DataByte = &copy
139+ }
140+ first = false
141+ continue
142+ }
143+ first = false
144+ if f.Kind == "list" {
145+ dynamic = true
146+ }
147+ if dynamic {
148+ f.Off = -1
149+ }
150+ if f.Kind == "pad" && n.Attr["align"] != "" {
151+ f.Align, _ = strconv.Atoi(n.Attr["align"])
152+ }
153+ r.Fields = append(r.Fields, f)
154+ off += f.Size
155+ }
156+ r.Fixed = off - 4
157+ out = append(out, r)
158+ }
159+ return out, nil
160+}
161+func requestDecl(m *Module, r Request) (string, error) {
162+ var b strings.Builder
163+ if r.Values != nil {
164+ b.WriteString(valuesDecl(r.Name, r.Values))
165+ }
166+ fmt.Fprintf(&b, "func %s(b *xturbo.Buf", r.Name)
167+ for _, p := range r.Params {
168+ fmt.Fprintf(&b, ", %s %s", p.Param, p.GoType)
169+ }
170+ b.WriteString(") xturbo.Seq {\n")
171+ ref := func(s string) string {
172+ // xcb-proto permits an exprfield to refer to a trailing list's
173+ // implicit <list>_len (QueryTextExtents.string_len).
174+ declared := false
175+ for _, n := range r.Node.Children {
176+ if n.Kind == "field" && n.Attr["name"] == s {
177+ declared = true
178+ }
179+ }
180+ for _, list := range r.Lists {
181+ if !declared && s == list.Node.Attr["name"]+"_len" {
182+ return "len(" + list.Param + ")"
183+ }
184+ }
185+ if list := r.Derived[s]; list != "" {
186+ return "len(" + list + ")"
187+ }
188+ return "int(" + paramName(s) + ")"
189+ }
190+ // Derived lengths are cast only after checking their wire width.
191+ for _, f := range append(append([]Field{}, r.Fields...), r.Params...) {
192+ if f.Kind != "field" || r.Derived[f.Node.Attr["name"]] == "" {
193+ continue
194+ }
195+ if f.Type.Size < 8 {
196+ fmt.Fprintf(&b, "if uint64(%s)>%d { b.Fail(xturbo.ErrBadLength); return 0 };", ref(f.Node.Attr["name"]), uint64(1)<<(8*f.Type.Size)-1)
197+ }
198+ }
199+ if r.DataByte != nil {
200+ f := r.DataByte
201+ if list := r.Derived[f.Node.Attr["name"]]; list != "" {
202+ fmt.Fprintf(&b, "if len(%s)>255 { b.Fail(xturbo.ErrBadLength); return 0 };", list)
203+ }
204+ }
205+ for _, f := range r.Lists {
206+ if f.Expr != nil && !(f.Expr.Kind == "fieldref" && r.Derived[f.Expr.Text] != "") {
207+ ex, err := renderExpr(f.Expr, ref, m)
208+ if err != nil {
209+ return "", err
210+ }
211+ fmt.Fprintf(&b, "if len(%s)!=%s { b.Fail(xturbo.ErrBadLength); return 0 };", f.Param, ex)
212+ }
213+ }
214+ body := fmt.Sprint((r.Fixed + 3) &^ 3)
215+ if len(r.Lists) > 0 {
216+ b.WriteString("size:=0;")
217+ for _, f := range r.Fields {
218+ if f.Kind == "list" {
219+ if f.Type.Variable {
220+ fmt.Fprintf(&b, "for i:=range %s { size+=%s[i].Size() };", f.Param, f.Param)
221+ } else {
222+ fmt.Fprintf(&b, "size+=len(%s)*%d;", f.Param, f.Type.Size)
223+ }
224+ } else if f.Align > 0 {
225+ fmt.Fprintf(&b, "size=(size+%d)&^%d;", f.Align-1, f.Align-1)
226+ } else {
227+ fmt.Fprintf(&b, "size+=%d;", f.Size)
228+ }
229+ }
230+ b.WriteString("size=(size+3)&^3;")
231+ body = "size"
232+ }
233+ if r.Values != nil {
234+ body += "+4*bits.OnesCount32(uint32(v.Mask))"
235+ }
236+ major := fmt.Sprint(r.Opcode)
237+ data := "0"
238+ if m.ExtName != "" {
239+ fmt.Fprintf(&b, "if b.Ext==nil { b.Fail(xturbo.ErrExtMissing); return 0 }; major:=b.Ext.Major(xturbo.Ext%s); if major==0 { b.Fail(xturbo.ErrExtMissing); return 0 };\n", m.ExtName)
240+ major = "major"
241+ data = fmt.Sprint(r.Opcode)
242+ } else if r.DataByte != nil {
243+ f := r.DataByte
244+ if f.Type.Base == "bool" {
245+ value := f.Param
246+ if f.Kind == "exprfield" {
247+ ex, err := renderExpr(f.Expr, ref, m)
248+ if err != nil {
249+ return "", err
250+ }
251+ value = "(" + ex + " != 0)"
252+ }
253+ fmt.Fprintf(&b, "var data uint8; if %s { data=1 };", value)
254+ data = "data"
255+ } else {
256+ data = "uint8(" + ref(f.Node.Attr["name"]) + ")"
257+ }
258+ }
259+ fmt.Fprintf(&b, "p,seq:=b.Request(%s,%s,%s); if p==nil { return 0 };\n", major, data, body)
260+ if len(r.Lists) > 0 {
261+ b.WriteString("off:=0;")
262+ }
263+ for _, f := range r.Fields {
264+ if f.Kind == "pad" {
265+ if len(r.Lists) > 0 {
266+ if f.Align > 0 {
267+ fmt.Fprintf(&b, "off=(off+%d)&^%d;", f.Align-1, f.Align-1)
268+ } else {
269+ fmt.Fprintf(&b, "off+=%d;", f.Size)
270+ }
271+ }
272+ continue
273+ }
274+ if f.Kind == "list" {
275+ if f.GoType == "*[32]byte" {
276+ fmt.Fprintf(&b, "copy(p[off:],%s[:]);", f.Param)
277+ } else if f.GoType == "string" || f.GoType == "[]byte" {
278+ fmt.Fprintf(&b, "copy(p[off:],%s); off+=len(%s);", f.Param, f.Param)
279+ } else {
280+ fmt.Fprintf(&b, "for i:=range %s {", f.Param)
281+ if isScalar(f.Type) {
282+ b.WriteString(putScalar(f.Type, f.Param+"[i]", "p[off:]"))
283+ } else {
284+ fmt.Fprintf(&b, "%s[i].Put(p[off:]);", f.Param)
285+ }
286+ if f.Type.Variable {
287+ fmt.Fprintf(&b, "off+=%s[i].Size();", f.Param)
288+ } else {
289+ fmt.Fprintf(&b, "off+=%d;", f.Type.Size)
290+ }
291+ b.WriteString("};")
292+ }
293+ continue
294+ }
295+ src := f.Param
296+ if list := r.Derived[f.Node.Attr["name"]]; list != "" {
297+ src = "len(" + list + ")"
298+ }
299+ if f.Kind == "exprfield" {
300+ var err error
301+ src, err = renderExpr(f.Expr, ref, m)
302+ if err != nil {
303+ return "", err
304+ }
305+ }
306+ dst := fmt.Sprintf("p[%d:]", f.Off)
307+ if len(r.Lists) > 0 {
308+ dst = "p[off:]"
309+ }
310+ if isScalar(f.Type) {
311+ b.WriteString(putScalar(f.Type, src, dst))
312+ } else {
313+ fmt.Fprintf(&b, "%s.Put(%s);", src, dst)
314+ }
315+ if len(r.Lists) > 0 {
316+ fmt.Fprintf(&b, "off+=%d;", f.Size)
317+ }
318+ }
319+ if r.Values != nil {
320+ fmt.Fprintf(&b, "off:=%d;", r.Fixed)
321+ for _, f := range r.Values.Fields {
322+ fmt.Fprintf(&b, "if v.Mask & %s != 0 {", f.Bit)
323+ b.WriteString(putScalar(f.Field.Type, "v."+f.Field.Name, "p[off:]"))
324+ b.WriteString("off+=4 };")
325+ }
326+ b.WriteString("_ = off;")
327+ }
328+ b.WriteString("return seq }\n")
329+ return b.String(), nil
330+}
331+func emitRequests(modules []*Module) error {
332+ for _, m := range modules {
333+ requests, err := resolveRequests(m)
334+ if err != nil {
335+ return err
336+ }
337+ data := struct {
338+ Pkg string
339+ Decls []string
340+ }{Pkg: m.Pkg}
341+ for _, r := range requests {
342+ decl, err := requestDecl(m, r)
343+ if err != nil {
344+ return err
345+ }
346+ data.Decls = append(data.Decls, decl)
347+ }
348+ all := strings.Join(data.Decls, "\n")
349+ imp := importsFor(m, all)
350+ if len(requests) > 0 {
351+ imp += "\nimport \"bnema.dev/xturbo\""
352+ }
353+ data.Decls = append([]string{imp}, data.Decls...)
354+ if err := writeTemplate(filepath.Join(m.Pkg, "requests_generated.go"), "requests", data); err != nil {
355+ return err
356+ }
357+ }
358+ return nil
359+}
A cmd/xtgen/resolve.go +356 -0
@@ -0,0 +1,356 @@
1+package main
2+
3+import (
4+ "encoding/json"
5+ "fmt"
6+ "os"
7+ "path/filepath"
8+ "strconv"
9+ "strings"
10+)
11+
12+var builtin = map[string]*Type{}
13+
14+func init() {
15+ for _, b := range []struct {
16+ xml, goType string
17+ size int
18+ }{
19+ {"CARD8", "uint8", 1}, {"CARD16", "uint16", 2}, {"CARD32", "uint32", 4}, {"CARD64", "uint64", 8},
20+ {"INT8", "int8", 1}, {"INT16", "int16", 2}, {"INT32", "int32", 4}, {"INT64", "int64", 8},
21+ {"BOOL", "bool", 1}, {"BOOL32", "bool", 4}, {"char", "byte", 1}, {"void", "byte", 1}, {"BYTE", "byte", 1},
22+ } {
23+ builtin[b.xml] = &Type{Name: b.xml, GoType: b.goType, Base: b.goType, Size: b.size, Kind: "scalar", Resolved: true}
24+ }
25+}
26+func loadModules() ([]*Module, error) {
27+ var manifest struct {
28+ Files []struct {
29+ Path string `json:"path"`
30+ } `json:"files"`
31+ }
32+ b, err := os.ReadFile("spec/manifest.json")
33+ if err != nil {
34+ return nil, err
35+ }
36+ if err = json.Unmarshal(b, &manifest); err != nil {
37+ return nil, err
38+ }
39+ var nodes []*Node
40+ for _, f := range manifest.Files {
41+ if filepath.Ext(f.Path) != ".xml" {
42+ continue
43+ }
44+ n, err := parseFile(f.Path)
45+ if err != nil {
46+ return nil, err
47+ }
48+ nodes = append(nodes, n)
49+ }
50+ return resolveModules(nodes)
51+}
52+func (m *Module) claim(name string, n *Node) error {
53+ if old := m.Names[name]; old != nil {
54+ return n.fail("Go name collision %s (previously %s:%d)", name, old.File, old.Line)
55+ }
56+ m.Names[name] = n
57+ return nil
58+}
59+func resolveModules(nodes []*Node) ([]*Module, error) {
60+ var modules []*Module
61+ byHeader := map[string]*Module{}
62+ for _, n := range nodes {
63+ m := &Module{Header: n.Attr["header"], Pkg: strings.ReplaceAll(n.Attr["header"], "_", ""), XName: n.Attr["extension-xname"], ExtName: n.Attr["extension-name"], Root: n, Symbols: map[string]*Type{}, Names: map[string]*Node{}}
64+ if byHeader[m.Header] != nil {
65+ return nil, n.fail("duplicate module %s", m.Header)
66+ }
67+ byHeader[m.Header] = m
68+ modules = append(modules, m)
69+ for _, c := range n.Children {
70+ switch c.Kind {
71+ case "xidtype", "xidunion", "typedef", "struct", "union":
72+ raw := c.Attr["name"]
73+ if c.Kind == "typedef" {
74+ raw = c.Attr["newname"]
75+ }
76+ name := goName(raw)
77+ if err := m.claim(name, c); err != nil {
78+ return nil, err
79+ }
80+ typ := &Type{Name: raw, GoType: name, Kind: c.Kind, Node: c, Module: m}
81+ m.Types = append(m.Types, typ)
82+ m.Symbols[raw] = typ
83+ }
84+ }
85+ }
86+ for _, m := range modules {
87+ for _, n := range m.Root.Children {
88+ if n.Kind == "import" {
89+ dep := byHeader[n.Text]
90+ if dep == nil {
91+ return nil, n.fail("unknown import %s", n.Text)
92+ }
93+ m.Imports = append(m.Imports, dep)
94+ }
95+ }
96+ }
97+ for _, m := range modules {
98+ for _, typ := range m.Types {
99+ if err := resolveType(typ); err != nil {
100+ return nil, err
101+ }
102+ }
103+ }
104+ for _, m := range modules {
105+ if err := resolveEnums(m); err != nil {
106+ return nil, err
107+ }
108+ }
109+ // Re-resolve enum annotations after widths are known, without changing wire sizes.
110+ for _, m := range modules {
111+ for _, typ := range m.Types {
112+ for i := range typ.Fields {
113+ f := &typ.Fields[i]
114+ if f.Kind != "field" {
115+ continue
116+ }
117+ if enum := f.Node.Attr["enum"]; enum != "" {
118+ if e, owner := findEnum(m, enum); e != nil {
119+ f.GoType = qualified(m, owner, e.Name)
120+ }
121+ }
122+ if mask := f.Node.Attr["mask"]; mask != "" {
123+ if e, owner := findEnum(m, mask); e != nil {
124+ f.GoType = qualified(m, owner, e.Name)
125+ }
126+ }
127+ }
128+ }
129+ }
130+ return modules, nil
131+}
132+func lookup(m *Module, name string) (*Type, error) {
133+ if t := builtin[name]; t != nil {
134+ return t, nil
135+ }
136+ if strings.Contains(name, ":") {
137+ parts := strings.SplitN(name, ":", 2)
138+ for _, dep := range m.Imports {
139+ if dep.Header == parts[0] {
140+ return lookup(dep, parts[1])
141+ }
142+ }
143+ return nil, m.Root.fail("unknown qualified type %s", name)
144+ }
145+ if t := m.Symbols[name]; t != nil {
146+ return t, nil
147+ }
148+ var found *Type
149+ for _, dep := range m.Imports {
150+ if t := dep.Symbols[name]; t != nil {
151+ if found != nil && found != t {
152+ return nil, m.Root.fail("ambiguous type %s", name)
153+ }
154+ found = t
155+ }
156+ }
157+ if found != nil {
158+ return found, nil
159+ }
160+ return nil, m.Root.fail("unknown type %s", name)
161+}
162+func qualified(m, owner *Module, name string) string {
163+ if owner == nil || owner == m {
164+ return name
165+ }
166+ return owner.Pkg + "." + name
167+}
168+func resolveType(t *Type) error {
169+ if t.Resolved {
170+ return nil
171+ }
172+ if t.Resolving {
173+ return t.Node.fail("recursive type %s", t.Name)
174+ }
175+ t.Resolving = true
176+ switch t.Kind {
177+ case "xidtype", "xidunion":
178+ t.Size = 4
179+ t.Base = "uint32"
180+ case "typedef":
181+ base, err := lookup(t.Module, t.Node.Attr["oldname"])
182+ if err != nil {
183+ return err
184+ }
185+ if err := resolveType(base); err != nil {
186+ return err
187+ }
188+ t.Size = base.Size
189+ t.Base = base.Base
190+ t.Variable = base.Variable
191+ default:
192+ off := 0
193+ for _, n := range t.Node.Children {
194+ if n.Kind == "doc" {
195+ continue
196+ }
197+ f := Field{Name: goName(n.Attr["name"]), Param: paramName(n.Attr["name"]), Kind: n.Kind, Node: n, Off: off}
198+ if t.Kind == "union" {
199+ f.Off = 0
200+ }
201+ switch n.Kind {
202+ case "pad":
203+ if n.Attr["align"] != "" {
204+ f.Align, _ = strconv.Atoi(n.Attr["align"])
205+ f.Size = (-off) & (f.Align - 1)
206+ } else {
207+ f.Size, _ = strconv.Atoi(n.Attr["bytes"])
208+ }
209+ case "field", "list":
210+ elem, err := lookup(t.Module, n.Attr["type"])
211+ if err != nil {
212+ return n.fail("%v", err)
213+ }
214+ if err := resolveType(elem); err != nil {
215+ return err
216+ }
217+ f.Type = elem
218+ f.GoType = qualified(t.Module, elem.Module, elem.GoType)
219+ f.Size = elem.Size
220+ if n.Kind == "list" {
221+ if len(n.Children) > 0 {
222+ f.Expr = n.Children[0]
223+ }
224+ if f.Expr != nil && f.Expr.Kind == "value" && !elem.Variable {
225+ count, err := strconv.Atoi(f.Expr.Text)
226+ if err != nil || count < 0 {
227+ return n.fail("invalid constant list size")
228+ }
229+ f.Count = count
230+ f.Size *= count
231+ f.GoType = fmt.Sprintf("[%d]%s", count, f.GoType)
232+ } else {
233+ t.Variable = true
234+ f.Size = 0
235+ f.GoType = "[]" + f.GoType
236+ if n.Attr["type"] == "char" {
237+ f.GoType = "string"
238+ }
239+ }
240+ }
241+ if elem.Variable {
242+ t.Variable = true
243+ }
244+ default:
245+ return n.fail("unsupported type member %s", n.Kind)
246+ }
247+ t.Fields = append(t.Fields, f)
248+ if t.Kind == "union" {
249+ if f.Size > off {
250+ off = f.Size
251+ }
252+ } else if !t.Variable {
253+ off += f.Size
254+ }
255+ }
256+ t.Size = off
257+ }
258+ t.Resolving = false
259+ t.Resolved = true
260+ return nil
261+}
262+func findEnum(m *Module, name string) (*Enum, *Module) {
263+ if strings.Contains(name, ":") {
264+ p := strings.SplitN(name, ":", 2)
265+ for _, dep := range m.Imports {
266+ if dep.Header == p[0] {
267+ return findEnum(dep, p[1])
268+ }
269+ }
270+ return nil, nil
271+ }
272+ for i := range m.Enums {
273+ if m.Enums[i].Node.Attr["name"] == name {
274+ return &m.Enums[i], m
275+ }
276+ }
277+ for _, dep := range m.Imports {
278+ for i := range dep.Enums {
279+ if dep.Enums[i].Node.Attr["name"] == name {
280+ return &dep.Enums[i], dep
281+ }
282+ }
283+ }
284+ return nil, nil
285+}
286+func resolveEnums(m *Module) error {
287+ for _, n := range m.Root.Children {
288+ if n.Kind != "enum" {
289+ continue
290+ }
291+ e := Enum{Name: goName(n.Attr["name"]), Base: "uint32", Node: n}
292+ if old := m.Names[e.Name]; old != nil {
293+ if !contains("xidtype xidunion typedef", old.Kind) {
294+ return n.fail("Go name collision %s", e.Name)
295+ }
296+ e.Existing = true
297+ } else if err := m.claim(e.Name, n); err != nil {
298+ return err
299+ }
300+ var max int64
301+ for _, item := range n.Children {
302+ if item.Kind == "doc" {
303+ continue
304+ }
305+ ex := item.Children[0]
306+ v, err := strconv.ParseInt(ex.Text, 0, 64)
307+ if err != nil {
308+ return ex.fail("invalid enum value")
309+ }
310+ if ex.Kind == "bit" {
311+ if v < 0 || v > 31 {
312+ return ex.fail("enum bit out of range")
313+ }
314+ v = 1 << uint(v)
315+ }
316+ if v < 0 || v > 0xffffffff {
317+ return ex.fail("enum value out of range")
318+ }
319+ if v > max {
320+ max = v
321+ }
322+ name := e.Name + goName(item.Attr["name"])
323+ if err := m.claim(name, item); err != nil {
324+ return err
325+ }
326+ e.Items = append(e.Items, EnumItem{name, v})
327+ }
328+ // Narrow only when every wire use has the same narrower width.
329+ width := 0
330+ mixed := false
331+ var scan func(*Node)
332+ scan = func(x *Node) {
333+ if x.Attr["enum"] == n.Attr["name"] || x.Attr["mask"] == n.Attr["name"] || x.Attr["altenum"] == n.Attr["name"] {
334+ typ, err := lookup(m, x.Attr["type"])
335+ if err == nil {
336+ if width != 0 && width != typ.Size {
337+ mixed = true
338+ }
339+ width = typ.Size
340+ }
341+ }
342+ for _, c := range x.Children {
343+ scan(c)
344+ }
345+ }
346+ scan(m.Root)
347+ if !mixed && width == 1 && max <= 255 {
348+ e.Base = "uint8"
349+ }
350+ if !mixed && width == 2 && max <= 65535 {
351+ e.Base = "uint16"
352+ }
353+ m.Enums = append(m.Enums, e)
354+ }
355+ return nil
356+}
A cmd/xtgen/resolve_test.go +165 -0
@@ -0,0 +1,165 @@
1+package main
2+
3+import (
4+ "os"
5+ "strings"
6+ "testing"
7+)
8+
9+func testModules(t *testing.T) []*Module {
10+ t.Helper()
11+ old, err := os.Getwd()
12+ if err != nil {
13+ t.Fatal(err)
14+ }
15+ if err = os.Chdir("../.."); err != nil {
16+ t.Fatal(err)
17+ }
18+ defer func() {
19+ if err := os.Chdir(old); err != nil {
20+ t.Fatal(err)
21+ }
22+ }()
23+ ms, err := loadModules()
24+ if err != nil {
25+ t.Fatal(err)
26+ }
27+ return ms
28+}
29+func TestResolveLayouts(t *testing.T) {
30+ ms := testModules(t)
31+ expected := map[string]int{"Setup": 40, "Screen": 40, "Rectangle": 8, "Point": 4, "Arc": 12, "Visualtype": 24, "Format": 8, "Depth": 8, "ClientMessageData": 20}
32+ for _, typ := range ms[0].Types {
33+ if want, ok := expected[typ.GoType]; ok {
34+ if typ.Size != want {
35+ t.Errorf("%s size=%d want %d", typ.GoType, typ.Size, want)
36+ }
37+ delete(expected, typ.GoType)
38+ }
39+ if typ.GoType == "Rectangle" {
40+ for i, want := range []int{0, 2, 4, 6} {
41+ if typ.Fields[i].Off != want {
42+ t.Errorf("rectangle field %d offset", i)
43+ }
44+ }
45+ }
46+ }
47+ if len(expected) != 0 {
48+ t.Fatal("missing types", expected)
49+ }
50+ for _, name := range []string{"Window", "Atom", "Cursor", "Pixmap", "Font"} {
51+ found := false
52+ for _, e := range ms[0].Enums {
53+ if e.Name == name {
54+ found = e.Existing
55+ }
56+ }
57+ if !found {
58+ t.Errorf("%s must reuse XID type", name)
59+ }
60+ }
61+ for _, m := range ms {
62+ if err := packetSizeChecks(m); err != nil {
63+ t.Fatal(err)
64+ }
65+ }
66+}
67+func TestResolveRejectsCollisions(t *testing.T) {
68+ for _, body := range []string{
69+ `<struct name="A"/><enum name="A"><item name="B"><value>0</value></item></enum>`,
70+ `<xidtype name="A"/><xidtype name="a"/>`,
71+ `<enum name="A"><item name="B"><value>0</value></item></enum><enum name="A"><item name="C"><value>0</value></item></enum>`,
72+ } {
73+ n, err := parseXML("collision.xml", strings.NewReader(`<xcb header="test">`+body+`</xcb>`))
74+ if err != nil {
75+ t.Fatal(err)
76+ }
77+ _, err = resolveModules([]*Node{n})
78+ if err == nil || !strings.Contains(err.Error(), "collision.xml:1:") || !strings.Contains(err.Error(), "collision") {
79+ t.Fatalf("got %v", err)
80+ }
81+ }
82+}
83+func TestNaming(t *testing.T) {
84+ for in, want := range map[string]string{"WINDOW": "Window", "data_len": "DataLen", "ClientIdSpec": "ClientIdSpec", "2d": "X2d", "BOOL32": "Bool32"} {
85+ if got := goName(in); got != want {
86+ t.Errorf("%s => %s want %s", in, got, want)
87+ }
88+ }
89+ if paramName("type") != "type_" {
90+ t.Fatal("keyword parameter")
91+ }
92+}
93+
94+func TestRenderExpr(t *testing.T) {
95+ n, err := parseXML("expr.xml", strings.NewReader(`<xcb header="test"><request name="R" opcode="1"><exprfield name="x" type="CARD32"><op op="*"><fieldref>n</fieldref><value>4</value></op></exprfield></request></xcb>`))
96+ if err != nil {
97+ t.Fatal(err)
98+ }
99+ got, err := renderExpr(n.Children[0].Children[0].Children[0], func(s string) string { return "int(v." + goName(s) + ")" }, nil)
100+ if err != nil || got != "(int(v.N) * 4)" {
101+ t.Fatalf("%s %v", got, err)
102+ }
103+}
104+
105+func TestFixedRequests(t *testing.T) {
106+ ms := testModules(t)
107+ for _, m := range ms {
108+ requests, err := resolveRequests(m)
109+ if err != nil {
110+ t.Fatal(err)
111+ }
112+ for _, r := range requests {
113+ decl, err := requestDecl(m, r)
114+ if err != nil {
115+ t.Fatal(err)
116+ }
117+ if !strings.Contains(decl, "if p==nil { return 0 }") {
118+ t.Fatal("missing sticky-error guard")
119+ }
120+ if m.Header == "xproto" && r.Name == "MapWindow" {
121+ if r.Fixed != 4 || len(r.Params) != 1 || r.Fields[0].Off != 0 {
122+ t.Fatal("MapWindow layout")
123+ }
124+ }
125+ if m.Header == "xfixes" && r.Name == "QueryVersion" {
126+ if r.Fixed != 8 || r.DataByte != nil || r.Fields[1].Off != 4 {
127+ t.Fatal("extension layout")
128+ }
129+ }
130+ }
131+ }
132+}
133+
134+func TestListResolution(t *testing.T) {
135+ for _, m := range testModules(t) {
136+ rs, err := resolveRequests(m)
137+ if err != nil {
138+ t.Fatal(err)
139+ }
140+ for _, r := range rs {
141+ switch r.Name {
142+ case "InternAtom":
143+ if r.Derived["name_len"] != "name" || len(r.Params) != 2 {
144+ t.Fatal("InternAtom derived length")
145+ }
146+ case "ChangeProperty":
147+ if len(r.Derived) != 0 || len(r.Params) != 7 {
148+ t.Fatal("ChangeProperty explicit expression fields")
149+ }
150+ case "AddGlyphs":
151+ if r.Derived["glyphs_len"] != "" {
152+ t.Fatal("shared count must remain explicit")
153+ }
154+ case "QueryClientIds":
155+ if r.Derived["num_specs"] != "specs" || r.Params[0].GoType != "[]ClientIdSpec" {
156+ t.Fatal("fixed struct list")
157+ }
158+ case "SetFontPath":
159+ if r.Params[0].GoType != "[]Str" || !r.Lists[0].Type.Variable {
160+ t.Fatal("variable struct list")
161+ }
162+ }
163+ }
164+ }
165+}
A cmd/xtgen/templates/ext.tmpl +10 -0
@@ -0,0 +1,10 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xturbo
3+
4+type ExtID uint8
5+const (
6+ ExtCore ExtID = iota
7+{{range .}} Ext{{.ExtName}}
8+{{end}} extCount
9+)
10+var ExtXName = [extCount]string{"", {{range .}}{{printf "%q" .XName}},{{end}}}
A cmd/xtgen/templates/replies.tmpl +5 -0
@@ -0,0 +1,5 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package {{.Pkg}}
3+{{range .Decls}}
4+{{.}}
5+{{end}}
A cmd/xtgen/templates/requests.tmpl +5 -0
@@ -0,0 +1,5 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package {{.Pkg}}
3+{{range .Decls}}
4+{{.}}
5+{{end}}
A cmd/xtgen/templates/sizes.tmpl +7 -0
@@ -0,0 +1,7 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package {{.Pkg}}
3+import "testing"
4+func TestWireSizes(t *testing.T) {
5+{{range .SizeChecks}}{{.}}
6+{{end}}
7+}
A cmd/xtgen/templates/types.tmpl +5 -0
@@ -0,0 +1,5 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package {{.Pkg}}
3+{{range .Decls}}
4+{{.}}
5+{{end}}
A cmd/xtgen/values.go +136 -0
@@ -0,0 +1,136 @@
1+package main
2+
3+import (
4+ "fmt"
5+ "sort"
6+ "strings"
7+)
8+
9+type ValueField struct {
10+ Field Field
11+ Bit string
12+ Value int64
13+}
14+type ValueList struct {
15+ Mask Field
16+ Fields []ValueField
17+}
18+
19+func resolveValues(m *Module, req *Node, name string) (*ValueList, error) {
20+ var sw *Node
21+ for _, n := range req.Children {
22+ if n.Kind == "switch" {
23+ if sw != nil {
24+ return nil, n.fail("multiple value switches are unsupported")
25+ }
26+ sw = n
27+ }
28+ }
29+ if sw == nil {
30+ return nil, nil
31+ }
32+ if len(sw.Children) < 2 || sw.Children[0].Kind != "fieldref" {
33+ return nil, sw.fail("value switch requires a mask fieldref and bitcases")
34+ }
35+ var mask *Node
36+ seenSwitch := false
37+ for _, n := range req.Children {
38+ if n == sw {
39+ seenSwitch = true
40+ continue
41+ }
42+ if seenSwitch && n.Kind != "doc" && n.Kind != "reply" {
43+ return nil, n.fail("value switch must be trailing")
44+ }
45+ if n.Kind == "list" {
46+ return nil, n.fail("lists combined with value switches are unsupported")
47+ }
48+ if !seenSwitch && n.Kind == "field" && n.Attr["name"] == sw.Children[0].Text {
49+ mask = n
50+ }
51+ }
52+ if mask == nil || mask.Attr["mask"] == "" {
53+ return nil, sw.fail("value switch requires a preceding typed mask")
54+ }
55+ mt, err := lookup(m, mask.Attr["type"])
56+ if err != nil {
57+ return nil, mask.fail("%v", err)
58+ }
59+ e, owner := findEnum(m, mask.Attr["mask"])
60+ if e == nil {
61+ return nil, mask.fail("unknown mask %s", mask.Attr["mask"])
62+ }
63+ if mt.Size > 4 || !isScalar(mt) {
64+ return nil, mask.fail("value mask must fit in 32 bits")
65+ }
66+ v := &ValueList{Mask: Field{Node: mask, GoType: qualified(m, owner, e.Name)}}
67+ used := map[int64]bool{}
68+ names := map[string]bool{"Mask": true}
69+ for _, bc := range sw.Children[1:] {
70+ var members []*Node
71+ for _, c := range bc.Children {
72+ if c.Kind != "doc" {
73+ members = append(members, c)
74+ }
75+ }
76+ if bc.Kind != "bitcase" || len(members) != 2 || members[0].Kind != "enumref" || members[1].Kind != "field" {
77+ return nil, bc.fail("value switch requires one enumref and one 4-byte field per bitcase")
78+ }
79+ bit, n := members[0], members[1]
80+ be, bo := findEnum(m, bit.Attr["ref"])
81+ if be != e || bo != owner {
82+ return nil, bit.fail("bitcase enum must match value mask")
83+ }
84+ var value int64
85+ found := false
86+ for _, item := range e.Items {
87+ if item.Name == e.Name+goName(bit.Text) {
88+ value = item.Value
89+ found = true
90+ }
91+ }
92+ if !found || value <= 0 || value&(value-1) != 0 || uint64(value) >= uint64(1)<<(8*mt.Size) || used[value] {
93+ return nil, bit.fail("bitcase requires a unique mask bit")
94+ }
95+ used[value] = true
96+ typ, err := lookup(m, n.Attr["type"])
97+ if err != nil {
98+ return nil, n.fail("%v", err)
99+ }
100+ if typ.Size != 4 || !isScalar(typ) {
101+ return nil, n.fail("value-list bitcase requires a 4-byte scalar field")
102+ }
103+ f := Field{Name: goName(n.Attr["name"]), GoType: qualified(m, typ.Module, typ.GoType), Type: typ, Node: n}
104+ for _, attr := range []string{"enum", "mask"} {
105+ if ref := n.Attr[attr]; ref != "" {
106+ fe, fo := findEnum(m, ref)
107+ if fe == nil {
108+ return nil, n.fail("unknown enum %s", ref)
109+ }
110+ f.GoType = qualified(m, fo, fe.Name)
111+ }
112+ }
113+ if names[f.Name] {
114+ return nil, n.fail("value field name collision %s", f.Name)
115+ }
116+ names[f.Name] = true
117+ v.Fields = append(v.Fields, ValueField{Field: f, Bit: qualified(m, owner, e.Name+goName(bit.Text)), Value: value})
118+ }
119+ sort.Slice(v.Fields, func(i, j int) bool { return v.Fields[i].Value < v.Fields[j].Value })
120+ if err := m.claim(name+"Values", sw); err != nil {
121+ return nil, err
122+ }
123+ return v, nil
124+}
125+func valuesDecl(name string, v *ValueList) string {
126+ var b strings.Builder
127+ fmt.Fprintf(&b, "type %sValues struct { Mask %s;", name, v.Mask.GoType)
128+ for _, f := range v.Fields {
129+ fmt.Fprintf(&b, "%s %s;", f.Field.Name, f.Field.GoType)
130+ }
131+ b.WriteString("};\n")
132+ for _, f := range v.Fields {
133+ fmt.Fprintf(&b, "func(v *%sValues) Set%s(x %s) *%sValues { v.Mask |= %s; v.%s=x; return v };\n", name, f.Field.Name, f.Field.GoType, name, f.Bit, f.Field.Name)
134+ }
135+ return b.String()
136+}
A cmd/xtgen/values_test.go +93 -0
@@ -0,0 +1,93 @@
1+package main
2+
3+import (
4+ "strings"
5+ "testing"
6+)
7+
8+func TestResolvePinnedValues(t *testing.T) {
9+ found := map[string]bool{}
10+ for _, m := range testModules(t) {
11+ rs, err := resolveRequests(m)
12+ if err != nil {
13+ t.Fatal(err)
14+ }
15+ for _, r := range rs {
16+ if r.Values != nil {
17+ found[m.Pkg+"/"+r.Name] = true
18+ if len(r.Values.Fields) == 0 {
19+ t.Fatal("empty values")
20+ }
21+ for i, f := range r.Values.Fields {
22+ if i > 0 && r.Values.Fields[i-1].Value >= f.Value {
23+ t.Fatal("not in bit order")
24+ }
25+ }
26+ for _, p := range r.Params {
27+ if p.Param == "valueMask" {
28+ t.Fatal("mask leaked into params")
29+ }
30+ }
31+ }
32+ }
33+ }
34+ for _, name := range []string{"xproto/CreateWindow", "xproto/ChangeWindowAttributes", "xproto/ConfigureWindow", "xproto/CreateGC", "xproto/ChangeGC", "xproto/ChangeKeyboardControl", "render/CreatePicture", "render/ChangePicture"} {
35+ if !found[name] {
36+ t.Error("missing", name)
37+ }
38+ }
39+ if len(found) != 8 {
40+ t.Fatal(found)
41+ }
42+}
43+
44+func TestResolveValueSwitches(t *testing.T) {
45+ prefix := `<xcb header="test"><enum name="Mask"><item name="Low"><bit>0</bit></item><item name="High"><bit>3</bit></item></enum><request name="Configure" opcode="1"><pad bytes="1"/><field name="value_mask" type="CARD32" mask="Mask"/>`
46+ high := `<bitcase><enumref ref="Mask">High</enumref><field name="high" type="BOOL32"/></bitcase>`
47+ low := `<bitcase><enumref ref="Mask">Low</enumref><field name="low" type="INT32"/></bitcase>`
48+ good := `<switch name="value_list"><fieldref>value_mask</fieldref>` + high + low + `</switch>`
49+ for _, tc := range []struct {
50+ name, body string
51+ valid bool
52+ }{
53+ {"sorted", good, true},
54+ {"expression", strings.Replace(good, "<fieldref>value_mask</fieldref>", "<popcount><fieldref>value_mask</fieldref></popcount>", 1), false},
55+ {"duplicate", strings.Replace(good, low, high, 1), false},
56+ {"unknown bit", strings.Replace(good, ">Low<", ">Missing<", 1), false},
57+ {"non scalar", strings.Replace(good, `type="INT32"`, `type="Pair"`, 1), false},
58+ {"trailing field", good + `<field name="extra" type="CARD32"/>`, false},
59+ } {
60+ t.Run(tc.name, func(t *testing.T) {
61+ xml := strings.Replace(prefix, `<request name=`, `<struct name="Pair"><field name="a" type="CARD32"/></struct><request name=`, 1) + tc.body + `</request></xcb>`
62+ n, err := parseXML("values.xml", strings.NewReader(xml))
63+ if err != nil {
64+ t.Fatal(err)
65+ }
66+ ms, err := resolveModules([]*Node{n})
67+ if err != nil {
68+ t.Fatal(err)
69+ }
70+ rs, err := resolveRequests(ms[0])
71+ if !tc.valid {
72+ if err == nil || !strings.Contains(err.Error(), "values.xml:1:") {
73+ t.Fatalf("got %v", err)
74+ }
75+ return
76+ }
77+ if err != nil {
78+ t.Fatal(err)
79+ }
80+ v := rs[0].Values
81+ if v.Fields[0].Field.Name != "Low" || v.Fields[1].Field.Name != "High" {
82+ t.Fatal("XML order used instead of bit order")
83+ }
84+ decl, err := requestDecl(ms[0], rs[0])
85+ if err != nil {
86+ t.Fatal(err)
87+ }
88+ if !strings.Contains(decl, "uint32(v.Low)") || !strings.Contains(decl, "if v.High") {
89+ t.Fatal(decl)
90+ }
91+ })
92+ }
93+}
A composite/replies_fuzz_test.go +39 -0
@@ -0,0 +1,39 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package composite
3+
4+import "testing"
5+
6+func FuzzParseQueryVersionReply(f *testing.F) {
7+ f.Add(make([]byte, 32))
8+ f.Fuzz(func(t *testing.T, raw []byte) {
9+ r, ok := ParseQueryVersionReply(raw)
10+ if !ok {
11+ if len(raw) >= 32 {
12+ t.Fatal("rejected a complete fixed-size reply")
13+ }
14+ return
15+ }
16+ if len(r.Raw()) != len(raw) {
17+ t.Fatal("Raw must return the parsed bytes")
18+ }
19+ _ = r.MajorVersion()
20+ _ = r.MinorVersion()
21+ })
22+}
23+
24+func FuzzParseGetOverlayWindowReply(f *testing.F) {
25+ f.Add(make([]byte, 32))
26+ f.Fuzz(func(t *testing.T, raw []byte) {
27+ r, ok := ParseGetOverlayWindowReply(raw)
28+ if !ok {
29+ if len(raw) >= 32 {
30+ t.Fatal("rejected a complete fixed-size reply")
31+ }
32+ return
33+ }
34+ if len(r.Raw()) != len(raw) {
35+ t.Fatal("Raw must return the parsed bytes")
36+ }
37+ _ = r.OverlayWin()
38+ })
39+}
A composite/replies_generated.go +42 -0
@@ -0,0 +1,42 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package composite
3+
4+import "bnema.dev/xturbo/xproto"
5+import "encoding/binary"
6+
7+// QueryVersionReply is a zero-copy view over a QueryVersion reply; offsets count from reply byte 0.
8+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
9+type QueryVersionReply struct{ raw []byte }
10+
11+// ParseQueryVersionReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
12+func ParseQueryVersionReply(raw []byte) (QueryVersionReply, bool) {
13+ if len(raw) < 32 {
14+ return QueryVersionReply{}, false
15+ }
16+ r := QueryVersionReply{raw: raw}
17+ return r, true
18+}
19+func (r QueryVersionReply) Raw() []byte { return r.raw }
20+func (r QueryVersionReply) MajorVersion() uint32 {
21+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
22+}
23+func (r QueryVersionReply) MinorVersion() uint32 {
24+ return uint32(binary.LittleEndian.Uint32(r.raw[12:]))
25+}
26+
27+// GetOverlayWindowReply is a zero-copy view over a GetOverlayWindow reply; offsets count from reply byte 0.
28+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
29+type GetOverlayWindowReply struct{ raw []byte }
30+
31+// ParseGetOverlayWindowReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
32+func ParseGetOverlayWindowReply(raw []byte) (GetOverlayWindowReply, bool) {
33+ if len(raw) < 32 {
34+ return GetOverlayWindowReply{}, false
35+ }
36+ r := GetOverlayWindowReply{raw: raw}
37+ return r, true
38+}
39+func (r GetOverlayWindowReply) Raw() []byte { return r.raw }
40+func (r GetOverlayWindowReply) OverlayWin() xproto.Window {
41+ return xproto.Window(binary.LittleEndian.Uint32(r.raw[8:]))
42+}
A composite/requests_generated.go +176 -0
@@ -0,0 +1,176 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package composite
3+
4+import "bnema.dev/xturbo/xfixes"
5+import "bnema.dev/xturbo/xproto"
6+import "encoding/binary"
7+import "bnema.dev/xturbo"
8+
9+func QueryVersion(b *xturbo.Buf, clientMajorVersion uint32, clientMinorVersion uint32) xturbo.Seq {
10+ if b.Ext == nil {
11+ b.Fail(xturbo.ErrExtMissing)
12+ return 0
13+ }
14+ major := b.Ext.Major(xturbo.ExtComposite)
15+ if major == 0 {
16+ b.Fail(xturbo.ErrExtMissing)
17+ return 0
18+ }
19+ p, seq := b.Request(major, 0, 8)
20+ if p == nil {
21+ return 0
22+ }
23+ binary.LittleEndian.PutUint32(p[0:], uint32(clientMajorVersion))
24+ binary.LittleEndian.PutUint32(p[4:], uint32(clientMinorVersion))
25+ return seq
26+}
27+
28+func RedirectWindow(b *xturbo.Buf, window xproto.Window, update Redirect) xturbo.Seq {
29+ if b.Ext == nil {
30+ b.Fail(xturbo.ErrExtMissing)
31+ return 0
32+ }
33+ major := b.Ext.Major(xturbo.ExtComposite)
34+ if major == 0 {
35+ b.Fail(xturbo.ErrExtMissing)
36+ return 0
37+ }
38+ p, seq := b.Request(major, 1, 8)
39+ if p == nil {
40+ return 0
41+ }
42+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
43+ p[4:][0] = byte(update)
44+ return seq
45+}
46+
47+func RedirectSubwindows(b *xturbo.Buf, window xproto.Window, update Redirect) xturbo.Seq {
48+ if b.Ext == nil {
49+ b.Fail(xturbo.ErrExtMissing)
50+ return 0
51+ }
52+ major := b.Ext.Major(xturbo.ExtComposite)
53+ if major == 0 {
54+ b.Fail(xturbo.ErrExtMissing)
55+ return 0
56+ }
57+ p, seq := b.Request(major, 2, 8)
58+ if p == nil {
59+ return 0
60+ }
61+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
62+ p[4:][0] = byte(update)
63+ return seq
64+}
65+
66+func UnredirectWindow(b *xturbo.Buf, window xproto.Window, update Redirect) xturbo.Seq {
67+ if b.Ext == nil {
68+ b.Fail(xturbo.ErrExtMissing)
69+ return 0
70+ }
71+ major := b.Ext.Major(xturbo.ExtComposite)
72+ if major == 0 {
73+ b.Fail(xturbo.ErrExtMissing)
74+ return 0
75+ }
76+ p, seq := b.Request(major, 3, 8)
77+ if p == nil {
78+ return 0
79+ }
80+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
81+ p[4:][0] = byte(update)
82+ return seq
83+}
84+
85+func UnredirectSubwindows(b *xturbo.Buf, window xproto.Window, update Redirect) xturbo.Seq {
86+ if b.Ext == nil {
87+ b.Fail(xturbo.ErrExtMissing)
88+ return 0
89+ }
90+ major := b.Ext.Major(xturbo.ExtComposite)
91+ if major == 0 {
92+ b.Fail(xturbo.ErrExtMissing)
93+ return 0
94+ }
95+ p, seq := b.Request(major, 4, 8)
96+ if p == nil {
97+ return 0
98+ }
99+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
100+ p[4:][0] = byte(update)
101+ return seq
102+}
103+
104+func CreateRegionFromBorderClip(b *xturbo.Buf, region xfixes.Region, window xproto.Window) xturbo.Seq {
105+ if b.Ext == nil {
106+ b.Fail(xturbo.ErrExtMissing)
107+ return 0
108+ }
109+ major := b.Ext.Major(xturbo.ExtComposite)
110+ if major == 0 {
111+ b.Fail(xturbo.ErrExtMissing)
112+ return 0
113+ }
114+ p, seq := b.Request(major, 5, 8)
115+ if p == nil {
116+ return 0
117+ }
118+ binary.LittleEndian.PutUint32(p[0:], uint32(region))
119+ binary.LittleEndian.PutUint32(p[4:], uint32(window))
120+ return seq
121+}
122+
123+func NameWindowPixmap(b *xturbo.Buf, window xproto.Window, pixmap xproto.Pixmap) xturbo.Seq {
124+ if b.Ext == nil {
125+ b.Fail(xturbo.ErrExtMissing)
126+ return 0
127+ }
128+ major := b.Ext.Major(xturbo.ExtComposite)
129+ if major == 0 {
130+ b.Fail(xturbo.ErrExtMissing)
131+ return 0
132+ }
133+ p, seq := b.Request(major, 6, 8)
134+ if p == nil {
135+ return 0
136+ }
137+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
138+ binary.LittleEndian.PutUint32(p[4:], uint32(pixmap))
139+ return seq
140+}
141+
142+func GetOverlayWindow(b *xturbo.Buf, window xproto.Window) xturbo.Seq {
143+ if b.Ext == nil {
144+ b.Fail(xturbo.ErrExtMissing)
145+ return 0
146+ }
147+ major := b.Ext.Major(xturbo.ExtComposite)
148+ if major == 0 {
149+ b.Fail(xturbo.ErrExtMissing)
150+ return 0
151+ }
152+ p, seq := b.Request(major, 7, 4)
153+ if p == nil {
154+ return 0
155+ }
156+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
157+ return seq
158+}
159+
160+func ReleaseOverlayWindow(b *xturbo.Buf, window xproto.Window) xturbo.Seq {
161+ if b.Ext == nil {
162+ b.Fail(xturbo.ErrExtMissing)
163+ return 0
164+ }
165+ major := b.Ext.Major(xturbo.ExtComposite)
166+ if major == 0 {
167+ b.Fail(xturbo.ErrExtMissing)
168+ return 0
169+ }
170+ p, seq := b.Request(major, 8, 4)
171+ if p == nil {
172+ return 0
173+ }
174+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
175+ return seq
176+}
A composite/sizes_test.go +14 -0
@@ -0,0 +1,14 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package composite
3+
4+import "testing"
5+
6+func TestWireSizes(t *testing.T) {
7+ if got := 32; got != 32 {
8+ t.Errorf("reply QueryVersion fixed size = %d", got)
9+ }
10+ if got := 32; got != 32 {
11+ t.Errorf("reply GetOverlayWindow fixed size = %d", got)
12+ }
13+
14+}
A composite/types_generated.go +7 -0
@@ -0,0 +1,7 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package composite
3+
4+type Redirect uint8
5+
6+const RedirectAutomatic Redirect = 0
7+const RedirectManual Redirect = 1
A ext.go +27 -0
@@ -0,0 +1,27 @@
1+package xturbo
2+
3+// ExtInfo is a negotiated extension's wire opcode and event/error bases.
4+type ExtInfo struct {
5+ Present bool
6+ Major, FirstEvent, FirstError uint8
7+}
8+
9+// ExtTable is populated during setup. Fixed arrays avoid lookup allocations.
10+// Reverse mapping is completed with the read-side runtime in Phase 3.
11+type ExtTable struct{ info [extCount]ExtInfo }
12+
13+func (t *ExtTable) Set(id ExtID, major, firstEvent, firstError uint8) {
14+ if id < extCount {
15+ t.info[id] = ExtInfo{true, major, firstEvent, firstError}
16+ }
17+}
18+func (t *ExtTable) Info(id ExtID) ExtInfo {
19+ if id >= extCount {
20+ return ExtInfo{}
21+ }
22+ if id == ExtCore {
23+ return ExtInfo{Present: true}
24+ }
25+ return t.info[id]
26+}
27+func (t *ExtTable) Major(id ExtID) uint8 { return t.Info(id).Major }
A ext_generated.go +19 -0
@@ -0,0 +1,19 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xturbo
3+
4+type ExtID uint8
5+
6+const (
7+ ExtCore ExtID = iota
8+ ExtBigRequests
9+ ExtGenericEvent
10+ ExtXCMisc
11+ ExtComposite
12+ ExtXFixes
13+ ExtRes
14+ ExtRender
15+ ExtShape
16+ extCount
17+)
18+
19+var ExtXName = [extCount]string{"", "BIG-REQUESTS", "Generic Event Extension", "XC-MISC", "Composite", "XFIXES", "X-Resource", "RENDER", "SHAPE"}
A ge/replies_fuzz_test.go +22 -0
@@ -0,0 +1,22 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package ge
3+
4+import "testing"
5+
6+func FuzzParseQueryVersionReply(f *testing.F) {
7+ f.Add(make([]byte, 32))
8+ f.Fuzz(func(t *testing.T, raw []byte) {
9+ r, ok := ParseQueryVersionReply(raw)
10+ if !ok {
11+ if len(raw) >= 32 {
12+ t.Fatal("rejected a complete fixed-size reply")
13+ }
14+ return
15+ }
16+ if len(r.Raw()) != len(raw) {
17+ t.Fatal("Raw must return the parsed bytes")
18+ }
19+ _ = r.MajorVersion()
20+ _ = r.MinorVersion()
21+ })
22+}
A ge/replies_generated.go +24 -0
@@ -0,0 +1,24 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package ge
3+
4+import "encoding/binary"
5+
6+// QueryVersionReply is a zero-copy view over a QueryVersion reply; offsets count from reply byte 0.
7+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
8+type QueryVersionReply struct{ raw []byte }
9+
10+// ParseQueryVersionReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
11+func ParseQueryVersionReply(raw []byte) (QueryVersionReply, bool) {
12+ if len(raw) < 32 {
13+ return QueryVersionReply{}, false
14+ }
15+ r := QueryVersionReply{raw: raw}
16+ return r, true
17+}
18+func (r QueryVersionReply) Raw() []byte { return r.raw }
19+func (r QueryVersionReply) MajorVersion() uint16 {
20+ return uint16(binary.LittleEndian.Uint16(r.raw[8:]))
21+}
22+func (r QueryVersionReply) MinorVersion() uint16 {
23+ return uint16(binary.LittleEndian.Uint16(r.raw[10:]))
24+}
A ge/requests_generated.go +24 -0
@@ -0,0 +1,24 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package ge
3+
4+import "encoding/binary"
5+import "bnema.dev/xturbo"
6+
7+func QueryVersion(b *xturbo.Buf, clientMajorVersion uint16, clientMinorVersion uint16) xturbo.Seq {
8+ if b.Ext == nil {
9+ b.Fail(xturbo.ErrExtMissing)
10+ return 0
11+ }
12+ major := b.Ext.Major(xturbo.ExtGenericEvent)
13+ if major == 0 {
14+ b.Fail(xturbo.ErrExtMissing)
15+ return 0
16+ }
17+ p, seq := b.Request(major, 0, 4)
18+ if p == nil {
19+ return 0
20+ }
21+ binary.LittleEndian.PutUint16(p[0:], uint16(clientMajorVersion))
22+ binary.LittleEndian.PutUint16(p[2:], uint16(clientMinorVersion))
23+ return seq
24+}
A ge/sizes_test.go +11 -0
@@ -0,0 +1,11 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package ge
3+
4+import "testing"
5+
6+func TestWireSizes(t *testing.T) {
7+ if got := 32; got != 32 {
8+ t.Errorf("reply QueryVersion fixed size = %d", got)
9+ }
10+
11+}
A ge/types_generated.go +2 -0
@@ -0,0 +1,2 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package ge
A generate.go +3 -0
@@ -0,0 +1,3 @@
1+package xturbo
2+
3+//go:generate go run ./cmd/xtgen -all
A internal/xtest/README.md +40 -0
@@ -0,0 +1,40 @@
1+# Wire goldens
2+
3+Refresh the request fixtures from the repository root:
4+
5+```
6+PATH="$PATH:/usr/sbin" go test -tags xserver ./internal/xtest -update
7+```
8+
9+The local `/usr/sbin/xtrace` is glibc's program execution tracer, not the X11
10+protocol proxy. The permitted fallback uses a raw Unix socketpair tee connected
11+to a fresh Xvfb server. A small independent reference encoder (not the generated
12+bindings) sends the requests; the tee records their actual bytes. GetGeometry's
13+successful response also establishes that the preceding MapWindow was accepted.
14+The captured target is the root window; XFIXES's major opcode is negotiated.
15+Tests read target/opcode from the fixture, not a hard-coded server assignment.
16+No runtime Conn is needed at this phase.
17+
18+The same run also writes reply goldens (`<Name>.reply.hex`): the server's
19+response to each reference request, read back through the tee. Events and
20+runtime integration belong to their subsequent tasks.
21+
22+T2.4 adds InternAtom, ChangeProperty and XRes QueryClientIds. A GetProperty
23+read-back validates the property contents. XRes's major opcode is negotiated;
24+QueryVersion 1.2 precedes the ClientIdSpec-list query. The capture is independent
25+of generated code, including counts, framing, and padding.
26+
27+T2.5 adds ConfigureWindow with empty, sparse and all-seven-bit masks,
28+CreateWindow, ChangeWindowAttributes and Render CreatePicture. The reference
29+encoder creates sibling windows, exercises signed coordinates and both BOOL32
30+values, and fences void requests with a successful reply (any preceding error
31+fails capture). RENDER's opcode and the root visual's picture format are queried
32+from Xvfb. Tests reuse only server-assigned resource/format IDs from fixtures;
33+mask bits, values and ordering remain independent expected inputs.
34+
35+T2.6 keeps the replies to QueryExtension, xfixes QueryVersion, GetGeometry,
36+InternAtom, GetProperty, res QueryClientIds and render QueryPictFormats, and
37+adds GetWindowAttributes (child window), QueryTree (root), an unset WM_NAME
38+GetProperty (zero-length value) and ListExtensions (variable STR list). These
39+reply-only requests use opcodes outside the request-golden classifier.
40+Generated `FuzzParse*Reply` targets seed from every matching reply golden.
A internal/xtest/capture_test.go +405 -0
@@ -0,0 +1,405 @@
1+//go:build xserver
2+
3+package xtest
4+
5+import (
6+ "bytes"
7+ "encoding/binary"
8+ "encoding/hex"
9+ "flag"
10+ "fmt"
11+ "io"
12+ "net"
13+ "os"
14+ "os/exec"
15+ "path/filepath"
16+ "strconv"
17+ "strings"
18+ "testing"
19+ "time"
20+
21+ "golang.org/x/sys/unix"
22+)
23+
24+var update = flag.Bool("update", false, "refresh request goldens using Xvfb and a raw socketpair tee")
25+
26+func TestCaptureRequests(t *testing.T) {
27+ if !*update {
28+ t.Skip("pass -update to capture request goldens")
29+ }
30+ // displayfd avoids display-number races and tells us when Xvfb is ready.
31+ r, w, err := os.Pipe()
32+ if err != nil {
33+ t.Fatal(err)
34+ }
35+ defer r.Close()
36+ cmd := exec.Command("Xvfb", "-displayfd", "3", "-screen", "0", "800x600x24", "-nolisten", "tcp", "-ac")
37+ cmd.ExtraFiles = []*os.File{w}
38+ var log bytes.Buffer
39+ cmd.Stderr = &log
40+ if err = cmd.Start(); err != nil {
41+ w.Close()
42+ t.Fatal(err)
43+ }
44+ w.Close()
45+ defer func() { _ = cmd.Process.Kill(); _ = cmd.Wait() }()
46+ _ = r.SetReadDeadline(time.Now().Add(5 * time.Second))
47+ var display [32]byte
48+ n, err := r.Read(display[:])
49+ if err != nil {
50+ t.Fatalf("Xvfb: %v: %s", err, log.String())
51+ }
52+ num, err := strconv.Atoi(strings.TrimSpace(string(display[:n])))
53+ if err != nil {
54+ t.Fatal(err)
55+ }
56+ server, err := net.DialTimeout("unix", fmt.Sprintf("/tmp/.X11-unix/X%d", num), 5*time.Second)
57+ if err != nil {
58+ t.Fatal(err)
59+ }
60+ defer server.Close()
61+ fds, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0)
62+ if err != nil {
63+ t.Fatal(err)
64+ }
65+ a := os.NewFile(uintptr(fds[0]), "capture-client")
66+ b := os.NewFile(uintptr(fds[1]), "capture-tee")
67+ client, err := net.FileConn(a)
68+ a.Close()
69+ if err != nil {
70+ b.Close()
71+ t.Fatal(err)
72+ }
73+ defer client.Close()
74+ tee, err := net.FileConn(b)
75+ b.Close()
76+ if err != nil {
77+ t.Fatal(err)
78+ }
79+ defer tee.Close()
80+ _ = client.SetDeadline(time.Now().Add(5 * time.Second))
81+ _ = server.SetDeadline(time.Now().Add(5 * time.Second))
82+ var recorded bytes.Buffer
83+ copied := make(chan error, 1)
84+ go func() { _, err := io.Copy(server, io.TeeReader(tee, &recorded)); copied <- err }()
85+ go func() { _, _ = io.Copy(tee, server) }()
86+ write := func(p []byte) {
87+ t.Helper()
88+ if _, err := client.Write(p); err != nil {
89+ t.Fatal(err)
90+ }
91+ }
92+ read := func(p []byte) {
93+ t.Helper()
94+ if _, err := io.ReadFull(client, p); err != nil {
95+ t.Fatal(err)
96+ }
97+ }
98+ // Independent reference encoder: no generated bindings participate in capture.
99+ write([]byte{'l', 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0})
100+ var setupHead [8]byte
101+ read(setupHead[:])
102+ if setupHead[0] != 1 {
103+ t.Fatalf("setup failed: %x", setupHead)
104+ }
105+ setup := make([]byte, int(binary.LittleEndian.Uint16(setupHead[6:]))*4)
106+ read(setup)
107+ vendorLen := int(binary.LittleEndian.Uint16(setup[16:]))
108+ formats := int(setup[21])
109+ screenOff := 32 + (vendorLen+3)&^3 + 8*formats
110+ root := binary.LittleEndian.Uint32(setup[screenOff:])
111+ // Query XFIXES dynamically rather than assuming a server-specific major opcode.
112+ query := []byte{98, 0, 4, 0, 6, 0, 0, 0, 'X', 'F', 'I', 'X', 'E', 'S', 0, 0}
113+ write(query)
114+ // Server bytes reach the client through the same tee; keep named replies as
115+ // reply goldens (reply byte 0 through 32+4*length).
116+ replies := map[string][]byte{}
117+ keep := func(name string, p []byte) []byte {
118+ t.Helper()
119+ if p[0] != 1 {
120+ t.Fatalf("%s: expected a reply, got %x", name, p)
121+ }
122+ replies[name] = p
123+ return p
124+ }
125+ packet := func() []byte {
126+ t.Helper()
127+ head := make([]byte, 32)
128+ read(head)
129+ if head[0] == 1 {
130+ tail := make([]byte, int(binary.LittleEndian.Uint32(head[4:]))*4)
131+ read(tail)
132+ head = append(head, tail...)
133+ }
134+ return head
135+ }
136+ ext := keep("xproto/QueryExtension", packet())
137+ if ext[0] != 1 || ext[8] != 1 {
138+ t.Fatalf("XFIXES unavailable: %x", ext)
139+ }
140+ major := ext[9]
141+ version := make([]byte, 12)
142+ version[0] = major
143+ version[2] = 3
144+ binary.LittleEndian.PutUint32(version[4:], 6)
145+ write(version)
146+ reply := keep("xfixes/QueryVersion", packet())
147+ if reply[0] != 1 {
148+ t.Fatalf("QueryVersion failed: %x", reply)
149+ }
150+ mapReq := make([]byte, 8)
151+ mapReq[0] = 8
152+ mapReq[2] = 2
153+ binary.LittleEndian.PutUint32(mapReq[4:], root)
154+ write(mapReq)
155+ geometry := append([]byte(nil), mapReq...)
156+ geometry[0] = 14
157+ write(geometry)
158+ geom := keep("xproto/GetGeometry", packet())
159+ if geom[0] != 1 || binary.LittleEndian.Uint16(geom[2:]) != 4 {
160+ t.Fatalf("MapWindow/GetGeometry rejected: %x", geom)
161+ }
162+
163+ // InternAtom, ChangeProperty and XRes QueryClientIds exercise derived lengths,
164+ // byte expressions and fixed-struct lists with independently assembled bytes.
165+ intern := []byte{16, 0, 4, 0, 7, 0, 0, 0, 'X', 'T', 'U', 'R', 'B', 'O', '_', 0}
166+ write(intern)
167+ atomReply := keep("xproto/InternAtom", packet())
168+ if atomReply[0] != 1 {
169+ t.Fatalf("InternAtom: %x", atomReply)
170+ }
171+ atom := binary.LittleEndian.Uint32(atomReply[8:])
172+ property := make([]byte, 28)
173+ property[0] = 18
174+ property[2] = 7
175+ binary.LittleEndian.PutUint32(property[4:], root)
176+ binary.LittleEndian.PutUint32(property[8:], atom)
177+ binary.LittleEndian.PutUint32(property[12:], 31)
178+ property[16] = 8
179+ binary.LittleEndian.PutUint32(property[20:], 3)
180+ copy(property[24:], "abc")
181+ write(property)
182+ // A successful GetProperty reply proves the preceding write was accepted.
183+ get := make([]byte, 24)
184+ get[0] = 20
185+ get[2] = 6
186+ binary.LittleEndian.PutUint32(get[4:], root)
187+ binary.LittleEndian.PutUint32(get[8:], atom)
188+ binary.LittleEndian.PutUint32(get[20:], 1)
189+ write(get)
190+ got := keep("xproto/GetProperty", packet())
191+ if got[0] != 1 || string(got[32:35]) != "abc" {
192+ t.Fatalf("ChangeProperty: %x", got)
193+ }
194+ resName := "X-Resource"
195+ queryRes := make([]byte, 20)
196+ queryRes[0] = 98
197+ queryRes[2] = 5
198+ queryRes[4] = byte(len(resName))
199+ copy(queryRes[8:], resName)
200+ write(queryRes)
201+ resExt := packet()
202+ if resExt[0] != 1 || resExt[8] != 1 {
203+ t.Fatalf("XRes unavailable: %x", resExt)
204+ }
205+ resMajor := resExt[9]
206+ resVersion := []byte{resMajor, 0, 2, 0, 1, 2, 0, 0}
207+ write(resVersion)
208+ if p := packet(); p[0] != 1 {
209+ t.Fatalf("XRes version: %x", p)
210+ }
211+ ids := make([]byte, 16)
212+ ids[0] = resMajor
213+ ids[1] = 4
214+ ids[2] = 4
215+ binary.LittleEndian.PutUint32(ids[4:], 1)
216+ binary.LittleEndian.PutUint32(ids[12:], 1)
217+ write(ids)
218+ keep("res/QueryClientIds", packet())
219+ // Value-list reference packets are assembled independently, including mask-bit
220+ // ordering. Two sibling windows allow all seven ConfigureWindow bits to be
221+ // exercised legally. A final reply fences all void requests and exposes errors.
222+ base := binary.LittleEndian.Uint32(setup[4:])
223+ child, sibling, picture := base|1, base|2, base|3
224+ create := func(id uint32, mask uint32, values ...uint32) {
225+ p := make([]byte, 32+4*len(values))
226+ p[0] = 1
227+ binary.LittleEndian.PutUint16(p[2:], uint16(len(p)/4))
228+ binary.LittleEndian.PutUint32(p[4:], id)
229+ binary.LittleEndian.PutUint32(p[8:], root)
230+ binary.LittleEndian.PutUint16(p[16:], 64)
231+ binary.LittleEndian.PutUint16(p[18:], 48)
232+ binary.LittleEndian.PutUint16(p[22:], 1) // InputOutput, inherited depth/visual
233+ binary.LittleEndian.PutUint32(p[28:], mask)
234+ for i, v := range values {
235+ binary.LittleEndian.PutUint32(p[32+4*i:], v)
236+ }
237+ write(p)
238+ }
239+ create(sibling, 0)
240+ create(child, 2|512|1024, 0x123456, 1, 0)
241+ change := make([]byte, 20)
242+ change[0], change[2] = 2, 5
243+ binary.LittleEndian.PutUint32(change[4:], child)
244+ binary.LittleEndian.PutUint32(change[8:], 512|1024)
245+ binary.LittleEndian.PutUint32(change[16:], 1) // false, true BOOL32 words
246+ write(change)
247+ configure := func(mask uint16, values ...uint32) {
248+ p := make([]byte, 12+4*len(values))
249+ p[0] = 12
250+ binary.LittleEndian.PutUint16(p[2:], uint16(len(p)/4))
251+ binary.LittleEndian.PutUint32(p[4:], child)
252+ binary.LittleEndian.PutUint16(p[8:], mask)
253+ for i, v := range values {
254+ binary.LittleEndian.PutUint32(p[12+4*i:], v)
255+ }
256+ write(p)
257+ }
258+ configure(0)
259+ configure(1|4|64, 0xfffffff9, 80, 0)
260+ configure(127, 0xfffffffd, 9, 96, 72, 2, sibling, 0)
261+ queryRender := []byte{98, 0, 4, 0, 6, 0, 0, 0, 'R', 'E', 'N', 'D', 'E', 'R', 0, 0}
262+ write(queryRender)
263+ renderExt := packet()
264+ if renderExt[0] != 1 || renderExt[8] != 1 {
265+ t.Fatalf("value requests/RENDER query: %x", renderExt)
266+ }
267+ renderMajor := renderExt[9]
268+ write([]byte{renderMajor, 1, 1, 0}) // QueryPictFormats
269+ formatsReply := keep("render/QueryPictFormats", packet())
270+ if formatsReply[0] != 1 {
271+ t.Fatalf("QueryPictFormats: %x", formatsReply)
272+ }
273+ // Match the root visual rather than guessing a server-assigned format ID.
274+ rootVisual := binary.LittleEndian.Uint32(setup[screenOff+32:])
275+ off := 32 + 28*int(binary.LittleEndian.Uint32(formatsReply[8:]))
276+ var format uint32
277+ for range binary.LittleEndian.Uint32(formatsReply[12:]) {
278+ depths := binary.LittleEndian.Uint32(formatsReply[off:])
279+ off += 8
280+ for range depths {
281+ visuals := binary.LittleEndian.Uint16(formatsReply[off+2:])
282+ off += 8
283+ for range visuals {
284+ if binary.LittleEndian.Uint32(formatsReply[off:]) == rootVisual {
285+ format = binary.LittleEndian.Uint32(formatsReply[off+4:])
286+ }
287+ off += 8
288+ }
289+ }
290+ }
291+ if format == 0 {
292+ t.Fatal("root visual has no Render format")
293+ }
294+ pic := make([]byte, 32)
295+ pic[0], pic[1], pic[2] = renderMajor, 4, 8
296+ binary.LittleEndian.PutUint32(pic[4:], picture)
297+ binary.LittleEndian.PutUint32(pic[8:], child)
298+ binary.LittleEndian.PutUint32(pic[12:], format)
299+ binary.LittleEndian.PutUint32(pic[16:], 1|16|32)
300+ binary.LittleEndian.PutUint32(pic[20:], 1) // RepeatNormal
301+ binary.LittleEndian.PutUint32(pic[24:], 0xfffffffb)
302+ binary.LittleEndian.PutUint32(pic[28:], 7)
303+ write(pic)
304+ write([]byte{43, 0, 1, 0}) // GetInputFocus fences CreatePicture
305+ if p := packet(); p[0] != 1 {
306+ t.Fatalf("CreatePicture rejected: %x", p)
307+ }
308+ // Reply-only captures. Opcodes 3, 15, 20 and 99 are not request goldens, so
309+ // the request-stream classifier below is unaffected.
310+ attrs := make([]byte, 8)
311+ attrs[0], attrs[2] = 3, 2
312+ binary.LittleEndian.PutUint32(attrs[4:], child)
313+ write(attrs)
314+ keep("xproto/GetWindowAttributes", packet())
315+ tree := make([]byte, 8)
316+ tree[0], tree[2] = 15, 2
317+ binary.LittleEndian.PutUint32(tree[4:], root)
318+ write(tree)
319+ keep("xproto/QueryTree", packet())
320+ // WM_NAME is unset on a fresh Xvfb root: a zero-length GetProperty reply.
321+ empty := make([]byte, 24)
322+ empty[0], empty[2] = 20, 6
323+ binary.LittleEndian.PutUint32(empty[4:], root)
324+ binary.LittleEndian.PutUint32(empty[8:], 39)
325+ binary.LittleEndian.PutUint32(empty[20:], 1)
326+ write(empty)
327+ keep("xproto/GetPropertyEmpty", packet())
328+ write([]byte{99, 0, 1, 0}) // ListExtensions: variable STR iterator
329+ keep("xproto/ListExtensions", packet())
330+ // Closing the client drains the request direction; wait before inspecting tee.
331+ client.Close()
332+ select {
333+ case err := <-copied:
334+ if err != nil {
335+ t.Fatal(err)
336+ }
337+ case <-time.After(5 * time.Second):
338+ t.Fatal("tee did not drain")
339+ }
340+ stream := recorded.Bytes()
341+ requests := stream[12:]
342+ captured := map[string][]byte{}
343+ configIndex := 0
344+ for len(requests) > 0 {
345+ size := int(binary.LittleEndian.Uint16(requests[2:])) * 4
346+ if size < 4 || size > len(requests) {
347+ t.Fatal("malformed capture")
348+ }
349+ p := requests[:size]
350+ switch p[0] {
351+ case 1:
352+ if binary.LittleEndian.Uint32(p[4:]) == child {
353+ captured["xproto/CreateWindow"] = p
354+ }
355+ case 2:
356+ captured["xproto/ChangeWindowAttributes"] = p
357+ case 12:
358+ names := []string{"ConfigureWindow", "ConfigureWindowSparse", "ConfigureWindowAll"}
359+ captured["xproto/"+names[configIndex]] = p
360+ configIndex++
361+ case 8:
362+ captured["xproto/MapWindow"] = p
363+ case 14:
364+ captured["xproto/GetGeometry"] = p
365+ case 16:
366+ captured["xproto/InternAtom"] = p
367+ case 18:
368+ captured["xproto/ChangeProperty"] = p
369+ default:
370+ if p[0] == renderMajor && p[1] == 4 {
371+ captured["render/CreatePicture"] = p
372+ }
373+ if p[0] == resMajor && p[1] == 4 {
374+ captured["res/QueryClientIds"] = p
375+ }
376+ if p[0] == major {
377+ captured["xfixes/QueryVersion"] = p
378+ }
379+ }
380+ requests = requests[size:]
381+ }
382+ if len(captured) != 12 || len(replies) != 11 {
383+ t.Fatal("missing captured requests or replies")
384+ }
385+ for name, p := range replies {
386+ path := filepath.Join("../../testdata/golden", name+".reply.hex")
387+ if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
388+ t.Fatal(err)
389+ }
390+ text := "# source: Xvfb reply via raw socketpair tee to an independent reference request\n# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace\n" + hex.EncodeToString(p) + "\n"
391+ if err := os.WriteFile(path, []byte(text), 0644); err != nil {
392+ t.Fatal(err)
393+ }
394+ }
395+ for name, p := range captured {
396+ path := filepath.Join("../../testdata/golden", name+".req.hex")
397+ if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
398+ t.Fatal(err)
399+ }
400+ text := "# source: Xvfb via raw socketpair tee; independent reference encoder; server accepted\n# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace\n" + hex.EncodeToString(p) + "\n"
401+ if err := os.WriteFile(path, []byte(text), 0644); err != nil {
402+ t.Fatal(err)
403+ }
404+ }
405+}
A internal/xtest/golden.go +22 -0
@@ -0,0 +1,22 @@
1+// Package xtest provides wire fixtures shared by binding tests.
2+package xtest
3+
4+import (
5+ "encoding/hex"
6+ "os"
7+ "strings"
8+)
9+
10+// LoadHex reads whitespace-separated hex with optional # comments.
11+func LoadHex(path string) ([]byte, error) {
12+ b, err := os.ReadFile(path)
13+ if err != nil {
14+ return nil, err
15+ }
16+ var text strings.Builder
17+ for line := range strings.SplitSeq(string(b), "\n") {
18+ line, _, _ = strings.Cut(line, "#")
19+ text.WriteString(strings.Join(strings.Fields(line), ""))
20+ }
21+ return hex.DecodeString(text.String())
22+}
A lists_test.go +87 -0
@@ -0,0 +1,87 @@
1+package xturbo_test
2+
3+import (
4+ "bytes"
5+ "encoding/binary"
6+ "strings"
7+ "testing"
8+
9+ "bnema.dev/xturbo"
10+ "bnema.dev/xturbo/internal/xtest"
11+ "bnema.dev/xturbo/render"
12+ "bnema.dev/xturbo/res"
13+ "bnema.dev/xturbo/xproto"
14+)
15+
16+func TestListGoldens(t *testing.T) {
17+ for _, name := range []string{"xproto/InternAtom", "xproto/ChangeProperty", "res/QueryClientIds"} {
18+ t.Run(name, func(t *testing.T) {
19+ want, err := xtest.LoadHex("testdata/golden/" + name + ".req.hex")
20+ if err != nil {
21+ t.Fatal(err)
22+ }
23+ b := xturbo.NewBuf(0)
24+ switch name {
25+ case "xproto/InternAtom":
26+ xproto.InternAtom(b, false, "XTURBO_")
27+ case "xproto/ChangeProperty":
28+ xproto.ChangeProperty(b, xproto.PropModeReplace, xproto.Window(binary.LittleEndian.Uint32(want[4:])), xproto.Atom(binary.LittleEndian.Uint32(want[8:])), xproto.AtomString, 8, 3, []byte("abc"))
29+ case "res/QueryClientIds":
30+ var ext xturbo.ExtTable
31+ ext.Set(xturbo.ExtRes, want[0], 0, 0)
32+ b.Ext = &ext
33+ res.QueryClientIds(b, []res.ClientIdSpec{{Client: 0, Mask: res.ClientIdMaskClientXID}})
34+ }
35+ if b.Err() != nil || !bytes.Equal(b.Bytes(), want) {
36+ t.Fatalf("err %v got %x want %x", b.Err(), b.Bytes(), want)
37+ }
38+ })
39+ }
40+}
41+func TestListLengths(t *testing.T) {
42+ b := xturbo.NewBuf(0)
43+ if xproto.ChangeProperty(b, 0, 1, 1, 1, 16, 2, []byte{1, 2}) != 0 || b.Err() != xturbo.ErrBadLength || b.Len() != 0 {
44+ t.Fatal("expression length mismatch")
45+ }
46+ b = xturbo.NewBuf(0)
47+ if xproto.InternAtom(b, false, strings.Repeat("x", 65536)) != 0 || b.Err() != xturbo.ErrBadLength {
48+ t.Fatal("derived length truncation")
49+ }
50+ b = xturbo.NewBuf(0)
51+ xproto.SetFontPath(b, []xproto.Str{{NameLen: 3, Name: "abc"}, {NameLen: 1, Name: "d"}})
52+ want := []byte{51, 0, 4, 0, 2, 0, 0, 0, 3, 'a', 'b', 'c', 1, 'd', 0, 0}
53+ if b.Err() != nil || !bytes.Equal(b.Bytes(), want) {
54+ t.Fatalf("variable structs: %x err %v", b.Bytes(), b.Err())
55+ }
56+ b = xturbo.NewBuf(0)
57+ xproto.QueryTextExtents(b, 1, []xproto.Char2b{{Byte1: 0, Byte2: 'a'}})
58+ if b.Bytes()[1] != 1 {
59+ t.Fatal("implicit list length exprfield")
60+ }
61+ var ext xturbo.ExtTable
62+ ext.Set(xturbo.ExtRender, 140, 0, 0)
63+ b = xturbo.NewBuf(0)
64+ b.Ext = &ext
65+ if render.AddGlyphs(b, 1, 2, []uint32{1}, nil, nil) != 0 || b.Err() != xturbo.ErrBadLength {
66+ t.Fatal("shared length must remain explicit")
67+ }
68+}
69+func TestAllocListRequests(t *testing.T) {
70+ b := xturbo.NewBuf(0)
71+ data := make([]byte, 4096)
72+ specs := []res.ClientIdSpec{{Client: 1, Mask: res.ClientIdMaskClientXID}}
73+ var ext xturbo.ExtTable
74+ ext.Set(xturbo.ExtRes, 141, 0, 0)
75+ b.Ext = &ext
76+ if n := testing.AllocsPerRun(1000, func() {
77+ b.Reset()
78+ xproto.InternAtom(b, false, "WM_CLASS")
79+ xproto.ChangeProperty(b, 0, 1, 1, 1, 8, 4096, data)
80+ res.QueryClientIds(b, specs)
81+ }); n != 0 {
82+ t.Fatal(n)
83+ }
84+ if b.Err() != nil {
85+ t.Fatal(b.Err())
86+ }
87+}
A render/replies_fuzz_test.go +135 -0
@@ -0,0 +1,135 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package render
3+
4+import "testing"
5+import "bnema.dev/xturbo/internal/xtest"
6+
7+func FuzzParseQueryVersionReply(f *testing.F) {
8+ f.Add(make([]byte, 32))
9+ f.Fuzz(func(t *testing.T, raw []byte) {
10+ r, ok := ParseQueryVersionReply(raw)
11+ if !ok {
12+ if len(raw) >= 32 {
13+ t.Fatal("rejected a complete fixed-size reply")
14+ }
15+ return
16+ }
17+ if len(r.Raw()) != len(raw) {
18+ t.Fatal("Raw must return the parsed bytes")
19+ }
20+ _ = r.MajorVersion()
21+ _ = r.MinorVersion()
22+ })
23+}
24+
25+func FuzzParseQueryPictFormatsReply(f *testing.F) {
26+ f.Add(make([]byte, 32))
27+ if raw, err := xtest.LoadHex("../testdata/golden/render/QueryPictFormats.reply.hex"); err != nil {
28+ f.Fatal(err)
29+ } else {
30+ f.Add(raw)
31+ }
32+ f.Fuzz(func(t *testing.T, raw []byte) {
33+ r, ok := ParseQueryPictFormatsReply(raw)
34+ if !ok {
35+ return
36+ }
37+ if len(r.Raw()) != len(raw) {
38+ t.Fatal("Raw must return the parsed bytes")
39+ }
40+ _ = r.NumFormats()
41+ _ = r.NumScreens()
42+ _ = r.NumDepths()
43+ _ = r.NumVisuals()
44+ _ = r.NumSubpixel()
45+ {
46+ l0 := r.Formats()
47+ for i := 0; i < l0.Len(); i++ {
48+ _ = l0.At(i)
49+ }
50+ }
51+ {
52+ it0 := r.Screens()
53+ for it0.Next() {
54+ _ = it0.Value().NumDepths()
55+ _ = it0.Value().Fallback()
56+ {
57+ it1 := it0.Value().Depths()
58+ for it1.Next() {
59+ _ = it1.Value().Depth()
60+ _ = it1.Value().NumVisuals()
61+ {
62+ l2 := it1.Value().Visuals()
63+ for i := 0; i < l2.Len(); i++ {
64+ _ = l2.At(i)
65+ }
66+ }
67+ }
68+ if it1.Err() {
69+ t.Fatal("iterator error after successful Parse")
70+ }
71+ }
72+ }
73+ if it0.Err() {
74+ t.Fatal("iterator error after successful Parse")
75+ }
76+ }
77+ {
78+ l0 := r.Subpixels()
79+ for i := 0; i < l0.Len(); i++ {
80+ _ = l0.At(i)
81+ }
82+ }
83+ })
84+}
85+
86+func FuzzParseQueryPictIndexValuesReply(f *testing.F) {
87+ f.Add(make([]byte, 32))
88+ f.Fuzz(func(t *testing.T, raw []byte) {
89+ r, ok := ParseQueryPictIndexValuesReply(raw)
90+ if !ok {
91+ return
92+ }
93+ if len(r.Raw()) != len(raw) {
94+ t.Fatal("Raw must return the parsed bytes")
95+ }
96+ _ = r.NumValues()
97+ {
98+ l0 := r.Values()
99+ for i := 0; i < l0.Len(); i++ {
100+ _ = l0.At(i)
101+ }
102+ }
103+ })
104+}
105+
106+func FuzzParseQueryFiltersReply(f *testing.F) {
107+ f.Add(make([]byte, 32))
108+ f.Fuzz(func(t *testing.T, raw []byte) {
109+ r, ok := ParseQueryFiltersReply(raw)
110+ if !ok {
111+ return
112+ }
113+ if len(r.Raw()) != len(raw) {
114+ t.Fatal("Raw must return the parsed bytes")
115+ }
116+ _ = r.NumAliases()
117+ _ = r.NumFilters()
118+ {
119+ l0 := r.Aliases()
120+ for i := 0; i < l0.Len(); i++ {
121+ _ = l0.At(i)
122+ }
123+ }
124+ {
125+ it0 := r.Filters()
126+ for it0.Next() {
127+ _ = it0.Value().NameLen()
128+ _ = len(it0.Value().Name())
129+ }
130+ if it0.Err() {
131+ t.Fatal("iterator error after successful Parse")
132+ }
133+ }
134+ })
135+}
A render/replies_generated.go +380 -0
@@ -0,0 +1,380 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package render
3+
4+import "bnema.dev/xturbo/xproto"
5+import "encoding/binary"
6+
7+// QueryVersionReply is a zero-copy view over a QueryVersion reply; offsets count from reply byte 0.
8+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
9+type QueryVersionReply struct{ raw []byte }
10+
11+// ParseQueryVersionReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
12+func ParseQueryVersionReply(raw []byte) (QueryVersionReply, bool) {
13+ if len(raw) < 32 {
14+ return QueryVersionReply{}, false
15+ }
16+ r := QueryVersionReply{raw: raw}
17+ return r, true
18+}
19+func (r QueryVersionReply) Raw() []byte { return r.raw }
20+func (r QueryVersionReply) MajorVersion() uint32 {
21+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
22+}
23+func (r QueryVersionReply) MinorVersion() uint32 {
24+ return uint32(binary.LittleEndian.Uint32(r.raw[12:]))
25+}
26+
27+// QueryPictFormatsReply is a zero-copy view over a QueryPictFormats reply; offsets count from reply byte 0.
28+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
29+type QueryPictFormatsReply struct{ raw []byte }
30+
31+// ParseQueryPictFormatsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
32+func ParseQueryPictFormatsReply(raw []byte) (QueryPictFormatsReply, bool) {
33+ if len(raw) < 32 {
34+ return QueryPictFormatsReply{}, false
35+ }
36+ r := QueryPictFormatsReply{raw: raw}
37+ off := 32
38+ {
39+ n := int(r.NumFormats())
40+ if n < 0 || n > len(r.raw) {
41+ return QueryPictFormatsReply{}, false
42+ }
43+ off += n * 28
44+ }
45+ if off > len(r.raw) {
46+ return QueryPictFormatsReply{}, false
47+ }
48+ {
49+ n := int(r.NumScreens())
50+ if off > len(r.raw) || n < 0 || n > len(r.raw) {
51+ return QueryPictFormatsReply{}, false
52+ }
53+ it := NewPictscreenIter(r.raw[off:], n)
54+ for it.Next() {
55+ off += it.Value().Size()
56+ }
57+ if it.Err() {
58+ return QueryPictFormatsReply{}, false
59+ }
60+ }
61+ {
62+ n := int(r.NumSubpixel())
63+ if n < 0 || n > len(r.raw) {
64+ return QueryPictFormatsReply{}, false
65+ }
66+ off += n * 4
67+ }
68+ if off > len(r.raw) {
69+ return QueryPictFormatsReply{}, false
70+ }
71+ if off > len(r.raw) {
72+ return QueryPictFormatsReply{}, false
73+ }
74+ return r, true
75+}
76+func (r QueryPictFormatsReply) Raw() []byte { return r.raw }
77+func (r QueryPictFormatsReply) NumFormats() uint32 {
78+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
79+}
80+func (r QueryPictFormatsReply) NumScreens() uint32 {
81+ return uint32(binary.LittleEndian.Uint32(r.raw[12:]))
82+}
83+func (r QueryPictFormatsReply) NumDepths() uint32 {
84+ return uint32(binary.LittleEndian.Uint32(r.raw[16:]))
85+}
86+func (r QueryPictFormatsReply) NumVisuals() uint32 {
87+ return uint32(binary.LittleEndian.Uint32(r.raw[20:]))
88+}
89+func (r QueryPictFormatsReply) NumSubpixel() uint32 {
90+ return uint32(binary.LittleEndian.Uint32(r.raw[24:]))
91+}
92+func (r QueryPictFormatsReply) Formats() PictforminfoList {
93+ off := 32
94+ end := off + (int(r.NumFormats()))*28
95+ return PictforminfoList{b: r.raw[off:end:end]}
96+}
97+func (r QueryPictFormatsReply) Screens() PictscreenIter {
98+ off := 32
99+ {
100+ n := int(r.NumFormats())
101+ off += n * 28
102+ }
103+ return NewPictscreenIter(r.raw[off:], int(r.NumScreens()))
104+}
105+func (r QueryPictFormatsReply) Subpixels() SubPixelList {
106+ off := 32
107+ {
108+ n := int(r.NumFormats())
109+ off += n * 28
110+ }
111+ {
112+ n := int(r.NumScreens())
113+ it := NewPictscreenIter(r.raw[off:], n)
114+ for it.Next() {
115+ off += it.Value().Size()
116+ }
117+ }
118+ end := off + (int(r.NumSubpixel()))*4
119+ return SubPixelList{b: r.raw[off:end:end]}
120+}
121+
122+// QueryPictIndexValuesReply is a zero-copy view over a QueryPictIndexValues reply; offsets count from reply byte 0.
123+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
124+type QueryPictIndexValuesReply struct{ raw []byte }
125+
126+// ParseQueryPictIndexValuesReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
127+func ParseQueryPictIndexValuesReply(raw []byte) (QueryPictIndexValuesReply, bool) {
128+ if len(raw) < 32 {
129+ return QueryPictIndexValuesReply{}, false
130+ }
131+ r := QueryPictIndexValuesReply{raw: raw}
132+ off := 32
133+ {
134+ n := int(r.NumValues())
135+ if n < 0 || n > len(r.raw) {
136+ return QueryPictIndexValuesReply{}, false
137+ }
138+ off += n * 12
139+ }
140+ if off > len(r.raw) {
141+ return QueryPictIndexValuesReply{}, false
142+ }
143+ if off > len(r.raw) {
144+ return QueryPictIndexValuesReply{}, false
145+ }
146+ return r, true
147+}
148+func (r QueryPictIndexValuesReply) Raw() []byte { return r.raw }
149+func (r QueryPictIndexValuesReply) NumValues() uint32 {
150+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
151+}
152+func (r QueryPictIndexValuesReply) Values() IndexvalueList {
153+ off := 32
154+ end := off + (int(r.NumValues()))*12
155+ return IndexvalueList{b: r.raw[off:end:end]}
156+}
157+
158+// QueryFiltersReply is a zero-copy view over a QueryFilters reply; offsets count from reply byte 0.
159+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
160+type QueryFiltersReply struct{ raw []byte }
161+
162+// ParseQueryFiltersReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
163+func ParseQueryFiltersReply(raw []byte) (QueryFiltersReply, bool) {
164+ if len(raw) < 32 {
165+ return QueryFiltersReply{}, false
166+ }
167+ r := QueryFiltersReply{raw: raw}
168+ off := 32
169+ {
170+ n := int(r.NumAliases())
171+ if n < 0 || n > len(r.raw) {
172+ return QueryFiltersReply{}, false
173+ }
174+ off += n * 2
175+ }
176+ if off > len(r.raw) {
177+ return QueryFiltersReply{}, false
178+ }
179+ {
180+ n := int(r.NumFilters())
181+ if off > len(r.raw) || n < 0 || n > len(r.raw) {
182+ return QueryFiltersReply{}, false
183+ }
184+ it := xproto.NewStrIter(r.raw[off:], n)
185+ for it.Next() {
186+ off += it.Value().Size()
187+ }
188+ if it.Err() {
189+ return QueryFiltersReply{}, false
190+ }
191+ }
192+ if off > len(r.raw) {
193+ return QueryFiltersReply{}, false
194+ }
195+ return r, true
196+}
197+func (r QueryFiltersReply) Raw() []byte { return r.raw }
198+func (r QueryFiltersReply) NumAliases() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[8:])) }
199+func (r QueryFiltersReply) NumFilters() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[12:])) }
200+func (r QueryFiltersReply) Aliases() Uint16List {
201+ off := 32
202+ end := off + (int(r.NumAliases()))*2
203+ return Uint16List{b: r.raw[off:end:end]}
204+}
205+func (r QueryFiltersReply) Filters() xproto.StrIter {
206+ off := 32
207+ {
208+ n := int(r.NumAliases())
209+ off += n * 2
210+ }
211+ return xproto.NewStrIter(r.raw[off:], int(r.NumFilters()))
212+}
213+
214+// PictdepthView is a zero-copy view over one wire-encoded Pictdepth, yielded by PictdepthIter.
215+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
216+type PictdepthView struct{ raw []byte }
217+
218+func (v PictdepthView) Raw() []byte { return v.raw }
219+
220+// Size is the element's wire size, including trailing alignment.
221+func (v PictdepthView) Size() int { return len(v.raw) }
222+func sizePictdepth(p []byte) int {
223+ if len(p) < 8 {
224+ return -1
225+ }
226+ v := PictdepthView{raw: p}
227+ _ = v
228+ off := 8
229+ {
230+ n := int(v.NumVisuals())
231+ if n < 0 || n > len(v.raw) {
232+ return -1
233+ }
234+ off += n * 8
235+ }
236+ if off > len(v.raw) {
237+ return -1
238+ }
239+ if off > len(v.raw) {
240+ return -1
241+ }
242+ return off
243+}
244+func (v PictdepthView) Depth() uint8 { return uint8(v.raw[0:][0]) }
245+func (v PictdepthView) NumVisuals() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[2:])) }
246+func (v PictdepthView) Visuals() PictvisualList {
247+ off := 8
248+ end := off + (int(v.NumVisuals()))*8
249+ return PictvisualList{b: v.raw[off:end:end]}
250+}
251+
252+// PictdepthIter walks n consecutive Pictdepth elements; Err reports a malformed length.
253+// It shares the lifetime of the bytes it walks.
254+type PictdepthIter struct {
255+ b []byte
256+ n int
257+ v PictdepthView
258+ err bool
259+}
260+
261+// NewPictdepthIter iterates n elements encoded at the start of b.
262+func NewPictdepthIter(b []byte, n int) PictdepthIter { return PictdepthIter{b: b, n: n} }
263+func (it *PictdepthIter) Next() bool {
264+ if it.n <= 0 || it.err {
265+ return false
266+ }
267+ s := sizePictdepth(it.b)
268+ if s < 0 {
269+ it.err = true
270+ it.n = 0
271+ return false
272+ }
273+ it.v = PictdepthView{raw: it.b[:s:s]}
274+ it.b = it.b[s:]
275+ it.n--
276+ return true
277+}
278+func (it *PictdepthIter) Value() PictdepthView { return it.v }
279+func (it *PictdepthIter) Err() bool { return it.err }
280+
281+// PictscreenView is a zero-copy view over one wire-encoded Pictscreen, yielded by PictscreenIter.
282+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
283+type PictscreenView struct{ raw []byte }
284+
285+func (v PictscreenView) Raw() []byte { return v.raw }
286+
287+// Size is the element's wire size, including trailing alignment.
288+func (v PictscreenView) Size() int { return len(v.raw) }
289+func sizePictscreen(p []byte) int {
290+ if len(p) < 8 {
291+ return -1
292+ }
293+ v := PictscreenView{raw: p}
294+ _ = v
295+ off := 8
296+ {
297+ n := int(v.NumDepths())
298+ if off > len(v.raw) || n < 0 || n > len(v.raw) {
299+ return -1
300+ }
301+ it := NewPictdepthIter(v.raw[off:], n)
302+ for it.Next() {
303+ off += it.Value().Size()
304+ }
305+ if it.Err() {
306+ return -1
307+ }
308+ }
309+ if off > len(v.raw) {
310+ return -1
311+ }
312+ return off
313+}
314+func (v PictscreenView) NumDepths() uint32 { return uint32(binary.LittleEndian.Uint32(v.raw[0:])) }
315+func (v PictscreenView) Fallback() Pictformat {
316+ return Pictformat(binary.LittleEndian.Uint32(v.raw[4:]))
317+}
318+func (v PictscreenView) Depths() PictdepthIter {
319+ off := 8
320+ return NewPictdepthIter(v.raw[off:], int(v.NumDepths()))
321+}
322+
323+// PictscreenIter walks n consecutive Pictscreen elements; Err reports a malformed length.
324+// It shares the lifetime of the bytes it walks.
325+type PictscreenIter struct {
326+ b []byte
327+ n int
328+ v PictscreenView
329+ err bool
330+}
331+
332+// NewPictscreenIter iterates n elements encoded at the start of b.
333+func NewPictscreenIter(b []byte, n int) PictscreenIter { return PictscreenIter{b: b, n: n} }
334+func (it *PictscreenIter) Next() bool {
335+ if it.n <= 0 || it.err {
336+ return false
337+ }
338+ s := sizePictscreen(it.b)
339+ if s < 0 {
340+ it.err = true
341+ it.n = 0
342+ return false
343+ }
344+ it.v = PictscreenView{raw: it.b[:s:s]}
345+ it.b = it.b[s:]
346+ it.n--
347+ return true
348+}
349+func (it *PictscreenIter) Value() PictscreenView { return it.v }
350+func (it *PictscreenIter) Err() bool { return it.err }
351+
352+// IndexvalueList is a borrowed view over a wire list of Indexvalue. It shares the lifetime of the bytes it was taken from; copy what you keep.
353+type IndexvalueList struct{ b []byte }
354+
355+func (l IndexvalueList) Len() int { return len(l.b) / 12 }
356+func (l IndexvalueList) At(i int) Indexvalue { return GetIndexvalue(l.b[i*12:]) }
357+
358+// PictforminfoList is a borrowed view over a wire list of Pictforminfo. It shares the lifetime of the bytes it was taken from; copy what you keep.
359+type PictforminfoList struct{ b []byte }
360+
361+func (l PictforminfoList) Len() int { return len(l.b) / 28 }
362+func (l PictforminfoList) At(i int) Pictforminfo { return GetPictforminfo(l.b[i*28:]) }
363+
364+// PictvisualList is a borrowed view over a wire list of Pictvisual. It shares the lifetime of the bytes it was taken from; copy what you keep.
365+type PictvisualList struct{ b []byte }
366+
367+func (l PictvisualList) Len() int { return len(l.b) / 8 }
368+func (l PictvisualList) At(i int) Pictvisual { return GetPictvisual(l.b[i*8:]) }
369+
370+// SubPixelList is a borrowed view over a wire list of SubPixel. It shares the lifetime of the bytes it was taken from; copy what you keep.
371+type SubPixelList struct{ b []byte }
372+
373+func (l SubPixelList) Len() int { return len(l.b) / 4 }
374+func (l SubPixelList) At(i int) SubPixel { return SubPixel(binary.LittleEndian.Uint32(l.b[i*4:])) }
375+
376+// Uint16List is a borrowed view over a wire list of uint16. It shares the lifetime of the bytes it was taken from; copy what you keep.
377+type Uint16List struct{ b []byte }
378+
379+func (l Uint16List) Len() int { return len(l.b) / 2 }
380+func (l Uint16List) At(i int) uint16 { return uint16(binary.LittleEndian.Uint16(l.b[i*2:])) }
A render/requests_generated.go +1276 -0
@@ -0,0 +1,1276 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package render
3+
4+import "bnema.dev/xturbo/xproto"
5+import "encoding/binary"
6+import "math/bits"
7+import "bnema.dev/xturbo"
8+
9+func QueryVersion(b *xturbo.Buf, clientMajorVersion uint32, clientMinorVersion uint32) xturbo.Seq {
10+ if b.Ext == nil {
11+ b.Fail(xturbo.ErrExtMissing)
12+ return 0
13+ }
14+ major := b.Ext.Major(xturbo.ExtRender)
15+ if major == 0 {
16+ b.Fail(xturbo.ErrExtMissing)
17+ return 0
18+ }
19+ p, seq := b.Request(major, 0, 8)
20+ if p == nil {
21+ return 0
22+ }
23+ binary.LittleEndian.PutUint32(p[0:], uint32(clientMajorVersion))
24+ binary.LittleEndian.PutUint32(p[4:], uint32(clientMinorVersion))
25+ return seq
26+}
27+
28+func QueryPictFormats(b *xturbo.Buf) xturbo.Seq {
29+ if b.Ext == nil {
30+ b.Fail(xturbo.ErrExtMissing)
31+ return 0
32+ }
33+ major := b.Ext.Major(xturbo.ExtRender)
34+ if major == 0 {
35+ b.Fail(xturbo.ErrExtMissing)
36+ return 0
37+ }
38+ p, seq := b.Request(major, 1, 0)
39+ if p == nil {
40+ return 0
41+ }
42+ return seq
43+}
44+
45+func QueryPictIndexValues(b *xturbo.Buf, format Pictformat) xturbo.Seq {
46+ if b.Ext == nil {
47+ b.Fail(xturbo.ErrExtMissing)
48+ return 0
49+ }
50+ major := b.Ext.Major(xturbo.ExtRender)
51+ if major == 0 {
52+ b.Fail(xturbo.ErrExtMissing)
53+ return 0
54+ }
55+ p, seq := b.Request(major, 2, 4)
56+ if p == nil {
57+ return 0
58+ }
59+ binary.LittleEndian.PutUint32(p[0:], uint32(format))
60+ return seq
61+}
62+
63+type CreatePictureValues struct {
64+ Mask Cp
65+ Repeat Repeat
66+ Alphamap Picture
67+ Alphaxorigin int32
68+ Alphayorigin int32
69+ Clipxorigin int32
70+ Clipyorigin int32
71+ Clipmask xproto.Pixmap
72+ Graphicsexposure uint32
73+ Subwindowmode xproto.SubwindowMode
74+ Polyedge PolyEdge
75+ Polymode PolyMode
76+ Dither xproto.Atom
77+ Componentalpha uint32
78+}
79+
80+func (v *CreatePictureValues) SetRepeat(x Repeat) *CreatePictureValues {
81+ v.Mask |= CpRepeat
82+ v.Repeat = x
83+ return v
84+}
85+func (v *CreatePictureValues) SetAlphamap(x Picture) *CreatePictureValues {
86+ v.Mask |= CpAlphaMap
87+ v.Alphamap = x
88+ return v
89+}
90+func (v *CreatePictureValues) SetAlphaxorigin(x int32) *CreatePictureValues {
91+ v.Mask |= CpAlphaXOrigin
92+ v.Alphaxorigin = x
93+ return v
94+}
95+func (v *CreatePictureValues) SetAlphayorigin(x int32) *CreatePictureValues {
96+ v.Mask |= CpAlphaYOrigin
97+ v.Alphayorigin = x
98+ return v
99+}
100+func (v *CreatePictureValues) SetClipxorigin(x int32) *CreatePictureValues {
101+ v.Mask |= CpClipXOrigin
102+ v.Clipxorigin = x
103+ return v
104+}
105+func (v *CreatePictureValues) SetClipyorigin(x int32) *CreatePictureValues {
106+ v.Mask |= CpClipYOrigin
107+ v.Clipyorigin = x
108+ return v
109+}
110+func (v *CreatePictureValues) SetClipmask(x xproto.Pixmap) *CreatePictureValues {
111+ v.Mask |= CpClipMask
112+ v.Clipmask = x
113+ return v
114+}
115+func (v *CreatePictureValues) SetGraphicsexposure(x uint32) *CreatePictureValues {
116+ v.Mask |= CpGraphicsExposure
117+ v.Graphicsexposure = x
118+ return v
119+}
120+func (v *CreatePictureValues) SetSubwindowmode(x xproto.SubwindowMode) *CreatePictureValues {
121+ v.Mask |= CpSubwindowMode
122+ v.Subwindowmode = x
123+ return v
124+}
125+func (v *CreatePictureValues) SetPolyedge(x PolyEdge) *CreatePictureValues {
126+ v.Mask |= CpPolyEdge
127+ v.Polyedge = x
128+ return v
129+}
130+func (v *CreatePictureValues) SetPolymode(x PolyMode) *CreatePictureValues {
131+ v.Mask |= CpPolyMode
132+ v.Polymode = x
133+ return v
134+}
135+func (v *CreatePictureValues) SetDither(x xproto.Atom) *CreatePictureValues {
136+ v.Mask |= CpDither
137+ v.Dither = x
138+ return v
139+}
140+func (v *CreatePictureValues) SetComponentalpha(x uint32) *CreatePictureValues {
141+ v.Mask |= CpComponentAlpha
142+ v.Componentalpha = x
143+ return v
144+}
145+func CreatePicture(b *xturbo.Buf, pid Picture, drawable xproto.Drawable, format Pictformat, v *CreatePictureValues) xturbo.Seq {
146+ if b.Ext == nil {
147+ b.Fail(xturbo.ErrExtMissing)
148+ return 0
149+ }
150+ major := b.Ext.Major(xturbo.ExtRender)
151+ if major == 0 {
152+ b.Fail(xturbo.ErrExtMissing)
153+ return 0
154+ }
155+ p, seq := b.Request(major, 4, 16+4*bits.OnesCount32(uint32(v.Mask)))
156+ if p == nil {
157+ return 0
158+ }
159+ binary.LittleEndian.PutUint32(p[0:], uint32(pid))
160+ binary.LittleEndian.PutUint32(p[4:], uint32(drawable))
161+ binary.LittleEndian.PutUint32(p[8:], uint32(format))
162+ binary.LittleEndian.PutUint32(p[12:], uint32(v.Mask))
163+ off := 16
164+ if v.Mask&CpRepeat != 0 {
165+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Repeat))
166+ off += 4
167+ }
168+ if v.Mask&CpAlphaMap != 0 {
169+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Alphamap))
170+ off += 4
171+ }
172+ if v.Mask&CpAlphaXOrigin != 0 {
173+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Alphaxorigin))
174+ off += 4
175+ }
176+ if v.Mask&CpAlphaYOrigin != 0 {
177+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Alphayorigin))
178+ off += 4
179+ }
180+ if v.Mask&CpClipXOrigin != 0 {
181+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Clipxorigin))
182+ off += 4
183+ }
184+ if v.Mask&CpClipYOrigin != 0 {
185+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Clipyorigin))
186+ off += 4
187+ }
188+ if v.Mask&CpClipMask != 0 {
189+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Clipmask))
190+ off += 4
191+ }
192+ if v.Mask&CpGraphicsExposure != 0 {
193+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Graphicsexposure))
194+ off += 4
195+ }
196+ if v.Mask&CpSubwindowMode != 0 {
197+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Subwindowmode))
198+ off += 4
199+ }
200+ if v.Mask&CpPolyEdge != 0 {
201+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Polyedge))
202+ off += 4
203+ }
204+ if v.Mask&CpPolyMode != 0 {
205+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Polymode))
206+ off += 4
207+ }
208+ if v.Mask&CpDither != 0 {
209+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Dither))
210+ off += 4
211+ }
212+ if v.Mask&CpComponentAlpha != 0 {
213+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Componentalpha))
214+ off += 4
215+ }
216+ _ = off
217+ return seq
218+}
219+
220+type ChangePictureValues struct {
221+ Mask Cp
222+ Repeat Repeat
223+ Alphamap Picture
224+ Alphaxorigin int32
225+ Alphayorigin int32
226+ Clipxorigin int32
227+ Clipyorigin int32
228+ Clipmask xproto.Pixmap
229+ Graphicsexposure uint32
230+ Subwindowmode xproto.SubwindowMode
231+ Polyedge PolyEdge
232+ Polymode PolyMode
233+ Dither xproto.Atom
234+ Componentalpha uint32
235+}
236+
237+func (v *ChangePictureValues) SetRepeat(x Repeat) *ChangePictureValues {
238+ v.Mask |= CpRepeat
239+ v.Repeat = x
240+ return v
241+}
242+func (v *ChangePictureValues) SetAlphamap(x Picture) *ChangePictureValues {
243+ v.Mask |= CpAlphaMap
244+ v.Alphamap = x
245+ return v
246+}
247+func (v *ChangePictureValues) SetAlphaxorigin(x int32) *ChangePictureValues {
248+ v.Mask |= CpAlphaXOrigin
249+ v.Alphaxorigin = x
250+ return v
251+}
252+func (v *ChangePictureValues) SetAlphayorigin(x int32) *ChangePictureValues {
253+ v.Mask |= CpAlphaYOrigin
254+ v.Alphayorigin = x
255+ return v
256+}
257+func (v *ChangePictureValues) SetClipxorigin(x int32) *ChangePictureValues {
258+ v.Mask |= CpClipXOrigin
259+ v.Clipxorigin = x
260+ return v
261+}
262+func (v *ChangePictureValues) SetClipyorigin(x int32) *ChangePictureValues {
263+ v.Mask |= CpClipYOrigin
264+ v.Clipyorigin = x
265+ return v
266+}
267+func (v *ChangePictureValues) SetClipmask(x xproto.Pixmap) *ChangePictureValues {
268+ v.Mask |= CpClipMask
269+ v.Clipmask = x
270+ return v
271+}
272+func (v *ChangePictureValues) SetGraphicsexposure(x uint32) *ChangePictureValues {
273+ v.Mask |= CpGraphicsExposure
274+ v.Graphicsexposure = x
275+ return v
276+}
277+func (v *ChangePictureValues) SetSubwindowmode(x xproto.SubwindowMode) *ChangePictureValues {
278+ v.Mask |= CpSubwindowMode
279+ v.Subwindowmode = x
280+ return v
281+}
282+func (v *ChangePictureValues) SetPolyedge(x PolyEdge) *ChangePictureValues {
283+ v.Mask |= CpPolyEdge
284+ v.Polyedge = x
285+ return v
286+}
287+func (v *ChangePictureValues) SetPolymode(x PolyMode) *ChangePictureValues {
288+ v.Mask |= CpPolyMode
289+ v.Polymode = x
290+ return v
291+}
292+func (v *ChangePictureValues) SetDither(x xproto.Atom) *ChangePictureValues {
293+ v.Mask |= CpDither
294+ v.Dither = x
295+ return v
296+}
297+func (v *ChangePictureValues) SetComponentalpha(x uint32) *ChangePictureValues {
298+ v.Mask |= CpComponentAlpha
299+ v.Componentalpha = x
300+ return v
301+}
302+func ChangePicture(b *xturbo.Buf, picture Picture, v *ChangePictureValues) xturbo.Seq {
303+ if b.Ext == nil {
304+ b.Fail(xturbo.ErrExtMissing)
305+ return 0
306+ }
307+ major := b.Ext.Major(xturbo.ExtRender)
308+ if major == 0 {
309+ b.Fail(xturbo.ErrExtMissing)
310+ return 0
311+ }
312+ p, seq := b.Request(major, 5, 8+4*bits.OnesCount32(uint32(v.Mask)))
313+ if p == nil {
314+ return 0
315+ }
316+ binary.LittleEndian.PutUint32(p[0:], uint32(picture))
317+ binary.LittleEndian.PutUint32(p[4:], uint32(v.Mask))
318+ off := 8
319+ if v.Mask&CpRepeat != 0 {
320+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Repeat))
321+ off += 4
322+ }
323+ if v.Mask&CpAlphaMap != 0 {
324+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Alphamap))
325+ off += 4
326+ }
327+ if v.Mask&CpAlphaXOrigin != 0 {
328+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Alphaxorigin))
329+ off += 4
330+ }
331+ if v.Mask&CpAlphaYOrigin != 0 {
332+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Alphayorigin))
333+ off += 4
334+ }
335+ if v.Mask&CpClipXOrigin != 0 {
336+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Clipxorigin))
337+ off += 4
338+ }
339+ if v.Mask&CpClipYOrigin != 0 {
340+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Clipyorigin))
341+ off += 4
342+ }
343+ if v.Mask&CpClipMask != 0 {
344+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Clipmask))
345+ off += 4
346+ }
347+ if v.Mask&CpGraphicsExposure != 0 {
348+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Graphicsexposure))
349+ off += 4
350+ }
351+ if v.Mask&CpSubwindowMode != 0 {
352+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Subwindowmode))
353+ off += 4
354+ }
355+ if v.Mask&CpPolyEdge != 0 {
356+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Polyedge))
357+ off += 4
358+ }
359+ if v.Mask&CpPolyMode != 0 {
360+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Polymode))
361+ off += 4
362+ }
363+ if v.Mask&CpDither != 0 {
364+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Dither))
365+ off += 4
366+ }
367+ if v.Mask&CpComponentAlpha != 0 {
368+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Componentalpha))
369+ off += 4
370+ }
371+ _ = off
372+ return seq
373+}
374+
375+func SetPictureClipRectangles(b *xturbo.Buf, picture Picture, clipXOrigin int16, clipYOrigin int16, rectangles []xproto.Rectangle) xturbo.Seq {
376+ size := 0
377+ size += 4
378+ size += 2
379+ size += 2
380+ size += len(rectangles) * 8
381+ size = (size + 3) &^ 3
382+ if b.Ext == nil {
383+ b.Fail(xturbo.ErrExtMissing)
384+ return 0
385+ }
386+ major := b.Ext.Major(xturbo.ExtRender)
387+ if major == 0 {
388+ b.Fail(xturbo.ErrExtMissing)
389+ return 0
390+ }
391+ p, seq := b.Request(major, 6, size)
392+ if p == nil {
393+ return 0
394+ }
395+ off := 0
396+ binary.LittleEndian.PutUint32(p[off:], uint32(picture))
397+ off += 4
398+ binary.LittleEndian.PutUint16(p[off:], uint16(clipXOrigin))
399+ off += 2
400+ binary.LittleEndian.PutUint16(p[off:], uint16(clipYOrigin))
401+ off += 2
402+ for i := range rectangles {
403+ rectangles[i].Put(p[off:])
404+ off += 8
405+ }
406+ return seq
407+}
408+
409+func FreePicture(b *xturbo.Buf, picture Picture) xturbo.Seq {
410+ if b.Ext == nil {
411+ b.Fail(xturbo.ErrExtMissing)
412+ return 0
413+ }
414+ major := b.Ext.Major(xturbo.ExtRender)
415+ if major == 0 {
416+ b.Fail(xturbo.ErrExtMissing)
417+ return 0
418+ }
419+ p, seq := b.Request(major, 7, 4)
420+ if p == nil {
421+ return 0
422+ }
423+ binary.LittleEndian.PutUint32(p[0:], uint32(picture))
424+ return seq
425+}
426+
427+func Composite(b *xturbo.Buf, op PictOp, src Picture, mask Picture, dst Picture, srcX int16, srcY int16, maskX int16, maskY int16, dstX int16, dstY int16, width uint16, height uint16) xturbo.Seq {
428+ if b.Ext == nil {
429+ b.Fail(xturbo.ErrExtMissing)
430+ return 0
431+ }
432+ major := b.Ext.Major(xturbo.ExtRender)
433+ if major == 0 {
434+ b.Fail(xturbo.ErrExtMissing)
435+ return 0
436+ }
437+ p, seq := b.Request(major, 8, 32)
438+ if p == nil {
439+ return 0
440+ }
441+ p[0:][0] = byte(op)
442+ binary.LittleEndian.PutUint32(p[4:], uint32(src))
443+ binary.LittleEndian.PutUint32(p[8:], uint32(mask))
444+ binary.LittleEndian.PutUint32(p[12:], uint32(dst))
445+ binary.LittleEndian.PutUint16(p[16:], uint16(srcX))
446+ binary.LittleEndian.PutUint16(p[18:], uint16(srcY))
447+ binary.LittleEndian.PutUint16(p[20:], uint16(maskX))
448+ binary.LittleEndian.PutUint16(p[22:], uint16(maskY))
449+ binary.LittleEndian.PutUint16(p[24:], uint16(dstX))
450+ binary.LittleEndian.PutUint16(p[26:], uint16(dstY))
451+ binary.LittleEndian.PutUint16(p[28:], uint16(width))
452+ binary.LittleEndian.PutUint16(p[30:], uint16(height))
453+ return seq
454+}
455+
456+func Trapezoids(b *xturbo.Buf, op PictOp, src Picture, dst Picture, maskFormat Pictformat, srcX int16, srcY int16, traps []Trapezoid) xturbo.Seq {
457+ size := 0
458+ size += 1
459+ size += 3
460+ size += 4
461+ size += 4
462+ size += 4
463+ size += 2
464+ size += 2
465+ size += len(traps) * 40
466+ size = (size + 3) &^ 3
467+ if b.Ext == nil {
468+ b.Fail(xturbo.ErrExtMissing)
469+ return 0
470+ }
471+ major := b.Ext.Major(xturbo.ExtRender)
472+ if major == 0 {
473+ b.Fail(xturbo.ErrExtMissing)
474+ return 0
475+ }
476+ p, seq := b.Request(major, 10, size)
477+ if p == nil {
478+ return 0
479+ }
480+ off := 0
481+ p[off:][0] = byte(op)
482+ off += 1
483+ off += 3
484+ binary.LittleEndian.PutUint32(p[off:], uint32(src))
485+ off += 4
486+ binary.LittleEndian.PutUint32(p[off:], uint32(dst))
487+ off += 4
488+ binary.LittleEndian.PutUint32(p[off:], uint32(maskFormat))
489+ off += 4
490+ binary.LittleEndian.PutUint16(p[off:], uint16(srcX))
491+ off += 2
492+ binary.LittleEndian.PutUint16(p[off:], uint16(srcY))
493+ off += 2
494+ for i := range traps {
495+ traps[i].Put(p[off:])
496+ off += 40
497+ }
498+ return seq
499+}
500+
501+func Triangles(b *xturbo.Buf, op PictOp, src Picture, dst Picture, maskFormat Pictformat, srcX int16, srcY int16, triangles []Triangle) xturbo.Seq {
502+ size := 0
503+ size += 1
504+ size += 3
505+ size += 4
506+ size += 4
507+ size += 4
508+ size += 2
509+ size += 2
510+ size += len(triangles) * 24
511+ size = (size + 3) &^ 3
512+ if b.Ext == nil {
513+ b.Fail(xturbo.ErrExtMissing)
514+ return 0
515+ }
516+ major := b.Ext.Major(xturbo.ExtRender)
517+ if major == 0 {
518+ b.Fail(xturbo.ErrExtMissing)
519+ return 0
520+ }
521+ p, seq := b.Request(major, 11, size)
522+ if p == nil {
523+ return 0
524+ }
525+ off := 0
526+ p[off:][0] = byte(op)
527+ off += 1
528+ off += 3
529+ binary.LittleEndian.PutUint32(p[off:], uint32(src))
530+ off += 4
531+ binary.LittleEndian.PutUint32(p[off:], uint32(dst))
532+ off += 4
533+ binary.LittleEndian.PutUint32(p[off:], uint32(maskFormat))
534+ off += 4
535+ binary.LittleEndian.PutUint16(p[off:], uint16(srcX))
536+ off += 2
537+ binary.LittleEndian.PutUint16(p[off:], uint16(srcY))
538+ off += 2
539+ for i := range triangles {
540+ triangles[i].Put(p[off:])
541+ off += 24
542+ }
543+ return seq
544+}
545+
546+func TriStrip(b *xturbo.Buf, op PictOp, src Picture, dst Picture, maskFormat Pictformat, srcX int16, srcY int16, points []Pointfix) xturbo.Seq {
547+ size := 0
548+ size += 1
549+ size += 3
550+ size += 4
551+ size += 4
552+ size += 4
553+ size += 2
554+ size += 2
555+ size += len(points) * 8
556+ size = (size + 3) &^ 3
557+ if b.Ext == nil {
558+ b.Fail(xturbo.ErrExtMissing)
559+ return 0
560+ }
561+ major := b.Ext.Major(xturbo.ExtRender)
562+ if major == 0 {
563+ b.Fail(xturbo.ErrExtMissing)
564+ return 0
565+ }
566+ p, seq := b.Request(major, 12, size)
567+ if p == nil {
568+ return 0
569+ }
570+ off := 0
571+ p[off:][0] = byte(op)
572+ off += 1
573+ off += 3
574+ binary.LittleEndian.PutUint32(p[off:], uint32(src))
575+ off += 4
576+ binary.LittleEndian.PutUint32(p[off:], uint32(dst))
577+ off += 4
578+ binary.LittleEndian.PutUint32(p[off:], uint32(maskFormat))
579+ off += 4
580+ binary.LittleEndian.PutUint16(p[off:], uint16(srcX))
581+ off += 2
582+ binary.LittleEndian.PutUint16(p[off:], uint16(srcY))
583+ off += 2
584+ for i := range points {
585+ points[i].Put(p[off:])
586+ off += 8
587+ }
588+ return seq
589+}
590+
591+func TriFan(b *xturbo.Buf, op PictOp, src Picture, dst Picture, maskFormat Pictformat, srcX int16, srcY int16, points []Pointfix) xturbo.Seq {
592+ size := 0
593+ size += 1
594+ size += 3
595+ size += 4
596+ size += 4
597+ size += 4
598+ size += 2
599+ size += 2
600+ size += len(points) * 8
601+ size = (size + 3) &^ 3
602+ if b.Ext == nil {
603+ b.Fail(xturbo.ErrExtMissing)
604+ return 0
605+ }
606+ major := b.Ext.Major(xturbo.ExtRender)
607+ if major == 0 {
608+ b.Fail(xturbo.ErrExtMissing)
609+ return 0
610+ }
611+ p, seq := b.Request(major, 13, size)
612+ if p == nil {
613+ return 0
614+ }
615+ off := 0
616+ p[off:][0] = byte(op)
617+ off += 1
618+ off += 3
619+ binary.LittleEndian.PutUint32(p[off:], uint32(src))
620+ off += 4
621+ binary.LittleEndian.PutUint32(p[off:], uint32(dst))
622+ off += 4
623+ binary.LittleEndian.PutUint32(p[off:], uint32(maskFormat))
624+ off += 4
625+ binary.LittleEndian.PutUint16(p[off:], uint16(srcX))
626+ off += 2
627+ binary.LittleEndian.PutUint16(p[off:], uint16(srcY))
628+ off += 2
629+ for i := range points {
630+ points[i].Put(p[off:])
631+ off += 8
632+ }
633+ return seq
634+}
635+
636+func CreateGlyphSet(b *xturbo.Buf, gsid Glyphset, format Pictformat) xturbo.Seq {
637+ if b.Ext == nil {
638+ b.Fail(xturbo.ErrExtMissing)
639+ return 0
640+ }
641+ major := b.Ext.Major(xturbo.ExtRender)
642+ if major == 0 {
643+ b.Fail(xturbo.ErrExtMissing)
644+ return 0
645+ }
646+ p, seq := b.Request(major, 17, 8)
647+ if p == nil {
648+ return 0
649+ }
650+ binary.LittleEndian.PutUint32(p[0:], uint32(gsid))
651+ binary.LittleEndian.PutUint32(p[4:], uint32(format))
652+ return seq
653+}
654+
655+func ReferenceGlyphSet(b *xturbo.Buf, gsid Glyphset, existing Glyphset) xturbo.Seq {
656+ if b.Ext == nil {
657+ b.Fail(xturbo.ErrExtMissing)
658+ return 0
659+ }
660+ major := b.Ext.Major(xturbo.ExtRender)
661+ if major == 0 {
662+ b.Fail(xturbo.ErrExtMissing)
663+ return 0
664+ }
665+ p, seq := b.Request(major, 18, 8)
666+ if p == nil {
667+ return 0
668+ }
669+ binary.LittleEndian.PutUint32(p[0:], uint32(gsid))
670+ binary.LittleEndian.PutUint32(p[4:], uint32(existing))
671+ return seq
672+}
673+
674+func FreeGlyphSet(b *xturbo.Buf, glyphset Glyphset) xturbo.Seq {
675+ if b.Ext == nil {
676+ b.Fail(xturbo.ErrExtMissing)
677+ return 0
678+ }
679+ major := b.Ext.Major(xturbo.ExtRender)
680+ if major == 0 {
681+ b.Fail(xturbo.ErrExtMissing)
682+ return 0
683+ }
684+ p, seq := b.Request(major, 19, 4)
685+ if p == nil {
686+ return 0
687+ }
688+ binary.LittleEndian.PutUint32(p[0:], uint32(glyphset))
689+ return seq
690+}
691+
692+func AddGlyphs(b *xturbo.Buf, glyphset Glyphset, glyphsLen uint32, glyphids []uint32, glyphs []Glyphinfo, data []byte) xturbo.Seq {
693+ if len(glyphids) != int(glyphsLen) {
694+ b.Fail(xturbo.ErrBadLength)
695+ return 0
696+ }
697+ if len(glyphs) != int(glyphsLen) {
698+ b.Fail(xturbo.ErrBadLength)
699+ return 0
700+ }
701+ size := 0
702+ size += 4
703+ size += 4
704+ size += len(glyphids) * 4
705+ size += len(glyphs) * 12
706+ size += len(data) * 1
707+ size = (size + 3) &^ 3
708+ if b.Ext == nil {
709+ b.Fail(xturbo.ErrExtMissing)
710+ return 0
711+ }
712+ major := b.Ext.Major(xturbo.ExtRender)
713+ if major == 0 {
714+ b.Fail(xturbo.ErrExtMissing)
715+ return 0
716+ }
717+ p, seq := b.Request(major, 20, size)
718+ if p == nil {
719+ return 0
720+ }
721+ off := 0
722+ binary.LittleEndian.PutUint32(p[off:], uint32(glyphset))
723+ off += 4
724+ binary.LittleEndian.PutUint32(p[off:], uint32(glyphsLen))
725+ off += 4
726+ for i := range glyphids {
727+ binary.LittleEndian.PutUint32(p[off:], uint32(glyphids[i]))
728+ off += 4
729+ }
730+ for i := range glyphs {
731+ glyphs[i].Put(p[off:])
732+ off += 12
733+ }
734+ copy(p[off:], data)
735+ off += len(data)
736+ return seq
737+}
738+
739+func FreeGlyphs(b *xturbo.Buf, glyphset Glyphset, glyphs []Glyph) xturbo.Seq {
740+ size := 0
741+ size += 4
742+ size += len(glyphs) * 4
743+ size = (size + 3) &^ 3
744+ if b.Ext == nil {
745+ b.Fail(xturbo.ErrExtMissing)
746+ return 0
747+ }
748+ major := b.Ext.Major(xturbo.ExtRender)
749+ if major == 0 {
750+ b.Fail(xturbo.ErrExtMissing)
751+ return 0
752+ }
753+ p, seq := b.Request(major, 22, size)
754+ if p == nil {
755+ return 0
756+ }
757+ off := 0
758+ binary.LittleEndian.PutUint32(p[off:], uint32(glyphset))
759+ off += 4
760+ for i := range glyphs {
761+ binary.LittleEndian.PutUint32(p[off:], uint32(glyphs[i]))
762+ off += 4
763+ }
764+ return seq
765+}
766+
767+func CompositeGlyphs8(b *xturbo.Buf, op PictOp, src Picture, dst Picture, maskFormat Pictformat, glyphset Glyphset, srcX int16, srcY int16, glyphcmds []byte) xturbo.Seq {
768+ size := 0
769+ size += 1
770+ size += 3
771+ size += 4
772+ size += 4
773+ size += 4
774+ size += 4
775+ size += 2
776+ size += 2
777+ size += len(glyphcmds) * 1
778+ size = (size + 3) &^ 3
779+ if b.Ext == nil {
780+ b.Fail(xturbo.ErrExtMissing)
781+ return 0
782+ }
783+ major := b.Ext.Major(xturbo.ExtRender)
784+ if major == 0 {
785+ b.Fail(xturbo.ErrExtMissing)
786+ return 0
787+ }
788+ p, seq := b.Request(major, 23, size)
789+ if p == nil {
790+ return 0
791+ }
792+ off := 0
793+ p[off:][0] = byte(op)
794+ off += 1
795+ off += 3
796+ binary.LittleEndian.PutUint32(p[off:], uint32(src))
797+ off += 4
798+ binary.LittleEndian.PutUint32(p[off:], uint32(dst))
799+ off += 4
800+ binary.LittleEndian.PutUint32(p[off:], uint32(maskFormat))
801+ off += 4
802+ binary.LittleEndian.PutUint32(p[off:], uint32(glyphset))
803+ off += 4
804+ binary.LittleEndian.PutUint16(p[off:], uint16(srcX))
805+ off += 2
806+ binary.LittleEndian.PutUint16(p[off:], uint16(srcY))
807+ off += 2
808+ copy(p[off:], glyphcmds)
809+ off += len(glyphcmds)
810+ return seq
811+}
812+
813+func CompositeGlyphs16(b *xturbo.Buf, op PictOp, src Picture, dst Picture, maskFormat Pictformat, glyphset Glyphset, srcX int16, srcY int16, glyphcmds []byte) xturbo.Seq {
814+ size := 0
815+ size += 1
816+ size += 3
817+ size += 4
818+ size += 4
819+ size += 4
820+ size += 4
821+ size += 2
822+ size += 2
823+ size += len(glyphcmds) * 1
824+ size = (size + 3) &^ 3
825+ if b.Ext == nil {
826+ b.Fail(xturbo.ErrExtMissing)
827+ return 0
828+ }
829+ major := b.Ext.Major(xturbo.ExtRender)
830+ if major == 0 {
831+ b.Fail(xturbo.ErrExtMissing)
832+ return 0
833+ }
834+ p, seq := b.Request(major, 24, size)
835+ if p == nil {
836+ return 0
837+ }
838+ off := 0
839+ p[off:][0] = byte(op)
840+ off += 1
841+ off += 3
842+ binary.LittleEndian.PutUint32(p[off:], uint32(src))
843+ off += 4
844+ binary.LittleEndian.PutUint32(p[off:], uint32(dst))
845+ off += 4
846+ binary.LittleEndian.PutUint32(p[off:], uint32(maskFormat))
847+ off += 4
848+ binary.LittleEndian.PutUint32(p[off:], uint32(glyphset))
849+ off += 4
850+ binary.LittleEndian.PutUint16(p[off:], uint16(srcX))
851+ off += 2
852+ binary.LittleEndian.PutUint16(p[off:], uint16(srcY))
853+ off += 2
854+ copy(p[off:], glyphcmds)
855+ off += len(glyphcmds)
856+ return seq
857+}
858+
859+func CompositeGlyphs32(b *xturbo.Buf, op PictOp, src Picture, dst Picture, maskFormat Pictformat, glyphset Glyphset, srcX int16, srcY int16, glyphcmds []byte) xturbo.Seq {
860+ size := 0
861+ size += 1
862+ size += 3
863+ size += 4
864+ size += 4
865+ size += 4
866+ size += 4
867+ size += 2
868+ size += 2
869+ size += len(glyphcmds) * 1
870+ size = (size + 3) &^ 3
871+ if b.Ext == nil {
872+ b.Fail(xturbo.ErrExtMissing)
873+ return 0
874+ }
875+ major := b.Ext.Major(xturbo.ExtRender)
876+ if major == 0 {
877+ b.Fail(xturbo.ErrExtMissing)
878+ return 0
879+ }
880+ p, seq := b.Request(major, 25, size)
881+ if p == nil {
882+ return 0
883+ }
884+ off := 0
885+ p[off:][0] = byte(op)
886+ off += 1
887+ off += 3
888+ binary.LittleEndian.PutUint32(p[off:], uint32(src))
889+ off += 4
890+ binary.LittleEndian.PutUint32(p[off:], uint32(dst))
891+ off += 4
892+ binary.LittleEndian.PutUint32(p[off:], uint32(maskFormat))
893+ off += 4
894+ binary.LittleEndian.PutUint32(p[off:], uint32(glyphset))
895+ off += 4
896+ binary.LittleEndian.PutUint16(p[off:], uint16(srcX))
897+ off += 2
898+ binary.LittleEndian.PutUint16(p[off:], uint16(srcY))
899+ off += 2
900+ copy(p[off:], glyphcmds)
901+ off += len(glyphcmds)
902+ return seq
903+}
904+
905+func FillRectangles(b *xturbo.Buf, op PictOp, dst Picture, color Color, rects []xproto.Rectangle) xturbo.Seq {
906+ size := 0
907+ size += 1
908+ size += 3
909+ size += 4
910+ size += 8
911+ size += len(rects) * 8
912+ size = (size + 3) &^ 3
913+ if b.Ext == nil {
914+ b.Fail(xturbo.ErrExtMissing)
915+ return 0
916+ }
917+ major := b.Ext.Major(xturbo.ExtRender)
918+ if major == 0 {
919+ b.Fail(xturbo.ErrExtMissing)
920+ return 0
921+ }
922+ p, seq := b.Request(major, 26, size)
923+ if p == nil {
924+ return 0
925+ }
926+ off := 0
927+ p[off:][0] = byte(op)
928+ off += 1
929+ off += 3
930+ binary.LittleEndian.PutUint32(p[off:], uint32(dst))
931+ off += 4
932+ color.Put(p[off:])
933+ off += 8
934+ for i := range rects {
935+ rects[i].Put(p[off:])
936+ off += 8
937+ }
938+ return seq
939+}
940+
941+func CreateCursor(b *xturbo.Buf, cid xproto.Cursor, source Picture, x uint16, y uint16) xturbo.Seq {
942+ if b.Ext == nil {
943+ b.Fail(xturbo.ErrExtMissing)
944+ return 0
945+ }
946+ major := b.Ext.Major(xturbo.ExtRender)
947+ if major == 0 {
948+ b.Fail(xturbo.ErrExtMissing)
949+ return 0
950+ }
951+ p, seq := b.Request(major, 27, 12)
952+ if p == nil {
953+ return 0
954+ }
955+ binary.LittleEndian.PutUint32(p[0:], uint32(cid))
956+ binary.LittleEndian.PutUint32(p[4:], uint32(source))
957+ binary.LittleEndian.PutUint16(p[8:], uint16(x))
958+ binary.LittleEndian.PutUint16(p[10:], uint16(y))
959+ return seq
960+}
961+
962+func SetPictureTransform(b *xturbo.Buf, picture Picture, transform Transform) xturbo.Seq {
963+ if b.Ext == nil {
964+ b.Fail(xturbo.ErrExtMissing)
965+ return 0
966+ }
967+ major := b.Ext.Major(xturbo.ExtRender)
968+ if major == 0 {
969+ b.Fail(xturbo.ErrExtMissing)
970+ return 0
971+ }
972+ p, seq := b.Request(major, 28, 40)
973+ if p == nil {
974+ return 0
975+ }
976+ binary.LittleEndian.PutUint32(p[0:], uint32(picture))
977+ transform.Put(p[4:])
978+ return seq
979+}
980+
981+func QueryFilters(b *xturbo.Buf, drawable xproto.Drawable) xturbo.Seq {
982+ if b.Ext == nil {
983+ b.Fail(xturbo.ErrExtMissing)
984+ return 0
985+ }
986+ major := b.Ext.Major(xturbo.ExtRender)
987+ if major == 0 {
988+ b.Fail(xturbo.ErrExtMissing)
989+ return 0
990+ }
991+ p, seq := b.Request(major, 29, 4)
992+ if p == nil {
993+ return 0
994+ }
995+ binary.LittleEndian.PutUint32(p[0:], uint32(drawable))
996+ return seq
997+}
998+
999+func SetPictureFilter(b *xturbo.Buf, picture Picture, filter string, values []Fixed) xturbo.Seq {
1000+ if uint64(len(filter)) > 65535 {
1001+ b.Fail(xturbo.ErrBadLength)
1002+ return 0
1003+ }
1004+ size := 0
1005+ size += 4
1006+ size += 2
1007+ size += 2
1008+ size += len(filter) * 1
1009+ size = (size + 3) &^ 3
1010+ size += len(values) * 4
1011+ size = (size + 3) &^ 3
1012+ if b.Ext == nil {
1013+ b.Fail(xturbo.ErrExtMissing)
1014+ return 0
1015+ }
1016+ major := b.Ext.Major(xturbo.ExtRender)
1017+ if major == 0 {
1018+ b.Fail(xturbo.ErrExtMissing)
1019+ return 0
1020+ }
1021+ p, seq := b.Request(major, 30, size)
1022+ if p == nil {
1023+ return 0
1024+ }
1025+ off := 0
1026+ binary.LittleEndian.PutUint32(p[off:], uint32(picture))
1027+ off += 4
1028+ binary.LittleEndian.PutUint16(p[off:], uint16(len(filter)))
1029+ off += 2
1030+ off += 2
1031+ copy(p[off:], filter)
1032+ off += len(filter)
1033+ off = (off + 3) &^ 3
1034+ for i := range values {
1035+ binary.LittleEndian.PutUint32(p[off:], uint32(values[i]))
1036+ off += 4
1037+ }
1038+ return seq
1039+}
1040+
1041+func CreateAnimCursor(b *xturbo.Buf, cid xproto.Cursor, cursors []Animcursorelt) xturbo.Seq {
1042+ size := 0
1043+ size += 4
1044+ size += len(cursors) * 8
1045+ size = (size + 3) &^ 3
1046+ if b.Ext == nil {
1047+ b.Fail(xturbo.ErrExtMissing)
1048+ return 0
1049+ }
1050+ major := b.Ext.Major(xturbo.ExtRender)
1051+ if major == 0 {
1052+ b.Fail(xturbo.ErrExtMissing)
1053+ return 0
1054+ }
1055+ p, seq := b.Request(major, 31, size)
1056+ if p == nil {
1057+ return 0
1058+ }
1059+ off := 0
1060+ binary.LittleEndian.PutUint32(p[off:], uint32(cid))
1061+ off += 4
1062+ for i := range cursors {
1063+ cursors[i].Put(p[off:])
1064+ off += 8
1065+ }
1066+ return seq
1067+}
1068+
1069+func AddTraps(b *xturbo.Buf, picture Picture, xOff int16, yOff int16, traps []Trap) xturbo.Seq {
1070+ size := 0
1071+ size += 4
1072+ size += 2
1073+ size += 2
1074+ size += len(traps) * 24
1075+ size = (size + 3) &^ 3
1076+ if b.Ext == nil {
1077+ b.Fail(xturbo.ErrExtMissing)
1078+ return 0
1079+ }
1080+ major := b.Ext.Major(xturbo.ExtRender)
1081+ if major == 0 {
1082+ b.Fail(xturbo.ErrExtMissing)
1083+ return 0
1084+ }
1085+ p, seq := b.Request(major, 32, size)
1086+ if p == nil {
1087+ return 0
1088+ }
1089+ off := 0
1090+ binary.LittleEndian.PutUint32(p[off:], uint32(picture))
1091+ off += 4
1092+ binary.LittleEndian.PutUint16(p[off:], uint16(xOff))
1093+ off += 2
1094+ binary.LittleEndian.PutUint16(p[off:], uint16(yOff))
1095+ off += 2
1096+ for i := range traps {
1097+ traps[i].Put(p[off:])
1098+ off += 24
1099+ }
1100+ return seq
1101+}
1102+
1103+func CreateSolidFill(b *xturbo.Buf, picture Picture, color Color) xturbo.Seq {
1104+ if b.Ext == nil {
1105+ b.Fail(xturbo.ErrExtMissing)
1106+ return 0
1107+ }
1108+ major := b.Ext.Major(xturbo.ExtRender)
1109+ if major == 0 {
1110+ b.Fail(xturbo.ErrExtMissing)
1111+ return 0
1112+ }
1113+ p, seq := b.Request(major, 33, 12)
1114+ if p == nil {
1115+ return 0
1116+ }
1117+ binary.LittleEndian.PutUint32(p[0:], uint32(picture))
1118+ color.Put(p[4:])
1119+ return seq
1120+}
1121+
1122+func CreateLinearGradient(b *xturbo.Buf, picture Picture, p1 Pointfix, p2 Pointfix, numStops uint32, stops []Fixed, colors []Color) xturbo.Seq {
1123+ if len(stops) != int(numStops) {
1124+ b.Fail(xturbo.ErrBadLength)
1125+ return 0
1126+ }
1127+ if len(colors) != int(numStops) {
1128+ b.Fail(xturbo.ErrBadLength)
1129+ return 0
1130+ }
1131+ size := 0
1132+ size += 4
1133+ size += 8
1134+ size += 8
1135+ size += 4
1136+ size += len(stops) * 4
1137+ size += len(colors) * 8
1138+ size = (size + 3) &^ 3
1139+ if b.Ext == nil {
1140+ b.Fail(xturbo.ErrExtMissing)
1141+ return 0
1142+ }
1143+ major := b.Ext.Major(xturbo.ExtRender)
1144+ if major == 0 {
1145+ b.Fail(xturbo.ErrExtMissing)
1146+ return 0
1147+ }
1148+ p, seq := b.Request(major, 34, size)
1149+ if p == nil {
1150+ return 0
1151+ }
1152+ off := 0
1153+ binary.LittleEndian.PutUint32(p[off:], uint32(picture))
1154+ off += 4
1155+ p1.Put(p[off:])
1156+ off += 8
1157+ p2.Put(p[off:])
1158+ off += 8
1159+ binary.LittleEndian.PutUint32(p[off:], uint32(numStops))
1160+ off += 4
1161+ for i := range stops {
1162+ binary.LittleEndian.PutUint32(p[off:], uint32(stops[i]))
1163+ off += 4
1164+ }
1165+ for i := range colors {
1166+ colors[i].Put(p[off:])
1167+ off += 8
1168+ }
1169+ return seq
1170+}
1171+
1172+func CreateRadialGradient(b *xturbo.Buf, picture Picture, inner Pointfix, outer Pointfix, innerRadius Fixed, outerRadius Fixed, numStops uint32, stops []Fixed, colors []Color) xturbo.Seq {
1173+ if len(stops) != int(numStops) {
1174+ b.Fail(xturbo.ErrBadLength)
1175+ return 0
1176+ }
1177+ if len(colors) != int(numStops) {
1178+ b.Fail(xturbo.ErrBadLength)
1179+ return 0
1180+ }
1181+ size := 0
1182+ size += 4
1183+ size += 8
1184+ size += 8
1185+ size += 4
1186+ size += 4
1187+ size += 4
1188+ size += len(stops) * 4
1189+ size += len(colors) * 8
1190+ size = (size + 3) &^ 3
1191+ if b.Ext == nil {
1192+ b.Fail(xturbo.ErrExtMissing)
1193+ return 0
1194+ }
1195+ major := b.Ext.Major(xturbo.ExtRender)
1196+ if major == 0 {
1197+ b.Fail(xturbo.ErrExtMissing)
1198+ return 0
1199+ }
1200+ p, seq := b.Request(major, 35, size)
1201+ if p == nil {
1202+ return 0
1203+ }
1204+ off := 0
1205+ binary.LittleEndian.PutUint32(p[off:], uint32(picture))
1206+ off += 4
1207+ inner.Put(p[off:])
1208+ off += 8
1209+ outer.Put(p[off:])
1210+ off += 8
1211+ binary.LittleEndian.PutUint32(p[off:], uint32(innerRadius))
1212+ off += 4
1213+ binary.LittleEndian.PutUint32(p[off:], uint32(outerRadius))
1214+ off += 4
1215+ binary.LittleEndian.PutUint32(p[off:], uint32(numStops))
1216+ off += 4
1217+ for i := range stops {
1218+ binary.LittleEndian.PutUint32(p[off:], uint32(stops[i]))
1219+ off += 4
1220+ }
1221+ for i := range colors {
1222+ colors[i].Put(p[off:])
1223+ off += 8
1224+ }
1225+ return seq
1226+}
1227+
1228+func CreateConicalGradient(b *xturbo.Buf, picture Picture, center Pointfix, angle Fixed, numStops uint32, stops []Fixed, colors []Color) xturbo.Seq {
1229+ if len(stops) != int(numStops) {
1230+ b.Fail(xturbo.ErrBadLength)
1231+ return 0
1232+ }
1233+ if len(colors) != int(numStops) {
1234+ b.Fail(xturbo.ErrBadLength)
1235+ return 0
1236+ }
1237+ size := 0
1238+ size += 4
1239+ size += 8
1240+ size += 4
1241+ size += 4
1242+ size += len(stops) * 4
1243+ size += len(colors) * 8
1244+ size = (size + 3) &^ 3
1245+ if b.Ext == nil {
1246+ b.Fail(xturbo.ErrExtMissing)
1247+ return 0
1248+ }
1249+ major := b.Ext.Major(xturbo.ExtRender)
1250+ if major == 0 {
1251+ b.Fail(xturbo.ErrExtMissing)
1252+ return 0
1253+ }
1254+ p, seq := b.Request(major, 36, size)
1255+ if p == nil {
1256+ return 0
1257+ }
1258+ off := 0
1259+ binary.LittleEndian.PutUint32(p[off:], uint32(picture))
1260+ off += 4
1261+ center.Put(p[off:])
1262+ off += 8
1263+ binary.LittleEndian.PutUint32(p[off:], uint32(angle))
1264+ off += 4
1265+ binary.LittleEndian.PutUint32(p[off:], uint32(numStops))
1266+ off += 4
1267+ for i := range stops {
1268+ binary.LittleEndian.PutUint32(p[off:], uint32(stops[i]))
1269+ off += 4
1270+ }
1271+ for i := range colors {
1272+ colors[i].Put(p[off:])
1273+ off += 8
1274+ }
1275+ return seq
1276+}
A render/sizes_test.go +68 -0
@@ -0,0 +1,68 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package render
3+
4+import "testing"
5+
6+func TestWireSizes(t *testing.T) {
7+ if DirectformatSize != 16 {
8+ t.Errorf("Directformat fixed prefix = %d", DirectformatSize)
9+ }
10+ if PictforminfoSize != 28 {
11+ t.Errorf("Pictforminfo fixed prefix = %d", PictforminfoSize)
12+ }
13+ if PictvisualSize != 8 {
14+ t.Errorf("Pictvisual fixed prefix = %d", PictvisualSize)
15+ }
16+ if PictdepthSize != 8 {
17+ t.Errorf("Pictdepth fixed prefix = %d", PictdepthSize)
18+ }
19+ if PictscreenSize != 8 {
20+ t.Errorf("Pictscreen fixed prefix = %d", PictscreenSize)
21+ }
22+ if IndexvalueSize != 12 {
23+ t.Errorf("Indexvalue fixed prefix = %d", IndexvalueSize)
24+ }
25+ if ColorSize != 8 {
26+ t.Errorf("Color fixed prefix = %d", ColorSize)
27+ }
28+ if PointfixSize != 8 {
29+ t.Errorf("Pointfix fixed prefix = %d", PointfixSize)
30+ }
31+ if LinefixSize != 16 {
32+ t.Errorf("Linefix fixed prefix = %d", LinefixSize)
33+ }
34+ if TriangleSize != 24 {
35+ t.Errorf("Triangle fixed prefix = %d", TriangleSize)
36+ }
37+ if TrapezoidSize != 40 {
38+ t.Errorf("Trapezoid fixed prefix = %d", TrapezoidSize)
39+ }
40+ if GlyphinfoSize != 12 {
41+ t.Errorf("Glyphinfo fixed prefix = %d", GlyphinfoSize)
42+ }
43+ if TransformSize != 36 {
44+ t.Errorf("Transform fixed prefix = %d", TransformSize)
45+ }
46+ if AnimcursoreltSize != 8 {
47+ t.Errorf("Animcursorelt fixed prefix = %d", AnimcursoreltSize)
48+ }
49+ if SpanfixSize != 12 {
50+ t.Errorf("Spanfix fixed prefix = %d", SpanfixSize)
51+ }
52+ if TrapSize != 24 {
53+ t.Errorf("Trap fixed prefix = %d", TrapSize)
54+ }
55+ if got := 32; got != 32 {
56+ t.Errorf("reply QueryVersion fixed size = %d", got)
57+ }
58+ if got := 32; got != 32 {
59+ t.Errorf("reply QueryPictFormats fixed size = %d", got)
60+ }
61+ if got := 32; got != 32 {
62+ t.Errorf("reply QueryPictIndexValues fixed size = %d", got)
63+ }
64+ if got := 32; got != 32 {
65+ t.Errorf("reply QueryFilters fixed size = %d", got)
66+ }
67+
68+}
A render/types_generated.go +522 -0
@@ -0,0 +1,522 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package render
3+
4+import "bnema.dev/xturbo/xproto"
5+import "encoding/binary"
6+
7+type Glyph uint32
8+
9+type Glyphset uint32
10+
11+type Picture uint32
12+
13+type Pictformat uint32
14+
15+type Fixed int32
16+
17+type Directformat struct {
18+ RedShift uint16
19+ RedMask uint16
20+ GreenShift uint16
21+ GreenMask uint16
22+ BlueShift uint16
23+ BlueMask uint16
24+ AlphaShift uint16
25+ AlphaMask uint16
26+}
27+
28+const DirectformatSize = 16
29+
30+func (v Directformat) Put(p []byte) {
31+ clear(p[:16])
32+ binary.LittleEndian.PutUint16(p[0:], uint16(v.RedShift))
33+ binary.LittleEndian.PutUint16(p[2:], uint16(v.RedMask))
34+ binary.LittleEndian.PutUint16(p[4:], uint16(v.GreenShift))
35+ binary.LittleEndian.PutUint16(p[6:], uint16(v.GreenMask))
36+ binary.LittleEndian.PutUint16(p[8:], uint16(v.BlueShift))
37+ binary.LittleEndian.PutUint16(p[10:], uint16(v.BlueMask))
38+ binary.LittleEndian.PutUint16(p[12:], uint16(v.AlphaShift))
39+ binary.LittleEndian.PutUint16(p[14:], uint16(v.AlphaMask))
40+}
41+func GetDirectformat(p []byte) (v Directformat) {
42+ _ = p[15]
43+ v.RedShift = uint16(binary.LittleEndian.Uint16(p[0:]))
44+ v.RedMask = uint16(binary.LittleEndian.Uint16(p[2:]))
45+ v.GreenShift = uint16(binary.LittleEndian.Uint16(p[4:]))
46+ v.GreenMask = uint16(binary.LittleEndian.Uint16(p[6:]))
47+ v.BlueShift = uint16(binary.LittleEndian.Uint16(p[8:]))
48+ v.BlueMask = uint16(binary.LittleEndian.Uint16(p[10:]))
49+ v.AlphaShift = uint16(binary.LittleEndian.Uint16(p[12:]))
50+ v.AlphaMask = uint16(binary.LittleEndian.Uint16(p[14:]))
51+ return
52+}
53+
54+type Pictforminfo struct {
55+ Id Pictformat
56+ Type PictType
57+ Depth uint8
58+ Direct Directformat
59+ Colormap xproto.Colormap
60+}
61+
62+const PictforminfoSize = 28
63+
64+func (v Pictforminfo) Put(p []byte) {
65+ clear(p[:28])
66+ binary.LittleEndian.PutUint32(p[0:], uint32(v.Id))
67+ p[4:][0] = byte(v.Type)
68+ p[5:][0] = byte(v.Depth)
69+ v.Direct.Put(p[8:])
70+ binary.LittleEndian.PutUint32(p[24:], uint32(v.Colormap))
71+}
72+func GetPictforminfo(p []byte) (v Pictforminfo) {
73+ _ = p[27]
74+ v.Id = Pictformat(binary.LittleEndian.Uint32(p[0:]))
75+ v.Type = PictType(p[4:][0])
76+ v.Depth = uint8(p[5:][0])
77+ v.Direct = GetDirectformat(p[8:])
78+ v.Colormap = xproto.Colormap(binary.LittleEndian.Uint32(p[24:]))
79+ return
80+}
81+
82+type Pictvisual struct {
83+ Visual xproto.Visualid
84+ Format Pictformat
85+}
86+
87+const PictvisualSize = 8
88+
89+func (v Pictvisual) Put(p []byte) {
90+ clear(p[:8])
91+ binary.LittleEndian.PutUint32(p[0:], uint32(v.Visual))
92+ binary.LittleEndian.PutUint32(p[4:], uint32(v.Format))
93+}
94+func GetPictvisual(p []byte) (v Pictvisual) {
95+ _ = p[7]
96+ v.Visual = xproto.Visualid(binary.LittleEndian.Uint32(p[0:]))
97+ v.Format = Pictformat(binary.LittleEndian.Uint32(p[4:]))
98+ return
99+}
100+
101+type Pictdepth struct {
102+ Depth uint8
103+ NumVisuals uint16
104+ Visuals []Pictvisual
105+}
106+
107+const PictdepthSize = 8
108+
109+func (v Pictdepth) Size() int {
110+ off := 0
111+ off += 1
112+ off += 1
113+ off += 2
114+ off += 4
115+ off += len(v.Visuals) * 8
116+ return off
117+}
118+func (v Pictdepth) Put(p []byte) {
119+ off := 0
120+ p[off:][0] = byte(v.Depth)
121+ off += 1
122+ clear(p[off : off+1])
123+ off += 1
124+ binary.LittleEndian.PutUint16(p[off:], uint16(v.NumVisuals))
125+ off += 2
126+ clear(p[off : off+4])
127+ off += 4
128+ for i := range v.Visuals {
129+ v.Visuals[i].Put(p[off+i*8:])
130+ }
131+ off += len(v.Visuals) * 8
132+}
133+
134+type Pictscreen struct {
135+ NumDepths uint32
136+ Fallback Pictformat
137+ Depths []Pictdepth
138+}
139+
140+const PictscreenSize = 8
141+
142+func (v Pictscreen) Size() int {
143+ off := 0
144+ off += 4
145+ off += 4
146+ for i := range v.Depths {
147+ off += v.Depths[i].Size()
148+ }
149+ return off
150+}
151+func (v Pictscreen) Put(p []byte) {
152+ off := 0
153+ binary.LittleEndian.PutUint32(p[off:], uint32(v.NumDepths))
154+ off += 4
155+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Fallback))
156+ off += 4
157+ for i := range v.Depths {
158+ v.Depths[i].Put(p[off:])
159+ off += v.Depths[i].Size()
160+ }
161+}
162+
163+type Indexvalue struct {
164+ Pixel uint32
165+ Red uint16
166+ Green uint16
167+ Blue uint16
168+ Alpha uint16
169+}
170+
171+const IndexvalueSize = 12
172+
173+func (v Indexvalue) Put(p []byte) {
174+ clear(p[:12])
175+ binary.LittleEndian.PutUint32(p[0:], uint32(v.Pixel))
176+ binary.LittleEndian.PutUint16(p[4:], uint16(v.Red))
177+ binary.LittleEndian.PutUint16(p[6:], uint16(v.Green))
178+ binary.LittleEndian.PutUint16(p[8:], uint16(v.Blue))
179+ binary.LittleEndian.PutUint16(p[10:], uint16(v.Alpha))
180+}
181+func GetIndexvalue(p []byte) (v Indexvalue) {
182+ _ = p[11]
183+ v.Pixel = uint32(binary.LittleEndian.Uint32(p[0:]))
184+ v.Red = uint16(binary.LittleEndian.Uint16(p[4:]))
185+ v.Green = uint16(binary.LittleEndian.Uint16(p[6:]))
186+ v.Blue = uint16(binary.LittleEndian.Uint16(p[8:]))
187+ v.Alpha = uint16(binary.LittleEndian.Uint16(p[10:]))
188+ return
189+}
190+
191+type Color struct {
192+ Red uint16
193+ Green uint16
194+ Blue uint16
195+ Alpha uint16
196+}
197+
198+const ColorSize = 8
199+
200+func (v Color) Put(p []byte) {
201+ clear(p[:8])
202+ binary.LittleEndian.PutUint16(p[0:], uint16(v.Red))
203+ binary.LittleEndian.PutUint16(p[2:], uint16(v.Green))
204+ binary.LittleEndian.PutUint16(p[4:], uint16(v.Blue))
205+ binary.LittleEndian.PutUint16(p[6:], uint16(v.Alpha))
206+}
207+func GetColor(p []byte) (v Color) {
208+ _ = p[7]
209+ v.Red = uint16(binary.LittleEndian.Uint16(p[0:]))
210+ v.Green = uint16(binary.LittleEndian.Uint16(p[2:]))
211+ v.Blue = uint16(binary.LittleEndian.Uint16(p[4:]))
212+ v.Alpha = uint16(binary.LittleEndian.Uint16(p[6:]))
213+ return
214+}
215+
216+type Pointfix struct {
217+ X Fixed
218+ Y Fixed
219+}
220+
221+const PointfixSize = 8
222+
223+func (v Pointfix) Put(p []byte) {
224+ clear(p[:8])
225+ binary.LittleEndian.PutUint32(p[0:], uint32(v.X))
226+ binary.LittleEndian.PutUint32(p[4:], uint32(v.Y))
227+}
228+func GetPointfix(p []byte) (v Pointfix) {
229+ _ = p[7]
230+ v.X = Fixed(binary.LittleEndian.Uint32(p[0:]))
231+ v.Y = Fixed(binary.LittleEndian.Uint32(p[4:]))
232+ return
233+}
234+
235+type Linefix struct {
236+ P1 Pointfix
237+ P2 Pointfix
238+}
239+
240+const LinefixSize = 16
241+
242+func (v Linefix) Put(p []byte) { clear(p[:16]); v.P1.Put(p[0:]); v.P2.Put(p[8:]) }
243+func GetLinefix(p []byte) (v Linefix) {
244+ _ = p[15]
245+ v.P1 = GetPointfix(p[0:])
246+ v.P2 = GetPointfix(p[8:])
247+ return
248+}
249+
250+type Triangle struct {
251+ P1 Pointfix
252+ P2 Pointfix
253+ P3 Pointfix
254+}
255+
256+const TriangleSize = 24
257+
258+func (v Triangle) Put(p []byte) { clear(p[:24]); v.P1.Put(p[0:]); v.P2.Put(p[8:]); v.P3.Put(p[16:]) }
259+func GetTriangle(p []byte) (v Triangle) {
260+ _ = p[23]
261+ v.P1 = GetPointfix(p[0:])
262+ v.P2 = GetPointfix(p[8:])
263+ v.P3 = GetPointfix(p[16:])
264+ return
265+}
266+
267+type Trapezoid struct {
268+ Top Fixed
269+ Bottom Fixed
270+ Left Linefix
271+ Right Linefix
272+}
273+
274+const TrapezoidSize = 40
275+
276+func (v Trapezoid) Put(p []byte) {
277+ clear(p[:40])
278+ binary.LittleEndian.PutUint32(p[0:], uint32(v.Top))
279+ binary.LittleEndian.PutUint32(p[4:], uint32(v.Bottom))
280+ v.Left.Put(p[8:])
281+ v.Right.Put(p[24:])
282+}
283+func GetTrapezoid(p []byte) (v Trapezoid) {
284+ _ = p[39]
285+ v.Top = Fixed(binary.LittleEndian.Uint32(p[0:]))
286+ v.Bottom = Fixed(binary.LittleEndian.Uint32(p[4:]))
287+ v.Left = GetLinefix(p[8:])
288+ v.Right = GetLinefix(p[24:])
289+ return
290+}
291+
292+type Glyphinfo struct {
293+ Width uint16
294+ Height uint16
295+ X int16
296+ Y int16
297+ XOff int16
298+ YOff int16
299+}
300+
301+const GlyphinfoSize = 12
302+
303+func (v Glyphinfo) Put(p []byte) {
304+ clear(p[:12])
305+ binary.LittleEndian.PutUint16(p[0:], uint16(v.Width))
306+ binary.LittleEndian.PutUint16(p[2:], uint16(v.Height))
307+ binary.LittleEndian.PutUint16(p[4:], uint16(v.X))
308+ binary.LittleEndian.PutUint16(p[6:], uint16(v.Y))
309+ binary.LittleEndian.PutUint16(p[8:], uint16(v.XOff))
310+ binary.LittleEndian.PutUint16(p[10:], uint16(v.YOff))
311+}
312+func GetGlyphinfo(p []byte) (v Glyphinfo) {
313+ _ = p[11]
314+ v.Width = uint16(binary.LittleEndian.Uint16(p[0:]))
315+ v.Height = uint16(binary.LittleEndian.Uint16(p[2:]))
316+ v.X = int16(binary.LittleEndian.Uint16(p[4:]))
317+ v.Y = int16(binary.LittleEndian.Uint16(p[6:]))
318+ v.XOff = int16(binary.LittleEndian.Uint16(p[8:]))
319+ v.YOff = int16(binary.LittleEndian.Uint16(p[10:]))
320+ return
321+}
322+
323+type Transform struct {
324+ Matrix11 Fixed
325+ Matrix12 Fixed
326+ Matrix13 Fixed
327+ Matrix21 Fixed
328+ Matrix22 Fixed
329+ Matrix23 Fixed
330+ Matrix31 Fixed
331+ Matrix32 Fixed
332+ Matrix33 Fixed
333+}
334+
335+const TransformSize = 36
336+
337+func (v Transform) Put(p []byte) {
338+ clear(p[:36])
339+ binary.LittleEndian.PutUint32(p[0:], uint32(v.Matrix11))
340+ binary.LittleEndian.PutUint32(p[4:], uint32(v.Matrix12))
341+ binary.LittleEndian.PutUint32(p[8:], uint32(v.Matrix13))
342+ binary.LittleEndian.PutUint32(p[12:], uint32(v.Matrix21))
343+ binary.LittleEndian.PutUint32(p[16:], uint32(v.Matrix22))
344+ binary.LittleEndian.PutUint32(p[20:], uint32(v.Matrix23))
345+ binary.LittleEndian.PutUint32(p[24:], uint32(v.Matrix31))
346+ binary.LittleEndian.PutUint32(p[28:], uint32(v.Matrix32))
347+ binary.LittleEndian.PutUint32(p[32:], uint32(v.Matrix33))
348+}
349+func GetTransform(p []byte) (v Transform) {
350+ _ = p[35]
351+ v.Matrix11 = Fixed(binary.LittleEndian.Uint32(p[0:]))
352+ v.Matrix12 = Fixed(binary.LittleEndian.Uint32(p[4:]))
353+ v.Matrix13 = Fixed(binary.LittleEndian.Uint32(p[8:]))
354+ v.Matrix21 = Fixed(binary.LittleEndian.Uint32(p[12:]))
355+ v.Matrix22 = Fixed(binary.LittleEndian.Uint32(p[16:]))
356+ v.Matrix23 = Fixed(binary.LittleEndian.Uint32(p[20:]))
357+ v.Matrix31 = Fixed(binary.LittleEndian.Uint32(p[24:]))
358+ v.Matrix32 = Fixed(binary.LittleEndian.Uint32(p[28:]))
359+ v.Matrix33 = Fixed(binary.LittleEndian.Uint32(p[32:]))
360+ return
361+}
362+
363+type Animcursorelt struct {
364+ Cursor xproto.Cursor
365+ Delay uint32
366+}
367+
368+const AnimcursoreltSize = 8
369+
370+func (v Animcursorelt) Put(p []byte) {
371+ clear(p[:8])
372+ binary.LittleEndian.PutUint32(p[0:], uint32(v.Cursor))
373+ binary.LittleEndian.PutUint32(p[4:], uint32(v.Delay))
374+}
375+func GetAnimcursorelt(p []byte) (v Animcursorelt) {
376+ _ = p[7]
377+ v.Cursor = xproto.Cursor(binary.LittleEndian.Uint32(p[0:]))
378+ v.Delay = uint32(binary.LittleEndian.Uint32(p[4:]))
379+ return
380+}
381+
382+type Spanfix struct {
383+ L Fixed
384+ R Fixed
385+ Y Fixed
386+}
387+
388+const SpanfixSize = 12
389+
390+func (v Spanfix) Put(p []byte) {
391+ clear(p[:12])
392+ binary.LittleEndian.PutUint32(p[0:], uint32(v.L))
393+ binary.LittleEndian.PutUint32(p[4:], uint32(v.R))
394+ binary.LittleEndian.PutUint32(p[8:], uint32(v.Y))
395+}
396+func GetSpanfix(p []byte) (v Spanfix) {
397+ _ = p[11]
398+ v.L = Fixed(binary.LittleEndian.Uint32(p[0:]))
399+ v.R = Fixed(binary.LittleEndian.Uint32(p[4:]))
400+ v.Y = Fixed(binary.LittleEndian.Uint32(p[8:]))
401+ return
402+}
403+
404+type Trap struct {
405+ Top Spanfix
406+ Bot Spanfix
407+}
408+
409+const TrapSize = 24
410+
411+func (v Trap) Put(p []byte) { clear(p[:24]); v.Top.Put(p[0:]); v.Bot.Put(p[12:]) }
412+func GetTrap(p []byte) (v Trap) {
413+ _ = p[23]
414+ v.Top = GetSpanfix(p[0:])
415+ v.Bot = GetSpanfix(p[12:])
416+ return
417+}
418+
419+type PictType uint8
420+
421+const PictTypeIndexed PictType = 0
422+const PictTypeDirect PictType = 1
423+
424+const PictureNone Picture = 0
425+
426+type PictOp uint8
427+
428+const PictOpClear PictOp = 0
429+const PictOpSrc PictOp = 1
430+const PictOpDst PictOp = 2
431+const PictOpOver PictOp = 3
432+const PictOpOverReverse PictOp = 4
433+const PictOpIn PictOp = 5
434+const PictOpInReverse PictOp = 6
435+const PictOpOut PictOp = 7
436+const PictOpOutReverse PictOp = 8
437+const PictOpAtop PictOp = 9
438+const PictOpAtopReverse PictOp = 10
439+const PictOpXor PictOp = 11
440+const PictOpAdd PictOp = 12
441+const PictOpSaturate PictOp = 13
442+const PictOpDisjointClear PictOp = 16
443+const PictOpDisjointSrc PictOp = 17
444+const PictOpDisjointDst PictOp = 18
445+const PictOpDisjointOver PictOp = 19
446+const PictOpDisjointOverReverse PictOp = 20
447+const PictOpDisjointIn PictOp = 21
448+const PictOpDisjointInReverse PictOp = 22
449+const PictOpDisjointOut PictOp = 23
450+const PictOpDisjointOutReverse PictOp = 24
451+const PictOpDisjointAtop PictOp = 25
452+const PictOpDisjointAtopReverse PictOp = 26
453+const PictOpDisjointXor PictOp = 27
454+const PictOpConjointClear PictOp = 32
455+const PictOpConjointSrc PictOp = 33
456+const PictOpConjointDst PictOp = 34
457+const PictOpConjointOver PictOp = 35
458+const PictOpConjointOverReverse PictOp = 36
459+const PictOpConjointIn PictOp = 37
460+const PictOpConjointInReverse PictOp = 38
461+const PictOpConjointOut PictOp = 39
462+const PictOpConjointOutReverse PictOp = 40
463+const PictOpConjointAtop PictOp = 41
464+const PictOpConjointAtopReverse PictOp = 42
465+const PictOpConjointXor PictOp = 43
466+const PictOpMultiply PictOp = 48
467+const PictOpScreen PictOp = 49
468+const PictOpOverlay PictOp = 50
469+const PictOpDarken PictOp = 51
470+const PictOpLighten PictOp = 52
471+const PictOpColorDodge PictOp = 53
472+const PictOpColorBurn PictOp = 54
473+const PictOpHardLight PictOp = 55
474+const PictOpSoftLight PictOp = 56
475+const PictOpDifference PictOp = 57
476+const PictOpExclusion PictOp = 58
477+const PictOpHSLHue PictOp = 59
478+const PictOpHSLSaturation PictOp = 60
479+const PictOpHSLColor PictOp = 61
480+const PictOpHSLLuminosity PictOp = 62
481+
482+type PolyEdge uint32
483+
484+const PolyEdgeSharp PolyEdge = 0
485+const PolyEdgeSmooth PolyEdge = 1
486+
487+type PolyMode uint32
488+
489+const PolyModePrecise PolyMode = 0
490+const PolyModeImprecise PolyMode = 1
491+
492+type Cp uint32
493+
494+const CpRepeat Cp = 1
495+const CpAlphaMap Cp = 2
496+const CpAlphaXOrigin Cp = 4
497+const CpAlphaYOrigin Cp = 8
498+const CpClipXOrigin Cp = 16
499+const CpClipYOrigin Cp = 32
500+const CpClipMask Cp = 64
501+const CpGraphicsExposure Cp = 128
502+const CpSubwindowMode Cp = 256
503+const CpPolyEdge Cp = 512
504+const CpPolyMode Cp = 1024
505+const CpDither Cp = 2048
506+const CpComponentAlpha Cp = 4096
507+
508+type SubPixel uint32
509+
510+const SubPixelUnknown SubPixel = 0
511+const SubPixelHorizontalRGB SubPixel = 1
512+const SubPixelHorizontalBGR SubPixel = 2
513+const SubPixelVerticalRGB SubPixel = 3
514+const SubPixelVerticalBGR SubPixel = 4
515+const SubPixelNone SubPixel = 5
516+
517+type Repeat uint32
518+
519+const RepeatNone Repeat = 0
520+const RepeatNormal Repeat = 1
521+const RepeatPad Repeat = 2
522+const RepeatReflect Repeat = 3
A replies_test.go +304 -0
@@ -0,0 +1,304 @@
1+package xturbo_test
2+
3+import (
4+ "bytes"
5+ "encoding/binary"
6+ "testing"
7+
8+ "bnema.dev/xturbo/internal/xtest"
9+ "bnema.dev/xturbo/render"
10+ "bnema.dev/xturbo/res"
11+ "bnema.dev/xturbo/xfixes"
12+ "bnema.dev/xturbo/xproto"
13+)
14+
15+func loadReply(t testing.TB, name string) []byte {
16+ t.Helper()
17+ raw, err := xtest.LoadHex("testdata/golden/" + name + ".reply.hex")
18+ if err != nil {
19+ t.Fatal(err)
20+ }
21+ if raw[0] != 1 || len(raw) != 32+4*int(binary.LittleEndian.Uint32(raw[4:])) {
22+ t.Fatalf("%s: not a framed reply", name)
23+ }
24+ return raw
25+}
26+
27+// Expected values are independent of the generated code: they follow from the
28+// capture script (window geometry, written property, ConfigureWindow state)
29+// or are read from the raw golden at protocol-spec offsets.
30+func TestReplyGoldens(t *testing.T) {
31+ u32 := func(raw []byte, off int) uint32 { return binary.LittleEndian.Uint32(raw[off:]) }
32+ t.Run("xproto/GetGeometry", func(t *testing.T) {
33+ raw := loadReply(t, "xproto/GetGeometry")
34+ r, ok := xproto.ParseGetGeometryReply(raw)
35+ if !ok || r.Depth() != 24 || r.Root() != xproto.Window(u32(raw, 8)) || r.X() != 0 || r.Y() != 0 ||
36+ r.Width() != 800 || r.Height() != 600 || r.BorderWidth() != 0 || !bytes.Equal(r.Raw(), raw) {
37+ t.Fatalf("decoded %+v", r)
38+ }
39+ })
40+ t.Run("xproto/QueryTree", func(t *testing.T) {
41+ raw := loadReply(t, "xproto/QueryTree")
42+ r, ok := xproto.ParseQueryTreeReply(raw)
43+ if !ok || r.Root() != xproto.Window(u32(raw, 8)) || r.Parent() != xproto.WindowNone || r.ChildrenLen() != 2 {
44+ t.Fatal("fixed fields")
45+ }
46+ c := r.Children()
47+ // Stacking order bottom-to-top: the sibling was created before the child.
48+ if c.Len() != 2 || c.At(0)&0x1fffff != 2 || c.At(1)&0x1fffff != 1 || c.At(0)&^0x1fffff != c.At(1)&^0x1fffff {
49+ t.Fatalf("children %x %x", c.At(0), c.At(1))
50+ }
51+ })
52+ t.Run("xproto/GetWindowAttributes", func(t *testing.T) {
53+ raw := loadReply(t, "xproto/GetWindowAttributes")
54+ r, ok := xproto.ParseGetWindowAttributesReply(raw)
55+ if !ok || r.BackingStore() != xproto.BackingStoreNotUseful || r.Visual() != xproto.Visualid(u32(raw, 8)) ||
56+ r.Class() != xproto.WindowClassInputOutput || r.BitGravity() != xproto.GravityBitForget ||
57+ r.WinGravity() != xproto.GravityNorthWest || r.BackingPlanes() != 0xffffffff || r.BackingPixel() != 0 ||
58+ !r.SaveUnder() || !r.MapIsInstalled() || r.MapState() != xproto.MapStateUnmapped || r.OverrideRedirect() ||
59+ r.Colormap() != xproto.Colormap(u32(raw, 28)) || r.AllEventMasks() != 0 || r.YourEventMask() != 0 ||
60+ r.DoNotPropagateMask() != 0 {
61+ t.Fatal("decoded attributes")
62+ }
63+ })
64+ t.Run("xproto/InternAtom", func(t *testing.T) {
65+ raw := loadReply(t, "xproto/InternAtom")
66+ r, ok := xproto.ParseInternAtomReply(raw)
67+ if !ok || r.Atom() == xproto.AtomNone || r.Atom() != xproto.Atom(u32(raw, 8)) {
68+ t.Fatal("atom")
69+ }
70+ })
71+ t.Run("xproto/GetProperty", func(t *testing.T) {
72+ raw := loadReply(t, "xproto/GetProperty")
73+ r, ok := xproto.ParseGetPropertyReply(raw)
74+ if !ok || r.Format() != 8 || r.Type() != xproto.AtomString || r.BytesAfter() != 0 || r.ValueLen() != 3 ||
75+ string(r.Value()) != "abc" || cap(r.Value()) != 3 {
76+ t.Fatalf("value %q", r.Value())
77+ }
78+ })
79+ t.Run("xproto/GetPropertyEmpty", func(t *testing.T) {
80+ raw := loadReply(t, "xproto/GetPropertyEmpty")
81+ r, ok := xproto.ParseGetPropertyReply(raw)
82+ if !ok || r.Format() != 0 || r.Type() != xproto.AtomNone || r.ValueLen() != 0 || len(r.Value()) != 0 {
83+ t.Fatal("empty property")
84+ }
85+ })
86+ t.Run("xproto/QueryExtension", func(t *testing.T) {
87+ raw := loadReply(t, "xproto/QueryExtension")
88+ r, ok := xproto.ParseQueryExtensionReply(raw)
89+ if !ok || !r.Present() || r.MajorOpcode() < 128 || r.FirstEvent() != raw[10] || r.FirstError() != raw[11] {
90+ t.Fatal("XFIXES query")
91+ }
92+ })
93+ t.Run("xproto/ListExtensions", func(t *testing.T) {
94+ raw := loadReply(t, "xproto/ListExtensions")
95+ r, ok := xproto.ParseListExtensionsReply(raw)
96+ if !ok {
97+ t.Fatal("parse")
98+ }
99+ it := r.Names()
100+ var names []string
101+ total := 32
102+ for it.Next() {
103+ v := it.Value()
104+ if int(v.NameLen()) != len(v.Name()) || v.Size() != 1+len(v.Name()) {
105+ t.Fatal("STR view")
106+ }
107+ names = append(names, string(v.Name()))
108+ total += v.Size()
109+ }
110+ if it.Err() || len(names) != int(r.NamesLen()) || total > len(raw) || len(raw)-total > 3 {
111+ t.Fatalf("iterated %d of %d, %d/%d bytes", len(names), r.NamesLen(), total, len(raw))
112+ }
113+ found := map[string]bool{}
114+ for _, n := range names {
115+ found[n] = true
116+ }
117+ for _, want := range []string{"XFIXES", "RENDER", "BIG-REQUESTS", "Composite", "X-Resource"} {
118+ if !found[want] {
119+ t.Fatalf("missing %s in %q", want, names)
120+ }
121+ }
122+ })
123+ t.Run("xfixes/QueryVersion", func(t *testing.T) {
124+ r, ok := xfixes.ParseQueryVersionReply(loadReply(t, "xfixes/QueryVersion"))
125+ if !ok || r.MajorVersion() != 6 || r.MinorVersion() != 0 {
126+ t.Fatal("version")
127+ }
128+ })
129+ t.Run("res/QueryClientIds", func(t *testing.T) {
130+ r, ok := res.ParseQueryClientIdsReply(loadReply(t, "res/QueryClientIds"))
131+ if !ok || r.NumIds() != 2 {
132+ t.Fatal("parse")
133+ }
134+ // Spec client 0 asks for every client's XID: the server client and ours.
135+ it := r.Ids()
136+ var clients []uint32
137+ for it.Next() {
138+ v := it.Value()
139+ if v.Spec().Mask != res.ClientIdMaskClientXID || v.Length() != 0 || v.Value().Len() != 0 || v.Size() != 12 {
140+ t.Fatal("ClientIdValue view")
141+ }
142+ clients = append(clients, v.Spec().Client)
143+ }
144+ if it.Err() || len(clients) != 2 || clients[0] != 0 || clients[1] == 0 {
145+ t.Fatalf("clients %x", clients)
146+ }
147+ })
148+ t.Run("render/QueryPictFormats", func(t *testing.T) {
149+ raw := loadReply(t, "render/QueryPictFormats")
150+ r, ok := render.ParseQueryPictFormatsReply(raw)
151+ if !ok || r.NumScreens() != 1 || r.Formats().Len() != int(r.NumFormats()) || r.Subpixels().Len() != int(r.NumSubpixel()) {
152+ t.Fatal("counts")
153+ }
154+ formats := map[render.Pictformat]bool{}
155+ for i := range r.Formats().Len() {
156+ f := r.Formats().At(i)
157+ formats[f.Id] = true
158+ }
159+ screens := r.Screens()
160+ visuals := 0
161+ for screens.Next() {
162+ depths := screens.Value().Depths()
163+ for depths.Next() {
164+ vs := depths.Value().Visuals()
165+ for i := range vs.Len() {
166+ if !formats[vs.At(i).Format] {
167+ t.Fatal("visual references an unknown format")
168+ }
169+ visuals++
170+ }
171+ }
172+ if depths.Err() {
173+ t.Fatal("depth iterator")
174+ }
175+ }
176+ if screens.Err() || visuals == 0 {
177+ t.Fatal("screen iterator")
178+ }
179+ for i := range r.Subpixels().Len() {
180+ if r.Subpixels().At(i) != render.SubPixelUnknown {
181+ t.Fatal("Xvfb subpixel order")
182+ }
183+ }
184+ })
185+}
186+
187+func TestReplyParseRejects(t *testing.T) {
188+ raw := loadReply(t, "xproto/QueryTree")
189+ if _, ok := xproto.ParseQueryTreeReply(raw[:31]); ok {
190+ t.Fatal("short fixed prefix accepted")
191+ }
192+ if _, ok := xproto.ParseQueryTreeReply(raw[:len(raw)-1]); ok {
193+ t.Fatal("truncated list accepted")
194+ }
195+ raw = loadReply(t, "xproto/GetWindowAttributes")
196+ if _, ok := xproto.ParseGetWindowAttributesReply(raw[:43]); ok {
197+ t.Fatal("44-byte reply prefix not enforced")
198+ }
199+ raw = bytes.Clone(loadReply(t, "xproto/ListExtensions"))
200+ raw[1] = 255 // names_len: far more STRs than the reply holds
201+ if _, ok := xproto.ParseListExtensionsReply(raw); ok {
202+ t.Fatal("STR count beyond the reply accepted")
203+ }
204+ prop := bytes.Clone(loadReply(t, "xproto/GetProperty"))
205+ prop[1] = 32 // 3 items of 4 bytes overrun the 36-byte reply
206+ if _, ok := xproto.ParseGetPropertyReply(prop); ok {
207+ t.Fatal("format*value_len overrun accepted")
208+ }
209+}
210+
211+func TestReplyAllocs(t *testing.T) {
212+ prop := loadReply(t, "xproto/GetProperty")
213+ tree := loadReply(t, "xproto/QueryTree")
214+ exts := loadReply(t, "xproto/ListExtensions")
215+ formats := loadReply(t, "render/QueryPictFormats")
216+ ids := loadReply(t, "res/QueryClientIds")
217+ var sink uint64
218+ n := testing.AllocsPerRun(1000, func() {
219+ p, _ := xproto.ParseGetPropertyReply(prop)
220+ v := p.Value()
221+ sink += uint64(len(v)) + uint64(p.Type()) + uint64(p.Format())
222+ q, _ := xproto.ParseQueryTreeReply(tree)
223+ c := q.Children()
224+ for i := range c.Len() {
225+ sink += uint64(c.At(i))
226+ }
227+ sink += uint64(q.Root()) + uint64(q.Parent())
228+ l, _ := xproto.ParseListExtensionsReply(exts)
229+ it := l.Names()
230+ for it.Next() {
231+ sink += uint64(len(it.Value().Name()))
232+ }
233+ f, _ := render.ParseQueryPictFormatsReply(formats)
234+ fl := f.Formats()
235+ for i := range fl.Len() {
236+ sink += uint64(fl.At(i).Id)
237+ }
238+ s := f.Screens()
239+ for s.Next() {
240+ d := s.Value().Depths()
241+ for d.Next() {
242+ vs := d.Value().Visuals()
243+ for i := range vs.Len() {
244+ sink += uint64(vs.At(i).Visual)
245+ }
246+ }
247+ }
248+ sp := f.Subpixels()
249+ for i := range sp.Len() {
250+ sink += uint64(sp.At(i))
251+ }
252+ r, _ := res.ParseQueryClientIdsReply(ids)
253+ ri := r.Ids()
254+ for ri.Next() {
255+ sink += uint64(ri.Value().Value().Len())
256+ }
257+ })
258+ if n != 0 {
259+ t.Fatalf("reply parse/getters/iteration allocate %v times", n)
260+ }
261+ _ = sink
262+}
263+
264+func BenchmarkGetPropertyReply(b *testing.B) {
265+ raw := loadReply(b, "xproto/GetProperty")
266+ var sink int
267+ b.ReportAllocs()
268+ for b.Loop() {
269+ r, ok := xproto.ParseGetPropertyReply(raw)
270+ if !ok {
271+ b.Fatal("parse")
272+ }
273+ sink += len(r.Value()) + int(r.Type())
274+ }
275+ _ = sink
276+}
277+
278+func BenchmarkQueryTreeReply(b *testing.B) {
279+ raw := loadReply(b, "xproto/QueryTree")
280+ var sink xproto.Window
281+ b.ReportAllocs()
282+ for b.Loop() {
283+ r, _ := xproto.ParseQueryTreeReply(raw)
284+ c := r.Children()
285+ for i := range c.Len() {
286+ sink ^= c.At(i)
287+ }
288+ }
289+ _ = sink
290+}
291+
292+func BenchmarkListExtensionsReply(b *testing.B) {
293+ raw := loadReply(b, "xproto/ListExtensions")
294+ var sink int
295+ b.ReportAllocs()
296+ for b.Loop() {
297+ r, _ := xproto.ParseListExtensionsReply(raw)
298+ it := r.Names()
299+ for it.Next() {
300+ sink += len(it.Value().Name())
301+ }
302+ }
303+ _ = sink
304+}
A requests_test.go +62 -0
@@ -0,0 +1,62 @@
1+package xturbo_test
2+
3+import (
4+ "bytes"
5+ "encoding/binary"
6+ "testing"
7+
8+ "bnema.dev/xturbo"
9+ "bnema.dev/xturbo/internal/xtest"
10+ "bnema.dev/xturbo/xfixes"
11+ "bnema.dev/xturbo/xproto"
12+)
13+
14+func TestRequestGoldens(t *testing.T) {
15+ for _, tc := range []struct {
16+ name string
17+ encode func(*xturbo.Buf, uint32) xturbo.Seq
18+ }{
19+ {"xproto/MapWindow", func(b *xturbo.Buf, id uint32) xturbo.Seq { return xproto.MapWindow(b, xproto.Window(id)) }},
20+ {"xproto/GetGeometry", func(b *xturbo.Buf, id uint32) xturbo.Seq { return xproto.GetGeometry(b, xproto.Drawable(id)) }},
21+ {"xfixes/QueryVersion", func(b *xturbo.Buf, _ uint32) xturbo.Seq { return xfixes.QueryVersion(b, 6, 0) }},
22+ } {
23+ t.Run(tc.name, func(t *testing.T) {
24+ want, err := xtest.LoadHex("testdata/golden/" + tc.name + ".req.hex")
25+ if err != nil {
26+ t.Fatal(err)
27+ }
28+ b := xturbo.NewBuf(0)
29+ var ext xturbo.ExtTable
30+ ext.Set(xturbo.ExtXFixes, want[0], 0, 0)
31+ b.Ext = &ext
32+ id := binary.LittleEndian.Uint32(want[4:])
33+ if tc.encode(b, id) != 1 || b.Err() != nil {
34+ t.Fatalf("seq/err: %v", b.Err())
35+ }
36+ if !bytes.Equal(b.Bytes(), want) {
37+ t.Fatalf("got %x want %x", b.Bytes(), want)
38+ }
39+ })
40+ }
41+}
42+func TestMissingExtension(t *testing.T) {
43+ for _, table := range []*xturbo.ExtTable{nil, {}} {
44+ b := xturbo.NewBuf(0)
45+ b.Ext = table
46+ if xfixes.QueryVersion(b, 6, 0) != 0 || b.Err() != xturbo.ErrExtMissing || b.Len() != 0 || xproto.MapWindow(b, 1) != 0 {
47+ t.Fatal("missing extension must fail sticky")
48+ }
49+ }
50+}
51+func TestAllocFixedRequests(t *testing.T) {
52+ b := xturbo.NewBuf(0)
53+ var ext xturbo.ExtTable
54+ ext.Set(xturbo.ExtXFixes, 138, 0, 0)
55+ b.Ext = &ext
56+ if n := testing.AllocsPerRun(1000, func() { b.Reset(); xproto.MapWindow(b, 1); xproto.GetGeometry(b, 1); xfixes.QueryVersion(b, 6, 0) }); n != 0 {
57+ t.Fatal(n)
58+ }
59+ if b.Err() != nil {
60+ t.Fatal(b.Err())
61+ }
62+}
A res/replies_fuzz_test.go +146 -0
@@ -0,0 +1,146 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package res
3+
4+import "testing"
5+import "bnema.dev/xturbo/internal/xtest"
6+
7+func FuzzParseQueryVersionReply(f *testing.F) {
8+ f.Add(make([]byte, 32))
9+ f.Fuzz(func(t *testing.T, raw []byte) {
10+ r, ok := ParseQueryVersionReply(raw)
11+ if !ok {
12+ if len(raw) >= 32 {
13+ t.Fatal("rejected a complete fixed-size reply")
14+ }
15+ return
16+ }
17+ if len(r.Raw()) != len(raw) {
18+ t.Fatal("Raw must return the parsed bytes")
19+ }
20+ _ = r.ServerMajor()
21+ _ = r.ServerMinor()
22+ })
23+}
24+
25+func FuzzParseQueryClientsReply(f *testing.F) {
26+ f.Add(make([]byte, 32))
27+ f.Fuzz(func(t *testing.T, raw []byte) {
28+ r, ok := ParseQueryClientsReply(raw)
29+ if !ok {
30+ return
31+ }
32+ if len(r.Raw()) != len(raw) {
33+ t.Fatal("Raw must return the parsed bytes")
34+ }
35+ _ = r.NumClients()
36+ {
37+ l0 := r.Clients()
38+ for i := 0; i < l0.Len(); i++ {
39+ _ = l0.At(i)
40+ }
41+ }
42+ })
43+}
44+
45+func FuzzParseQueryClientResourcesReply(f *testing.F) {
46+ f.Add(make([]byte, 32))
47+ f.Fuzz(func(t *testing.T, raw []byte) {
48+ r, ok := ParseQueryClientResourcesReply(raw)
49+ if !ok {
50+ return
51+ }
52+ if len(r.Raw()) != len(raw) {
53+ t.Fatal("Raw must return the parsed bytes")
54+ }
55+ _ = r.NumTypes()
56+ {
57+ l0 := r.Types()
58+ for i := 0; i < l0.Len(); i++ {
59+ _ = l0.At(i)
60+ }
61+ }
62+ })
63+}
64+
65+func FuzzParseQueryClientPixmapBytesReply(f *testing.F) {
66+ f.Add(make([]byte, 32))
67+ f.Fuzz(func(t *testing.T, raw []byte) {
68+ r, ok := ParseQueryClientPixmapBytesReply(raw)
69+ if !ok {
70+ if len(raw) >= 32 {
71+ t.Fatal("rejected a complete fixed-size reply")
72+ }
73+ return
74+ }
75+ if len(r.Raw()) != len(raw) {
76+ t.Fatal("Raw must return the parsed bytes")
77+ }
78+ _ = r.Bytes()
79+ _ = r.BytesOverflow()
80+ })
81+}
82+
83+func FuzzParseQueryClientIdsReply(f *testing.F) {
84+ f.Add(make([]byte, 32))
85+ if raw, err := xtest.LoadHex("../testdata/golden/res/QueryClientIds.reply.hex"); err != nil {
86+ f.Fatal(err)
87+ } else {
88+ f.Add(raw)
89+ }
90+ f.Fuzz(func(t *testing.T, raw []byte) {
91+ r, ok := ParseQueryClientIdsReply(raw)
92+ if !ok {
93+ return
94+ }
95+ if len(r.Raw()) != len(raw) {
96+ t.Fatal("Raw must return the parsed bytes")
97+ }
98+ _ = r.NumIds()
99+ {
100+ it0 := r.Ids()
101+ for it0.Next() {
102+ _ = it0.Value().Spec()
103+ _ = it0.Value().Length()
104+ {
105+ l1 := it0.Value().Value()
106+ for i := 0; i < l1.Len(); i++ {
107+ _ = l1.At(i)
108+ }
109+ }
110+ }
111+ if it0.Err() {
112+ t.Fatal("iterator error after successful Parse")
113+ }
114+ }
115+ })
116+}
117+
118+func FuzzParseQueryResourceBytesReply(f *testing.F) {
119+ f.Add(make([]byte, 32))
120+ f.Fuzz(func(t *testing.T, raw []byte) {
121+ r, ok := ParseQueryResourceBytesReply(raw)
122+ if !ok {
123+ return
124+ }
125+ if len(r.Raw()) != len(raw) {
126+ t.Fatal("Raw must return the parsed bytes")
127+ }
128+ _ = r.NumSizes()
129+ {
130+ it0 := r.Sizes()
131+ for it0.Next() {
132+ _ = it0.Value().Size_()
133+ _ = it0.Value().NumCrossReferences()
134+ {
135+ l1 := it0.Value().CrossReferences()
136+ for i := 0; i < l1.Len(); i++ {
137+ _ = l1.At(i)
138+ }
139+ }
140+ }
141+ if it0.Err() {
142+ t.Fatal("iterator error after successful Parse")
143+ }
144+ }
145+ })
146+}
A res/replies_generated.go +348 -0
@@ -0,0 +1,348 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package res
3+
4+import "encoding/binary"
5+
6+// QueryVersionReply is a zero-copy view over a QueryVersion reply; offsets count from reply byte 0.
7+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
8+type QueryVersionReply struct{ raw []byte }
9+
10+// ParseQueryVersionReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
11+func ParseQueryVersionReply(raw []byte) (QueryVersionReply, bool) {
12+ if len(raw) < 32 {
13+ return QueryVersionReply{}, false
14+ }
15+ r := QueryVersionReply{raw: raw}
16+ return r, true
17+}
18+func (r QueryVersionReply) Raw() []byte { return r.raw }
19+func (r QueryVersionReply) ServerMajor() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
20+func (r QueryVersionReply) ServerMinor() uint16 {
21+ return uint16(binary.LittleEndian.Uint16(r.raw[10:]))
22+}
23+
24+// QueryClientsReply is a zero-copy view over a QueryClients reply; offsets count from reply byte 0.
25+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
26+type QueryClientsReply struct{ raw []byte }
27+
28+// ParseQueryClientsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
29+func ParseQueryClientsReply(raw []byte) (QueryClientsReply, bool) {
30+ if len(raw) < 32 {
31+ return QueryClientsReply{}, false
32+ }
33+ r := QueryClientsReply{raw: raw}
34+ off := 32
35+ {
36+ n := int(r.NumClients())
37+ if n < 0 || n > len(r.raw) {
38+ return QueryClientsReply{}, false
39+ }
40+ off += n * 8
41+ }
42+ if off > len(r.raw) {
43+ return QueryClientsReply{}, false
44+ }
45+ if off > len(r.raw) {
46+ return QueryClientsReply{}, false
47+ }
48+ return r, true
49+}
50+func (r QueryClientsReply) Raw() []byte { return r.raw }
51+func (r QueryClientsReply) NumClients() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[8:])) }
52+func (r QueryClientsReply) Clients() ClientList {
53+ off := 32
54+ end := off + (int(r.NumClients()))*8
55+ return ClientList{b: r.raw[off:end:end]}
56+}
57+
58+// QueryClientResourcesReply is a zero-copy view over a QueryClientResources reply; offsets count from reply byte 0.
59+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
60+type QueryClientResourcesReply struct{ raw []byte }
61+
62+// ParseQueryClientResourcesReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
63+func ParseQueryClientResourcesReply(raw []byte) (QueryClientResourcesReply, bool) {
64+ if len(raw) < 32 {
65+ return QueryClientResourcesReply{}, false
66+ }
67+ r := QueryClientResourcesReply{raw: raw}
68+ off := 32
69+ {
70+ n := int(r.NumTypes())
71+ if n < 0 || n > len(r.raw) {
72+ return QueryClientResourcesReply{}, false
73+ }
74+ off += n * 8
75+ }
76+ if off > len(r.raw) {
77+ return QueryClientResourcesReply{}, false
78+ }
79+ if off > len(r.raw) {
80+ return QueryClientResourcesReply{}, false
81+ }
82+ return r, true
83+}
84+func (r QueryClientResourcesReply) Raw() []byte { return r.raw }
85+func (r QueryClientResourcesReply) NumTypes() uint32 {
86+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
87+}
88+func (r QueryClientResourcesReply) Types() TypeList {
89+ off := 32
90+ end := off + (int(r.NumTypes()))*8
91+ return TypeList{b: r.raw[off:end:end]}
92+}
93+
94+// QueryClientPixmapBytesReply is a zero-copy view over a QueryClientPixmapBytes reply; offsets count from reply byte 0.
95+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
96+type QueryClientPixmapBytesReply struct{ raw []byte }
97+
98+// ParseQueryClientPixmapBytesReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
99+func ParseQueryClientPixmapBytesReply(raw []byte) (QueryClientPixmapBytesReply, bool) {
100+ if len(raw) < 32 {
101+ return QueryClientPixmapBytesReply{}, false
102+ }
103+ r := QueryClientPixmapBytesReply{raw: raw}
104+ return r, true
105+}
106+func (r QueryClientPixmapBytesReply) Raw() []byte { return r.raw }
107+func (r QueryClientPixmapBytesReply) Bytes() uint32 {
108+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
109+}
110+func (r QueryClientPixmapBytesReply) BytesOverflow() uint32 {
111+ return uint32(binary.LittleEndian.Uint32(r.raw[12:]))
112+}
113+
114+// QueryClientIdsReply is a zero-copy view over a QueryClientIds reply; offsets count from reply byte 0.
115+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
116+type QueryClientIdsReply struct{ raw []byte }
117+
118+// ParseQueryClientIdsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
119+func ParseQueryClientIdsReply(raw []byte) (QueryClientIdsReply, bool) {
120+ if len(raw) < 32 {
121+ return QueryClientIdsReply{}, false
122+ }
123+ r := QueryClientIdsReply{raw: raw}
124+ off := 32
125+ {
126+ n := int(r.NumIds())
127+ if off > len(r.raw) || n < 0 || n > len(r.raw) {
128+ return QueryClientIdsReply{}, false
129+ }
130+ it := NewClientIdValueIter(r.raw[off:], n)
131+ for it.Next() {
132+ off += it.Value().Size()
133+ }
134+ if it.Err() {
135+ return QueryClientIdsReply{}, false
136+ }
137+ }
138+ if off > len(r.raw) {
139+ return QueryClientIdsReply{}, false
140+ }
141+ return r, true
142+}
143+func (r QueryClientIdsReply) Raw() []byte { return r.raw }
144+func (r QueryClientIdsReply) NumIds() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[8:])) }
145+func (r QueryClientIdsReply) Ids() ClientIdValueIter {
146+ off := 32
147+ return NewClientIdValueIter(r.raw[off:], int(r.NumIds()))
148+}
149+
150+// QueryResourceBytesReply is a zero-copy view over a QueryResourceBytes reply; offsets count from reply byte 0.
151+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
152+type QueryResourceBytesReply struct{ raw []byte }
153+
154+// ParseQueryResourceBytesReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
155+func ParseQueryResourceBytesReply(raw []byte) (QueryResourceBytesReply, bool) {
156+ if len(raw) < 32 {
157+ return QueryResourceBytesReply{}, false
158+ }
159+ r := QueryResourceBytesReply{raw: raw}
160+ off := 32
161+ {
162+ n := int(r.NumSizes())
163+ if off > len(r.raw) || n < 0 || n > len(r.raw) {
164+ return QueryResourceBytesReply{}, false
165+ }
166+ it := NewResourceSizeValueIter(r.raw[off:], n)
167+ for it.Next() {
168+ off += it.Value().Size()
169+ }
170+ if it.Err() {
171+ return QueryResourceBytesReply{}, false
172+ }
173+ }
174+ if off > len(r.raw) {
175+ return QueryResourceBytesReply{}, false
176+ }
177+ return r, true
178+}
179+func (r QueryResourceBytesReply) Raw() []byte { return r.raw }
180+func (r QueryResourceBytesReply) NumSizes() uint32 {
181+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
182+}
183+func (r QueryResourceBytesReply) Sizes() ResourceSizeValueIter {
184+ off := 32
185+ return NewResourceSizeValueIter(r.raw[off:], int(r.NumSizes()))
186+}
187+
188+// ClientIdValueView is a zero-copy view over one wire-encoded ClientIdValue, yielded by ClientIdValueIter.
189+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
190+type ClientIdValueView struct{ raw []byte }
191+
192+func (v ClientIdValueView) Raw() []byte { return v.raw }
193+
194+// Size is the element's wire size, including trailing alignment.
195+func (v ClientIdValueView) Size() int { return len(v.raw) }
196+func sizeClientIdValue(p []byte) int {
197+ if len(p) < 12 {
198+ return -1
199+ }
200+ v := ClientIdValueView{raw: p}
201+ _ = v
202+ off := 12
203+ {
204+ n := (int(v.Length()) / 4)
205+ if n < 0 || n > len(v.raw) {
206+ return -1
207+ }
208+ off += n * 4
209+ }
210+ if off > len(v.raw) {
211+ return -1
212+ }
213+ if off > len(v.raw) {
214+ return -1
215+ }
216+ return off
217+}
218+func (v ClientIdValueView) Spec() ClientIdSpec { return GetClientIdSpec(v.raw[0:]) }
219+func (v ClientIdValueView) Length() uint32 { return uint32(binary.LittleEndian.Uint32(v.raw[8:])) }
220+func (v ClientIdValueView) Value() Uint32List {
221+ off := 12
222+ end := off + (int(v.Length())/4)*4
223+ return Uint32List{b: v.raw[off:end:end]}
224+}
225+
226+// ClientIdValueIter walks n consecutive ClientIdValue elements; Err reports a malformed length.
227+// It shares the lifetime of the bytes it walks.
228+type ClientIdValueIter struct {
229+ b []byte
230+ n int
231+ v ClientIdValueView
232+ err bool
233+}
234+
235+// NewClientIdValueIter iterates n elements encoded at the start of b.
236+func NewClientIdValueIter(b []byte, n int) ClientIdValueIter { return ClientIdValueIter{b: b, n: n} }
237+func (it *ClientIdValueIter) Next() bool {
238+ if it.n <= 0 || it.err {
239+ return false
240+ }
241+ s := sizeClientIdValue(it.b)
242+ if s < 0 {
243+ it.err = true
244+ it.n = 0
245+ return false
246+ }
247+ it.v = ClientIdValueView{raw: it.b[:s:s]}
248+ it.b = it.b[s:]
249+ it.n--
250+ return true
251+}
252+func (it *ClientIdValueIter) Value() ClientIdValueView { return it.v }
253+func (it *ClientIdValueIter) Err() bool { return it.err }
254+
255+// ResourceSizeValueView is a zero-copy view over one wire-encoded ResourceSizeValue, yielded by ResourceSizeValueIter.
256+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
257+type ResourceSizeValueView struct{ raw []byte }
258+
259+func (v ResourceSizeValueView) Raw() []byte { return v.raw }
260+
261+// Size is the element's wire size, including trailing alignment.
262+func (v ResourceSizeValueView) Size() int { return len(v.raw) }
263+func sizeResourceSizeValue(p []byte) int {
264+ if len(p) < 24 {
265+ return -1
266+ }
267+ v := ResourceSizeValueView{raw: p}
268+ _ = v
269+ off := 24
270+ {
271+ n := int(v.NumCrossReferences())
272+ if n < 0 || n > len(v.raw) {
273+ return -1
274+ }
275+ off += n * 20
276+ }
277+ if off > len(v.raw) {
278+ return -1
279+ }
280+ if off > len(v.raw) {
281+ return -1
282+ }
283+ return off
284+}
285+func (v ResourceSizeValueView) Size_() ResourceSizeSpec { return GetResourceSizeSpec(v.raw[0:]) }
286+func (v ResourceSizeValueView) NumCrossReferences() uint32 {
287+ return uint32(binary.LittleEndian.Uint32(v.raw[20:]))
288+}
289+func (v ResourceSizeValueView) CrossReferences() ResourceSizeSpecList {
290+ off := 24
291+ end := off + (int(v.NumCrossReferences()))*20
292+ return ResourceSizeSpecList{b: v.raw[off:end:end]}
293+}
294+
295+// ResourceSizeValueIter walks n consecutive ResourceSizeValue elements; Err reports a malformed length.
296+// It shares the lifetime of the bytes it walks.
297+type ResourceSizeValueIter struct {
298+ b []byte
299+ n int
300+ v ResourceSizeValueView
301+ err bool
302+}
303+
304+// NewResourceSizeValueIter iterates n elements encoded at the start of b.
305+func NewResourceSizeValueIter(b []byte, n int) ResourceSizeValueIter {
306+ return ResourceSizeValueIter{b: b, n: n}
307+}
308+func (it *ResourceSizeValueIter) Next() bool {
309+ if it.n <= 0 || it.err {
310+ return false
311+ }
312+ s := sizeResourceSizeValue(it.b)
313+ if s < 0 {
314+ it.err = true
315+ it.n = 0
316+ return false
317+ }
318+ it.v = ResourceSizeValueView{raw: it.b[:s:s]}
319+ it.b = it.b[s:]
320+ it.n--
321+ return true
322+}
323+func (it *ResourceSizeValueIter) Value() ResourceSizeValueView { return it.v }
324+func (it *ResourceSizeValueIter) Err() bool { return it.err }
325+
326+// ClientList is a borrowed view over a wire list of Client. It shares the lifetime of the bytes it was taken from; copy what you keep.
327+type ClientList struct{ b []byte }
328+
329+func (l ClientList) Len() int { return len(l.b) / 8 }
330+func (l ClientList) At(i int) Client { return GetClient(l.b[i*8:]) }
331+
332+// ResourceSizeSpecList is a borrowed view over a wire list of ResourceSizeSpec. It shares the lifetime of the bytes it was taken from; copy what you keep.
333+type ResourceSizeSpecList struct{ b []byte }
334+
335+func (l ResourceSizeSpecList) Len() int { return len(l.b) / 20 }
336+func (l ResourceSizeSpecList) At(i int) ResourceSizeSpec { return GetResourceSizeSpec(l.b[i*20:]) }
337+
338+// TypeList is a borrowed view over a wire list of Type. It shares the lifetime of the bytes it was taken from; copy what you keep.
339+type TypeList struct{ b []byte }
340+
341+func (l TypeList) Len() int { return len(l.b) / 8 }
342+func (l TypeList) At(i int) Type { return GetType(l.b[i*8:]) }
343+
344+// Uint32List is a borrowed view over a wire list of uint32. It shares the lifetime of the bytes it was taken from; copy what you keep.
345+type Uint32List struct{ b []byte }
346+
347+func (l Uint32List) Len() int { return len(l.b) / 4 }
348+func (l Uint32List) At(i int) uint32 { return uint32(binary.LittleEndian.Uint32(l.b[i*4:])) }
A res/requests_generated.go +144 -0
@@ -0,0 +1,144 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package res
3+
4+import "encoding/binary"
5+import "bnema.dev/xturbo"
6+
7+func QueryVersion(b *xturbo.Buf, clientMajor uint8, clientMinor uint8) xturbo.Seq {
8+ if b.Ext == nil {
9+ b.Fail(xturbo.ErrExtMissing)
10+ return 0
11+ }
12+ major := b.Ext.Major(xturbo.ExtRes)
13+ if major == 0 {
14+ b.Fail(xturbo.ErrExtMissing)
15+ return 0
16+ }
17+ p, seq := b.Request(major, 0, 4)
18+ if p == nil {
19+ return 0
20+ }
21+ p[0:][0] = byte(clientMajor)
22+ p[1:][0] = byte(clientMinor)
23+ return seq
24+}
25+
26+func QueryClients(b *xturbo.Buf) xturbo.Seq {
27+ if b.Ext == nil {
28+ b.Fail(xturbo.ErrExtMissing)
29+ return 0
30+ }
31+ major := b.Ext.Major(xturbo.ExtRes)
32+ if major == 0 {
33+ b.Fail(xturbo.ErrExtMissing)
34+ return 0
35+ }
36+ p, seq := b.Request(major, 1, 0)
37+ if p == nil {
38+ return 0
39+ }
40+ return seq
41+}
42+
43+func QueryClientResources(b *xturbo.Buf, xid uint32) xturbo.Seq {
44+ if b.Ext == nil {
45+ b.Fail(xturbo.ErrExtMissing)
46+ return 0
47+ }
48+ major := b.Ext.Major(xturbo.ExtRes)
49+ if major == 0 {
50+ b.Fail(xturbo.ErrExtMissing)
51+ return 0
52+ }
53+ p, seq := b.Request(major, 2, 4)
54+ if p == nil {
55+ return 0
56+ }
57+ binary.LittleEndian.PutUint32(p[0:], uint32(xid))
58+ return seq
59+}
60+
61+func QueryClientPixmapBytes(b *xturbo.Buf, xid uint32) xturbo.Seq {
62+ if b.Ext == nil {
63+ b.Fail(xturbo.ErrExtMissing)
64+ return 0
65+ }
66+ major := b.Ext.Major(xturbo.ExtRes)
67+ if major == 0 {
68+ b.Fail(xturbo.ErrExtMissing)
69+ return 0
70+ }
71+ p, seq := b.Request(major, 3, 4)
72+ if p == nil {
73+ return 0
74+ }
75+ binary.LittleEndian.PutUint32(p[0:], uint32(xid))
76+ return seq
77+}
78+
79+func QueryClientIds(b *xturbo.Buf, specs []ClientIdSpec) xturbo.Seq {
80+ if uint64(len(specs)) > 4294967295 {
81+ b.Fail(xturbo.ErrBadLength)
82+ return 0
83+ }
84+ size := 0
85+ size += 4
86+ size += len(specs) * 8
87+ size = (size + 3) &^ 3
88+ if b.Ext == nil {
89+ b.Fail(xturbo.ErrExtMissing)
90+ return 0
91+ }
92+ major := b.Ext.Major(xturbo.ExtRes)
93+ if major == 0 {
94+ b.Fail(xturbo.ErrExtMissing)
95+ return 0
96+ }
97+ p, seq := b.Request(major, 4, size)
98+ if p == nil {
99+ return 0
100+ }
101+ off := 0
102+ binary.LittleEndian.PutUint32(p[off:], uint32(len(specs)))
103+ off += 4
104+ for i := range specs {
105+ specs[i].Put(p[off:])
106+ off += 8
107+ }
108+ return seq
109+}
110+
111+func QueryResourceBytes(b *xturbo.Buf, client uint32, specs []ResourceIdSpec) xturbo.Seq {
112+ if uint64(len(specs)) > 4294967295 {
113+ b.Fail(xturbo.ErrBadLength)
114+ return 0
115+ }
116+ size := 0
117+ size += 4
118+ size += 4
119+ size += len(specs) * 8
120+ size = (size + 3) &^ 3
121+ if b.Ext == nil {
122+ b.Fail(xturbo.ErrExtMissing)
123+ return 0
124+ }
125+ major := b.Ext.Major(xturbo.ExtRes)
126+ if major == 0 {
127+ b.Fail(xturbo.ErrExtMissing)
128+ return 0
129+ }
130+ p, seq := b.Request(major, 5, size)
131+ if p == nil {
132+ return 0
133+ }
134+ off := 0
135+ binary.LittleEndian.PutUint32(p[off:], uint32(client))
136+ off += 4
137+ binary.LittleEndian.PutUint32(p[off:], uint32(len(specs)))
138+ off += 4
139+ for i := range specs {
140+ specs[i].Put(p[off:])
141+ off += 8
142+ }
143+ return seq
144+}
A res/sizes_test.go +47 -0
@@ -0,0 +1,47 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package res
3+
4+import "testing"
5+
6+func TestWireSizes(t *testing.T) {
7+ if ClientSize != 8 {
8+ t.Errorf("Client fixed prefix = %d", ClientSize)
9+ }
10+ if TypeSize != 8 {
11+ t.Errorf("Type fixed prefix = %d", TypeSize)
12+ }
13+ if ClientIdSpecSize != 8 {
14+ t.Errorf("ClientIdSpec fixed prefix = %d", ClientIdSpecSize)
15+ }
16+ if ClientIdValueSize != 12 {
17+ t.Errorf("ClientIdValue fixed prefix = %d", ClientIdValueSize)
18+ }
19+ if ResourceIdSpecSize != 8 {
20+ t.Errorf("ResourceIdSpec fixed prefix = %d", ResourceIdSpecSize)
21+ }
22+ if ResourceSizeSpecSize != 20 {
23+ t.Errorf("ResourceSizeSpec fixed prefix = %d", ResourceSizeSpecSize)
24+ }
25+ if ResourceSizeValueSize != 24 {
26+ t.Errorf("ResourceSizeValue fixed prefix = %d", ResourceSizeValueSize)
27+ }
28+ if got := 32; got != 32 {
29+ t.Errorf("reply QueryVersion fixed size = %d", got)
30+ }
31+ if got := 32; got != 32 {
32+ t.Errorf("reply QueryClients fixed size = %d", got)
33+ }
34+ if got := 32; got != 32 {
35+ t.Errorf("reply QueryClientResources fixed size = %d", got)
36+ }
37+ if got := 32; got != 32 {
38+ t.Errorf("reply QueryClientPixmapBytes fixed size = %d", got)
39+ }
40+ if got := 32; got != 32 {
41+ t.Errorf("reply QueryClientIds fixed size = %d", got)
42+ }
43+ if got := 32; got != 32 {
44+ t.Errorf("reply QueryResourceBytes fixed size = %d", got)
45+ }
46+
47+}
A res/types_generated.go +159 -0
@@ -0,0 +1,159 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package res
3+
4+import "bnema.dev/xturbo/xproto"
5+import "encoding/binary"
6+
7+type Client struct {
8+ ResourceBase uint32
9+ ResourceMask uint32
10+}
11+
12+const ClientSize = 8
13+
14+func (v Client) Put(p []byte) {
15+ clear(p[:8])
16+ binary.LittleEndian.PutUint32(p[0:], uint32(v.ResourceBase))
17+ binary.LittleEndian.PutUint32(p[4:], uint32(v.ResourceMask))
18+}
19+func GetClient(p []byte) (v Client) {
20+ _ = p[7]
21+ v.ResourceBase = uint32(binary.LittleEndian.Uint32(p[0:]))
22+ v.ResourceMask = uint32(binary.LittleEndian.Uint32(p[4:]))
23+ return
24+}
25+
26+type Type struct {
27+ ResourceType xproto.Atom
28+ Count uint32
29+}
30+
31+const TypeSize = 8
32+
33+func (v Type) Put(p []byte) {
34+ clear(p[:8])
35+ binary.LittleEndian.PutUint32(p[0:], uint32(v.ResourceType))
36+ binary.LittleEndian.PutUint32(p[4:], uint32(v.Count))
37+}
38+func GetType(p []byte) (v Type) {
39+ _ = p[7]
40+ v.ResourceType = xproto.Atom(binary.LittleEndian.Uint32(p[0:]))
41+ v.Count = uint32(binary.LittleEndian.Uint32(p[4:]))
42+ return
43+}
44+
45+type ClientIdSpec struct {
46+ Client uint32
47+ Mask ClientIdMask
48+}
49+
50+const ClientIdSpecSize = 8
51+
52+func (v ClientIdSpec) Put(p []byte) {
53+ clear(p[:8])
54+ binary.LittleEndian.PutUint32(p[0:], uint32(v.Client))
55+ binary.LittleEndian.PutUint32(p[4:], uint32(v.Mask))
56+}
57+func GetClientIdSpec(p []byte) (v ClientIdSpec) {
58+ _ = p[7]
59+ v.Client = uint32(binary.LittleEndian.Uint32(p[0:]))
60+ v.Mask = ClientIdMask(binary.LittleEndian.Uint32(p[4:]))
61+ return
62+}
63+
64+type ClientIdValue struct {
65+ Spec ClientIdSpec
66+ Length uint32
67+ Value []uint32
68+}
69+
70+const ClientIdValueSize = 12
71+
72+func (v ClientIdValue) Size() int { off := 0; off += 8; off += 4; off += len(v.Value) * 4; return off }
73+func (v ClientIdValue) Put(p []byte) {
74+ off := 0
75+ v.Spec.Put(p[off:])
76+ off += 8
77+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Length))
78+ off += 4
79+ for i := range v.Value {
80+ binary.LittleEndian.PutUint32(p[off+i*4:], uint32(v.Value[i]))
81+ }
82+ off += len(v.Value) * 4
83+}
84+
85+type ResourceIdSpec struct {
86+ Resource uint32
87+ Type uint32
88+}
89+
90+const ResourceIdSpecSize = 8
91+
92+func (v ResourceIdSpec) Put(p []byte) {
93+ clear(p[:8])
94+ binary.LittleEndian.PutUint32(p[0:], uint32(v.Resource))
95+ binary.LittleEndian.PutUint32(p[4:], uint32(v.Type))
96+}
97+func GetResourceIdSpec(p []byte) (v ResourceIdSpec) {
98+ _ = p[7]
99+ v.Resource = uint32(binary.LittleEndian.Uint32(p[0:]))
100+ v.Type = uint32(binary.LittleEndian.Uint32(p[4:]))
101+ return
102+}
103+
104+type ResourceSizeSpec struct {
105+ Spec ResourceIdSpec
106+ Bytes uint32
107+ RefCount uint32
108+ UseCount uint32
109+}
110+
111+const ResourceSizeSpecSize = 20
112+
113+func (v ResourceSizeSpec) Put(p []byte) {
114+ clear(p[:20])
115+ v.Spec.Put(p[0:])
116+ binary.LittleEndian.PutUint32(p[8:], uint32(v.Bytes))
117+ binary.LittleEndian.PutUint32(p[12:], uint32(v.RefCount))
118+ binary.LittleEndian.PutUint32(p[16:], uint32(v.UseCount))
119+}
120+func GetResourceSizeSpec(p []byte) (v ResourceSizeSpec) {
121+ _ = p[19]
122+ v.Spec = GetResourceIdSpec(p[0:])
123+ v.Bytes = uint32(binary.LittleEndian.Uint32(p[8:]))
124+ v.RefCount = uint32(binary.LittleEndian.Uint32(p[12:]))
125+ v.UseCount = uint32(binary.LittleEndian.Uint32(p[16:]))
126+ return
127+}
128+
129+type ResourceSizeValue struct {
130+ Size_ ResourceSizeSpec
131+ NumCrossReferences uint32
132+ CrossReferences []ResourceSizeSpec
133+}
134+
135+const ResourceSizeValueSize = 24
136+
137+func (v ResourceSizeValue) Size() int {
138+ off := 0
139+ off += 20
140+ off += 4
141+ off += len(v.CrossReferences) * 20
142+ return off
143+}
144+func (v ResourceSizeValue) Put(p []byte) {
145+ off := 0
146+ v.Size_.Put(p[off:])
147+ off += 20
148+ binary.LittleEndian.PutUint32(p[off:], uint32(v.NumCrossReferences))
149+ off += 4
150+ for i := range v.CrossReferences {
151+ v.CrossReferences[i].Put(p[off+i*20:])
152+ }
153+ off += len(v.CrossReferences) * 20
154+}
155+
156+type ClientIdMask uint32
157+
158+const ClientIdMaskClientXID ClientIdMask = 1
159+const ClientIdMaskLocalClientPID ClientIdMask = 2
A shape/replies_fuzz_test.go +86 -0
@@ -0,0 +1,86 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package shape
3+
4+import "testing"
5+
6+func FuzzParseQueryVersionReply(f *testing.F) {
7+ f.Add(make([]byte, 32))
8+ f.Fuzz(func(t *testing.T, raw []byte) {
9+ r, ok := ParseQueryVersionReply(raw)
10+ if !ok {
11+ if len(raw) >= 32 {
12+ t.Fatal("rejected a complete fixed-size reply")
13+ }
14+ return
15+ }
16+ if len(r.Raw()) != len(raw) {
17+ t.Fatal("Raw must return the parsed bytes")
18+ }
19+ _ = r.MajorVersion()
20+ _ = r.MinorVersion()
21+ })
22+}
23+
24+func FuzzParseQueryExtentsReply(f *testing.F) {
25+ f.Add(make([]byte, 32))
26+ f.Fuzz(func(t *testing.T, raw []byte) {
27+ r, ok := ParseQueryExtentsReply(raw)
28+ if !ok {
29+ if len(raw) >= 32 {
30+ t.Fatal("rejected a complete fixed-size reply")
31+ }
32+ return
33+ }
34+ if len(r.Raw()) != len(raw) {
35+ t.Fatal("Raw must return the parsed bytes")
36+ }
37+ _ = r.BoundingShaped()
38+ _ = r.ClipShaped()
39+ _ = r.BoundingShapeExtentsX()
40+ _ = r.BoundingShapeExtentsY()
41+ _ = r.BoundingShapeExtentsWidth()
42+ _ = r.BoundingShapeExtentsHeight()
43+ _ = r.ClipShapeExtentsX()
44+ _ = r.ClipShapeExtentsY()
45+ _ = r.ClipShapeExtentsWidth()
46+ _ = r.ClipShapeExtentsHeight()
47+ })
48+}
49+
50+func FuzzParseInputSelectedReply(f *testing.F) {
51+ f.Add(make([]byte, 32))
52+ f.Fuzz(func(t *testing.T, raw []byte) {
53+ r, ok := ParseInputSelectedReply(raw)
54+ if !ok {
55+ if len(raw) >= 32 {
56+ t.Fatal("rejected a complete fixed-size reply")
57+ }
58+ return
59+ }
60+ if len(r.Raw()) != len(raw) {
61+ t.Fatal("Raw must return the parsed bytes")
62+ }
63+ _ = r.Enabled()
64+ })
65+}
66+
67+func FuzzParseGetRectanglesReply(f *testing.F) {
68+ f.Add(make([]byte, 32))
69+ f.Fuzz(func(t *testing.T, raw []byte) {
70+ r, ok := ParseGetRectanglesReply(raw)
71+ if !ok {
72+ return
73+ }
74+ if len(r.Raw()) != len(raw) {
75+ t.Fatal("Raw must return the parsed bytes")
76+ }
77+ _ = r.Ordering()
78+ _ = r.RectanglesLen()
79+ {
80+ l0 := r.Rectangles()
81+ for i := 0; i < l0.Len(); i++ {
82+ _ = l0.At(i)
83+ }
84+ }
85+ })
86+}
A shape/replies_generated.go +123 -0
@@ -0,0 +1,123 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package shape
3+
4+import "bnema.dev/xturbo/xproto"
5+import "encoding/binary"
6+
7+// QueryVersionReply is a zero-copy view over a QueryVersion reply; offsets count from reply byte 0.
8+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
9+type QueryVersionReply struct{ raw []byte }
10+
11+// ParseQueryVersionReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
12+func ParseQueryVersionReply(raw []byte) (QueryVersionReply, bool) {
13+ if len(raw) < 32 {
14+ return QueryVersionReply{}, false
15+ }
16+ r := QueryVersionReply{raw: raw}
17+ return r, true
18+}
19+func (r QueryVersionReply) Raw() []byte { return r.raw }
20+func (r QueryVersionReply) MajorVersion() uint16 {
21+ return uint16(binary.LittleEndian.Uint16(r.raw[8:]))
22+}
23+func (r QueryVersionReply) MinorVersion() uint16 {
24+ return uint16(binary.LittleEndian.Uint16(r.raw[10:]))
25+}
26+
27+// QueryExtentsReply is a zero-copy view over a QueryExtents reply; offsets count from reply byte 0.
28+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
29+type QueryExtentsReply struct{ raw []byte }
30+
31+// ParseQueryExtentsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
32+func ParseQueryExtentsReply(raw []byte) (QueryExtentsReply, bool) {
33+ if len(raw) < 32 {
34+ return QueryExtentsReply{}, false
35+ }
36+ r := QueryExtentsReply{raw: raw}
37+ return r, true
38+}
39+func (r QueryExtentsReply) Raw() []byte { return r.raw }
40+func (r QueryExtentsReply) BoundingShaped() bool { return (r.raw[8:][0] != 0) }
41+func (r QueryExtentsReply) ClipShaped() bool { return (r.raw[9:][0] != 0) }
42+func (r QueryExtentsReply) BoundingShapeExtentsX() int16 {
43+ return int16(binary.LittleEndian.Uint16(r.raw[12:]))
44+}
45+func (r QueryExtentsReply) BoundingShapeExtentsY() int16 {
46+ return int16(binary.LittleEndian.Uint16(r.raw[14:]))
47+}
48+func (r QueryExtentsReply) BoundingShapeExtentsWidth() uint16 {
49+ return uint16(binary.LittleEndian.Uint16(r.raw[16:]))
50+}
51+func (r QueryExtentsReply) BoundingShapeExtentsHeight() uint16 {
52+ return uint16(binary.LittleEndian.Uint16(r.raw[18:]))
53+}
54+func (r QueryExtentsReply) ClipShapeExtentsX() int16 {
55+ return int16(binary.LittleEndian.Uint16(r.raw[20:]))
56+}
57+func (r QueryExtentsReply) ClipShapeExtentsY() int16 {
58+ return int16(binary.LittleEndian.Uint16(r.raw[22:]))
59+}
60+func (r QueryExtentsReply) ClipShapeExtentsWidth() uint16 {
61+ return uint16(binary.LittleEndian.Uint16(r.raw[24:]))
62+}
63+func (r QueryExtentsReply) ClipShapeExtentsHeight() uint16 {
64+ return uint16(binary.LittleEndian.Uint16(r.raw[26:]))
65+}
66+
67+// InputSelectedReply is a zero-copy view over a InputSelected reply; offsets count from reply byte 0.
68+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
69+type InputSelectedReply struct{ raw []byte }
70+
71+// ParseInputSelectedReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
72+func ParseInputSelectedReply(raw []byte) (InputSelectedReply, bool) {
73+ if len(raw) < 32 {
74+ return InputSelectedReply{}, false
75+ }
76+ r := InputSelectedReply{raw: raw}
77+ return r, true
78+}
79+func (r InputSelectedReply) Raw() []byte { return r.raw }
80+func (r InputSelectedReply) Enabled() bool { return (r.raw[1:][0] != 0) }
81+
82+// GetRectanglesReply is a zero-copy view over a GetRectangles reply; offsets count from reply byte 0.
83+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
84+type GetRectanglesReply struct{ raw []byte }
85+
86+// ParseGetRectanglesReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
87+func ParseGetRectanglesReply(raw []byte) (GetRectanglesReply, bool) {
88+ if len(raw) < 32 {
89+ return GetRectanglesReply{}, false
90+ }
91+ r := GetRectanglesReply{raw: raw}
92+ off := 32
93+ {
94+ n := int(r.RectanglesLen())
95+ if n < 0 || n > len(r.raw) {
96+ return GetRectanglesReply{}, false
97+ }
98+ off += n * 8
99+ }
100+ if off > len(r.raw) {
101+ return GetRectanglesReply{}, false
102+ }
103+ if off > len(r.raw) {
104+ return GetRectanglesReply{}, false
105+ }
106+ return r, true
107+}
108+func (r GetRectanglesReply) Raw() []byte { return r.raw }
109+func (r GetRectanglesReply) Ordering() xproto.ClipOrdering { return xproto.ClipOrdering(r.raw[1:][0]) }
110+func (r GetRectanglesReply) RectanglesLen() uint32 {
111+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
112+}
113+func (r GetRectanglesReply) Rectangles() RectangleList {
114+ off := 32
115+ end := off + (int(r.RectanglesLen()))*8
116+ return RectangleList{b: r.raw[off:end:end]}
117+}
118+
119+// RectangleList is a borrowed view over a wire list of xproto.Rectangle. It shares the lifetime of the bytes it was taken from; copy what you keep.
120+type RectangleList struct{ b []byte }
121+
122+func (l RectangleList) Len() int { return len(l.b) / 8 }
123+func (l RectangleList) At(i int) xproto.Rectangle { return xproto.GetRectangle(l.b[i*8:]) }
A shape/requests_generated.go +214 -0
@@ -0,0 +1,214 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package shape
3+
4+import "bnema.dev/xturbo/xproto"
5+import "encoding/binary"
6+import "bnema.dev/xturbo"
7+
8+func QueryVersion(b *xturbo.Buf) xturbo.Seq {
9+ if b.Ext == nil {
10+ b.Fail(xturbo.ErrExtMissing)
11+ return 0
12+ }
13+ major := b.Ext.Major(xturbo.ExtShape)
14+ if major == 0 {
15+ b.Fail(xturbo.ErrExtMissing)
16+ return 0
17+ }
18+ p, seq := b.Request(major, 0, 0)
19+ if p == nil {
20+ return 0
21+ }
22+ return seq
23+}
24+
25+func Rectangles(b *xturbo.Buf, operation So, destinationKind Sk, ordering xproto.ClipOrdering, destinationWindow xproto.Window, xOffset int16, yOffset int16, rectangles []xproto.Rectangle) xturbo.Seq {
26+ size := 0
27+ size += 1
28+ size += 1
29+ size += 1
30+ size += 1
31+ size += 4
32+ size += 2
33+ size += 2
34+ size += len(rectangles) * 8
35+ size = (size + 3) &^ 3
36+ if b.Ext == nil {
37+ b.Fail(xturbo.ErrExtMissing)
38+ return 0
39+ }
40+ major := b.Ext.Major(xturbo.ExtShape)
41+ if major == 0 {
42+ b.Fail(xturbo.ErrExtMissing)
43+ return 0
44+ }
45+ p, seq := b.Request(major, 1, size)
46+ if p == nil {
47+ return 0
48+ }
49+ off := 0
50+ p[off:][0] = byte(operation)
51+ off += 1
52+ p[off:][0] = byte(destinationKind)
53+ off += 1
54+ p[off:][0] = byte(ordering)
55+ off += 1
56+ off += 1
57+ binary.LittleEndian.PutUint32(p[off:], uint32(destinationWindow))
58+ off += 4
59+ binary.LittleEndian.PutUint16(p[off:], uint16(xOffset))
60+ off += 2
61+ binary.LittleEndian.PutUint16(p[off:], uint16(yOffset))
62+ off += 2
63+ for i := range rectangles {
64+ rectangles[i].Put(p[off:])
65+ off += 8
66+ }
67+ return seq
68+}
69+
70+func Mask(b *xturbo.Buf, operation So, destinationKind Sk, destinationWindow xproto.Window, xOffset int16, yOffset int16, sourceBitmap xproto.Pixmap) xturbo.Seq {
71+ if b.Ext == nil {
72+ b.Fail(xturbo.ErrExtMissing)
73+ return 0
74+ }
75+ major := b.Ext.Major(xturbo.ExtShape)
76+ if major == 0 {
77+ b.Fail(xturbo.ErrExtMissing)
78+ return 0
79+ }
80+ p, seq := b.Request(major, 2, 16)
81+ if p == nil {
82+ return 0
83+ }
84+ p[0:][0] = byte(operation)
85+ p[1:][0] = byte(destinationKind)
86+ binary.LittleEndian.PutUint32(p[4:], uint32(destinationWindow))
87+ binary.LittleEndian.PutUint16(p[8:], uint16(xOffset))
88+ binary.LittleEndian.PutUint16(p[10:], uint16(yOffset))
89+ binary.LittleEndian.PutUint32(p[12:], uint32(sourceBitmap))
90+ return seq
91+}
92+
93+func Combine(b *xturbo.Buf, operation So, destinationKind Sk, sourceKind Sk, destinationWindow xproto.Window, xOffset int16, yOffset int16, sourceWindow xproto.Window) xturbo.Seq {
94+ if b.Ext == nil {
95+ b.Fail(xturbo.ErrExtMissing)
96+ return 0
97+ }
98+ major := b.Ext.Major(xturbo.ExtShape)
99+ if major == 0 {
100+ b.Fail(xturbo.ErrExtMissing)
101+ return 0
102+ }
103+ p, seq := b.Request(major, 3, 16)
104+ if p == nil {
105+ return 0
106+ }
107+ p[0:][0] = byte(operation)
108+ p[1:][0] = byte(destinationKind)
109+ p[2:][0] = byte(sourceKind)
110+ binary.LittleEndian.PutUint32(p[4:], uint32(destinationWindow))
111+ binary.LittleEndian.PutUint16(p[8:], uint16(xOffset))
112+ binary.LittleEndian.PutUint16(p[10:], uint16(yOffset))
113+ binary.LittleEndian.PutUint32(p[12:], uint32(sourceWindow))
114+ return seq
115+}
116+
117+func Offset(b *xturbo.Buf, destinationKind Sk, destinationWindow xproto.Window, xOffset int16, yOffset int16) xturbo.Seq {
118+ if b.Ext == nil {
119+ b.Fail(xturbo.ErrExtMissing)
120+ return 0
121+ }
122+ major := b.Ext.Major(xturbo.ExtShape)
123+ if major == 0 {
124+ b.Fail(xturbo.ErrExtMissing)
125+ return 0
126+ }
127+ p, seq := b.Request(major, 4, 12)
128+ if p == nil {
129+ return 0
130+ }
131+ p[0:][0] = byte(destinationKind)
132+ binary.LittleEndian.PutUint32(p[4:], uint32(destinationWindow))
133+ binary.LittleEndian.PutUint16(p[8:], uint16(xOffset))
134+ binary.LittleEndian.PutUint16(p[10:], uint16(yOffset))
135+ return seq
136+}
137+
138+func QueryExtents(b *xturbo.Buf, destinationWindow xproto.Window) xturbo.Seq {
139+ if b.Ext == nil {
140+ b.Fail(xturbo.ErrExtMissing)
141+ return 0
142+ }
143+ major := b.Ext.Major(xturbo.ExtShape)
144+ if major == 0 {
145+ b.Fail(xturbo.ErrExtMissing)
146+ return 0
147+ }
148+ p, seq := b.Request(major, 5, 4)
149+ if p == nil {
150+ return 0
151+ }
152+ binary.LittleEndian.PutUint32(p[0:], uint32(destinationWindow))
153+ return seq
154+}
155+
156+func SelectInput(b *xturbo.Buf, destinationWindow xproto.Window, enable bool) xturbo.Seq {
157+ if b.Ext == nil {
158+ b.Fail(xturbo.ErrExtMissing)
159+ return 0
160+ }
161+ major := b.Ext.Major(xturbo.ExtShape)
162+ if major == 0 {
163+ b.Fail(xturbo.ErrExtMissing)
164+ return 0
165+ }
166+ p, seq := b.Request(major, 6, 8)
167+ if p == nil {
168+ return 0
169+ }
170+ binary.LittleEndian.PutUint32(p[0:], uint32(destinationWindow))
171+ if enable {
172+ p[4:][0] = 1
173+ } else {
174+ p[4:][0] = 0
175+ }
176+ return seq
177+}
178+
179+func InputSelected(b *xturbo.Buf, destinationWindow xproto.Window) xturbo.Seq {
180+ if b.Ext == nil {
181+ b.Fail(xturbo.ErrExtMissing)
182+ return 0
183+ }
184+ major := b.Ext.Major(xturbo.ExtShape)
185+ if major == 0 {
186+ b.Fail(xturbo.ErrExtMissing)
187+ return 0
188+ }
189+ p, seq := b.Request(major, 7, 4)
190+ if p == nil {
191+ return 0
192+ }
193+ binary.LittleEndian.PutUint32(p[0:], uint32(destinationWindow))
194+ return seq
195+}
196+
197+func GetRectangles(b *xturbo.Buf, window xproto.Window, sourceKind Sk) xturbo.Seq {
198+ if b.Ext == nil {
199+ b.Fail(xturbo.ErrExtMissing)
200+ return 0
201+ }
202+ major := b.Ext.Major(xturbo.ExtShape)
203+ if major == 0 {
204+ b.Fail(xturbo.ErrExtMissing)
205+ return 0
206+ }
207+ p, seq := b.Request(major, 8, 8)
208+ if p == nil {
209+ return 0
210+ }
211+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
212+ p[4:][0] = byte(sourceKind)
213+ return seq
214+}
A shape/sizes_test.go +23 -0
@@ -0,0 +1,23 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package shape
3+
4+import "testing"
5+
6+func TestWireSizes(t *testing.T) {
7+ if got := 32; got != 32 {
8+ t.Errorf("event Notify fixed size = %d", got)
9+ }
10+ if got := 32; got != 32 {
11+ t.Errorf("reply QueryVersion fixed size = %d", got)
12+ }
13+ if got := 32; got != 32 {
14+ t.Errorf("reply QueryExtents fixed size = %d", got)
15+ }
16+ if got := 32; got != 32 {
17+ t.Errorf("reply InputSelected fixed size = %d", got)
18+ }
19+ if got := 32; got != 32 {
20+ t.Errorf("reply GetRectangles fixed size = %d", got)
21+ }
22+
23+}
A shape/types_generated.go +20 -0
@@ -0,0 +1,20 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package shape
3+
4+type Op uint8
5+
6+type Kind uint8
7+
8+type So uint8
9+
10+const SoSet So = 0
11+const SoUnion So = 1
12+const SoIntersect So = 2
13+const SoSubtract So = 3
14+const SoInvert So = 4
15+
16+type Sk uint8
17+
18+const SkBounding Sk = 0
19+const SkClip Sk = 1
20+const SkInput Sk = 2
A testdata/golden/render/CreatePicture.req.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb via raw socketpair tee; independent reference encoder; server accepted
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+8b0408000300200001002000290000003100000001000000fbffffff07000000
A testdata/golden/render/QueryPictFormats.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+01001200cf0200001700000001000000060000001001000000000000000000002300000001010000000000000000000000000000000001000000000024000000010800000000000000000000000000000000ff000000000025000000012000001000ff000800ff000000ff001800ff000000000026000000012000001000ff000800ff000000ff00000000000000000027000000012000000800ff001000ff001800ff000000ff000000000028000000012000000800ff001000ff001800ff00000000000000000029000000011800001000ff000800ff000000ff0000000000000000002a000000011800000000ff000800ff001000ff0000000000000000002b0000000110000008000f0004000f0000000f0000000000000000002c0000000110000000000f0004000f0008000f0000000000000000002d000000011000000a001f0005001f0000001f0000000000000000002e0000000110000000001f0005001f000a001f0000000000000000002f000000011000000a001f0005001f0000001f000f00010000000000300000000110000000001f0005001f000a001f000f0001000000000031000000011000000b001f0005003f0000001f000000000000000000320000000110000000001f0005003f000b001f000000000000000000330000000110000008000f0004000f0000000f000c000f0000000000340000000110000000000f0004000f0008000f000c000f000000000035000000012000000000ff000800ff001000ff00000000000000000036000000012000001400ff030a00ff030000ff031e0003000000000037000000012000001400ff030a00ff030000ff03000000000000000038000000012000000000ff030a00ff031400ff031e0003000000000039000000012000000000ff030a00ff031400ff03000000000000000006000000230000001800000100000000210000002900000022000000290000009102000029000000920200002900000093020000290000009402000029000000950200002900000096020000290000009702000029000000980200002900000099020000290000009a020000290000009b020000290000009c020000290000009d020000290000009e020000290000009f02000029000000a002000029000000a102000029000000a202000029000000a302000029000000a402000029000000a502000029000000a602000029000000a702000029000000a802000029000000a902000029000000aa02000029000000ab02000029000000ac02000029000000ad02000029000000ae02000029000000af02000029000000b002000029000000b102000029000000b202000029000000b302000029000000b402000029000000b502000029000000b602000029000000b702000029000000b802000029000000b902000029000000ba02000029000000bb02000029000000bc02000029000000bd02000029000000be02000029000000bf02000029000000c002000029000000c102000029000000c202000029000000c302000029000000c402000029000000c502000029000000c602000029000000c702000029000000c802000029000000c902000029000000ca02000029000000cb02000029000000cc02000029000000cd02000029000000ce02000029000000cf02000029000000d002000029000000d102000029000000d202000029000000d302000029000000d402000029000000d502000029000000d602000029000000d702000029000000d802000029000000d902000029000000da02000029000000db02000029000000dc02000029000000dd02000029000000de02000029000000df02000029000000e002000029000000e102000029000000e202000029000000e302000029000000e402000029000000e502000029000000e602000029000000e702000029000000e802000029000000e902000029000000ea02000029000000eb02000029000000ec02000029000000ed02000029000000ee02000029000000ef02000029000000f002000029000000f102000029000000f202000029000000f302000029000000f402000029000000f502000029000000f602000029000000f702000029000000f802000029000000f902000029000000fa02000029000000fb02000029000000fc02000029000000fd02000029000000fe02000029000000ff0200002900000000030000290000000103000029000000020300002900000003030000290000000403000029000000050300002900000006030000290000000703000029000000080300002900000009030000290000000a030000290000000b030000290000000c030000290000000d030000290000000e030000290000000f0300002900000010030000290000001103000029000000120300002900000013030000290000001403000029000000150300002900000016030000290000001703000029000000180300002900000019030000290000001a030000290000001b030000290000001c030000290000001d030000290000001e030000290000001f0300002900000020030000290000002103000029000000220300002900000023030000290000002403000029000000250300002900000026030000290000002703000029000000280300002900000029030000290000002a030000290000002b030000290000002c030000290000002d030000290000002e030000290000002f0300002900000030030000290000003103000029000000320300002900000033030000290000003403000029000000350300002900000036030000290000003703000029000000380300002900000039030000290000003a030000290000003b030000290000003c030000290000003d030000290000003e030000290000003f0300002900000040030000290000004103000029000000420300002900000043030000290000004403000029000000450300002900000046030000290000004703000029000000480300002900000049030000290000004a030000290000004b030000290000004c030000290000004d030000290000004e030000290000004f0300002900000050030000290000005103000029000000520300002900000053030000290000005403000029000000550300002900000056030000290000005703000029000000580300002900000059030000290000005a030000290000005b030000290000005c030000290000005d030000290000005e030000290000005f0300002900000060030000290000006103000029000000620300002900000063030000290000006403000029000000650300002900000066030000290000006703000029000000680300002900000069030000290000006a030000290000006b030000290000006c030000290000006d030000290000006e030000290000006f0300002900000070030000290000007103000029000000720300002900000073030000290000007403000029000000750300002900000076030000290000007703000029000000780300002900000079030000290000007a030000290000007b030000290000007c030000290000007d030000290000007e030000290000007f0300002900000080030000290000008103000029000000820300002900000083030000290000008403000029000000850300002900000086030000290000008703000029000000880300002900000089030000290000008a030000290000008b030000290000008c030000290000008d030000290000008e030000290000000100000000000000040000000000000008000000000000001000000000000000200010000000000040000000250000008f0300002500000090030000250000009103000025000000920300002500000093030000250000009403000025000000950300002500000096030000250000009703000025000000980300002500000099030000250000009a030000250000009b030000250000009c030000250000009d03000025000000
A testdata/golden/res/QueryClientIds.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+01000a0006000000020000000000000000000000000000000000000000000000000000000100000000000000000020000100000000000000
A testdata/golden/res/QueryClientIds.req.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb via raw socketpair tee; independent reference encoder; server accepted
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+94040400010000000000000001000000
A testdata/golden/xfixes/QueryVersion.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+0100020000000000060000000000000000000000000000000000000000000000
A testdata/golden/xfixes/QueryVersion.req.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb via raw socketpair tee; independent reference encoder; server accepted
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+8a0003000600000000000000
A testdata/golden/xproto/ChangeProperty.req.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb via raw socketpair tee; independent reference encoder; server accepted
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+120007009f030000e70000001f000000080000000300000061626300
A testdata/golden/xproto/ChangeWindowAttributes.req.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb via raw socketpair tee; independent reference encoder; server accepted
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+0200050001002000000600000000000001000000
A testdata/golden/xproto/ConfigureWindow.req.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb via raw socketpair tee; independent reference encoder; server accepted
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+0c0003000100200000000000
A testdata/golden/xproto/ConfigureWindowAll.req.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb via raw socketpair tee; independent reference encoder; server accepted
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+0c000a00010020007f000000fdffffff090000006000000048000000020000000200200000000000
A testdata/golden/xproto/ConfigureWindowSparse.req.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb via raw socketpair tee; independent reference encoder; server accepted
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+0c0006000100200045000000f9ffffff5000000000000000
A testdata/golden/xproto/CreateWindow.req.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb via raw socketpair tee; independent reference encoder; server accepted
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+01000b00010020009f0300000000000040003000000001000000000002060000563412000100000000000000
A testdata/golden/xproto/GetGeometry.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+01180400000000009f0300000000000020035802000000000000000000000000
A testdata/golden/xproto/GetGeometry.req.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb via raw socketpair tee; independent reference encoder; server accepted
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+0e0002009f030000
A testdata/golden/xproto/GetProperty.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+01080700010000001f000000000000000300000000000000000000000000000061626300
A testdata/golden/xproto/GetPropertyEmpty.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+0100170000000000000000000000000000000000000000000000000000000000
A testdata/golden/xproto/GetWindowAttributes.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+01001500030000002100000001000001ffffffff000000000101000020000000000000000000000000000000
A testdata/golden/xproto/InternAtom.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+0100050000000000e70000000000000000000000000000000000000000000000
A testdata/golden/xproto/InternAtom.req.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb via raw socketpair tee; independent reference encoder; server accepted
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+100004000700000058545552424f5f00
A testdata/golden/xproto/ListExtensions.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+01171800370000000000000000000000000000000000000000000000000000001747656e65726963204576656e7420457874656e73696f6e055348415045074d49542d53484d0f58496e707574457874656e73696f6e0558544553540c4249472d52455155455354530453594e4309584b4559424f4152440758432d4d495343085345435552495459065846495845530652454e4445520552414e44520858494e4552414d4109436f6d706f736974650644414d414745104d49542d53435245454e2d53415645520d444f55424c452d425546464552065245434f52440750726573656e740a582d5265736f757263650658566964656f03474c5800
A testdata/golden/xproto/MapWindow.req.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb via raw socketpair tee; independent reference encoder; server accepted
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+080002009f030000
A testdata/golden/xproto/QueryExtension.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+0100010000000000018a578c0000000000000000000000000000000000000000
A testdata/golden/xproto/QueryTree.reply.hex +3 -0
@@ -0,0 +1,3 @@
1+# source: Xvfb reply via raw socketpair tee to an independent reference request
2+# xtrace fallback: local xtrace is glibc's execution tracer, not X11 xtrace
3+01001600020000009f03000000000000020000000000000000000000000000000200200001002000
A values_test.go +103 -0
@@ -0,0 +1,103 @@
1+package xturbo_test
2+
3+import (
4+ "bytes"
5+ "encoding/binary"
6+ "testing"
7+
8+ "bnema.dev/xturbo"
9+ "bnema.dev/xturbo/internal/xtest"
10+ "bnema.dev/xturbo/render"
11+ "bnema.dev/xturbo/xproto"
12+)
13+
14+func TestValueRequestGoldens(t *testing.T) {
15+ for _, name := range []string{"xproto/ConfigureWindow", "xproto/ConfigureWindowSparse", "xproto/ConfigureWindowAll", "xproto/CreateWindow", "xproto/ChangeWindowAttributes", "render/CreatePicture"} {
16+ t.Run(name, func(t *testing.T) {
17+ want, err := xtest.LoadHex("testdata/golden/" + name + ".req.hex")
18+ if err != nil {
19+ t.Fatal(err)
20+ }
21+ u32 := func(off int) uint32 { return binary.LittleEndian.Uint32(want[off:]) }
22+ b := xturbo.NewBuf(0)
23+ var seq xturbo.Seq
24+ switch name {
25+ case "xproto/ConfigureWindow":
26+ seq = xproto.ConfigureWindow(b, xproto.Window(u32(4)), &xproto.ConfigureWindowValues{})
27+ case "xproto/ConfigureWindowSparse":
28+ var v xproto.ConfigureWindowValues
29+ if v.SetStackMode(xproto.StackModeAbove).SetWidth(80).SetX(-7) != &v {
30+ t.Fatal("setter chaining")
31+ }
32+ seq = xproto.ConfigureWindow(b, xproto.Window(u32(4)), &v)
33+ case "xproto/ConfigureWindowAll":
34+ var v xproto.ConfigureWindowValues
35+ v.SetStackMode(xproto.StackModeAbove).SetSibling(xproto.Window(u32(32))).SetBorderWidth(2).SetHeight(72).SetWidth(96).SetY(9).SetX(-3)
36+ seq = xproto.ConfigureWindow(b, xproto.Window(u32(4)), &v)
37+ case "xproto/CreateWindow":
38+ var v xproto.CreateWindowValues
39+ v.SetSaveUnder(false).SetOverrideRedirect(true).SetBackgroundPixel(0x123456)
40+ seq = xproto.CreateWindow(b, 0, xproto.Window(u32(4)), xproto.Window(u32(8)), 0, 0, 64, 48, 0, xproto.WindowClassInputOutput, 0, &v)
41+ case "xproto/ChangeWindowAttributes":
42+ var v xproto.ChangeWindowAttributesValues
43+ v.SetSaveUnder(true).SetOverrideRedirect(false)
44+ seq = xproto.ChangeWindowAttributes(b, xproto.Window(u32(4)), &v)
45+ case "render/CreatePicture":
46+ var ext xturbo.ExtTable
47+ ext.Set(xturbo.ExtRender, want[0], 0, 0)
48+ b.Ext = &ext
49+ var v render.CreatePictureValues
50+ v.SetClipyorigin(7).SetClipxorigin(-5).SetRepeat(render.RepeatNormal)
51+ seq = render.CreatePicture(b, render.Picture(u32(4)), xproto.Drawable(u32(8)), render.Pictformat(u32(12)), &v)
52+ }
53+ if seq != 1 || b.Err() != nil {
54+ t.Fatalf("seq=%d err=%v", seq, b.Err())
55+ }
56+ if !bytes.Equal(b.Bytes(), want) {
57+ t.Fatalf("got %x want %x", b.Bytes(), want)
58+ }
59+ })
60+ }
61+}
62+
63+func TestAllocValueRequests(t *testing.T) {
64+ b := xturbo.NewBuf(0)
65+ var ext xturbo.ExtTable
66+ ext.Set(xturbo.ExtRender, 139, 0, 0)
67+ b.Ext = &ext
68+ var v xproto.ConfigureWindowValues
69+ v.SetX(-1).SetY(-2).SetWidth(800).SetHeight(600).SetBorderWidth(1).SetSibling(2).SetStackMode(xproto.StackModeAbove)
70+ var create xproto.CreateWindowValues
71+ create.SetOverrideRedirect(true).SetSaveUnder(false)
72+ var change xproto.ChangeWindowAttributesValues
73+ change.SetOverrideRedirect(false).SetSaveUnder(true)
74+ var pic render.CreatePictureValues
75+ pic.SetRepeat(render.RepeatNormal).SetClipxorigin(-1)
76+ if n := testing.AllocsPerRun(1000, func() {
77+ b.Reset()
78+ xproto.ConfigureWindow(b, 1, &v)
79+ xproto.CreateWindow(b, 0, 1, 2, 0, 0, 80, 60, 0, xproto.WindowClassInputOutput, 0, &create)
80+ xproto.ChangeWindowAttributes(b, 1, &change)
81+ render.CreatePicture(b, 1, 1, 1, &pic)
82+ }); n != 0 {
83+ t.Fatal(n)
84+ }
85+ if b.Err() != nil {
86+ t.Fatal(b.Err())
87+ }
88+}
89+
90+func TestValueRequestFailures(t *testing.T) {
91+ b := xturbo.NewBuf(0)
92+ b.Fail(xturbo.ErrBadLength)
93+ if xproto.ConfigureWindow(b, 1, &xproto.ConfigureWindowValues{}) != 0 || b.Len() != 0 || b.Err() != xturbo.ErrBadLength {
94+ t.Fatal("sticky error")
95+ }
96+ for _, ext := range []*xturbo.ExtTable{nil, {}} {
97+ b := xturbo.NewBuf(0)
98+ b.Ext = ext
99+ if render.CreatePicture(b, 1, 1, 1, &render.CreatePictureValues{}) != 0 || b.Err() != xturbo.ErrExtMissing || b.Len() != 0 {
100+ t.Fatal("missing extension")
101+ }
102+ }
103+}
A xcmisc/replies_fuzz_test.go +60 -0
@@ -0,0 +1,60 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xcmisc
3+
4+import "testing"
5+
6+func FuzzParseGetVersionReply(f *testing.F) {
7+ f.Add(make([]byte, 32))
8+ f.Fuzz(func(t *testing.T, raw []byte) {
9+ r, ok := ParseGetVersionReply(raw)
10+ if !ok {
11+ if len(raw) >= 32 {
12+ t.Fatal("rejected a complete fixed-size reply")
13+ }
14+ return
15+ }
16+ if len(r.Raw()) != len(raw) {
17+ t.Fatal("Raw must return the parsed bytes")
18+ }
19+ _ = r.ServerMajorVersion()
20+ _ = r.ServerMinorVersion()
21+ })
22+}
23+
24+func FuzzParseGetXIDRangeReply(f *testing.F) {
25+ f.Add(make([]byte, 32))
26+ f.Fuzz(func(t *testing.T, raw []byte) {
27+ r, ok := ParseGetXIDRangeReply(raw)
28+ if !ok {
29+ if len(raw) >= 32 {
30+ t.Fatal("rejected a complete fixed-size reply")
31+ }
32+ return
33+ }
34+ if len(r.Raw()) != len(raw) {
35+ t.Fatal("Raw must return the parsed bytes")
36+ }
37+ _ = r.StartId()
38+ _ = r.Count()
39+ })
40+}
41+
42+func FuzzParseGetXIDListReply(f *testing.F) {
43+ f.Add(make([]byte, 32))
44+ f.Fuzz(func(t *testing.T, raw []byte) {
45+ r, ok := ParseGetXIDListReply(raw)
46+ if !ok {
47+ return
48+ }
49+ if len(r.Raw()) != len(raw) {
50+ t.Fatal("Raw must return the parsed bytes")
51+ }
52+ _ = r.IdsLen()
53+ {
54+ l0 := r.Ids()
55+ for i := 0; i < l0.Len(); i++ {
56+ _ = l0.At(i)
57+ }
58+ }
59+ })
60+}
A xcmisc/replies_generated.go +80 -0
@@ -0,0 +1,80 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xcmisc
3+
4+import "encoding/binary"
5+
6+// GetVersionReply is a zero-copy view over a GetVersion reply; offsets count from reply byte 0.
7+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
8+type GetVersionReply struct{ raw []byte }
9+
10+// ParseGetVersionReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
11+func ParseGetVersionReply(raw []byte) (GetVersionReply, bool) {
12+ if len(raw) < 32 {
13+ return GetVersionReply{}, false
14+ }
15+ r := GetVersionReply{raw: raw}
16+ return r, true
17+}
18+func (r GetVersionReply) Raw() []byte { return r.raw }
19+func (r GetVersionReply) ServerMajorVersion() uint16 {
20+ return uint16(binary.LittleEndian.Uint16(r.raw[8:]))
21+}
22+func (r GetVersionReply) ServerMinorVersion() uint16 {
23+ return uint16(binary.LittleEndian.Uint16(r.raw[10:]))
24+}
25+
26+// GetXIDRangeReply is a zero-copy view over a GetXIDRange reply; offsets count from reply byte 0.
27+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
28+type GetXIDRangeReply struct{ raw []byte }
29+
30+// ParseGetXIDRangeReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
31+func ParseGetXIDRangeReply(raw []byte) (GetXIDRangeReply, bool) {
32+ if len(raw) < 32 {
33+ return GetXIDRangeReply{}, false
34+ }
35+ r := GetXIDRangeReply{raw: raw}
36+ return r, true
37+}
38+func (r GetXIDRangeReply) Raw() []byte { return r.raw }
39+func (r GetXIDRangeReply) StartId() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[8:])) }
40+func (r GetXIDRangeReply) Count() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[12:])) }
41+
42+// GetXIDListReply is a zero-copy view over a GetXIDList reply; offsets count from reply byte 0.
43+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
44+type GetXIDListReply struct{ raw []byte }
45+
46+// ParseGetXIDListReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
47+func ParseGetXIDListReply(raw []byte) (GetXIDListReply, bool) {
48+ if len(raw) < 32 {
49+ return GetXIDListReply{}, false
50+ }
51+ r := GetXIDListReply{raw: raw}
52+ off := 32
53+ {
54+ n := int(r.IdsLen())
55+ if n < 0 || n > len(r.raw) {
56+ return GetXIDListReply{}, false
57+ }
58+ off += n * 4
59+ }
60+ if off > len(r.raw) {
61+ return GetXIDListReply{}, false
62+ }
63+ if off > len(r.raw) {
64+ return GetXIDListReply{}, false
65+ }
66+ return r, true
67+}
68+func (r GetXIDListReply) Raw() []byte { return r.raw }
69+func (r GetXIDListReply) IdsLen() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[8:])) }
70+func (r GetXIDListReply) Ids() Uint32List {
71+ off := 32
72+ end := off + (int(r.IdsLen()))*4
73+ return Uint32List{b: r.raw[off:end:end]}
74+}
75+
76+// Uint32List is a borrowed view over a wire list of uint32. It shares the lifetime of the bytes it was taken from; copy what you keep.
77+type Uint32List struct{ b []byte }
78+
79+func (l Uint32List) Len() int { return len(l.b) / 4 }
80+func (l Uint32List) At(i int) uint32 { return uint32(binary.LittleEndian.Uint32(l.b[i*4:])) }
A xcmisc/requests_generated.go +59 -0
@@ -0,0 +1,59 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xcmisc
3+
4+import "encoding/binary"
5+import "bnema.dev/xturbo"
6+
7+func GetVersion(b *xturbo.Buf, clientMajorVersion uint16, clientMinorVersion uint16) xturbo.Seq {
8+ if b.Ext == nil {
9+ b.Fail(xturbo.ErrExtMissing)
10+ return 0
11+ }
12+ major := b.Ext.Major(xturbo.ExtXCMisc)
13+ if major == 0 {
14+ b.Fail(xturbo.ErrExtMissing)
15+ return 0
16+ }
17+ p, seq := b.Request(major, 0, 4)
18+ if p == nil {
19+ return 0
20+ }
21+ binary.LittleEndian.PutUint16(p[0:], uint16(clientMajorVersion))
22+ binary.LittleEndian.PutUint16(p[2:], uint16(clientMinorVersion))
23+ return seq
24+}
25+
26+func GetXIDRange(b *xturbo.Buf) xturbo.Seq {
27+ if b.Ext == nil {
28+ b.Fail(xturbo.ErrExtMissing)
29+ return 0
30+ }
31+ major := b.Ext.Major(xturbo.ExtXCMisc)
32+ if major == 0 {
33+ b.Fail(xturbo.ErrExtMissing)
34+ return 0
35+ }
36+ p, seq := b.Request(major, 1, 0)
37+ if p == nil {
38+ return 0
39+ }
40+ return seq
41+}
42+
43+func GetXIDList(b *xturbo.Buf, count uint32) xturbo.Seq {
44+ if b.Ext == nil {
45+ b.Fail(xturbo.ErrExtMissing)
46+ return 0
47+ }
48+ major := b.Ext.Major(xturbo.ExtXCMisc)
49+ if major == 0 {
50+ b.Fail(xturbo.ErrExtMissing)
51+ return 0
52+ }
53+ p, seq := b.Request(major, 2, 4)
54+ if p == nil {
55+ return 0
56+ }
57+ binary.LittleEndian.PutUint32(p[0:], uint32(count))
58+ return seq
59+}
A xcmisc/sizes_test.go +17 -0
@@ -0,0 +1,17 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xcmisc
3+
4+import "testing"
5+
6+func TestWireSizes(t *testing.T) {
7+ if got := 32; got != 32 {
8+ t.Errorf("reply GetVersion fixed size = %d", got)
9+ }
10+ if got := 32; got != 32 {
11+ t.Errorf("reply GetXIDRange fixed size = %d", got)
12+ }
13+ if got := 32; got != 32 {
14+ t.Errorf("reply GetXIDList fixed size = %d", got)
15+ }
16+
17+}
A xcmisc/types_generated.go +2 -0
@@ -0,0 +1,2 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xcmisc
A xfixes/replies_fuzz_test.go +136 -0
@@ -0,0 +1,136 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xfixes
3+
4+import "testing"
5+import "bnema.dev/xturbo/internal/xtest"
6+
7+func FuzzParseQueryVersionReply(f *testing.F) {
8+ f.Add(make([]byte, 32))
9+ if raw, err := xtest.LoadHex("../testdata/golden/xfixes/QueryVersion.reply.hex"); err != nil {
10+ f.Fatal(err)
11+ } else {
12+ f.Add(raw)
13+ }
14+ f.Fuzz(func(t *testing.T, raw []byte) {
15+ r, ok := ParseQueryVersionReply(raw)
16+ if !ok {
17+ if len(raw) >= 32 {
18+ t.Fatal("rejected a complete fixed-size reply")
19+ }
20+ return
21+ }
22+ if len(r.Raw()) != len(raw) {
23+ t.Fatal("Raw must return the parsed bytes")
24+ }
25+ _ = r.MajorVersion()
26+ _ = r.MinorVersion()
27+ })
28+}
29+
30+func FuzzParseGetCursorImageReply(f *testing.F) {
31+ f.Add(make([]byte, 32))
32+ f.Fuzz(func(t *testing.T, raw []byte) {
33+ r, ok := ParseGetCursorImageReply(raw)
34+ if !ok {
35+ return
36+ }
37+ if len(r.Raw()) != len(raw) {
38+ t.Fatal("Raw must return the parsed bytes")
39+ }
40+ _ = r.X()
41+ _ = r.Y()
42+ _ = r.Width()
43+ _ = r.Height()
44+ _ = r.Xhot()
45+ _ = r.Yhot()
46+ _ = r.CursorSerial()
47+ {
48+ l0 := r.CursorImage()
49+ for i := 0; i < l0.Len(); i++ {
50+ _ = l0.At(i)
51+ }
52+ }
53+ })
54+}
55+
56+func FuzzParseFetchRegionReply(f *testing.F) {
57+ f.Add(make([]byte, 32))
58+ f.Fuzz(func(t *testing.T, raw []byte) {
59+ r, ok := ParseFetchRegionReply(raw)
60+ if !ok {
61+ return
62+ }
63+ if len(r.Raw()) != len(raw) {
64+ t.Fatal("Raw must return the parsed bytes")
65+ }
66+ _ = r.Extents()
67+ {
68+ l0 := r.Rectangles()
69+ for i := 0; i < l0.Len(); i++ {
70+ _ = l0.At(i)
71+ }
72+ }
73+ })
74+}
75+
76+func FuzzParseGetCursorNameReply(f *testing.F) {
77+ f.Add(make([]byte, 32))
78+ f.Fuzz(func(t *testing.T, raw []byte) {
79+ r, ok := ParseGetCursorNameReply(raw)
80+ if !ok {
81+ return
82+ }
83+ if len(r.Raw()) != len(raw) {
84+ t.Fatal("Raw must return the parsed bytes")
85+ }
86+ _ = r.Atom()
87+ _ = r.Nbytes()
88+ _ = len(r.Name())
89+ })
90+}
91+
92+func FuzzParseGetCursorImageAndNameReply(f *testing.F) {
93+ f.Add(make([]byte, 32))
94+ f.Fuzz(func(t *testing.T, raw []byte) {
95+ r, ok := ParseGetCursorImageAndNameReply(raw)
96+ if !ok {
97+ return
98+ }
99+ if len(r.Raw()) != len(raw) {
100+ t.Fatal("Raw must return the parsed bytes")
101+ }
102+ _ = r.X()
103+ _ = r.Y()
104+ _ = r.Width()
105+ _ = r.Height()
106+ _ = r.Xhot()
107+ _ = r.Yhot()
108+ _ = r.CursorSerial()
109+ _ = r.CursorAtom()
110+ _ = r.Nbytes()
111+ {
112+ l0 := r.CursorImage()
113+ for i := 0; i < l0.Len(); i++ {
114+ _ = l0.At(i)
115+ }
116+ }
117+ _ = len(r.Name())
118+ })
119+}
120+
121+func FuzzParseGetClientDisconnectModeReply(f *testing.F) {
122+ f.Add(make([]byte, 32))
123+ f.Fuzz(func(t *testing.T, raw []byte) {
124+ r, ok := ParseGetClientDisconnectModeReply(raw)
125+ if !ok {
126+ if len(raw) >= 32 {
127+ t.Fatal("rejected a complete fixed-size reply")
128+ }
129+ return
130+ }
131+ if len(r.Raw()) != len(raw) {
132+ t.Fatal("Raw must return the parsed bytes")
133+ }
134+ _ = r.DisconnectMode()
135+ })
136+}
A xfixes/replies_generated.go +242 -0
@@ -0,0 +1,242 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xfixes
3+
4+import "bnema.dev/xturbo/xproto"
5+import "encoding/binary"
6+
7+// QueryVersionReply is a zero-copy view over a QueryVersion reply; offsets count from reply byte 0.
8+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
9+type QueryVersionReply struct{ raw []byte }
10+
11+// ParseQueryVersionReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
12+func ParseQueryVersionReply(raw []byte) (QueryVersionReply, bool) {
13+ if len(raw) < 32 {
14+ return QueryVersionReply{}, false
15+ }
16+ r := QueryVersionReply{raw: raw}
17+ return r, true
18+}
19+func (r QueryVersionReply) Raw() []byte { return r.raw }
20+func (r QueryVersionReply) MajorVersion() uint32 {
21+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
22+}
23+func (r QueryVersionReply) MinorVersion() uint32 {
24+ return uint32(binary.LittleEndian.Uint32(r.raw[12:]))
25+}
26+
27+// GetCursorImageReply is a zero-copy view over a GetCursorImage reply; offsets count from reply byte 0.
28+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
29+type GetCursorImageReply struct{ raw []byte }
30+
31+// ParseGetCursorImageReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
32+func ParseGetCursorImageReply(raw []byte) (GetCursorImageReply, bool) {
33+ if len(raw) < 32 {
34+ return GetCursorImageReply{}, false
35+ }
36+ r := GetCursorImageReply{raw: raw}
37+ off := 32
38+ {
39+ n := (int(r.Width()) * int(r.Height()))
40+ if n < 0 || n > len(r.raw) {
41+ return GetCursorImageReply{}, false
42+ }
43+ off += n * 4
44+ }
45+ if off > len(r.raw) {
46+ return GetCursorImageReply{}, false
47+ }
48+ if off > len(r.raw) {
49+ return GetCursorImageReply{}, false
50+ }
51+ return r, true
52+}
53+func (r GetCursorImageReply) Raw() []byte { return r.raw }
54+func (r GetCursorImageReply) X() int16 { return int16(binary.LittleEndian.Uint16(r.raw[8:])) }
55+func (r GetCursorImageReply) Y() int16 { return int16(binary.LittleEndian.Uint16(r.raw[10:])) }
56+func (r GetCursorImageReply) Width() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[12:])) }
57+func (r GetCursorImageReply) Height() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[14:])) }
58+func (r GetCursorImageReply) Xhot() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[16:])) }
59+func (r GetCursorImageReply) Yhot() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[18:])) }
60+func (r GetCursorImageReply) CursorSerial() uint32 {
61+ return uint32(binary.LittleEndian.Uint32(r.raw[20:]))
62+}
63+func (r GetCursorImageReply) CursorImage() Uint32List {
64+ off := 32
65+ end := off + (int(r.Width())*int(r.Height()))*4
66+ return Uint32List{b: r.raw[off:end:end]}
67+}
68+
69+// FetchRegionReply is a zero-copy view over a FetchRegion reply; offsets count from reply byte 0.
70+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
71+type FetchRegionReply struct{ raw []byte }
72+
73+// ParseFetchRegionReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
74+func ParseFetchRegionReply(raw []byte) (FetchRegionReply, bool) {
75+ if len(raw) < 32 {
76+ return FetchRegionReply{}, false
77+ }
78+ r := FetchRegionReply{raw: raw}
79+ off := 32
80+ {
81+ n := (int(binary.LittleEndian.Uint32(r.raw[4:])) / 2)
82+ if n < 0 || n > len(r.raw) {
83+ return FetchRegionReply{}, false
84+ }
85+ off += n * 8
86+ }
87+ if off > len(r.raw) {
88+ return FetchRegionReply{}, false
89+ }
90+ if off > len(r.raw) {
91+ return FetchRegionReply{}, false
92+ }
93+ return r, true
94+}
95+func (r FetchRegionReply) Raw() []byte { return r.raw }
96+func (r FetchRegionReply) Extents() xproto.Rectangle { return xproto.GetRectangle(r.raw[8:]) }
97+func (r FetchRegionReply) Rectangles() RectangleList {
98+ off := 32
99+ end := off + (int(binary.LittleEndian.Uint32(r.raw[4:]))/2)*8
100+ return RectangleList{b: r.raw[off:end:end]}
101+}
102+
103+// GetCursorNameReply is a zero-copy view over a GetCursorName reply; offsets count from reply byte 0.
104+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
105+type GetCursorNameReply struct{ raw []byte }
106+
107+// ParseGetCursorNameReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
108+func ParseGetCursorNameReply(raw []byte) (GetCursorNameReply, bool) {
109+ if len(raw) < 32 {
110+ return GetCursorNameReply{}, false
111+ }
112+ r := GetCursorNameReply{raw: raw}
113+ off := 32
114+ {
115+ n := int(r.Nbytes())
116+ if n < 0 || n > len(r.raw) {
117+ return GetCursorNameReply{}, false
118+ }
119+ off += n * 1
120+ }
121+ if off > len(r.raw) {
122+ return GetCursorNameReply{}, false
123+ }
124+ if off > len(r.raw) {
125+ return GetCursorNameReply{}, false
126+ }
127+ return r, true
128+}
129+func (r GetCursorNameReply) Raw() []byte { return r.raw }
130+func (r GetCursorNameReply) Atom() xproto.Atom {
131+ return xproto.Atom(binary.LittleEndian.Uint32(r.raw[8:]))
132+}
133+func (r GetCursorNameReply) Nbytes() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[12:])) }
134+func (r GetCursorNameReply) Name() []byte {
135+ off := 32
136+ end := off + int(r.Nbytes())
137+ return r.raw[off:end:end]
138+}
139+
140+// GetCursorImageAndNameReply is a zero-copy view over a GetCursorImageAndName reply; offsets count from reply byte 0.
141+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
142+type GetCursorImageAndNameReply struct{ raw []byte }
143+
144+// ParseGetCursorImageAndNameReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
145+func ParseGetCursorImageAndNameReply(raw []byte) (GetCursorImageAndNameReply, bool) {
146+ if len(raw) < 32 {
147+ return GetCursorImageAndNameReply{}, false
148+ }
149+ r := GetCursorImageAndNameReply{raw: raw}
150+ off := 32
151+ {
152+ n := (int(r.Width()) * int(r.Height()))
153+ if n < 0 || n > len(r.raw) {
154+ return GetCursorImageAndNameReply{}, false
155+ }
156+ off += n * 4
157+ }
158+ if off > len(r.raw) {
159+ return GetCursorImageAndNameReply{}, false
160+ }
161+ {
162+ n := int(r.Nbytes())
163+ if n < 0 || n > len(r.raw) {
164+ return GetCursorImageAndNameReply{}, false
165+ }
166+ off += n * 1
167+ }
168+ if off > len(r.raw) {
169+ return GetCursorImageAndNameReply{}, false
170+ }
171+ if off > len(r.raw) {
172+ return GetCursorImageAndNameReply{}, false
173+ }
174+ return r, true
175+}
176+func (r GetCursorImageAndNameReply) Raw() []byte { return r.raw }
177+func (r GetCursorImageAndNameReply) X() int16 { return int16(binary.LittleEndian.Uint16(r.raw[8:])) }
178+func (r GetCursorImageAndNameReply) Y() int16 { return int16(binary.LittleEndian.Uint16(r.raw[10:])) }
179+func (r GetCursorImageAndNameReply) Width() uint16 {
180+ return uint16(binary.LittleEndian.Uint16(r.raw[12:]))
181+}
182+func (r GetCursorImageAndNameReply) Height() uint16 {
183+ return uint16(binary.LittleEndian.Uint16(r.raw[14:]))
184+}
185+func (r GetCursorImageAndNameReply) Xhot() uint16 {
186+ return uint16(binary.LittleEndian.Uint16(r.raw[16:]))
187+}
188+func (r GetCursorImageAndNameReply) Yhot() uint16 {
189+ return uint16(binary.LittleEndian.Uint16(r.raw[18:]))
190+}
191+func (r GetCursorImageAndNameReply) CursorSerial() uint32 {
192+ return uint32(binary.LittleEndian.Uint32(r.raw[20:]))
193+}
194+func (r GetCursorImageAndNameReply) CursorAtom() xproto.Atom {
195+ return xproto.Atom(binary.LittleEndian.Uint32(r.raw[24:]))
196+}
197+func (r GetCursorImageAndNameReply) Nbytes() uint16 {
198+ return uint16(binary.LittleEndian.Uint16(r.raw[28:]))
199+}
200+func (r GetCursorImageAndNameReply) CursorImage() Uint32List {
201+ off := 32
202+ end := off + (int(r.Width())*int(r.Height()))*4
203+ return Uint32List{b: r.raw[off:end:end]}
204+}
205+func (r GetCursorImageAndNameReply) Name() []byte {
206+ off := 32
207+ {
208+ n := (int(r.Width()) * int(r.Height()))
209+ off += n * 4
210+ }
211+ end := off + int(r.Nbytes())
212+ return r.raw[off:end:end]
213+}
214+
215+// GetClientDisconnectModeReply is a zero-copy view over a GetClientDisconnectMode reply; offsets count from reply byte 0.
216+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
217+type GetClientDisconnectModeReply struct{ raw []byte }
218+
219+// ParseGetClientDisconnectModeReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
220+func ParseGetClientDisconnectModeReply(raw []byte) (GetClientDisconnectModeReply, bool) {
221+ if len(raw) < 32 {
222+ return GetClientDisconnectModeReply{}, false
223+ }
224+ r := GetClientDisconnectModeReply{raw: raw}
225+ return r, true
226+}
227+func (r GetClientDisconnectModeReply) Raw() []byte { return r.raw }
228+func (r GetClientDisconnectModeReply) DisconnectMode() ClientDisconnectFlags {
229+ return ClientDisconnectFlags(binary.LittleEndian.Uint32(r.raw[8:]))
230+}
231+
232+// RectangleList is a borrowed view over a wire list of xproto.Rectangle. It shares the lifetime of the bytes it was taken from; copy what you keep.
233+type RectangleList struct{ b []byte }
234+
235+func (l RectangleList) Len() int { return len(l.b) / 8 }
236+func (l RectangleList) At(i int) xproto.Rectangle { return xproto.GetRectangle(l.b[i*8:]) }
237+
238+// Uint32List is a borrowed view over a wire list of uint32. It shares the lifetime of the bytes it was taken from; copy what you keep.
239+type Uint32List struct{ b []byte }
240+
241+func (l Uint32List) Len() int { return len(l.b) / 4 }
242+func (l Uint32List) At(i int) uint32 { return uint32(binary.LittleEndian.Uint32(l.b[i*4:])) }
A xfixes/requests_generated.go +766 -0
@@ -0,0 +1,766 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xfixes
3+
4+import "bnema.dev/xturbo/render"
5+import "bnema.dev/xturbo/shape"
6+import "bnema.dev/xturbo/xproto"
7+import "encoding/binary"
8+import "bnema.dev/xturbo"
9+
10+func QueryVersion(b *xturbo.Buf, clientMajorVersion uint32, clientMinorVersion uint32) xturbo.Seq {
11+ if b.Ext == nil {
12+ b.Fail(xturbo.ErrExtMissing)
13+ return 0
14+ }
15+ major := b.Ext.Major(xturbo.ExtXFixes)
16+ if major == 0 {
17+ b.Fail(xturbo.ErrExtMissing)
18+ return 0
19+ }
20+ p, seq := b.Request(major, 0, 8)
21+ if p == nil {
22+ return 0
23+ }
24+ binary.LittleEndian.PutUint32(p[0:], uint32(clientMajorVersion))
25+ binary.LittleEndian.PutUint32(p[4:], uint32(clientMinorVersion))
26+ return seq
27+}
28+
29+func ChangeSaveSet(b *xturbo.Buf, mode SaveSetMode, target SaveSetTarget, map_ SaveSetMapping, window xproto.Window) xturbo.Seq {
30+ if b.Ext == nil {
31+ b.Fail(xturbo.ErrExtMissing)
32+ return 0
33+ }
34+ major := b.Ext.Major(xturbo.ExtXFixes)
35+ if major == 0 {
36+ b.Fail(xturbo.ErrExtMissing)
37+ return 0
38+ }
39+ p, seq := b.Request(major, 1, 8)
40+ if p == nil {
41+ return 0
42+ }
43+ p[0:][0] = byte(mode)
44+ p[1:][0] = byte(target)
45+ p[2:][0] = byte(map_)
46+ binary.LittleEndian.PutUint32(p[4:], uint32(window))
47+ return seq
48+}
49+
50+func SelectSelectionInput(b *xturbo.Buf, window xproto.Window, selection xproto.Atom, eventMask SelectionEventMask) xturbo.Seq {
51+ if b.Ext == nil {
52+ b.Fail(xturbo.ErrExtMissing)
53+ return 0
54+ }
55+ major := b.Ext.Major(xturbo.ExtXFixes)
56+ if major == 0 {
57+ b.Fail(xturbo.ErrExtMissing)
58+ return 0
59+ }
60+ p, seq := b.Request(major, 2, 12)
61+ if p == nil {
62+ return 0
63+ }
64+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
65+ binary.LittleEndian.PutUint32(p[4:], uint32(selection))
66+ binary.LittleEndian.PutUint32(p[8:], uint32(eventMask))
67+ return seq
68+}
69+
70+func SelectCursorInput(b *xturbo.Buf, window xproto.Window, eventMask CursorNotifyMask) xturbo.Seq {
71+ if b.Ext == nil {
72+ b.Fail(xturbo.ErrExtMissing)
73+ return 0
74+ }
75+ major := b.Ext.Major(xturbo.ExtXFixes)
76+ if major == 0 {
77+ b.Fail(xturbo.ErrExtMissing)
78+ return 0
79+ }
80+ p, seq := b.Request(major, 3, 8)
81+ if p == nil {
82+ return 0
83+ }
84+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
85+ binary.LittleEndian.PutUint32(p[4:], uint32(eventMask))
86+ return seq
87+}
88+
89+func GetCursorImage(b *xturbo.Buf) xturbo.Seq {
90+ if b.Ext == nil {
91+ b.Fail(xturbo.ErrExtMissing)
92+ return 0
93+ }
94+ major := b.Ext.Major(xturbo.ExtXFixes)
95+ if major == 0 {
96+ b.Fail(xturbo.ErrExtMissing)
97+ return 0
98+ }
99+ p, seq := b.Request(major, 4, 0)
100+ if p == nil {
101+ return 0
102+ }
103+ return seq
104+}
105+
106+func CreateRegion(b *xturbo.Buf, region Region, rectangles []xproto.Rectangle) xturbo.Seq {
107+ size := 0
108+ size += 4
109+ size += len(rectangles) * 8
110+ size = (size + 3) &^ 3
111+ if b.Ext == nil {
112+ b.Fail(xturbo.ErrExtMissing)
113+ return 0
114+ }
115+ major := b.Ext.Major(xturbo.ExtXFixes)
116+ if major == 0 {
117+ b.Fail(xturbo.ErrExtMissing)
118+ return 0
119+ }
120+ p, seq := b.Request(major, 5, size)
121+ if p == nil {
122+ return 0
123+ }
124+ off := 0
125+ binary.LittleEndian.PutUint32(p[off:], uint32(region))
126+ off += 4
127+ for i := range rectangles {
128+ rectangles[i].Put(p[off:])
129+ off += 8
130+ }
131+ return seq
132+}
133+
134+func CreateRegionFromBitmap(b *xturbo.Buf, region Region, bitmap xproto.Pixmap) xturbo.Seq {
135+ if b.Ext == nil {
136+ b.Fail(xturbo.ErrExtMissing)
137+ return 0
138+ }
139+ major := b.Ext.Major(xturbo.ExtXFixes)
140+ if major == 0 {
141+ b.Fail(xturbo.ErrExtMissing)
142+ return 0
143+ }
144+ p, seq := b.Request(major, 6, 8)
145+ if p == nil {
146+ return 0
147+ }
148+ binary.LittleEndian.PutUint32(p[0:], uint32(region))
149+ binary.LittleEndian.PutUint32(p[4:], uint32(bitmap))
150+ return seq
151+}
152+
153+func CreateRegionFromWindow(b *xturbo.Buf, region Region, window xproto.Window, kind shape.Sk) xturbo.Seq {
154+ if b.Ext == nil {
155+ b.Fail(xturbo.ErrExtMissing)
156+ return 0
157+ }
158+ major := b.Ext.Major(xturbo.ExtXFixes)
159+ if major == 0 {
160+ b.Fail(xturbo.ErrExtMissing)
161+ return 0
162+ }
163+ p, seq := b.Request(major, 7, 12)
164+ if p == nil {
165+ return 0
166+ }
167+ binary.LittleEndian.PutUint32(p[0:], uint32(region))
168+ binary.LittleEndian.PutUint32(p[4:], uint32(window))
169+ p[8:][0] = byte(kind)
170+ return seq
171+}
172+
173+func CreateRegionFromGC(b *xturbo.Buf, region Region, gc xproto.Gcontext) xturbo.Seq {
174+ if b.Ext == nil {
175+ b.Fail(xturbo.ErrExtMissing)
176+ return 0
177+ }
178+ major := b.Ext.Major(xturbo.ExtXFixes)
179+ if major == 0 {
180+ b.Fail(xturbo.ErrExtMissing)
181+ return 0
182+ }
183+ p, seq := b.Request(major, 8, 8)
184+ if p == nil {
185+ return 0
186+ }
187+ binary.LittleEndian.PutUint32(p[0:], uint32(region))
188+ binary.LittleEndian.PutUint32(p[4:], uint32(gc))
189+ return seq
190+}
191+
192+func CreateRegionFromPicture(b *xturbo.Buf, region Region, picture render.Picture) xturbo.Seq {
193+ if b.Ext == nil {
194+ b.Fail(xturbo.ErrExtMissing)
195+ return 0
196+ }
197+ major := b.Ext.Major(xturbo.ExtXFixes)
198+ if major == 0 {
199+ b.Fail(xturbo.ErrExtMissing)
200+ return 0
201+ }
202+ p, seq := b.Request(major, 9, 8)
203+ if p == nil {
204+ return 0
205+ }
206+ binary.LittleEndian.PutUint32(p[0:], uint32(region))
207+ binary.LittleEndian.PutUint32(p[4:], uint32(picture))
208+ return seq
209+}
210+
211+func DestroyRegion(b *xturbo.Buf, region Region) xturbo.Seq {
212+ if b.Ext == nil {
213+ b.Fail(xturbo.ErrExtMissing)
214+ return 0
215+ }
216+ major := b.Ext.Major(xturbo.ExtXFixes)
217+ if major == 0 {
218+ b.Fail(xturbo.ErrExtMissing)
219+ return 0
220+ }
221+ p, seq := b.Request(major, 10, 4)
222+ if p == nil {
223+ return 0
224+ }
225+ binary.LittleEndian.PutUint32(p[0:], uint32(region))
226+ return seq
227+}
228+
229+func SetRegion(b *xturbo.Buf, region Region, rectangles []xproto.Rectangle) xturbo.Seq {
230+ size := 0
231+ size += 4
232+ size += len(rectangles) * 8
233+ size = (size + 3) &^ 3
234+ if b.Ext == nil {
235+ b.Fail(xturbo.ErrExtMissing)
236+ return 0
237+ }
238+ major := b.Ext.Major(xturbo.ExtXFixes)
239+ if major == 0 {
240+ b.Fail(xturbo.ErrExtMissing)
241+ return 0
242+ }
243+ p, seq := b.Request(major, 11, size)
244+ if p == nil {
245+ return 0
246+ }
247+ off := 0
248+ binary.LittleEndian.PutUint32(p[off:], uint32(region))
249+ off += 4
250+ for i := range rectangles {
251+ rectangles[i].Put(p[off:])
252+ off += 8
253+ }
254+ return seq
255+}
256+
257+func CopyRegion(b *xturbo.Buf, source Region, destination Region) xturbo.Seq {
258+ if b.Ext == nil {
259+ b.Fail(xturbo.ErrExtMissing)
260+ return 0
261+ }
262+ major := b.Ext.Major(xturbo.ExtXFixes)
263+ if major == 0 {
264+ b.Fail(xturbo.ErrExtMissing)
265+ return 0
266+ }
267+ p, seq := b.Request(major, 12, 8)
268+ if p == nil {
269+ return 0
270+ }
271+ binary.LittleEndian.PutUint32(p[0:], uint32(source))
272+ binary.LittleEndian.PutUint32(p[4:], uint32(destination))
273+ return seq
274+}
275+
276+func UnionRegion(b *xturbo.Buf, source1 Region, source2 Region, destination Region) xturbo.Seq {
277+ if b.Ext == nil {
278+ b.Fail(xturbo.ErrExtMissing)
279+ return 0
280+ }
281+ major := b.Ext.Major(xturbo.ExtXFixes)
282+ if major == 0 {
283+ b.Fail(xturbo.ErrExtMissing)
284+ return 0
285+ }
286+ p, seq := b.Request(major, 13, 12)
287+ if p == nil {
288+ return 0
289+ }
290+ binary.LittleEndian.PutUint32(p[0:], uint32(source1))
291+ binary.LittleEndian.PutUint32(p[4:], uint32(source2))
292+ binary.LittleEndian.PutUint32(p[8:], uint32(destination))
293+ return seq
294+}
295+
296+func IntersectRegion(b *xturbo.Buf, source1 Region, source2 Region, destination Region) xturbo.Seq {
297+ if b.Ext == nil {
298+ b.Fail(xturbo.ErrExtMissing)
299+ return 0
300+ }
301+ major := b.Ext.Major(xturbo.ExtXFixes)
302+ if major == 0 {
303+ b.Fail(xturbo.ErrExtMissing)
304+ return 0
305+ }
306+ p, seq := b.Request(major, 14, 12)
307+ if p == nil {
308+ return 0
309+ }
310+ binary.LittleEndian.PutUint32(p[0:], uint32(source1))
311+ binary.LittleEndian.PutUint32(p[4:], uint32(source2))
312+ binary.LittleEndian.PutUint32(p[8:], uint32(destination))
313+ return seq
314+}
315+
316+func SubtractRegion(b *xturbo.Buf, source1 Region, source2 Region, destination Region) xturbo.Seq {
317+ if b.Ext == nil {
318+ b.Fail(xturbo.ErrExtMissing)
319+ return 0
320+ }
321+ major := b.Ext.Major(xturbo.ExtXFixes)
322+ if major == 0 {
323+ b.Fail(xturbo.ErrExtMissing)
324+ return 0
325+ }
326+ p, seq := b.Request(major, 15, 12)
327+ if p == nil {
328+ return 0
329+ }
330+ binary.LittleEndian.PutUint32(p[0:], uint32(source1))
331+ binary.LittleEndian.PutUint32(p[4:], uint32(source2))
332+ binary.LittleEndian.PutUint32(p[8:], uint32(destination))
333+ return seq
334+}
335+
336+func InvertRegion(b *xturbo.Buf, source Region, bounds xproto.Rectangle, destination Region) xturbo.Seq {
337+ if b.Ext == nil {
338+ b.Fail(xturbo.ErrExtMissing)
339+ return 0
340+ }
341+ major := b.Ext.Major(xturbo.ExtXFixes)
342+ if major == 0 {
343+ b.Fail(xturbo.ErrExtMissing)
344+ return 0
345+ }
346+ p, seq := b.Request(major, 16, 16)
347+ if p == nil {
348+ return 0
349+ }
350+ binary.LittleEndian.PutUint32(p[0:], uint32(source))
351+ bounds.Put(p[4:])
352+ binary.LittleEndian.PutUint32(p[12:], uint32(destination))
353+ return seq
354+}
355+
356+func TranslateRegion(b *xturbo.Buf, region Region, dx int16, dy int16) xturbo.Seq {
357+ if b.Ext == nil {
358+ b.Fail(xturbo.ErrExtMissing)
359+ return 0
360+ }
361+ major := b.Ext.Major(xturbo.ExtXFixes)
362+ if major == 0 {
363+ b.Fail(xturbo.ErrExtMissing)
364+ return 0
365+ }
366+ p, seq := b.Request(major, 17, 8)
367+ if p == nil {
368+ return 0
369+ }
370+ binary.LittleEndian.PutUint32(p[0:], uint32(region))
371+ binary.LittleEndian.PutUint16(p[4:], uint16(dx))
372+ binary.LittleEndian.PutUint16(p[6:], uint16(dy))
373+ return seq
374+}
375+
376+func RegionExtents(b *xturbo.Buf, source Region, destination Region) xturbo.Seq {
377+ if b.Ext == nil {
378+ b.Fail(xturbo.ErrExtMissing)
379+ return 0
380+ }
381+ major := b.Ext.Major(xturbo.ExtXFixes)
382+ if major == 0 {
383+ b.Fail(xturbo.ErrExtMissing)
384+ return 0
385+ }
386+ p, seq := b.Request(major, 18, 8)
387+ if p == nil {
388+ return 0
389+ }
390+ binary.LittleEndian.PutUint32(p[0:], uint32(source))
391+ binary.LittleEndian.PutUint32(p[4:], uint32(destination))
392+ return seq
393+}
394+
395+func FetchRegion(b *xturbo.Buf, region Region) xturbo.Seq {
396+ if b.Ext == nil {
397+ b.Fail(xturbo.ErrExtMissing)
398+ return 0
399+ }
400+ major := b.Ext.Major(xturbo.ExtXFixes)
401+ if major == 0 {
402+ b.Fail(xturbo.ErrExtMissing)
403+ return 0
404+ }
405+ p, seq := b.Request(major, 19, 4)
406+ if p == nil {
407+ return 0
408+ }
409+ binary.LittleEndian.PutUint32(p[0:], uint32(region))
410+ return seq
411+}
412+
413+func SetGCClipRegion(b *xturbo.Buf, gc xproto.Gcontext, region Region, xOrigin int16, yOrigin int16) xturbo.Seq {
414+ if b.Ext == nil {
415+ b.Fail(xturbo.ErrExtMissing)
416+ return 0
417+ }
418+ major := b.Ext.Major(xturbo.ExtXFixes)
419+ if major == 0 {
420+ b.Fail(xturbo.ErrExtMissing)
421+ return 0
422+ }
423+ p, seq := b.Request(major, 20, 12)
424+ if p == nil {
425+ return 0
426+ }
427+ binary.LittleEndian.PutUint32(p[0:], uint32(gc))
428+ binary.LittleEndian.PutUint32(p[4:], uint32(region))
429+ binary.LittleEndian.PutUint16(p[8:], uint16(xOrigin))
430+ binary.LittleEndian.PutUint16(p[10:], uint16(yOrigin))
431+ return seq
432+}
433+
434+func SetWindowShapeRegion(b *xturbo.Buf, dest xproto.Window, destKind shape.Sk, xOffset int16, yOffset int16, region Region) xturbo.Seq {
435+ if b.Ext == nil {
436+ b.Fail(xturbo.ErrExtMissing)
437+ return 0
438+ }
439+ major := b.Ext.Major(xturbo.ExtXFixes)
440+ if major == 0 {
441+ b.Fail(xturbo.ErrExtMissing)
442+ return 0
443+ }
444+ p, seq := b.Request(major, 21, 16)
445+ if p == nil {
446+ return 0
447+ }
448+ binary.LittleEndian.PutUint32(p[0:], uint32(dest))
449+ p[4:][0] = byte(destKind)
450+ binary.LittleEndian.PutUint16(p[8:], uint16(xOffset))
451+ binary.LittleEndian.PutUint16(p[10:], uint16(yOffset))
452+ binary.LittleEndian.PutUint32(p[12:], uint32(region))
453+ return seq
454+}
455+
456+func SetPictureClipRegion(b *xturbo.Buf, picture render.Picture, region Region, xOrigin int16, yOrigin int16) xturbo.Seq {
457+ if b.Ext == nil {
458+ b.Fail(xturbo.ErrExtMissing)
459+ return 0
460+ }
461+ major := b.Ext.Major(xturbo.ExtXFixes)
462+ if major == 0 {
463+ b.Fail(xturbo.ErrExtMissing)
464+ return 0
465+ }
466+ p, seq := b.Request(major, 22, 12)
467+ if p == nil {
468+ return 0
469+ }
470+ binary.LittleEndian.PutUint32(p[0:], uint32(picture))
471+ binary.LittleEndian.PutUint32(p[4:], uint32(region))
472+ binary.LittleEndian.PutUint16(p[8:], uint16(xOrigin))
473+ binary.LittleEndian.PutUint16(p[10:], uint16(yOrigin))
474+ return seq
475+}
476+
477+func SetCursorName(b *xturbo.Buf, cursor xproto.Cursor, name string) xturbo.Seq {
478+ if uint64(len(name)) > 65535 {
479+ b.Fail(xturbo.ErrBadLength)
480+ return 0
481+ }
482+ size := 0
483+ size += 4
484+ size += 2
485+ size += 2
486+ size += len(name) * 1
487+ size = (size + 3) &^ 3
488+ if b.Ext == nil {
489+ b.Fail(xturbo.ErrExtMissing)
490+ return 0
491+ }
492+ major := b.Ext.Major(xturbo.ExtXFixes)
493+ if major == 0 {
494+ b.Fail(xturbo.ErrExtMissing)
495+ return 0
496+ }
497+ p, seq := b.Request(major, 23, size)
498+ if p == nil {
499+ return 0
500+ }
501+ off := 0
502+ binary.LittleEndian.PutUint32(p[off:], uint32(cursor))
503+ off += 4
504+ binary.LittleEndian.PutUint16(p[off:], uint16(len(name)))
505+ off += 2
506+ off += 2
507+ copy(p[off:], name)
508+ off += len(name)
509+ return seq
510+}
511+
512+func GetCursorName(b *xturbo.Buf, cursor xproto.Cursor) xturbo.Seq {
513+ if b.Ext == nil {
514+ b.Fail(xturbo.ErrExtMissing)
515+ return 0
516+ }
517+ major := b.Ext.Major(xturbo.ExtXFixes)
518+ if major == 0 {
519+ b.Fail(xturbo.ErrExtMissing)
520+ return 0
521+ }
522+ p, seq := b.Request(major, 24, 4)
523+ if p == nil {
524+ return 0
525+ }
526+ binary.LittleEndian.PutUint32(p[0:], uint32(cursor))
527+ return seq
528+}
529+
530+func GetCursorImageAndName(b *xturbo.Buf) xturbo.Seq {
531+ if b.Ext == nil {
532+ b.Fail(xturbo.ErrExtMissing)
533+ return 0
534+ }
535+ major := b.Ext.Major(xturbo.ExtXFixes)
536+ if major == 0 {
537+ b.Fail(xturbo.ErrExtMissing)
538+ return 0
539+ }
540+ p, seq := b.Request(major, 25, 0)
541+ if p == nil {
542+ return 0
543+ }
544+ return seq
545+}
546+
547+func ChangeCursor(b *xturbo.Buf, source xproto.Cursor, destination xproto.Cursor) xturbo.Seq {
548+ if b.Ext == nil {
549+ b.Fail(xturbo.ErrExtMissing)
550+ return 0
551+ }
552+ major := b.Ext.Major(xturbo.ExtXFixes)
553+ if major == 0 {
554+ b.Fail(xturbo.ErrExtMissing)
555+ return 0
556+ }
557+ p, seq := b.Request(major, 26, 8)
558+ if p == nil {
559+ return 0
560+ }
561+ binary.LittleEndian.PutUint32(p[0:], uint32(source))
562+ binary.LittleEndian.PutUint32(p[4:], uint32(destination))
563+ return seq
564+}
565+
566+func ChangeCursorByName(b *xturbo.Buf, src xproto.Cursor, name string) xturbo.Seq {
567+ if uint64(len(name)) > 65535 {
568+ b.Fail(xturbo.ErrBadLength)
569+ return 0
570+ }
571+ size := 0
572+ size += 4
573+ size += 2
574+ size += 2
575+ size += len(name) * 1
576+ size = (size + 3) &^ 3
577+ if b.Ext == nil {
578+ b.Fail(xturbo.ErrExtMissing)
579+ return 0
580+ }
581+ major := b.Ext.Major(xturbo.ExtXFixes)
582+ if major == 0 {
583+ b.Fail(xturbo.ErrExtMissing)
584+ return 0
585+ }
586+ p, seq := b.Request(major, 27, size)
587+ if p == nil {
588+ return 0
589+ }
590+ off := 0
591+ binary.LittleEndian.PutUint32(p[off:], uint32(src))
592+ off += 4
593+ binary.LittleEndian.PutUint16(p[off:], uint16(len(name)))
594+ off += 2
595+ off += 2
596+ copy(p[off:], name)
597+ off += len(name)
598+ return seq
599+}
600+
601+func ExpandRegion(b *xturbo.Buf, source Region, destination Region, left uint16, right uint16, top uint16, bottom uint16) xturbo.Seq {
602+ if b.Ext == nil {
603+ b.Fail(xturbo.ErrExtMissing)
604+ return 0
605+ }
606+ major := b.Ext.Major(xturbo.ExtXFixes)
607+ if major == 0 {
608+ b.Fail(xturbo.ErrExtMissing)
609+ return 0
610+ }
611+ p, seq := b.Request(major, 28, 16)
612+ if p == nil {
613+ return 0
614+ }
615+ binary.LittleEndian.PutUint32(p[0:], uint32(source))
616+ binary.LittleEndian.PutUint32(p[4:], uint32(destination))
617+ binary.LittleEndian.PutUint16(p[8:], uint16(left))
618+ binary.LittleEndian.PutUint16(p[10:], uint16(right))
619+ binary.LittleEndian.PutUint16(p[12:], uint16(top))
620+ binary.LittleEndian.PutUint16(p[14:], uint16(bottom))
621+ return seq
622+}
623+
624+func HideCursor(b *xturbo.Buf, window xproto.Window) xturbo.Seq {
625+ if b.Ext == nil {
626+ b.Fail(xturbo.ErrExtMissing)
627+ return 0
628+ }
629+ major := b.Ext.Major(xturbo.ExtXFixes)
630+ if major == 0 {
631+ b.Fail(xturbo.ErrExtMissing)
632+ return 0
633+ }
634+ p, seq := b.Request(major, 29, 4)
635+ if p == nil {
636+ return 0
637+ }
638+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
639+ return seq
640+}
641+
642+func ShowCursor(b *xturbo.Buf, window xproto.Window) xturbo.Seq {
643+ if b.Ext == nil {
644+ b.Fail(xturbo.ErrExtMissing)
645+ return 0
646+ }
647+ major := b.Ext.Major(xturbo.ExtXFixes)
648+ if major == 0 {
649+ b.Fail(xturbo.ErrExtMissing)
650+ return 0
651+ }
652+ p, seq := b.Request(major, 30, 4)
653+ if p == nil {
654+ return 0
655+ }
656+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
657+ return seq
658+}
659+
660+func CreatePointerBarrier(b *xturbo.Buf, barrier Barrier, window xproto.Window, x1 uint16, y1 uint16, x2 uint16, y2 uint16, directions BarrierDirections, devices []uint16) xturbo.Seq {
661+ if uint64(len(devices)) > 65535 {
662+ b.Fail(xturbo.ErrBadLength)
663+ return 0
664+ }
665+ size := 0
666+ size += 4
667+ size += 4
668+ size += 2
669+ size += 2
670+ size += 2
671+ size += 2
672+ size += 4
673+ size += 2
674+ size += 2
675+ size += len(devices) * 2
676+ size = (size + 3) &^ 3
677+ if b.Ext == nil {
678+ b.Fail(xturbo.ErrExtMissing)
679+ return 0
680+ }
681+ major := b.Ext.Major(xturbo.ExtXFixes)
682+ if major == 0 {
683+ b.Fail(xturbo.ErrExtMissing)
684+ return 0
685+ }
686+ p, seq := b.Request(major, 31, size)
687+ if p == nil {
688+ return 0
689+ }
690+ off := 0
691+ binary.LittleEndian.PutUint32(p[off:], uint32(barrier))
692+ off += 4
693+ binary.LittleEndian.PutUint32(p[off:], uint32(window))
694+ off += 4
695+ binary.LittleEndian.PutUint16(p[off:], uint16(x1))
696+ off += 2
697+ binary.LittleEndian.PutUint16(p[off:], uint16(y1))
698+ off += 2
699+ binary.LittleEndian.PutUint16(p[off:], uint16(x2))
700+ off += 2
701+ binary.LittleEndian.PutUint16(p[off:], uint16(y2))
702+ off += 2
703+ binary.LittleEndian.PutUint32(p[off:], uint32(directions))
704+ off += 4
705+ off += 2
706+ binary.LittleEndian.PutUint16(p[off:], uint16(len(devices)))
707+ off += 2
708+ for i := range devices {
709+ binary.LittleEndian.PutUint16(p[off:], uint16(devices[i]))
710+ off += 2
711+ }
712+ return seq
713+}
714+
715+func DeletePointerBarrier(b *xturbo.Buf, barrier Barrier) xturbo.Seq {
716+ if b.Ext == nil {
717+ b.Fail(xturbo.ErrExtMissing)
718+ return 0
719+ }
720+ major := b.Ext.Major(xturbo.ExtXFixes)
721+ if major == 0 {
722+ b.Fail(xturbo.ErrExtMissing)
723+ return 0
724+ }
725+ p, seq := b.Request(major, 32, 4)
726+ if p == nil {
727+ return 0
728+ }
729+ binary.LittleEndian.PutUint32(p[0:], uint32(barrier))
730+ return seq
731+}
732+
733+func SetClientDisconnectMode(b *xturbo.Buf, disconnectMode ClientDisconnectFlags) xturbo.Seq {
734+ if b.Ext == nil {
735+ b.Fail(xturbo.ErrExtMissing)
736+ return 0
737+ }
738+ major := b.Ext.Major(xturbo.ExtXFixes)
739+ if major == 0 {
740+ b.Fail(xturbo.ErrExtMissing)
741+ return 0
742+ }
743+ p, seq := b.Request(major, 33, 4)
744+ if p == nil {
745+ return 0
746+ }
747+ binary.LittleEndian.PutUint32(p[0:], uint32(disconnectMode))
748+ return seq
749+}
750+
751+func GetClientDisconnectMode(b *xturbo.Buf) xturbo.Seq {
752+ if b.Ext == nil {
753+ b.Fail(xturbo.ErrExtMissing)
754+ return 0
755+ }
756+ major := b.Ext.Major(xturbo.ExtXFixes)
757+ if major == 0 {
758+ b.Fail(xturbo.ErrExtMissing)
759+ return 0
760+ }
761+ p, seq := b.Request(major, 34, 0)
762+ if p == nil {
763+ return 0
764+ }
765+ return seq
766+}
A xfixes/sizes_test.go +32 -0
@@ -0,0 +1,32 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xfixes
3+
4+import "testing"
5+
6+func TestWireSizes(t *testing.T) {
7+ if got := 32; got != 32 {
8+ t.Errorf("reply QueryVersion fixed size = %d", got)
9+ }
10+ if got := 32; got != 32 {
11+ t.Errorf("event SelectionNotify fixed size = %d", got)
12+ }
13+ if got := 32; got != 32 {
14+ t.Errorf("event CursorNotify fixed size = %d", got)
15+ }
16+ if got := 32; got != 32 {
17+ t.Errorf("reply GetCursorImage fixed size = %d", got)
18+ }
19+ if got := 32; got != 32 {
20+ t.Errorf("reply FetchRegion fixed size = %d", got)
21+ }
22+ if got := 32; got != 32 {
23+ t.Errorf("reply GetCursorName fixed size = %d", got)
24+ }
25+ if got := 32; got != 32 {
26+ t.Errorf("reply GetCursorImageAndName fixed size = %d", got)
27+ }
28+ if got := 32; got != 32 {
29+ t.Errorf("reply GetClientDisconnectMode fixed size = %d", got)
30+ }
31+
32+}
A xfixes/types_generated.go +55 -0
@@ -0,0 +1,55 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xfixes
3+
4+type Region uint32
5+
6+type Barrier uint32
7+
8+type SaveSetMode uint8
9+
10+const SaveSetModeInsert SaveSetMode = 0
11+const SaveSetModeDelete SaveSetMode = 1
12+
13+type SaveSetTarget uint8
14+
15+const SaveSetTargetNearest SaveSetTarget = 0
16+const SaveSetTargetRoot SaveSetTarget = 1
17+
18+type SaveSetMapping uint8
19+
20+const SaveSetMappingMap SaveSetMapping = 0
21+const SaveSetMappingUnmap SaveSetMapping = 1
22+
23+type SelectionEvent uint8
24+
25+const SelectionEventSetSelectionOwner SelectionEvent = 0
26+const SelectionEventSelectionWindowDestroy SelectionEvent = 1
27+const SelectionEventSelectionClientClose SelectionEvent = 2
28+
29+type SelectionEventMask uint32
30+
31+const SelectionEventMaskSetSelectionOwner SelectionEventMask = 1
32+const SelectionEventMaskSelectionWindowDestroy SelectionEventMask = 2
33+const SelectionEventMaskSelectionClientClose SelectionEventMask = 4
34+
35+type CursorNotify uint8
36+
37+const CursorNotifyDisplayCursor CursorNotify = 0
38+
39+type CursorNotifyMask uint32
40+
41+const CursorNotifyMaskDisplayCursor CursorNotifyMask = 1
42+
43+const RegionNone Region = 0
44+
45+type BarrierDirections uint32
46+
47+const BarrierDirectionsPositiveX BarrierDirections = 1
48+const BarrierDirectionsPositiveY BarrierDirections = 2
49+const BarrierDirectionsNegativeX BarrierDirections = 4
50+const BarrierDirectionsNegativeY BarrierDirections = 8
51+
52+type ClientDisconnectFlags uint32
53+
54+const ClientDisconnectFlagsDefault ClientDisconnectFlags = 0
55+const ClientDisconnectFlagsTerminate ClientDisconnectFlags = 1
A xproto/replies_fuzz_test.go +895 -0
@@ -0,0 +1,895 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xproto
3+
4+import "testing"
5+import "bnema.dev/xturbo/internal/xtest"
6+
7+func FuzzParseGetWindowAttributesReply(f *testing.F) {
8+ f.Add(make([]byte, 44))
9+ if raw, err := xtest.LoadHex("../testdata/golden/xproto/GetWindowAttributes.reply.hex"); err != nil {
10+ f.Fatal(err)
11+ } else {
12+ f.Add(raw)
13+ }
14+ f.Fuzz(func(t *testing.T, raw []byte) {
15+ r, ok := ParseGetWindowAttributesReply(raw)
16+ if !ok {
17+ if len(raw) >= 44 {
18+ t.Fatal("rejected a complete fixed-size reply")
19+ }
20+ return
21+ }
22+ if len(r.Raw()) != len(raw) {
23+ t.Fatal("Raw must return the parsed bytes")
24+ }
25+ _ = r.BackingStore()
26+ _ = r.Visual()
27+ _ = r.Class()
28+ _ = r.BitGravity()
29+ _ = r.WinGravity()
30+ _ = r.BackingPlanes()
31+ _ = r.BackingPixel()
32+ _ = r.SaveUnder()
33+ _ = r.MapIsInstalled()
34+ _ = r.MapState()
35+ _ = r.OverrideRedirect()
36+ _ = r.Colormap()
37+ _ = r.AllEventMasks()
38+ _ = r.YourEventMask()
39+ _ = r.DoNotPropagateMask()
40+ })
41+}
42+
43+func FuzzParseGetGeometryReply(f *testing.F) {
44+ f.Add(make([]byte, 32))
45+ if raw, err := xtest.LoadHex("../testdata/golden/xproto/GetGeometry.reply.hex"); err != nil {
46+ f.Fatal(err)
47+ } else {
48+ f.Add(raw)
49+ }
50+ f.Fuzz(func(t *testing.T, raw []byte) {
51+ r, ok := ParseGetGeometryReply(raw)
52+ if !ok {
53+ if len(raw) >= 32 {
54+ t.Fatal("rejected a complete fixed-size reply")
55+ }
56+ return
57+ }
58+ if len(r.Raw()) != len(raw) {
59+ t.Fatal("Raw must return the parsed bytes")
60+ }
61+ _ = r.Depth()
62+ _ = r.Root()
63+ _ = r.X()
64+ _ = r.Y()
65+ _ = r.Width()
66+ _ = r.Height()
67+ _ = r.BorderWidth()
68+ })
69+}
70+
71+func FuzzParseQueryTreeReply(f *testing.F) {
72+ f.Add(make([]byte, 32))
73+ if raw, err := xtest.LoadHex("../testdata/golden/xproto/QueryTree.reply.hex"); err != nil {
74+ f.Fatal(err)
75+ } else {
76+ f.Add(raw)
77+ }
78+ f.Fuzz(func(t *testing.T, raw []byte) {
79+ r, ok := ParseQueryTreeReply(raw)
80+ if !ok {
81+ return
82+ }
83+ if len(r.Raw()) != len(raw) {
84+ t.Fatal("Raw must return the parsed bytes")
85+ }
86+ _ = r.Root()
87+ _ = r.Parent()
88+ _ = r.ChildrenLen()
89+ {
90+ l0 := r.Children()
91+ for i := 0; i < l0.Len(); i++ {
92+ _ = l0.At(i)
93+ }
94+ }
95+ })
96+}
97+
98+func FuzzParseInternAtomReply(f *testing.F) {
99+ f.Add(make([]byte, 32))
100+ if raw, err := xtest.LoadHex("../testdata/golden/xproto/InternAtom.reply.hex"); err != nil {
101+ f.Fatal(err)
102+ } else {
103+ f.Add(raw)
104+ }
105+ f.Fuzz(func(t *testing.T, raw []byte) {
106+ r, ok := ParseInternAtomReply(raw)
107+ if !ok {
108+ if len(raw) >= 32 {
109+ t.Fatal("rejected a complete fixed-size reply")
110+ }
111+ return
112+ }
113+ if len(r.Raw()) != len(raw) {
114+ t.Fatal("Raw must return the parsed bytes")
115+ }
116+ _ = r.Atom()
117+ })
118+}
119+
120+func FuzzParseGetAtomNameReply(f *testing.F) {
121+ f.Add(make([]byte, 32))
122+ f.Fuzz(func(t *testing.T, raw []byte) {
123+ r, ok := ParseGetAtomNameReply(raw)
124+ if !ok {
125+ return
126+ }
127+ if len(r.Raw()) != len(raw) {
128+ t.Fatal("Raw must return the parsed bytes")
129+ }
130+ _ = r.NameLen()
131+ _ = len(r.Name())
132+ })
133+}
134+
135+func FuzzParseGetPropertyReply(f *testing.F) {
136+ f.Add(make([]byte, 32))
137+ if raw, err := xtest.LoadHex("../testdata/golden/xproto/GetProperty.reply.hex"); err != nil {
138+ f.Fatal(err)
139+ } else {
140+ f.Add(raw)
141+ }
142+ if raw, err := xtest.LoadHex("../testdata/golden/xproto/GetPropertyEmpty.reply.hex"); err != nil {
143+ f.Fatal(err)
144+ } else {
145+ f.Add(raw)
146+ }
147+ f.Fuzz(func(t *testing.T, raw []byte) {
148+ r, ok := ParseGetPropertyReply(raw)
149+ if !ok {
150+ return
151+ }
152+ if len(r.Raw()) != len(raw) {
153+ t.Fatal("Raw must return the parsed bytes")
154+ }
155+ _ = r.Format()
156+ _ = r.Type()
157+ _ = r.BytesAfter()
158+ _ = r.ValueLen()
159+ _ = len(r.Value())
160+ })
161+}
162+
163+func FuzzParseListPropertiesReply(f *testing.F) {
164+ f.Add(make([]byte, 32))
165+ f.Fuzz(func(t *testing.T, raw []byte) {
166+ r, ok := ParseListPropertiesReply(raw)
167+ if !ok {
168+ return
169+ }
170+ if len(r.Raw()) != len(raw) {
171+ t.Fatal("Raw must return the parsed bytes")
172+ }
173+ _ = r.AtomsLen()
174+ {
175+ l0 := r.Atoms()
176+ for i := 0; i < l0.Len(); i++ {
177+ _ = l0.At(i)
178+ }
179+ }
180+ })
181+}
182+
183+func FuzzParseGetSelectionOwnerReply(f *testing.F) {
184+ f.Add(make([]byte, 32))
185+ f.Fuzz(func(t *testing.T, raw []byte) {
186+ r, ok := ParseGetSelectionOwnerReply(raw)
187+ if !ok {
188+ if len(raw) >= 32 {
189+ t.Fatal("rejected a complete fixed-size reply")
190+ }
191+ return
192+ }
193+ if len(r.Raw()) != len(raw) {
194+ t.Fatal("Raw must return the parsed bytes")
195+ }
196+ _ = r.Owner()
197+ })
198+}
199+
200+func FuzzParseGrabPointerReply(f *testing.F) {
201+ f.Add(make([]byte, 32))
202+ f.Fuzz(func(t *testing.T, raw []byte) {
203+ r, ok := ParseGrabPointerReply(raw)
204+ if !ok {
205+ if len(raw) >= 32 {
206+ t.Fatal("rejected a complete fixed-size reply")
207+ }
208+ return
209+ }
210+ if len(r.Raw()) != len(raw) {
211+ t.Fatal("Raw must return the parsed bytes")
212+ }
213+ _ = r.Status()
214+ })
215+}
216+
217+func FuzzParseGrabKeyboardReply(f *testing.F) {
218+ f.Add(make([]byte, 32))
219+ f.Fuzz(func(t *testing.T, raw []byte) {
220+ r, ok := ParseGrabKeyboardReply(raw)
221+ if !ok {
222+ if len(raw) >= 32 {
223+ t.Fatal("rejected a complete fixed-size reply")
224+ }
225+ return
226+ }
227+ if len(r.Raw()) != len(raw) {
228+ t.Fatal("Raw must return the parsed bytes")
229+ }
230+ _ = r.Status()
231+ })
232+}
233+
234+func FuzzParseQueryPointerReply(f *testing.F) {
235+ f.Add(make([]byte, 32))
236+ f.Fuzz(func(t *testing.T, raw []byte) {
237+ r, ok := ParseQueryPointerReply(raw)
238+ if !ok {
239+ if len(raw) >= 32 {
240+ t.Fatal("rejected a complete fixed-size reply")
241+ }
242+ return
243+ }
244+ if len(r.Raw()) != len(raw) {
245+ t.Fatal("Raw must return the parsed bytes")
246+ }
247+ _ = r.SameScreen()
248+ _ = r.Root()
249+ _ = r.Child()
250+ _ = r.RootX()
251+ _ = r.RootY()
252+ _ = r.WinX()
253+ _ = r.WinY()
254+ _ = r.Mask()
255+ })
256+}
257+
258+func FuzzParseGetMotionEventsReply(f *testing.F) {
259+ f.Add(make([]byte, 32))
260+ f.Fuzz(func(t *testing.T, raw []byte) {
261+ r, ok := ParseGetMotionEventsReply(raw)
262+ if !ok {
263+ return
264+ }
265+ if len(r.Raw()) != len(raw) {
266+ t.Fatal("Raw must return the parsed bytes")
267+ }
268+ _ = r.EventsLen()
269+ {
270+ l0 := r.Events()
271+ for i := 0; i < l0.Len(); i++ {
272+ _ = l0.At(i)
273+ }
274+ }
275+ })
276+}
277+
278+func FuzzParseTranslateCoordinatesReply(f *testing.F) {
279+ f.Add(make([]byte, 32))
280+ f.Fuzz(func(t *testing.T, raw []byte) {
281+ r, ok := ParseTranslateCoordinatesReply(raw)
282+ if !ok {
283+ if len(raw) >= 32 {
284+ t.Fatal("rejected a complete fixed-size reply")
285+ }
286+ return
287+ }
288+ if len(r.Raw()) != len(raw) {
289+ t.Fatal("Raw must return the parsed bytes")
290+ }
291+ _ = r.SameScreen()
292+ _ = r.Child()
293+ _ = r.DstX()
294+ _ = r.DstY()
295+ })
296+}
297+
298+func FuzzParseGetInputFocusReply(f *testing.F) {
299+ f.Add(make([]byte, 32))
300+ f.Fuzz(func(t *testing.T, raw []byte) {
301+ r, ok := ParseGetInputFocusReply(raw)
302+ if !ok {
303+ if len(raw) >= 32 {
304+ t.Fatal("rejected a complete fixed-size reply")
305+ }
306+ return
307+ }
308+ if len(r.Raw()) != len(raw) {
309+ t.Fatal("Raw must return the parsed bytes")
310+ }
311+ _ = r.RevertTo()
312+ _ = r.Focus()
313+ })
314+}
315+
316+func FuzzParseQueryKeymapReply(f *testing.F) {
317+ f.Add(make([]byte, 40))
318+ f.Fuzz(func(t *testing.T, raw []byte) {
319+ r, ok := ParseQueryKeymapReply(raw)
320+ if !ok {
321+ if len(raw) >= 40 {
322+ t.Fatal("rejected a complete fixed-size reply")
323+ }
324+ return
325+ }
326+ if len(r.Raw()) != len(raw) {
327+ t.Fatal("Raw must return the parsed bytes")
328+ }
329+ _ = len(r.Keys())
330+ })
331+}
332+
333+func FuzzParseQueryFontReply(f *testing.F) {
334+ f.Add(make([]byte, 60))
335+ f.Fuzz(func(t *testing.T, raw []byte) {
336+ r, ok := ParseQueryFontReply(raw)
337+ if !ok {
338+ return
339+ }
340+ if len(r.Raw()) != len(raw) {
341+ t.Fatal("Raw must return the parsed bytes")
342+ }
343+ _ = r.MinBounds()
344+ _ = r.MaxBounds()
345+ _ = r.MinCharOrByte2()
346+ _ = r.MaxCharOrByte2()
347+ _ = r.DefaultChar()
348+ _ = r.PropertiesLen()
349+ _ = r.DrawDirection()
350+ _ = r.MinByte1()
351+ _ = r.MaxByte1()
352+ _ = r.AllCharsExist()
353+ _ = r.FontAscent()
354+ _ = r.FontDescent()
355+ _ = r.CharInfosLen()
356+ {
357+ l0 := r.Properties()
358+ for i := 0; i < l0.Len(); i++ {
359+ _ = l0.At(i)
360+ }
361+ }
362+ {
363+ l0 := r.CharInfos()
364+ for i := 0; i < l0.Len(); i++ {
365+ _ = l0.At(i)
366+ }
367+ }
368+ })
369+}
370+
371+func FuzzParseQueryTextExtentsReply(f *testing.F) {
372+ f.Add(make([]byte, 32))
373+ f.Fuzz(func(t *testing.T, raw []byte) {
374+ r, ok := ParseQueryTextExtentsReply(raw)
375+ if !ok {
376+ if len(raw) >= 32 {
377+ t.Fatal("rejected a complete fixed-size reply")
378+ }
379+ return
380+ }
381+ if len(r.Raw()) != len(raw) {
382+ t.Fatal("Raw must return the parsed bytes")
383+ }
384+ _ = r.DrawDirection()
385+ _ = r.FontAscent()
386+ _ = r.FontDescent()
387+ _ = r.OverallAscent()
388+ _ = r.OverallDescent()
389+ _ = r.OverallWidth()
390+ _ = r.OverallLeft()
391+ _ = r.OverallRight()
392+ })
393+}
394+
395+func FuzzParseListFontsReply(f *testing.F) {
396+ f.Add(make([]byte, 32))
397+ f.Fuzz(func(t *testing.T, raw []byte) {
398+ r, ok := ParseListFontsReply(raw)
399+ if !ok {
400+ return
401+ }
402+ if len(r.Raw()) != len(raw) {
403+ t.Fatal("Raw must return the parsed bytes")
404+ }
405+ _ = r.NamesLen()
406+ {
407+ it0 := r.Names()
408+ for it0.Next() {
409+ _ = it0.Value().NameLen()
410+ _ = len(it0.Value().Name())
411+ }
412+ if it0.Err() {
413+ t.Fatal("iterator error after successful Parse")
414+ }
415+ }
416+ })
417+}
418+
419+func FuzzParseListFontsWithInfoReply(f *testing.F) {
420+ f.Add(make([]byte, 60))
421+ f.Fuzz(func(t *testing.T, raw []byte) {
422+ r, ok := ParseListFontsWithInfoReply(raw)
423+ if !ok {
424+ return
425+ }
426+ if len(r.Raw()) != len(raw) {
427+ t.Fatal("Raw must return the parsed bytes")
428+ }
429+ _ = r.NameLen()
430+ _ = r.MinBounds()
431+ _ = r.MaxBounds()
432+ _ = r.MinCharOrByte2()
433+ _ = r.MaxCharOrByte2()
434+ _ = r.DefaultChar()
435+ _ = r.PropertiesLen()
436+ _ = r.DrawDirection()
437+ _ = r.MinByte1()
438+ _ = r.MaxByte1()
439+ _ = r.AllCharsExist()
440+ _ = r.FontAscent()
441+ _ = r.FontDescent()
442+ _ = r.RepliesHint()
443+ {
444+ l0 := r.Properties()
445+ for i := 0; i < l0.Len(); i++ {
446+ _ = l0.At(i)
447+ }
448+ }
449+ _ = len(r.Name())
450+ })
451+}
452+
453+func FuzzParseGetFontPathReply(f *testing.F) {
454+ f.Add(make([]byte, 32))
455+ f.Fuzz(func(t *testing.T, raw []byte) {
456+ r, ok := ParseGetFontPathReply(raw)
457+ if !ok {
458+ return
459+ }
460+ if len(r.Raw()) != len(raw) {
461+ t.Fatal("Raw must return the parsed bytes")
462+ }
463+ _ = r.PathLen()
464+ {
465+ it0 := r.Path()
466+ for it0.Next() {
467+ _ = it0.Value().NameLen()
468+ _ = len(it0.Value().Name())
469+ }
470+ if it0.Err() {
471+ t.Fatal("iterator error after successful Parse")
472+ }
473+ }
474+ })
475+}
476+
477+func FuzzParseGetImageReply(f *testing.F) {
478+ f.Add(make([]byte, 32))
479+ f.Fuzz(func(t *testing.T, raw []byte) {
480+ r, ok := ParseGetImageReply(raw)
481+ if !ok {
482+ return
483+ }
484+ if len(r.Raw()) != len(raw) {
485+ t.Fatal("Raw must return the parsed bytes")
486+ }
487+ _ = r.Depth()
488+ _ = r.Visual()
489+ _ = len(r.Data())
490+ })
491+}
492+
493+func FuzzParseListInstalledColormapsReply(f *testing.F) {
494+ f.Add(make([]byte, 32))
495+ f.Fuzz(func(t *testing.T, raw []byte) {
496+ r, ok := ParseListInstalledColormapsReply(raw)
497+ if !ok {
498+ return
499+ }
500+ if len(r.Raw()) != len(raw) {
501+ t.Fatal("Raw must return the parsed bytes")
502+ }
503+ _ = r.CmapsLen()
504+ {
505+ l0 := r.Cmaps()
506+ for i := 0; i < l0.Len(); i++ {
507+ _ = l0.At(i)
508+ }
509+ }
510+ })
511+}
512+
513+func FuzzParseAllocColorReply(f *testing.F) {
514+ f.Add(make([]byte, 32))
515+ f.Fuzz(func(t *testing.T, raw []byte) {
516+ r, ok := ParseAllocColorReply(raw)
517+ if !ok {
518+ if len(raw) >= 32 {
519+ t.Fatal("rejected a complete fixed-size reply")
520+ }
521+ return
522+ }
523+ if len(r.Raw()) != len(raw) {
524+ t.Fatal("Raw must return the parsed bytes")
525+ }
526+ _ = r.Red()
527+ _ = r.Green()
528+ _ = r.Blue()
529+ _ = r.Pixel()
530+ })
531+}
532+
533+func FuzzParseAllocNamedColorReply(f *testing.F) {
534+ f.Add(make([]byte, 32))
535+ f.Fuzz(func(t *testing.T, raw []byte) {
536+ r, ok := ParseAllocNamedColorReply(raw)
537+ if !ok {
538+ if len(raw) >= 32 {
539+ t.Fatal("rejected a complete fixed-size reply")
540+ }
541+ return
542+ }
543+ if len(r.Raw()) != len(raw) {
544+ t.Fatal("Raw must return the parsed bytes")
545+ }
546+ _ = r.Pixel()
547+ _ = r.ExactRed()
548+ _ = r.ExactGreen()
549+ _ = r.ExactBlue()
550+ _ = r.VisualRed()
551+ _ = r.VisualGreen()
552+ _ = r.VisualBlue()
553+ })
554+}
555+
556+func FuzzParseAllocColorCellsReply(f *testing.F) {
557+ f.Add(make([]byte, 32))
558+ f.Fuzz(func(t *testing.T, raw []byte) {
559+ r, ok := ParseAllocColorCellsReply(raw)
560+ if !ok {
561+ return
562+ }
563+ if len(r.Raw()) != len(raw) {
564+ t.Fatal("Raw must return the parsed bytes")
565+ }
566+ _ = r.PixelsLen()
567+ _ = r.MasksLen()
568+ {
569+ l0 := r.Pixels()
570+ for i := 0; i < l0.Len(); i++ {
571+ _ = l0.At(i)
572+ }
573+ }
574+ {
575+ l0 := r.Masks()
576+ for i := 0; i < l0.Len(); i++ {
577+ _ = l0.At(i)
578+ }
579+ }
580+ })
581+}
582+
583+func FuzzParseAllocColorPlanesReply(f *testing.F) {
584+ f.Add(make([]byte, 32))
585+ f.Fuzz(func(t *testing.T, raw []byte) {
586+ r, ok := ParseAllocColorPlanesReply(raw)
587+ if !ok {
588+ return
589+ }
590+ if len(r.Raw()) != len(raw) {
591+ t.Fatal("Raw must return the parsed bytes")
592+ }
593+ _ = r.PixelsLen()
594+ _ = r.RedMask()
595+ _ = r.GreenMask()
596+ _ = r.BlueMask()
597+ {
598+ l0 := r.Pixels()
599+ for i := 0; i < l0.Len(); i++ {
600+ _ = l0.At(i)
601+ }
602+ }
603+ })
604+}
605+
606+func FuzzParseQueryColorsReply(f *testing.F) {
607+ f.Add(make([]byte, 32))
608+ f.Fuzz(func(t *testing.T, raw []byte) {
609+ r, ok := ParseQueryColorsReply(raw)
610+ if !ok {
611+ return
612+ }
613+ if len(r.Raw()) != len(raw) {
614+ t.Fatal("Raw must return the parsed bytes")
615+ }
616+ _ = r.ColorsLen()
617+ {
618+ l0 := r.Colors()
619+ for i := 0; i < l0.Len(); i++ {
620+ _ = l0.At(i)
621+ }
622+ }
623+ })
624+}
625+
626+func FuzzParseLookupColorReply(f *testing.F) {
627+ f.Add(make([]byte, 32))
628+ f.Fuzz(func(t *testing.T, raw []byte) {
629+ r, ok := ParseLookupColorReply(raw)
630+ if !ok {
631+ if len(raw) >= 32 {
632+ t.Fatal("rejected a complete fixed-size reply")
633+ }
634+ return
635+ }
636+ if len(r.Raw()) != len(raw) {
637+ t.Fatal("Raw must return the parsed bytes")
638+ }
639+ _ = r.ExactRed()
640+ _ = r.ExactGreen()
641+ _ = r.ExactBlue()
642+ _ = r.VisualRed()
643+ _ = r.VisualGreen()
644+ _ = r.VisualBlue()
645+ })
646+}
647+
648+func FuzzParseQueryBestSizeReply(f *testing.F) {
649+ f.Add(make([]byte, 32))
650+ f.Fuzz(func(t *testing.T, raw []byte) {
651+ r, ok := ParseQueryBestSizeReply(raw)
652+ if !ok {
653+ if len(raw) >= 32 {
654+ t.Fatal("rejected a complete fixed-size reply")
655+ }
656+ return
657+ }
658+ if len(r.Raw()) != len(raw) {
659+ t.Fatal("Raw must return the parsed bytes")
660+ }
661+ _ = r.Width()
662+ _ = r.Height()
663+ })
664+}
665+
666+func FuzzParseQueryExtensionReply(f *testing.F) {
667+ f.Add(make([]byte, 32))
668+ if raw, err := xtest.LoadHex("../testdata/golden/xproto/QueryExtension.reply.hex"); err != nil {
669+ f.Fatal(err)
670+ } else {
671+ f.Add(raw)
672+ }
673+ f.Fuzz(func(t *testing.T, raw []byte) {
674+ r, ok := ParseQueryExtensionReply(raw)
675+ if !ok {
676+ if len(raw) >= 32 {
677+ t.Fatal("rejected a complete fixed-size reply")
678+ }
679+ return
680+ }
681+ if len(r.Raw()) != len(raw) {
682+ t.Fatal("Raw must return the parsed bytes")
683+ }
684+ _ = r.Present()
685+ _ = r.MajorOpcode()
686+ _ = r.FirstEvent()
687+ _ = r.FirstError()
688+ })
689+}
690+
691+func FuzzParseListExtensionsReply(f *testing.F) {
692+ f.Add(make([]byte, 32))
693+ if raw, err := xtest.LoadHex("../testdata/golden/xproto/ListExtensions.reply.hex"); err != nil {
694+ f.Fatal(err)
695+ } else {
696+ f.Add(raw)
697+ }
698+ f.Fuzz(func(t *testing.T, raw []byte) {
699+ r, ok := ParseListExtensionsReply(raw)
700+ if !ok {
701+ return
702+ }
703+ if len(r.Raw()) != len(raw) {
704+ t.Fatal("Raw must return the parsed bytes")
705+ }
706+ _ = r.NamesLen()
707+ {
708+ it0 := r.Names()
709+ for it0.Next() {
710+ _ = it0.Value().NameLen()
711+ _ = len(it0.Value().Name())
712+ }
713+ if it0.Err() {
714+ t.Fatal("iterator error after successful Parse")
715+ }
716+ }
717+ })
718+}
719+
720+func FuzzParseGetKeyboardMappingReply(f *testing.F) {
721+ f.Add(make([]byte, 32))
722+ f.Fuzz(func(t *testing.T, raw []byte) {
723+ r, ok := ParseGetKeyboardMappingReply(raw)
724+ if !ok {
725+ return
726+ }
727+ if len(r.Raw()) != len(raw) {
728+ t.Fatal("Raw must return the parsed bytes")
729+ }
730+ _ = r.KeysymsPerKeycode()
731+ {
732+ l0 := r.Keysyms()
733+ for i := 0; i < l0.Len(); i++ {
734+ _ = l0.At(i)
735+ }
736+ }
737+ })
738+}
739+
740+func FuzzParseGetKeyboardControlReply(f *testing.F) {
741+ f.Add(make([]byte, 52))
742+ f.Fuzz(func(t *testing.T, raw []byte) {
743+ r, ok := ParseGetKeyboardControlReply(raw)
744+ if !ok {
745+ if len(raw) >= 52 {
746+ t.Fatal("rejected a complete fixed-size reply")
747+ }
748+ return
749+ }
750+ if len(r.Raw()) != len(raw) {
751+ t.Fatal("Raw must return the parsed bytes")
752+ }
753+ _ = r.GlobalAutoRepeat()
754+ _ = r.LedMask()
755+ _ = r.KeyClickPercent()
756+ _ = r.BellPercent()
757+ _ = r.BellPitch()
758+ _ = r.BellDuration()
759+ _ = len(r.AutoRepeats())
760+ })
761+}
762+
763+func FuzzParseGetPointerControlReply(f *testing.F) {
764+ f.Add(make([]byte, 32))
765+ f.Fuzz(func(t *testing.T, raw []byte) {
766+ r, ok := ParseGetPointerControlReply(raw)
767+ if !ok {
768+ if len(raw) >= 32 {
769+ t.Fatal("rejected a complete fixed-size reply")
770+ }
771+ return
772+ }
773+ if len(r.Raw()) != len(raw) {
774+ t.Fatal("Raw must return the parsed bytes")
775+ }
776+ _ = r.AccelerationNumerator()
777+ _ = r.AccelerationDenominator()
778+ _ = r.Threshold()
779+ })
780+}
781+
782+func FuzzParseGetScreenSaverReply(f *testing.F) {
783+ f.Add(make([]byte, 32))
784+ f.Fuzz(func(t *testing.T, raw []byte) {
785+ r, ok := ParseGetScreenSaverReply(raw)
786+ if !ok {
787+ if len(raw) >= 32 {
788+ t.Fatal("rejected a complete fixed-size reply")
789+ }
790+ return
791+ }
792+ if len(r.Raw()) != len(raw) {
793+ t.Fatal("Raw must return the parsed bytes")
794+ }
795+ _ = r.Timeout()
796+ _ = r.Interval()
797+ _ = r.PreferBlanking()
798+ _ = r.AllowExposures()
799+ })
800+}
801+
802+func FuzzParseListHostsReply(f *testing.F) {
803+ f.Add(make([]byte, 32))
804+ f.Fuzz(func(t *testing.T, raw []byte) {
805+ r, ok := ParseListHostsReply(raw)
806+ if !ok {
807+ return
808+ }
809+ if len(r.Raw()) != len(raw) {
810+ t.Fatal("Raw must return the parsed bytes")
811+ }
812+ _ = r.Mode()
813+ _ = r.HostsLen()
814+ {
815+ it0 := r.Hosts()
816+ for it0.Next() {
817+ _ = it0.Value().Family()
818+ _ = it0.Value().AddressLen()
819+ _ = len(it0.Value().Address())
820+ }
821+ if it0.Err() {
822+ t.Fatal("iterator error after successful Parse")
823+ }
824+ }
825+ })
826+}
827+
828+func FuzzParseSetPointerMappingReply(f *testing.F) {
829+ f.Add(make([]byte, 32))
830+ f.Fuzz(func(t *testing.T, raw []byte) {
831+ r, ok := ParseSetPointerMappingReply(raw)
832+ if !ok {
833+ if len(raw) >= 32 {
834+ t.Fatal("rejected a complete fixed-size reply")
835+ }
836+ return
837+ }
838+ if len(r.Raw()) != len(raw) {
839+ t.Fatal("Raw must return the parsed bytes")
840+ }
841+ _ = r.Status()
842+ })
843+}
844+
845+func FuzzParseGetPointerMappingReply(f *testing.F) {
846+ f.Add(make([]byte, 32))
847+ f.Fuzz(func(t *testing.T, raw []byte) {
848+ r, ok := ParseGetPointerMappingReply(raw)
849+ if !ok {
850+ return
851+ }
852+ if len(r.Raw()) != len(raw) {
853+ t.Fatal("Raw must return the parsed bytes")
854+ }
855+ _ = r.MapLen()
856+ _ = len(r.Map())
857+ })
858+}
859+
860+func FuzzParseSetModifierMappingReply(f *testing.F) {
861+ f.Add(make([]byte, 32))
862+ f.Fuzz(func(t *testing.T, raw []byte) {
863+ r, ok := ParseSetModifierMappingReply(raw)
864+ if !ok {
865+ if len(raw) >= 32 {
866+ t.Fatal("rejected a complete fixed-size reply")
867+ }
868+ return
869+ }
870+ if len(r.Raw()) != len(raw) {
871+ t.Fatal("Raw must return the parsed bytes")
872+ }
873+ _ = r.Status()
874+ })
875+}
876+
877+func FuzzParseGetModifierMappingReply(f *testing.F) {
878+ f.Add(make([]byte, 32))
879+ f.Fuzz(func(t *testing.T, raw []byte) {
880+ r, ok := ParseGetModifierMappingReply(raw)
881+ if !ok {
882+ return
883+ }
884+ if len(r.Raw()) != len(raw) {
885+ t.Fatal("Raw must return the parsed bytes")
886+ }
887+ _ = r.KeycodesPerModifier()
888+ {
889+ l0 := r.Keycodes()
890+ for i := 0; i < l0.Len(); i++ {
891+ _ = l0.At(i)
892+ }
893+ }
894+ })
895+}
A xproto/replies_generated.go +1964 -0
@@ -0,0 +1,1964 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xproto
3+
4+import "encoding/binary"
5+
6+// GetWindowAttributesReply is a zero-copy view over a GetWindowAttributes reply; offsets count from reply byte 0.
7+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
8+type GetWindowAttributesReply struct{ raw []byte }
9+
10+// ParseGetWindowAttributesReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
11+func ParseGetWindowAttributesReply(raw []byte) (GetWindowAttributesReply, bool) {
12+ if len(raw) < 44 {
13+ return GetWindowAttributesReply{}, false
14+ }
15+ r := GetWindowAttributesReply{raw: raw}
16+ return r, true
17+}
18+func (r GetWindowAttributesReply) Raw() []byte { return r.raw }
19+func (r GetWindowAttributesReply) BackingStore() BackingStore { return BackingStore(r.raw[1:][0]) }
20+func (r GetWindowAttributesReply) Visual() Visualid {
21+ return Visualid(binary.LittleEndian.Uint32(r.raw[8:]))
22+}
23+func (r GetWindowAttributesReply) Class() WindowClass {
24+ return WindowClass(binary.LittleEndian.Uint16(r.raw[12:]))
25+}
26+func (r GetWindowAttributesReply) BitGravity() Gravity { return Gravity(r.raw[14:][0]) }
27+func (r GetWindowAttributesReply) WinGravity() Gravity { return Gravity(r.raw[15:][0]) }
28+func (r GetWindowAttributesReply) BackingPlanes() uint32 {
29+ return uint32(binary.LittleEndian.Uint32(r.raw[16:]))
30+}
31+func (r GetWindowAttributesReply) BackingPixel() uint32 {
32+ return uint32(binary.LittleEndian.Uint32(r.raw[20:]))
33+}
34+func (r GetWindowAttributesReply) SaveUnder() bool { return (r.raw[24:][0] != 0) }
35+func (r GetWindowAttributesReply) MapIsInstalled() bool { return (r.raw[25:][0] != 0) }
36+func (r GetWindowAttributesReply) MapState() MapState { return MapState(r.raw[26:][0]) }
37+func (r GetWindowAttributesReply) OverrideRedirect() bool { return (r.raw[27:][0] != 0) }
38+func (r GetWindowAttributesReply) Colormap() Colormap {
39+ return Colormap(binary.LittleEndian.Uint32(r.raw[28:]))
40+}
41+func (r GetWindowAttributesReply) AllEventMasks() EventMask {
42+ return EventMask(binary.LittleEndian.Uint32(r.raw[32:]))
43+}
44+func (r GetWindowAttributesReply) YourEventMask() EventMask {
45+ return EventMask(binary.LittleEndian.Uint32(r.raw[36:]))
46+}
47+func (r GetWindowAttributesReply) DoNotPropagateMask() EventMask {
48+ return EventMask(binary.LittleEndian.Uint16(r.raw[40:]))
49+}
50+
51+// GetGeometryReply is a zero-copy view over a GetGeometry reply; offsets count from reply byte 0.
52+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
53+type GetGeometryReply struct{ raw []byte }
54+
55+// ParseGetGeometryReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
56+func ParseGetGeometryReply(raw []byte) (GetGeometryReply, bool) {
57+ if len(raw) < 32 {
58+ return GetGeometryReply{}, false
59+ }
60+ r := GetGeometryReply{raw: raw}
61+ return r, true
62+}
63+func (r GetGeometryReply) Raw() []byte { return r.raw }
64+func (r GetGeometryReply) Depth() uint8 { return uint8(r.raw[1:][0]) }
65+func (r GetGeometryReply) Root() Window { return Window(binary.LittleEndian.Uint32(r.raw[8:])) }
66+func (r GetGeometryReply) X() int16 { return int16(binary.LittleEndian.Uint16(r.raw[12:])) }
67+func (r GetGeometryReply) Y() int16 { return int16(binary.LittleEndian.Uint16(r.raw[14:])) }
68+func (r GetGeometryReply) Width() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[16:])) }
69+func (r GetGeometryReply) Height() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[18:])) }
70+func (r GetGeometryReply) BorderWidth() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[20:])) }
71+
72+// QueryTreeReply is a zero-copy view over a QueryTree reply; offsets count from reply byte 0.
73+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
74+type QueryTreeReply struct{ raw []byte }
75+
76+// ParseQueryTreeReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
77+func ParseQueryTreeReply(raw []byte) (QueryTreeReply, bool) {
78+ if len(raw) < 32 {
79+ return QueryTreeReply{}, false
80+ }
81+ r := QueryTreeReply{raw: raw}
82+ off := 32
83+ {
84+ n := int(r.ChildrenLen())
85+ if n < 0 || n > len(r.raw) {
86+ return QueryTreeReply{}, false
87+ }
88+ off += n * 4
89+ }
90+ if off > len(r.raw) {
91+ return QueryTreeReply{}, false
92+ }
93+ if off > len(r.raw) {
94+ return QueryTreeReply{}, false
95+ }
96+ return r, true
97+}
98+func (r QueryTreeReply) Raw() []byte { return r.raw }
99+func (r QueryTreeReply) Root() Window { return Window(binary.LittleEndian.Uint32(r.raw[8:])) }
100+func (r QueryTreeReply) Parent() Window { return Window(binary.LittleEndian.Uint32(r.raw[12:])) }
101+func (r QueryTreeReply) ChildrenLen() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[16:])) }
102+func (r QueryTreeReply) Children() WindowList {
103+ off := 32
104+ end := off + (int(r.ChildrenLen()))*4
105+ return WindowList{b: r.raw[off:end:end]}
106+}
107+
108+// InternAtomReply is a zero-copy view over a InternAtom reply; offsets count from reply byte 0.
109+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
110+type InternAtomReply struct{ raw []byte }
111+
112+// ParseInternAtomReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
113+func ParseInternAtomReply(raw []byte) (InternAtomReply, bool) {
114+ if len(raw) < 32 {
115+ return InternAtomReply{}, false
116+ }
117+ r := InternAtomReply{raw: raw}
118+ return r, true
119+}
120+func (r InternAtomReply) Raw() []byte { return r.raw }
121+func (r InternAtomReply) Atom() Atom { return Atom(binary.LittleEndian.Uint32(r.raw[8:])) }
122+
123+// GetAtomNameReply is a zero-copy view over a GetAtomName reply; offsets count from reply byte 0.
124+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
125+type GetAtomNameReply struct{ raw []byte }
126+
127+// ParseGetAtomNameReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
128+func ParseGetAtomNameReply(raw []byte) (GetAtomNameReply, bool) {
129+ if len(raw) < 32 {
130+ return GetAtomNameReply{}, false
131+ }
132+ r := GetAtomNameReply{raw: raw}
133+ off := 32
134+ {
135+ n := int(r.NameLen())
136+ if n < 0 || n > len(r.raw) {
137+ return GetAtomNameReply{}, false
138+ }
139+ off += n * 1
140+ }
141+ if off > len(r.raw) {
142+ return GetAtomNameReply{}, false
143+ }
144+ if off > len(r.raw) {
145+ return GetAtomNameReply{}, false
146+ }
147+ return r, true
148+}
149+func (r GetAtomNameReply) Raw() []byte { return r.raw }
150+func (r GetAtomNameReply) NameLen() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
151+func (r GetAtomNameReply) Name() []byte {
152+ off := 32
153+ end := off + int(r.NameLen())
154+ return r.raw[off:end:end]
155+}
156+
157+// GetPropertyReply is a zero-copy view over a GetProperty reply; offsets count from reply byte 0.
158+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
159+type GetPropertyReply struct{ raw []byte }
160+
161+// ParseGetPropertyReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
162+func ParseGetPropertyReply(raw []byte) (GetPropertyReply, bool) {
163+ if len(raw) < 32 {
164+ return GetPropertyReply{}, false
165+ }
166+ r := GetPropertyReply{raw: raw}
167+ off := 32
168+ {
169+ n := (int(r.ValueLen()) * (int(r.Format()) / 8))
170+ if n < 0 || n > len(r.raw) {
171+ return GetPropertyReply{}, false
172+ }
173+ off += n * 1
174+ }
175+ if off > len(r.raw) {
176+ return GetPropertyReply{}, false
177+ }
178+ if off > len(r.raw) {
179+ return GetPropertyReply{}, false
180+ }
181+ return r, true
182+}
183+func (r GetPropertyReply) Raw() []byte { return r.raw }
184+func (r GetPropertyReply) Format() uint8 { return uint8(r.raw[1:][0]) }
185+func (r GetPropertyReply) Type() Atom { return Atom(binary.LittleEndian.Uint32(r.raw[8:])) }
186+func (r GetPropertyReply) BytesAfter() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[12:])) }
187+func (r GetPropertyReply) ValueLen() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[16:])) }
188+func (r GetPropertyReply) Value() []byte {
189+ off := 32
190+ end := off + (int(r.ValueLen()) * (int(r.Format()) / 8))
191+ return r.raw[off:end:end]
192+}
193+
194+// ListPropertiesReply is a zero-copy view over a ListProperties reply; offsets count from reply byte 0.
195+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
196+type ListPropertiesReply struct{ raw []byte }
197+
198+// ParseListPropertiesReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
199+func ParseListPropertiesReply(raw []byte) (ListPropertiesReply, bool) {
200+ if len(raw) < 32 {
201+ return ListPropertiesReply{}, false
202+ }
203+ r := ListPropertiesReply{raw: raw}
204+ off := 32
205+ {
206+ n := int(r.AtomsLen())
207+ if n < 0 || n > len(r.raw) {
208+ return ListPropertiesReply{}, false
209+ }
210+ off += n * 4
211+ }
212+ if off > len(r.raw) {
213+ return ListPropertiesReply{}, false
214+ }
215+ if off > len(r.raw) {
216+ return ListPropertiesReply{}, false
217+ }
218+ return r, true
219+}
220+func (r ListPropertiesReply) Raw() []byte { return r.raw }
221+func (r ListPropertiesReply) AtomsLen() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
222+func (r ListPropertiesReply) Atoms() AtomList {
223+ off := 32
224+ end := off + (int(r.AtomsLen()))*4
225+ return AtomList{b: r.raw[off:end:end]}
226+}
227+
228+// GetSelectionOwnerReply is a zero-copy view over a GetSelectionOwner reply; offsets count from reply byte 0.
229+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
230+type GetSelectionOwnerReply struct{ raw []byte }
231+
232+// ParseGetSelectionOwnerReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
233+func ParseGetSelectionOwnerReply(raw []byte) (GetSelectionOwnerReply, bool) {
234+ if len(raw) < 32 {
235+ return GetSelectionOwnerReply{}, false
236+ }
237+ r := GetSelectionOwnerReply{raw: raw}
238+ return r, true
239+}
240+func (r GetSelectionOwnerReply) Raw() []byte { return r.raw }
241+func (r GetSelectionOwnerReply) Owner() Window { return Window(binary.LittleEndian.Uint32(r.raw[8:])) }
242+
243+// GrabPointerReply is a zero-copy view over a GrabPointer reply; offsets count from reply byte 0.
244+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
245+type GrabPointerReply struct{ raw []byte }
246+
247+// ParseGrabPointerReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
248+func ParseGrabPointerReply(raw []byte) (GrabPointerReply, bool) {
249+ if len(raw) < 32 {
250+ return GrabPointerReply{}, false
251+ }
252+ r := GrabPointerReply{raw: raw}
253+ return r, true
254+}
255+func (r GrabPointerReply) Raw() []byte { return r.raw }
256+func (r GrabPointerReply) Status() GrabStatus { return GrabStatus(r.raw[1:][0]) }
257+
258+// GrabKeyboardReply is a zero-copy view over a GrabKeyboard reply; offsets count from reply byte 0.
259+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
260+type GrabKeyboardReply struct{ raw []byte }
261+
262+// ParseGrabKeyboardReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
263+func ParseGrabKeyboardReply(raw []byte) (GrabKeyboardReply, bool) {
264+ if len(raw) < 32 {
265+ return GrabKeyboardReply{}, false
266+ }
267+ r := GrabKeyboardReply{raw: raw}
268+ return r, true
269+}
270+func (r GrabKeyboardReply) Raw() []byte { return r.raw }
271+func (r GrabKeyboardReply) Status() GrabStatus { return GrabStatus(r.raw[1:][0]) }
272+
273+// QueryPointerReply is a zero-copy view over a QueryPointer reply; offsets count from reply byte 0.
274+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
275+type QueryPointerReply struct{ raw []byte }
276+
277+// ParseQueryPointerReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
278+func ParseQueryPointerReply(raw []byte) (QueryPointerReply, bool) {
279+ if len(raw) < 32 {
280+ return QueryPointerReply{}, false
281+ }
282+ r := QueryPointerReply{raw: raw}
283+ return r, true
284+}
285+func (r QueryPointerReply) Raw() []byte { return r.raw }
286+func (r QueryPointerReply) SameScreen() bool { return (r.raw[1:][0] != 0) }
287+func (r QueryPointerReply) Root() Window { return Window(binary.LittleEndian.Uint32(r.raw[8:])) }
288+func (r QueryPointerReply) Child() Window { return Window(binary.LittleEndian.Uint32(r.raw[12:])) }
289+func (r QueryPointerReply) RootX() int16 { return int16(binary.LittleEndian.Uint16(r.raw[16:])) }
290+func (r QueryPointerReply) RootY() int16 { return int16(binary.LittleEndian.Uint16(r.raw[18:])) }
291+func (r QueryPointerReply) WinX() int16 { return int16(binary.LittleEndian.Uint16(r.raw[20:])) }
292+func (r QueryPointerReply) WinY() int16 { return int16(binary.LittleEndian.Uint16(r.raw[22:])) }
293+func (r QueryPointerReply) Mask() KeyButMask {
294+ return KeyButMask(binary.LittleEndian.Uint16(r.raw[24:]))
295+}
296+
297+// GetMotionEventsReply is a zero-copy view over a GetMotionEvents reply; offsets count from reply byte 0.
298+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
299+type GetMotionEventsReply struct{ raw []byte }
300+
301+// ParseGetMotionEventsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
302+func ParseGetMotionEventsReply(raw []byte) (GetMotionEventsReply, bool) {
303+ if len(raw) < 32 {
304+ return GetMotionEventsReply{}, false
305+ }
306+ r := GetMotionEventsReply{raw: raw}
307+ off := 32
308+ {
309+ n := int(r.EventsLen())
310+ if n < 0 || n > len(r.raw) {
311+ return GetMotionEventsReply{}, false
312+ }
313+ off += n * 8
314+ }
315+ if off > len(r.raw) {
316+ return GetMotionEventsReply{}, false
317+ }
318+ if off > len(r.raw) {
319+ return GetMotionEventsReply{}, false
320+ }
321+ return r, true
322+}
323+func (r GetMotionEventsReply) Raw() []byte { return r.raw }
324+func (r GetMotionEventsReply) EventsLen() uint32 {
325+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
326+}
327+func (r GetMotionEventsReply) Events() TimecoordList {
328+ off := 32
329+ end := off + (int(r.EventsLen()))*8
330+ return TimecoordList{b: r.raw[off:end:end]}
331+}
332+
333+// TranslateCoordinatesReply is a zero-copy view over a TranslateCoordinates reply; offsets count from reply byte 0.
334+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
335+type TranslateCoordinatesReply struct{ raw []byte }
336+
337+// ParseTranslateCoordinatesReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
338+func ParseTranslateCoordinatesReply(raw []byte) (TranslateCoordinatesReply, bool) {
339+ if len(raw) < 32 {
340+ return TranslateCoordinatesReply{}, false
341+ }
342+ r := TranslateCoordinatesReply{raw: raw}
343+ return r, true
344+}
345+func (r TranslateCoordinatesReply) Raw() []byte { return r.raw }
346+func (r TranslateCoordinatesReply) SameScreen() bool { return (r.raw[1:][0] != 0) }
347+func (r TranslateCoordinatesReply) Child() Window {
348+ return Window(binary.LittleEndian.Uint32(r.raw[8:]))
349+}
350+func (r TranslateCoordinatesReply) DstX() int16 { return int16(binary.LittleEndian.Uint16(r.raw[12:])) }
351+func (r TranslateCoordinatesReply) DstY() int16 { return int16(binary.LittleEndian.Uint16(r.raw[14:])) }
352+
353+// GetInputFocusReply is a zero-copy view over a GetInputFocus reply; offsets count from reply byte 0.
354+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
355+type GetInputFocusReply struct{ raw []byte }
356+
357+// ParseGetInputFocusReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
358+func ParseGetInputFocusReply(raw []byte) (GetInputFocusReply, bool) {
359+ if len(raw) < 32 {
360+ return GetInputFocusReply{}, false
361+ }
362+ r := GetInputFocusReply{raw: raw}
363+ return r, true
364+}
365+func (r GetInputFocusReply) Raw() []byte { return r.raw }
366+func (r GetInputFocusReply) RevertTo() InputFocus { return InputFocus(r.raw[1:][0]) }
367+func (r GetInputFocusReply) Focus() Window { return Window(binary.LittleEndian.Uint32(r.raw[8:])) }
368+
369+// QueryKeymapReply is a zero-copy view over a QueryKeymap reply; offsets count from reply byte 0.
370+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
371+type QueryKeymapReply struct{ raw []byte }
372+
373+// ParseQueryKeymapReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
374+func ParseQueryKeymapReply(raw []byte) (QueryKeymapReply, bool) {
375+ if len(raw) < 40 {
376+ return QueryKeymapReply{}, false
377+ }
378+ r := QueryKeymapReply{raw: raw}
379+ return r, true
380+}
381+func (r QueryKeymapReply) Raw() []byte { return r.raw }
382+func (r QueryKeymapReply) Keys() []byte { off := 8; end := off + 32; return r.raw[off:end:end] }
383+
384+// QueryFontReply is a zero-copy view over a QueryFont reply; offsets count from reply byte 0.
385+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
386+type QueryFontReply struct{ raw []byte }
387+
388+// ParseQueryFontReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
389+func ParseQueryFontReply(raw []byte) (QueryFontReply, bool) {
390+ if len(raw) < 60 {
391+ return QueryFontReply{}, false
392+ }
393+ r := QueryFontReply{raw: raw}
394+ off := 60
395+ {
396+ n := int(r.PropertiesLen())
397+ if n < 0 || n > len(r.raw) {
398+ return QueryFontReply{}, false
399+ }
400+ off += n * 8
401+ }
402+ if off > len(r.raw) {
403+ return QueryFontReply{}, false
404+ }
405+ {
406+ n := int(r.CharInfosLen())
407+ if n < 0 || n > len(r.raw) {
408+ return QueryFontReply{}, false
409+ }
410+ off += n * 12
411+ }
412+ if off > len(r.raw) {
413+ return QueryFontReply{}, false
414+ }
415+ if off > len(r.raw) {
416+ return QueryFontReply{}, false
417+ }
418+ return r, true
419+}
420+func (r QueryFontReply) Raw() []byte { return r.raw }
421+func (r QueryFontReply) MinBounds() Charinfo { return GetCharinfo(r.raw[8:]) }
422+func (r QueryFontReply) MaxBounds() Charinfo { return GetCharinfo(r.raw[24:]) }
423+func (r QueryFontReply) MinCharOrByte2() uint16 {
424+ return uint16(binary.LittleEndian.Uint16(r.raw[40:]))
425+}
426+func (r QueryFontReply) MaxCharOrByte2() uint16 {
427+ return uint16(binary.LittleEndian.Uint16(r.raw[42:]))
428+}
429+func (r QueryFontReply) DefaultChar() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[44:])) }
430+func (r QueryFontReply) PropertiesLen() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[46:])) }
431+func (r QueryFontReply) DrawDirection() FontDraw { return FontDraw(r.raw[48:][0]) }
432+func (r QueryFontReply) MinByte1() uint8 { return uint8(r.raw[49:][0]) }
433+func (r QueryFontReply) MaxByte1() uint8 { return uint8(r.raw[50:][0]) }
434+func (r QueryFontReply) AllCharsExist() bool { return (r.raw[51:][0] != 0) }
435+func (r QueryFontReply) FontAscent() int16 { return int16(binary.LittleEndian.Uint16(r.raw[52:])) }
436+func (r QueryFontReply) FontDescent() int16 { return int16(binary.LittleEndian.Uint16(r.raw[54:])) }
437+func (r QueryFontReply) CharInfosLen() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[56:])) }
438+func (r QueryFontReply) Properties() FontpropList {
439+ off := 60
440+ end := off + (int(r.PropertiesLen()))*8
441+ return FontpropList{b: r.raw[off:end:end]}
442+}
443+func (r QueryFontReply) CharInfos() CharinfoList {
444+ off := 60
445+ {
446+ n := int(r.PropertiesLen())
447+ off += n * 8
448+ }
449+ end := off + (int(r.CharInfosLen()))*12
450+ return CharinfoList{b: r.raw[off:end:end]}
451+}
452+
453+// QueryTextExtentsReply is a zero-copy view over a QueryTextExtents reply; offsets count from reply byte 0.
454+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
455+type QueryTextExtentsReply struct{ raw []byte }
456+
457+// ParseQueryTextExtentsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
458+func ParseQueryTextExtentsReply(raw []byte) (QueryTextExtentsReply, bool) {
459+ if len(raw) < 32 {
460+ return QueryTextExtentsReply{}, false
461+ }
462+ r := QueryTextExtentsReply{raw: raw}
463+ return r, true
464+}
465+func (r QueryTextExtentsReply) Raw() []byte { return r.raw }
466+func (r QueryTextExtentsReply) DrawDirection() FontDraw { return FontDraw(r.raw[1:][0]) }
467+func (r QueryTextExtentsReply) FontAscent() int16 {
468+ return int16(binary.LittleEndian.Uint16(r.raw[8:]))
469+}
470+func (r QueryTextExtentsReply) FontDescent() int16 {
471+ return int16(binary.LittleEndian.Uint16(r.raw[10:]))
472+}
473+func (r QueryTextExtentsReply) OverallAscent() int16 {
474+ return int16(binary.LittleEndian.Uint16(r.raw[12:]))
475+}
476+func (r QueryTextExtentsReply) OverallDescent() int16 {
477+ return int16(binary.LittleEndian.Uint16(r.raw[14:]))
478+}
479+func (r QueryTextExtentsReply) OverallWidth() int32 {
480+ return int32(binary.LittleEndian.Uint32(r.raw[16:]))
481+}
482+func (r QueryTextExtentsReply) OverallLeft() int32 {
483+ return int32(binary.LittleEndian.Uint32(r.raw[20:]))
484+}
485+func (r QueryTextExtentsReply) OverallRight() int32 {
486+ return int32(binary.LittleEndian.Uint32(r.raw[24:]))
487+}
488+
489+// ListFontsReply is a zero-copy view over a ListFonts reply; offsets count from reply byte 0.
490+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
491+type ListFontsReply struct{ raw []byte }
492+
493+// ParseListFontsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
494+func ParseListFontsReply(raw []byte) (ListFontsReply, bool) {
495+ if len(raw) < 32 {
496+ return ListFontsReply{}, false
497+ }
498+ r := ListFontsReply{raw: raw}
499+ off := 32
500+ {
501+ n := int(r.NamesLen())
502+ if off > len(r.raw) || n < 0 || n > len(r.raw) {
503+ return ListFontsReply{}, false
504+ }
505+ it := NewStrIter(r.raw[off:], n)
506+ for it.Next() {
507+ off += it.Value().Size()
508+ }
509+ if it.Err() {
510+ return ListFontsReply{}, false
511+ }
512+ }
513+ if off > len(r.raw) {
514+ return ListFontsReply{}, false
515+ }
516+ return r, true
517+}
518+func (r ListFontsReply) Raw() []byte { return r.raw }
519+func (r ListFontsReply) NamesLen() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
520+func (r ListFontsReply) Names() StrIter { off := 32; return NewStrIter(r.raw[off:], int(r.NamesLen())) }
521+
522+// ListFontsWithInfoReply is a zero-copy view over a ListFontsWithInfo reply; offsets count from reply byte 0.
523+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
524+type ListFontsWithInfoReply struct{ raw []byte }
525+
526+// ParseListFontsWithInfoReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
527+func ParseListFontsWithInfoReply(raw []byte) (ListFontsWithInfoReply, bool) {
528+ if len(raw) < 60 {
529+ return ListFontsWithInfoReply{}, false
530+ }
531+ r := ListFontsWithInfoReply{raw: raw}
532+ off := 60
533+ {
534+ n := int(r.PropertiesLen())
535+ if n < 0 || n > len(r.raw) {
536+ return ListFontsWithInfoReply{}, false
537+ }
538+ off += n * 8
539+ }
540+ if off > len(r.raw) {
541+ return ListFontsWithInfoReply{}, false
542+ }
543+ {
544+ n := int(r.NameLen())
545+ if n < 0 || n > len(r.raw) {
546+ return ListFontsWithInfoReply{}, false
547+ }
548+ off += n * 1
549+ }
550+ if off > len(r.raw) {
551+ return ListFontsWithInfoReply{}, false
552+ }
553+ if off > len(r.raw) {
554+ return ListFontsWithInfoReply{}, false
555+ }
556+ return r, true
557+}
558+func (r ListFontsWithInfoReply) Raw() []byte { return r.raw }
559+func (r ListFontsWithInfoReply) NameLen() uint8 { return uint8(r.raw[1:][0]) }
560+func (r ListFontsWithInfoReply) MinBounds() Charinfo { return GetCharinfo(r.raw[8:]) }
561+func (r ListFontsWithInfoReply) MaxBounds() Charinfo { return GetCharinfo(r.raw[24:]) }
562+func (r ListFontsWithInfoReply) MinCharOrByte2() uint16 {
563+ return uint16(binary.LittleEndian.Uint16(r.raw[40:]))
564+}
565+func (r ListFontsWithInfoReply) MaxCharOrByte2() uint16 {
566+ return uint16(binary.LittleEndian.Uint16(r.raw[42:]))
567+}
568+func (r ListFontsWithInfoReply) DefaultChar() uint16 {
569+ return uint16(binary.LittleEndian.Uint16(r.raw[44:]))
570+}
571+func (r ListFontsWithInfoReply) PropertiesLen() uint16 {
572+ return uint16(binary.LittleEndian.Uint16(r.raw[46:]))
573+}
574+func (r ListFontsWithInfoReply) DrawDirection() FontDraw { return FontDraw(r.raw[48:][0]) }
575+func (r ListFontsWithInfoReply) MinByte1() uint8 { return uint8(r.raw[49:][0]) }
576+func (r ListFontsWithInfoReply) MaxByte1() uint8 { return uint8(r.raw[50:][0]) }
577+func (r ListFontsWithInfoReply) AllCharsExist() bool { return (r.raw[51:][0] != 0) }
578+func (r ListFontsWithInfoReply) FontAscent() int16 {
579+ return int16(binary.LittleEndian.Uint16(r.raw[52:]))
580+}
581+func (r ListFontsWithInfoReply) FontDescent() int16 {
582+ return int16(binary.LittleEndian.Uint16(r.raw[54:]))
583+}
584+func (r ListFontsWithInfoReply) RepliesHint() uint32 {
585+ return uint32(binary.LittleEndian.Uint32(r.raw[56:]))
586+}
587+func (r ListFontsWithInfoReply) Properties() FontpropList {
588+ off := 60
589+ end := off + (int(r.PropertiesLen()))*8
590+ return FontpropList{b: r.raw[off:end:end]}
591+}
592+func (r ListFontsWithInfoReply) Name() []byte {
593+ off := 60
594+ {
595+ n := int(r.PropertiesLen())
596+ off += n * 8
597+ }
598+ end := off + int(r.NameLen())
599+ return r.raw[off:end:end]
600+}
601+
602+// GetFontPathReply is a zero-copy view over a GetFontPath reply; offsets count from reply byte 0.
603+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
604+type GetFontPathReply struct{ raw []byte }
605+
606+// ParseGetFontPathReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
607+func ParseGetFontPathReply(raw []byte) (GetFontPathReply, bool) {
608+ if len(raw) < 32 {
609+ return GetFontPathReply{}, false
610+ }
611+ r := GetFontPathReply{raw: raw}
612+ off := 32
613+ {
614+ n := int(r.PathLen())
615+ if off > len(r.raw) || n < 0 || n > len(r.raw) {
616+ return GetFontPathReply{}, false
617+ }
618+ it := NewStrIter(r.raw[off:], n)
619+ for it.Next() {
620+ off += it.Value().Size()
621+ }
622+ if it.Err() {
623+ return GetFontPathReply{}, false
624+ }
625+ }
626+ if off > len(r.raw) {
627+ return GetFontPathReply{}, false
628+ }
629+ return r, true
630+}
631+func (r GetFontPathReply) Raw() []byte { return r.raw }
632+func (r GetFontPathReply) PathLen() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
633+func (r GetFontPathReply) Path() StrIter { off := 32; return NewStrIter(r.raw[off:], int(r.PathLen())) }
634+
635+// GetImageReply is a zero-copy view over a GetImage reply; offsets count from reply byte 0.
636+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
637+type GetImageReply struct{ raw []byte }
638+
639+// ParseGetImageReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
640+func ParseGetImageReply(raw []byte) (GetImageReply, bool) {
641+ if len(raw) < 32 {
642+ return GetImageReply{}, false
643+ }
644+ r := GetImageReply{raw: raw}
645+ off := 32
646+ {
647+ n := (int(binary.LittleEndian.Uint32(r.raw[4:])) * 4)
648+ if n < 0 || n > len(r.raw) {
649+ return GetImageReply{}, false
650+ }
651+ off += n * 1
652+ }
653+ if off > len(r.raw) {
654+ return GetImageReply{}, false
655+ }
656+ if off > len(r.raw) {
657+ return GetImageReply{}, false
658+ }
659+ return r, true
660+}
661+func (r GetImageReply) Raw() []byte { return r.raw }
662+func (r GetImageReply) Depth() uint8 { return uint8(r.raw[1:][0]) }
663+func (r GetImageReply) Visual() Visualid { return Visualid(binary.LittleEndian.Uint32(r.raw[8:])) }
664+func (r GetImageReply) Data() []byte {
665+ off := 32
666+ end := off + (int(binary.LittleEndian.Uint32(r.raw[4:])) * 4)
667+ return r.raw[off:end:end]
668+}
669+
670+// ListInstalledColormapsReply is a zero-copy view over a ListInstalledColormaps reply; offsets count from reply byte 0.
671+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
672+type ListInstalledColormapsReply struct{ raw []byte }
673+
674+// ParseListInstalledColormapsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
675+func ParseListInstalledColormapsReply(raw []byte) (ListInstalledColormapsReply, bool) {
676+ if len(raw) < 32 {
677+ return ListInstalledColormapsReply{}, false
678+ }
679+ r := ListInstalledColormapsReply{raw: raw}
680+ off := 32
681+ {
682+ n := int(r.CmapsLen())
683+ if n < 0 || n > len(r.raw) {
684+ return ListInstalledColormapsReply{}, false
685+ }
686+ off += n * 4
687+ }
688+ if off > len(r.raw) {
689+ return ListInstalledColormapsReply{}, false
690+ }
691+ if off > len(r.raw) {
692+ return ListInstalledColormapsReply{}, false
693+ }
694+ return r, true
695+}
696+func (r ListInstalledColormapsReply) Raw() []byte { return r.raw }
697+func (r ListInstalledColormapsReply) CmapsLen() uint16 {
698+ return uint16(binary.LittleEndian.Uint16(r.raw[8:]))
699+}
700+func (r ListInstalledColormapsReply) Cmaps() ColormapList {
701+ off := 32
702+ end := off + (int(r.CmapsLen()))*4
703+ return ColormapList{b: r.raw[off:end:end]}
704+}
705+
706+// AllocColorReply is a zero-copy view over a AllocColor reply; offsets count from reply byte 0.
707+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
708+type AllocColorReply struct{ raw []byte }
709+
710+// ParseAllocColorReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
711+func ParseAllocColorReply(raw []byte) (AllocColorReply, bool) {
712+ if len(raw) < 32 {
713+ return AllocColorReply{}, false
714+ }
715+ r := AllocColorReply{raw: raw}
716+ return r, true
717+}
718+func (r AllocColorReply) Raw() []byte { return r.raw }
719+func (r AllocColorReply) Red() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
720+func (r AllocColorReply) Green() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[10:])) }
721+func (r AllocColorReply) Blue() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[12:])) }
722+func (r AllocColorReply) Pixel() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[16:])) }
723+
724+// AllocNamedColorReply is a zero-copy view over a AllocNamedColor reply; offsets count from reply byte 0.
725+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
726+type AllocNamedColorReply struct{ raw []byte }
727+
728+// ParseAllocNamedColorReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
729+func ParseAllocNamedColorReply(raw []byte) (AllocNamedColorReply, bool) {
730+ if len(raw) < 32 {
731+ return AllocNamedColorReply{}, false
732+ }
733+ r := AllocNamedColorReply{raw: raw}
734+ return r, true
735+}
736+func (r AllocNamedColorReply) Raw() []byte { return r.raw }
737+func (r AllocNamedColorReply) Pixel() uint32 { return uint32(binary.LittleEndian.Uint32(r.raw[8:])) }
738+func (r AllocNamedColorReply) ExactRed() uint16 {
739+ return uint16(binary.LittleEndian.Uint16(r.raw[12:]))
740+}
741+func (r AllocNamedColorReply) ExactGreen() uint16 {
742+ return uint16(binary.LittleEndian.Uint16(r.raw[14:]))
743+}
744+func (r AllocNamedColorReply) ExactBlue() uint16 {
745+ return uint16(binary.LittleEndian.Uint16(r.raw[16:]))
746+}
747+func (r AllocNamedColorReply) VisualRed() uint16 {
748+ return uint16(binary.LittleEndian.Uint16(r.raw[18:]))
749+}
750+func (r AllocNamedColorReply) VisualGreen() uint16 {
751+ return uint16(binary.LittleEndian.Uint16(r.raw[20:]))
752+}
753+func (r AllocNamedColorReply) VisualBlue() uint16 {
754+ return uint16(binary.LittleEndian.Uint16(r.raw[22:]))
755+}
756+
757+// AllocColorCellsReply is a zero-copy view over a AllocColorCells reply; offsets count from reply byte 0.
758+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
759+type AllocColorCellsReply struct{ raw []byte }
760+
761+// ParseAllocColorCellsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
762+func ParseAllocColorCellsReply(raw []byte) (AllocColorCellsReply, bool) {
763+ if len(raw) < 32 {
764+ return AllocColorCellsReply{}, false
765+ }
766+ r := AllocColorCellsReply{raw: raw}
767+ off := 32
768+ {
769+ n := int(r.PixelsLen())
770+ if n < 0 || n > len(r.raw) {
771+ return AllocColorCellsReply{}, false
772+ }
773+ off += n * 4
774+ }
775+ if off > len(r.raw) {
776+ return AllocColorCellsReply{}, false
777+ }
778+ {
779+ n := int(r.MasksLen())
780+ if n < 0 || n > len(r.raw) {
781+ return AllocColorCellsReply{}, false
782+ }
783+ off += n * 4
784+ }
785+ if off > len(r.raw) {
786+ return AllocColorCellsReply{}, false
787+ }
788+ if off > len(r.raw) {
789+ return AllocColorCellsReply{}, false
790+ }
791+ return r, true
792+}
793+func (r AllocColorCellsReply) Raw() []byte { return r.raw }
794+func (r AllocColorCellsReply) PixelsLen() uint16 {
795+ return uint16(binary.LittleEndian.Uint16(r.raw[8:]))
796+}
797+func (r AllocColorCellsReply) MasksLen() uint16 {
798+ return uint16(binary.LittleEndian.Uint16(r.raw[10:]))
799+}
800+func (r AllocColorCellsReply) Pixels() Uint32List {
801+ off := 32
802+ end := off + (int(r.PixelsLen()))*4
803+ return Uint32List{b: r.raw[off:end:end]}
804+}
805+func (r AllocColorCellsReply) Masks() Uint32List {
806+ off := 32
807+ {
808+ n := int(r.PixelsLen())
809+ off += n * 4
810+ }
811+ end := off + (int(r.MasksLen()))*4
812+ return Uint32List{b: r.raw[off:end:end]}
813+}
814+
815+// AllocColorPlanesReply is a zero-copy view over a AllocColorPlanes reply; offsets count from reply byte 0.
816+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
817+type AllocColorPlanesReply struct{ raw []byte }
818+
819+// ParseAllocColorPlanesReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
820+func ParseAllocColorPlanesReply(raw []byte) (AllocColorPlanesReply, bool) {
821+ if len(raw) < 32 {
822+ return AllocColorPlanesReply{}, false
823+ }
824+ r := AllocColorPlanesReply{raw: raw}
825+ off := 32
826+ {
827+ n := int(r.PixelsLen())
828+ if n < 0 || n > len(r.raw) {
829+ return AllocColorPlanesReply{}, false
830+ }
831+ off += n * 4
832+ }
833+ if off > len(r.raw) {
834+ return AllocColorPlanesReply{}, false
835+ }
836+ if off > len(r.raw) {
837+ return AllocColorPlanesReply{}, false
838+ }
839+ return r, true
840+}
841+func (r AllocColorPlanesReply) Raw() []byte { return r.raw }
842+func (r AllocColorPlanesReply) PixelsLen() uint16 {
843+ return uint16(binary.LittleEndian.Uint16(r.raw[8:]))
844+}
845+func (r AllocColorPlanesReply) RedMask() uint32 {
846+ return uint32(binary.LittleEndian.Uint32(r.raw[12:]))
847+}
848+func (r AllocColorPlanesReply) GreenMask() uint32 {
849+ return uint32(binary.LittleEndian.Uint32(r.raw[16:]))
850+}
851+func (r AllocColorPlanesReply) BlueMask() uint32 {
852+ return uint32(binary.LittleEndian.Uint32(r.raw[20:]))
853+}
854+func (r AllocColorPlanesReply) Pixels() Uint32List {
855+ off := 32
856+ end := off + (int(r.PixelsLen()))*4
857+ return Uint32List{b: r.raw[off:end:end]}
858+}
859+
860+// QueryColorsReply is a zero-copy view over a QueryColors reply; offsets count from reply byte 0.
861+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
862+type QueryColorsReply struct{ raw []byte }
863+
864+// ParseQueryColorsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
865+func ParseQueryColorsReply(raw []byte) (QueryColorsReply, bool) {
866+ if len(raw) < 32 {
867+ return QueryColorsReply{}, false
868+ }
869+ r := QueryColorsReply{raw: raw}
870+ off := 32
871+ {
872+ n := int(r.ColorsLen())
873+ if n < 0 || n > len(r.raw) {
874+ return QueryColorsReply{}, false
875+ }
876+ off += n * 8
877+ }
878+ if off > len(r.raw) {
879+ return QueryColorsReply{}, false
880+ }
881+ if off > len(r.raw) {
882+ return QueryColorsReply{}, false
883+ }
884+ return r, true
885+}
886+func (r QueryColorsReply) Raw() []byte { return r.raw }
887+func (r QueryColorsReply) ColorsLen() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
888+func (r QueryColorsReply) Colors() RgbList {
889+ off := 32
890+ end := off + (int(r.ColorsLen()))*8
891+ return RgbList{b: r.raw[off:end:end]}
892+}
893+
894+// LookupColorReply is a zero-copy view over a LookupColor reply; offsets count from reply byte 0.
895+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
896+type LookupColorReply struct{ raw []byte }
897+
898+// ParseLookupColorReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
899+func ParseLookupColorReply(raw []byte) (LookupColorReply, bool) {
900+ if len(raw) < 32 {
901+ return LookupColorReply{}, false
902+ }
903+ r := LookupColorReply{raw: raw}
904+ return r, true
905+}
906+func (r LookupColorReply) Raw() []byte { return r.raw }
907+func (r LookupColorReply) ExactRed() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
908+func (r LookupColorReply) ExactGreen() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[10:])) }
909+func (r LookupColorReply) ExactBlue() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[12:])) }
910+func (r LookupColorReply) VisualRed() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[14:])) }
911+func (r LookupColorReply) VisualGreen() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[16:])) }
912+func (r LookupColorReply) VisualBlue() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[18:])) }
913+
914+// QueryBestSizeReply is a zero-copy view over a QueryBestSize reply; offsets count from reply byte 0.
915+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
916+type QueryBestSizeReply struct{ raw []byte }
917+
918+// ParseQueryBestSizeReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
919+func ParseQueryBestSizeReply(raw []byte) (QueryBestSizeReply, bool) {
920+ if len(raw) < 32 {
921+ return QueryBestSizeReply{}, false
922+ }
923+ r := QueryBestSizeReply{raw: raw}
924+ return r, true
925+}
926+func (r QueryBestSizeReply) Raw() []byte { return r.raw }
927+func (r QueryBestSizeReply) Width() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
928+func (r QueryBestSizeReply) Height() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[10:])) }
929+
930+// QueryExtensionReply is a zero-copy view over a QueryExtension reply; offsets count from reply byte 0.
931+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
932+type QueryExtensionReply struct{ raw []byte }
933+
934+// ParseQueryExtensionReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
935+func ParseQueryExtensionReply(raw []byte) (QueryExtensionReply, bool) {
936+ if len(raw) < 32 {
937+ return QueryExtensionReply{}, false
938+ }
939+ r := QueryExtensionReply{raw: raw}
940+ return r, true
941+}
942+func (r QueryExtensionReply) Raw() []byte { return r.raw }
943+func (r QueryExtensionReply) Present() bool { return (r.raw[8:][0] != 0) }
944+func (r QueryExtensionReply) MajorOpcode() uint8 { return uint8(r.raw[9:][0]) }
945+func (r QueryExtensionReply) FirstEvent() uint8 { return uint8(r.raw[10:][0]) }
946+func (r QueryExtensionReply) FirstError() uint8 { return uint8(r.raw[11:][0]) }
947+
948+// ListExtensionsReply is a zero-copy view over a ListExtensions reply; offsets count from reply byte 0.
949+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
950+type ListExtensionsReply struct{ raw []byte }
951+
952+// ParseListExtensionsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
953+func ParseListExtensionsReply(raw []byte) (ListExtensionsReply, bool) {
954+ if len(raw) < 32 {
955+ return ListExtensionsReply{}, false
956+ }
957+ r := ListExtensionsReply{raw: raw}
958+ off := 32
959+ {
960+ n := int(r.NamesLen())
961+ if off > len(r.raw) || n < 0 || n > len(r.raw) {
962+ return ListExtensionsReply{}, false
963+ }
964+ it := NewStrIter(r.raw[off:], n)
965+ for it.Next() {
966+ off += it.Value().Size()
967+ }
968+ if it.Err() {
969+ return ListExtensionsReply{}, false
970+ }
971+ }
972+ if off > len(r.raw) {
973+ return ListExtensionsReply{}, false
974+ }
975+ return r, true
976+}
977+func (r ListExtensionsReply) Raw() []byte { return r.raw }
978+func (r ListExtensionsReply) NamesLen() uint8 { return uint8(r.raw[1:][0]) }
979+func (r ListExtensionsReply) Names() StrIter {
980+ off := 32
981+ return NewStrIter(r.raw[off:], int(r.NamesLen()))
982+}
983+
984+// GetKeyboardMappingReply is a zero-copy view over a GetKeyboardMapping reply; offsets count from reply byte 0.
985+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
986+type GetKeyboardMappingReply struct{ raw []byte }
987+
988+// ParseGetKeyboardMappingReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
989+func ParseGetKeyboardMappingReply(raw []byte) (GetKeyboardMappingReply, bool) {
990+ if len(raw) < 32 {
991+ return GetKeyboardMappingReply{}, false
992+ }
993+ r := GetKeyboardMappingReply{raw: raw}
994+ off := 32
995+ {
996+ n := int(binary.LittleEndian.Uint32(r.raw[4:]))
997+ if n < 0 || n > len(r.raw) {
998+ return GetKeyboardMappingReply{}, false
999+ }
1000+ off += n * 4
1001+ }
1002+ if off > len(r.raw) {
1003+ return GetKeyboardMappingReply{}, false
1004+ }
1005+ if off > len(r.raw) {
1006+ return GetKeyboardMappingReply{}, false
1007+ }
1008+ return r, true
1009+}
1010+func (r GetKeyboardMappingReply) Raw() []byte { return r.raw }
1011+func (r GetKeyboardMappingReply) KeysymsPerKeycode() byte { return byte(r.raw[1:][0]) }
1012+func (r GetKeyboardMappingReply) Keysyms() KeysymList {
1013+ off := 32
1014+ end := off + (int(binary.LittleEndian.Uint32(r.raw[4:])))*4
1015+ return KeysymList{b: r.raw[off:end:end]}
1016+}
1017+
1018+// GetKeyboardControlReply is a zero-copy view over a GetKeyboardControl reply; offsets count from reply byte 0.
1019+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
1020+type GetKeyboardControlReply struct{ raw []byte }
1021+
1022+// ParseGetKeyboardControlReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
1023+func ParseGetKeyboardControlReply(raw []byte) (GetKeyboardControlReply, bool) {
1024+ if len(raw) < 52 {
1025+ return GetKeyboardControlReply{}, false
1026+ }
1027+ r := GetKeyboardControlReply{raw: raw}
1028+ return r, true
1029+}
1030+func (r GetKeyboardControlReply) Raw() []byte { return r.raw }
1031+func (r GetKeyboardControlReply) GlobalAutoRepeat() AutoRepeatMode {
1032+ return AutoRepeatMode(r.raw[1:][0])
1033+}
1034+func (r GetKeyboardControlReply) LedMask() uint32 {
1035+ return uint32(binary.LittleEndian.Uint32(r.raw[8:]))
1036+}
1037+func (r GetKeyboardControlReply) KeyClickPercent() uint8 { return uint8(r.raw[12:][0]) }
1038+func (r GetKeyboardControlReply) BellPercent() uint8 { return uint8(r.raw[13:][0]) }
1039+func (r GetKeyboardControlReply) BellPitch() uint16 {
1040+ return uint16(binary.LittleEndian.Uint16(r.raw[14:]))
1041+}
1042+func (r GetKeyboardControlReply) BellDuration() uint16 {
1043+ return uint16(binary.LittleEndian.Uint16(r.raw[16:]))
1044+}
1045+func (r GetKeyboardControlReply) AutoRepeats() []byte {
1046+ off := 20
1047+ end := off + 32
1048+ return r.raw[off:end:end]
1049+}
1050+
1051+// GetPointerControlReply is a zero-copy view over a GetPointerControl reply; offsets count from reply byte 0.
1052+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
1053+type GetPointerControlReply struct{ raw []byte }
1054+
1055+// ParseGetPointerControlReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
1056+func ParseGetPointerControlReply(raw []byte) (GetPointerControlReply, bool) {
1057+ if len(raw) < 32 {
1058+ return GetPointerControlReply{}, false
1059+ }
1060+ r := GetPointerControlReply{raw: raw}
1061+ return r, true
1062+}
1063+func (r GetPointerControlReply) Raw() []byte { return r.raw }
1064+func (r GetPointerControlReply) AccelerationNumerator() uint16 {
1065+ return uint16(binary.LittleEndian.Uint16(r.raw[8:]))
1066+}
1067+func (r GetPointerControlReply) AccelerationDenominator() uint16 {
1068+ return uint16(binary.LittleEndian.Uint16(r.raw[10:]))
1069+}
1070+func (r GetPointerControlReply) Threshold() uint16 {
1071+ return uint16(binary.LittleEndian.Uint16(r.raw[12:]))
1072+}
1073+
1074+// GetScreenSaverReply is a zero-copy view over a GetScreenSaver reply; offsets count from reply byte 0.
1075+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
1076+type GetScreenSaverReply struct{ raw []byte }
1077+
1078+// ParseGetScreenSaverReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
1079+func ParseGetScreenSaverReply(raw []byte) (GetScreenSaverReply, bool) {
1080+ if len(raw) < 32 {
1081+ return GetScreenSaverReply{}, false
1082+ }
1083+ r := GetScreenSaverReply{raw: raw}
1084+ return r, true
1085+}
1086+func (r GetScreenSaverReply) Raw() []byte { return r.raw }
1087+func (r GetScreenSaverReply) Timeout() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
1088+func (r GetScreenSaverReply) Interval() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[10:])) }
1089+func (r GetScreenSaverReply) PreferBlanking() Blanking { return Blanking(r.raw[12:][0]) }
1090+func (r GetScreenSaverReply) AllowExposures() Exposures { return Exposures(r.raw[13:][0]) }
1091+
1092+// ListHostsReply is a zero-copy view over a ListHosts reply; offsets count from reply byte 0.
1093+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
1094+type ListHostsReply struct{ raw []byte }
1095+
1096+// ParseListHostsReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
1097+func ParseListHostsReply(raw []byte) (ListHostsReply, bool) {
1098+ if len(raw) < 32 {
1099+ return ListHostsReply{}, false
1100+ }
1101+ r := ListHostsReply{raw: raw}
1102+ off := 32
1103+ {
1104+ n := int(r.HostsLen())
1105+ if off > len(r.raw) || n < 0 || n > len(r.raw) {
1106+ return ListHostsReply{}, false
1107+ }
1108+ it := NewHostIter(r.raw[off:], n)
1109+ for it.Next() {
1110+ off += it.Value().Size()
1111+ }
1112+ if it.Err() {
1113+ return ListHostsReply{}, false
1114+ }
1115+ }
1116+ if off > len(r.raw) {
1117+ return ListHostsReply{}, false
1118+ }
1119+ return r, true
1120+}
1121+func (r ListHostsReply) Raw() []byte { return r.raw }
1122+func (r ListHostsReply) Mode() AccessControl { return AccessControl(r.raw[1:][0]) }
1123+func (r ListHostsReply) HostsLen() uint16 { return uint16(binary.LittleEndian.Uint16(r.raw[8:])) }
1124+func (r ListHostsReply) Hosts() HostIter {
1125+ off := 32
1126+ return NewHostIter(r.raw[off:], int(r.HostsLen()))
1127+}
1128+
1129+// SetPointerMappingReply is a zero-copy view over a SetPointerMapping reply; offsets count from reply byte 0.
1130+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
1131+type SetPointerMappingReply struct{ raw []byte }
1132+
1133+// ParseSetPointerMappingReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
1134+func ParseSetPointerMappingReply(raw []byte) (SetPointerMappingReply, bool) {
1135+ if len(raw) < 32 {
1136+ return SetPointerMappingReply{}, false
1137+ }
1138+ r := SetPointerMappingReply{raw: raw}
1139+ return r, true
1140+}
1141+func (r SetPointerMappingReply) Raw() []byte { return r.raw }
1142+func (r SetPointerMappingReply) Status() MappingStatus { return MappingStatus(r.raw[1:][0]) }
1143+
1144+// GetPointerMappingReply is a zero-copy view over a GetPointerMapping reply; offsets count from reply byte 0.
1145+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
1146+type GetPointerMappingReply struct{ raw []byte }
1147+
1148+// ParseGetPointerMappingReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
1149+func ParseGetPointerMappingReply(raw []byte) (GetPointerMappingReply, bool) {
1150+ if len(raw) < 32 {
1151+ return GetPointerMappingReply{}, false
1152+ }
1153+ r := GetPointerMappingReply{raw: raw}
1154+ off := 32
1155+ {
1156+ n := int(r.MapLen())
1157+ if n < 0 || n > len(r.raw) {
1158+ return GetPointerMappingReply{}, false
1159+ }
1160+ off += n * 1
1161+ }
1162+ if off > len(r.raw) {
1163+ return GetPointerMappingReply{}, false
1164+ }
1165+ if off > len(r.raw) {
1166+ return GetPointerMappingReply{}, false
1167+ }
1168+ return r, true
1169+}
1170+func (r GetPointerMappingReply) Raw() []byte { return r.raw }
1171+func (r GetPointerMappingReply) MapLen() uint8 { return uint8(r.raw[1:][0]) }
1172+func (r GetPointerMappingReply) Map() []byte {
1173+ off := 32
1174+ end := off + int(r.MapLen())
1175+ return r.raw[off:end:end]
1176+}
1177+
1178+// SetModifierMappingReply is a zero-copy view over a SetModifierMapping reply; offsets count from reply byte 0.
1179+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
1180+type SetModifierMappingReply struct{ raw []byte }
1181+
1182+// ParseSetModifierMappingReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
1183+func ParseSetModifierMappingReply(raw []byte) (SetModifierMappingReply, bool) {
1184+ if len(raw) < 32 {
1185+ return SetModifierMappingReply{}, false
1186+ }
1187+ r := SetModifierMappingReply{raw: raw}
1188+ return r, true
1189+}
1190+func (r SetModifierMappingReply) Raw() []byte { return r.raw }
1191+func (r SetModifierMappingReply) Status() MappingStatus { return MappingStatus(r.raw[1:][0]) }
1192+
1193+// GetModifierMappingReply is a zero-copy view over a GetModifierMapping reply; offsets count from reply byte 0.
1194+// It borrows the reply bytes: valid only until the Handler callback returns, because the read ring is reused. Copy what you keep.
1195+type GetModifierMappingReply struct{ raw []byte }
1196+
1197+// ParseGetModifierMappingReply validates raw (the whole reply, 32+4*length bytes) once; getters do not re-check.
1198+func ParseGetModifierMappingReply(raw []byte) (GetModifierMappingReply, bool) {
1199+ if len(raw) < 32 {
1200+ return GetModifierMappingReply{}, false
1201+ }
1202+ r := GetModifierMappingReply{raw: raw}
1203+ off := 32
1204+ {
1205+ n := (int(r.KeycodesPerModifier()) * 8)
1206+ if n < 0 || n > len(r.raw) {
1207+ return GetModifierMappingReply{}, false
1208+ }
1209+ off += n * 1
1210+ }
1211+ if off > len(r.raw) {
1212+ return GetModifierMappingReply{}, false
1213+ }
1214+ if off > len(r.raw) {
1215+ return GetModifierMappingReply{}, false
1216+ }
1217+ return r, true
1218+}
1219+func (r GetModifierMappingReply) Raw() []byte { return r.raw }
1220+func (r GetModifierMappingReply) KeycodesPerModifier() uint8 { return uint8(r.raw[1:][0]) }
1221+func (r GetModifierMappingReply) Keycodes() KeycodeList {
1222+ off := 32
1223+ end := off + (int(r.KeycodesPerModifier())*8)*1
1224+ return KeycodeList{b: r.raw[off:end:end]}
1225+}
1226+
1227+// DepthView is a zero-copy view over one wire-encoded Depth, yielded by DepthIter.
1228+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
1229+type DepthView struct{ raw []byte }
1230+
1231+func (v DepthView) Raw() []byte { return v.raw }
1232+
1233+// Size is the element's wire size, including trailing alignment.
1234+func (v DepthView) Size() int { return len(v.raw) }
1235+func sizeDepth(p []byte) int {
1236+ if len(p) < 8 {
1237+ return -1
1238+ }
1239+ v := DepthView{raw: p}
1240+ _ = v
1241+ off := 8
1242+ {
1243+ n := int(v.VisualsLen())
1244+ if n < 0 || n > len(v.raw) {
1245+ return -1
1246+ }
1247+ off += n * 24
1248+ }
1249+ if off > len(v.raw) {
1250+ return -1
1251+ }
1252+ if off > len(v.raw) {
1253+ return -1
1254+ }
1255+ return off
1256+}
1257+func (v DepthView) Depth() uint8 { return uint8(v.raw[0:][0]) }
1258+func (v DepthView) VisualsLen() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[2:])) }
1259+func (v DepthView) Visuals() VisualtypeList {
1260+ off := 8
1261+ end := off + (int(v.VisualsLen()))*24
1262+ return VisualtypeList{b: v.raw[off:end:end]}
1263+}
1264+
1265+// DepthIter walks n consecutive Depth elements; Err reports a malformed length.
1266+// It shares the lifetime of the bytes it walks.
1267+type DepthIter struct {
1268+ b []byte
1269+ n int
1270+ v DepthView
1271+ err bool
1272+}
1273+
1274+// NewDepthIter iterates n elements encoded at the start of b.
1275+func NewDepthIter(b []byte, n int) DepthIter { return DepthIter{b: b, n: n} }
1276+func (it *DepthIter) Next() bool {
1277+ if it.n <= 0 || it.err {
1278+ return false
1279+ }
1280+ s := sizeDepth(it.b)
1281+ if s < 0 {
1282+ it.err = true
1283+ it.n = 0
1284+ return false
1285+ }
1286+ it.v = DepthView{raw: it.b[:s:s]}
1287+ it.b = it.b[s:]
1288+ it.n--
1289+ return true
1290+}
1291+func (it *DepthIter) Value() DepthView { return it.v }
1292+func (it *DepthIter) Err() bool { return it.err }
1293+
1294+// ScreenView is a zero-copy view over one wire-encoded Screen, yielded by ScreenIter.
1295+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
1296+type ScreenView struct{ raw []byte }
1297+
1298+func (v ScreenView) Raw() []byte { return v.raw }
1299+
1300+// Size is the element's wire size, including trailing alignment.
1301+func (v ScreenView) Size() int { return len(v.raw) }
1302+func sizeScreen(p []byte) int {
1303+ if len(p) < 40 {
1304+ return -1
1305+ }
1306+ v := ScreenView{raw: p}
1307+ _ = v
1308+ off := 40
1309+ {
1310+ n := int(v.AllowedDepthsLen())
1311+ if off > len(v.raw) || n < 0 || n > len(v.raw) {
1312+ return -1
1313+ }
1314+ it := NewDepthIter(v.raw[off:], n)
1315+ for it.Next() {
1316+ off += it.Value().Size()
1317+ }
1318+ if it.Err() {
1319+ return -1
1320+ }
1321+ }
1322+ if off > len(v.raw) {
1323+ return -1
1324+ }
1325+ return off
1326+}
1327+func (v ScreenView) Root() Window { return Window(binary.LittleEndian.Uint32(v.raw[0:])) }
1328+func (v ScreenView) DefaultColormap() Colormap {
1329+ return Colormap(binary.LittleEndian.Uint32(v.raw[4:]))
1330+}
1331+func (v ScreenView) WhitePixel() uint32 { return uint32(binary.LittleEndian.Uint32(v.raw[8:])) }
1332+func (v ScreenView) BlackPixel() uint32 { return uint32(binary.LittleEndian.Uint32(v.raw[12:])) }
1333+func (v ScreenView) CurrentInputMasks() EventMask {
1334+ return EventMask(binary.LittleEndian.Uint32(v.raw[16:]))
1335+}
1336+func (v ScreenView) WidthInPixels() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[20:])) }
1337+func (v ScreenView) HeightInPixels() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[22:])) }
1338+func (v ScreenView) WidthInMillimeters() uint16 {
1339+ return uint16(binary.LittleEndian.Uint16(v.raw[24:]))
1340+}
1341+func (v ScreenView) HeightInMillimeters() uint16 {
1342+ return uint16(binary.LittleEndian.Uint16(v.raw[26:]))
1343+}
1344+func (v ScreenView) MinInstalledMaps() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[28:])) }
1345+func (v ScreenView) MaxInstalledMaps() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[30:])) }
1346+func (v ScreenView) RootVisual() Visualid { return Visualid(binary.LittleEndian.Uint32(v.raw[32:])) }
1347+func (v ScreenView) BackingStores() BackingStore { return BackingStore(v.raw[36:][0]) }
1348+func (v ScreenView) SaveUnders() bool { return (v.raw[37:][0] != 0) }
1349+func (v ScreenView) RootDepth() uint8 { return uint8(v.raw[38:][0]) }
1350+func (v ScreenView) AllowedDepthsLen() uint8 { return uint8(v.raw[39:][0]) }
1351+func (v ScreenView) AllowedDepths() DepthIter {
1352+ off := 40
1353+ return NewDepthIter(v.raw[off:], int(v.AllowedDepthsLen()))
1354+}
1355+
1356+// ScreenIter walks n consecutive Screen elements; Err reports a malformed length.
1357+// It shares the lifetime of the bytes it walks.
1358+type ScreenIter struct {
1359+ b []byte
1360+ n int
1361+ v ScreenView
1362+ err bool
1363+}
1364+
1365+// NewScreenIter iterates n elements encoded at the start of b.
1366+func NewScreenIter(b []byte, n int) ScreenIter { return ScreenIter{b: b, n: n} }
1367+func (it *ScreenIter) Next() bool {
1368+ if it.n <= 0 || it.err {
1369+ return false
1370+ }
1371+ s := sizeScreen(it.b)
1372+ if s < 0 {
1373+ it.err = true
1374+ it.n = 0
1375+ return false
1376+ }
1377+ it.v = ScreenView{raw: it.b[:s:s]}
1378+ it.b = it.b[s:]
1379+ it.n--
1380+ return true
1381+}
1382+func (it *ScreenIter) Value() ScreenView { return it.v }
1383+func (it *ScreenIter) Err() bool { return it.err }
1384+
1385+// SetupRequestView is a zero-copy view over one wire-encoded SetupRequest, yielded by SetupRequestIter.
1386+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
1387+type SetupRequestView struct{ raw []byte }
1388+
1389+func (v SetupRequestView) Raw() []byte { return v.raw }
1390+
1391+// Size is the element's wire size, including trailing alignment.
1392+func (v SetupRequestView) Size() int { return len(v.raw) }
1393+func sizeSetupRequest(p []byte) int {
1394+ if len(p) < 12 {
1395+ return -1
1396+ }
1397+ v := SetupRequestView{raw: p}
1398+ _ = v
1399+ off := 12
1400+ {
1401+ n := int(v.AuthorizationProtocolNameLen())
1402+ if n < 0 || n > len(v.raw) {
1403+ return -1
1404+ }
1405+ off += n * 1
1406+ }
1407+ if off > len(v.raw) {
1408+ return -1
1409+ }
1410+ off = (off + 3) &^ 3
1411+ {
1412+ n := int(v.AuthorizationProtocolDataLen())
1413+ if n < 0 || n > len(v.raw) {
1414+ return -1
1415+ }
1416+ off += n * 1
1417+ }
1418+ if off > len(v.raw) {
1419+ return -1
1420+ }
1421+ off = (off + 3) &^ 3
1422+ if off > len(v.raw) {
1423+ return -1
1424+ }
1425+ return off
1426+}
1427+func (v SetupRequestView) ByteOrder() uint8 { return uint8(v.raw[0:][0]) }
1428+func (v SetupRequestView) ProtocolMajorVersion() uint16 {
1429+ return uint16(binary.LittleEndian.Uint16(v.raw[2:]))
1430+}
1431+func (v SetupRequestView) ProtocolMinorVersion() uint16 {
1432+ return uint16(binary.LittleEndian.Uint16(v.raw[4:]))
1433+}
1434+func (v SetupRequestView) AuthorizationProtocolNameLen() uint16 {
1435+ return uint16(binary.LittleEndian.Uint16(v.raw[6:]))
1436+}
1437+func (v SetupRequestView) AuthorizationProtocolDataLen() uint16 {
1438+ return uint16(binary.LittleEndian.Uint16(v.raw[8:]))
1439+}
1440+func (v SetupRequestView) AuthorizationProtocolName() []byte {
1441+ off := 12
1442+ end := off + int(v.AuthorizationProtocolNameLen())
1443+ return v.raw[off:end:end]
1444+}
1445+func (v SetupRequestView) AuthorizationProtocolData() []byte {
1446+ off := 12
1447+ {
1448+ n := int(v.AuthorizationProtocolNameLen())
1449+ off += n * 1
1450+ }
1451+ off = (off + 3) &^ 3
1452+ end := off + int(v.AuthorizationProtocolDataLen())
1453+ return v.raw[off:end:end]
1454+}
1455+
1456+// SetupRequestIter walks n consecutive SetupRequest elements; Err reports a malformed length.
1457+// It shares the lifetime of the bytes it walks.
1458+type SetupRequestIter struct {
1459+ b []byte
1460+ n int
1461+ v SetupRequestView
1462+ err bool
1463+}
1464+
1465+// NewSetupRequestIter iterates n elements encoded at the start of b.
1466+func NewSetupRequestIter(b []byte, n int) SetupRequestIter { return SetupRequestIter{b: b, n: n} }
1467+func (it *SetupRequestIter) Next() bool {
1468+ if it.n <= 0 || it.err {
1469+ return false
1470+ }
1471+ s := sizeSetupRequest(it.b)
1472+ if s < 0 {
1473+ it.err = true
1474+ it.n = 0
1475+ return false
1476+ }
1477+ it.v = SetupRequestView{raw: it.b[:s:s]}
1478+ it.b = it.b[s:]
1479+ it.n--
1480+ return true
1481+}
1482+func (it *SetupRequestIter) Value() SetupRequestView { return it.v }
1483+func (it *SetupRequestIter) Err() bool { return it.err }
1484+
1485+// SetupFailedView is a zero-copy view over one wire-encoded SetupFailed, yielded by SetupFailedIter.
1486+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
1487+type SetupFailedView struct{ raw []byte }
1488+
1489+func (v SetupFailedView) Raw() []byte { return v.raw }
1490+
1491+// Size is the element's wire size, including trailing alignment.
1492+func (v SetupFailedView) Size() int { return len(v.raw) }
1493+func sizeSetupFailed(p []byte) int {
1494+ if len(p) < 8 {
1495+ return -1
1496+ }
1497+ v := SetupFailedView{raw: p}
1498+ _ = v
1499+ off := 8
1500+ {
1501+ n := int(v.ReasonLen())
1502+ if n < 0 || n > len(v.raw) {
1503+ return -1
1504+ }
1505+ off += n * 1
1506+ }
1507+ if off > len(v.raw) {
1508+ return -1
1509+ }
1510+ if off > len(v.raw) {
1511+ return -1
1512+ }
1513+ return off
1514+}
1515+func (v SetupFailedView) Status() uint8 { return uint8(v.raw[0:][0]) }
1516+func (v SetupFailedView) ReasonLen() uint8 { return uint8(v.raw[1:][0]) }
1517+func (v SetupFailedView) ProtocolMajorVersion() uint16 {
1518+ return uint16(binary.LittleEndian.Uint16(v.raw[2:]))
1519+}
1520+func (v SetupFailedView) ProtocolMinorVersion() uint16 {
1521+ return uint16(binary.LittleEndian.Uint16(v.raw[4:]))
1522+}
1523+func (v SetupFailedView) Length() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[6:])) }
1524+func (v SetupFailedView) Reason() []byte {
1525+ off := 8
1526+ end := off + int(v.ReasonLen())
1527+ return v.raw[off:end:end]
1528+}
1529+
1530+// SetupFailedIter walks n consecutive SetupFailed elements; Err reports a malformed length.
1531+// It shares the lifetime of the bytes it walks.
1532+type SetupFailedIter struct {
1533+ b []byte
1534+ n int
1535+ v SetupFailedView
1536+ err bool
1537+}
1538+
1539+// NewSetupFailedIter iterates n elements encoded at the start of b.
1540+func NewSetupFailedIter(b []byte, n int) SetupFailedIter { return SetupFailedIter{b: b, n: n} }
1541+func (it *SetupFailedIter) Next() bool {
1542+ if it.n <= 0 || it.err {
1543+ return false
1544+ }
1545+ s := sizeSetupFailed(it.b)
1546+ if s < 0 {
1547+ it.err = true
1548+ it.n = 0
1549+ return false
1550+ }
1551+ it.v = SetupFailedView{raw: it.b[:s:s]}
1552+ it.b = it.b[s:]
1553+ it.n--
1554+ return true
1555+}
1556+func (it *SetupFailedIter) Value() SetupFailedView { return it.v }
1557+func (it *SetupFailedIter) Err() bool { return it.err }
1558+
1559+// SetupAuthenticateView is a zero-copy view over one wire-encoded SetupAuthenticate, yielded by SetupAuthenticateIter.
1560+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
1561+type SetupAuthenticateView struct{ raw []byte }
1562+
1563+func (v SetupAuthenticateView) Raw() []byte { return v.raw }
1564+
1565+// Size is the element's wire size, including trailing alignment.
1566+func (v SetupAuthenticateView) Size() int { return len(v.raw) }
1567+func sizeSetupAuthenticate(p []byte) int {
1568+ if len(p) < 8 {
1569+ return -1
1570+ }
1571+ v := SetupAuthenticateView{raw: p}
1572+ _ = v
1573+ off := 8
1574+ {
1575+ n := (int(v.Length()) * 4)
1576+ if n < 0 || n > len(v.raw) {
1577+ return -1
1578+ }
1579+ off += n * 1
1580+ }
1581+ if off > len(v.raw) {
1582+ return -1
1583+ }
1584+ if off > len(v.raw) {
1585+ return -1
1586+ }
1587+ return off
1588+}
1589+func (v SetupAuthenticateView) Status() uint8 { return uint8(v.raw[0:][0]) }
1590+func (v SetupAuthenticateView) Length() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[6:])) }
1591+func (v SetupAuthenticateView) Reason() []byte {
1592+ off := 8
1593+ end := off + (int(v.Length()) * 4)
1594+ return v.raw[off:end:end]
1595+}
1596+
1597+// SetupAuthenticateIter walks n consecutive SetupAuthenticate elements; Err reports a malformed length.
1598+// It shares the lifetime of the bytes it walks.
1599+type SetupAuthenticateIter struct {
1600+ b []byte
1601+ n int
1602+ v SetupAuthenticateView
1603+ err bool
1604+}
1605+
1606+// NewSetupAuthenticateIter iterates n elements encoded at the start of b.
1607+func NewSetupAuthenticateIter(b []byte, n int) SetupAuthenticateIter {
1608+ return SetupAuthenticateIter{b: b, n: n}
1609+}
1610+func (it *SetupAuthenticateIter) Next() bool {
1611+ if it.n <= 0 || it.err {
1612+ return false
1613+ }
1614+ s := sizeSetupAuthenticate(it.b)
1615+ if s < 0 {
1616+ it.err = true
1617+ it.n = 0
1618+ return false
1619+ }
1620+ it.v = SetupAuthenticateView{raw: it.b[:s:s]}
1621+ it.b = it.b[s:]
1622+ it.n--
1623+ return true
1624+}
1625+func (it *SetupAuthenticateIter) Value() SetupAuthenticateView { return it.v }
1626+func (it *SetupAuthenticateIter) Err() bool { return it.err }
1627+
1628+// SetupView is a zero-copy view over one wire-encoded Setup, yielded by SetupIter.
1629+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
1630+type SetupView struct{ raw []byte }
1631+
1632+func (v SetupView) Raw() []byte { return v.raw }
1633+
1634+// Size is the element's wire size, including trailing alignment.
1635+func (v SetupView) Size() int { return len(v.raw) }
1636+func sizeSetup(p []byte) int {
1637+ if len(p) < 40 {
1638+ return -1
1639+ }
1640+ v := SetupView{raw: p}
1641+ _ = v
1642+ off := 40
1643+ {
1644+ n := int(v.VendorLen())
1645+ if n < 0 || n > len(v.raw) {
1646+ return -1
1647+ }
1648+ off += n * 1
1649+ }
1650+ if off > len(v.raw) {
1651+ return -1
1652+ }
1653+ off = (off + 3) &^ 3
1654+ {
1655+ n := int(v.PixmapFormatsLen())
1656+ if n < 0 || n > len(v.raw) {
1657+ return -1
1658+ }
1659+ off += n * 8
1660+ }
1661+ if off > len(v.raw) {
1662+ return -1
1663+ }
1664+ {
1665+ n := int(v.RootsLen())
1666+ if off > len(v.raw) || n < 0 || n > len(v.raw) {
1667+ return -1
1668+ }
1669+ it := NewScreenIter(v.raw[off:], n)
1670+ for it.Next() {
1671+ off += it.Value().Size()
1672+ }
1673+ if it.Err() {
1674+ return -1
1675+ }
1676+ }
1677+ if off > len(v.raw) {
1678+ return -1
1679+ }
1680+ return off
1681+}
1682+func (v SetupView) Status() uint8 { return uint8(v.raw[0:][0]) }
1683+func (v SetupView) ProtocolMajorVersion() uint16 {
1684+ return uint16(binary.LittleEndian.Uint16(v.raw[2:]))
1685+}
1686+func (v SetupView) ProtocolMinorVersion() uint16 {
1687+ return uint16(binary.LittleEndian.Uint16(v.raw[4:]))
1688+}
1689+func (v SetupView) Length() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[6:])) }
1690+func (v SetupView) ReleaseNumber() uint32 { return uint32(binary.LittleEndian.Uint32(v.raw[8:])) }
1691+func (v SetupView) ResourceIdBase() uint32 { return uint32(binary.LittleEndian.Uint32(v.raw[12:])) }
1692+func (v SetupView) ResourceIdMask() uint32 { return uint32(binary.LittleEndian.Uint32(v.raw[16:])) }
1693+func (v SetupView) MotionBufferSize() uint32 { return uint32(binary.LittleEndian.Uint32(v.raw[20:])) }
1694+func (v SetupView) VendorLen() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[24:])) }
1695+func (v SetupView) MaximumRequestLength() uint16 {
1696+ return uint16(binary.LittleEndian.Uint16(v.raw[26:]))
1697+}
1698+func (v SetupView) RootsLen() uint8 { return uint8(v.raw[28:][0]) }
1699+func (v SetupView) PixmapFormatsLen() uint8 { return uint8(v.raw[29:][0]) }
1700+func (v SetupView) ImageByteOrder() ImageOrder { return ImageOrder(v.raw[30:][0]) }
1701+func (v SetupView) BitmapFormatBitOrder() ImageOrder { return ImageOrder(v.raw[31:][0]) }
1702+func (v SetupView) BitmapFormatScanlineUnit() uint8 { return uint8(v.raw[32:][0]) }
1703+func (v SetupView) BitmapFormatScanlinePad() uint8 { return uint8(v.raw[33:][0]) }
1704+func (v SetupView) MinKeycode() Keycode { return Keycode(v.raw[34:][0]) }
1705+func (v SetupView) MaxKeycode() Keycode { return Keycode(v.raw[35:][0]) }
1706+func (v SetupView) Vendor() []byte {
1707+ off := 40
1708+ end := off + int(v.VendorLen())
1709+ return v.raw[off:end:end]
1710+}
1711+func (v SetupView) PixmapFormats() FormatList {
1712+ off := 40
1713+ {
1714+ n := int(v.VendorLen())
1715+ off += n * 1
1716+ }
1717+ off = (off + 3) &^ 3
1718+ end := off + (int(v.PixmapFormatsLen()))*8
1719+ return FormatList{b: v.raw[off:end:end]}
1720+}
1721+func (v SetupView) Roots() ScreenIter {
1722+ off := 40
1723+ {
1724+ n := int(v.VendorLen())
1725+ off += n * 1
1726+ }
1727+ off = (off + 3) &^ 3
1728+ {
1729+ n := int(v.PixmapFormatsLen())
1730+ off += n * 8
1731+ }
1732+ return NewScreenIter(v.raw[off:], int(v.RootsLen()))
1733+}
1734+
1735+// SetupIter walks n consecutive Setup elements; Err reports a malformed length.
1736+// It shares the lifetime of the bytes it walks.
1737+type SetupIter struct {
1738+ b []byte
1739+ n int
1740+ v SetupView
1741+ err bool
1742+}
1743+
1744+// NewSetupIter iterates n elements encoded at the start of b.
1745+func NewSetupIter(b []byte, n int) SetupIter { return SetupIter{b: b, n: n} }
1746+func (it *SetupIter) Next() bool {
1747+ if it.n <= 0 || it.err {
1748+ return false
1749+ }
1750+ s := sizeSetup(it.b)
1751+ if s < 0 {
1752+ it.err = true
1753+ it.n = 0
1754+ return false
1755+ }
1756+ it.v = SetupView{raw: it.b[:s:s]}
1757+ it.b = it.b[s:]
1758+ it.n--
1759+ return true
1760+}
1761+func (it *SetupIter) Value() SetupView { return it.v }
1762+func (it *SetupIter) Err() bool { return it.err }
1763+
1764+// StrView is a zero-copy view over one wire-encoded Str, yielded by StrIter.
1765+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
1766+type StrView struct{ raw []byte }
1767+
1768+func (v StrView) Raw() []byte { return v.raw }
1769+
1770+// Size is the element's wire size, including trailing alignment.
1771+func (v StrView) Size() int { return len(v.raw) }
1772+func sizeStr(p []byte) int {
1773+ if len(p) < 1 {
1774+ return -1
1775+ }
1776+ v := StrView{raw: p}
1777+ _ = v
1778+ off := 1
1779+ {
1780+ n := int(v.NameLen())
1781+ if n < 0 || n > len(v.raw) {
1782+ return -1
1783+ }
1784+ off += n * 1
1785+ }
1786+ if off > len(v.raw) {
1787+ return -1
1788+ }
1789+ if off > len(v.raw) {
1790+ return -1
1791+ }
1792+ return off
1793+}
1794+func (v StrView) NameLen() uint8 { return uint8(v.raw[0:][0]) }
1795+func (v StrView) Name() []byte { off := 1; end := off + int(v.NameLen()); return v.raw[off:end:end] }
1796+
1797+// StrIter walks n consecutive Str elements; Err reports a malformed length.
1798+// It shares the lifetime of the bytes it walks.
1799+type StrIter struct {
1800+ b []byte
1801+ n int
1802+ v StrView
1803+ err bool
1804+}
1805+
1806+// NewStrIter iterates n elements encoded at the start of b.
1807+func NewStrIter(b []byte, n int) StrIter { return StrIter{b: b, n: n} }
1808+func (it *StrIter) Next() bool {
1809+ if it.n <= 0 || it.err {
1810+ return false
1811+ }
1812+ s := sizeStr(it.b)
1813+ if s < 0 {
1814+ it.err = true
1815+ it.n = 0
1816+ return false
1817+ }
1818+ it.v = StrView{raw: it.b[:s:s]}
1819+ it.b = it.b[s:]
1820+ it.n--
1821+ return true
1822+}
1823+func (it *StrIter) Value() StrView { return it.v }
1824+func (it *StrIter) Err() bool { return it.err }
1825+
1826+// HostView is a zero-copy view over one wire-encoded Host, yielded by HostIter.
1827+// It shares the lifetime of the bytes it was taken from (for replies: until the Handler callback returns). Copy what you keep.
1828+type HostView struct{ raw []byte }
1829+
1830+func (v HostView) Raw() []byte { return v.raw }
1831+
1832+// Size is the element's wire size, including trailing alignment.
1833+func (v HostView) Size() int { return len(v.raw) }
1834+func sizeHost(p []byte) int {
1835+ if len(p) < 4 {
1836+ return -1
1837+ }
1838+ v := HostView{raw: p}
1839+ _ = v
1840+ off := 4
1841+ {
1842+ n := int(v.AddressLen())
1843+ if n < 0 || n > len(v.raw) {
1844+ return -1
1845+ }
1846+ off += n * 1
1847+ }
1848+ if off > len(v.raw) {
1849+ return -1
1850+ }
1851+ off = (off + 3) &^ 3
1852+ if off > len(v.raw) {
1853+ return -1
1854+ }
1855+ return off
1856+}
1857+func (v HostView) Family() Family { return Family(v.raw[0:][0]) }
1858+func (v HostView) AddressLen() uint16 { return uint16(binary.LittleEndian.Uint16(v.raw[2:])) }
1859+func (v HostView) Address() []byte {
1860+ off := 4
1861+ end := off + int(v.AddressLen())
1862+ return v.raw[off:end:end]
1863+}
1864+
1865+// HostIter walks n consecutive Host elements; Err reports a malformed length.
1866+// It shares the lifetime of the bytes it walks.
1867+type HostIter struct {
1868+ b []byte
1869+ n int
1870+ v HostView
1871+ err bool
1872+}
1873+
1874+// NewHostIter iterates n elements encoded at the start of b.
1875+func NewHostIter(b []byte, n int) HostIter { return HostIter{b: b, n: n} }
1876+func (it *HostIter) Next() bool {
1877+ if it.n <= 0 || it.err {
1878+ return false
1879+ }
1880+ s := sizeHost(it.b)
1881+ if s < 0 {
1882+ it.err = true
1883+ it.n = 0
1884+ return false
1885+ }
1886+ it.v = HostView{raw: it.b[:s:s]}
1887+ it.b = it.b[s:]
1888+ it.n--
1889+ return true
1890+}
1891+func (it *HostIter) Value() HostView { return it.v }
1892+func (it *HostIter) Err() bool { return it.err }
1893+
1894+// AtomList is a borrowed view over a wire list of Atom. It shares the lifetime of the bytes it was taken from; copy what you keep.
1895+type AtomList struct{ b []byte }
1896+
1897+func (l AtomList) Len() int { return len(l.b) / 4 }
1898+func (l AtomList) At(i int) Atom { return Atom(binary.LittleEndian.Uint32(l.b[i*4:])) }
1899+
1900+// CharinfoList is a borrowed view over a wire list of Charinfo. It shares the lifetime of the bytes it was taken from; copy what you keep.
1901+type CharinfoList struct{ b []byte }
1902+
1903+func (l CharinfoList) Len() int { return len(l.b) / 12 }
1904+func (l CharinfoList) At(i int) Charinfo { return GetCharinfo(l.b[i*12:]) }
1905+
1906+// ColormapList is a borrowed view over a wire list of Colormap. It shares the lifetime of the bytes it was taken from; copy what you keep.
1907+type ColormapList struct{ b []byte }
1908+
1909+func (l ColormapList) Len() int { return len(l.b) / 4 }
1910+func (l ColormapList) At(i int) Colormap { return Colormap(binary.LittleEndian.Uint32(l.b[i*4:])) }
1911+
1912+// FontpropList is a borrowed view over a wire list of Fontprop. It shares the lifetime of the bytes it was taken from; copy what you keep.
1913+type FontpropList struct{ b []byte }
1914+
1915+func (l FontpropList) Len() int { return len(l.b) / 8 }
1916+func (l FontpropList) At(i int) Fontprop { return GetFontprop(l.b[i*8:]) }
1917+
1918+// FormatList is a borrowed view over a wire list of Format. It shares the lifetime of the bytes it was taken from; copy what you keep.
1919+type FormatList struct{ b []byte }
1920+
1921+func (l FormatList) Len() int { return len(l.b) / 8 }
1922+func (l FormatList) At(i int) Format { return GetFormat(l.b[i*8:]) }
1923+
1924+// KeycodeList is a borrowed view over a wire list of Keycode. It shares the lifetime of the bytes it was taken from; copy what you keep.
1925+type KeycodeList struct{ b []byte }
1926+
1927+func (l KeycodeList) Len() int { return len(l.b) / 1 }
1928+func (l KeycodeList) At(i int) Keycode { return Keycode(l.b[i*1:][0]) }
1929+
1930+// KeysymList is a borrowed view over a wire list of Keysym. It shares the lifetime of the bytes it was taken from; copy what you keep.
1931+type KeysymList struct{ b []byte }
1932+
1933+func (l KeysymList) Len() int { return len(l.b) / 4 }
1934+func (l KeysymList) At(i int) Keysym { return Keysym(binary.LittleEndian.Uint32(l.b[i*4:])) }
1935+
1936+// RgbList is a borrowed view over a wire list of Rgb. It shares the lifetime of the bytes it was taken from; copy what you keep.
1937+type RgbList struct{ b []byte }
1938+
1939+func (l RgbList) Len() int { return len(l.b) / 8 }
1940+func (l RgbList) At(i int) Rgb { return GetRgb(l.b[i*8:]) }
1941+
1942+// TimecoordList is a borrowed view over a wire list of Timecoord. It shares the lifetime of the bytes it was taken from; copy what you keep.
1943+type TimecoordList struct{ b []byte }
1944+
1945+func (l TimecoordList) Len() int { return len(l.b) / 8 }
1946+func (l TimecoordList) At(i int) Timecoord { return GetTimecoord(l.b[i*8:]) }
1947+
1948+// Uint32List is a borrowed view over a wire list of uint32. It shares the lifetime of the bytes it was taken from; copy what you keep.
1949+type Uint32List struct{ b []byte }
1950+
1951+func (l Uint32List) Len() int { return len(l.b) / 4 }
1952+func (l Uint32List) At(i int) uint32 { return uint32(binary.LittleEndian.Uint32(l.b[i*4:])) }
1953+
1954+// VisualtypeList is a borrowed view over a wire list of Visualtype. It shares the lifetime of the bytes it was taken from; copy what you keep.
1955+type VisualtypeList struct{ b []byte }
1956+
1957+func (l VisualtypeList) Len() int { return len(l.b) / 24 }
1958+func (l VisualtypeList) At(i int) Visualtype { return GetVisualtype(l.b[i*24:]) }
1959+
1960+// WindowList is a borrowed view over a wire list of Window. It shares the lifetime of the bytes it was taken from; copy what you keep.
1961+type WindowList struct{ b []byte }
1962+
1963+func (l WindowList) Len() int { return len(l.b) / 4 }
1964+func (l WindowList) At(i int) Window { return Window(binary.LittleEndian.Uint32(l.b[i*4:])) }
A xproto/requests_generated.go +2780 -0
@@ -0,0 +1,2780 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xproto
3+
4+import "encoding/binary"
5+import "math/bits"
6+import "bnema.dev/xturbo"
7+
8+type CreateWindowValues struct {
9+ Mask Cw
10+ BackgroundPixmap Pixmap
11+ BackgroundPixel uint32
12+ BorderPixmap Pixmap
13+ BorderPixel uint32
14+ BitGravity Gravity
15+ WinGravity Gravity
16+ BackingStore BackingStore
17+ BackingPlanes uint32
18+ BackingPixel uint32
19+ OverrideRedirect bool
20+ SaveUnder bool
21+ EventMask EventMask
22+ DoNotPropogateMask EventMask
23+ Colormap Colormap
24+ Cursor Cursor
25+}
26+
27+func (v *CreateWindowValues) SetBackgroundPixmap(x Pixmap) *CreateWindowValues {
28+ v.Mask |= CwBackPixmap
29+ v.BackgroundPixmap = x
30+ return v
31+}
32+func (v *CreateWindowValues) SetBackgroundPixel(x uint32) *CreateWindowValues {
33+ v.Mask |= CwBackPixel
34+ v.BackgroundPixel = x
35+ return v
36+}
37+func (v *CreateWindowValues) SetBorderPixmap(x Pixmap) *CreateWindowValues {
38+ v.Mask |= CwBorderPixmap
39+ v.BorderPixmap = x
40+ return v
41+}
42+func (v *CreateWindowValues) SetBorderPixel(x uint32) *CreateWindowValues {
43+ v.Mask |= CwBorderPixel
44+ v.BorderPixel = x
45+ return v
46+}
47+func (v *CreateWindowValues) SetBitGravity(x Gravity) *CreateWindowValues {
48+ v.Mask |= CwBitGravity
49+ v.BitGravity = x
50+ return v
51+}
52+func (v *CreateWindowValues) SetWinGravity(x Gravity) *CreateWindowValues {
53+ v.Mask |= CwWinGravity
54+ v.WinGravity = x
55+ return v
56+}
57+func (v *CreateWindowValues) SetBackingStore(x BackingStore) *CreateWindowValues {
58+ v.Mask |= CwBackingStore
59+ v.BackingStore = x
60+ return v
61+}
62+func (v *CreateWindowValues) SetBackingPlanes(x uint32) *CreateWindowValues {
63+ v.Mask |= CwBackingPlanes
64+ v.BackingPlanes = x
65+ return v
66+}
67+func (v *CreateWindowValues) SetBackingPixel(x uint32) *CreateWindowValues {
68+ v.Mask |= CwBackingPixel
69+ v.BackingPixel = x
70+ return v
71+}
72+func (v *CreateWindowValues) SetOverrideRedirect(x bool) *CreateWindowValues {
73+ v.Mask |= CwOverrideRedirect
74+ v.OverrideRedirect = x
75+ return v
76+}
77+func (v *CreateWindowValues) SetSaveUnder(x bool) *CreateWindowValues {
78+ v.Mask |= CwSaveUnder
79+ v.SaveUnder = x
80+ return v
81+}
82+func (v *CreateWindowValues) SetEventMask(x EventMask) *CreateWindowValues {
83+ v.Mask |= CwEventMask
84+ v.EventMask = x
85+ return v
86+}
87+func (v *CreateWindowValues) SetDoNotPropogateMask(x EventMask) *CreateWindowValues {
88+ v.Mask |= CwDontPropagate
89+ v.DoNotPropogateMask = x
90+ return v
91+}
92+func (v *CreateWindowValues) SetColormap(x Colormap) *CreateWindowValues {
93+ v.Mask |= CwColormap
94+ v.Colormap = x
95+ return v
96+}
97+func (v *CreateWindowValues) SetCursor(x Cursor) *CreateWindowValues {
98+ v.Mask |= CwCursor
99+ v.Cursor = x
100+ return v
101+}
102+func CreateWindow(b *xturbo.Buf, depth uint8, wid Window, parent Window, x int16, y int16, width uint16, height uint16, borderWidth uint16, class WindowClass, visual Visualid, v *CreateWindowValues) xturbo.Seq {
103+ p, seq := b.Request(1, uint8(int(depth)), 28+4*bits.OnesCount32(uint32(v.Mask)))
104+ if p == nil {
105+ return 0
106+ }
107+ binary.LittleEndian.PutUint32(p[0:], uint32(wid))
108+ binary.LittleEndian.PutUint32(p[4:], uint32(parent))
109+ binary.LittleEndian.PutUint16(p[8:], uint16(x))
110+ binary.LittleEndian.PutUint16(p[10:], uint16(y))
111+ binary.LittleEndian.PutUint16(p[12:], uint16(width))
112+ binary.LittleEndian.PutUint16(p[14:], uint16(height))
113+ binary.LittleEndian.PutUint16(p[16:], uint16(borderWidth))
114+ binary.LittleEndian.PutUint16(p[18:], uint16(class))
115+ binary.LittleEndian.PutUint32(p[20:], uint32(visual))
116+ binary.LittleEndian.PutUint32(p[24:], uint32(v.Mask))
117+ off := 28
118+ if v.Mask&CwBackPixmap != 0 {
119+ binary.LittleEndian.PutUint32(p[off:], uint32(v.BackgroundPixmap))
120+ off += 4
121+ }
122+ if v.Mask&CwBackPixel != 0 {
123+ binary.LittleEndian.PutUint32(p[off:], uint32(v.BackgroundPixel))
124+ off += 4
125+ }
126+ if v.Mask&CwBorderPixmap != 0 {
127+ binary.LittleEndian.PutUint32(p[off:], uint32(v.BorderPixmap))
128+ off += 4
129+ }
130+ if v.Mask&CwBorderPixel != 0 {
131+ binary.LittleEndian.PutUint32(p[off:], uint32(v.BorderPixel))
132+ off += 4
133+ }
134+ if v.Mask&CwBitGravity != 0 {
135+ binary.LittleEndian.PutUint32(p[off:], uint32(v.BitGravity))
136+ off += 4
137+ }
138+ if v.Mask&CwWinGravity != 0 {
139+ binary.LittleEndian.PutUint32(p[off:], uint32(v.WinGravity))
140+ off += 4
141+ }
142+ if v.Mask&CwBackingStore != 0 {
143+ binary.LittleEndian.PutUint32(p[off:], uint32(v.BackingStore))
144+ off += 4
145+ }
146+ if v.Mask&CwBackingPlanes != 0 {
147+ binary.LittleEndian.PutUint32(p[off:], uint32(v.BackingPlanes))
148+ off += 4
149+ }
150+ if v.Mask&CwBackingPixel != 0 {
151+ binary.LittleEndian.PutUint32(p[off:], uint32(v.BackingPixel))
152+ off += 4
153+ }
154+ if v.Mask&CwOverrideRedirect != 0 {
155+ if v.OverrideRedirect {
156+ binary.LittleEndian.PutUint32(p[off:], 1)
157+ } else {
158+ binary.LittleEndian.PutUint32(p[off:], 0)
159+ }
160+ off += 4
161+ }
162+ if v.Mask&CwSaveUnder != 0 {
163+ if v.SaveUnder {
164+ binary.LittleEndian.PutUint32(p[off:], 1)
165+ } else {
166+ binary.LittleEndian.PutUint32(p[off:], 0)
167+ }
168+ off += 4
169+ }
170+ if v.Mask&CwEventMask != 0 {
171+ binary.LittleEndian.PutUint32(p[off:], uint32(v.EventMask))
172+ off += 4
173+ }
174+ if v.Mask&CwDontPropagate != 0 {
175+ binary.LittleEndian.PutUint32(p[off:], uint32(v.DoNotPropogateMask))
176+ off += 4
177+ }
178+ if v.Mask&CwColormap != 0 {
179+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Colormap))
180+ off += 4
181+ }
182+ if v.Mask&CwCursor != 0 {
183+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Cursor))
184+ off += 4
185+ }
186+ _ = off
187+ return seq
188+}
189+
190+type ChangeWindowAttributesValues struct {
191+ Mask Cw
192+ BackgroundPixmap Pixmap
193+ BackgroundPixel uint32
194+ BorderPixmap Pixmap
195+ BorderPixel uint32
196+ BitGravity Gravity
197+ WinGravity Gravity
198+ BackingStore BackingStore
199+ BackingPlanes uint32
200+ BackingPixel uint32
201+ OverrideRedirect bool
202+ SaveUnder bool
203+ EventMask EventMask
204+ DoNotPropogateMask EventMask
205+ Colormap Colormap
206+ Cursor Cursor
207+}
208+
209+func (v *ChangeWindowAttributesValues) SetBackgroundPixmap(x Pixmap) *ChangeWindowAttributesValues {
210+ v.Mask |= CwBackPixmap
211+ v.BackgroundPixmap = x
212+ return v
213+}
214+func (v *ChangeWindowAttributesValues) SetBackgroundPixel(x uint32) *ChangeWindowAttributesValues {
215+ v.Mask |= CwBackPixel
216+ v.BackgroundPixel = x
217+ return v
218+}
219+func (v *ChangeWindowAttributesValues) SetBorderPixmap(x Pixmap) *ChangeWindowAttributesValues {
220+ v.Mask |= CwBorderPixmap
221+ v.BorderPixmap = x
222+ return v
223+}
224+func (v *ChangeWindowAttributesValues) SetBorderPixel(x uint32) *ChangeWindowAttributesValues {
225+ v.Mask |= CwBorderPixel
226+ v.BorderPixel = x
227+ return v
228+}
229+func (v *ChangeWindowAttributesValues) SetBitGravity(x Gravity) *ChangeWindowAttributesValues {
230+ v.Mask |= CwBitGravity
231+ v.BitGravity = x
232+ return v
233+}
234+func (v *ChangeWindowAttributesValues) SetWinGravity(x Gravity) *ChangeWindowAttributesValues {
235+ v.Mask |= CwWinGravity
236+ v.WinGravity = x
237+ return v
238+}
239+func (v *ChangeWindowAttributesValues) SetBackingStore(x BackingStore) *ChangeWindowAttributesValues {
240+ v.Mask |= CwBackingStore
241+ v.BackingStore = x
242+ return v
243+}
244+func (v *ChangeWindowAttributesValues) SetBackingPlanes(x uint32) *ChangeWindowAttributesValues {
245+ v.Mask |= CwBackingPlanes
246+ v.BackingPlanes = x
247+ return v
248+}
249+func (v *ChangeWindowAttributesValues) SetBackingPixel(x uint32) *ChangeWindowAttributesValues {
250+ v.Mask |= CwBackingPixel
251+ v.BackingPixel = x
252+ return v
253+}
254+func (v *ChangeWindowAttributesValues) SetOverrideRedirect(x bool) *ChangeWindowAttributesValues {
255+ v.Mask |= CwOverrideRedirect
256+ v.OverrideRedirect = x
257+ return v
258+}
259+func (v *ChangeWindowAttributesValues) SetSaveUnder(x bool) *ChangeWindowAttributesValues {
260+ v.Mask |= CwSaveUnder
261+ v.SaveUnder = x
262+ return v
263+}
264+func (v *ChangeWindowAttributesValues) SetEventMask(x EventMask) *ChangeWindowAttributesValues {
265+ v.Mask |= CwEventMask
266+ v.EventMask = x
267+ return v
268+}
269+func (v *ChangeWindowAttributesValues) SetDoNotPropogateMask(x EventMask) *ChangeWindowAttributesValues {
270+ v.Mask |= CwDontPropagate
271+ v.DoNotPropogateMask = x
272+ return v
273+}
274+func (v *ChangeWindowAttributesValues) SetColormap(x Colormap) *ChangeWindowAttributesValues {
275+ v.Mask |= CwColormap
276+ v.Colormap = x
277+ return v
278+}
279+func (v *ChangeWindowAttributesValues) SetCursor(x Cursor) *ChangeWindowAttributesValues {
280+ v.Mask |= CwCursor
281+ v.Cursor = x
282+ return v
283+}
284+func ChangeWindowAttributes(b *xturbo.Buf, window Window, v *ChangeWindowAttributesValues) xturbo.Seq {
285+ p, seq := b.Request(2, 0, 8+4*bits.OnesCount32(uint32(v.Mask)))
286+ if p == nil {
287+ return 0
288+ }
289+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
290+ binary.LittleEndian.PutUint32(p[4:], uint32(v.Mask))
291+ off := 8
292+ if v.Mask&CwBackPixmap != 0 {
293+ binary.LittleEndian.PutUint32(p[off:], uint32(v.BackgroundPixmap))
294+ off += 4
295+ }
296+ if v.Mask&CwBackPixel != 0 {
297+ binary.LittleEndian.PutUint32(p[off:], uint32(v.BackgroundPixel))
298+ off += 4
299+ }
300+ if v.Mask&CwBorderPixmap != 0 {
301+ binary.LittleEndian.PutUint32(p[off:], uint32(v.BorderPixmap))
302+ off += 4
303+ }
304+ if v.Mask&CwBorderPixel != 0 {
305+ binary.LittleEndian.PutUint32(p[off:], uint32(v.BorderPixel))
306+ off += 4
307+ }
308+ if v.Mask&CwBitGravity != 0 {
309+ binary.LittleEndian.PutUint32(p[off:], uint32(v.BitGravity))
310+ off += 4
311+ }
312+ if v.Mask&CwWinGravity != 0 {
313+ binary.LittleEndian.PutUint32(p[off:], uint32(v.WinGravity))
314+ off += 4
315+ }
316+ if v.Mask&CwBackingStore != 0 {
317+ binary.LittleEndian.PutUint32(p[off:], uint32(v.BackingStore))
318+ off += 4
319+ }
320+ if v.Mask&CwBackingPlanes != 0 {
321+ binary.LittleEndian.PutUint32(p[off:], uint32(v.BackingPlanes))
322+ off += 4
323+ }
324+ if v.Mask&CwBackingPixel != 0 {
325+ binary.LittleEndian.PutUint32(p[off:], uint32(v.BackingPixel))
326+ off += 4
327+ }
328+ if v.Mask&CwOverrideRedirect != 0 {
329+ if v.OverrideRedirect {
330+ binary.LittleEndian.PutUint32(p[off:], 1)
331+ } else {
332+ binary.LittleEndian.PutUint32(p[off:], 0)
333+ }
334+ off += 4
335+ }
336+ if v.Mask&CwSaveUnder != 0 {
337+ if v.SaveUnder {
338+ binary.LittleEndian.PutUint32(p[off:], 1)
339+ } else {
340+ binary.LittleEndian.PutUint32(p[off:], 0)
341+ }
342+ off += 4
343+ }
344+ if v.Mask&CwEventMask != 0 {
345+ binary.LittleEndian.PutUint32(p[off:], uint32(v.EventMask))
346+ off += 4
347+ }
348+ if v.Mask&CwDontPropagate != 0 {
349+ binary.LittleEndian.PutUint32(p[off:], uint32(v.DoNotPropogateMask))
350+ off += 4
351+ }
352+ if v.Mask&CwColormap != 0 {
353+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Colormap))
354+ off += 4
355+ }
356+ if v.Mask&CwCursor != 0 {
357+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Cursor))
358+ off += 4
359+ }
360+ _ = off
361+ return seq
362+}
363+
364+func GetWindowAttributes(b *xturbo.Buf, window Window) xturbo.Seq {
365+ p, seq := b.Request(3, 0, 4)
366+ if p == nil {
367+ return 0
368+ }
369+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
370+ return seq
371+}
372+
373+func DestroyWindow(b *xturbo.Buf, window Window) xturbo.Seq {
374+ p, seq := b.Request(4, 0, 4)
375+ if p == nil {
376+ return 0
377+ }
378+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
379+ return seq
380+}
381+
382+func DestroySubwindows(b *xturbo.Buf, window Window) xturbo.Seq {
383+ p, seq := b.Request(5, 0, 4)
384+ if p == nil {
385+ return 0
386+ }
387+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
388+ return seq
389+}
390+
391+func ChangeSaveSet(b *xturbo.Buf, mode SetMode, window Window) xturbo.Seq {
392+ p, seq := b.Request(6, uint8(int(mode)), 4)
393+ if p == nil {
394+ return 0
395+ }
396+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
397+ return seq
398+}
399+
400+func ReparentWindow(b *xturbo.Buf, window Window, parent Window, x int16, y int16) xturbo.Seq {
401+ p, seq := b.Request(7, 0, 12)
402+ if p == nil {
403+ return 0
404+ }
405+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
406+ binary.LittleEndian.PutUint32(p[4:], uint32(parent))
407+ binary.LittleEndian.PutUint16(p[8:], uint16(x))
408+ binary.LittleEndian.PutUint16(p[10:], uint16(y))
409+ return seq
410+}
411+
412+func MapWindow(b *xturbo.Buf, window Window) xturbo.Seq {
413+ p, seq := b.Request(8, 0, 4)
414+ if p == nil {
415+ return 0
416+ }
417+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
418+ return seq
419+}
420+
421+func MapSubwindows(b *xturbo.Buf, window Window) xturbo.Seq {
422+ p, seq := b.Request(9, 0, 4)
423+ if p == nil {
424+ return 0
425+ }
426+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
427+ return seq
428+}
429+
430+func UnmapWindow(b *xturbo.Buf, window Window) xturbo.Seq {
431+ p, seq := b.Request(10, 0, 4)
432+ if p == nil {
433+ return 0
434+ }
435+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
436+ return seq
437+}
438+
439+func UnmapSubwindows(b *xturbo.Buf, window Window) xturbo.Seq {
440+ p, seq := b.Request(11, 0, 4)
441+ if p == nil {
442+ return 0
443+ }
444+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
445+ return seq
446+}
447+
448+type ConfigureWindowValues struct {
449+ Mask ConfigWindow
450+ X int32
451+ Y int32
452+ Width uint32
453+ Height uint32
454+ BorderWidth uint32
455+ Sibling Window
456+ StackMode StackMode
457+}
458+
459+func (v *ConfigureWindowValues) SetX(x int32) *ConfigureWindowValues {
460+ v.Mask |= ConfigWindowX
461+ v.X = x
462+ return v
463+}
464+func (v *ConfigureWindowValues) SetY(x int32) *ConfigureWindowValues {
465+ v.Mask |= ConfigWindowY
466+ v.Y = x
467+ return v
468+}
469+func (v *ConfigureWindowValues) SetWidth(x uint32) *ConfigureWindowValues {
470+ v.Mask |= ConfigWindowWidth
471+ v.Width = x
472+ return v
473+}
474+func (v *ConfigureWindowValues) SetHeight(x uint32) *ConfigureWindowValues {
475+ v.Mask |= ConfigWindowHeight
476+ v.Height = x
477+ return v
478+}
479+func (v *ConfigureWindowValues) SetBorderWidth(x uint32) *ConfigureWindowValues {
480+ v.Mask |= ConfigWindowBorderWidth
481+ v.BorderWidth = x
482+ return v
483+}
484+func (v *ConfigureWindowValues) SetSibling(x Window) *ConfigureWindowValues {
485+ v.Mask |= ConfigWindowSibling
486+ v.Sibling = x
487+ return v
488+}
489+func (v *ConfigureWindowValues) SetStackMode(x StackMode) *ConfigureWindowValues {
490+ v.Mask |= ConfigWindowStackMode
491+ v.StackMode = x
492+ return v
493+}
494+func ConfigureWindow(b *xturbo.Buf, window Window, v *ConfigureWindowValues) xturbo.Seq {
495+ p, seq := b.Request(12, 0, 8+4*bits.OnesCount32(uint32(v.Mask)))
496+ if p == nil {
497+ return 0
498+ }
499+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
500+ binary.LittleEndian.PutUint16(p[4:], uint16(v.Mask))
501+ off := 8
502+ if v.Mask&ConfigWindowX != 0 {
503+ binary.LittleEndian.PutUint32(p[off:], uint32(v.X))
504+ off += 4
505+ }
506+ if v.Mask&ConfigWindowY != 0 {
507+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Y))
508+ off += 4
509+ }
510+ if v.Mask&ConfigWindowWidth != 0 {
511+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Width))
512+ off += 4
513+ }
514+ if v.Mask&ConfigWindowHeight != 0 {
515+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Height))
516+ off += 4
517+ }
518+ if v.Mask&ConfigWindowBorderWidth != 0 {
519+ binary.LittleEndian.PutUint32(p[off:], uint32(v.BorderWidth))
520+ off += 4
521+ }
522+ if v.Mask&ConfigWindowSibling != 0 {
523+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Sibling))
524+ off += 4
525+ }
526+ if v.Mask&ConfigWindowStackMode != 0 {
527+ binary.LittleEndian.PutUint32(p[off:], uint32(v.StackMode))
528+ off += 4
529+ }
530+ _ = off
531+ return seq
532+}
533+
534+func CirculateWindow(b *xturbo.Buf, direction Circulate, window Window) xturbo.Seq {
535+ p, seq := b.Request(13, uint8(int(direction)), 4)
536+ if p == nil {
537+ return 0
538+ }
539+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
540+ return seq
541+}
542+
543+func GetGeometry(b *xturbo.Buf, drawable Drawable) xturbo.Seq {
544+ p, seq := b.Request(14, 0, 4)
545+ if p == nil {
546+ return 0
547+ }
548+ binary.LittleEndian.PutUint32(p[0:], uint32(drawable))
549+ return seq
550+}
551+
552+func QueryTree(b *xturbo.Buf, window Window) xturbo.Seq {
553+ p, seq := b.Request(15, 0, 4)
554+ if p == nil {
555+ return 0
556+ }
557+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
558+ return seq
559+}
560+
561+func InternAtom(b *xturbo.Buf, onlyIfExists bool, name string) xturbo.Seq {
562+ if uint64(len(name)) > 65535 {
563+ b.Fail(xturbo.ErrBadLength)
564+ return 0
565+ }
566+ size := 0
567+ size += 2
568+ size += 2
569+ size += len(name) * 1
570+ size = (size + 3) &^ 3
571+ var data uint8
572+ if onlyIfExists {
573+ data = 1
574+ }
575+ p, seq := b.Request(16, data, size)
576+ if p == nil {
577+ return 0
578+ }
579+ off := 0
580+ binary.LittleEndian.PutUint16(p[off:], uint16(len(name)))
581+ off += 2
582+ off += 2
583+ copy(p[off:], name)
584+ off += len(name)
585+ return seq
586+}
587+
588+func GetAtomName(b *xturbo.Buf, atom Atom) xturbo.Seq {
589+ p, seq := b.Request(17, 0, 4)
590+ if p == nil {
591+ return 0
592+ }
593+ binary.LittleEndian.PutUint32(p[0:], uint32(atom))
594+ return seq
595+}
596+
597+func ChangeProperty(b *xturbo.Buf, mode PropMode, window Window, property Atom, type_ Atom, format uint8, dataLen uint32, data []byte) xturbo.Seq {
598+ if len(data) != ((int(dataLen) * int(format)) / 8) {
599+ b.Fail(xturbo.ErrBadLength)
600+ return 0
601+ }
602+ size := 0
603+ size += 4
604+ size += 4
605+ size += 4
606+ size += 1
607+ size += 3
608+ size += 4
609+ size += len(data) * 1
610+ size = (size + 3) &^ 3
611+ p, seq := b.Request(18, uint8(int(mode)), size)
612+ if p == nil {
613+ return 0
614+ }
615+ off := 0
616+ binary.LittleEndian.PutUint32(p[off:], uint32(window))
617+ off += 4
618+ binary.LittleEndian.PutUint32(p[off:], uint32(property))
619+ off += 4
620+ binary.LittleEndian.PutUint32(p[off:], uint32(type_))
621+ off += 4
622+ p[off:][0] = byte(format)
623+ off += 1
624+ off += 3
625+ binary.LittleEndian.PutUint32(p[off:], uint32(dataLen))
626+ off += 4
627+ copy(p[off:], data)
628+ off += len(data)
629+ return seq
630+}
631+
632+func DeleteProperty(b *xturbo.Buf, window Window, property Atom) xturbo.Seq {
633+ p, seq := b.Request(19, 0, 8)
634+ if p == nil {
635+ return 0
636+ }
637+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
638+ binary.LittleEndian.PutUint32(p[4:], uint32(property))
639+ return seq
640+}
641+
642+func GetProperty(b *xturbo.Buf, delete bool, window Window, property Atom, type_ Atom, longOffset uint32, longLength uint32) xturbo.Seq {
643+ var data uint8
644+ if delete {
645+ data = 1
646+ }
647+ p, seq := b.Request(20, data, 20)
648+ if p == nil {
649+ return 0
650+ }
651+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
652+ binary.LittleEndian.PutUint32(p[4:], uint32(property))
653+ binary.LittleEndian.PutUint32(p[8:], uint32(type_))
654+ binary.LittleEndian.PutUint32(p[12:], uint32(longOffset))
655+ binary.LittleEndian.PutUint32(p[16:], uint32(longLength))
656+ return seq
657+}
658+
659+func ListProperties(b *xturbo.Buf, window Window) xturbo.Seq {
660+ p, seq := b.Request(21, 0, 4)
661+ if p == nil {
662+ return 0
663+ }
664+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
665+ return seq
666+}
667+
668+func SetSelectionOwner(b *xturbo.Buf, owner Window, selection Atom, time Timestamp) xturbo.Seq {
669+ p, seq := b.Request(22, 0, 12)
670+ if p == nil {
671+ return 0
672+ }
673+ binary.LittleEndian.PutUint32(p[0:], uint32(owner))
674+ binary.LittleEndian.PutUint32(p[4:], uint32(selection))
675+ binary.LittleEndian.PutUint32(p[8:], uint32(time))
676+ return seq
677+}
678+
679+func GetSelectionOwner(b *xturbo.Buf, selection Atom) xturbo.Seq {
680+ p, seq := b.Request(23, 0, 4)
681+ if p == nil {
682+ return 0
683+ }
684+ binary.LittleEndian.PutUint32(p[0:], uint32(selection))
685+ return seq
686+}
687+
688+func ConvertSelection(b *xturbo.Buf, requestor Window, selection Atom, target Atom, property Atom, time Timestamp) xturbo.Seq {
689+ p, seq := b.Request(24, 0, 20)
690+ if p == nil {
691+ return 0
692+ }
693+ binary.LittleEndian.PutUint32(p[0:], uint32(requestor))
694+ binary.LittleEndian.PutUint32(p[4:], uint32(selection))
695+ binary.LittleEndian.PutUint32(p[8:], uint32(target))
696+ binary.LittleEndian.PutUint32(p[12:], uint32(property))
697+ binary.LittleEndian.PutUint32(p[16:], uint32(time))
698+ return seq
699+}
700+
701+func SendEvent(b *xturbo.Buf, propagate bool, destination Window, eventMask EventMask, event *[32]byte) xturbo.Seq {
702+ if len(event) != 32 {
703+ b.Fail(xturbo.ErrBadLength)
704+ return 0
705+ }
706+ size := 0
707+ size += 4
708+ size += 4
709+ size += len(event) * 1
710+ size = (size + 3) &^ 3
711+ var data uint8
712+ if propagate {
713+ data = 1
714+ }
715+ p, seq := b.Request(25, data, size)
716+ if p == nil {
717+ return 0
718+ }
719+ off := 0
720+ binary.LittleEndian.PutUint32(p[off:], uint32(destination))
721+ off += 4
722+ binary.LittleEndian.PutUint32(p[off:], uint32(eventMask))
723+ off += 4
724+ copy(p[off:], event[:])
725+ return seq
726+}
727+
728+func GrabPointer(b *xturbo.Buf, ownerEvents bool, grabWindow Window, eventMask EventMask, pointerMode GrabMode, keyboardMode GrabMode, confineTo Window, cursor Cursor, time Timestamp) xturbo.Seq {
729+ var data uint8
730+ if ownerEvents {
731+ data = 1
732+ }
733+ p, seq := b.Request(26, data, 20)
734+ if p == nil {
735+ return 0
736+ }
737+ binary.LittleEndian.PutUint32(p[0:], uint32(grabWindow))
738+ binary.LittleEndian.PutUint16(p[4:], uint16(eventMask))
739+ p[6:][0] = byte(pointerMode)
740+ p[7:][0] = byte(keyboardMode)
741+ binary.LittleEndian.PutUint32(p[8:], uint32(confineTo))
742+ binary.LittleEndian.PutUint32(p[12:], uint32(cursor))
743+ binary.LittleEndian.PutUint32(p[16:], uint32(time))
744+ return seq
745+}
746+
747+func UngrabPointer(b *xturbo.Buf, time Timestamp) xturbo.Seq {
748+ p, seq := b.Request(27, 0, 4)
749+ if p == nil {
750+ return 0
751+ }
752+ binary.LittleEndian.PutUint32(p[0:], uint32(time))
753+ return seq
754+}
755+
756+func GrabButton(b *xturbo.Buf, ownerEvents bool, grabWindow Window, eventMask EventMask, pointerMode GrabMode, keyboardMode GrabMode, confineTo Window, cursor Cursor, button ButtonIndex, modifiers ModMask) xturbo.Seq {
757+ var data uint8
758+ if ownerEvents {
759+ data = 1
760+ }
761+ p, seq := b.Request(28, data, 20)
762+ if p == nil {
763+ return 0
764+ }
765+ binary.LittleEndian.PutUint32(p[0:], uint32(grabWindow))
766+ binary.LittleEndian.PutUint16(p[4:], uint16(eventMask))
767+ p[6:][0] = byte(pointerMode)
768+ p[7:][0] = byte(keyboardMode)
769+ binary.LittleEndian.PutUint32(p[8:], uint32(confineTo))
770+ binary.LittleEndian.PutUint32(p[12:], uint32(cursor))
771+ p[16:][0] = byte(button)
772+ binary.LittleEndian.PutUint16(p[18:], uint16(modifiers))
773+ return seq
774+}
775+
776+func UngrabButton(b *xturbo.Buf, button ButtonIndex, grabWindow Window, modifiers ModMask) xturbo.Seq {
777+ p, seq := b.Request(29, uint8(int(button)), 8)
778+ if p == nil {
779+ return 0
780+ }
781+ binary.LittleEndian.PutUint32(p[0:], uint32(grabWindow))
782+ binary.LittleEndian.PutUint16(p[4:], uint16(modifiers))
783+ return seq
784+}
785+
786+func ChangeActivePointerGrab(b *xturbo.Buf, cursor Cursor, time Timestamp, eventMask EventMask) xturbo.Seq {
787+ p, seq := b.Request(30, 0, 12)
788+ if p == nil {
789+ return 0
790+ }
791+ binary.LittleEndian.PutUint32(p[0:], uint32(cursor))
792+ binary.LittleEndian.PutUint32(p[4:], uint32(time))
793+ binary.LittleEndian.PutUint16(p[8:], uint16(eventMask))
794+ return seq
795+}
796+
797+func GrabKeyboard(b *xturbo.Buf, ownerEvents bool, grabWindow Window, time Timestamp, pointerMode GrabMode, keyboardMode GrabMode) xturbo.Seq {
798+ var data uint8
799+ if ownerEvents {
800+ data = 1
801+ }
802+ p, seq := b.Request(31, data, 12)
803+ if p == nil {
804+ return 0
805+ }
806+ binary.LittleEndian.PutUint32(p[0:], uint32(grabWindow))
807+ binary.LittleEndian.PutUint32(p[4:], uint32(time))
808+ p[8:][0] = byte(pointerMode)
809+ p[9:][0] = byte(keyboardMode)
810+ return seq
811+}
812+
813+func UngrabKeyboard(b *xturbo.Buf, time Timestamp) xturbo.Seq {
814+ p, seq := b.Request(32, 0, 4)
815+ if p == nil {
816+ return 0
817+ }
818+ binary.LittleEndian.PutUint32(p[0:], uint32(time))
819+ return seq
820+}
821+
822+func GrabKey(b *xturbo.Buf, ownerEvents bool, grabWindow Window, modifiers ModMask, key Keycode, pointerMode GrabMode, keyboardMode GrabMode) xturbo.Seq {
823+ var data uint8
824+ if ownerEvents {
825+ data = 1
826+ }
827+ p, seq := b.Request(33, data, 12)
828+ if p == nil {
829+ return 0
830+ }
831+ binary.LittleEndian.PutUint32(p[0:], uint32(grabWindow))
832+ binary.LittleEndian.PutUint16(p[4:], uint16(modifiers))
833+ p[6:][0] = byte(key)
834+ p[7:][0] = byte(pointerMode)
835+ p[8:][0] = byte(keyboardMode)
836+ return seq
837+}
838+
839+func UngrabKey(b *xturbo.Buf, key Keycode, grabWindow Window, modifiers ModMask) xturbo.Seq {
840+ p, seq := b.Request(34, uint8(int(key)), 8)
841+ if p == nil {
842+ return 0
843+ }
844+ binary.LittleEndian.PutUint32(p[0:], uint32(grabWindow))
845+ binary.LittleEndian.PutUint16(p[4:], uint16(modifiers))
846+ return seq
847+}
848+
849+func AllowEvents(b *xturbo.Buf, mode Allow, time Timestamp) xturbo.Seq {
850+ p, seq := b.Request(35, uint8(int(mode)), 4)
851+ if p == nil {
852+ return 0
853+ }
854+ binary.LittleEndian.PutUint32(p[0:], uint32(time))
855+ return seq
856+}
857+
858+func GrabServer(b *xturbo.Buf) xturbo.Seq {
859+ p, seq := b.Request(36, 0, 0)
860+ if p == nil {
861+ return 0
862+ }
863+ return seq
864+}
865+
866+func UngrabServer(b *xturbo.Buf) xturbo.Seq {
867+ p, seq := b.Request(37, 0, 0)
868+ if p == nil {
869+ return 0
870+ }
871+ return seq
872+}
873+
874+func QueryPointer(b *xturbo.Buf, window Window) xturbo.Seq {
875+ p, seq := b.Request(38, 0, 4)
876+ if p == nil {
877+ return 0
878+ }
879+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
880+ return seq
881+}
882+
883+func GetMotionEvents(b *xturbo.Buf, window Window, start Timestamp, stop Timestamp) xturbo.Seq {
884+ p, seq := b.Request(39, 0, 12)
885+ if p == nil {
886+ return 0
887+ }
888+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
889+ binary.LittleEndian.PutUint32(p[4:], uint32(start))
890+ binary.LittleEndian.PutUint32(p[8:], uint32(stop))
891+ return seq
892+}
893+
894+func TranslateCoordinates(b *xturbo.Buf, srcWindow Window, dstWindow Window, srcX int16, srcY int16) xturbo.Seq {
895+ p, seq := b.Request(40, 0, 12)
896+ if p == nil {
897+ return 0
898+ }
899+ binary.LittleEndian.PutUint32(p[0:], uint32(srcWindow))
900+ binary.LittleEndian.PutUint32(p[4:], uint32(dstWindow))
901+ binary.LittleEndian.PutUint16(p[8:], uint16(srcX))
902+ binary.LittleEndian.PutUint16(p[10:], uint16(srcY))
903+ return seq
904+}
905+
906+func WarpPointer(b *xturbo.Buf, srcWindow Window, dstWindow Window, srcX int16, srcY int16, srcWidth uint16, srcHeight uint16, dstX int16, dstY int16) xturbo.Seq {
907+ p, seq := b.Request(41, 0, 20)
908+ if p == nil {
909+ return 0
910+ }
911+ binary.LittleEndian.PutUint32(p[0:], uint32(srcWindow))
912+ binary.LittleEndian.PutUint32(p[4:], uint32(dstWindow))
913+ binary.LittleEndian.PutUint16(p[8:], uint16(srcX))
914+ binary.LittleEndian.PutUint16(p[10:], uint16(srcY))
915+ binary.LittleEndian.PutUint16(p[12:], uint16(srcWidth))
916+ binary.LittleEndian.PutUint16(p[14:], uint16(srcHeight))
917+ binary.LittleEndian.PutUint16(p[16:], uint16(dstX))
918+ binary.LittleEndian.PutUint16(p[18:], uint16(dstY))
919+ return seq
920+}
921+
922+func SetInputFocus(b *xturbo.Buf, revertTo InputFocus, focus Window, time Timestamp) xturbo.Seq {
923+ p, seq := b.Request(42, uint8(int(revertTo)), 8)
924+ if p == nil {
925+ return 0
926+ }
927+ binary.LittleEndian.PutUint32(p[0:], uint32(focus))
928+ binary.LittleEndian.PutUint32(p[4:], uint32(time))
929+ return seq
930+}
931+
932+func GetInputFocus(b *xturbo.Buf) xturbo.Seq {
933+ p, seq := b.Request(43, 0, 0)
934+ if p == nil {
935+ return 0
936+ }
937+ return seq
938+}
939+
940+func QueryKeymap(b *xturbo.Buf) xturbo.Seq {
941+ p, seq := b.Request(44, 0, 0)
942+ if p == nil {
943+ return 0
944+ }
945+ return seq
946+}
947+
948+func OpenFont(b *xturbo.Buf, fid Font, name string) xturbo.Seq {
949+ if uint64(len(name)) > 65535 {
950+ b.Fail(xturbo.ErrBadLength)
951+ return 0
952+ }
953+ size := 0
954+ size += 4
955+ size += 2
956+ size += 2
957+ size += len(name) * 1
958+ size = (size + 3) &^ 3
959+ p, seq := b.Request(45, 0, size)
960+ if p == nil {
961+ return 0
962+ }
963+ off := 0
964+ binary.LittleEndian.PutUint32(p[off:], uint32(fid))
965+ off += 4
966+ binary.LittleEndian.PutUint16(p[off:], uint16(len(name)))
967+ off += 2
968+ off += 2
969+ copy(p[off:], name)
970+ off += len(name)
971+ return seq
972+}
973+
974+func CloseFont(b *xturbo.Buf, font Font) xturbo.Seq {
975+ p, seq := b.Request(46, 0, 4)
976+ if p == nil {
977+ return 0
978+ }
979+ binary.LittleEndian.PutUint32(p[0:], uint32(font))
980+ return seq
981+}
982+
983+func QueryFont(b *xturbo.Buf, font Fontable) xturbo.Seq {
984+ p, seq := b.Request(47, 0, 4)
985+ if p == nil {
986+ return 0
987+ }
988+ binary.LittleEndian.PutUint32(p[0:], uint32(font))
989+ return seq
990+}
991+
992+func QueryTextExtents(b *xturbo.Buf, font Fontable, string []Char2b) xturbo.Seq {
993+ size := 0
994+ size += 4
995+ size += len(string) * 2
996+ size = (size + 3) &^ 3
997+ var data uint8
998+ if (len(string) & 1) != 0 {
999+ data = 1
1000+ }
1001+ p, seq := b.Request(48, data, size)
1002+ if p == nil {
1003+ return 0
1004+ }
1005+ off := 0
1006+ binary.LittleEndian.PutUint32(p[off:], uint32(font))
1007+ off += 4
1008+ for i := range string {
1009+ string[i].Put(p[off:])
1010+ off += 2
1011+ }
1012+ return seq
1013+}
1014+
1015+func ListFonts(b *xturbo.Buf, maxNames uint16, pattern string) xturbo.Seq {
1016+ if uint64(len(pattern)) > 65535 {
1017+ b.Fail(xturbo.ErrBadLength)
1018+ return 0
1019+ }
1020+ size := 0
1021+ size += 2
1022+ size += 2
1023+ size += len(pattern) * 1
1024+ size = (size + 3) &^ 3
1025+ p, seq := b.Request(49, 0, size)
1026+ if p == nil {
1027+ return 0
1028+ }
1029+ off := 0
1030+ binary.LittleEndian.PutUint16(p[off:], uint16(maxNames))
1031+ off += 2
1032+ binary.LittleEndian.PutUint16(p[off:], uint16(len(pattern)))
1033+ off += 2
1034+ copy(p[off:], pattern)
1035+ off += len(pattern)
1036+ return seq
1037+}
1038+
1039+func ListFontsWithInfo(b *xturbo.Buf, maxNames uint16, pattern string) xturbo.Seq {
1040+ if uint64(len(pattern)) > 65535 {
1041+ b.Fail(xturbo.ErrBadLength)
1042+ return 0
1043+ }
1044+ size := 0
1045+ size += 2
1046+ size += 2
1047+ size += len(pattern) * 1
1048+ size = (size + 3) &^ 3
1049+ p, seq := b.Request(50, 0, size)
1050+ if p == nil {
1051+ return 0
1052+ }
1053+ off := 0
1054+ binary.LittleEndian.PutUint16(p[off:], uint16(maxNames))
1055+ off += 2
1056+ binary.LittleEndian.PutUint16(p[off:], uint16(len(pattern)))
1057+ off += 2
1058+ copy(p[off:], pattern)
1059+ off += len(pattern)
1060+ return seq
1061+}
1062+
1063+func SetFontPath(b *xturbo.Buf, font []Str) xturbo.Seq {
1064+ if uint64(len(font)) > 65535 {
1065+ b.Fail(xturbo.ErrBadLength)
1066+ return 0
1067+ }
1068+ size := 0
1069+ size += 2
1070+ size += 2
1071+ for i := range font {
1072+ size += font[i].Size()
1073+ }
1074+ size = (size + 3) &^ 3
1075+ p, seq := b.Request(51, 0, size)
1076+ if p == nil {
1077+ return 0
1078+ }
1079+ off := 0
1080+ binary.LittleEndian.PutUint16(p[off:], uint16(len(font)))
1081+ off += 2
1082+ off += 2
1083+ for i := range font {
1084+ font[i].Put(p[off:])
1085+ off += font[i].Size()
1086+ }
1087+ return seq
1088+}
1089+
1090+func GetFontPath(b *xturbo.Buf) xturbo.Seq {
1091+ p, seq := b.Request(52, 0, 0)
1092+ if p == nil {
1093+ return 0
1094+ }
1095+ return seq
1096+}
1097+
1098+func CreatePixmap(b *xturbo.Buf, depth uint8, pid Pixmap, drawable Drawable, width uint16, height uint16) xturbo.Seq {
1099+ p, seq := b.Request(53, uint8(int(depth)), 12)
1100+ if p == nil {
1101+ return 0
1102+ }
1103+ binary.LittleEndian.PutUint32(p[0:], uint32(pid))
1104+ binary.LittleEndian.PutUint32(p[4:], uint32(drawable))
1105+ binary.LittleEndian.PutUint16(p[8:], uint16(width))
1106+ binary.LittleEndian.PutUint16(p[10:], uint16(height))
1107+ return seq
1108+}
1109+
1110+func FreePixmap(b *xturbo.Buf, pixmap Pixmap) xturbo.Seq {
1111+ p, seq := b.Request(54, 0, 4)
1112+ if p == nil {
1113+ return 0
1114+ }
1115+ binary.LittleEndian.PutUint32(p[0:], uint32(pixmap))
1116+ return seq
1117+}
1118+
1119+type CreateGCValues struct {
1120+ Mask Gc
1121+ Function Gx
1122+ PlaneMask uint32
1123+ Foreground uint32
1124+ Background uint32
1125+ LineWidth uint32
1126+ LineStyle LineStyle
1127+ CapStyle CapStyle
1128+ JoinStyle JoinStyle
1129+ FillStyle FillStyle
1130+ FillRule FillRule
1131+ Tile Pixmap
1132+ Stipple Pixmap
1133+ TileStippleXOrigin int32
1134+ TileStippleYOrigin int32
1135+ Font Font
1136+ SubwindowMode SubwindowMode
1137+ GraphicsExposures bool
1138+ ClipXOrigin int32
1139+ ClipYOrigin int32
1140+ ClipMask Pixmap
1141+ DashOffset uint32
1142+ Dashes uint32
1143+ ArcMode ArcMode
1144+}
1145+
1146+func (v *CreateGCValues) SetFunction(x Gx) *CreateGCValues {
1147+ v.Mask |= GcFunction
1148+ v.Function = x
1149+ return v
1150+}
1151+func (v *CreateGCValues) SetPlaneMask(x uint32) *CreateGCValues {
1152+ v.Mask |= GcPlaneMask
1153+ v.PlaneMask = x
1154+ return v
1155+}
1156+func (v *CreateGCValues) SetForeground(x uint32) *CreateGCValues {
1157+ v.Mask |= GcForeground
1158+ v.Foreground = x
1159+ return v
1160+}
1161+func (v *CreateGCValues) SetBackground(x uint32) *CreateGCValues {
1162+ v.Mask |= GcBackground
1163+ v.Background = x
1164+ return v
1165+}
1166+func (v *CreateGCValues) SetLineWidth(x uint32) *CreateGCValues {
1167+ v.Mask |= GcLineWidth
1168+ v.LineWidth = x
1169+ return v
1170+}
1171+func (v *CreateGCValues) SetLineStyle(x LineStyle) *CreateGCValues {
1172+ v.Mask |= GcLineStyle
1173+ v.LineStyle = x
1174+ return v
1175+}
1176+func (v *CreateGCValues) SetCapStyle(x CapStyle) *CreateGCValues {
1177+ v.Mask |= GcCapStyle
1178+ v.CapStyle = x
1179+ return v
1180+}
1181+func (v *CreateGCValues) SetJoinStyle(x JoinStyle) *CreateGCValues {
1182+ v.Mask |= GcJoinStyle
1183+ v.JoinStyle = x
1184+ return v
1185+}
1186+func (v *CreateGCValues) SetFillStyle(x FillStyle) *CreateGCValues {
1187+ v.Mask |= GcFillStyle
1188+ v.FillStyle = x
1189+ return v
1190+}
1191+func (v *CreateGCValues) SetFillRule(x FillRule) *CreateGCValues {
1192+ v.Mask |= GcFillRule
1193+ v.FillRule = x
1194+ return v
1195+}
1196+func (v *CreateGCValues) SetTile(x Pixmap) *CreateGCValues { v.Mask |= GcTile; v.Tile = x; return v }
1197+func (v *CreateGCValues) SetStipple(x Pixmap) *CreateGCValues {
1198+ v.Mask |= GcStipple
1199+ v.Stipple = x
1200+ return v
1201+}
1202+func (v *CreateGCValues) SetTileStippleXOrigin(x int32) *CreateGCValues {
1203+ v.Mask |= GcTileStippleOriginX
1204+ v.TileStippleXOrigin = x
1205+ return v
1206+}
1207+func (v *CreateGCValues) SetTileStippleYOrigin(x int32) *CreateGCValues {
1208+ v.Mask |= GcTileStippleOriginY
1209+ v.TileStippleYOrigin = x
1210+ return v
1211+}
1212+func (v *CreateGCValues) SetFont(x Font) *CreateGCValues { v.Mask |= GcFont; v.Font = x; return v }
1213+func (v *CreateGCValues) SetSubwindowMode(x SubwindowMode) *CreateGCValues {
1214+ v.Mask |= GcSubwindowMode
1215+ v.SubwindowMode = x
1216+ return v
1217+}
1218+func (v *CreateGCValues) SetGraphicsExposures(x bool) *CreateGCValues {
1219+ v.Mask |= GcGraphicsExposures
1220+ v.GraphicsExposures = x
1221+ return v
1222+}
1223+func (v *CreateGCValues) SetClipXOrigin(x int32) *CreateGCValues {
1224+ v.Mask |= GcClipOriginX
1225+ v.ClipXOrigin = x
1226+ return v
1227+}
1228+func (v *CreateGCValues) SetClipYOrigin(x int32) *CreateGCValues {
1229+ v.Mask |= GcClipOriginY
1230+ v.ClipYOrigin = x
1231+ return v
1232+}
1233+func (v *CreateGCValues) SetClipMask(x Pixmap) *CreateGCValues {
1234+ v.Mask |= GcClipMask
1235+ v.ClipMask = x
1236+ return v
1237+}
1238+func (v *CreateGCValues) SetDashOffset(x uint32) *CreateGCValues {
1239+ v.Mask |= GcDashOffset
1240+ v.DashOffset = x
1241+ return v
1242+}
1243+func (v *CreateGCValues) SetDashes(x uint32) *CreateGCValues {
1244+ v.Mask |= GcDashList
1245+ v.Dashes = x
1246+ return v
1247+}
1248+func (v *CreateGCValues) SetArcMode(x ArcMode) *CreateGCValues {
1249+ v.Mask |= GcArcMode
1250+ v.ArcMode = x
1251+ return v
1252+}
1253+func CreateGC(b *xturbo.Buf, cid Gcontext, drawable Drawable, v *CreateGCValues) xturbo.Seq {
1254+ p, seq := b.Request(55, 0, 12+4*bits.OnesCount32(uint32(v.Mask)))
1255+ if p == nil {
1256+ return 0
1257+ }
1258+ binary.LittleEndian.PutUint32(p[0:], uint32(cid))
1259+ binary.LittleEndian.PutUint32(p[4:], uint32(drawable))
1260+ binary.LittleEndian.PutUint32(p[8:], uint32(v.Mask))
1261+ off := 12
1262+ if v.Mask&GcFunction != 0 {
1263+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Function))
1264+ off += 4
1265+ }
1266+ if v.Mask&GcPlaneMask != 0 {
1267+ binary.LittleEndian.PutUint32(p[off:], uint32(v.PlaneMask))
1268+ off += 4
1269+ }
1270+ if v.Mask&GcForeground != 0 {
1271+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Foreground))
1272+ off += 4
1273+ }
1274+ if v.Mask&GcBackground != 0 {
1275+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Background))
1276+ off += 4
1277+ }
1278+ if v.Mask&GcLineWidth != 0 {
1279+ binary.LittleEndian.PutUint32(p[off:], uint32(v.LineWidth))
1280+ off += 4
1281+ }
1282+ if v.Mask&GcLineStyle != 0 {
1283+ binary.LittleEndian.PutUint32(p[off:], uint32(v.LineStyle))
1284+ off += 4
1285+ }
1286+ if v.Mask&GcCapStyle != 0 {
1287+ binary.LittleEndian.PutUint32(p[off:], uint32(v.CapStyle))
1288+ off += 4
1289+ }
1290+ if v.Mask&GcJoinStyle != 0 {
1291+ binary.LittleEndian.PutUint32(p[off:], uint32(v.JoinStyle))
1292+ off += 4
1293+ }
1294+ if v.Mask&GcFillStyle != 0 {
1295+ binary.LittleEndian.PutUint32(p[off:], uint32(v.FillStyle))
1296+ off += 4
1297+ }
1298+ if v.Mask&GcFillRule != 0 {
1299+ binary.LittleEndian.PutUint32(p[off:], uint32(v.FillRule))
1300+ off += 4
1301+ }
1302+ if v.Mask&GcTile != 0 {
1303+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Tile))
1304+ off += 4
1305+ }
1306+ if v.Mask&GcStipple != 0 {
1307+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Stipple))
1308+ off += 4
1309+ }
1310+ if v.Mask&GcTileStippleOriginX != 0 {
1311+ binary.LittleEndian.PutUint32(p[off:], uint32(v.TileStippleXOrigin))
1312+ off += 4
1313+ }
1314+ if v.Mask&GcTileStippleOriginY != 0 {
1315+ binary.LittleEndian.PutUint32(p[off:], uint32(v.TileStippleYOrigin))
1316+ off += 4
1317+ }
1318+ if v.Mask&GcFont != 0 {
1319+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Font))
1320+ off += 4
1321+ }
1322+ if v.Mask&GcSubwindowMode != 0 {
1323+ binary.LittleEndian.PutUint32(p[off:], uint32(v.SubwindowMode))
1324+ off += 4
1325+ }
1326+ if v.Mask&GcGraphicsExposures != 0 {
1327+ if v.GraphicsExposures {
1328+ binary.LittleEndian.PutUint32(p[off:], 1)
1329+ } else {
1330+ binary.LittleEndian.PutUint32(p[off:], 0)
1331+ }
1332+ off += 4
1333+ }
1334+ if v.Mask&GcClipOriginX != 0 {
1335+ binary.LittleEndian.PutUint32(p[off:], uint32(v.ClipXOrigin))
1336+ off += 4
1337+ }
1338+ if v.Mask&GcClipOriginY != 0 {
1339+ binary.LittleEndian.PutUint32(p[off:], uint32(v.ClipYOrigin))
1340+ off += 4
1341+ }
1342+ if v.Mask&GcClipMask != 0 {
1343+ binary.LittleEndian.PutUint32(p[off:], uint32(v.ClipMask))
1344+ off += 4
1345+ }
1346+ if v.Mask&GcDashOffset != 0 {
1347+ binary.LittleEndian.PutUint32(p[off:], uint32(v.DashOffset))
1348+ off += 4
1349+ }
1350+ if v.Mask&GcDashList != 0 {
1351+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Dashes))
1352+ off += 4
1353+ }
1354+ if v.Mask&GcArcMode != 0 {
1355+ binary.LittleEndian.PutUint32(p[off:], uint32(v.ArcMode))
1356+ off += 4
1357+ }
1358+ _ = off
1359+ return seq
1360+}
1361+
1362+type ChangeGCValues struct {
1363+ Mask Gc
1364+ Function Gx
1365+ PlaneMask uint32
1366+ Foreground uint32
1367+ Background uint32
1368+ LineWidth uint32
1369+ LineStyle LineStyle
1370+ CapStyle CapStyle
1371+ JoinStyle JoinStyle
1372+ FillStyle FillStyle
1373+ FillRule FillRule
1374+ Tile Pixmap
1375+ Stipple Pixmap
1376+ TileStippleXOrigin int32
1377+ TileStippleYOrigin int32
1378+ Font Font
1379+ SubwindowMode SubwindowMode
1380+ GraphicsExposures bool
1381+ ClipXOrigin int32
1382+ ClipYOrigin int32
1383+ ClipMask Pixmap
1384+ DashOffset uint32
1385+ Dashes uint32
1386+ ArcMode ArcMode
1387+}
1388+
1389+func (v *ChangeGCValues) SetFunction(x Gx) *ChangeGCValues {
1390+ v.Mask |= GcFunction
1391+ v.Function = x
1392+ return v
1393+}
1394+func (v *ChangeGCValues) SetPlaneMask(x uint32) *ChangeGCValues {
1395+ v.Mask |= GcPlaneMask
1396+ v.PlaneMask = x
1397+ return v
1398+}
1399+func (v *ChangeGCValues) SetForeground(x uint32) *ChangeGCValues {
1400+ v.Mask |= GcForeground
1401+ v.Foreground = x
1402+ return v
1403+}
1404+func (v *ChangeGCValues) SetBackground(x uint32) *ChangeGCValues {
1405+ v.Mask |= GcBackground
1406+ v.Background = x
1407+ return v
1408+}
1409+func (v *ChangeGCValues) SetLineWidth(x uint32) *ChangeGCValues {
1410+ v.Mask |= GcLineWidth
1411+ v.LineWidth = x
1412+ return v
1413+}
1414+func (v *ChangeGCValues) SetLineStyle(x LineStyle) *ChangeGCValues {
1415+ v.Mask |= GcLineStyle
1416+ v.LineStyle = x
1417+ return v
1418+}
1419+func (v *ChangeGCValues) SetCapStyle(x CapStyle) *ChangeGCValues {
1420+ v.Mask |= GcCapStyle
1421+ v.CapStyle = x
1422+ return v
1423+}
1424+func (v *ChangeGCValues) SetJoinStyle(x JoinStyle) *ChangeGCValues {
1425+ v.Mask |= GcJoinStyle
1426+ v.JoinStyle = x
1427+ return v
1428+}
1429+func (v *ChangeGCValues) SetFillStyle(x FillStyle) *ChangeGCValues {
1430+ v.Mask |= GcFillStyle
1431+ v.FillStyle = x
1432+ return v
1433+}
1434+func (v *ChangeGCValues) SetFillRule(x FillRule) *ChangeGCValues {
1435+ v.Mask |= GcFillRule
1436+ v.FillRule = x
1437+ return v
1438+}
1439+func (v *ChangeGCValues) SetTile(x Pixmap) *ChangeGCValues { v.Mask |= GcTile; v.Tile = x; return v }
1440+func (v *ChangeGCValues) SetStipple(x Pixmap) *ChangeGCValues {
1441+ v.Mask |= GcStipple
1442+ v.Stipple = x
1443+ return v
1444+}
1445+func (v *ChangeGCValues) SetTileStippleXOrigin(x int32) *ChangeGCValues {
1446+ v.Mask |= GcTileStippleOriginX
1447+ v.TileStippleXOrigin = x
1448+ return v
1449+}
1450+func (v *ChangeGCValues) SetTileStippleYOrigin(x int32) *ChangeGCValues {
1451+ v.Mask |= GcTileStippleOriginY
1452+ v.TileStippleYOrigin = x
1453+ return v
1454+}
1455+func (v *ChangeGCValues) SetFont(x Font) *ChangeGCValues { v.Mask |= GcFont; v.Font = x; return v }
1456+func (v *ChangeGCValues) SetSubwindowMode(x SubwindowMode) *ChangeGCValues {
1457+ v.Mask |= GcSubwindowMode
1458+ v.SubwindowMode = x
1459+ return v
1460+}
1461+func (v *ChangeGCValues) SetGraphicsExposures(x bool) *ChangeGCValues {
1462+ v.Mask |= GcGraphicsExposures
1463+ v.GraphicsExposures = x
1464+ return v
1465+}
1466+func (v *ChangeGCValues) SetClipXOrigin(x int32) *ChangeGCValues {
1467+ v.Mask |= GcClipOriginX
1468+ v.ClipXOrigin = x
1469+ return v
1470+}
1471+func (v *ChangeGCValues) SetClipYOrigin(x int32) *ChangeGCValues {
1472+ v.Mask |= GcClipOriginY
1473+ v.ClipYOrigin = x
1474+ return v
1475+}
1476+func (v *ChangeGCValues) SetClipMask(x Pixmap) *ChangeGCValues {
1477+ v.Mask |= GcClipMask
1478+ v.ClipMask = x
1479+ return v
1480+}
1481+func (v *ChangeGCValues) SetDashOffset(x uint32) *ChangeGCValues {
1482+ v.Mask |= GcDashOffset
1483+ v.DashOffset = x
1484+ return v
1485+}
1486+func (v *ChangeGCValues) SetDashes(x uint32) *ChangeGCValues {
1487+ v.Mask |= GcDashList
1488+ v.Dashes = x
1489+ return v
1490+}
1491+func (v *ChangeGCValues) SetArcMode(x ArcMode) *ChangeGCValues {
1492+ v.Mask |= GcArcMode
1493+ v.ArcMode = x
1494+ return v
1495+}
1496+func ChangeGC(b *xturbo.Buf, gc Gcontext, v *ChangeGCValues) xturbo.Seq {
1497+ p, seq := b.Request(56, 0, 8+4*bits.OnesCount32(uint32(v.Mask)))
1498+ if p == nil {
1499+ return 0
1500+ }
1501+ binary.LittleEndian.PutUint32(p[0:], uint32(gc))
1502+ binary.LittleEndian.PutUint32(p[4:], uint32(v.Mask))
1503+ off := 8
1504+ if v.Mask&GcFunction != 0 {
1505+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Function))
1506+ off += 4
1507+ }
1508+ if v.Mask&GcPlaneMask != 0 {
1509+ binary.LittleEndian.PutUint32(p[off:], uint32(v.PlaneMask))
1510+ off += 4
1511+ }
1512+ if v.Mask&GcForeground != 0 {
1513+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Foreground))
1514+ off += 4
1515+ }
1516+ if v.Mask&GcBackground != 0 {
1517+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Background))
1518+ off += 4
1519+ }
1520+ if v.Mask&GcLineWidth != 0 {
1521+ binary.LittleEndian.PutUint32(p[off:], uint32(v.LineWidth))
1522+ off += 4
1523+ }
1524+ if v.Mask&GcLineStyle != 0 {
1525+ binary.LittleEndian.PutUint32(p[off:], uint32(v.LineStyle))
1526+ off += 4
1527+ }
1528+ if v.Mask&GcCapStyle != 0 {
1529+ binary.LittleEndian.PutUint32(p[off:], uint32(v.CapStyle))
1530+ off += 4
1531+ }
1532+ if v.Mask&GcJoinStyle != 0 {
1533+ binary.LittleEndian.PutUint32(p[off:], uint32(v.JoinStyle))
1534+ off += 4
1535+ }
1536+ if v.Mask&GcFillStyle != 0 {
1537+ binary.LittleEndian.PutUint32(p[off:], uint32(v.FillStyle))
1538+ off += 4
1539+ }
1540+ if v.Mask&GcFillRule != 0 {
1541+ binary.LittleEndian.PutUint32(p[off:], uint32(v.FillRule))
1542+ off += 4
1543+ }
1544+ if v.Mask&GcTile != 0 {
1545+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Tile))
1546+ off += 4
1547+ }
1548+ if v.Mask&GcStipple != 0 {
1549+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Stipple))
1550+ off += 4
1551+ }
1552+ if v.Mask&GcTileStippleOriginX != 0 {
1553+ binary.LittleEndian.PutUint32(p[off:], uint32(v.TileStippleXOrigin))
1554+ off += 4
1555+ }
1556+ if v.Mask&GcTileStippleOriginY != 0 {
1557+ binary.LittleEndian.PutUint32(p[off:], uint32(v.TileStippleYOrigin))
1558+ off += 4
1559+ }
1560+ if v.Mask&GcFont != 0 {
1561+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Font))
1562+ off += 4
1563+ }
1564+ if v.Mask&GcSubwindowMode != 0 {
1565+ binary.LittleEndian.PutUint32(p[off:], uint32(v.SubwindowMode))
1566+ off += 4
1567+ }
1568+ if v.Mask&GcGraphicsExposures != 0 {
1569+ if v.GraphicsExposures {
1570+ binary.LittleEndian.PutUint32(p[off:], 1)
1571+ } else {
1572+ binary.LittleEndian.PutUint32(p[off:], 0)
1573+ }
1574+ off += 4
1575+ }
1576+ if v.Mask&GcClipOriginX != 0 {
1577+ binary.LittleEndian.PutUint32(p[off:], uint32(v.ClipXOrigin))
1578+ off += 4
1579+ }
1580+ if v.Mask&GcClipOriginY != 0 {
1581+ binary.LittleEndian.PutUint32(p[off:], uint32(v.ClipYOrigin))
1582+ off += 4
1583+ }
1584+ if v.Mask&GcClipMask != 0 {
1585+ binary.LittleEndian.PutUint32(p[off:], uint32(v.ClipMask))
1586+ off += 4
1587+ }
1588+ if v.Mask&GcDashOffset != 0 {
1589+ binary.LittleEndian.PutUint32(p[off:], uint32(v.DashOffset))
1590+ off += 4
1591+ }
1592+ if v.Mask&GcDashList != 0 {
1593+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Dashes))
1594+ off += 4
1595+ }
1596+ if v.Mask&GcArcMode != 0 {
1597+ binary.LittleEndian.PutUint32(p[off:], uint32(v.ArcMode))
1598+ off += 4
1599+ }
1600+ _ = off
1601+ return seq
1602+}
1603+
1604+func CopyGC(b *xturbo.Buf, srcGc Gcontext, dstGc Gcontext, valueMask Gc) xturbo.Seq {
1605+ p, seq := b.Request(57, 0, 12)
1606+ if p == nil {
1607+ return 0
1608+ }
1609+ binary.LittleEndian.PutUint32(p[0:], uint32(srcGc))
1610+ binary.LittleEndian.PutUint32(p[4:], uint32(dstGc))
1611+ binary.LittleEndian.PutUint32(p[8:], uint32(valueMask))
1612+ return seq
1613+}
1614+
1615+func SetDashes(b *xturbo.Buf, gc Gcontext, dashOffset uint16, dashes []byte) xturbo.Seq {
1616+ if uint64(len(dashes)) > 65535 {
1617+ b.Fail(xturbo.ErrBadLength)
1618+ return 0
1619+ }
1620+ size := 0
1621+ size += 4
1622+ size += 2
1623+ size += 2
1624+ size += len(dashes) * 1
1625+ size = (size + 3) &^ 3
1626+ p, seq := b.Request(58, 0, size)
1627+ if p == nil {
1628+ return 0
1629+ }
1630+ off := 0
1631+ binary.LittleEndian.PutUint32(p[off:], uint32(gc))
1632+ off += 4
1633+ binary.LittleEndian.PutUint16(p[off:], uint16(dashOffset))
1634+ off += 2
1635+ binary.LittleEndian.PutUint16(p[off:], uint16(len(dashes)))
1636+ off += 2
1637+ copy(p[off:], dashes)
1638+ off += len(dashes)
1639+ return seq
1640+}
1641+
1642+func SetClipRectangles(b *xturbo.Buf, ordering ClipOrdering, gc Gcontext, clipXOrigin int16, clipYOrigin int16, rectangles []Rectangle) xturbo.Seq {
1643+ size := 0
1644+ size += 4
1645+ size += 2
1646+ size += 2
1647+ size += len(rectangles) * 8
1648+ size = (size + 3) &^ 3
1649+ p, seq := b.Request(59, uint8(int(ordering)), size)
1650+ if p == nil {
1651+ return 0
1652+ }
1653+ off := 0
1654+ binary.LittleEndian.PutUint32(p[off:], uint32(gc))
1655+ off += 4
1656+ binary.LittleEndian.PutUint16(p[off:], uint16(clipXOrigin))
1657+ off += 2
1658+ binary.LittleEndian.PutUint16(p[off:], uint16(clipYOrigin))
1659+ off += 2
1660+ for i := range rectangles {
1661+ rectangles[i].Put(p[off:])
1662+ off += 8
1663+ }
1664+ return seq
1665+}
1666+
1667+func FreeGC(b *xturbo.Buf, gc Gcontext) xturbo.Seq {
1668+ p, seq := b.Request(60, 0, 4)
1669+ if p == nil {
1670+ return 0
1671+ }
1672+ binary.LittleEndian.PutUint32(p[0:], uint32(gc))
1673+ return seq
1674+}
1675+
1676+func ClearArea(b *xturbo.Buf, exposures bool, window Window, x int16, y int16, width uint16, height uint16) xturbo.Seq {
1677+ var data uint8
1678+ if exposures {
1679+ data = 1
1680+ }
1681+ p, seq := b.Request(61, data, 12)
1682+ if p == nil {
1683+ return 0
1684+ }
1685+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
1686+ binary.LittleEndian.PutUint16(p[4:], uint16(x))
1687+ binary.LittleEndian.PutUint16(p[6:], uint16(y))
1688+ binary.LittleEndian.PutUint16(p[8:], uint16(width))
1689+ binary.LittleEndian.PutUint16(p[10:], uint16(height))
1690+ return seq
1691+}
1692+
1693+func CopyArea(b *xturbo.Buf, srcDrawable Drawable, dstDrawable Drawable, gc Gcontext, srcX int16, srcY int16, dstX int16, dstY int16, width uint16, height uint16) xturbo.Seq {
1694+ p, seq := b.Request(62, 0, 24)
1695+ if p == nil {
1696+ return 0
1697+ }
1698+ binary.LittleEndian.PutUint32(p[0:], uint32(srcDrawable))
1699+ binary.LittleEndian.PutUint32(p[4:], uint32(dstDrawable))
1700+ binary.LittleEndian.PutUint32(p[8:], uint32(gc))
1701+ binary.LittleEndian.PutUint16(p[12:], uint16(srcX))
1702+ binary.LittleEndian.PutUint16(p[14:], uint16(srcY))
1703+ binary.LittleEndian.PutUint16(p[16:], uint16(dstX))
1704+ binary.LittleEndian.PutUint16(p[18:], uint16(dstY))
1705+ binary.LittleEndian.PutUint16(p[20:], uint16(width))
1706+ binary.LittleEndian.PutUint16(p[22:], uint16(height))
1707+ return seq
1708+}
1709+
1710+func CopyPlane(b *xturbo.Buf, srcDrawable Drawable, dstDrawable Drawable, gc Gcontext, srcX int16, srcY int16, dstX int16, dstY int16, width uint16, height uint16, bitPlane uint32) xturbo.Seq {
1711+ p, seq := b.Request(63, 0, 28)
1712+ if p == nil {
1713+ return 0
1714+ }
1715+ binary.LittleEndian.PutUint32(p[0:], uint32(srcDrawable))
1716+ binary.LittleEndian.PutUint32(p[4:], uint32(dstDrawable))
1717+ binary.LittleEndian.PutUint32(p[8:], uint32(gc))
1718+ binary.LittleEndian.PutUint16(p[12:], uint16(srcX))
1719+ binary.LittleEndian.PutUint16(p[14:], uint16(srcY))
1720+ binary.LittleEndian.PutUint16(p[16:], uint16(dstX))
1721+ binary.LittleEndian.PutUint16(p[18:], uint16(dstY))
1722+ binary.LittleEndian.PutUint16(p[20:], uint16(width))
1723+ binary.LittleEndian.PutUint16(p[22:], uint16(height))
1724+ binary.LittleEndian.PutUint32(p[24:], uint32(bitPlane))
1725+ return seq
1726+}
1727+
1728+func PolyPoint(b *xturbo.Buf, coordinateMode CoordMode, drawable Drawable, gc Gcontext, points []Point) xturbo.Seq {
1729+ size := 0
1730+ size += 4
1731+ size += 4
1732+ size += len(points) * 4
1733+ size = (size + 3) &^ 3
1734+ p, seq := b.Request(64, uint8(int(coordinateMode)), size)
1735+ if p == nil {
1736+ return 0
1737+ }
1738+ off := 0
1739+ binary.LittleEndian.PutUint32(p[off:], uint32(drawable))
1740+ off += 4
1741+ binary.LittleEndian.PutUint32(p[off:], uint32(gc))
1742+ off += 4
1743+ for i := range points {
1744+ points[i].Put(p[off:])
1745+ off += 4
1746+ }
1747+ return seq
1748+}
1749+
1750+func PolyLine(b *xturbo.Buf, coordinateMode CoordMode, drawable Drawable, gc Gcontext, points []Point) xturbo.Seq {
1751+ size := 0
1752+ size += 4
1753+ size += 4
1754+ size += len(points) * 4
1755+ size = (size + 3) &^ 3
1756+ p, seq := b.Request(65, uint8(int(coordinateMode)), size)
1757+ if p == nil {
1758+ return 0
1759+ }
1760+ off := 0
1761+ binary.LittleEndian.PutUint32(p[off:], uint32(drawable))
1762+ off += 4
1763+ binary.LittleEndian.PutUint32(p[off:], uint32(gc))
1764+ off += 4
1765+ for i := range points {
1766+ points[i].Put(p[off:])
1767+ off += 4
1768+ }
1769+ return seq
1770+}
1771+
1772+func PolySegment(b *xturbo.Buf, drawable Drawable, gc Gcontext, segments []Segment) xturbo.Seq {
1773+ size := 0
1774+ size += 4
1775+ size += 4
1776+ size += len(segments) * 8
1777+ size = (size + 3) &^ 3
1778+ p, seq := b.Request(66, 0, size)
1779+ if p == nil {
1780+ return 0
1781+ }
1782+ off := 0
1783+ binary.LittleEndian.PutUint32(p[off:], uint32(drawable))
1784+ off += 4
1785+ binary.LittleEndian.PutUint32(p[off:], uint32(gc))
1786+ off += 4
1787+ for i := range segments {
1788+ segments[i].Put(p[off:])
1789+ off += 8
1790+ }
1791+ return seq
1792+}
1793+
1794+func PolyRectangle(b *xturbo.Buf, drawable Drawable, gc Gcontext, rectangles []Rectangle) xturbo.Seq {
1795+ size := 0
1796+ size += 4
1797+ size += 4
1798+ size += len(rectangles) * 8
1799+ size = (size + 3) &^ 3
1800+ p, seq := b.Request(67, 0, size)
1801+ if p == nil {
1802+ return 0
1803+ }
1804+ off := 0
1805+ binary.LittleEndian.PutUint32(p[off:], uint32(drawable))
1806+ off += 4
1807+ binary.LittleEndian.PutUint32(p[off:], uint32(gc))
1808+ off += 4
1809+ for i := range rectangles {
1810+ rectangles[i].Put(p[off:])
1811+ off += 8
1812+ }
1813+ return seq
1814+}
1815+
1816+func PolyArc(b *xturbo.Buf, drawable Drawable, gc Gcontext, arcs []Arc) xturbo.Seq {
1817+ size := 0
1818+ size += 4
1819+ size += 4
1820+ size += len(arcs) * 12
1821+ size = (size + 3) &^ 3
1822+ p, seq := b.Request(68, 0, size)
1823+ if p == nil {
1824+ return 0
1825+ }
1826+ off := 0
1827+ binary.LittleEndian.PutUint32(p[off:], uint32(drawable))
1828+ off += 4
1829+ binary.LittleEndian.PutUint32(p[off:], uint32(gc))
1830+ off += 4
1831+ for i := range arcs {
1832+ arcs[i].Put(p[off:])
1833+ off += 12
1834+ }
1835+ return seq
1836+}
1837+
1838+func FillPoly(b *xturbo.Buf, drawable Drawable, gc Gcontext, shape PolyShape, coordinateMode CoordMode, points []Point) xturbo.Seq {
1839+ size := 0
1840+ size += 4
1841+ size += 4
1842+ size += 1
1843+ size += 1
1844+ size += 2
1845+ size += len(points) * 4
1846+ size = (size + 3) &^ 3
1847+ p, seq := b.Request(69, 0, size)
1848+ if p == nil {
1849+ return 0
1850+ }
1851+ off := 0
1852+ binary.LittleEndian.PutUint32(p[off:], uint32(drawable))
1853+ off += 4
1854+ binary.LittleEndian.PutUint32(p[off:], uint32(gc))
1855+ off += 4
1856+ p[off:][0] = byte(shape)
1857+ off += 1
1858+ p[off:][0] = byte(coordinateMode)
1859+ off += 1
1860+ off += 2
1861+ for i := range points {
1862+ points[i].Put(p[off:])
1863+ off += 4
1864+ }
1865+ return seq
1866+}
1867+
1868+func PolyFillRectangle(b *xturbo.Buf, drawable Drawable, gc Gcontext, rectangles []Rectangle) xturbo.Seq {
1869+ size := 0
1870+ size += 4
1871+ size += 4
1872+ size += len(rectangles) * 8
1873+ size = (size + 3) &^ 3
1874+ p, seq := b.Request(70, 0, size)
1875+ if p == nil {
1876+ return 0
1877+ }
1878+ off := 0
1879+ binary.LittleEndian.PutUint32(p[off:], uint32(drawable))
1880+ off += 4
1881+ binary.LittleEndian.PutUint32(p[off:], uint32(gc))
1882+ off += 4
1883+ for i := range rectangles {
1884+ rectangles[i].Put(p[off:])
1885+ off += 8
1886+ }
1887+ return seq
1888+}
1889+
1890+func PolyFillArc(b *xturbo.Buf, drawable Drawable, gc Gcontext, arcs []Arc) xturbo.Seq {
1891+ size := 0
1892+ size += 4
1893+ size += 4
1894+ size += len(arcs) * 12
1895+ size = (size + 3) &^ 3
1896+ p, seq := b.Request(71, 0, size)
1897+ if p == nil {
1898+ return 0
1899+ }
1900+ off := 0
1901+ binary.LittleEndian.PutUint32(p[off:], uint32(drawable))
1902+ off += 4
1903+ binary.LittleEndian.PutUint32(p[off:], uint32(gc))
1904+ off += 4
1905+ for i := range arcs {
1906+ arcs[i].Put(p[off:])
1907+ off += 12
1908+ }
1909+ return seq
1910+}
1911+
1912+func PutImage(b *xturbo.Buf, format ImageFormat, drawable Drawable, gc Gcontext, width uint16, height uint16, dstX int16, dstY int16, leftPad uint8, depth uint8, data []byte) xturbo.Seq {
1913+ size := 0
1914+ size += 4
1915+ size += 4
1916+ size += 2
1917+ size += 2
1918+ size += 2
1919+ size += 2
1920+ size += 1
1921+ size += 1
1922+ size += 2
1923+ size += len(data) * 1
1924+ size = (size + 3) &^ 3
1925+ p, seq := b.Request(72, uint8(int(format)), size)
1926+ if p == nil {
1927+ return 0
1928+ }
1929+ off := 0
1930+ binary.LittleEndian.PutUint32(p[off:], uint32(drawable))
1931+ off += 4
1932+ binary.LittleEndian.PutUint32(p[off:], uint32(gc))
1933+ off += 4
1934+ binary.LittleEndian.PutUint16(p[off:], uint16(width))
1935+ off += 2
1936+ binary.LittleEndian.PutUint16(p[off:], uint16(height))
1937+ off += 2
1938+ binary.LittleEndian.PutUint16(p[off:], uint16(dstX))
1939+ off += 2
1940+ binary.LittleEndian.PutUint16(p[off:], uint16(dstY))
1941+ off += 2
1942+ p[off:][0] = byte(leftPad)
1943+ off += 1
1944+ p[off:][0] = byte(depth)
1945+ off += 1
1946+ off += 2
1947+ copy(p[off:], data)
1948+ off += len(data)
1949+ return seq
1950+}
1951+
1952+func GetImage(b *xturbo.Buf, format ImageFormat, drawable Drawable, x int16, y int16, width uint16, height uint16, planeMask uint32) xturbo.Seq {
1953+ p, seq := b.Request(73, uint8(int(format)), 16)
1954+ if p == nil {
1955+ return 0
1956+ }
1957+ binary.LittleEndian.PutUint32(p[0:], uint32(drawable))
1958+ binary.LittleEndian.PutUint16(p[4:], uint16(x))
1959+ binary.LittleEndian.PutUint16(p[6:], uint16(y))
1960+ binary.LittleEndian.PutUint16(p[8:], uint16(width))
1961+ binary.LittleEndian.PutUint16(p[10:], uint16(height))
1962+ binary.LittleEndian.PutUint32(p[12:], uint32(planeMask))
1963+ return seq
1964+}
1965+
1966+func PolyText8(b *xturbo.Buf, drawable Drawable, gc Gcontext, x int16, y int16, items []byte) xturbo.Seq {
1967+ size := 0
1968+ size += 4
1969+ size += 4
1970+ size += 2
1971+ size += 2
1972+ size += len(items) * 1
1973+ size = (size + 3) &^ 3
1974+ p, seq := b.Request(74, 0, size)
1975+ if p == nil {
1976+ return 0
1977+ }
1978+ off := 0
1979+ binary.LittleEndian.PutUint32(p[off:], uint32(drawable))
1980+ off += 4
1981+ binary.LittleEndian.PutUint32(p[off:], uint32(gc))
1982+ off += 4
1983+ binary.LittleEndian.PutUint16(p[off:], uint16(x))
1984+ off += 2
1985+ binary.LittleEndian.PutUint16(p[off:], uint16(y))
1986+ off += 2
1987+ copy(p[off:], items)
1988+ off += len(items)
1989+ return seq
1990+}
1991+
1992+func PolyText16(b *xturbo.Buf, drawable Drawable, gc Gcontext, x int16, y int16, items []byte) xturbo.Seq {
1993+ size := 0
1994+ size += 4
1995+ size += 4
1996+ size += 2
1997+ size += 2
1998+ size += len(items) * 1
1999+ size = (size + 3) &^ 3
2000+ p, seq := b.Request(75, 0, size)
2001+ if p == nil {
2002+ return 0
2003+ }
2004+ off := 0
2005+ binary.LittleEndian.PutUint32(p[off:], uint32(drawable))
2006+ off += 4
2007+ binary.LittleEndian.PutUint32(p[off:], uint32(gc))
2008+ off += 4
2009+ binary.LittleEndian.PutUint16(p[off:], uint16(x))
2010+ off += 2
2011+ binary.LittleEndian.PutUint16(p[off:], uint16(y))
2012+ off += 2
2013+ copy(p[off:], items)
2014+ off += len(items)
2015+ return seq
2016+}
2017+
2018+func ImageText8(b *xturbo.Buf, drawable Drawable, gc Gcontext, x int16, y int16, string string) xturbo.Seq {
2019+ if len(string) > 255 {
2020+ b.Fail(xturbo.ErrBadLength)
2021+ return 0
2022+ }
2023+ size := 0
2024+ size += 4
2025+ size += 4
2026+ size += 2
2027+ size += 2
2028+ size += len(string) * 1
2029+ size = (size + 3) &^ 3
2030+ p, seq := b.Request(76, uint8(len(string)), size)
2031+ if p == nil {
2032+ return 0
2033+ }
2034+ off := 0
2035+ binary.LittleEndian.PutUint32(p[off:], uint32(drawable))
2036+ off += 4
2037+ binary.LittleEndian.PutUint32(p[off:], uint32(gc))
2038+ off += 4
2039+ binary.LittleEndian.PutUint16(p[off:], uint16(x))
2040+ off += 2
2041+ binary.LittleEndian.PutUint16(p[off:], uint16(y))
2042+ off += 2
2043+ copy(p[off:], string)
2044+ off += len(string)
2045+ return seq
2046+}
2047+
2048+func ImageText16(b *xturbo.Buf, drawable Drawable, gc Gcontext, x int16, y int16, string []Char2b) xturbo.Seq {
2049+ if len(string) > 255 {
2050+ b.Fail(xturbo.ErrBadLength)
2051+ return 0
2052+ }
2053+ size := 0
2054+ size += 4
2055+ size += 4
2056+ size += 2
2057+ size += 2
2058+ size += len(string) * 2
2059+ size = (size + 3) &^ 3
2060+ p, seq := b.Request(77, uint8(len(string)), size)
2061+ if p == nil {
2062+ return 0
2063+ }
2064+ off := 0
2065+ binary.LittleEndian.PutUint32(p[off:], uint32(drawable))
2066+ off += 4
2067+ binary.LittleEndian.PutUint32(p[off:], uint32(gc))
2068+ off += 4
2069+ binary.LittleEndian.PutUint16(p[off:], uint16(x))
2070+ off += 2
2071+ binary.LittleEndian.PutUint16(p[off:], uint16(y))
2072+ off += 2
2073+ for i := range string {
2074+ string[i].Put(p[off:])
2075+ off += 2
2076+ }
2077+ return seq
2078+}
2079+
2080+func CreateColormap(b *xturbo.Buf, alloc ColormapAlloc, mid Colormap, window Window, visual Visualid) xturbo.Seq {
2081+ p, seq := b.Request(78, uint8(int(alloc)), 12)
2082+ if p == nil {
2083+ return 0
2084+ }
2085+ binary.LittleEndian.PutUint32(p[0:], uint32(mid))
2086+ binary.LittleEndian.PutUint32(p[4:], uint32(window))
2087+ binary.LittleEndian.PutUint32(p[8:], uint32(visual))
2088+ return seq
2089+}
2090+
2091+func FreeColormap(b *xturbo.Buf, cmap Colormap) xturbo.Seq {
2092+ p, seq := b.Request(79, 0, 4)
2093+ if p == nil {
2094+ return 0
2095+ }
2096+ binary.LittleEndian.PutUint32(p[0:], uint32(cmap))
2097+ return seq
2098+}
2099+
2100+func CopyColormapAndFree(b *xturbo.Buf, mid Colormap, srcCmap Colormap) xturbo.Seq {
2101+ p, seq := b.Request(80, 0, 8)
2102+ if p == nil {
2103+ return 0
2104+ }
2105+ binary.LittleEndian.PutUint32(p[0:], uint32(mid))
2106+ binary.LittleEndian.PutUint32(p[4:], uint32(srcCmap))
2107+ return seq
2108+}
2109+
2110+func InstallColormap(b *xturbo.Buf, cmap Colormap) xturbo.Seq {
2111+ p, seq := b.Request(81, 0, 4)
2112+ if p == nil {
2113+ return 0
2114+ }
2115+ binary.LittleEndian.PutUint32(p[0:], uint32(cmap))
2116+ return seq
2117+}
2118+
2119+func UninstallColormap(b *xturbo.Buf, cmap Colormap) xturbo.Seq {
2120+ p, seq := b.Request(82, 0, 4)
2121+ if p == nil {
2122+ return 0
2123+ }
2124+ binary.LittleEndian.PutUint32(p[0:], uint32(cmap))
2125+ return seq
2126+}
2127+
2128+func ListInstalledColormaps(b *xturbo.Buf, window Window) xturbo.Seq {
2129+ p, seq := b.Request(83, 0, 4)
2130+ if p == nil {
2131+ return 0
2132+ }
2133+ binary.LittleEndian.PutUint32(p[0:], uint32(window))
2134+ return seq
2135+}
2136+
2137+func AllocColor(b *xturbo.Buf, cmap Colormap, red uint16, green uint16, blue uint16) xturbo.Seq {
2138+ p, seq := b.Request(84, 0, 12)
2139+ if p == nil {
2140+ return 0
2141+ }
2142+ binary.LittleEndian.PutUint32(p[0:], uint32(cmap))
2143+ binary.LittleEndian.PutUint16(p[4:], uint16(red))
2144+ binary.LittleEndian.PutUint16(p[6:], uint16(green))
2145+ binary.LittleEndian.PutUint16(p[8:], uint16(blue))
2146+ return seq
2147+}
2148+
2149+func AllocNamedColor(b *xturbo.Buf, cmap Colormap, name string) xturbo.Seq {
2150+ if uint64(len(name)) > 65535 {
2151+ b.Fail(xturbo.ErrBadLength)
2152+ return 0
2153+ }
2154+ size := 0
2155+ size += 4
2156+ size += 2
2157+ size += 2
2158+ size += len(name) * 1
2159+ size = (size + 3) &^ 3
2160+ p, seq := b.Request(85, 0, size)
2161+ if p == nil {
2162+ return 0
2163+ }
2164+ off := 0
2165+ binary.LittleEndian.PutUint32(p[off:], uint32(cmap))
2166+ off += 4
2167+ binary.LittleEndian.PutUint16(p[off:], uint16(len(name)))
2168+ off += 2
2169+ off += 2
2170+ copy(p[off:], name)
2171+ off += len(name)
2172+ return seq
2173+}
2174+
2175+func AllocColorCells(b *xturbo.Buf, contiguous bool, cmap Colormap, colors uint16, planes uint16) xturbo.Seq {
2176+ var data uint8
2177+ if contiguous {
2178+ data = 1
2179+ }
2180+ p, seq := b.Request(86, data, 8)
2181+ if p == nil {
2182+ return 0
2183+ }
2184+ binary.LittleEndian.PutUint32(p[0:], uint32(cmap))
2185+ binary.LittleEndian.PutUint16(p[4:], uint16(colors))
2186+ binary.LittleEndian.PutUint16(p[6:], uint16(planes))
2187+ return seq
2188+}
2189+
2190+func AllocColorPlanes(b *xturbo.Buf, contiguous bool, cmap Colormap, colors uint16, reds uint16, greens uint16, blues uint16) xturbo.Seq {
2191+ var data uint8
2192+ if contiguous {
2193+ data = 1
2194+ }
2195+ p, seq := b.Request(87, data, 12)
2196+ if p == nil {
2197+ return 0
2198+ }
2199+ binary.LittleEndian.PutUint32(p[0:], uint32(cmap))
2200+ binary.LittleEndian.PutUint16(p[4:], uint16(colors))
2201+ binary.LittleEndian.PutUint16(p[6:], uint16(reds))
2202+ binary.LittleEndian.PutUint16(p[8:], uint16(greens))
2203+ binary.LittleEndian.PutUint16(p[10:], uint16(blues))
2204+ return seq
2205+}
2206+
2207+func FreeColors(b *xturbo.Buf, cmap Colormap, planeMask uint32, pixels []uint32) xturbo.Seq {
2208+ size := 0
2209+ size += 4
2210+ size += 4
2211+ size += len(pixels) * 4
2212+ size = (size + 3) &^ 3
2213+ p, seq := b.Request(88, 0, size)
2214+ if p == nil {
2215+ return 0
2216+ }
2217+ off := 0
2218+ binary.LittleEndian.PutUint32(p[off:], uint32(cmap))
2219+ off += 4
2220+ binary.LittleEndian.PutUint32(p[off:], uint32(planeMask))
2221+ off += 4
2222+ for i := range pixels {
2223+ binary.LittleEndian.PutUint32(p[off:], uint32(pixels[i]))
2224+ off += 4
2225+ }
2226+ return seq
2227+}
2228+
2229+func StoreColors(b *xturbo.Buf, cmap Colormap, items []Coloritem) xturbo.Seq {
2230+ size := 0
2231+ size += 4
2232+ size += len(items) * 12
2233+ size = (size + 3) &^ 3
2234+ p, seq := b.Request(89, 0, size)
2235+ if p == nil {
2236+ return 0
2237+ }
2238+ off := 0
2239+ binary.LittleEndian.PutUint32(p[off:], uint32(cmap))
2240+ off += 4
2241+ for i := range items {
2242+ items[i].Put(p[off:])
2243+ off += 12
2244+ }
2245+ return seq
2246+}
2247+
2248+func StoreNamedColor(b *xturbo.Buf, flags ColorFlag, cmap Colormap, pixel uint32, name string) xturbo.Seq {
2249+ if uint64(len(name)) > 65535 {
2250+ b.Fail(xturbo.ErrBadLength)
2251+ return 0
2252+ }
2253+ size := 0
2254+ size += 4
2255+ size += 4
2256+ size += 2
2257+ size += 2
2258+ size += len(name) * 1
2259+ size = (size + 3) &^ 3
2260+ p, seq := b.Request(90, uint8(int(flags)), size)
2261+ if p == nil {
2262+ return 0
2263+ }
2264+ off := 0
2265+ binary.LittleEndian.PutUint32(p[off:], uint32(cmap))
2266+ off += 4
2267+ binary.LittleEndian.PutUint32(p[off:], uint32(pixel))
2268+ off += 4
2269+ binary.LittleEndian.PutUint16(p[off:], uint16(len(name)))
2270+ off += 2
2271+ off += 2
2272+ copy(p[off:], name)
2273+ off += len(name)
2274+ return seq
2275+}
2276+
2277+func QueryColors(b *xturbo.Buf, cmap Colormap, pixels []uint32) xturbo.Seq {
2278+ size := 0
2279+ size += 4
2280+ size += len(pixels) * 4
2281+ size = (size + 3) &^ 3
2282+ p, seq := b.Request(91, 0, size)
2283+ if p == nil {
2284+ return 0
2285+ }
2286+ off := 0
2287+ binary.LittleEndian.PutUint32(p[off:], uint32(cmap))
2288+ off += 4
2289+ for i := range pixels {
2290+ binary.LittleEndian.PutUint32(p[off:], uint32(pixels[i]))
2291+ off += 4
2292+ }
2293+ return seq
2294+}
2295+
2296+func LookupColor(b *xturbo.Buf, cmap Colormap, name string) xturbo.Seq {
2297+ if uint64(len(name)) > 65535 {
2298+ b.Fail(xturbo.ErrBadLength)
2299+ return 0
2300+ }
2301+ size := 0
2302+ size += 4
2303+ size += 2
2304+ size += 2
2305+ size += len(name) * 1
2306+ size = (size + 3) &^ 3
2307+ p, seq := b.Request(92, 0, size)
2308+ if p == nil {
2309+ return 0
2310+ }
2311+ off := 0
2312+ binary.LittleEndian.PutUint32(p[off:], uint32(cmap))
2313+ off += 4
2314+ binary.LittleEndian.PutUint16(p[off:], uint16(len(name)))
2315+ off += 2
2316+ off += 2
2317+ copy(p[off:], name)
2318+ off += len(name)
2319+ return seq
2320+}
2321+
2322+func CreateCursor(b *xturbo.Buf, cid Cursor, source Pixmap, mask Pixmap, foreRed uint16, foreGreen uint16, foreBlue uint16, backRed uint16, backGreen uint16, backBlue uint16, x uint16, y uint16) xturbo.Seq {
2323+ p, seq := b.Request(93, 0, 28)
2324+ if p == nil {
2325+ return 0
2326+ }
2327+ binary.LittleEndian.PutUint32(p[0:], uint32(cid))
2328+ binary.LittleEndian.PutUint32(p[4:], uint32(source))
2329+ binary.LittleEndian.PutUint32(p[8:], uint32(mask))
2330+ binary.LittleEndian.PutUint16(p[12:], uint16(foreRed))
2331+ binary.LittleEndian.PutUint16(p[14:], uint16(foreGreen))
2332+ binary.LittleEndian.PutUint16(p[16:], uint16(foreBlue))
2333+ binary.LittleEndian.PutUint16(p[18:], uint16(backRed))
2334+ binary.LittleEndian.PutUint16(p[20:], uint16(backGreen))
2335+ binary.LittleEndian.PutUint16(p[22:], uint16(backBlue))
2336+ binary.LittleEndian.PutUint16(p[24:], uint16(x))
2337+ binary.LittleEndian.PutUint16(p[26:], uint16(y))
2338+ return seq
2339+}
2340+
2341+func CreateGlyphCursor(b *xturbo.Buf, cid Cursor, sourceFont Font, maskFont Font, sourceChar uint16, maskChar uint16, foreRed uint16, foreGreen uint16, foreBlue uint16, backRed uint16, backGreen uint16, backBlue uint16) xturbo.Seq {
2342+ p, seq := b.Request(94, 0, 28)
2343+ if p == nil {
2344+ return 0
2345+ }
2346+ binary.LittleEndian.PutUint32(p[0:], uint32(cid))
2347+ binary.LittleEndian.PutUint32(p[4:], uint32(sourceFont))
2348+ binary.LittleEndian.PutUint32(p[8:], uint32(maskFont))
2349+ binary.LittleEndian.PutUint16(p[12:], uint16(sourceChar))
2350+ binary.LittleEndian.PutUint16(p[14:], uint16(maskChar))
2351+ binary.LittleEndian.PutUint16(p[16:], uint16(foreRed))
2352+ binary.LittleEndian.PutUint16(p[18:], uint16(foreGreen))
2353+ binary.LittleEndian.PutUint16(p[20:], uint16(foreBlue))
2354+ binary.LittleEndian.PutUint16(p[22:], uint16(backRed))
2355+ binary.LittleEndian.PutUint16(p[24:], uint16(backGreen))
2356+ binary.LittleEndian.PutUint16(p[26:], uint16(backBlue))
2357+ return seq
2358+}
2359+
2360+func FreeCursor(b *xturbo.Buf, cursor Cursor) xturbo.Seq {
2361+ p, seq := b.Request(95, 0, 4)
2362+ if p == nil {
2363+ return 0
2364+ }
2365+ binary.LittleEndian.PutUint32(p[0:], uint32(cursor))
2366+ return seq
2367+}
2368+
2369+func RecolorCursor(b *xturbo.Buf, cursor Cursor, foreRed uint16, foreGreen uint16, foreBlue uint16, backRed uint16, backGreen uint16, backBlue uint16) xturbo.Seq {
2370+ p, seq := b.Request(96, 0, 16)
2371+ if p == nil {
2372+ return 0
2373+ }
2374+ binary.LittleEndian.PutUint32(p[0:], uint32(cursor))
2375+ binary.LittleEndian.PutUint16(p[4:], uint16(foreRed))
2376+ binary.LittleEndian.PutUint16(p[6:], uint16(foreGreen))
2377+ binary.LittleEndian.PutUint16(p[8:], uint16(foreBlue))
2378+ binary.LittleEndian.PutUint16(p[10:], uint16(backRed))
2379+ binary.LittleEndian.PutUint16(p[12:], uint16(backGreen))
2380+ binary.LittleEndian.PutUint16(p[14:], uint16(backBlue))
2381+ return seq
2382+}
2383+
2384+func QueryBestSize(b *xturbo.Buf, class QueryShapeOf, drawable Drawable, width uint16, height uint16) xturbo.Seq {
2385+ p, seq := b.Request(97, uint8(int(class)), 8)
2386+ if p == nil {
2387+ return 0
2388+ }
2389+ binary.LittleEndian.PutUint32(p[0:], uint32(drawable))
2390+ binary.LittleEndian.PutUint16(p[4:], uint16(width))
2391+ binary.LittleEndian.PutUint16(p[6:], uint16(height))
2392+ return seq
2393+}
2394+
2395+func QueryExtension(b *xturbo.Buf, name string) xturbo.Seq {
2396+ if uint64(len(name)) > 65535 {
2397+ b.Fail(xturbo.ErrBadLength)
2398+ return 0
2399+ }
2400+ size := 0
2401+ size += 2
2402+ size += 2
2403+ size += len(name) * 1
2404+ size = (size + 3) &^ 3
2405+ p, seq := b.Request(98, 0, size)
2406+ if p == nil {
2407+ return 0
2408+ }
2409+ off := 0
2410+ binary.LittleEndian.PutUint16(p[off:], uint16(len(name)))
2411+ off += 2
2412+ off += 2
2413+ copy(p[off:], name)
2414+ off += len(name)
2415+ return seq
2416+}
2417+
2418+func ListExtensions(b *xturbo.Buf) xturbo.Seq {
2419+ p, seq := b.Request(99, 0, 0)
2420+ if p == nil {
2421+ return 0
2422+ }
2423+ return seq
2424+}
2425+
2426+func ChangeKeyboardMapping(b *xturbo.Buf, keycodeCount uint8, firstKeycode Keycode, keysymsPerKeycode uint8, keysyms []Keysym) xturbo.Seq {
2427+ if len(keysyms) != (int(keycodeCount) * int(keysymsPerKeycode)) {
2428+ b.Fail(xturbo.ErrBadLength)
2429+ return 0
2430+ }
2431+ size := 0
2432+ size += 1
2433+ size += 1
2434+ size += 2
2435+ size += len(keysyms) * 4
2436+ size = (size + 3) &^ 3
2437+ p, seq := b.Request(100, uint8(int(keycodeCount)), size)
2438+ if p == nil {
2439+ return 0
2440+ }
2441+ off := 0
2442+ p[off:][0] = byte(firstKeycode)
2443+ off += 1
2444+ p[off:][0] = byte(keysymsPerKeycode)
2445+ off += 1
2446+ off += 2
2447+ for i := range keysyms {
2448+ binary.LittleEndian.PutUint32(p[off:], uint32(keysyms[i]))
2449+ off += 4
2450+ }
2451+ return seq
2452+}
2453+
2454+func GetKeyboardMapping(b *xturbo.Buf, firstKeycode Keycode, count uint8) xturbo.Seq {
2455+ p, seq := b.Request(101, 0, 4)
2456+ if p == nil {
2457+ return 0
2458+ }
2459+ p[0:][0] = byte(firstKeycode)
2460+ p[1:][0] = byte(count)
2461+ return seq
2462+}
2463+
2464+type ChangeKeyboardControlValues struct {
2465+ Mask Kb
2466+ KeyClickPercent int32
2467+ BellPercent int32
2468+ BellPitch int32
2469+ BellDuration int32
2470+ Led uint32
2471+ LedMode LedMode
2472+ Key Keycode32
2473+ AutoRepeatMode AutoRepeatMode
2474+}
2475+
2476+func (v *ChangeKeyboardControlValues) SetKeyClickPercent(x int32) *ChangeKeyboardControlValues {
2477+ v.Mask |= KbKeyClickPercent
2478+ v.KeyClickPercent = x
2479+ return v
2480+}
2481+func (v *ChangeKeyboardControlValues) SetBellPercent(x int32) *ChangeKeyboardControlValues {
2482+ v.Mask |= KbBellPercent
2483+ v.BellPercent = x
2484+ return v
2485+}
2486+func (v *ChangeKeyboardControlValues) SetBellPitch(x int32) *ChangeKeyboardControlValues {
2487+ v.Mask |= KbBellPitch
2488+ v.BellPitch = x
2489+ return v
2490+}
2491+func (v *ChangeKeyboardControlValues) SetBellDuration(x int32) *ChangeKeyboardControlValues {
2492+ v.Mask |= KbBellDuration
2493+ v.BellDuration = x
2494+ return v
2495+}
2496+func (v *ChangeKeyboardControlValues) SetLed(x uint32) *ChangeKeyboardControlValues {
2497+ v.Mask |= KbLed
2498+ v.Led = x
2499+ return v
2500+}
2501+func (v *ChangeKeyboardControlValues) SetLedMode(x LedMode) *ChangeKeyboardControlValues {
2502+ v.Mask |= KbLedMode
2503+ v.LedMode = x
2504+ return v
2505+}
2506+func (v *ChangeKeyboardControlValues) SetKey(x Keycode32) *ChangeKeyboardControlValues {
2507+ v.Mask |= KbKey
2508+ v.Key = x
2509+ return v
2510+}
2511+func (v *ChangeKeyboardControlValues) SetAutoRepeatMode(x AutoRepeatMode) *ChangeKeyboardControlValues {
2512+ v.Mask |= KbAutoRepeatMode
2513+ v.AutoRepeatMode = x
2514+ return v
2515+}
2516+func ChangeKeyboardControl(b *xturbo.Buf, v *ChangeKeyboardControlValues) xturbo.Seq {
2517+ p, seq := b.Request(102, 0, 4+4*bits.OnesCount32(uint32(v.Mask)))
2518+ if p == nil {
2519+ return 0
2520+ }
2521+ binary.LittleEndian.PutUint32(p[0:], uint32(v.Mask))
2522+ off := 4
2523+ if v.Mask&KbKeyClickPercent != 0 {
2524+ binary.LittleEndian.PutUint32(p[off:], uint32(v.KeyClickPercent))
2525+ off += 4
2526+ }
2527+ if v.Mask&KbBellPercent != 0 {
2528+ binary.LittleEndian.PutUint32(p[off:], uint32(v.BellPercent))
2529+ off += 4
2530+ }
2531+ if v.Mask&KbBellPitch != 0 {
2532+ binary.LittleEndian.PutUint32(p[off:], uint32(v.BellPitch))
2533+ off += 4
2534+ }
2535+ if v.Mask&KbBellDuration != 0 {
2536+ binary.LittleEndian.PutUint32(p[off:], uint32(v.BellDuration))
2537+ off += 4
2538+ }
2539+ if v.Mask&KbLed != 0 {
2540+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Led))
2541+ off += 4
2542+ }
2543+ if v.Mask&KbLedMode != 0 {
2544+ binary.LittleEndian.PutUint32(p[off:], uint32(v.LedMode))
2545+ off += 4
2546+ }
2547+ if v.Mask&KbKey != 0 {
2548+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Key))
2549+ off += 4
2550+ }
2551+ if v.Mask&KbAutoRepeatMode != 0 {
2552+ binary.LittleEndian.PutUint32(p[off:], uint32(v.AutoRepeatMode))
2553+ off += 4
2554+ }
2555+ _ = off
2556+ return seq
2557+}
2558+
2559+func GetKeyboardControl(b *xturbo.Buf) xturbo.Seq {
2560+ p, seq := b.Request(103, 0, 0)
2561+ if p == nil {
2562+ return 0
2563+ }
2564+ return seq
2565+}
2566+
2567+func Bell(b *xturbo.Buf, percent int8) xturbo.Seq {
2568+ p, seq := b.Request(104, uint8(int(percent)), 0)
2569+ if p == nil {
2570+ return 0
2571+ }
2572+ return seq
2573+}
2574+
2575+func ChangePointerControl(b *xturbo.Buf, accelerationNumerator int16, accelerationDenominator int16, threshold int16, doAcceleration bool, doThreshold bool) xturbo.Seq {
2576+ p, seq := b.Request(105, 0, 8)
2577+ if p == nil {
2578+ return 0
2579+ }
2580+ binary.LittleEndian.PutUint16(p[0:], uint16(accelerationNumerator))
2581+ binary.LittleEndian.PutUint16(p[2:], uint16(accelerationDenominator))
2582+ binary.LittleEndian.PutUint16(p[4:], uint16(threshold))
2583+ if doAcceleration {
2584+ p[6:][0] = 1
2585+ } else {
2586+ p[6:][0] = 0
2587+ }
2588+ if doThreshold {
2589+ p[7:][0] = 1
2590+ } else {
2591+ p[7:][0] = 0
2592+ }
2593+ return seq
2594+}
2595+
2596+func GetPointerControl(b *xturbo.Buf) xturbo.Seq {
2597+ p, seq := b.Request(106, 0, 0)
2598+ if p == nil {
2599+ return 0
2600+ }
2601+ return seq
2602+}
2603+
2604+func SetScreenSaver(b *xturbo.Buf, timeout int16, interval int16, preferBlanking Blanking, allowExposures Exposures) xturbo.Seq {
2605+ p, seq := b.Request(107, 0, 8)
2606+ if p == nil {
2607+ return 0
2608+ }
2609+ binary.LittleEndian.PutUint16(p[0:], uint16(timeout))
2610+ binary.LittleEndian.PutUint16(p[2:], uint16(interval))
2611+ p[4:][0] = byte(preferBlanking)
2612+ p[5:][0] = byte(allowExposures)
2613+ return seq
2614+}
2615+
2616+func GetScreenSaver(b *xturbo.Buf) xturbo.Seq {
2617+ p, seq := b.Request(108, 0, 0)
2618+ if p == nil {
2619+ return 0
2620+ }
2621+ return seq
2622+}
2623+
2624+func ChangeHosts(b *xturbo.Buf, mode HostMode, family Family, address []byte) xturbo.Seq {
2625+ if uint64(len(address)) > 65535 {
2626+ b.Fail(xturbo.ErrBadLength)
2627+ return 0
2628+ }
2629+ size := 0
2630+ size += 1
2631+ size += 1
2632+ size += 2
2633+ size += len(address) * 1
2634+ size = (size + 3) &^ 3
2635+ p, seq := b.Request(109, uint8(int(mode)), size)
2636+ if p == nil {
2637+ return 0
2638+ }
2639+ off := 0
2640+ p[off:][0] = byte(family)
2641+ off += 1
2642+ off += 1
2643+ binary.LittleEndian.PutUint16(p[off:], uint16(len(address)))
2644+ off += 2
2645+ copy(p[off:], address)
2646+ off += len(address)
2647+ return seq
2648+}
2649+
2650+func ListHosts(b *xturbo.Buf) xturbo.Seq {
2651+ p, seq := b.Request(110, 0, 0)
2652+ if p == nil {
2653+ return 0
2654+ }
2655+ return seq
2656+}
2657+
2658+func SetAccessControl(b *xturbo.Buf, mode AccessControl) xturbo.Seq {
2659+ p, seq := b.Request(111, uint8(int(mode)), 0)
2660+ if p == nil {
2661+ return 0
2662+ }
2663+ return seq
2664+}
2665+
2666+func SetCloseDownMode(b *xturbo.Buf, mode CloseDown) xturbo.Seq {
2667+ p, seq := b.Request(112, uint8(int(mode)), 0)
2668+ if p == nil {
2669+ return 0
2670+ }
2671+ return seq
2672+}
2673+
2674+func KillClient(b *xturbo.Buf, resource uint32) xturbo.Seq {
2675+ p, seq := b.Request(113, 0, 4)
2676+ if p == nil {
2677+ return 0
2678+ }
2679+ binary.LittleEndian.PutUint32(p[0:], uint32(resource))
2680+ return seq
2681+}
2682+
2683+func RotateProperties(b *xturbo.Buf, window Window, delta int16, atoms []Atom) xturbo.Seq {
2684+ if uint64(len(atoms)) > 65535 {
2685+ b.Fail(xturbo.ErrBadLength)
2686+ return 0
2687+ }
2688+ size := 0
2689+ size += 4
2690+ size += 2
2691+ size += 2
2692+ size += len(atoms) * 4
2693+ size = (size + 3) &^ 3
2694+ p, seq := b.Request(114, 0, size)
2695+ if p == nil {
2696+ return 0
2697+ }
2698+ off := 0
2699+ binary.LittleEndian.PutUint32(p[off:], uint32(window))
2700+ off += 4
2701+ binary.LittleEndian.PutUint16(p[off:], uint16(len(atoms)))
2702+ off += 2
2703+ binary.LittleEndian.PutUint16(p[off:], uint16(delta))
2704+ off += 2
2705+ for i := range atoms {
2706+ binary.LittleEndian.PutUint32(p[off:], uint32(atoms[i]))
2707+ off += 4
2708+ }
2709+ return seq
2710+}
2711+
2712+func ForceScreenSaver(b *xturbo.Buf, mode ScreenSaver) xturbo.Seq {
2713+ p, seq := b.Request(115, uint8(int(mode)), 0)
2714+ if p == nil {
2715+ return 0
2716+ }
2717+ return seq
2718+}
2719+
2720+func SetPointerMapping(b *xturbo.Buf, map_ []byte) xturbo.Seq {
2721+ if len(map_) > 255 {
2722+ b.Fail(xturbo.ErrBadLength)
2723+ return 0
2724+ }
2725+ size := 0
2726+ size += len(map_) * 1
2727+ size = (size + 3) &^ 3
2728+ p, seq := b.Request(116, uint8(len(map_)), size)
2729+ if p == nil {
2730+ return 0
2731+ }
2732+ off := 0
2733+ copy(p[off:], map_)
2734+ off += len(map_)
2735+ return seq
2736+}
2737+
2738+func GetPointerMapping(b *xturbo.Buf) xturbo.Seq {
2739+ p, seq := b.Request(117, 0, 0)
2740+ if p == nil {
2741+ return 0
2742+ }
2743+ return seq
2744+}
2745+
2746+func SetModifierMapping(b *xturbo.Buf, keycodesPerModifier uint8, keycodes []Keycode) xturbo.Seq {
2747+ if len(keycodes) != (int(keycodesPerModifier) * 8) {
2748+ b.Fail(xturbo.ErrBadLength)
2749+ return 0
2750+ }
2751+ size := 0
2752+ size += len(keycodes) * 1
2753+ size = (size + 3) &^ 3
2754+ p, seq := b.Request(118, uint8(int(keycodesPerModifier)), size)
2755+ if p == nil {
2756+ return 0
2757+ }
2758+ off := 0
2759+ for i := range keycodes {
2760+ p[off:][0] = byte(keycodes[i])
2761+ off += 1
2762+ }
2763+ return seq
2764+}
2765+
2766+func GetModifierMapping(b *xturbo.Buf) xturbo.Seq {
2767+ p, seq := b.Request(119, 0, 0)
2768+ if p == nil {
2769+ return 0
2770+ }
2771+ return seq
2772+}
2773+
2774+func NoOperation(b *xturbo.Buf) xturbo.Seq {
2775+ p, seq := b.Request(127, 0, 0)
2776+ if p == nil {
2777+ return 0
2778+ }
2779+ return seq
2780+}
A xproto/requests_test.go +83 -0
@@ -0,0 +1,83 @@
1+package xproto
2+
3+import (
4+ "bnema.dev/xturbo"
5+ "testing"
6+)
7+
8+func BenchmarkConfigureWindow(b *testing.B) {
9+ buf := xturbo.NewBuf(0)
10+ var v ConfigureWindowValues
11+ v.SetX(-1).SetY(-2).SetWidth(800).SetHeight(600).SetBorderWidth(1).SetSibling(2).SetStackMode(StackModeAbove)
12+ batch := 0
13+ b.ReportAllocs()
14+ b.ResetTimer()
15+ for i := 0; i < b.N; i++ {
16+ if batch == 60000 {
17+ b.StopTimer()
18+ buf = xturbo.NewBuf(0)
19+ batch = 0
20+ b.StartTimer()
21+ }
22+ buf.Reset()
23+ ConfigureWindow(buf, 1, &v)
24+ batch++
25+ }
26+ if buf.Err() != nil {
27+ b.Fatal(buf.Err())
28+ }
29+}
30+
31+func BenchmarkMapWindow(b *testing.B) {
32+ buf := xturbo.NewBuf(0)
33+ batch := 0
34+ b.ReportAllocs()
35+ b.ResetTimer()
36+ for i := 0; i < b.N; i++ {
37+ if batch == 60000 {
38+ b.StopTimer()
39+ buf = xturbo.NewBuf(0)
40+ batch = 0
41+ b.StartTimer()
42+ }
43+ buf.Reset()
44+ MapWindow(buf, 1)
45+ batch++
46+ }
47+}
48+
49+func BenchmarkInternAtom(b *testing.B) {
50+ buf := xturbo.NewBuf(0)
51+ batch := 0
52+ b.ReportAllocs()
53+ b.ResetTimer()
54+ for i := 0; i < b.N; i++ {
55+ if batch == 60000 {
56+ b.StopTimer()
57+ buf = xturbo.NewBuf(0)
58+ batch = 0
59+ b.StartTimer()
60+ }
61+ buf.Reset()
62+ InternAtom(buf, false, "WM_CLASS")
63+ batch++
64+ }
65+}
66+func BenchmarkChangeProperty4KiB(b *testing.B) {
67+ buf := xturbo.NewBuf(0)
68+ data := make([]byte, 4096)
69+ batch := 0
70+ b.ReportAllocs()
71+ b.ResetTimer()
72+ for i := 0; i < b.N; i++ {
73+ if batch == 60000 {
74+ b.StopTimer()
75+ buf = xturbo.NewBuf(0)
76+ batch = 0
77+ b.StartTimer()
78+ }
79+ buf.Reset()
80+ ChangeProperty(buf, 0, 1, 1, 1, 8, 4096, data)
81+ batch++
82+ }
83+}
A xproto/sizes_test.go +293 -0
@@ -0,0 +1,293 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xproto
3+
4+import "testing"
5+
6+func TestWireSizes(t *testing.T) {
7+ if Char2bSize != 2 {
8+ t.Errorf("Char2b fixed prefix = %d", Char2bSize)
9+ }
10+ if PointSize != 4 {
11+ t.Errorf("Point fixed prefix = %d", PointSize)
12+ }
13+ if RectangleSize != 8 {
14+ t.Errorf("Rectangle fixed prefix = %d", RectangleSize)
15+ }
16+ if ArcSize != 12 {
17+ t.Errorf("Arc fixed prefix = %d", ArcSize)
18+ }
19+ if FormatSize != 8 {
20+ t.Errorf("Format fixed prefix = %d", FormatSize)
21+ }
22+ if VisualtypeSize != 24 {
23+ t.Errorf("Visualtype fixed prefix = %d", VisualtypeSize)
24+ }
25+ if DepthSize != 8 {
26+ t.Errorf("Depth fixed prefix = %d", DepthSize)
27+ }
28+ if ScreenSize != 40 {
29+ t.Errorf("Screen fixed prefix = %d", ScreenSize)
30+ }
31+ if SetupRequestSize != 12 {
32+ t.Errorf("SetupRequest fixed prefix = %d", SetupRequestSize)
33+ }
34+ if SetupFailedSize != 8 {
35+ t.Errorf("SetupFailed fixed prefix = %d", SetupFailedSize)
36+ }
37+ if SetupAuthenticateSize != 8 {
38+ t.Errorf("SetupAuthenticate fixed prefix = %d", SetupAuthenticateSize)
39+ }
40+ if SetupSize != 40 {
41+ t.Errorf("Setup fixed prefix = %d", SetupSize)
42+ }
43+ if ClientMessageDataSize != 20 {
44+ t.Errorf("ClientMessageData fixed prefix = %d", ClientMessageDataSize)
45+ }
46+ if TimecoordSize != 8 {
47+ t.Errorf("Timecoord fixed prefix = %d", TimecoordSize)
48+ }
49+ if FontpropSize != 8 {
50+ t.Errorf("Fontprop fixed prefix = %d", FontpropSize)
51+ }
52+ if CharinfoSize != 12 {
53+ t.Errorf("Charinfo fixed prefix = %d", CharinfoSize)
54+ }
55+ if StrSize != 1 {
56+ t.Errorf("Str fixed prefix = %d", StrSize)
57+ }
58+ if SegmentSize != 8 {
59+ t.Errorf("Segment fixed prefix = %d", SegmentSize)
60+ }
61+ if ColoritemSize != 12 {
62+ t.Errorf("Coloritem fixed prefix = %d", ColoritemSize)
63+ }
64+ if RgbSize != 8 {
65+ t.Errorf("Rgb fixed prefix = %d", RgbSize)
66+ }
67+ if HostSize != 4 {
68+ t.Errorf("Host fixed prefix = %d", HostSize)
69+ }
70+ if got := 32; got != 32 {
71+ t.Errorf("event KeyPress fixed size = %d", got)
72+ }
73+ if got := 32; got != 32 {
74+ t.Errorf("event KeyRelease fixed size = %d", got)
75+ }
76+ if got := 32; got != 32 {
77+ t.Errorf("event ButtonPress fixed size = %d", got)
78+ }
79+ if got := 32; got != 32 {
80+ t.Errorf("event ButtonRelease fixed size = %d", got)
81+ }
82+ if got := 32; got != 32 {
83+ t.Errorf("event MotionNotify fixed size = %d", got)
84+ }
85+ if got := 32; got != 32 {
86+ t.Errorf("event EnterNotify fixed size = %d", got)
87+ }
88+ if got := 32; got != 32 {
89+ t.Errorf("event LeaveNotify fixed size = %d", got)
90+ }
91+ if got := 32; got != 32 {
92+ t.Errorf("event FocusIn fixed size = %d", got)
93+ }
94+ if got := 32; got != 32 {
95+ t.Errorf("event FocusOut fixed size = %d", got)
96+ }
97+ if got := 32; got != 32 {
98+ t.Errorf("event KeymapNotify fixed size = %d", got)
99+ }
100+ if got := 32; got != 32 {
101+ t.Errorf("event Expose fixed size = %d", got)
102+ }
103+ if got := 32; got != 32 {
104+ t.Errorf("event GraphicsExposure fixed size = %d", got)
105+ }
106+ if got := 32; got != 32 {
107+ t.Errorf("event NoExposure fixed size = %d", got)
108+ }
109+ if got := 32; got != 32 {
110+ t.Errorf("event VisibilityNotify fixed size = %d", got)
111+ }
112+ if got := 32; got != 32 {
113+ t.Errorf("event CreateNotify fixed size = %d", got)
114+ }
115+ if got := 32; got != 32 {
116+ t.Errorf("event DestroyNotify fixed size = %d", got)
117+ }
118+ if got := 32; got != 32 {
119+ t.Errorf("event UnmapNotify fixed size = %d", got)
120+ }
121+ if got := 32; got != 32 {
122+ t.Errorf("event MapNotify fixed size = %d", got)
123+ }
124+ if got := 32; got != 32 {
125+ t.Errorf("event MapRequest fixed size = %d", got)
126+ }
127+ if got := 32; got != 32 {
128+ t.Errorf("event ReparentNotify fixed size = %d", got)
129+ }
130+ if got := 32; got != 32 {
131+ t.Errorf("event ConfigureNotify fixed size = %d", got)
132+ }
133+ if got := 32; got != 32 {
134+ t.Errorf("event ConfigureRequest fixed size = %d", got)
135+ }
136+ if got := 32; got != 32 {
137+ t.Errorf("event GravityNotify fixed size = %d", got)
138+ }
139+ if got := 32; got != 32 {
140+ t.Errorf("event ResizeRequest fixed size = %d", got)
141+ }
142+ if got := 32; got != 32 {
143+ t.Errorf("event CirculateNotify fixed size = %d", got)
144+ }
145+ if got := 32; got != 32 {
146+ t.Errorf("event CirculateRequest fixed size = %d", got)
147+ }
148+ if got := 32; got != 32 {
149+ t.Errorf("event PropertyNotify fixed size = %d", got)
150+ }
151+ if got := 32; got != 32 {
152+ t.Errorf("event SelectionClear fixed size = %d", got)
153+ }
154+ if got := 32; got != 32 {
155+ t.Errorf("event SelectionRequest fixed size = %d", got)
156+ }
157+ if got := 32; got != 32 {
158+ t.Errorf("event SelectionNotify fixed size = %d", got)
159+ }
160+ if got := 32; got != 32 {
161+ t.Errorf("event ColormapNotify fixed size = %d", got)
162+ }
163+ if got := 32; got != 32 {
164+ t.Errorf("event ClientMessage fixed size = %d", got)
165+ }
166+ if got := 32; got != 32 {
167+ t.Errorf("event MappingNotify fixed size = %d", got)
168+ }
169+ if got := 32; got != 32 {
170+ t.Errorf("event GeGeneric fixed size = %d", got)
171+ }
172+ if got := 44; got != 44 {
173+ t.Errorf("reply GetWindowAttributes fixed size = %d", got)
174+ }
175+ if got := 32; got != 32 {
176+ t.Errorf("reply GetGeometry fixed size = %d", got)
177+ }
178+ if got := 32; got != 32 {
179+ t.Errorf("reply QueryTree fixed size = %d", got)
180+ }
181+ if got := 32; got != 32 {
182+ t.Errorf("reply InternAtom fixed size = %d", got)
183+ }
184+ if got := 32; got != 32 {
185+ t.Errorf("reply GetAtomName fixed size = %d", got)
186+ }
187+ if got := 32; got != 32 {
188+ t.Errorf("reply GetProperty fixed size = %d", got)
189+ }
190+ if got := 32; got != 32 {
191+ t.Errorf("reply ListProperties fixed size = %d", got)
192+ }
193+ if got := 32; got != 32 {
194+ t.Errorf("reply GetSelectionOwner fixed size = %d", got)
195+ }
196+ if got := 32; got != 32 {
197+ t.Errorf("reply GrabPointer fixed size = %d", got)
198+ }
199+ if got := 32; got != 32 {
200+ t.Errorf("reply GrabKeyboard fixed size = %d", got)
201+ }
202+ if got := 32; got != 32 {
203+ t.Errorf("reply QueryPointer fixed size = %d", got)
204+ }
205+ if got := 32; got != 32 {
206+ t.Errorf("reply GetMotionEvents fixed size = %d", got)
207+ }
208+ if got := 32; got != 32 {
209+ t.Errorf("reply TranslateCoordinates fixed size = %d", got)
210+ }
211+ if got := 32; got != 32 {
212+ t.Errorf("reply GetInputFocus fixed size = %d", got)
213+ }
214+ if got := 40; got != 40 {
215+ t.Errorf("reply QueryKeymap fixed size = %d", got)
216+ }
217+ if got := 60; got != 60 {
218+ t.Errorf("reply QueryFont fixed size = %d", got)
219+ }
220+ if got := 32; got != 32 {
221+ t.Errorf("reply QueryTextExtents fixed size = %d", got)
222+ }
223+ if got := 32; got != 32 {
224+ t.Errorf("reply ListFonts fixed size = %d", got)
225+ }
226+ if got := 60; got != 60 {
227+ t.Errorf("reply ListFontsWithInfo fixed size = %d", got)
228+ }
229+ if got := 32; got != 32 {
230+ t.Errorf("reply GetFontPath fixed size = %d", got)
231+ }
232+ if got := 32; got != 32 {
233+ t.Errorf("reply GetImage fixed size = %d", got)
234+ }
235+ if got := 32; got != 32 {
236+ t.Errorf("reply ListInstalledColormaps fixed size = %d", got)
237+ }
238+ if got := 32; got != 32 {
239+ t.Errorf("reply AllocColor fixed size = %d", got)
240+ }
241+ if got := 32; got != 32 {
242+ t.Errorf("reply AllocNamedColor fixed size = %d", got)
243+ }
244+ if got := 32; got != 32 {
245+ t.Errorf("reply AllocColorCells fixed size = %d", got)
246+ }
247+ if got := 32; got != 32 {
248+ t.Errorf("reply AllocColorPlanes fixed size = %d", got)
249+ }
250+ if got := 32; got != 32 {
251+ t.Errorf("reply QueryColors fixed size = %d", got)
252+ }
253+ if got := 32; got != 32 {
254+ t.Errorf("reply LookupColor fixed size = %d", got)
255+ }
256+ if got := 32; got != 32 {
257+ t.Errorf("reply QueryBestSize fixed size = %d", got)
258+ }
259+ if got := 32; got != 32 {
260+ t.Errorf("reply QueryExtension fixed size = %d", got)
261+ }
262+ if got := 32; got != 32 {
263+ t.Errorf("reply ListExtensions fixed size = %d", got)
264+ }
265+ if got := 32; got != 32 {
266+ t.Errorf("reply GetKeyboardMapping fixed size = %d", got)
267+ }
268+ if got := 52; got != 52 {
269+ t.Errorf("reply GetKeyboardControl fixed size = %d", got)
270+ }
271+ if got := 32; got != 32 {
272+ t.Errorf("reply GetPointerControl fixed size = %d", got)
273+ }
274+ if got := 32; got != 32 {
275+ t.Errorf("reply GetScreenSaver fixed size = %d", got)
276+ }
277+ if got := 32; got != 32 {
278+ t.Errorf("reply ListHosts fixed size = %d", got)
279+ }
280+ if got := 32; got != 32 {
281+ t.Errorf("reply SetPointerMapping fixed size = %d", got)
282+ }
283+ if got := 32; got != 32 {
284+ t.Errorf("reply GetPointerMapping fixed size = %d", got)
285+ }
286+ if got := 32; got != 32 {
287+ t.Errorf("reply SetModifierMapping fixed size = %d", got)
288+ }
289+ if got := 32; got != 32 {
290+ t.Errorf("reply GetModifierMapping fixed size = %d", got)
291+ }
292+
293+}
A xproto/types_generated.go +1353 -0
@@ -0,0 +1,1353 @@
1+// Code generated by xtgen; DO NOT EDIT.
2+package xproto
3+
4+import "encoding/binary"
5+
6+type Char2b struct {
7+ Byte1 uint8
8+ Byte2 uint8
9+}
10+
11+const Char2bSize = 2
12+
13+func (v Char2b) Put(p []byte) { clear(p[:2]); p[0:][0] = byte(v.Byte1); p[1:][0] = byte(v.Byte2) }
14+func GetChar2b(p []byte) (v Char2b) {
15+ _ = p[1]
16+ v.Byte1 = uint8(p[0:][0])
17+ v.Byte2 = uint8(p[1:][0])
18+ return
19+}
20+
21+type Window uint32
22+
23+type Pixmap uint32
24+
25+type Cursor uint32
26+
27+type Font uint32
28+
29+type Gcontext uint32
30+
31+type Colormap uint32
32+
33+type Atom uint32
34+
35+type Drawable uint32
36+
37+type Fontable uint32
38+
39+type Bool32 uint32
40+
41+type Visualid uint32
42+
43+type Timestamp uint32
44+
45+type Keysym uint32
46+
47+type Keycode uint8
48+
49+type Keycode32 uint32
50+
51+type Button uint8
52+
53+type Point struct {
54+ X int16
55+ Y int16
56+}
57+
58+const PointSize = 4
59+
60+func (v Point) Put(p []byte) {
61+ clear(p[:4])
62+ binary.LittleEndian.PutUint16(p[0:], uint16(v.X))
63+ binary.LittleEndian.PutUint16(p[2:], uint16(v.Y))
64+}
65+func GetPoint(p []byte) (v Point) {
66+ _ = p[3]
67+ v.X = int16(binary.LittleEndian.Uint16(p[0:]))
68+ v.Y = int16(binary.LittleEndian.Uint16(p[2:]))
69+ return
70+}
71+
72+type Rectangle struct {
73+ X int16
74+ Y int16
75+ Width uint16
76+ Height uint16
77+}
78+
79+const RectangleSize = 8
80+
81+func (v Rectangle) Put(p []byte) {
82+ clear(p[:8])
83+ binary.LittleEndian.PutUint16(p[0:], uint16(v.X))
84+ binary.LittleEndian.PutUint16(p[2:], uint16(v.Y))
85+ binary.LittleEndian.PutUint16(p[4:], uint16(v.Width))
86+ binary.LittleEndian.PutUint16(p[6:], uint16(v.Height))
87+}
88+func GetRectangle(p []byte) (v Rectangle) {
89+ _ = p[7]
90+ v.X = int16(binary.LittleEndian.Uint16(p[0:]))
91+ v.Y = int16(binary.LittleEndian.Uint16(p[2:]))
92+ v.Width = uint16(binary.LittleEndian.Uint16(p[4:]))
93+ v.Height = uint16(binary.LittleEndian.Uint16(p[6:]))
94+ return
95+}
96+
97+type Arc struct {
98+ X int16
99+ Y int16
100+ Width uint16
101+ Height uint16
102+ Angle1 int16
103+ Angle2 int16
104+}
105+
106+const ArcSize = 12
107+
108+func (v Arc) Put(p []byte) {
109+ clear(p[:12])
110+ binary.LittleEndian.PutUint16(p[0:], uint16(v.X))
111+ binary.LittleEndian.PutUint16(p[2:], uint16(v.Y))
112+ binary.LittleEndian.PutUint16(p[4:], uint16(v.Width))
113+ binary.LittleEndian.PutUint16(p[6:], uint16(v.Height))
114+ binary.LittleEndian.PutUint16(p[8:], uint16(v.Angle1))
115+ binary.LittleEndian.PutUint16(p[10:], uint16(v.Angle2))
116+}
117+func GetArc(p []byte) (v Arc) {
118+ _ = p[11]
119+ v.X = int16(binary.LittleEndian.Uint16(p[0:]))
120+ v.Y = int16(binary.LittleEndian.Uint16(p[2:]))
121+ v.Width = uint16(binary.LittleEndian.Uint16(p[4:]))
122+ v.Height = uint16(binary.LittleEndian.Uint16(p[6:]))
123+ v.Angle1 = int16(binary.LittleEndian.Uint16(p[8:]))
124+ v.Angle2 = int16(binary.LittleEndian.Uint16(p[10:]))
125+ return
126+}
127+
128+type Format struct {
129+ Depth uint8
130+ BitsPerPixel uint8
131+ ScanlinePad uint8
132+}
133+
134+const FormatSize = 8
135+
136+func (v Format) Put(p []byte) {
137+ clear(p[:8])
138+ p[0:][0] = byte(v.Depth)
139+ p[1:][0] = byte(v.BitsPerPixel)
140+ p[2:][0] = byte(v.ScanlinePad)
141+}
142+func GetFormat(p []byte) (v Format) {
143+ _ = p[7]
144+ v.Depth = uint8(p[0:][0])
145+ v.BitsPerPixel = uint8(p[1:][0])
146+ v.ScanlinePad = uint8(p[2:][0])
147+ return
148+}
149+
150+type Visualtype struct {
151+ VisualId Visualid
152+ Class VisualClass
153+ BitsPerRgbValue uint8
154+ ColormapEntries uint16
155+ RedMask uint32
156+ GreenMask uint32
157+ BlueMask uint32
158+}
159+
160+const VisualtypeSize = 24
161+
162+func (v Visualtype) Put(p []byte) {
163+ clear(p[:24])
164+ binary.LittleEndian.PutUint32(p[0:], uint32(v.VisualId))
165+ p[4:][0] = byte(v.Class)
166+ p[5:][0] = byte(v.BitsPerRgbValue)
167+ binary.LittleEndian.PutUint16(p[6:], uint16(v.ColormapEntries))
168+ binary.LittleEndian.PutUint32(p[8:], uint32(v.RedMask))
169+ binary.LittleEndian.PutUint32(p[12:], uint32(v.GreenMask))
170+ binary.LittleEndian.PutUint32(p[16:], uint32(v.BlueMask))
171+}
172+func GetVisualtype(p []byte) (v Visualtype) {
173+ _ = p[23]
174+ v.VisualId = Visualid(binary.LittleEndian.Uint32(p[0:]))
175+ v.Class = VisualClass(p[4:][0])
176+ v.BitsPerRgbValue = uint8(p[5:][0])
177+ v.ColormapEntries = uint16(binary.LittleEndian.Uint16(p[6:]))
178+ v.RedMask = uint32(binary.LittleEndian.Uint32(p[8:]))
179+ v.GreenMask = uint32(binary.LittleEndian.Uint32(p[12:]))
180+ v.BlueMask = uint32(binary.LittleEndian.Uint32(p[16:]))
181+ return
182+}
183+
184+type Depth struct {
185+ Depth uint8
186+ VisualsLen uint16
187+ Visuals []Visualtype
188+}
189+
190+const DepthSize = 8
191+
192+func (v Depth) Size() int {
193+ off := 0
194+ off += 1
195+ off += 1
196+ off += 2
197+ off += 4
198+ off += len(v.Visuals) * 24
199+ return off
200+}
201+func (v Depth) Put(p []byte) {
202+ off := 0
203+ p[off:][0] = byte(v.Depth)
204+ off += 1
205+ clear(p[off : off+1])
206+ off += 1
207+ binary.LittleEndian.PutUint16(p[off:], uint16(v.VisualsLen))
208+ off += 2
209+ clear(p[off : off+4])
210+ off += 4
211+ for i := range v.Visuals {
212+ v.Visuals[i].Put(p[off+i*24:])
213+ }
214+ off += len(v.Visuals) * 24
215+}
216+
217+type Screen struct {
218+ Root Window
219+ DefaultColormap Colormap
220+ WhitePixel uint32
221+ BlackPixel uint32
222+ CurrentInputMasks EventMask
223+ WidthInPixels uint16
224+ HeightInPixels uint16
225+ WidthInMillimeters uint16
226+ HeightInMillimeters uint16
227+ MinInstalledMaps uint16
228+ MaxInstalledMaps uint16
229+ RootVisual Visualid
230+ BackingStores BackingStore
231+ SaveUnders bool
232+ RootDepth uint8
233+ AllowedDepthsLen uint8
234+ AllowedDepths []Depth
235+}
236+
237+const ScreenSize = 40
238+
239+func (v Screen) Size() int {
240+ off := 0
241+ off += 4
242+ off += 4
243+ off += 4
244+ off += 4
245+ off += 4
246+ off += 2
247+ off += 2
248+ off += 2
249+ off += 2
250+ off += 2
251+ off += 2
252+ off += 4
253+ off += 1
254+ off += 1
255+ off += 1
256+ off += 1
257+ for i := range v.AllowedDepths {
258+ off += v.AllowedDepths[i].Size()
259+ }
260+ return off
261+}
262+func (v Screen) Put(p []byte) {
263+ off := 0
264+ binary.LittleEndian.PutUint32(p[off:], uint32(v.Root))
265+ off += 4
266+ binary.LittleEndian.PutUint32(p[off:], uint32(v.DefaultColormap))
267+ off += 4
268+ binary.LittleEndian.PutUint32(p[off:], uint32(v.WhitePixel))
269+ off += 4
270+ binary.LittleEndian.PutUint32(p[off:], uint32(v.BlackPixel))
271+ off += 4
272+ binary.LittleEndian.PutUint32(p[off:], uint32(v.CurrentInputMasks))
273+ off += 4
274+ binary.LittleEndian.PutUint16(p[off:], uint16(v.WidthInPixels))
275+ off += 2
276+ binary.LittleEndian.PutUint16(p[off:], uint16(v.HeightInPixels))
277+ off += 2
278+ binary.LittleEndian.PutUint16(p[off:], uint16(v.WidthInMillimeters))
279+ off += 2
280+ binary.LittleEndian.PutUint16(p[off:], uint16(v.HeightInMillimeters))
281+ off += 2
282+ binary.LittleEndian.PutUint16(p[off:], uint16(v.MinInstalledMaps))
283+ off += 2
284+ binary.LittleEndian.PutUint16(p[off:], uint16(v.MaxInstalledMaps))
285+ off += 2
286+ binary.LittleEndian.PutUint32(p[off:], uint32(v.RootVisual))
287+ off += 4
288+ p[off:][0] = byte(v.BackingStores)
289+ off += 1
290+ if v.SaveUnders {
291+ p[off:][0] = 1
292+ } else {
293+ p[off:][0] = 0
294+ }
295+ off += 1
296+ p[off:][0] = byte(v.RootDepth)
297+ off += 1
298+ p[off:][0] = byte(v.AllowedDepthsLen)
299+ off += 1
300+ for i := range v.AllowedDepths {
301+ v.AllowedDepths[i].Put(p[off:])
302+ off += v.AllowedDepths[i].Size()
303+ }
304+}
305+
306+type SetupRequest struct {
307+ ByteOrder uint8
308+ ProtocolMajorVersion uint16
309+ ProtocolMinorVersion uint16
310+ AuthorizationProtocolNameLen uint16
311+ AuthorizationProtocolDataLen uint16
312+ AuthorizationProtocolName string
313+ AuthorizationProtocolData string
314+}
315+
316+const SetupRequestSize = 12
317+
318+func (v SetupRequest) Size() int {
319+ off := 0
320+ off += 1
321+ off += 1
322+ off += 2
323+ off += 2
324+ off += 2
325+ off += 2
326+ off += 2
327+ off += len(v.AuthorizationProtocolName) * 1
328+ off = (off + 3) &^ 3
329+ off += len(v.AuthorizationProtocolData) * 1
330+ off = (off + 3) &^ 3
331+ return off
332+}
333+func (v SetupRequest) Put(p []byte) {
334+ off := 0
335+ p[off:][0] = byte(v.ByteOrder)
336+ off += 1
337+ clear(p[off : off+1])
338+ off += 1
339+ binary.LittleEndian.PutUint16(p[off:], uint16(v.ProtocolMajorVersion))
340+ off += 2
341+ binary.LittleEndian.PutUint16(p[off:], uint16(v.ProtocolMinorVersion))
342+ off += 2
343+ binary.LittleEndian.PutUint16(p[off:], uint16(v.AuthorizationProtocolNameLen))
344+ off += 2
345+ binary.LittleEndian.PutUint16(p[off:], uint16(v.AuthorizationProtocolDataLen))
346+ off += 2
347+ clear(p[off : off+2])
348+ off += 2
349+ for i := range v.AuthorizationProtocolName {
350+ p[off+i*1:][0] = byte(v.AuthorizationProtocolName[i])
351+ }
352+ off += len(v.AuthorizationProtocolName) * 1
353+ {
354+ next := (off + 3) &^ 3
355+ clear(p[off:next])
356+ off = next
357+ }
358+ for i := range v.AuthorizationProtocolData {
359+ p[off+i*1:][0] = byte(v.AuthorizationProtocolData[i])
360+ }
361+ off += len(v.AuthorizationProtocolData) * 1
362+ {
363+ next := (off + 3) &^ 3
364+ clear(p[off:next])
365+ off = next
366+ }
367+}
368+
369+type SetupFailed struct {
370+ Status uint8
371+ ReasonLen uint8
372+ ProtocolMajorVersion uint16
373+ ProtocolMinorVersion uint16
374+ Length uint16
375+ Reason string
376+}
377+
378+const SetupFailedSize = 8
379+
380+func (v SetupFailed) Size() int {
381+ off := 0
382+ off += 1
383+ off += 1
384+ off += 2
385+ off += 2
386+ off += 2
387+ off += len(v.Reason) * 1
388+ return off
389+}
390+func (v SetupFailed) Put(p []byte) {
391+ off := 0
392+ p[off:][0] = byte(v.Status)
393+ off += 1
394+ p[off:][0] = byte(v.ReasonLen)
395+ off += 1
396+ binary.LittleEndian.PutUint16(p[off:], uint16(v.ProtocolMajorVersion))
397+ off += 2
398+ binary.LittleEndian.PutUint16(p[off:], uint16(v.ProtocolMinorVersion))
399+ off += 2
400+ binary.LittleEndian.PutUint16(p[off:], uint16(v.Length))
401+ off += 2
402+ for i := range v.Reason {
403+ p[off+i*1:][0] = byte(v.Reason[i])
404+ }
405+ off += len(v.Reason) * 1
406+}
407+
408+type SetupAuthenticate struct {
409+ Status uint8
410+ Length uint16
411+ Reason string
412+}
413+
414+const SetupAuthenticateSize = 8
415+
416+func (v SetupAuthenticate) Size() int {
417+ off := 0
418+ off += 1
419+ off += 5
420+ off += 2
421+ off += len(v.Reason) * 1
422+ return off
423+}
424+func (v SetupAuthenticate) Put(p []byte) {
425+ off := 0
426+ p[off:][0] = byte(v.Status)
427+ off += 1
428+ clear(p[off : off+5])
429+ off += 5
430+ binary.LittleEndian.PutUint16(p[off:], uint16(v.Length))
431+ off += 2
432+ for i := range v.Reason {
433+ p[off+i*1:][0] = byte(v.Reason[i])
434+ }
435+ off += len(v.Reason) * 1
436+}
437+
438+type Setup struct {
439+ Status uint8
440+ ProtocolMajorVersion uint16
441+ ProtocolMinorVersion uint16
442+ Length uint16
443+ ReleaseNumber uint32
444+ ResourceIdBase uint32
445+ ResourceIdMask uint32
446+ MotionBufferSize uint32
447+ VendorLen uint16
448+ MaximumRequestLength uint16
449+ RootsLen uint8
450+ PixmapFormatsLen uint8
451+ ImageByteOrder ImageOrder
452+ BitmapFormatBitOrder ImageOrder
453+ BitmapFormatScanlineUnit uint8
454+ BitmapFormatScanlinePad uint8
455+ MinKeycode Keycode
456+ MaxKeycode Keycode
457+ Vendor string
458+ PixmapFormats []Format
459+ Roots []Screen
460+}
461+
462+const SetupSize = 40
463+
464+func (v Setup) Size() int {
465+ off := 0
466+ off += 1
467+ off += 1
468+ off += 2
469+ off += 2
470+ off += 2
471+ off += 4
472+ off += 4
473+ off += 4
474+ off += 4
475+ off += 2
476+ off += 2
477+ off += 1
478+ off += 1
479+ off += 1
480+ off += 1
481+ off += 1
482+ off += 1
483+ off += 1
484+ off += 1
485+ off += 4
486+ off += len(v.Vendor) * 1
487+ off = (off + 3) &^ 3
488+ off += len(v.PixmapFormats) * 8
489+ for i := range v.Roots {
490+ off += v.Roots[i].Size()
491+ }
492+ return off
493+}
494+func (v Setup) Put(p []byte) {
495+ off := 0
496+ p[off:][0] = byte(v.Status)
497+ off += 1
498+ clear(p[off : off+1])
499+ off += 1
500+ binary.LittleEndian.PutUint16(p[off:], uint16(v.ProtocolMajorVersion))
501+ off += 2
502+ binary.LittleEndian.PutUint16(p[off:], uint16(v.ProtocolMinorVersion))
503+ off += 2
504+ binary.LittleEndian.PutUint16(p[off:], uint16(v.Length))
505+ off += 2
506+ binary.LittleEndian.PutUint32(p[off:], uint32(v.ReleaseNumber))
507+ off += 4
508+ binary.LittleEndian.PutUint32(p[off:], uint32(v.ResourceIdBase))
509+ off += 4
510+ binary.LittleEndian.PutUint32(p[off:], uint32(v.ResourceIdMask))
511+ off += 4
512+ binary.LittleEndian.PutUint32(p[off:], uint32(v.MotionBufferSize))
513+ off += 4
514+ binary.LittleEndian.PutUint16(p[off:], uint16(v.VendorLen))
515+ off += 2
516+ binary.LittleEndian.PutUint16(p[off:], uint16(v.MaximumRequestLength))
517+ off += 2
518+ p[off:][0] = byte(v.RootsLen)
519+ off += 1
520+ p[off:][0] = byte(v.PixmapFormatsLen)
521+ off += 1
522+ p[off:][0] = byte(v.ImageByteOrder)
523+ off += 1
524+ p[off:][0] = byte(v.BitmapFormatBitOrder)
525+ off += 1
526+ p[off:][0] = byte(v.BitmapFormatScanlineUnit)
527+ off += 1
528+ p[off:][0] = byte(v.BitmapFormatScanlinePad)
529+ off += 1
530+ p[off:][0] = byte(v.MinKeycode)
531+ off += 1
532+ p[off:][0] = byte(v.MaxKeycode)
533+ off += 1
534+ clear(p[off : off+4])
535+ off += 4
536+ for i := range v.Vendor {
537+ p[off+i*1:][0] = byte(v.Vendor[i])
538+ }
539+ off += len(v.Vendor) * 1
540+ {
541+ next := (off + 3) &^ 3
542+ clear(p[off:next])
543+ off = next
544+ }
545+ for i := range v.PixmapFormats {
546+ v.PixmapFormats[i].Put(p[off+i*8:])
547+ }
548+ off += len(v.PixmapFormats) * 8
549+ for i := range v.Roots {
550+ v.Roots[i].Put(p[off:])
551+ off += v.Roots[i].Size()
552+ }
553+}
554+
555+type ClientMessageData struct{ raw []byte }
556+
557+const ClientMessageDataSize = 20
558+
559+func GetClientMessageData(p []byte) ClientMessageData { return ClientMessageData{raw: p[:20]} }
560+func (v ClientMessageData) Put(p []byte) { copy(p[:20], v.raw) }
561+func (v ClientMessageData) Data8() (out [20]uint8) {
562+ for i := range out {
563+ out[i] = uint8(v.raw[i*1:][0])
564+ }
565+ return
566+}
567+func (v ClientMessageData) Data16() (out [10]uint16) {
568+ for i := range out {
569+ out[i] = uint16(binary.LittleEndian.Uint16(v.raw[i*2:]))
570+ }
571+ return
572+}
573+func (v ClientMessageData) Data32() (out [5]uint32) {
574+ for i := range out {
575+ out[i] = uint32(binary.LittleEndian.Uint32(v.raw[i*4:]))
576+ }
577+ return
578+}
579+
580+type Timecoord struct {
581+ Time Timestamp
582+ X int16
583+ Y int16
584+}
585+
586+const TimecoordSize = 8
587+
588+func (v Timecoord) Put(p []byte) {
589+ clear(p[:8])
590+ binary.LittleEndian.PutUint32(p[0:], uint32(v.Time))
591+ binary.LittleEndian.PutUint16(p[4:], uint16(v.X))
592+ binary.LittleEndian.PutUint16(p[6:], uint16(v.Y))
593+}
594+func GetTimecoord(p []byte) (v Timecoord) {
595+ _ = p[7]
596+ v.Time = Timestamp(binary.LittleEndian.Uint32(p[0:]))
597+ v.X = int16(binary.LittleEndian.Uint16(p[4:]))
598+ v.Y = int16(binary.LittleEndian.Uint16(p[6:]))
599+ return
600+}
601+
602+type Fontprop struct {
603+ Name Atom
604+ Value uint32
605+}
606+
607+const FontpropSize = 8
608+
609+func (v Fontprop) Put(p []byte) {
610+ clear(p[:8])
611+ binary.LittleEndian.PutUint32(p[0:], uint32(v.Name))
612+ binary.LittleEndian.PutUint32(p[4:], uint32(v.Value))
613+}
614+func GetFontprop(p []byte) (v Fontprop) {
615+ _ = p[7]
616+ v.Name = Atom(binary.LittleEndian.Uint32(p[0:]))
617+ v.Value = uint32(binary.LittleEndian.Uint32(p[4:]))
618+ return
619+}
620+
621+type Charinfo struct {
622+ LeftSideBearing int16
623+ RightSideBearing int16
624+ CharacterWidth int16
625+ Ascent int16
626+ Descent int16
627+ Attributes uint16
628+}
629+
630+const CharinfoSize = 12
631+
632+func (v Charinfo) Put(p []byte) {
633+ clear(p[:12])
634+ binary.LittleEndian.PutUint16(p[0:], uint16(v.LeftSideBearing))
635+ binary.LittleEndian.PutUint16(p[2:], uint16(v.RightSideBearing))
636+ binary.LittleEndian.PutUint16(p[4:], uint16(v.CharacterWidth))
637+ binary.LittleEndian.PutUint16(p[6:], uint16(v.Ascent))
638+ binary.LittleEndian.PutUint16(p[8:], uint16(v.Descent))
639+ binary.LittleEndian.PutUint16(p[10:], uint16(v.Attributes))
640+}
641+func GetCharinfo(p []byte) (v Charinfo) {
642+ _ = p[11]
643+ v.LeftSideBearing = int16(binary.LittleEndian.Uint16(p[0:]))
644+ v.RightSideBearing = int16(binary.LittleEndian.Uint16(p[2:]))
645+ v.CharacterWidth = int16(binary.LittleEndian.Uint16(p[4:]))
646+ v.Ascent = int16(binary.LittleEndian.Uint16(p[6:]))
647+ v.Descent = int16(binary.LittleEndian.Uint16(p[8:]))
648+ v.Attributes = uint16(binary.LittleEndian.Uint16(p[10:]))
649+ return
650+}
651+
652+type Str struct {
653+ NameLen uint8
654+ Name string
655+}
656+
657+const StrSize = 1
658+
659+func (v Str) Size() int { off := 0; off += 1; off += len(v.Name) * 1; return off }
660+func (v Str) Put(p []byte) {
661+ off := 0
662+ p[off:][0] = byte(v.NameLen)
663+ off += 1
664+ for i := range v.Name {
665+ p[off+i*1:][0] = byte(v.Name[i])
666+ }
667+ off += len(v.Name) * 1
668+}
669+
670+type Segment struct {
671+ X1 int16
672+ Y1 int16
673+ X2 int16
674+ Y2 int16
675+}
676+
677+const SegmentSize = 8
678+
679+func (v Segment) Put(p []byte) {
680+ clear(p[:8])
681+ binary.LittleEndian.PutUint16(p[0:], uint16(v.X1))
682+ binary.LittleEndian.PutUint16(p[2:], uint16(v.Y1))
683+ binary.LittleEndian.PutUint16(p[4:], uint16(v.X2))
684+ binary.LittleEndian.PutUint16(p[6:], uint16(v.Y2))
685+}
686+func GetSegment(p []byte) (v Segment) {
687+ _ = p[7]
688+ v.X1 = int16(binary.LittleEndian.Uint16(p[0:]))
689+ v.Y1 = int16(binary.LittleEndian.Uint16(p[2:]))
690+ v.X2 = int16(binary.LittleEndian.Uint16(p[4:]))
691+ v.Y2 = int16(binary.LittleEndian.Uint16(p[6:]))
692+ return
693+}
694+
695+type Coloritem struct {
696+ Pixel uint32
697+ Red uint16
698+ Green uint16
699+ Blue uint16
700+ Flags ColorFlag
701+}
702+
703+const ColoritemSize = 12
704+
705+func (v Coloritem) Put(p []byte) {
706+ clear(p[:12])
707+ binary.LittleEndian.PutUint32(p[0:], uint32(v.Pixel))
708+ binary.LittleEndian.PutUint16(p[4:], uint16(v.Red))
709+ binary.LittleEndian.PutUint16(p[6:], uint16(v.Green))
710+ binary.LittleEndian.PutUint16(p[8:], uint16(v.Blue))
711+ p[10:][0] = byte(v.Flags)
712+}
713+func GetColoritem(p []byte) (v Coloritem) {
714+ _ = p[11]
715+ v.Pixel = uint32(binary.LittleEndian.Uint32(p[0:]))
716+ v.Red = uint16(binary.LittleEndian.Uint16(p[4:]))
717+ v.Green = uint16(binary.LittleEndian.Uint16(p[6:]))
718+ v.Blue = uint16(binary.LittleEndian.Uint16(p[8:]))
719+ v.Flags = ColorFlag(p[10:][0])
720+ return
721+}
722+
723+type Rgb struct {
724+ Red uint16
725+ Green uint16
726+ Blue uint16
727+}
728+
729+const RgbSize = 8
730+
731+func (v Rgb) Put(p []byte) {
732+ clear(p[:8])
733+ binary.LittleEndian.PutUint16(p[0:], uint16(v.Red))
734+ binary.LittleEndian.PutUint16(p[2:], uint16(v.Green))
735+ binary.LittleEndian.PutUint16(p[4:], uint16(v.Blue))
736+}
737+func GetRgb(p []byte) (v Rgb) {
738+ _ = p[7]
739+ v.Red = uint16(binary.LittleEndian.Uint16(p[0:]))
740+ v.Green = uint16(binary.LittleEndian.Uint16(p[2:]))
741+ v.Blue = uint16(binary.LittleEndian.Uint16(p[4:]))
742+ return
743+}
744+
745+type Host struct {
746+ Family Family
747+ AddressLen uint16
748+ Address []byte
749+}
750+
751+const HostSize = 4
752+
753+func (v Host) Size() int {
754+ off := 0
755+ off += 1
756+ off += 1
757+ off += 2
758+ off += len(v.Address) * 1
759+ off = (off + 3) &^ 3
760+ return off
761+}
762+func (v Host) Put(p []byte) {
763+ off := 0
764+ p[off:][0] = byte(v.Family)
765+ off += 1
766+ clear(p[off : off+1])
767+ off += 1
768+ binary.LittleEndian.PutUint16(p[off:], uint16(v.AddressLen))
769+ off += 2
770+ for i := range v.Address {
771+ p[off+i*1:][0] = byte(v.Address[i])
772+ }
773+ off += len(v.Address) * 1
774+ {
775+ next := (off + 3) &^ 3
776+ clear(p[off:next])
777+ off = next
778+ }
779+}
780+
781+type VisualClass uint8
782+
783+const VisualClassStaticGray VisualClass = 0
784+const VisualClassGrayScale VisualClass = 1
785+const VisualClassStaticColor VisualClass = 2
786+const VisualClassPseudoColor VisualClass = 3
787+const VisualClassTrueColor VisualClass = 4
788+const VisualClassDirectColor VisualClass = 5
789+
790+type EventMask uint32
791+
792+const EventMaskNoEvent EventMask = 0
793+const EventMaskKeyPress EventMask = 1
794+const EventMaskKeyRelease EventMask = 2
795+const EventMaskButtonPress EventMask = 4
796+const EventMaskButtonRelease EventMask = 8
797+const EventMaskEnterWindow EventMask = 16
798+const EventMaskLeaveWindow EventMask = 32
799+const EventMaskPointerMotion EventMask = 64
800+const EventMaskPointerMotionHint EventMask = 128
801+const EventMaskButton1Motion EventMask = 256
802+const EventMaskButton2Motion EventMask = 512
803+const EventMaskButton3Motion EventMask = 1024
804+const EventMaskButton4Motion EventMask = 2048
805+const EventMaskButton5Motion EventMask = 4096
806+const EventMaskButtonMotion EventMask = 8192
807+const EventMaskKeymapState EventMask = 16384
808+const EventMaskExposure EventMask = 32768
809+const EventMaskVisibilityChange EventMask = 65536
810+const EventMaskStructureNotify EventMask = 131072
811+const EventMaskResizeRedirect EventMask = 262144
812+const EventMaskSubstructureNotify EventMask = 524288
813+const EventMaskSubstructureRedirect EventMask = 1048576
814+const EventMaskFocusChange EventMask = 2097152
815+const EventMaskPropertyChange EventMask = 4194304
816+const EventMaskColorMapChange EventMask = 8388608
817+const EventMaskOwnerGrabButton EventMask = 16777216
818+
819+type BackingStore uint32
820+
821+const BackingStoreNotUseful BackingStore = 0
822+const BackingStoreWhenMapped BackingStore = 1
823+const BackingStoreAlways BackingStore = 2
824+
825+type ImageOrder uint8
826+
827+const ImageOrderLSBFirst ImageOrder = 0
828+const ImageOrderMSBFirst ImageOrder = 1
829+
830+type ModMask uint16
831+
832+const ModMaskShift ModMask = 1
833+const ModMaskLock ModMask = 2
834+const ModMaskControl ModMask = 4
835+const ModMaskX1 ModMask = 8
836+const ModMaskX2 ModMask = 16
837+const ModMaskX3 ModMask = 32
838+const ModMaskX4 ModMask = 64
839+const ModMaskX5 ModMask = 128
840+const ModMaskAny ModMask = 32768
841+
842+type KeyButMask uint16
843+
844+const KeyButMaskShift KeyButMask = 1
845+const KeyButMaskLock KeyButMask = 2
846+const KeyButMaskControl KeyButMask = 4
847+const KeyButMaskMod1 KeyButMask = 8
848+const KeyButMaskMod2 KeyButMask = 16
849+const KeyButMaskMod3 KeyButMask = 32
850+const KeyButMaskMod4 KeyButMask = 64
851+const KeyButMaskMod5 KeyButMask = 128
852+const KeyButMaskButton1 KeyButMask = 256
853+const KeyButMaskButton2 KeyButMask = 512
854+const KeyButMaskButton3 KeyButMask = 1024
855+const KeyButMaskButton4 KeyButMask = 2048
856+const KeyButMaskButton5 KeyButMask = 4096
857+
858+const WindowNone Window = 0
859+
860+type ButtonMask uint32
861+
862+const ButtonMaskX1 ButtonMask = 256
863+const ButtonMaskX2 ButtonMask = 512
864+const ButtonMaskX3 ButtonMask = 1024
865+const ButtonMaskX4 ButtonMask = 2048
866+const ButtonMaskX5 ButtonMask = 4096
867+const ButtonMaskAny ButtonMask = 32768
868+
869+type Motion uint8
870+
871+const MotionNormal Motion = 0
872+const MotionHint Motion = 1
873+
874+type NotifyDetail uint8
875+
876+const NotifyDetailAncestor NotifyDetail = 0
877+const NotifyDetailVirtual NotifyDetail = 1
878+const NotifyDetailInferior NotifyDetail = 2
879+const NotifyDetailNonlinear NotifyDetail = 3
880+const NotifyDetailNonlinearVirtual NotifyDetail = 4
881+const NotifyDetailPointer NotifyDetail = 5
882+const NotifyDetailPointerRoot NotifyDetail = 6
883+const NotifyDetailNone NotifyDetail = 7
884+
885+type NotifyMode uint8
886+
887+const NotifyModeNormal NotifyMode = 0
888+const NotifyModeGrab NotifyMode = 1
889+const NotifyModeUngrab NotifyMode = 2
890+const NotifyModeWhileGrabbed NotifyMode = 3
891+
892+type Visibility uint8
893+
894+const VisibilityUnobscured Visibility = 0
895+const VisibilityPartiallyObscured Visibility = 1
896+const VisibilityFullyObscured Visibility = 2
897+
898+type Place uint8
899+
900+const PlaceOnTop Place = 0
901+const PlaceOnBottom Place = 1
902+
903+type Property uint8
904+
905+const PropertyNewValue Property = 0
906+const PropertyDelete Property = 1
907+
908+type Time uint32
909+
910+const TimeCurrentTime Time = 0
911+
912+const AtomNone Atom = 0
913+const AtomAny Atom = 0
914+const AtomPrimary Atom = 1
915+const AtomSecondary Atom = 2
916+const AtomArc Atom = 3
917+const AtomAtom Atom = 4
918+const AtomBitmap Atom = 5
919+const AtomCardinal Atom = 6
920+const AtomColormap Atom = 7
921+const AtomCursor Atom = 8
922+const AtomCutBuffer0 Atom = 9
923+const AtomCutBuffer1 Atom = 10
924+const AtomCutBuffer2 Atom = 11
925+const AtomCutBuffer3 Atom = 12
926+const AtomCutBuffer4 Atom = 13
927+const AtomCutBuffer5 Atom = 14
928+const AtomCutBuffer6 Atom = 15
929+const AtomCutBuffer7 Atom = 16
930+const AtomDrawable Atom = 17
931+const AtomFont Atom = 18
932+const AtomInteger Atom = 19
933+const AtomPixmap Atom = 20
934+const AtomPoint Atom = 21
935+const AtomRectangle Atom = 22
936+const AtomResourceManager Atom = 23
937+const AtomRgbColorMap Atom = 24
938+const AtomRgbBestMap Atom = 25
939+const AtomRgbBlueMap Atom = 26
940+const AtomRgbDefaultMap Atom = 27
941+const AtomRgbGrayMap Atom = 28
942+const AtomRgbGreenMap Atom = 29
943+const AtomRgbRedMap Atom = 30
944+const AtomString Atom = 31
945+const AtomVisualid Atom = 32
946+const AtomWindow Atom = 33
947+const AtomWmCommand Atom = 34
948+const AtomWmHints Atom = 35
949+const AtomWmClientMachine Atom = 36
950+const AtomWmIconName Atom = 37
951+const AtomWmIconSize Atom = 38
952+const AtomWmName Atom = 39
953+const AtomWmNormalHints Atom = 40
954+const AtomWmSizeHints Atom = 41
955+const AtomWmZoomHints Atom = 42
956+const AtomMinSpace Atom = 43
957+const AtomNormSpace Atom = 44
958+const AtomMaxSpace Atom = 45
959+const AtomEndSpace Atom = 46
960+const AtomSuperscriptX Atom = 47
961+const AtomSuperscriptY Atom = 48
962+const AtomSubscriptX Atom = 49
963+const AtomSubscriptY Atom = 50
964+const AtomUnderlinePosition Atom = 51
965+const AtomUnderlineThickness Atom = 52
966+const AtomStrikeoutAscent Atom = 53
967+const AtomStrikeoutDescent Atom = 54
968+const AtomItalicAngle Atom = 55
969+const AtomXHeight Atom = 56
970+const AtomQuadWidth Atom = 57
971+const AtomWeight Atom = 58
972+const AtomPointSize Atom = 59
973+const AtomResolution Atom = 60
974+const AtomCopyright Atom = 61
975+const AtomNotice Atom = 62
976+const AtomFontName Atom = 63
977+const AtomFamilyName Atom = 64
978+const AtomFullName Atom = 65
979+const AtomCapHeight Atom = 66
980+const AtomWmClass Atom = 67
981+const AtomWmTransientFor Atom = 68
982+
983+type ColormapState uint8
984+
985+const ColormapStateUninstalled ColormapState = 0
986+const ColormapStateInstalled ColormapState = 1
987+
988+const ColormapNone Colormap = 0
989+
990+type Mapping uint8
991+
992+const MappingModifier Mapping = 0
993+const MappingKeyboard Mapping = 1
994+const MappingPointer Mapping = 2
995+
996+type WindowClass uint16
997+
998+const WindowClassCopyFromParent WindowClass = 0
999+const WindowClassInputOutput WindowClass = 1
1000+const WindowClassInputOnly WindowClass = 2
1001+
1002+type Cw uint32
1003+
1004+const CwBackPixmap Cw = 1
1005+const CwBackPixel Cw = 2
1006+const CwBorderPixmap Cw = 4
1007+const CwBorderPixel Cw = 8
1008+const CwBitGravity Cw = 16
1009+const CwWinGravity Cw = 32
1010+const CwBackingStore Cw = 64
1011+const CwBackingPlanes Cw = 128
1012+const CwBackingPixel Cw = 256
1013+const CwOverrideRedirect Cw = 512
1014+const CwSaveUnder Cw = 1024
1015+const CwEventMask Cw = 2048
1016+const CwDontPropagate Cw = 4096
1017+const CwColormap Cw = 8192
1018+const CwCursor Cw = 16384
1019+
1020+type BackPixmap uint32
1021+
1022+const BackPixmapNone BackPixmap = 0
1023+const BackPixmapParentRelative BackPixmap = 1
1024+
1025+type Gravity uint32
1026+
1027+const GravityBitForget Gravity = 0
1028+const GravityWinUnmap Gravity = 0
1029+const GravityNorthWest Gravity = 1
1030+const GravityNorth Gravity = 2
1031+const GravityNorthEast Gravity = 3
1032+const GravityWest Gravity = 4
1033+const GravityCenter Gravity = 5
1034+const GravityEast Gravity = 6
1035+const GravitySouthWest Gravity = 7
1036+const GravitySouth Gravity = 8
1037+const GravitySouthEast Gravity = 9
1038+const GravityStatic Gravity = 10
1039+
1040+type MapState uint8
1041+
1042+const MapStateUnmapped MapState = 0
1043+const MapStateUnviewable MapState = 1
1044+const MapStateViewable MapState = 2
1045+
1046+type SetMode uint8
1047+
1048+const SetModeInsert SetMode = 0
1049+const SetModeDelete SetMode = 1
1050+
1051+type ConfigWindow uint16
1052+
1053+const ConfigWindowX ConfigWindow = 1
1054+const ConfigWindowY ConfigWindow = 2
1055+const ConfigWindowWidth ConfigWindow = 4
1056+const ConfigWindowHeight ConfigWindow = 8
1057+const ConfigWindowBorderWidth ConfigWindow = 16
1058+const ConfigWindowSibling ConfigWindow = 32
1059+const ConfigWindowStackMode ConfigWindow = 64
1060+
1061+type StackMode uint32
1062+
1063+const StackModeAbove StackMode = 0
1064+const StackModeBelow StackMode = 1
1065+const StackModeTopIf StackMode = 2
1066+const StackModeBottomIf StackMode = 3
1067+const StackModeOpposite StackMode = 4
1068+
1069+type Circulate uint8
1070+
1071+const CirculateRaiseLowest Circulate = 0
1072+const CirculateLowerHighest Circulate = 1
1073+
1074+type PropMode uint8
1075+
1076+const PropModeReplace PropMode = 0
1077+const PropModePrepend PropMode = 1
1078+const PropModeAppend PropMode = 2
1079+
1080+type GetPropertyType uint32
1081+
1082+const GetPropertyTypeAny GetPropertyType = 0
1083+
1084+type SendEventDest uint32
1085+
1086+const SendEventDestPointerWindow SendEventDest = 0
1087+const SendEventDestItemFocus SendEventDest = 1
1088+
1089+type GrabMode uint8
1090+
1091+const GrabModeSync GrabMode = 0
1092+const GrabModeAsync GrabMode = 1
1093+
1094+type GrabStatus uint8
1095+
1096+const GrabStatusSuccess GrabStatus = 0
1097+const GrabStatusAlreadyGrabbed GrabStatus = 1
1098+const GrabStatusInvalidTime GrabStatus = 2
1099+const GrabStatusNotViewable GrabStatus = 3
1100+const GrabStatusFrozen GrabStatus = 4
1101+
1102+const CursorNone Cursor = 0
1103+
1104+type ButtonIndex uint8
1105+
1106+const ButtonIndexAny ButtonIndex = 0
1107+const ButtonIndexX1 ButtonIndex = 1
1108+const ButtonIndexX2 ButtonIndex = 2
1109+const ButtonIndexX3 ButtonIndex = 3
1110+const ButtonIndexX4 ButtonIndex = 4
1111+const ButtonIndexX5 ButtonIndex = 5
1112+
1113+type Grab uint8
1114+
1115+const GrabAny Grab = 0
1116+
1117+type Allow uint8
1118+
1119+const AllowAsyncPointer Allow = 0
1120+const AllowSyncPointer Allow = 1
1121+const AllowReplayPointer Allow = 2
1122+const AllowAsyncKeyboard Allow = 3
1123+const AllowSyncKeyboard Allow = 4
1124+const AllowReplayKeyboard Allow = 5
1125+const AllowAsyncBoth Allow = 6
1126+const AllowSyncBoth Allow = 7
1127+
1128+type InputFocus uint32
1129+
1130+const InputFocusNone InputFocus = 0
1131+const InputFocusPointerRoot InputFocus = 1
1132+const InputFocusParent InputFocus = 2
1133+const InputFocusFollowKeyboard InputFocus = 3
1134+
1135+type FontDraw uint8
1136+
1137+const FontDrawLeftToRight FontDraw = 0
1138+const FontDrawRightToLeft FontDraw = 1
1139+
1140+type Gc uint32
1141+
1142+const GcFunction Gc = 1
1143+const GcPlaneMask Gc = 2
1144+const GcForeground Gc = 4
1145+const GcBackground Gc = 8
1146+const GcLineWidth Gc = 16
1147+const GcLineStyle Gc = 32
1148+const GcCapStyle Gc = 64
1149+const GcJoinStyle Gc = 128
1150+const GcFillStyle Gc = 256
1151+const GcFillRule Gc = 512
1152+const GcTile Gc = 1024
1153+const GcStipple Gc = 2048
1154+const GcTileStippleOriginX Gc = 4096
1155+const GcTileStippleOriginY Gc = 8192
1156+const GcFont Gc = 16384
1157+const GcSubwindowMode Gc = 32768
1158+const GcGraphicsExposures Gc = 65536
1159+const GcClipOriginX Gc = 131072
1160+const GcClipOriginY Gc = 262144
1161+const GcClipMask Gc = 524288
1162+const GcDashOffset Gc = 1048576
1163+const GcDashList Gc = 2097152
1164+const GcArcMode Gc = 4194304
1165+
1166+type Gx uint32
1167+
1168+const GxClear Gx = 0
1169+const GxAnd Gx = 1
1170+const GxAndReverse Gx = 2
1171+const GxCopy Gx = 3
1172+const GxAndInverted Gx = 4
1173+const GxNoop Gx = 5
1174+const GxXor Gx = 6
1175+const GxOr Gx = 7
1176+const GxNor Gx = 8
1177+const GxEquiv Gx = 9
1178+const GxInvert Gx = 10
1179+const GxOrReverse Gx = 11
1180+const GxCopyInverted Gx = 12
1181+const GxOrInverted Gx = 13
1182+const GxNand Gx = 14
1183+const GxSet Gx = 15
1184+
1185+type LineStyle uint32
1186+
1187+const LineStyleSolid LineStyle = 0
1188+const LineStyleOnOffDash LineStyle = 1
1189+const LineStyleDoubleDash LineStyle = 2
1190+
1191+type CapStyle uint32
1192+
1193+const CapStyleNotLast CapStyle = 0
1194+const CapStyleButt CapStyle = 1
1195+const CapStyleRound CapStyle = 2
1196+const CapStyleProjecting CapStyle = 3
1197+
1198+type JoinStyle uint32
1199+
1200+const JoinStyleMiter JoinStyle = 0
1201+const JoinStyleRound JoinStyle = 1
1202+const JoinStyleBevel JoinStyle = 2
1203+
1204+type FillStyle uint32
1205+
1206+const FillStyleSolid FillStyle = 0
1207+const FillStyleTiled FillStyle = 1
1208+const FillStyleStippled FillStyle = 2
1209+const FillStyleOpaqueStippled FillStyle = 3
1210+
1211+type FillRule uint32
1212+
1213+const FillRuleEvenOdd FillRule = 0
1214+const FillRuleWinding FillRule = 1
1215+
1216+type SubwindowMode uint32
1217+
1218+const SubwindowModeClipByChildren SubwindowMode = 0
1219+const SubwindowModeIncludeInferiors SubwindowMode = 1
1220+
1221+type ArcMode uint32
1222+
1223+const ArcModeChord ArcMode = 0
1224+const ArcModePieSlice ArcMode = 1
1225+
1226+type ClipOrdering uint8
1227+
1228+const ClipOrderingUnsorted ClipOrdering = 0
1229+const ClipOrderingYSorted ClipOrdering = 1
1230+const ClipOrderingYXSorted ClipOrdering = 2
1231+const ClipOrderingYXBanded ClipOrdering = 3
1232+
1233+type CoordMode uint8
1234+
1235+const CoordModeOrigin CoordMode = 0
1236+const CoordModePrevious CoordMode = 1
1237+
1238+type PolyShape uint8
1239+
1240+const PolyShapeComplex PolyShape = 0
1241+const PolyShapeNonconvex PolyShape = 1
1242+const PolyShapeConvex PolyShape = 2
1243+
1244+type ImageFormat uint8
1245+
1246+const ImageFormatXYBitmap ImageFormat = 0
1247+const ImageFormatXYPixmap ImageFormat = 1
1248+const ImageFormatZPixmap ImageFormat = 2
1249+
1250+type ColormapAlloc uint8
1251+
1252+const ColormapAllocNone ColormapAlloc = 0
1253+const ColormapAllocAll ColormapAlloc = 1
1254+
1255+type ColorFlag uint8
1256+
1257+const ColorFlagRed ColorFlag = 1
1258+const ColorFlagGreen ColorFlag = 2
1259+const ColorFlagBlue ColorFlag = 4
1260+
1261+const PixmapNone Pixmap = 0
1262+
1263+const FontNone Font = 0
1264+
1265+type QueryShapeOf uint8
1266+
1267+const QueryShapeOfLargestCursor QueryShapeOf = 0
1268+const QueryShapeOfFastestTile QueryShapeOf = 1
1269+const QueryShapeOfFastestStipple QueryShapeOf = 2
1270+
1271+type Kb uint32
1272+
1273+const KbKeyClickPercent Kb = 1
1274+const KbBellPercent Kb = 2
1275+const KbBellPitch Kb = 4
1276+const KbBellDuration Kb = 8
1277+const KbLed Kb = 16
1278+const KbLedMode Kb = 32
1279+const KbKey Kb = 64
1280+const KbAutoRepeatMode Kb = 128
1281+
1282+type LedMode uint32
1283+
1284+const LedModeOff LedMode = 0
1285+const LedModeOn LedMode = 1
1286+
1287+type AutoRepeatMode uint32
1288+
1289+const AutoRepeatModeOff AutoRepeatMode = 0
1290+const AutoRepeatModeOn AutoRepeatMode = 1
1291+const AutoRepeatModeDefault AutoRepeatMode = 2
1292+
1293+type Blanking uint8
1294+
1295+const BlankingNotPreferred Blanking = 0
1296+const BlankingPreferred Blanking = 1
1297+const BlankingDefault Blanking = 2
1298+
1299+type Exposures uint8
1300+
1301+const ExposuresNotAllowed Exposures = 0
1302+const ExposuresAllowed Exposures = 1
1303+const ExposuresDefault Exposures = 2
1304+
1305+type HostMode uint8
1306+
1307+const HostModeInsert HostMode = 0
1308+const HostModeDelete HostMode = 1
1309+
1310+type Family uint8
1311+
1312+const FamilyInternet Family = 0
1313+const FamilyDECnet Family = 1
1314+const FamilyChaos Family = 2
1315+const FamilyServerInterpreted Family = 5
1316+const FamilyInternet6 Family = 6
1317+
1318+type AccessControl uint8
1319+
1320+const AccessControlDisable AccessControl = 0
1321+const AccessControlEnable AccessControl = 1
1322+
1323+type CloseDown uint8
1324+
1325+const CloseDownDestroyAll CloseDown = 0
1326+const CloseDownRetainPermanent CloseDown = 1
1327+const CloseDownRetainTemporary CloseDown = 2
1328+
1329+type Kill uint32
1330+
1331+const KillAllTemporary Kill = 0
1332+
1333+type ScreenSaver uint8
1334+
1335+const ScreenSaverReset ScreenSaver = 0
1336+const ScreenSaverActive ScreenSaver = 1
1337+
1338+type MappingStatus uint8
1339+
1340+const MappingStatusSuccess MappingStatus = 0
1341+const MappingStatusBusy MappingStatus = 1
1342+const MappingStatusFailure MappingStatus = 2
1343+
1344+type MapIndex uint32
1345+
1346+const MapIndexShift MapIndex = 0
1347+const MapIndexLock MapIndex = 1
1348+const MapIndexControl MapIndex = 2
1349+const MapIndexX1 MapIndex = 3
1350+const MapIndexX2 MapIndex = 4
1351+const MapIndexX3 MapIndex = 5
1352+const MapIndexX4 MapIndex = 6
1353+const MapIndexX5 MapIndex = 7
A xproto/types_test.go +54 -0
@@ -0,0 +1,54 @@
1+package xproto
2+
3+import (
4+ "encoding/binary"
5+ "testing"
6+)
7+
8+func TestRectangleWire(t *testing.T) {
9+ v := Rectangle{X: -2, Y: 3, Width: 640, Height: 480}
10+ var p [8]byte
11+ v.Put(p[:])
12+ want := [8]byte{254, 255, 3, 0, 128, 2, 224, 1}
13+ if p != want || GetRectangle(p[:]) != v {
14+ t.Fatalf("wire %x", p)
15+ }
16+}
17+func TestVariableStructWire(t *testing.T) {
18+ v := Str{NameLen: 3, Name: "abc"}
19+ p := make([]byte, v.Size())
20+ v.Put(p)
21+ if string(p) != "\x03abc" {
22+ t.Fatalf("wire %x", p)
23+ }
24+ s := SetupRequest{ByteOrder: 'l', ProtocolMajorVersion: 11, AuthorizationProtocolNameLen: 1, AuthorizationProtocolDataLen: 2, AuthorizationProtocolName: "a", AuthorizationProtocolData: "bc"}
25+ p = make([]byte, s.Size())
26+ s.Put(p)
27+ if len(p) != 20 || p[12] != 'a' || p[16] != 'b' || p[17] != 'c' || p[19] != 0 {
28+ t.Fatalf("aligned setup %x", p)
29+ }
30+}
31+func TestUnionView(t *testing.T) {
32+ var p [20]byte
33+ binary.LittleEndian.PutUint32(p[:], 0x12345678)
34+ v := GetClientMessageData(p[:])
35+ if v.Data8()[0] != 0x78 || v.Data16()[0] != 0x5678 || v.Data32()[0] != 0x12345678 {
36+ t.Fatal("union members")
37+ }
38+}
39+func TestAllocStructPut(t *testing.T) {
40+ v := Rectangle{Width: 10}
41+ var p [8]byte
42+ if n := testing.AllocsPerRun(1000, func() { v.Put(p[:]); _ = GetRectangle(p[:]) }); n != 0 {
43+ t.Fatal(n)
44+ }
45+}
46+
47+func BenchmarkRectanglePut(b *testing.B) {
48+ v := Rectangle{Width: 640, Height: 480}
49+ var p [8]byte
50+ b.ReportAllocs()
51+ for b.Loop() {
52+ v.Put(p[:])
53+ }
54+}

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 1

↑↓ moveenter openesc close