detached adae91e

feat(wlgen): generate typed server bindings from protocol XML

Add cmd/wlgen, vendored wayland and xdg-shell protocols, generated protocol packages, string/array/fd/fixed arguments, PostError, and e2e tests replacing the hand-written prototype.
commit
adae91e7ed15e817910b06d4d9e0fa750149159c
author
brice · · 2026-09-23 10:22 UTC
parent
54d04f6
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
20 files · +8939 -138
M Makefile +4 -1
@@ -1,4 +1,7 @@
1-.PHONY: test vet race check
1+.PHONY: test vet race check generate
2+
3+generate:
4+ CGO_ENABLED=0 go generate ./protocol
25
36 test:
47 CGO_ENABLED=0 go test ./...
M README.md +5 -1
@@ -4,7 +4,7 @@ Go bindings for libwayland without cgo, loaded at runtime through github.com/bne
44
55 ## Status
66
7-Early v0.x. Server side first; client side planned.
7+Early v0.x. Server bindings and generated Wayland protocol packages are available.
88
99 ## Requirements
1010
@@ -16,6 +16,10 @@ Linux, Go 1.27, and `libwayland-server.so.0` at runtime.
1616 CGO_ENABLED=0 go build ./...
1717 ```
1818
19+## Protocol generation
20+
21+Vendored protocol XML lives in `protocols/`. Run `make generate` to regenerate the Go packages in `protocol/`.
22+
1923 ## License
2024
2125 MIT.
A cmd/wlgen/main.go +438 -0
@@ -0,0 +1,438 @@
1+package main
2+
3+import (
4+ "bytes"
5+ "encoding/xml"
6+ "flag"
7+ "fmt"
8+ "go/format"
9+ "os"
10+ "sort"
11+ "strings"
12+ "unicode"
13+)
14+
15+type protocol struct {
16+ Interfaces []iface `xml:"interface"`
17+}
18+type iface struct {
19+ Name string `xml:"name,attr"`
20+ Version int32 `xml:"version,attr"`
21+ Description description `xml:"description"`
22+ Requests []message `xml:"request"`
23+ Events []message `xml:"event"`
24+ Enums []enum `xml:"enum"`
25+}
26+type description struct {
27+ Summary string `xml:"summary,attr"`
28+}
29+type message struct {
30+ Name string `xml:"name,attr"`
31+ Type string `xml:"type,attr"`
32+ Since int `xml:"since,attr"`
33+ Description description `xml:"description"`
34+ Args []arg `xml:"arg"`
35+}
36+type arg struct {
37+ Name string `xml:"name,attr"`
38+ Type string `xml:"type,attr"`
39+ Interface string `xml:"interface,attr"`
40+ Nullable bool `xml:"allow-null,attr"`
41+}
42+type enum struct {
43+ Name string `xml:"name,attr"`
44+ Bitfield bool `xml:"bitfield,attr"`
45+ Description description `xml:"description"`
46+ Entries []entry `xml:"entry"`
47+}
48+type entry struct {
49+ Name string `xml:"name,attr"`
50+ Value string `xml:"value,attr"`
51+}
52+type flags []string
53+
54+func (f *flags) String() string { return strings.Join(*f, ",") }
55+func (f *flags) Set(s string) error { *f = append(*f, s); return nil }
56+func parse(path string) (protocol, error) {
57+ var p protocol
58+ b, e := os.ReadFile(path)
59+ if e == nil {
60+ e = xml.Unmarshal(b, &p)
61+ }
62+ return p, e
63+}
64+func camel(s string) string {
65+ var b strings.Builder
66+ for _, part := range strings.Split(s, "_") {
67+ if part == "" {
68+ continue
69+ }
70+ r := []rune(part)
71+ b.WriteRune(unicode.ToUpper(r[0]))
72+ b.WriteString(string(r[1:]))
73+ }
74+ return b.String()
75+}
76+func name(s string) string {
77+ for _, prefix := range []string{"wl_", "xdg_"} {
78+ if strings.HasPrefix(s, prefix) {
79+ s = strings.TrimPrefix(s, prefix)
80+ break
81+ }
82+ }
83+ return camel(s)
84+}
85+func signature(m message) string {
86+ var b strings.Builder
87+ if m.Since > 1 {
88+ fmt.Fprint(&b, m.Since)
89+ }
90+ for _, a := range m.Args {
91+ if a.Type == "new_id" && a.Interface == "" {
92+ b.WriteString("sun")
93+ continue
94+ }
95+ if a.Nullable {
96+ b.WriteByte('?')
97+ }
98+ b.WriteString(map[string]string{"int": "i", "uint": "u", "fixed": "f", "string": "s", "array": "a", "object": "o", "new_id": "n", "fd": "h"}[a.Type])
99+ }
100+ return b.String()
101+}
102+
103+type gen struct {
104+ bytes.Buffer
105+ owners map[string]string
106+ imports map[string]string
107+}
108+
109+func (g *gen) p(f string, a ...any) { fmt.Fprintf(&g.Buffer, f, a...) }
110+func (g *gen) ref(s string) (string, error) {
111+ if s == "" {
112+ return "nil", nil
113+ }
114+ alias, ok := g.owners[s]
115+ if !ok {
116+ return "", fmt.Errorf("unknown interface %s", s)
117+ }
118+ if alias != "" {
119+ alias += "."
120+ }
121+ return alias + name(s) + "Interface", nil
122+}
123+func (g *gen) wrapper(s string) string {
124+ alias := g.owners[s]
125+ if alias != "" {
126+ alias += "."
127+ }
128+ return alias + name(s)
129+}
130+func (g *gen) table(m message) error {
131+ var ts []string
132+ for _, a := range m.Args {
133+ if a.Type == "new_id" && a.Interface == "" {
134+ ts = append(ts, "nil", "nil", "nil")
135+ continue
136+ }
137+ t := "nil"
138+ if a.Type == "object" || a.Type == "new_id" {
139+ var e error
140+ t, e = g.ref(a.Interface)
141+ if e != nil {
142+ return e
143+ }
144+ }
145+ ts = append(ts, t)
146+ }
147+ g.p("{Name:%q,Signature:%q,Types:[]*server.Interface{%s}},\n", m.Name, signature(m), strings.Join(ts, ","))
148+ return nil
149+}
150+func (g *gen) typ(a arg, event bool) string {
151+ switch a.Type {
152+ case "uint":
153+ return "uint32"
154+ case "int":
155+ return "int32"
156+ case "fixed":
157+ return "server.Fixed"
158+ case "string":
159+ return "string"
160+ case "array":
161+ return "[]byte"
162+ case "fd":
163+ return "int"
164+ case "new_id":
165+ if !event {
166+ return "uint32"
167+ }
168+ fallthrough
169+ case "object":
170+ if a.Interface == "" {
171+ return "*server.Resource"
172+ }
173+ return "*" + g.wrapper(a.Interface)
174+ }
175+ return "server.Arg"
176+}
177+func param(a arg) string {
178+ s := a.Name
179+ if parts := strings.Split(s, "_"); len(parts) > 1 {
180+ s = parts[0]
181+ for _, part := range parts[1:] {
182+ s += camel(part)
183+ }
184+ }
185+ switch s {
186+ case "interface", "type", "map", "range", "func", "var", "package", "select", "default", "go", "defer", "return", "chan", "import":
187+ return s + "Arg"
188+ }
189+ return s
190+}
191+func (g *gen) params(m message, event bool) {
192+ for _, a := range m.Args {
193+ if a.Type == "new_id" && a.Interface == "" && !event {
194+ g.p(", interfaceName string, version uint32, id uint32")
195+ continue
196+ }
197+ g.p(", %s %s", param(a), g.typ(a, event))
198+ }
199+}
200+func (g *gen) generate(pr protocol, pkg string) ([]byte, error) {
201+ g.p("// Code generated by wlgen; DO NOT EDIT.\npackage %s\nimport (\"github.com/bnema/purego-libwayland/server\"\n", pkg)
202+ pin := false
203+ for _, it := range pr.Interfaces {
204+ for _, m := range it.Events {
205+ for _, a := range m.Args {
206+ if a.Type == "string" || a.Type == "array" || (a.Type == "new_id" && a.Interface == "") {
207+ pin = true
208+ }
209+ }
210+ }
211+ }
212+ if pin {
213+ g.p("\"runtime\"\n")
214+ }
215+ for _, it := range pr.Interfaces {
216+ if len(it.Requests) > 0 {
217+ g.p("\"fmt\"\n")
218+ break
219+ }
220+ }
221+ aliases := make([]string, 0, len(g.imports))
222+ for alias := range g.imports {
223+ aliases = append(aliases, alias)
224+ }
225+ sort.Strings(aliases)
226+ for _, alias := range aliases {
227+ g.p("%s %q\n", alias, g.imports[alias])
228+ }
229+ g.p(")\n")
230+ for _, it := range pr.Interfaces {
231+ g.p("var %sInterface *server.Interface\n", name(it.Name))
232+ }
233+ g.p("func init(){\n")
234+ for _, it := range pr.Interfaces {
235+ g.p("%sInterface=&server.Interface{Name:%q,Version:%d}\n", name(it.Name), it.Name, it.Version)
236+ }
237+ for _, it := range pr.Interfaces {
238+ n := name(it.Name)
239+ g.p("%sInterface.Requests=[]server.Message{\n", n)
240+ for _, m := range it.Requests {
241+ if e := g.table(m); e != nil {
242+ return nil, e
243+ }
244+ }
245+ g.p("}\n%sInterface.Events=[]server.Message{\n", n)
246+ for _, m := range it.Events {
247+ if e := g.table(m); e != nil {
248+ return nil, e
249+ }
250+ }
251+ g.p("}\n")
252+ }
253+ g.p("if err:=server.NewInterfaces(")
254+ for _, it := range pr.Interfaces {
255+ g.p("%sInterface,", name(it.Name))
256+ }
257+ g.p(");err!=nil{panic(err)}}\n")
258+ for _, it := range pr.Interfaces {
259+ n := name(it.Name)
260+ g.p("// %s %s.\ntype %s struct{*server.Resource}\nfunc Wrap%s(r *server.Resource)*%s{if r==nil{return nil};return &%s{r}}\n", n, it.Description.Summary, n, n, n, n)
261+ for j, m := range it.Requests {
262+ g.p("const %sRequest%s uint32=%d\n", n, camel(m.Name), j)
263+ }
264+ for j, m := range it.Events {
265+ g.p("const %sEvent%s uint32=%d\n", n, camel(m.Name), j)
266+ }
267+ for _, en := range it.Enums {
268+ t := n + camel(en.Name)
269+ g.p("// %s %s", t, en.Description.Summary)
270+ if en.Bitfield {
271+ g.p(" (bitfield)")
272+ }
273+ g.p(".\ntype %s uint32\nconst(\n", t)
274+ for _, v := range en.Entries {
275+ g.p("%s%s %s=%s\n", t, camel(v.Name), t, v.Value)
276+ }
277+ g.p(")\n")
278+ }
279+ g.p("// %sHandler handles %s requests.\ntype %sHandler interface{\n", n, it.Name, n)
280+ for _, m := range it.Requests {
281+ g.p("%s(self *%s", camel(m.Name), n)
282+ g.params(m, false)
283+ g.p(")\n")
284+ }
285+ g.p("}\nfunc New%s(c server.Client,version int32,id uint32,h %sHandler)(*%s,error){", n, n, n)
286+ if len(it.Requests) > 0 {
287+ g.p("if h==nil{return nil,fmt.Errorf(%q)}\n", "purego-libwayland: nil handler for "+it.Name)
288+ }
289+ g.p("var self *%s\nr,err:=c.CreateResource(%sInterface,version,id,func(_ *server.Resource,opcode uint32,args []server.Arg){switch opcode{\n", n, n)
290+ for j, m := range it.Requests {
291+ g.p("case %d:h.%s(self", j, camel(m.Name))
292+ idx := 0
293+ for _, a := range m.Args {
294+ if a.Type == "new_id" && a.Interface == "" {
295+ g.p(",args[%d].String(),args[%d].Uint(),args[%d].NewID()", idx, idx+1, idx+2)
296+ idx += 3
297+ continue
298+ }
299+ x := fmt.Sprintf("args[%d]", idx)
300+ idx++
301+ switch a.Type {
302+ case "uint", "int", "fixed", "string", "array", "fd", "new_id":
303+ accessor := camel(a.Type)
304+ if a.Type == "new_id" {
305+ accessor = "NewID"
306+ }
307+ g.p(",%s.%s()", x, accessor)
308+ case "object":
309+ if a.Interface == "" {
310+ g.p(",%s.Resource()", x)
311+ } else {
312+ g.p(",%sWrap%s(%s.Resource())", func() string {
313+ if v := g.owners[a.Interface]; v != "" {
314+ return v + "."
315+ }
316+ return ""
317+ }(), name(a.Interface), x)
318+ }
319+ }
320+ }
321+ g.p(")")
322+ if m.Type == "destructor" {
323+ g.p(";self.Destroy()")
324+ }
325+ g.p("\n")
326+ }
327+ g.p("}});if err!=nil{return nil,err};self=Wrap%s(r);r.Data=self;return self,nil}\n", n)
328+ for _, m := range it.Events {
329+ g.p("// Send%s %s", camel(m.Name), m.Description.Summary)
330+ if m.Since > 1 {
331+ g.p(" (since version %d)", m.Since)
332+ }
333+ g.p(".\nfunc(self *%s)Send%s(", n, camel(m.Name))
334+ for i, a := range m.Args {
335+ if i > 0 {
336+ g.p(",")
337+ }
338+ g.p("%s %s", param(a), g.typ(a, true))
339+ }
340+ g.p("){\n")
341+ needsPin := false
342+ for _, a := range m.Args {
343+ if a.Type == "string" || a.Type == "array" || (a.Type == "new_id" && a.Interface == "") {
344+ needsPin = true
345+ }
346+ }
347+ if needsPin {
348+ g.p("var p runtime.Pinner;defer p.Unpin()\n")
349+ }
350+ g.p("self.PostEvent(%sEvent%s", n, camel(m.Name))
351+ for _, a := range m.Args {
352+ v := param(a)
353+ if a.Type == "new_id" && a.Interface == "" {
354+ g.p(",server.String(&p,%s.Iface().Name,false),server.Uint(uint32(%s.Version())),server.NewID(%s)", v, v, v)
355+ continue
356+ }
357+ switch a.Type {
358+ case "uint", "int", "fd":
359+ g.p(",server.%s(%s)", map[string]string{"uint": "Uint", "int": "Int", "fd": "Fd"}[a.Type], v)
360+ case "fixed":
361+ g.p(",server.FixedArg(%s)", v)
362+ case "string":
363+ g.p(",server.String(&p,%s,%t)", v, a.Nullable)
364+ case "array":
365+ g.p(",server.Array(&p,%s)", v)
366+ case "object", "new_id":
367+ constructor := "Object"
368+ if a.Type == "new_id" {
369+ constructor = "NewID"
370+ }
371+ if a.Interface == "" {
372+ g.p(",server.%s(%s)", constructor, v)
373+ } else {
374+ g.p(",server.%s(resourceOf(%s))", constructor, v)
375+ }
376+ }
377+ }
378+ g.p(")\n}\n")
379+ }
380+ g.p("func New%sGlobal(d *server.Display,version int32,bind server.BindFunc)error{return d.CreateGlobal(%sInterface,version,bind)}\n", n, n)
381+ }
382+ g.p("func resourceOf(v interface{GetResource()*server.Resource})*server.Resource{if v==nil{return nil};return v.GetResource()}\n")
383+ for _, it := range pr.Interfaces {
384+ n := name(it.Name)
385+ g.p("func(self *%s)GetResource()*server.Resource{if self==nil{return nil};return self.Resource}\n", n)
386+ }
387+ return format.Source(g.Bytes())
388+}
389+func main() {
390+ if e := run(); e != nil {
391+ fmt.Fprintln(os.Stderr, e)
392+ os.Exit(1)
393+ }
394+}
395+func run() error {
396+ var im, ix flags
397+ flag.Var(&im, "import", "alias=Go package path")
398+ flag.Var(&ix, "import-xml", "alias=protocol XML")
399+ pkg := flag.String("package", "", "Go package")
400+ out := flag.String("out", "", "output file")
401+ flag.Parse()
402+ if *pkg == "" || *out == "" || flag.NArg() != 1 {
403+ return fmt.Errorf("usage: wlgen -package name -out file [-import alias=path -import-xml alias=xml] protocol.xml")
404+ }
405+ g := &gen{owners: map[string]string{}, imports: map[string]string{}}
406+ for _, s := range im {
407+ a, v, ok := strings.Cut(s, "=")
408+ if !ok {
409+ return fmt.Errorf("invalid import %q", s)
410+ }
411+ g.imports[a] = v
412+ }
413+ for _, s := range ix {
414+ a, v, ok := strings.Cut(s, "=")
415+ if !ok || g.imports[a] == "" {
416+ return fmt.Errorf("invalid import XML %q", s)
417+ }
418+ p, e := parse(v)
419+ if e != nil {
420+ return e
421+ }
422+ for _, it := range p.Interfaces {
423+ g.owners[it.Name] = a
424+ }
425+ }
426+ p, e := parse(flag.Arg(0))
427+ if e != nil {
428+ return e
429+ }
430+ for _, it := range p.Interfaces {
431+ g.owners[it.Name] = ""
432+ }
433+ b, e := g.generate(p, *pkg)
434+ if e != nil {
435+ return e
436+ }
437+ return os.WriteFile(*out, b, 0644)
438+}
A cmd/wlgen/main_test.go +34 -0
@@ -0,0 +1,34 @@
1+package main
2+
3+import (
4+ "strings"
5+ "testing"
6+)
7+
8+func TestUntypedNewIDEvent(t *testing.T) {
9+ g := &gen{owners: map[string]string{"test_device": ""}, imports: map[string]string{}}
10+ b, err := g.generate(protocol{Interfaces: []iface{{Name: "test_device", Version: 1, Events: []message{{Name: "created", Args: []arg{{Name: "id", Type: "new_id"}}}}}}}, "test")
11+ if err != nil {
12+ t.Fatal(err)
13+ }
14+ s := string(b)
15+ if !strings.Contains(s, `Signature: "sun"`) || !strings.Contains(s, `server.String(&p, id.Iface().Name, false), server.Uint(uint32(id.Version())), server.NewID(id)`) {
16+ t.Fatalf("untyped new_id event missing wire args:\n%s", s)
17+ }
18+}
19+
20+func TestSignature(t *testing.T) {
21+ cases := []struct {
22+ m message
23+ want string
24+ }{
25+ {message{Name: "bind", Args: []arg{{Type: "uint"}, {Type: "new_id"}}}, "usun"},
26+ {message{Since: 2, Args: []arg{{Type: "object", Nullable: true}, {Type: "fd"}, {Type: "fixed"}}}, "2?ohf"},
27+ {message{Args: []arg{{Type: "new_id", Interface: "wl_surface"}}}, "n"},
28+ }
29+ for _, c := range cases {
30+ if got := signature(c.m); got != c.want {
31+ t.Errorf("signature(%+v)=%q, want %q", c.m, got, c.want)
32+ }
33+ }
34+}
A internal/e2e/args_test.go +251 -0
@@ -0,0 +1,251 @@
1+package e2e_test
2+
3+import (
4+ "bytes"
5+ "errors"
6+ "testing"
7+ "time"
8+
9+ "github.com/bnema/purego-libwayland/protocol/wayland"
10+ "github.com/bnema/purego-libwayland/server"
11+ "github.com/bnema/wlturbo"
12+ "golang.org/x/sys/unix"
13+)
14+
15+func receive[T any](t *testing.T, ch <-chan T) T {
16+ t.Helper()
17+ select {
18+ case v := <-ch:
19+ return v
20+ case <-time.After(3 * time.Second):
21+ t.Fatal("timed out waiting for event")
22+ var zero T
23+ return zero
24+ }
25+}
26+
27+type argsProxy struct {
28+ wlturbo.BaseProxy
29+ received chan argsEvent
30+ kind string
31+}
32+type argsEvent struct {
33+ text string
34+ data []byte
35+ fixed wlturbo.Fixed
36+ fd int
37+}
38+
39+func (p *argsProxy) Dispatch(e *wlturbo.Event) {
40+ switch p.kind {
41+ case "seat":
42+ p.received <- argsEvent{text: e.String()}
43+ case "keyboard":
44+ if e.Opcode == uint16(wayland.KeyboardEventKeymap) {
45+ _ = e.Uint32()
46+ p.received <- argsEvent{fd: int(e.Fd())}
47+ } else if e.Opcode == uint16(wayland.KeyboardEventEnter) {
48+ _ = e.Uint32()
49+ _ = e.Uint32()
50+ p.received <- argsEvent{data: e.Array()}
51+ }
52+ case "pointer":
53+ _ = e.Uint32()
54+ p.received <- argsEvent{fixed: e.Fixed()}
55+ }
56+}
57+
58+type sourceHandler struct{ requests chan string }
59+
60+func (h sourceHandler) Offer(_ *wayland.DataSource, mimeType string) { h.requests <- mimeType }
61+func (sourceHandler) Destroy(*wayland.DataSource) {}
62+func (sourceHandler) SetActions(*wayland.DataSource, uint32) {}
63+
64+type managerHandler struct {
65+ requests chan string
66+ t *testing.T
67+}
68+
69+func (h managerHandler) CreateDataSource(self *wayland.DataDeviceManager, id uint32) {
70+ if _, err := wayland.NewDataSource(self.Client(), 1, id, sourceHandler{h.requests}); err != nil {
71+ h.t.Error(err)
72+ }
73+}
74+func (managerHandler) GetDataDevice(*wayland.DataDeviceManager, uint32, *wayland.Seat) {}
75+func (managerHandler) Release(*wayland.DataDeviceManager) {}
76+
77+type shmHandler struct {
78+ requests chan string
79+ t *testing.T
80+}
81+
82+func (h shmHandler) CreatePool(self *wayland.Shm, id uint32, fd int, size int32) {
83+ defer unix.Close(fd)
84+ h.requests <- "pool"
85+ if _, err := wayland.NewShmPool(self.Client(), 1, id, poolHandler{}); err != nil {
86+ h.t.Error(err)
87+ }
88+}
89+func (shmHandler) Release(*wayland.Shm) {}
90+
91+type poolHandler struct{}
92+
93+func (poolHandler) CreateBuffer(*wayland.ShmPool, uint32, int32, int32, int32, int32, uint32) {}
94+func (poolHandler) Destroy(*wayland.ShmPool) {}
95+func (poolHandler) Resize(self *wayland.ShmPool, size int32) { self.PostError(7, "bad % request") }
96+
97+type seatHandler struct{ t *testing.T }
98+
99+type noPointerRequests struct{}
100+
101+func (noPointerRequests) SetCursor(*wayland.Pointer, uint32, *wayland.Surface, int32, int32) {}
102+func (noPointerRequests) Release(*wayland.Pointer) {}
103+
104+type noKeyboardRequests struct{}
105+
106+func (noKeyboardRequests) Release(*wayland.Keyboard) {}
107+
108+func (h seatHandler) GetPointer(self *wayland.Seat, id uint32) {
109+ p, err := wayland.NewPointer(self.Client(), 1, id, noPointerRequests{})
110+ if err != nil {
111+ h.t.Error(err)
112+ return
113+ }
114+ p.SendMotion(42, server.FixedFromFloat(-1.5), 0)
115+}
116+func (h seatHandler) GetKeyboard(self *wayland.Seat, id uint32) {
117+ k, err := wayland.NewKeyboard(self.Client(), 1, id, noKeyboardRequests{})
118+ if err != nil {
119+ h.t.Error(err)
120+ return
121+ }
122+ fds := []int{0, 0}
123+ if err := unix.Pipe(fds); err != nil {
124+ h.t.Error(err)
125+ return
126+ }
127+ defer unix.Close(fds[0])
128+ defer unix.Close(fds[1])
129+ if _, err := unix.Write(fds[1], []byte("fd contents")); err != nil {
130+ h.t.Error(err)
131+ return
132+ }
133+ k.SendKeymap(1, fds[0], 11)
134+ k.SendEnter(1, wayland.WrapSurface(self.Resource), []byte{1, 2, 3})
135+}
136+func (seatHandler) GetTouch(*wayland.Seat, uint32) {}
137+func (seatHandler) Release(*wayland.Seat) {}
138+func TestArgumentRoundtripAndPostError(t *testing.T) {
139+ socket, d, _ := startServer(t)
140+ requests := make(chan string, 1)
141+ stringsReceived := make(chan string, 1)
142+ d.Do(func() {
143+ if err := wayland.NewDataDeviceManagerGlobal(d, 1, func(c server.Client, v, id uint32) {
144+ if _, e := wayland.NewDataDeviceManager(c, int32(v), id, managerHandler{stringsReceived, t}); e != nil {
145+ t.Error(e)
146+ }
147+ }); err != nil {
148+ t.Error(err)
149+ }
150+ if err := wayland.NewShmGlobal(d, 1, func(c server.Client, v, id uint32) {
151+ if _, e := wayland.NewShm(c, int32(v), id, shmHandler{requests, t}); e != nil {
152+ t.Error(e)
153+ }
154+ }); err != nil {
155+ t.Error(err)
156+ }
157+ if err := wayland.NewSeatGlobal(d, 1, func(c server.Client, v, id uint32) {
158+ s, e := wayland.NewSeat(c, int32(v), id, seatHandler{t})
159+ if e != nil {
160+ t.Error(e)
161+ return
162+ }
163+ s.SendName("hello")
164+ }); err != nil {
165+ t.Error(err)
166+ }
167+ })
168+ c, err := wlturbo.Connect(socket)
169+ must(t, err)
170+ defer c.Close()
171+ must(t, c.Roundtrip())
172+ bind := func(name string) (uint32, *argsProxy) {
173+ t.Helper()
174+ g, ok := c.Registry().FindGlobal(name)
175+ if !ok {
176+ t.Fatalf("%s missing", name)
177+ }
178+ id, e := c.Registry().BindID(g.Name, g.Interface, 1)
179+ must(t, e)
180+ p := &argsProxy{received: make(chan argsEvent, 4), kind: name[3:]}
181+ p.SetID(id)
182+ c.Context().Register(p)
183+ return id, p
184+ }
185+ manager, _ := bind("wl_data_device_manager")
186+ seat, sp := bind("wl_seat")
187+ shm, _ := bind("wl_shm")
188+ source := c.AllocateID()
189+ must(t, c.SendRequest(manager, uint16(wayland.DataDeviceManagerRequestCreateDataSource), source))
190+ must(t, c.SendRequest(source, uint16(wayland.DataSourceRequestOffer), "request text"))
191+ pool := c.AllocateID()
192+ fds := []int{0, 0}
193+ must(t, unix.Pipe(fds))
194+ defer unix.Close(fds[0])
195+ defer unix.Close(fds[1])
196+ must(t, c.SendRequestWithFDs(shm, uint16(wayland.ShmRequestCreatePool), []int{fds[0]}, pool, uint32(0), int32(4096)))
197+ keyboard := c.AllocateID()
198+ kp := &argsProxy{received: make(chan argsEvent, 4), kind: "keyboard"}
199+ kp.SetID(keyboard)
200+ c.Context().Register(kp)
201+ pointer := c.AllocateID()
202+ pp := &argsProxy{received: make(chan argsEvent, 4), kind: "pointer"}
203+ pp.SetID(pointer)
204+ c.Context().Register(pp)
205+ must(t, c.SendRequest(seat, uint16(wayland.SeatRequestGetKeyboard), keyboard))
206+ must(t, c.SendRequest(seat, uint16(wayland.SeatRequestGetPointer), pointer))
207+ must(t, c.Roundtrip())
208+ if text := receive(t, stringsReceived); text != "request text" {
209+ t.Fatalf("string request = %q", text)
210+ }
211+ if receive(t, requests) != "pool" {
212+ t.Fatal("fd request missing")
213+ }
214+ if e := receive(t, sp.received); e.text != "hello" {
215+ t.Fatalf("string event: %+v", e)
216+ }
217+ a, b := receive(t, kp.received), receive(t, kp.received)
218+ if a.fd <= 0 || !bytes.Equal(b.data, []byte{1, 2, 3}) {
219+ t.Fatalf("keyboard events: %+v %+v", a, b)
220+ }
221+ buf := make([]byte, 32)
222+ n, e := unix.Read(a.fd, buf)
223+ unix.Close(a.fd)
224+ if e != nil || string(buf[:n]) != "fd contents" {
225+ t.Fatalf("fd: %q %v", buf[:n], e)
226+ }
227+ if e := receive(t, pp.received); e.fixed.Float64() != -1.5 {
228+ t.Fatalf("fixed: %+v", e)
229+ }
230+ must(t, c.SendRequest(pool, uint16(wayland.ShmPoolRequestResize), int32(8192)))
231+ result := make(chan error, 1)
232+ go func() {
233+ for i := 0; i < 10; i++ {
234+ if err := c.Dispatch(); err != nil {
235+ result <- err
236+ return
237+ }
238+ }
239+ result <- nil
240+ }()
241+ select {
242+ case err := <-result:
243+ var displayErr *wlturbo.DisplayError
244+ if !errors.As(err, &displayErr) || displayErr.ObjectID != pool || displayErr.Code != 7 || displayErr.Message != "bad % request" {
245+ t.Fatalf("PostError result = %v", err)
246+ }
247+ case <-time.After(3 * time.Second):
248+ t.Fatal("client did not disconnect after PostError")
249+ }
250+
251+}
R internal/proto/feasibility_test.go → internal/e2e/feasibility_test.go +68 -43 renamed, 58% similar
@@ -1,4 +1,4 @@
1-package proto_test
1+package e2e_test
22
33 import (
44 "context"
@@ -8,7 +8,7 @@ import (
88 "testing"
99 "time"
1010
11- "github.com/bnema/purego-libwayland/internal/proto"
11+ "github.com/bnema/purego-libwayland/protocol/wayland"
1212 "github.com/bnema/purego-libwayland/server"
1313 "github.com/bnema/wlturbo"
1414 "golang.org/x/sys/unix"
@@ -18,9 +18,6 @@ import (
1818 // commits counts wl_surface.commit requests received by Go handlers.
1919 func startServer(t *testing.T) (socket string, d *server.Display, commits chan uint32) {
2020 t.Helper()
21- if err := proto.Init(); err != nil {
22- t.Fatal(err)
23- }
2421 d, err := server.NewDisplay()
2522 if err != nil {
2623 t.Fatal(err)
@@ -43,38 +40,10 @@ func startServer(t *testing.T) (socket string, d *server.Display, commits chan u
4340
4441 commits = make(chan uint32, 16)
4542 var serial uint32
46- surface := func(r *server.Resource, op uint32, args []server.Arg) {
47- switch op {
48- case proto.SurfaceDestroy:
49- r.Destroy()
50- case proto.SurfaceFrame:
51- cb, err := r.Client().CreateResource(proto.Callback, 1, args[0].NewID(), nil)
52- if err != nil {
53- t.Error(err)
54- return
55- }
56- serial++
57- cb.PostEvent(proto.CallbackDone, server.Uint(serial))
58- cb.Destroy()
59- case proto.SurfaceCommit:
60- commits <- r.ID()
61- }
62- }
63- compositor := func(r *server.Resource, op uint32, args []server.Arg) {
64- iface, h := proto.Surface, server.Handler(surface)
65- if op == proto.CompositorCreateRegion {
66- iface, h = proto.Region, func(r *server.Resource, op uint32, _ []server.Arg) {
67- if op == proto.RegionDestroy {
68- r.Destroy()
69- }
70- }
71- }
72- if _, err := r.Client().CreateResource(iface, r.Version(), args[0].NewID(), h); err != nil {
73- t.Error(err)
74- }
75- }
76- err = d.CreateGlobal(proto.Compositor, 1, func(c server.Client, version, id uint32) {
77- if _, err := c.CreateResource(proto.Compositor, int32(version), id, compositor); err != nil {
43+ surface := &surfaceHandler{commits: commits, serial: &serial, t: t}
44+ compositor := &compositorHandler{surface: surface, t: t}
45+ err = wayland.NewCompositorGlobal(d, 1, func(c server.Client, version, id uint32) {
46+ if _, err := wayland.NewCompositor(c, int32(version), id, compositor); err != nil {
7847 t.Error(err)
7948 }
8049 })
@@ -87,8 +56,13 @@ func startServer(t *testing.T) (socket string, d *server.Display, commits chan u
8756 go func() { done <- d.Run(ctx) }()
8857 t.Cleanup(func() {
8958 cancel()
90- if err := <-done; err != nil {
91- t.Error(err)
59+ select {
60+ case err := <-done:
61+ if err != nil {
62+ t.Error(err)
63+ }
64+ case <-time.After(3 * time.Second):
65+ t.Fatal("server did not stop")
9266 }
9367 })
9468 return socket, d, commits
@@ -135,14 +109,14 @@ func TestRequestEventRoundtripAndDisconnect(t *testing.T) {
135109 t.Fatal(err)
136110 }
137111 surf := c.AllocateID()
138- must(t, c.SendRequest(comp, proto.CompositorCreateSurface, surf))
112+ must(t, c.SendRequest(comp, uint16(wayland.CompositorRequestCreateSurface), surf))
139113 cb := c.AllocateID()
140114 gotDone := make(chan uint32, 1)
141115 cbProxy := &doneProxy{done: gotDone}
142116 cbProxy.SetID(cb)
143117 c.Context().Register(cbProxy)
144- must(t, c.SendRequest(surf, proto.SurfaceFrame, cb))
145- must(t, c.SendRequest(surf, proto.SurfaceCommit))
118+ must(t, c.SendRequest(surf, uint16(wayland.SurfaceRequestFrame), cb))
119+ must(t, c.SendRequest(surf, uint16(wayland.SurfaceRequestCommit)))
146120 must(t, c.Roundtrip())
147121
148122 select {
@@ -186,7 +160,7 @@ type doneProxy struct {
186160 }
187161
188162 func (p *doneProxy) Dispatch(e *wlturbo.Event) {
189- if e.Opcode == proto.CallbackDone {
163+ if e.Opcode == uint16(wayland.CallbackEventDone) {
190164 p.done <- e.Uint32()
191165 }
192166 }
@@ -197,3 +171,54 @@ func must(t *testing.T, err error) {
197171 t.Fatal(err)
198172 }
199173 }
174+
175+type compositorHandler struct {
176+ surface *surfaceHandler
177+ t *testing.T
178+}
179+
180+func (h *compositorHandler) CreateSurface(self *wayland.Compositor, id uint32) {
181+ if _, err := wayland.NewSurface(self.Client(), self.Version(), id, h.surface); err != nil {
182+ h.t.Error(err)
183+ }
184+}
185+func (h *compositorHandler) CreateRegion(self *wayland.Compositor, id uint32) {
186+ if _, err := wayland.NewRegion(self.Client(), self.Version(), id, regionHandler{}); err != nil {
187+ h.t.Error(err)
188+ }
189+}
190+func (*compositorHandler) Release(*wayland.Compositor) {}
191+
192+type regionHandler struct{}
193+
194+func (regionHandler) Destroy(*wayland.Region) {}
195+func (regionHandler) Add(*wayland.Region, int32, int32, int32, int32) {}
196+func (regionHandler) Subtract(*wayland.Region, int32, int32, int32, int32) {}
197+
198+type surfaceHandler struct {
199+ commits chan uint32
200+ serial *uint32
201+ t *testing.T
202+}
203+
204+func (*surfaceHandler) Destroy(*wayland.Surface) {}
205+func (*surfaceHandler) Attach(*wayland.Surface, *wayland.Buffer, int32, int32) {}
206+func (*surfaceHandler) Damage(*wayland.Surface, int32, int32, int32, int32) {}
207+func (h *surfaceHandler) Frame(self *wayland.Surface, id uint32) {
208+ cb, err := wayland.NewCallback(self.Client(), 1, id, nil)
209+ if err != nil {
210+ h.t.Error(err)
211+ return
212+ }
213+ *h.serial++
214+ cb.SendDone(*h.serial)
215+ cb.Destroy()
216+}
217+func (*surfaceHandler) SetOpaqueRegion(*wayland.Surface, *wayland.Region) {}
218+func (*surfaceHandler) SetInputRegion(*wayland.Surface, *wayland.Region) {}
219+func (h *surfaceHandler) Commit(self *wayland.Surface) { h.commits <- self.ID() }
220+func (*surfaceHandler) SetBufferTransform(*wayland.Surface, int32) {}
221+func (*surfaceHandler) SetBufferScale(*wayland.Surface, int32) {}
222+func (*surfaceHandler) DamageBuffer(*wayland.Surface, int32, int32, int32, int32) {}
223+func (*surfaceHandler) Offset(*wayland.Surface, int32, int32) {}
224+func (*surfaceHandler) GetRelease(*wayland.Surface, uint32) {}
D internal/proto/core.go +0 -55
@@ -1,55 +0,0 @@
1-// Package proto holds hand-written core interfaces for the feasibility
2-// prototype. The generator replaces this package.
3-package proto
4-
5-import (
6- "sync"
7-
8- "github.com/bnema/purego-libwayland/server"
9-)
10-
11-var (
12- Compositor = &server.Interface{Name: "wl_compositor", Version: 1}
13- Surface = &server.Interface{Name: "wl_surface", Version: 1}
14- Region = &server.Interface{Name: "wl_region", Version: 1}
15- Callback = &server.Interface{Name: "wl_callback", Version: 1}
16-)
17-
18-// Opcodes used by the prototype.
19-const (
20- CompositorCreateSurface = 0
21- CompositorCreateRegion = 1
22- SurfaceDestroy = 0
23- SurfaceFrame = 3
24- SurfaceCommit = 6
25- RegionDestroy = 0
26- CallbackDone = 0
27-)
28-
29-var initOnce = sync.OnceValue(initInterfaces)
30-
31-// Init builds the C tables once per process.
32-func Init() error { return initOnce() }
33-
34-func initInterfaces() error {
35- Compositor.Requests = []server.Message{
36- {Name: "create_surface", Signature: "n", Types: []*server.Interface{Surface}},
37- {Name: "create_region", Signature: "n", Types: []*server.Interface{Region}},
38- }
39- Surface.Requests = []server.Message{
40- {Name: "destroy", Signature: ""},
41- {Name: "attach", Signature: "?oii", Types: []*server.Interface{nil, nil, nil}},
42- {Name: "damage", Signature: "iiii"},
43- {Name: "frame", Signature: "n", Types: []*server.Interface{Callback}},
44- {Name: "set_opaque_region", Signature: "?o", Types: []*server.Interface{Region}},
45- {Name: "set_input_region", Signature: "?o", Types: []*server.Interface{Region}},
46- {Name: "commit", Signature: ""},
47- }
48- Region.Requests = []server.Message{
49- {Name: "destroy", Signature: ""},
50- {Name: "add", Signature: "iiii"},
51- {Name: "subtract", Signature: "iiii"},
52- }
53- Callback.Events = []server.Message{{Name: "done", Signature: "u"}}
54- return server.NewInterfaces(Compositor, Surface, Region, Callback)
55-}
A protocol/gen.go +5 -0
@@ -0,0 +1,5 @@
1+// Package protocol holds generated server bindings for vendored Wayland protocols.
2+package protocol
3+
4+//go:generate go run ../cmd/wlgen -package wayland -out wayland/wayland.go ../protocols/wayland.xml
5+//go:generate go run ../cmd/wlgen -package xdgshell -out xdgshell/xdgshell.go -import wayland=github.com/bnema/purego-libwayland/protocol/wayland -import-xml wayland=../protocols/wayland.xml ../protocols/xdg-shell.xml
A protocol/wayland/wayland.go +2320 -0
@@ -0,0 +1,2320 @@
1+// Code generated by wlgen; DO NOT EDIT.
2+package wayland
3+
4+import (
5+ "fmt"
6+ "github.com/bnema/purego-libwayland/server"
7+ "runtime"
8+)
9+
10+var DisplayInterface *server.Interface
11+var RegistryInterface *server.Interface
12+var CallbackInterface *server.Interface
13+var CompositorInterface *server.Interface
14+var ShmPoolInterface *server.Interface
15+var ShmInterface *server.Interface
16+var BufferInterface *server.Interface
17+var DataOfferInterface *server.Interface
18+var DataSourceInterface *server.Interface
19+var DataDeviceInterface *server.Interface
20+var DataDeviceManagerInterface *server.Interface
21+var ShellInterface *server.Interface
22+var ShellSurfaceInterface *server.Interface
23+var SurfaceInterface *server.Interface
24+var SeatInterface *server.Interface
25+var PointerInterface *server.Interface
26+var KeyboardInterface *server.Interface
27+var TouchInterface *server.Interface
28+var OutputInterface *server.Interface
29+var RegionInterface *server.Interface
30+var SubcompositorInterface *server.Interface
31+var SubsurfaceInterface *server.Interface
32+var FixesInterface *server.Interface
33+
34+func init() {
35+ DisplayInterface = &server.Interface{Name: "wl_display", Version: 1}
36+ RegistryInterface = &server.Interface{Name: "wl_registry", Version: 1}
37+ CallbackInterface = &server.Interface{Name: "wl_callback", Version: 1}
38+ CompositorInterface = &server.Interface{Name: "wl_compositor", Version: 7}
39+ ShmPoolInterface = &server.Interface{Name: "wl_shm_pool", Version: 3}
40+ ShmInterface = &server.Interface{Name: "wl_shm", Version: 3}
41+ BufferInterface = &server.Interface{Name: "wl_buffer", Version: 1}
42+ DataOfferInterface = &server.Interface{Name: "wl_data_offer", Version: 4}
43+ DataSourceInterface = &server.Interface{Name: "wl_data_source", Version: 4}
44+ DataDeviceInterface = &server.Interface{Name: "wl_data_device", Version: 4}
45+ DataDeviceManagerInterface = &server.Interface{Name: "wl_data_device_manager", Version: 4}
46+ ShellInterface = &server.Interface{Name: "wl_shell", Version: 1}
47+ ShellSurfaceInterface = &server.Interface{Name: "wl_shell_surface", Version: 1}
48+ SurfaceInterface = &server.Interface{Name: "wl_surface", Version: 7}
49+ SeatInterface = &server.Interface{Name: "wl_seat", Version: 11}
50+ PointerInterface = &server.Interface{Name: "wl_pointer", Version: 11}
51+ KeyboardInterface = &server.Interface{Name: "wl_keyboard", Version: 11}
52+ TouchInterface = &server.Interface{Name: "wl_touch", Version: 11}
53+ OutputInterface = &server.Interface{Name: "wl_output", Version: 4}
54+ RegionInterface = &server.Interface{Name: "wl_region", Version: 7}
55+ SubcompositorInterface = &server.Interface{Name: "wl_subcompositor", Version: 1}
56+ SubsurfaceInterface = &server.Interface{Name: "wl_subsurface", Version: 1}
57+ FixesInterface = &server.Interface{Name: "wl_fixes", Version: 2}
58+ DisplayInterface.Requests = []server.Message{
59+ {Name: "sync", Signature: "n", Types: []*server.Interface{CallbackInterface}},
60+ {Name: "get_registry", Signature: "n", Types: []*server.Interface{RegistryInterface}},
61+ }
62+ DisplayInterface.Events = []server.Message{
63+ {Name: "error", Signature: "ous", Types: []*server.Interface{nil, nil, nil}},
64+ {Name: "delete_id", Signature: "u", Types: []*server.Interface{nil}},
65+ }
66+ RegistryInterface.Requests = []server.Message{
67+ {Name: "bind", Signature: "usun", Types: []*server.Interface{nil, nil, nil, nil}},
68+ }
69+ RegistryInterface.Events = []server.Message{
70+ {Name: "global", Signature: "usu", Types: []*server.Interface{nil, nil, nil}},
71+ {Name: "global_remove", Signature: "u", Types: []*server.Interface{nil}},
72+ }
73+ CallbackInterface.Requests = []server.Message{}
74+ CallbackInterface.Events = []server.Message{
75+ {Name: "done", Signature: "u", Types: []*server.Interface{nil}},
76+ }
77+ CompositorInterface.Requests = []server.Message{
78+ {Name: "create_surface", Signature: "n", Types: []*server.Interface{SurfaceInterface}},
79+ {Name: "create_region", Signature: "n", Types: []*server.Interface{RegionInterface}},
80+ {Name: "release", Signature: "7", Types: []*server.Interface{}},
81+ }
82+ CompositorInterface.Events = []server.Message{}
83+ ShmPoolInterface.Requests = []server.Message{
84+ {Name: "create_buffer", Signature: "niiiiu", Types: []*server.Interface{BufferInterface, nil, nil, nil, nil, nil}},
85+ {Name: "destroy", Signature: "", Types: []*server.Interface{}},
86+ {Name: "resize", Signature: "i", Types: []*server.Interface{nil}},
87+ }
88+ ShmPoolInterface.Events = []server.Message{}
89+ ShmInterface.Requests = []server.Message{
90+ {Name: "create_pool", Signature: "nhi", Types: []*server.Interface{ShmPoolInterface, nil, nil}},
91+ {Name: "release", Signature: "2", Types: []*server.Interface{}},
92+ }
93+ ShmInterface.Events = []server.Message{
94+ {Name: "format", Signature: "u", Types: []*server.Interface{nil}},
95+ }
96+ BufferInterface.Requests = []server.Message{
97+ {Name: "destroy", Signature: "", Types: []*server.Interface{}},
98+ }
99+ BufferInterface.Events = []server.Message{
100+ {Name: "release", Signature: "", Types: []*server.Interface{}},
101+ }
102+ DataOfferInterface.Requests = []server.Message{
103+ {Name: "accept", Signature: "u?s", Types: []*server.Interface{nil, nil}},
104+ {Name: "receive", Signature: "sh", Types: []*server.Interface{nil, nil}},
105+ {Name: "destroy", Signature: "", Types: []*server.Interface{}},
106+ {Name: "finish", Signature: "3", Types: []*server.Interface{}},
107+ {Name: "set_actions", Signature: "3uu", Types: []*server.Interface{nil, nil}},
108+ }
109+ DataOfferInterface.Events = []server.Message{
110+ {Name: "offer", Signature: "s", Types: []*server.Interface{nil}},
111+ {Name: "source_actions", Signature: "3u", Types: []*server.Interface{nil}},
112+ {Name: "action", Signature: "3u", Types: []*server.Interface{nil}},
113+ }
114+ DataSourceInterface.Requests = []server.Message{
115+ {Name: "offer", Signature: "s", Types: []*server.Interface{nil}},
116+ {Name: "destroy", Signature: "", Types: []*server.Interface{}},
117+ {Name: "set_actions", Signature: "3u", Types: []*server.Interface{nil}},
118+ }
119+ DataSourceInterface.Events = []server.Message{
120+ {Name: "target", Signature: "?s", Types: []*server.Interface{nil}},
121+ {Name: "send", Signature: "sh", Types: []*server.Interface{nil, nil}},
122+ {Name: "cancelled", Signature: "", Types: []*server.Interface{}},
123+ {Name: "dnd_drop_performed", Signature: "3", Types: []*server.Interface{}},
124+ {Name: "dnd_finished", Signature: "3", Types: []*server.Interface{}},
125+ {Name: "action", Signature: "3u", Types: []*server.Interface{nil}},
126+ }
127+ DataDeviceInterface.Requests = []server.Message{
128+ {Name: "start_drag", Signature: "?oo?ou", Types: []*server.Interface{DataSourceInterface, SurfaceInterface, SurfaceInterface, nil}},
129+ {Name: "set_selection", Signature: "?ou", Types: []*server.Interface{DataSourceInterface, nil}},
130+ {Name: "release", Signature: "2", Types: []*server.Interface{}},
131+ }
132+ DataDeviceInterface.Events = []server.Message{
133+ {Name: "data_offer", Signature: "n", Types: []*server.Interface{DataOfferInterface}},
134+ {Name: "enter", Signature: "uoff?o", Types: []*server.Interface{nil, SurfaceInterface, nil, nil, DataOfferInterface}},
135+ {Name: "leave", Signature: "", Types: []*server.Interface{}},
136+ {Name: "motion", Signature: "uff", Types: []*server.Interface{nil, nil, nil}},
137+ {Name: "drop", Signature: "", Types: []*server.Interface{}},
138+ {Name: "selection", Signature: "?o", Types: []*server.Interface{DataOfferInterface}},
139+ }
140+ DataDeviceManagerInterface.Requests = []server.Message{
141+ {Name: "create_data_source", Signature: "n", Types: []*server.Interface{DataSourceInterface}},
142+ {Name: "get_data_device", Signature: "no", Types: []*server.Interface{DataDeviceInterface, SeatInterface}},
143+ {Name: "release", Signature: "4", Types: []*server.Interface{}},
144+ }
145+ DataDeviceManagerInterface.Events = []server.Message{}
146+ ShellInterface.Requests = []server.Message{
147+ {Name: "get_shell_surface", Signature: "no", Types: []*server.Interface{ShellSurfaceInterface, SurfaceInterface}},
148+ }
149+ ShellInterface.Events = []server.Message{}
150+ ShellSurfaceInterface.Requests = []server.Message{
151+ {Name: "pong", Signature: "u", Types: []*server.Interface{nil}},
152+ {Name: "move", Signature: "ou", Types: []*server.Interface{SeatInterface, nil}},
153+ {Name: "resize", Signature: "ouu", Types: []*server.Interface{SeatInterface, nil, nil}},
154+ {Name: "set_toplevel", Signature: "", Types: []*server.Interface{}},
155+ {Name: "set_transient", Signature: "oiiu", Types: []*server.Interface{SurfaceInterface, nil, nil, nil}},
156+ {Name: "set_fullscreen", Signature: "uu?o", Types: []*server.Interface{nil, nil, OutputInterface}},
157+ {Name: "set_popup", Signature: "ouoiiu", Types: []*server.Interface{SeatInterface, nil, SurfaceInterface, nil, nil, nil}},
158+ {Name: "set_maximized", Signature: "?o", Types: []*server.Interface{OutputInterface}},
159+ {Name: "set_title", Signature: "s", Types: []*server.Interface{nil}},
160+ {Name: "set_class", Signature: "s", Types: []*server.Interface{nil}},
161+ }
162+ ShellSurfaceInterface.Events = []server.Message{
163+ {Name: "ping", Signature: "u", Types: []*server.Interface{nil}},
164+ {Name: "configure", Signature: "uii", Types: []*server.Interface{nil, nil, nil}},
165+ {Name: "popup_done", Signature: "", Types: []*server.Interface{}},
166+ }
167+ SurfaceInterface.Requests = []server.Message{
168+ {Name: "destroy", Signature: "", Types: []*server.Interface{}},
169+ {Name: "attach", Signature: "?oii", Types: []*server.Interface{BufferInterface, nil, nil}},
170+ {Name: "damage", Signature: "iiii", Types: []*server.Interface{nil, nil, nil, nil}},
171+ {Name: "frame", Signature: "n", Types: []*server.Interface{CallbackInterface}},
172+ {Name: "set_opaque_region", Signature: "?o", Types: []*server.Interface{RegionInterface}},
173+ {Name: "set_input_region", Signature: "?o", Types: []*server.Interface{RegionInterface}},
174+ {Name: "commit", Signature: "", Types: []*server.Interface{}},
175+ {Name: "set_buffer_transform", Signature: "2i", Types: []*server.Interface{nil}},
176+ {Name: "set_buffer_scale", Signature: "3i", Types: []*server.Interface{nil}},
177+ {Name: "damage_buffer", Signature: "4iiii", Types: []*server.Interface{nil, nil, nil, nil}},
178+ {Name: "offset", Signature: "5ii", Types: []*server.Interface{nil, nil}},
179+ {Name: "get_release", Signature: "7n", Types: []*server.Interface{CallbackInterface}},
180+ }
181+ SurfaceInterface.Events = []server.Message{
182+ {Name: "enter", Signature: "o", Types: []*server.Interface{OutputInterface}},
183+ {Name: "leave", Signature: "o", Types: []*server.Interface{OutputInterface}},
184+ {Name: "preferred_buffer_scale", Signature: "6i", Types: []*server.Interface{nil}},
185+ {Name: "preferred_buffer_transform", Signature: "6u", Types: []*server.Interface{nil}},
186+ }
187+ SeatInterface.Requests = []server.Message{
188+ {Name: "get_pointer", Signature: "n", Types: []*server.Interface{PointerInterface}},
189+ {Name: "get_keyboard", Signature: "n", Types: []*server.Interface{KeyboardInterface}},
190+ {Name: "get_touch", Signature: "n", Types: []*server.Interface{TouchInterface}},
191+ {Name: "release", Signature: "5", Types: []*server.Interface{}},
192+ }
193+ SeatInterface.Events = []server.Message{
194+ {Name: "capabilities", Signature: "u", Types: []*server.Interface{nil}},
195+ {Name: "name", Signature: "2s", Types: []*server.Interface{nil}},
196+ }
197+ PointerInterface.Requests = []server.Message{
198+ {Name: "set_cursor", Signature: "u?oii", Types: []*server.Interface{nil, SurfaceInterface, nil, nil}},
199+ {Name: "release", Signature: "3", Types: []*server.Interface{}},
200+ }
201+ PointerInterface.Events = []server.Message{
202+ {Name: "enter", Signature: "uoff", Types: []*server.Interface{nil, SurfaceInterface, nil, nil}},
203+ {Name: "leave", Signature: "uo", Types: []*server.Interface{nil, SurfaceInterface}},
204+ {Name: "motion", Signature: "uff", Types: []*server.Interface{nil, nil, nil}},
205+ {Name: "button", Signature: "uuuu", Types: []*server.Interface{nil, nil, nil, nil}},
206+ {Name: "axis", Signature: "uuf", Types: []*server.Interface{nil, nil, nil}},
207+ {Name: "frame", Signature: "5", Types: []*server.Interface{}},
208+ {Name: "axis_source", Signature: "5u", Types: []*server.Interface{nil}},
209+ {Name: "axis_stop", Signature: "5uu", Types: []*server.Interface{nil, nil}},
210+ {Name: "axis_discrete", Signature: "5ui", Types: []*server.Interface{nil, nil}},
211+ {Name: "axis_value120", Signature: "8ui", Types: []*server.Interface{nil, nil}},
212+ {Name: "axis_relative_direction", Signature: "9uu", Types: []*server.Interface{nil, nil}},
213+ {Name: "warp", Signature: "11ff", Types: []*server.Interface{nil, nil}},
214+ }
215+ KeyboardInterface.Requests = []server.Message{
216+ {Name: "release", Signature: "3", Types: []*server.Interface{}},
217+ }
218+ KeyboardInterface.Events = []server.Message{
219+ {Name: "keymap", Signature: "uhu", Types: []*server.Interface{nil, nil, nil}},
220+ {Name: "enter", Signature: "uoa", Types: []*server.Interface{nil, SurfaceInterface, nil}},
221+ {Name: "leave", Signature: "uo", Types: []*server.Interface{nil, SurfaceInterface}},
222+ {Name: "key", Signature: "uuuu", Types: []*server.Interface{nil, nil, nil, nil}},
223+ {Name: "modifiers", Signature: "uuuuu", Types: []*server.Interface{nil, nil, nil, nil, nil}},
224+ {Name: "repeat_info", Signature: "4ii", Types: []*server.Interface{nil, nil}},
225+ }
226+ TouchInterface.Requests = []server.Message{
227+ {Name: "release", Signature: "3", Types: []*server.Interface{}},
228+ }
229+ TouchInterface.Events = []server.Message{
230+ {Name: "down", Signature: "uuoiff", Types: []*server.Interface{nil, nil, SurfaceInterface, nil, nil, nil}},
231+ {Name: "up", Signature: "uui", Types: []*server.Interface{nil, nil, nil}},
232+ {Name: "motion", Signature: "uiff", Types: []*server.Interface{nil, nil, nil, nil}},
233+ {Name: "frame", Signature: "", Types: []*server.Interface{}},
234+ {Name: "cancel", Signature: "", Types: []*server.Interface{}},
235+ {Name: "shape", Signature: "6iff", Types: []*server.Interface{nil, nil, nil}},
236+ {Name: "orientation", Signature: "6if", Types: []*server.Interface{nil, nil}},
237+ }
238+ OutputInterface.Requests = []server.Message{
239+ {Name: "release", Signature: "3", Types: []*server.Interface{}},
240+ }
241+ OutputInterface.Events = []server.Message{
242+ {Name: "geometry", Signature: "iiiiissi", Types: []*server.Interface{nil, nil, nil, nil, nil, nil, nil, nil}},
243+ {Name: "mode", Signature: "uiii", Types: []*server.Interface{nil, nil, nil, nil}},
244+ {Name: "done", Signature: "2", Types: []*server.Interface{}},
245+ {Name: "scale", Signature: "2i", Types: []*server.Interface{nil}},
246+ {Name: "name", Signature: "4s", Types: []*server.Interface{nil}},
247+ {Name: "description", Signature: "4s", Types: []*server.Interface{nil}},
248+ }
249+ RegionInterface.Requests = []server.Message{
250+ {Name: "destroy", Signature: "", Types: []*server.Interface{}},
251+ {Name: "add", Signature: "iiii", Types: []*server.Interface{nil, nil, nil, nil}},
252+ {Name: "subtract", Signature: "iiii", Types: []*server.Interface{nil, nil, nil, nil}},
253+ }
254+ RegionInterface.Events = []server.Message{}
255+ SubcompositorInterface.Requests = []server.Message{
256+ {Name: "destroy", Signature: "", Types: []*server.Interface{}},
257+ {Name: "get_subsurface", Signature: "noo", Types: []*server.Interface{SubsurfaceInterface, SurfaceInterface, SurfaceInterface}},
258+ }
259+ SubcompositorInterface.Events = []server.Message{}
260+ SubsurfaceInterface.Requests = []server.Message{
261+ {Name: "destroy", Signature: "", Types: []*server.Interface{}},
262+ {Name: "set_position", Signature: "ii", Types: []*server.Interface{nil, nil}},
263+ {Name: "place_above", Signature: "o", Types: []*server.Interface{SurfaceInterface}},
264+ {Name: "place_below", Signature: "o", Types: []*server.Interface{SurfaceInterface}},
265+ {Name: "set_sync", Signature: "", Types: []*server.Interface{}},
266+ {Name: "set_desync", Signature: "", Types: []*server.Interface{}},
267+ }
268+ SubsurfaceInterface.Events = []server.Message{}
269+ FixesInterface.Requests = []server.Message{
270+ {Name: "destroy", Signature: "", Types: []*server.Interface{}},
271+ {Name: "destroy_registry", Signature: "o", Types: []*server.Interface{RegistryInterface}},
272+ {Name: "ack_global_remove", Signature: "2ou", Types: []*server.Interface{RegistryInterface, nil}},
273+ }
274+ FixesInterface.Events = []server.Message{}
275+ if err := server.NewInterfaces(DisplayInterface, RegistryInterface, CallbackInterface, CompositorInterface, ShmPoolInterface, ShmInterface, BufferInterface, DataOfferInterface, DataSourceInterface, DataDeviceInterface, DataDeviceManagerInterface, ShellInterface, ShellSurfaceInterface, SurfaceInterface, SeatInterface, PointerInterface, KeyboardInterface, TouchInterface, OutputInterface, RegionInterface, SubcompositorInterface, SubsurfaceInterface, FixesInterface); err != nil {
276+ panic(err)
277+ }
278+}
279+
280+// Display core global object.
281+type Display struct{ *server.Resource }
282+
283+func WrapDisplay(r *server.Resource) *Display {
284+ if r == nil {
285+ return nil
286+ }
287+ return &Display{r}
288+}
289+
290+const DisplayRequestSync uint32 = 0
291+const DisplayRequestGetRegistry uint32 = 1
292+const DisplayEventError uint32 = 0
293+const DisplayEventDeleteId uint32 = 1
294+
295+// DisplayError global error values.
296+type DisplayError uint32
297+
298+const (
299+ DisplayErrorInvalidObject DisplayError = 0
300+ DisplayErrorInvalidMethod DisplayError = 1
301+ DisplayErrorNoMemory DisplayError = 2
302+ DisplayErrorImplementation DisplayError = 3
303+)
304+
305+// DisplayHandler handles wl_display requests.
306+type DisplayHandler interface {
307+ Sync(self *Display, callback uint32)
308+ GetRegistry(self *Display, registry uint32)
309+}
310+
311+func NewDisplay(c server.Client, version int32, id uint32, h DisplayHandler) (*Display, error) {
312+ if h == nil {
313+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_display")
314+ }
315+ var self *Display
316+ r, err := c.CreateResource(DisplayInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
317+ switch opcode {
318+ case 0:
319+ h.Sync(self, args[0].NewID())
320+ case 1:
321+ h.GetRegistry(self, args[0].NewID())
322+ }
323+ })
324+ if err != nil {
325+ return nil, err
326+ }
327+ self = WrapDisplay(r)
328+ r.Data = self
329+ return self, nil
330+}
331+
332+// SendError fatal error event.
333+func (self *Display) SendError(objectId *server.Resource, code uint32, message string) {
334+ var p runtime.Pinner
335+ defer p.Unpin()
336+ self.PostEvent(DisplayEventError, server.Object(objectId), server.Uint(code), server.String(&p, message, false))
337+}
338+
339+// SendDeleteId acknowledge object ID deletion.
340+func (self *Display) SendDeleteId(id uint32) {
341+ self.PostEvent(DisplayEventDeleteId, server.Uint(id))
342+}
343+func NewDisplayGlobal(d *server.Display, version int32, bind server.BindFunc) error {
344+ return d.CreateGlobal(DisplayInterface, version, bind)
345+}
346+
347+// Registry global registry object.
348+type Registry struct{ *server.Resource }
349+
350+func WrapRegistry(r *server.Resource) *Registry {
351+ if r == nil {
352+ return nil
353+ }
354+ return &Registry{r}
355+}
356+
357+const RegistryRequestBind uint32 = 0
358+const RegistryEventGlobal uint32 = 0
359+const RegistryEventGlobalRemove uint32 = 1
360+
361+// RegistryHandler handles wl_registry requests.
362+type RegistryHandler interface {
363+ Bind(self *Registry, name uint32, interfaceName string, version uint32, id uint32)
364+}
365+
366+func NewRegistry(c server.Client, version int32, id uint32, h RegistryHandler) (*Registry, error) {
367+ if h == nil {
368+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_registry")
369+ }
370+ var self *Registry
371+ r, err := c.CreateResource(RegistryInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
372+ switch opcode {
373+ case 0:
374+ h.Bind(self, args[0].Uint(), args[1].String(), args[2].Uint(), args[3].NewID())
375+ }
376+ })
377+ if err != nil {
378+ return nil, err
379+ }
380+ self = WrapRegistry(r)
381+ r.Data = self
382+ return self, nil
383+}
384+
385+// SendGlobal announce global object.
386+func (self *Registry) SendGlobal(name uint32, interfaceArg string, version uint32) {
387+ var p runtime.Pinner
388+ defer p.Unpin()
389+ self.PostEvent(RegistryEventGlobal, server.Uint(name), server.String(&p, interfaceArg, false), server.Uint(version))
390+}
391+
392+// SendGlobalRemove announce removal of global object.
393+func (self *Registry) SendGlobalRemove(name uint32) {
394+ self.PostEvent(RegistryEventGlobalRemove, server.Uint(name))
395+}
396+func NewRegistryGlobal(d *server.Display, version int32, bind server.BindFunc) error {
397+ return d.CreateGlobal(RegistryInterface, version, bind)
398+}
399+
400+// Callback callback object.
401+type Callback struct{ *server.Resource }
402+
403+func WrapCallback(r *server.Resource) *Callback {
404+ if r == nil {
405+ return nil
406+ }
407+ return &Callback{r}
408+}
409+
410+const CallbackEventDone uint32 = 0
411+
412+// CallbackHandler handles wl_callback requests.
413+type CallbackHandler interface {
414+}
415+
416+func NewCallback(c server.Client, version int32, id uint32, h CallbackHandler) (*Callback, error) {
417+ var self *Callback
418+ r, err := c.CreateResource(CallbackInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
419+ switch opcode {
420+ }
421+ })
422+ if err != nil {
423+ return nil, err
424+ }
425+ self = WrapCallback(r)
426+ r.Data = self
427+ return self, nil
428+}
429+
430+// SendDone done event.
431+func (self *Callback) SendDone(callbackData uint32) {
432+ self.PostEvent(CallbackEventDone, server.Uint(callbackData))
433+}
434+func NewCallbackGlobal(d *server.Display, version int32, bind server.BindFunc) error {
435+ return d.CreateGlobal(CallbackInterface, version, bind)
436+}
437+
438+// Compositor the compositor singleton.
439+type Compositor struct{ *server.Resource }
440+
441+func WrapCompositor(r *server.Resource) *Compositor {
442+ if r == nil {
443+ return nil
444+ }
445+ return &Compositor{r}
446+}
447+
448+const CompositorRequestCreateSurface uint32 = 0
449+const CompositorRequestCreateRegion uint32 = 1
450+const CompositorRequestRelease uint32 = 2
451+
452+// CompositorHandler handles wl_compositor requests.
453+type CompositorHandler interface {
454+ CreateSurface(self *Compositor, id uint32)
455+ CreateRegion(self *Compositor, id uint32)
456+ Release(self *Compositor)
457+}
458+
459+func NewCompositor(c server.Client, version int32, id uint32, h CompositorHandler) (*Compositor, error) {
460+ if h == nil {
461+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_compositor")
462+ }
463+ var self *Compositor
464+ r, err := c.CreateResource(CompositorInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
465+ switch opcode {
466+ case 0:
467+ h.CreateSurface(self, args[0].NewID())
468+ case 1:
469+ h.CreateRegion(self, args[0].NewID())
470+ case 2:
471+ h.Release(self)
472+ self.Destroy()
473+ }
474+ })
475+ if err != nil {
476+ return nil, err
477+ }
478+ self = WrapCompositor(r)
479+ r.Data = self
480+ return self, nil
481+}
482+func NewCompositorGlobal(d *server.Display, version int32, bind server.BindFunc) error {
483+ return d.CreateGlobal(CompositorInterface, version, bind)
484+}
485+
486+// ShmPool a shared memory pool.
487+type ShmPool struct{ *server.Resource }
488+
489+func WrapShmPool(r *server.Resource) *ShmPool {
490+ if r == nil {
491+ return nil
492+ }
493+ return &ShmPool{r}
494+}
495+
496+const ShmPoolRequestCreateBuffer uint32 = 0
497+const ShmPoolRequestDestroy uint32 = 1
498+const ShmPoolRequestResize uint32 = 2
499+
500+// ShmPoolError wl_shm_pool error values.
501+type ShmPoolError uint32
502+
503+const (
504+ ShmPoolErrorInvalidFormat ShmPoolError = 0
505+ ShmPoolErrorInvalidStride ShmPoolError = 1
506+)
507+
508+// ShmPoolHandler handles wl_shm_pool requests.
509+type ShmPoolHandler interface {
510+ CreateBuffer(self *ShmPool, id uint32, offset int32, width int32, height int32, stride int32, format uint32)
511+ Destroy(self *ShmPool)
512+ Resize(self *ShmPool, size int32)
513+}
514+
515+func NewShmPool(c server.Client, version int32, id uint32, h ShmPoolHandler) (*ShmPool, error) {
516+ if h == nil {
517+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_shm_pool")
518+ }
519+ var self *ShmPool
520+ r, err := c.CreateResource(ShmPoolInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
521+ switch opcode {
522+ case 0:
523+ h.CreateBuffer(self, args[0].NewID(), args[1].Int(), args[2].Int(), args[3].Int(), args[4].Int(), args[5].Uint())
524+ case 1:
525+ h.Destroy(self)
526+ self.Destroy()
527+ case 2:
528+ h.Resize(self, args[0].Int())
529+ }
530+ })
531+ if err != nil {
532+ return nil, err
533+ }
534+ self = WrapShmPool(r)
535+ r.Data = self
536+ return self, nil
537+}
538+func NewShmPoolGlobal(d *server.Display, version int32, bind server.BindFunc) error {
539+ return d.CreateGlobal(ShmPoolInterface, version, bind)
540+}
541+
542+// Shm shared memory support.
543+type Shm struct{ *server.Resource }
544+
545+func WrapShm(r *server.Resource) *Shm {
546+ if r == nil {
547+ return nil
548+ }
549+ return &Shm{r}
550+}
551+
552+const ShmRequestCreatePool uint32 = 0
553+const ShmRequestRelease uint32 = 1
554+const ShmEventFormat uint32 = 0
555+
556+// ShmError wl_shm error values.
557+type ShmError uint32
558+
559+const (
560+ ShmErrorInvalidFormat ShmError = 0
561+ ShmErrorInvalidStride ShmError = 1
562+ ShmErrorInvalidFd ShmError = 2
563+)
564+
565+// ShmFormat pixel formats.
566+type ShmFormat uint32
567+
568+const (
569+ ShmFormatArgb8888 ShmFormat = 0
570+ ShmFormatXrgb8888 ShmFormat = 1
571+ ShmFormatC8 ShmFormat = 0x20203843
572+ ShmFormatRgb332 ShmFormat = 0x38424752
573+ ShmFormatBgr233 ShmFormat = 0x38524742
574+ ShmFormatXrgb4444 ShmFormat = 0x32315258
575+ ShmFormatXbgr4444 ShmFormat = 0x32314258
576+ ShmFormatRgbx4444 ShmFormat = 0x32315852
577+ ShmFormatBgrx4444 ShmFormat = 0x32315842
578+ ShmFormatArgb4444 ShmFormat = 0x32315241
579+ ShmFormatAbgr4444 ShmFormat = 0x32314241
580+ ShmFormatRgba4444 ShmFormat = 0x32314152
581+ ShmFormatBgra4444 ShmFormat = 0x32314142
582+ ShmFormatXrgb1555 ShmFormat = 0x35315258
583+ ShmFormatXbgr1555 ShmFormat = 0x35314258
584+ ShmFormatRgbx5551 ShmFormat = 0x35315852
585+ ShmFormatBgrx5551 ShmFormat = 0x35315842
586+ ShmFormatArgb1555 ShmFormat = 0x35315241
587+ ShmFormatAbgr1555 ShmFormat = 0x35314241
588+ ShmFormatRgba5551 ShmFormat = 0x35314152
589+ ShmFormatBgra5551 ShmFormat = 0x35314142
590+ ShmFormatRgb565 ShmFormat = 0x36314752
591+ ShmFormatBgr565 ShmFormat = 0x36314742
592+ ShmFormatRgb888 ShmFormat = 0x34324752
593+ ShmFormatBgr888 ShmFormat = 0x34324742
594+ ShmFormatXbgr8888 ShmFormat = 0x34324258
595+ ShmFormatRgbx8888 ShmFormat = 0x34325852
596+ ShmFormatBgrx8888 ShmFormat = 0x34325842
597+ ShmFormatAbgr8888 ShmFormat = 0x34324241
598+ ShmFormatRgba8888 ShmFormat = 0x34324152
599+ ShmFormatBgra8888 ShmFormat = 0x34324142
600+ ShmFormatXrgb2101010 ShmFormat = 0x30335258
601+ ShmFormatXbgr2101010 ShmFormat = 0x30334258
602+ ShmFormatRgbx1010102 ShmFormat = 0x30335852
603+ ShmFormatBgrx1010102 ShmFormat = 0x30335842
604+ ShmFormatArgb2101010 ShmFormat = 0x30335241
605+ ShmFormatAbgr2101010 ShmFormat = 0x30334241
606+ ShmFormatRgba1010102 ShmFormat = 0x30334152
607+ ShmFormatBgra1010102 ShmFormat = 0x30334142
608+ ShmFormatYuyv ShmFormat = 0x56595559
609+ ShmFormatYvyu ShmFormat = 0x55595659
610+ ShmFormatUyvy ShmFormat = 0x59565955
611+ ShmFormatVyuy ShmFormat = 0x59555956
612+ ShmFormatAyuv ShmFormat = 0x56555941
613+ ShmFormatNv12 ShmFormat = 0x3231564e
614+ ShmFormatNv21 ShmFormat = 0x3132564e
615+ ShmFormatNv16 ShmFormat = 0x3631564e
616+ ShmFormatNv61 ShmFormat = 0x3136564e
617+ ShmFormatYuv410 ShmFormat = 0x39565559
618+ ShmFormatYvu410 ShmFormat = 0x39555659
619+ ShmFormatYuv411 ShmFormat = 0x31315559
620+ ShmFormatYvu411 ShmFormat = 0x31315659
621+ ShmFormatYuv420 ShmFormat = 0x32315559
622+ ShmFormatYvu420 ShmFormat = 0x32315659
623+ ShmFormatYuv422 ShmFormat = 0x36315559
624+ ShmFormatYvu422 ShmFormat = 0x36315659
625+ ShmFormatYuv444 ShmFormat = 0x34325559
626+ ShmFormatYvu444 ShmFormat = 0x34325659
627+ ShmFormatR8 ShmFormat = 0x20203852
628+ ShmFormatR16 ShmFormat = 0x20363152
629+ ShmFormatRg88 ShmFormat = 0x38384752
630+ ShmFormatGr88 ShmFormat = 0x38385247
631+ ShmFormatRg1616 ShmFormat = 0x32334752
632+ ShmFormatGr1616 ShmFormat = 0x32335247
633+ ShmFormatXrgb16161616f ShmFormat = 0x48345258
634+ ShmFormatXbgr16161616f ShmFormat = 0x48344258
635+ ShmFormatArgb16161616f ShmFormat = 0x48345241
636+ ShmFormatAbgr16161616f ShmFormat = 0x48344241
637+ ShmFormatXyuv8888 ShmFormat = 0x56555958
638+ ShmFormatVuy888 ShmFormat = 0x34325556
639+ ShmFormatVuy101010 ShmFormat = 0x30335556
640+ ShmFormatY210 ShmFormat = 0x30313259
641+ ShmFormatY212 ShmFormat = 0x32313259
642+ ShmFormatY216 ShmFormat = 0x36313259
643+ ShmFormatY410 ShmFormat = 0x30313459
644+ ShmFormatY412 ShmFormat = 0x32313459
645+ ShmFormatY416 ShmFormat = 0x36313459
646+ ShmFormatXvyu2101010 ShmFormat = 0x30335658
647+ ShmFormatXvyu1216161616 ShmFormat = 0x36335658
648+ ShmFormatXvyu16161616 ShmFormat = 0x38345658
649+ ShmFormatY0l0 ShmFormat = 0x304c3059
650+ ShmFormatX0l0 ShmFormat = 0x304c3058
651+ ShmFormatY0l2 ShmFormat = 0x324c3059
652+ ShmFormatX0l2 ShmFormat = 0x324c3058
653+ ShmFormatYuv4208bit ShmFormat = 0x38305559
654+ ShmFormatYuv42010bit ShmFormat = 0x30315559
655+ ShmFormatXrgb8888A8 ShmFormat = 0x38415258
656+ ShmFormatXbgr8888A8 ShmFormat = 0x38414258
657+ ShmFormatRgbx8888A8 ShmFormat = 0x38415852
658+ ShmFormatBgrx8888A8 ShmFormat = 0x38415842
659+ ShmFormatRgb888A8 ShmFormat = 0x38413852
660+ ShmFormatBgr888A8 ShmFormat = 0x38413842
661+ ShmFormatRgb565A8 ShmFormat = 0x38413552
662+ ShmFormatBgr565A8 ShmFormat = 0x38413542
663+ ShmFormatNv24 ShmFormat = 0x3432564e
664+ ShmFormatNv42 ShmFormat = 0x3234564e
665+ ShmFormatP210 ShmFormat = 0x30313250
666+ ShmFormatP010 ShmFormat = 0x30313050
667+ ShmFormatP012 ShmFormat = 0x32313050
668+ ShmFormatP016 ShmFormat = 0x36313050
669+ ShmFormatAxbxgxrx106106106106 ShmFormat = 0x30314241
670+ ShmFormatNv15 ShmFormat = 0x3531564e
671+ ShmFormatQ410 ShmFormat = 0x30313451
672+ ShmFormatQ401 ShmFormat = 0x31303451
673+ ShmFormatXrgb16161616 ShmFormat = 0x38345258
674+ ShmFormatXbgr16161616 ShmFormat = 0x38344258
675+ ShmFormatArgb16161616 ShmFormat = 0x38345241
676+ ShmFormatAbgr16161616 ShmFormat = 0x38344241
677+ ShmFormatC1 ShmFormat = 0x20203143
678+ ShmFormatC2 ShmFormat = 0x20203243
679+ ShmFormatC4 ShmFormat = 0x20203443
680+ ShmFormatD1 ShmFormat = 0x20203144
681+ ShmFormatD2 ShmFormat = 0x20203244
682+ ShmFormatD4 ShmFormat = 0x20203444
683+ ShmFormatD8 ShmFormat = 0x20203844
684+ ShmFormatR1 ShmFormat = 0x20203152
685+ ShmFormatR2 ShmFormat = 0x20203252
686+ ShmFormatR4 ShmFormat = 0x20203452
687+ ShmFormatR10 ShmFormat = 0x20303152
688+ ShmFormatR12 ShmFormat = 0x20323152
689+ ShmFormatAvuy8888 ShmFormat = 0x59555641
690+ ShmFormatXvuy8888 ShmFormat = 0x59555658
691+ ShmFormatP030 ShmFormat = 0x30333050
692+ ShmFormatRgb161616 ShmFormat = 0x38344752
693+ ShmFormatBgr161616 ShmFormat = 0x38344742
694+ ShmFormatR16f ShmFormat = 0x48202052
695+ ShmFormatGr1616f ShmFormat = 0x48205247
696+ ShmFormatBgr161616f ShmFormat = 0x48524742
697+ ShmFormatR32f ShmFormat = 0x46202052
698+ ShmFormatGr3232f ShmFormat = 0x46205247
699+ ShmFormatBgr323232f ShmFormat = 0x46524742
700+ ShmFormatAbgr32323232f ShmFormat = 0x46384241
701+ ShmFormatNv20 ShmFormat = 0x3032564e
702+ ShmFormatNv30 ShmFormat = 0x3033564e
703+ ShmFormatS010 ShmFormat = 0x30313053
704+ ShmFormatS210 ShmFormat = 0x30313253
705+ ShmFormatS410 ShmFormat = 0x30313453
706+ ShmFormatS012 ShmFormat = 0x32313053
707+ ShmFormatS212 ShmFormat = 0x32313253
708+ ShmFormatS412 ShmFormat = 0x32313453
709+ ShmFormatS016 ShmFormat = 0x36313053
710+ ShmFormatS216 ShmFormat = 0x36313253
711+ ShmFormatS416 ShmFormat = 0x36313453
712+ ShmFormatXvuy2101010 ShmFormat = 0x30335958
713+ ShmFormatP230 ShmFormat = 0x30333250
714+ ShmFormatT430 ShmFormat = 0x30333454
715+ ShmFormatY8 ShmFormat = 0x59455247
716+ ShmFormatXyyy2101010 ShmFormat = 0x34415059
717+)
718+
719+// ShmHandler handles wl_shm requests.
720+type ShmHandler interface {
721+ CreatePool(self *Shm, id uint32, fd int, size int32)
722+ Release(self *Shm)
723+}
724+
725+func NewShm(c server.Client, version int32, id uint32, h ShmHandler) (*Shm, error) {
726+ if h == nil {
727+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_shm")
728+ }
729+ var self *Shm
730+ r, err := c.CreateResource(ShmInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
731+ switch opcode {
732+ case 0:
733+ h.CreatePool(self, args[0].NewID(), args[1].Fd(), args[2].Int())
734+ case 1:
735+ h.Release(self)
736+ self.Destroy()
737+ }
738+ })
739+ if err != nil {
740+ return nil, err
741+ }
742+ self = WrapShm(r)
743+ r.Data = self
744+ return self, nil
745+}
746+
747+// SendFormat pixel format description.
748+func (self *Shm) SendFormat(format uint32) {
749+ self.PostEvent(ShmEventFormat, server.Uint(format))
750+}
751+func NewShmGlobal(d *server.Display, version int32, bind server.BindFunc) error {
752+ return d.CreateGlobal(ShmInterface, version, bind)
753+}
754+
755+// Buffer content for a wl_surface.
756+type Buffer struct{ *server.Resource }
757+
758+func WrapBuffer(r *server.Resource) *Buffer {
759+ if r == nil {
760+ return nil
761+ }
762+ return &Buffer{r}
763+}
764+
765+const BufferRequestDestroy uint32 = 0
766+const BufferEventRelease uint32 = 0
767+
768+// BufferHandler handles wl_buffer requests.
769+type BufferHandler interface {
770+ Destroy(self *Buffer)
771+}
772+
773+func NewBuffer(c server.Client, version int32, id uint32, h BufferHandler) (*Buffer, error) {
774+ if h == nil {
775+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_buffer")
776+ }
777+ var self *Buffer
778+ r, err := c.CreateResource(BufferInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
779+ switch opcode {
780+ case 0:
781+ h.Destroy(self)
782+ self.Destroy()
783+ }
784+ })
785+ if err != nil {
786+ return nil, err
787+ }
788+ self = WrapBuffer(r)
789+ r.Data = self
790+ return self, nil
791+}
792+
793+// SendRelease compositor releases buffer.
794+func (self *Buffer) SendRelease() {
795+ self.PostEvent(BufferEventRelease)
796+}
797+func NewBufferGlobal(d *server.Display, version int32, bind server.BindFunc) error {
798+ return d.CreateGlobal(BufferInterface, version, bind)
799+}
800+
801+// DataOffer offer to transfer data.
802+type DataOffer struct{ *server.Resource }
803+
804+func WrapDataOffer(r *server.Resource) *DataOffer {
805+ if r == nil {
806+ return nil
807+ }
808+ return &DataOffer{r}
809+}
810+
811+const DataOfferRequestAccept uint32 = 0
812+const DataOfferRequestReceive uint32 = 1
813+const DataOfferRequestDestroy uint32 = 2
814+const DataOfferRequestFinish uint32 = 3
815+const DataOfferRequestSetActions uint32 = 4
816+const DataOfferEventOffer uint32 = 0
817+const DataOfferEventSourceActions uint32 = 1
818+const DataOfferEventAction uint32 = 2
819+
820+// DataOfferError .
821+type DataOfferError uint32
822+
823+const (
824+ DataOfferErrorInvalidFinish DataOfferError = 0
825+ DataOfferErrorInvalidActionMask DataOfferError = 1
826+ DataOfferErrorInvalidAction DataOfferError = 2
827+ DataOfferErrorInvalidOffer DataOfferError = 3
828+)
829+
830+// DataOfferHandler handles wl_data_offer requests.
831+type DataOfferHandler interface {
832+ Accept(self *DataOffer, serial uint32, mimeType string)
833+ Receive(self *DataOffer, mimeType string, fd int)
834+ Destroy(self *DataOffer)
835+ Finish(self *DataOffer)
836+ SetActions(self *DataOffer, dndActions uint32, preferredAction uint32)
837+}
838+
839+func NewDataOffer(c server.Client, version int32, id uint32, h DataOfferHandler) (*DataOffer, error) {
840+ if h == nil {
841+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_data_offer")
842+ }
843+ var self *DataOffer
844+ r, err := c.CreateResource(DataOfferInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
845+ switch opcode {
846+ case 0:
847+ h.Accept(self, args[0].Uint(), args[1].String())
848+ case 1:
849+ h.Receive(self, args[0].String(), args[1].Fd())
850+ case 2:
851+ h.Destroy(self)
852+ self.Destroy()
853+ case 3:
854+ h.Finish(self)
855+ case 4:
856+ h.SetActions(self, args[0].Uint(), args[1].Uint())
857+ }
858+ })
859+ if err != nil {
860+ return nil, err
861+ }
862+ self = WrapDataOffer(r)
863+ r.Data = self
864+ return self, nil
865+}
866+
867+// SendOffer advertise offered mime type.
868+func (self *DataOffer) SendOffer(mimeType string) {
869+ var p runtime.Pinner
870+ defer p.Unpin()
871+ self.PostEvent(DataOfferEventOffer, server.String(&p, mimeType, false))
872+}
873+
874+// SendSourceActions notify the source-side available actions (since version 3).
875+func (self *DataOffer) SendSourceActions(sourceActions uint32) {
876+ self.PostEvent(DataOfferEventSourceActions, server.Uint(sourceActions))
877+}
878+
879+// SendAction notify the selected action (since version 3).
880+func (self *DataOffer) SendAction(dndAction uint32) {
881+ self.PostEvent(DataOfferEventAction, server.Uint(dndAction))
882+}
883+func NewDataOfferGlobal(d *server.Display, version int32, bind server.BindFunc) error {
884+ return d.CreateGlobal(DataOfferInterface, version, bind)
885+}
886+
887+// DataSource offer to transfer data.
888+type DataSource struct{ *server.Resource }
889+
890+func WrapDataSource(r *server.Resource) *DataSource {
891+ if r == nil {
892+ return nil
893+ }
894+ return &DataSource{r}
895+}
896+
897+const DataSourceRequestOffer uint32 = 0
898+const DataSourceRequestDestroy uint32 = 1
899+const DataSourceRequestSetActions uint32 = 2
900+const DataSourceEventTarget uint32 = 0
901+const DataSourceEventSend uint32 = 1
902+const DataSourceEventCancelled uint32 = 2
903+const DataSourceEventDndDropPerformed uint32 = 3
904+const DataSourceEventDndFinished uint32 = 4
905+const DataSourceEventAction uint32 = 5
906+
907+// DataSourceError .
908+type DataSourceError uint32
909+
910+const (
911+ DataSourceErrorInvalidActionMask DataSourceError = 0
912+ DataSourceErrorInvalidSource DataSourceError = 1
913+)
914+
915+// DataSourceHandler handles wl_data_source requests.
916+type DataSourceHandler interface {
917+ Offer(self *DataSource, mimeType string)
918+ Destroy(self *DataSource)
919+ SetActions(self *DataSource, dndActions uint32)
920+}
921+
922+func NewDataSource(c server.Client, version int32, id uint32, h DataSourceHandler) (*DataSource, error) {
923+ if h == nil {
924+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_data_source")
925+ }
926+ var self *DataSource
927+ r, err := c.CreateResource(DataSourceInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
928+ switch opcode {
929+ case 0:
930+ h.Offer(self, args[0].String())
931+ case 1:
932+ h.Destroy(self)
933+ self.Destroy()
934+ case 2:
935+ h.SetActions(self, args[0].Uint())
936+ }
937+ })
938+ if err != nil {
939+ return nil, err
940+ }
941+ self = WrapDataSource(r)
942+ r.Data = self
943+ return self, nil
944+}
945+
946+// SendTarget a target accepts an offered mime type.
947+func (self *DataSource) SendTarget(mimeType string) {
948+ var p runtime.Pinner
949+ defer p.Unpin()
950+ self.PostEvent(DataSourceEventTarget, server.String(&p, mimeType, true))
951+}
952+
953+// SendSend send the data.
954+func (self *DataSource) SendSend(mimeType string, fd int) {
955+ var p runtime.Pinner
956+ defer p.Unpin()
957+ self.PostEvent(DataSourceEventSend, server.String(&p, mimeType, false), server.Fd(fd))
958+}
959+
960+// SendCancelled selection was cancelled.
961+func (self *DataSource) SendCancelled() {
962+ self.PostEvent(DataSourceEventCancelled)
963+}
964+
965+// SendDndDropPerformed the drag-and-drop operation physically finished (since version 3).
966+func (self *DataSource) SendDndDropPerformed() {
967+ self.PostEvent(DataSourceEventDndDropPerformed)
968+}
969+
970+// SendDndFinished the drag-and-drop operation concluded (since version 3).
971+func (self *DataSource) SendDndFinished() {
972+ self.PostEvent(DataSourceEventDndFinished)
973+}
974+
975+// SendAction notify the selected action (since version 3).
976+func (self *DataSource) SendAction(dndAction uint32) {
977+ self.PostEvent(DataSourceEventAction, server.Uint(dndAction))
978+}
979+func NewDataSourceGlobal(d *server.Display, version int32, bind server.BindFunc) error {
980+ return d.CreateGlobal(DataSourceInterface, version, bind)
981+}
982+
983+// DataDevice data transfer device.
984+type DataDevice struct{ *server.Resource }
985+
986+func WrapDataDevice(r *server.Resource) *DataDevice {
987+ if r == nil {
988+ return nil
989+ }
990+ return &DataDevice{r}
991+}
992+
993+const DataDeviceRequestStartDrag uint32 = 0
994+const DataDeviceRequestSetSelection uint32 = 1
995+const DataDeviceRequestRelease uint32 = 2
996+const DataDeviceEventDataOffer uint32 = 0
997+const DataDeviceEventEnter uint32 = 1
998+const DataDeviceEventLeave uint32 = 2
999+const DataDeviceEventMotion uint32 = 3
1000+const DataDeviceEventDrop uint32 = 4
1001+const DataDeviceEventSelection uint32 = 5
1002+
1003+// DataDeviceError .
1004+type DataDeviceError uint32
1005+
1006+const (
1007+ DataDeviceErrorRole DataDeviceError = 0
1008+ DataDeviceErrorUsedSource DataDeviceError = 1
1009+)
1010+
1011+// DataDeviceHandler handles wl_data_device requests.
1012+type DataDeviceHandler interface {
1013+ StartDrag(self *DataDevice, source *DataSource, origin *Surface, icon *Surface, serial uint32)
1014+ SetSelection(self *DataDevice, source *DataSource, serial uint32)
1015+ Release(self *DataDevice)
1016+}
1017+
1018+func NewDataDevice(c server.Client, version int32, id uint32, h DataDeviceHandler) (*DataDevice, error) {
1019+ if h == nil {
1020+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_data_device")
1021+ }
1022+ var self *DataDevice
1023+ r, err := c.CreateResource(DataDeviceInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
1024+ switch opcode {
1025+ case 0:
1026+ h.StartDrag(self, WrapDataSource(args[0].Resource()), WrapSurface(args[1].Resource()), WrapSurface(args[2].Resource()), args[3].Uint())
1027+ case 1:
1028+ h.SetSelection(self, WrapDataSource(args[0].Resource()), args[1].Uint())
1029+ case 2:
1030+ h.Release(self)
1031+ self.Destroy()
1032+ }
1033+ })
1034+ if err != nil {
1035+ return nil, err
1036+ }
1037+ self = WrapDataDevice(r)
1038+ r.Data = self
1039+ return self, nil
1040+}
1041+
1042+// SendDataOffer introduce a new wl_data_offer.
1043+func (self *DataDevice) SendDataOffer(id *DataOffer) {
1044+ self.PostEvent(DataDeviceEventDataOffer, server.NewID(resourceOf(id)))
1045+}
1046+
1047+// SendEnter initiate drag-and-drop session.
1048+func (self *DataDevice) SendEnter(serial uint32, surface *Surface, x server.Fixed, y server.Fixed, id *DataOffer) {
1049+ self.PostEvent(DataDeviceEventEnter, server.Uint(serial), server.Object(resourceOf(surface)), server.FixedArg(x), server.FixedArg(y), server.Object(resourceOf(id)))
1050+}
1051+
1052+// SendLeave end drag-and-drop session.
1053+func (self *DataDevice) SendLeave() {
1054+ self.PostEvent(DataDeviceEventLeave)
1055+}
1056+
1057+// SendMotion drag-and-drop session motion.
1058+func (self *DataDevice) SendMotion(time uint32, x server.Fixed, y server.Fixed) {
1059+ self.PostEvent(DataDeviceEventMotion, server.Uint(time), server.FixedArg(x), server.FixedArg(y))
1060+}
1061+
1062+// SendDrop end drag-and-drop session successfully.
1063+func (self *DataDevice) SendDrop() {
1064+ self.PostEvent(DataDeviceEventDrop)
1065+}
1066+
1067+// SendSelection advertise new selection.
1068+func (self *DataDevice) SendSelection(id *DataOffer) {
1069+ self.PostEvent(DataDeviceEventSelection, server.Object(resourceOf(id)))
1070+}
1071+func NewDataDeviceGlobal(d *server.Display, version int32, bind server.BindFunc) error {
1072+ return d.CreateGlobal(DataDeviceInterface, version, bind)
1073+}
1074+
1075+// DataDeviceManager data transfer interface.
1076+type DataDeviceManager struct{ *server.Resource }
1077+
1078+func WrapDataDeviceManager(r *server.Resource) *DataDeviceManager {
1079+ if r == nil {
1080+ return nil
1081+ }
1082+ return &DataDeviceManager{r}
1083+}
1084+
1085+const DataDeviceManagerRequestCreateDataSource uint32 = 0
1086+const DataDeviceManagerRequestGetDataDevice uint32 = 1
1087+const DataDeviceManagerRequestRelease uint32 = 2
1088+
1089+// DataDeviceManagerDndAction drag and drop actions (bitfield).
1090+type DataDeviceManagerDndAction uint32
1091+
1092+const (
1093+ DataDeviceManagerDndActionNone DataDeviceManagerDndAction = 0
1094+ DataDeviceManagerDndActionCopy DataDeviceManagerDndAction = 1
1095+ DataDeviceManagerDndActionMove DataDeviceManagerDndAction = 2
1096+ DataDeviceManagerDndActionAsk DataDeviceManagerDndAction = 4
1097+)
1098+
1099+// DataDeviceManagerHandler handles wl_data_device_manager requests.
1100+type DataDeviceManagerHandler interface {
1101+ CreateDataSource(self *DataDeviceManager, id uint32)
1102+ GetDataDevice(self *DataDeviceManager, id uint32, seat *Seat)
1103+ Release(self *DataDeviceManager)
1104+}
1105+
1106+func NewDataDeviceManager(c server.Client, version int32, id uint32, h DataDeviceManagerHandler) (*DataDeviceManager, error) {
1107+ if h == nil {
1108+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_data_device_manager")
1109+ }
1110+ var self *DataDeviceManager
1111+ r, err := c.CreateResource(DataDeviceManagerInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
1112+ switch opcode {
1113+ case 0:
1114+ h.CreateDataSource(self, args[0].NewID())
1115+ case 1:
1116+ h.GetDataDevice(self, args[0].NewID(), WrapSeat(args[1].Resource()))
1117+ case 2:
1118+ h.Release(self)
1119+ self.Destroy()
1120+ }
1121+ })
1122+ if err != nil {
1123+ return nil, err
1124+ }
1125+ self = WrapDataDeviceManager(r)
1126+ r.Data = self
1127+ return self, nil
1128+}
1129+func NewDataDeviceManagerGlobal(d *server.Display, version int32, bind server.BindFunc) error {
1130+ return d.CreateGlobal(DataDeviceManagerInterface, version, bind)
1131+}
1132+
1133+// Shell create desktop-style surfaces.
1134+type Shell struct{ *server.Resource }
1135+
1136+func WrapShell(r *server.Resource) *Shell {
1137+ if r == nil {
1138+ return nil
1139+ }
1140+ return &Shell{r}
1141+}
1142+
1143+const ShellRequestGetShellSurface uint32 = 0
1144+
1145+// ShellError .
1146+type ShellError uint32
1147+
1148+const (
1149+ ShellErrorRole ShellError = 0
1150+)
1151+
1152+// ShellHandler handles wl_shell requests.
1153+type ShellHandler interface {
1154+ GetShellSurface(self *Shell, id uint32, surface *Surface)
1155+}
1156+
1157+func NewShell(c server.Client, version int32, id uint32, h ShellHandler) (*Shell, error) {
1158+ if h == nil {
1159+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_shell")
1160+ }
1161+ var self *Shell
1162+ r, err := c.CreateResource(ShellInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
1163+ switch opcode {
1164+ case 0:
1165+ h.GetShellSurface(self, args[0].NewID(), WrapSurface(args[1].Resource()))
1166+ }
1167+ })
1168+ if err != nil {
1169+ return nil, err
1170+ }
1171+ self = WrapShell(r)
1172+ r.Data = self
1173+ return self, nil
1174+}
1175+func NewShellGlobal(d *server.Display, version int32, bind server.BindFunc) error {
1176+ return d.CreateGlobal(ShellInterface, version, bind)
1177+}
1178+
1179+// ShellSurface desktop-style metadata interface.
1180+type ShellSurface struct{ *server.Resource }
1181+
1182+func WrapShellSurface(r *server.Resource) *ShellSurface {
1183+ if r == nil {
1184+ return nil
1185+ }
1186+ return &ShellSurface{r}
1187+}
1188+
1189+const ShellSurfaceRequestPong uint32 = 0
1190+const ShellSurfaceRequestMove uint32 = 1
1191+const ShellSurfaceRequestResize uint32 = 2
1192+const ShellSurfaceRequestSetToplevel uint32 = 3
1193+const ShellSurfaceRequestSetTransient uint32 = 4
1194+const ShellSurfaceRequestSetFullscreen uint32 = 5
1195+const ShellSurfaceRequestSetPopup uint32 = 6
1196+const ShellSurfaceRequestSetMaximized uint32 = 7
1197+const ShellSurfaceRequestSetTitle uint32 = 8
1198+const ShellSurfaceRequestSetClass uint32 = 9
1199+const ShellSurfaceEventPing uint32 = 0
1200+const ShellSurfaceEventConfigure uint32 = 1
1201+const ShellSurfaceEventPopupDone uint32 = 2
1202+
1203+// ShellSurfaceResize edge values for resizing (bitfield).
1204+type ShellSurfaceResize uint32
1205+
1206+const (
1207+ ShellSurfaceResizeNone ShellSurfaceResize = 0
1208+ ShellSurfaceResizeTop ShellSurfaceResize = 1
1209+ ShellSurfaceResizeBottom ShellSurfaceResize = 2
1210+ ShellSurfaceResizeLeft ShellSurfaceResize = 4
1211+ ShellSurfaceResizeTopLeft ShellSurfaceResize = 5
1212+ ShellSurfaceResizeBottomLeft ShellSurfaceResize = 6
1213+ ShellSurfaceResizeRight ShellSurfaceResize = 8
1214+ ShellSurfaceResizeTopRight ShellSurfaceResize = 9
1215+ ShellSurfaceResizeBottomRight ShellSurfaceResize = 10
1216+)
1217+
1218+// ShellSurfaceTransient details of transient behaviour (bitfield).
1219+type ShellSurfaceTransient uint32
1220+
1221+const (
1222+ ShellSurfaceTransientInactive ShellSurfaceTransient = 0x1
1223+)
1224+
1225+// ShellSurfaceFullscreenMethod different method to set the surface fullscreen.
1226+type ShellSurfaceFullscreenMethod uint32
1227+
1228+const (
1229+ ShellSurfaceFullscreenMethodDefault ShellSurfaceFullscreenMethod = 0
1230+ ShellSurfaceFullscreenMethodScale ShellSurfaceFullscreenMethod = 1
1231+ ShellSurfaceFullscreenMethodDriver ShellSurfaceFullscreenMethod = 2
1232+ ShellSurfaceFullscreenMethodFill ShellSurfaceFullscreenMethod = 3
1233+)
1234+
1235+// ShellSurfaceHandler handles wl_shell_surface requests.
1236+type ShellSurfaceHandler interface {
1237+ Pong(self *ShellSurface, serial uint32)
1238+ Move(self *ShellSurface, seat *Seat, serial uint32)
1239+ Resize(self *ShellSurface, seat *Seat, serial uint32, edges uint32)
1240+ SetToplevel(self *ShellSurface)
1241+ SetTransient(self *ShellSurface, parent *Surface, x int32, y int32, flags uint32)
1242+ SetFullscreen(self *ShellSurface, method uint32, framerate uint32, output *Output)
1243+ SetPopup(self *ShellSurface, seat *Seat, serial uint32, parent *Surface, x int32, y int32, flags uint32)
1244+ SetMaximized(self *ShellSurface, output *Output)
1245+ SetTitle(self *ShellSurface, title string)
1246+ SetClass(self *ShellSurface, class string)
1247+}
1248+
1249+func NewShellSurface(c server.Client, version int32, id uint32, h ShellSurfaceHandler) (*ShellSurface, error) {
1250+ if h == nil {
1251+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_shell_surface")
1252+ }
1253+ var self *ShellSurface
1254+ r, err := c.CreateResource(ShellSurfaceInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
1255+ switch opcode {
1256+ case 0:
1257+ h.Pong(self, args[0].Uint())
1258+ case 1:
1259+ h.Move(self, WrapSeat(args[0].Resource()), args[1].Uint())
1260+ case 2:
1261+ h.Resize(self, WrapSeat(args[0].Resource()), args[1].Uint(), args[2].Uint())
1262+ case 3:
1263+ h.SetToplevel(self)
1264+ case 4:
1265+ h.SetTransient(self, WrapSurface(args[0].Resource()), args[1].Int(), args[2].Int(), args[3].Uint())
1266+ case 5:
1267+ h.SetFullscreen(self, args[0].Uint(), args[1].Uint(), WrapOutput(args[2].Resource()))
1268+ case 6:
1269+ h.SetPopup(self, WrapSeat(args[0].Resource()), args[1].Uint(), WrapSurface(args[2].Resource()), args[3].Int(), args[4].Int(), args[5].Uint())
1270+ case 7:
1271+ h.SetMaximized(self, WrapOutput(args[0].Resource()))
1272+ case 8:
1273+ h.SetTitle(self, args[0].String())
1274+ case 9:
1275+ h.SetClass(self, args[0].String())
1276+ }
1277+ })
1278+ if err != nil {
1279+ return nil, err
1280+ }
1281+ self = WrapShellSurface(r)
1282+ r.Data = self
1283+ return self, nil
1284+}
1285+
1286+// SendPing ping client.
1287+func (self *ShellSurface) SendPing(serial uint32) {
1288+ self.PostEvent(ShellSurfaceEventPing, server.Uint(serial))
1289+}
1290+
1291+// SendConfigure suggest resize.
1292+func (self *ShellSurface) SendConfigure(edges uint32, width int32, height int32) {
1293+ self.PostEvent(ShellSurfaceEventConfigure, server.Uint(edges), server.Int(width), server.Int(height))
1294+}
1295+
1296+// SendPopupDone popup interaction is done.
1297+func (self *ShellSurface) SendPopupDone() {
1298+ self.PostEvent(ShellSurfaceEventPopupDone)
1299+}
1300+func NewShellSurfaceGlobal(d *server.Display, version int32, bind server.BindFunc) error {
1301+ return d.CreateGlobal(ShellSurfaceInterface, version, bind)
1302+}
1303+
1304+// Surface an onscreen surface.
1305+type Surface struct{ *server.Resource }
1306+
1307+func WrapSurface(r *server.Resource) *Surface {
1308+ if r == nil {
1309+ return nil
1310+ }
1311+ return &Surface{r}
1312+}
1313+
1314+const SurfaceRequestDestroy uint32 = 0
1315+const SurfaceRequestAttach uint32 = 1
1316+const SurfaceRequestDamage uint32 = 2
1317+const SurfaceRequestFrame uint32 = 3
1318+const SurfaceRequestSetOpaqueRegion uint32 = 4
1319+const SurfaceRequestSetInputRegion uint32 = 5
1320+const SurfaceRequestCommit uint32 = 6
1321+const SurfaceRequestSetBufferTransform uint32 = 7
1322+const SurfaceRequestSetBufferScale uint32 = 8
1323+const SurfaceRequestDamageBuffer uint32 = 9
1324+const SurfaceRequestOffset uint32 = 10
1325+const SurfaceRequestGetRelease uint32 = 11
1326+const SurfaceEventEnter uint32 = 0
1327+const SurfaceEventLeave uint32 = 1
1328+const SurfaceEventPreferredBufferScale uint32 = 2
1329+const SurfaceEventPreferredBufferTransform uint32 = 3
1330+
1331+// SurfaceError wl_surface error values.
1332+type SurfaceError uint32
1333+
1334+const (
1335+ SurfaceErrorInvalidScale SurfaceError = 0
1336+ SurfaceErrorInvalidTransform SurfaceError = 1
1337+ SurfaceErrorInvalidSize SurfaceError = 2
1338+ SurfaceErrorInvalidOffset SurfaceError = 3
1339+ SurfaceErrorDefunctRoleObject SurfaceError = 4
1340+ SurfaceErrorNoBuffer SurfaceError = 5
1341+)
1342+
1343+// SurfaceHandler handles wl_surface requests.
1344+type SurfaceHandler interface {
1345+ Destroy(self *Surface)
1346+ Attach(self *Surface, buffer *Buffer, x int32, y int32)
1347+ Damage(self *Surface, x int32, y int32, width int32, height int32)
1348+ Frame(self *Surface, callback uint32)
1349+ SetOpaqueRegion(self *Surface, region *Region)
1350+ SetInputRegion(self *Surface, region *Region)
1351+ Commit(self *Surface)
1352+ SetBufferTransform(self *Surface, transform int32)
1353+ SetBufferScale(self *Surface, scale int32)
1354+ DamageBuffer(self *Surface, x int32, y int32, width int32, height int32)
1355+ Offset(self *Surface, x int32, y int32)
1356+ GetRelease(self *Surface, callback uint32)
1357+}
1358+
1359+func NewSurface(c server.Client, version int32, id uint32, h SurfaceHandler) (*Surface, error) {
1360+ if h == nil {
1361+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_surface")
1362+ }
1363+ var self *Surface
1364+ r, err := c.CreateResource(SurfaceInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
1365+ switch opcode {
1366+ case 0:
1367+ h.Destroy(self)
1368+ self.Destroy()
1369+ case 1:
1370+ h.Attach(self, WrapBuffer(args[0].Resource()), args[1].Int(), args[2].Int())
1371+ case 2:
1372+ h.Damage(self, args[0].Int(), args[1].Int(), args[2].Int(), args[3].Int())
1373+ case 3:
1374+ h.Frame(self, args[0].NewID())
1375+ case 4:
1376+ h.SetOpaqueRegion(self, WrapRegion(args[0].Resource()))
1377+ case 5:
1378+ h.SetInputRegion(self, WrapRegion(args[0].Resource()))
1379+ case 6:
1380+ h.Commit(self)
1381+ case 7:
1382+ h.SetBufferTransform(self, args[0].Int())
1383+ case 8:
1384+ h.SetBufferScale(self, args[0].Int())
1385+ case 9:
1386+ h.DamageBuffer(self, args[0].Int(), args[1].Int(), args[2].Int(), args[3].Int())
1387+ case 10:
1388+ h.Offset(self, args[0].Int(), args[1].Int())
1389+ case 11:
1390+ h.GetRelease(self, args[0].NewID())
1391+ }
1392+ })
1393+ if err != nil {
1394+ return nil, err
1395+ }
1396+ self = WrapSurface(r)
1397+ r.Data = self
1398+ return self, nil
1399+}
1400+
1401+// SendEnter surface enters an output.
1402+func (self *Surface) SendEnter(output *Output) {
1403+ self.PostEvent(SurfaceEventEnter, server.Object(resourceOf(output)))
1404+}
1405+
1406+// SendLeave surface leaves an output.
1407+func (self *Surface) SendLeave(output *Output) {
1408+ self.PostEvent(SurfaceEventLeave, server.Object(resourceOf(output)))
1409+}
1410+
1411+// SendPreferredBufferScale preferred buffer scale for the surface (since version 6).
1412+func (self *Surface) SendPreferredBufferScale(factor int32) {
1413+ self.PostEvent(SurfaceEventPreferredBufferScale, server.Int(factor))
1414+}
1415+
1416+// SendPreferredBufferTransform preferred buffer transform for the surface (since version 6).
1417+func (self *Surface) SendPreferredBufferTransform(transform uint32) {
1418+ self.PostEvent(SurfaceEventPreferredBufferTransform, server.Uint(transform))
1419+}
1420+func NewSurfaceGlobal(d *server.Display, version int32, bind server.BindFunc) error {
1421+ return d.CreateGlobal(SurfaceInterface, version, bind)
1422+}
1423+
1424+// Seat group of input devices.
1425+type Seat struct{ *server.Resource }
1426+
1427+func WrapSeat(r *server.Resource) *Seat {
1428+ if r == nil {
1429+ return nil
1430+ }
1431+ return &Seat{r}
1432+}
1433+
1434+const SeatRequestGetPointer uint32 = 0
1435+const SeatRequestGetKeyboard uint32 = 1
1436+const SeatRequestGetTouch uint32 = 2
1437+const SeatRequestRelease uint32 = 3
1438+const SeatEventCapabilities uint32 = 0
1439+const SeatEventName uint32 = 1
1440+
1441+// SeatCapability seat capability bitmask (bitfield).
1442+type SeatCapability uint32
1443+
1444+const (
1445+ SeatCapabilityPointer SeatCapability = 1
1446+ SeatCapabilityKeyboard SeatCapability = 2
1447+ SeatCapabilityTouch SeatCapability = 4
1448+)
1449+
1450+// SeatError wl_seat error values.
1451+type SeatError uint32
1452+
1453+const (
1454+ SeatErrorMissingCapability SeatError = 0
1455+)
1456+
1457+// SeatHandler handles wl_seat requests.
1458+type SeatHandler interface {
1459+ GetPointer(self *Seat, id uint32)
1460+ GetKeyboard(self *Seat, id uint32)
1461+ GetTouch(self *Seat, id uint32)
1462+ Release(self *Seat)
1463+}
1464+
1465+func NewSeat(c server.Client, version int32, id uint32, h SeatHandler) (*Seat, error) {
1466+ if h == nil {
1467+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_seat")
1468+ }
1469+ var self *Seat
1470+ r, err := c.CreateResource(SeatInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
1471+ switch opcode {
1472+ case 0:
1473+ h.GetPointer(self, args[0].NewID())
1474+ case 1:
1475+ h.GetKeyboard(self, args[0].NewID())
1476+ case 2:
1477+ h.GetTouch(self, args[0].NewID())
1478+ case 3:
1479+ h.Release(self)
1480+ self.Destroy()
1481+ }
1482+ })
1483+ if err != nil {
1484+ return nil, err
1485+ }
1486+ self = WrapSeat(r)
1487+ r.Data = self
1488+ return self, nil
1489+}
1490+
1491+// SendCapabilities seat capabilities changed.
1492+func (self *Seat) SendCapabilities(capabilities uint32) {
1493+ self.PostEvent(SeatEventCapabilities, server.Uint(capabilities))
1494+}
1495+
1496+// SendName unique identifier for this seat (since version 2).
1497+func (self *Seat) SendName(name string) {
1498+ var p runtime.Pinner
1499+ defer p.Unpin()
1500+ self.PostEvent(SeatEventName, server.String(&p, name, false))
1501+}
1502+func NewSeatGlobal(d *server.Display, version int32, bind server.BindFunc) error {
1503+ return d.CreateGlobal(SeatInterface, version, bind)
1504+}
1505+
1506+// Pointer pointer input device.
1507+type Pointer struct{ *server.Resource }
1508+
1509+func WrapPointer(r *server.Resource) *Pointer {
1510+ if r == nil {
1511+ return nil
1512+ }
1513+ return &Pointer{r}
1514+}
1515+
1516+const PointerRequestSetCursor uint32 = 0
1517+const PointerRequestRelease uint32 = 1
1518+const PointerEventEnter uint32 = 0
1519+const PointerEventLeave uint32 = 1
1520+const PointerEventMotion uint32 = 2
1521+const PointerEventButton uint32 = 3
1522+const PointerEventAxis uint32 = 4
1523+const PointerEventFrame uint32 = 5
1524+const PointerEventAxisSource uint32 = 6
1525+const PointerEventAxisStop uint32 = 7
1526+const PointerEventAxisDiscrete uint32 = 8
1527+const PointerEventAxisValue120 uint32 = 9
1528+const PointerEventAxisRelativeDirection uint32 = 10
1529+const PointerEventWarp uint32 = 11
1530+
1531+// PointerError .
1532+type PointerError uint32
1533+
1534+const (
1535+ PointerErrorRole PointerError = 0
1536+)
1537+
1538+// PointerButtonState physical button state.
1539+type PointerButtonState uint32
1540+
1541+const (
1542+ PointerButtonStateReleased PointerButtonState = 0
1543+ PointerButtonStatePressed PointerButtonState = 1
1544+)
1545+
1546+// PointerAxis axis types.
1547+type PointerAxis uint32
1548+
1549+const (
1550+ PointerAxisVerticalScroll PointerAxis = 0
1551+ PointerAxisHorizontalScroll PointerAxis = 1
1552+)
1553+
1554+// PointerAxisSource axis source types.
1555+type PointerAxisSource uint32
1556+
1557+const (
1558+ PointerAxisSourceWheel PointerAxisSource = 0
1559+ PointerAxisSourceFinger PointerAxisSource = 1
1560+ PointerAxisSourceContinuous PointerAxisSource = 2
1561+ PointerAxisSourceWheelTilt PointerAxisSource = 3
1562+)
1563+
1564+// PointerAxisRelativeDirection axis relative direction.
1565+type PointerAxisRelativeDirection uint32
1566+
1567+const (
1568+ PointerAxisRelativeDirectionIdentical PointerAxisRelativeDirection = 0
1569+ PointerAxisRelativeDirectionInverted PointerAxisRelativeDirection = 1
1570+)
1571+
1572+// PointerHandler handles wl_pointer requests.
1573+type PointerHandler interface {
1574+ SetCursor(self *Pointer, serial uint32, surface *Surface, hotspotX int32, hotspotY int32)
1575+ Release(self *Pointer)
1576+}
1577+
1578+func NewPointer(c server.Client, version int32, id uint32, h PointerHandler) (*Pointer, error) {
1579+ if h == nil {
1580+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_pointer")
1581+ }
1582+ var self *Pointer
1583+ r, err := c.CreateResource(PointerInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
1584+ switch opcode {
1585+ case 0:
1586+ h.SetCursor(self, args[0].Uint(), WrapSurface(args[1].Resource()), args[2].Int(), args[3].Int())
1587+ case 1:
1588+ h.Release(self)
1589+ self.Destroy()
1590+ }
1591+ })
1592+ if err != nil {
1593+ return nil, err
1594+ }
1595+ self = WrapPointer(r)
1596+ r.Data = self
1597+ return self, nil
1598+}
1599+
1600+// SendEnter enter event.
1601+func (self *Pointer) SendEnter(serial uint32, surface *Surface, surfaceX server.Fixed, surfaceY server.Fixed) {
1602+ self.PostEvent(PointerEventEnter, server.Uint(serial), server.Object(resourceOf(surface)), server.FixedArg(surfaceX), server.FixedArg(surfaceY))
1603+}
1604+
1605+// SendLeave leave event.
1606+func (self *Pointer) SendLeave(serial uint32, surface *Surface) {
1607+ self.PostEvent(PointerEventLeave, server.Uint(serial), server.Object(resourceOf(surface)))
1608+}
1609+
1610+// SendMotion pointer motion event.
1611+func (self *Pointer) SendMotion(time uint32, surfaceX server.Fixed, surfaceY server.Fixed) {
1612+ self.PostEvent(PointerEventMotion, server.Uint(time), server.FixedArg(surfaceX), server.FixedArg(surfaceY))
1613+}
1614+
1615+// SendButton pointer button event.
1616+func (self *Pointer) SendButton(serial uint32, time uint32, button uint32, state uint32) {
1617+ self.PostEvent(PointerEventButton, server.Uint(serial), server.Uint(time), server.Uint(button), server.Uint(state))
1618+}
1619+
1620+// SendAxis axis event.
1621+func (self *Pointer) SendAxis(time uint32, axis uint32, value server.Fixed) {
1622+ self.PostEvent(PointerEventAxis, server.Uint(time), server.Uint(axis), server.FixedArg(value))
1623+}
1624+
1625+// SendFrame end of a pointer event sequence (since version 5).
1626+func (self *Pointer) SendFrame() {
1627+ self.PostEvent(PointerEventFrame)
1628+}
1629+
1630+// SendAxisSource axis source event (since version 5).
1631+func (self *Pointer) SendAxisSource(axisSource uint32) {
1632+ self.PostEvent(PointerEventAxisSource, server.Uint(axisSource))
1633+}
1634+
1635+// SendAxisStop axis stop event (since version 5).
1636+func (self *Pointer) SendAxisStop(time uint32, axis uint32) {
1637+ self.PostEvent(PointerEventAxisStop, server.Uint(time), server.Uint(axis))
1638+}
1639+
1640+// SendAxisDiscrete axis click event (since version 5).
1641+func (self *Pointer) SendAxisDiscrete(axis uint32, discrete int32) {
1642+ self.PostEvent(PointerEventAxisDiscrete, server.Uint(axis), server.Int(discrete))
1643+}
1644+
1645+// SendAxisValue120 axis high-resolution scroll event (since version 8).
1646+func (self *Pointer) SendAxisValue120(axis uint32, value120 int32) {
1647+ self.PostEvent(PointerEventAxisValue120, server.Uint(axis), server.Int(value120))
1648+}
1649+
1650+// SendAxisRelativeDirection axis relative physical direction event (since version 9).
1651+func (self *Pointer) SendAxisRelativeDirection(axis uint32, direction uint32) {
1652+ self.PostEvent(PointerEventAxisRelativeDirection, server.Uint(axis), server.Uint(direction))
1653+}
1654+
1655+// SendWarp pointer warp event (since version 11).
1656+func (self *Pointer) SendWarp(surfaceX server.Fixed, surfaceY server.Fixed) {
1657+ self.PostEvent(PointerEventWarp, server.FixedArg(surfaceX), server.FixedArg(surfaceY))
1658+}
1659+func NewPointerGlobal(d *server.Display, version int32, bind server.BindFunc) error {
1660+ return d.CreateGlobal(PointerInterface, version, bind)
1661+}
1662+
1663+// Keyboard keyboard input device.
1664+type Keyboard struct{ *server.Resource }
1665+
1666+func WrapKeyboard(r *server.Resource) *Keyboard {
1667+ if r == nil {
1668+ return nil
1669+ }
1670+ return &Keyboard{r}
1671+}
1672+
1673+const KeyboardRequestRelease uint32 = 0
1674+const KeyboardEventKeymap uint32 = 0
1675+const KeyboardEventEnter uint32 = 1
1676+const KeyboardEventLeave uint32 = 2
1677+const KeyboardEventKey uint32 = 3
1678+const KeyboardEventModifiers uint32 = 4
1679+const KeyboardEventRepeatInfo uint32 = 5
1680+
1681+// KeyboardKeymapFormat keyboard mapping format.
1682+type KeyboardKeymapFormat uint32
1683+
1684+const (
1685+ KeyboardKeymapFormatNoKeymap KeyboardKeymapFormat = 0
1686+ KeyboardKeymapFormatXkbV1 KeyboardKeymapFormat = 1
1687+)
1688+
1689+// KeyboardKeyState physical key state.
1690+type KeyboardKeyState uint32
1691+
1692+const (
1693+ KeyboardKeyStateReleased KeyboardKeyState = 0
1694+ KeyboardKeyStatePressed KeyboardKeyState = 1
1695+ KeyboardKeyStateRepeated KeyboardKeyState = 2
1696+)
1697+
1698+// KeyboardHandler handles wl_keyboard requests.
1699+type KeyboardHandler interface {
1700+ Release(self *Keyboard)
1701+}
1702+
1703+func NewKeyboard(c server.Client, version int32, id uint32, h KeyboardHandler) (*Keyboard, error) {
1704+ if h == nil {
1705+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_keyboard")
1706+ }
1707+ var self *Keyboard
1708+ r, err := c.CreateResource(KeyboardInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
1709+ switch opcode {
1710+ case 0:
1711+ h.Release(self)
1712+ self.Destroy()
1713+ }
1714+ })
1715+ if err != nil {
1716+ return nil, err
1717+ }
1718+ self = WrapKeyboard(r)
1719+ r.Data = self
1720+ return self, nil
1721+}
1722+
1723+// SendKeymap keyboard mapping.
1724+func (self *Keyboard) SendKeymap(format uint32, fd int, size uint32) {
1725+ self.PostEvent(KeyboardEventKeymap, server.Uint(format), server.Fd(fd), server.Uint(size))
1726+}
1727+
1728+// SendEnter enter event.
1729+func (self *Keyboard) SendEnter(serial uint32, surface *Surface, keys []byte) {
1730+ var p runtime.Pinner
1731+ defer p.Unpin()
1732+ self.PostEvent(KeyboardEventEnter, server.Uint(serial), server.Object(resourceOf(surface)), server.Array(&p, keys))
1733+}
1734+
1735+// SendLeave leave event.
1736+func (self *Keyboard) SendLeave(serial uint32, surface *Surface) {
1737+ self.PostEvent(KeyboardEventLeave, server.Uint(serial), server.Object(resourceOf(surface)))
1738+}
1739+
1740+// SendKey key event.
1741+func (self *Keyboard) SendKey(serial uint32, time uint32, key uint32, state uint32) {
1742+ self.PostEvent(KeyboardEventKey, server.Uint(serial), server.Uint(time), server.Uint(key), server.Uint(state))
1743+}
1744+
1745+// SendModifiers modifier and group state.
1746+func (self *Keyboard) SendModifiers(serial uint32, modsDepressed uint32, modsLatched uint32, modsLocked uint32, group uint32) {
1747+ self.PostEvent(KeyboardEventModifiers, server.Uint(serial), server.Uint(modsDepressed), server.Uint(modsLatched), server.Uint(modsLocked), server.Uint(group))
1748+}
1749+
1750+// SendRepeatInfo repeat rate and delay (since version 4).
1751+func (self *Keyboard) SendRepeatInfo(rate int32, delay int32) {
1752+ self.PostEvent(KeyboardEventRepeatInfo, server.Int(rate), server.Int(delay))
1753+}
1754+func NewKeyboardGlobal(d *server.Display, version int32, bind server.BindFunc) error {
1755+ return d.CreateGlobal(KeyboardInterface, version, bind)
1756+}
1757+
1758+// Touch touchscreen input device.
1759+type Touch struct{ *server.Resource }
1760+
1761+func WrapTouch(r *server.Resource) *Touch {
1762+ if r == nil {
1763+ return nil
1764+ }
1765+ return &Touch{r}
1766+}
1767+
1768+const TouchRequestRelease uint32 = 0
1769+const TouchEventDown uint32 = 0
1770+const TouchEventUp uint32 = 1
1771+const TouchEventMotion uint32 = 2
1772+const TouchEventFrame uint32 = 3
1773+const TouchEventCancel uint32 = 4
1774+const TouchEventShape uint32 = 5
1775+const TouchEventOrientation uint32 = 6
1776+
1777+// TouchHandler handles wl_touch requests.
1778+type TouchHandler interface {
1779+ Release(self *Touch)
1780+}
1781+
1782+func NewTouch(c server.Client, version int32, id uint32, h TouchHandler) (*Touch, error) {
1783+ if h == nil {
1784+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_touch")
1785+ }
1786+ var self *Touch
1787+ r, err := c.CreateResource(TouchInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
1788+ switch opcode {
1789+ case 0:
1790+ h.Release(self)
1791+ self.Destroy()
1792+ }
1793+ })
1794+ if err != nil {
1795+ return nil, err
1796+ }
1797+ self = WrapTouch(r)
1798+ r.Data = self
1799+ return self, nil
1800+}
1801+
1802+// SendDown touch down event and beginning of a touch sequence.
1803+func (self *Touch) SendDown(serial uint32, time uint32, surface *Surface, id int32, x server.Fixed, y server.Fixed) {
1804+ self.PostEvent(TouchEventDown, server.Uint(serial), server.Uint(time), server.Object(resourceOf(surface)), server.Int(id), server.FixedArg(x), server.FixedArg(y))
1805+}
1806+
1807+// SendUp end of a touch event sequence.
1808+func (self *Touch) SendUp(serial uint32, time uint32, id int32) {
1809+ self.PostEvent(TouchEventUp, server.Uint(serial), server.Uint(time), server.Int(id))
1810+}
1811+
1812+// SendMotion update of touch point coordinates.
1813+func (self *Touch) SendMotion(time uint32, id int32, x server.Fixed, y server.Fixed) {
1814+ self.PostEvent(TouchEventMotion, server.Uint(time), server.Int(id), server.FixedArg(x), server.FixedArg(y))
1815+}
1816+
1817+// SendFrame end of touch frame event.
1818+func (self *Touch) SendFrame() {
1819+ self.PostEvent(TouchEventFrame)
1820+}
1821+
1822+// SendCancel touch session cancelled.
1823+func (self *Touch) SendCancel() {
1824+ self.PostEvent(TouchEventCancel)
1825+}
1826+
1827+// SendShape update shape of touch point (since version 6).
1828+func (self *Touch) SendShape(id int32, major server.Fixed, minor server.Fixed) {
1829+ self.PostEvent(TouchEventShape, server.Int(id), server.FixedArg(major), server.FixedArg(minor))
1830+}
1831+
1832+// SendOrientation update orientation of touch point (since version 6).
1833+func (self *Touch) SendOrientation(id int32, orientation server.Fixed) {
1834+ self.PostEvent(TouchEventOrientation, server.Int(id), server.FixedArg(orientation))
1835+}
1836+func NewTouchGlobal(d *server.Display, version int32, bind server.BindFunc) error {
1837+ return d.CreateGlobal(TouchInterface, version, bind)
1838+}
1839+
1840+// Output compositor output region.
1841+type Output struct{ *server.Resource }
1842+
1843+func WrapOutput(r *server.Resource) *Output {
1844+ if r == nil {
1845+ return nil
1846+ }
1847+ return &Output{r}
1848+}
1849+
1850+const OutputRequestRelease uint32 = 0
1851+const OutputEventGeometry uint32 = 0
1852+const OutputEventMode uint32 = 1
1853+const OutputEventDone uint32 = 2
1854+const OutputEventScale uint32 = 3
1855+const OutputEventName uint32 = 4
1856+const OutputEventDescription uint32 = 5
1857+
1858+// OutputSubpixel subpixel geometry information.
1859+type OutputSubpixel uint32
1860+
1861+const (
1862+ OutputSubpixelUnknown OutputSubpixel = 0
1863+ OutputSubpixelNone OutputSubpixel = 1
1864+ OutputSubpixelHorizontalRgb OutputSubpixel = 2
1865+ OutputSubpixelHorizontalBgr OutputSubpixel = 3
1866+ OutputSubpixelVerticalRgb OutputSubpixel = 4
1867+ OutputSubpixelVerticalBgr OutputSubpixel = 5
1868+)
1869+
1870+// OutputTransform transformation applied to buffer contents.
1871+type OutputTransform uint32
1872+
1873+const (
1874+ OutputTransformNormal OutputTransform = 0
1875+ OutputTransform90 OutputTransform = 1
1876+ OutputTransform180 OutputTransform = 2
1877+ OutputTransform270 OutputTransform = 3
1878+ OutputTransformFlipped OutputTransform = 4
1879+ OutputTransformFlipped90 OutputTransform = 5
1880+ OutputTransformFlipped180 OutputTransform = 6
1881+ OutputTransformFlipped270 OutputTransform = 7
1882+)
1883+
1884+// OutputMode mode information (bitfield).
1885+type OutputMode uint32
1886+
1887+const (
1888+ OutputModeCurrent OutputMode = 0x1
1889+ OutputModePreferred OutputMode = 0x2
1890+)
1891+
1892+// OutputHandler handles wl_output requests.
1893+type OutputHandler interface {
1894+ Release(self *Output)
1895+}
1896+
1897+func NewOutput(c server.Client, version int32, id uint32, h OutputHandler) (*Output, error) {
1898+ if h == nil {
1899+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_output")
1900+ }
1901+ var self *Output
1902+ r, err := c.CreateResource(OutputInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
1903+ switch opcode {
1904+ case 0:
1905+ h.Release(self)
1906+ self.Destroy()
1907+ }
1908+ })
1909+ if err != nil {
1910+ return nil, err
1911+ }
1912+ self = WrapOutput(r)
1913+ r.Data = self
1914+ return self, nil
1915+}
1916+
1917+// SendGeometry properties of the output.
1918+func (self *Output) SendGeometry(x int32, y int32, physicalWidth int32, physicalHeight int32, subpixel int32, make string, model string, transform int32) {
1919+ var p runtime.Pinner
1920+ defer p.Unpin()
1921+ self.PostEvent(OutputEventGeometry, server.Int(x), server.Int(y), server.Int(physicalWidth), server.Int(physicalHeight), server.Int(subpixel), server.String(&p, make, false), server.String(&p, model, false), server.Int(transform))
1922+}
1923+
1924+// SendMode advertise available modes for the output.
1925+func (self *Output) SendMode(flags uint32, width int32, height int32, refresh int32) {
1926+ self.PostEvent(OutputEventMode, server.Uint(flags), server.Int(width), server.Int(height), server.Int(refresh))
1927+}
1928+
1929+// SendDone sent all information about output (since version 2).
1930+func (self *Output) SendDone() {
1931+ self.PostEvent(OutputEventDone)
1932+}
1933+
1934+// SendScale output scaling properties (since version 2).
1935+func (self *Output) SendScale(factor int32) {
1936+ self.PostEvent(OutputEventScale, server.Int(factor))
1937+}
1938+
1939+// SendName name of this output (since version 4).
1940+func (self *Output) SendName(name string) {
1941+ var p runtime.Pinner
1942+ defer p.Unpin()
1943+ self.PostEvent(OutputEventName, server.String(&p, name, false))
1944+}
1945+
1946+// SendDescription human-readable description of this output (since version 4).
1947+func (self *Output) SendDescription(description string) {
1948+ var p runtime.Pinner
1949+ defer p.Unpin()
1950+ self.PostEvent(OutputEventDescription, server.String(&p, description, false))
1951+}
1952+func NewOutputGlobal(d *server.Display, version int32, bind server.BindFunc) error {
1953+ return d.CreateGlobal(OutputInterface, version, bind)
1954+}
1955+
1956+// Region region interface.
1957+type Region struct{ *server.Resource }
1958+
1959+func WrapRegion(r *server.Resource) *Region {
1960+ if r == nil {
1961+ return nil
1962+ }
1963+ return &Region{r}
1964+}
1965+
1966+const RegionRequestDestroy uint32 = 0
1967+const RegionRequestAdd uint32 = 1
1968+const RegionRequestSubtract uint32 = 2
1969+
1970+// RegionHandler handles wl_region requests.
1971+type RegionHandler interface {
1972+ Destroy(self *Region)
1973+ Add(self *Region, x int32, y int32, width int32, height int32)
1974+ Subtract(self *Region, x int32, y int32, width int32, height int32)
1975+}
1976+
1977+func NewRegion(c server.Client, version int32, id uint32, h RegionHandler) (*Region, error) {
1978+ if h == nil {
1979+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_region")
1980+ }
1981+ var self *Region
1982+ r, err := c.CreateResource(RegionInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
1983+ switch opcode {
1984+ case 0:
1985+ h.Destroy(self)
1986+ self.Destroy()
1987+ case 1:
1988+ h.Add(self, args[0].Int(), args[1].Int(), args[2].Int(), args[3].Int())
1989+ case 2:
1990+ h.Subtract(self, args[0].Int(), args[1].Int(), args[2].Int(), args[3].Int())
1991+ }
1992+ })
1993+ if err != nil {
1994+ return nil, err
1995+ }
1996+ self = WrapRegion(r)
1997+ r.Data = self
1998+ return self, nil
1999+}
2000+func NewRegionGlobal(d *server.Display, version int32, bind server.BindFunc) error {
2001+ return d.CreateGlobal(RegionInterface, version, bind)
2002+}
2003+
2004+// Subcompositor sub-surface compositing.
2005+type Subcompositor struct{ *server.Resource }
2006+
2007+func WrapSubcompositor(r *server.Resource) *Subcompositor {
2008+ if r == nil {
2009+ return nil
2010+ }
2011+ return &Subcompositor{r}
2012+}
2013+
2014+const SubcompositorRequestDestroy uint32 = 0
2015+const SubcompositorRequestGetSubsurface uint32 = 1
2016+
2017+// SubcompositorError .
2018+type SubcompositorError uint32
2019+
2020+const (
2021+ SubcompositorErrorBadSurface SubcompositorError = 0
2022+ SubcompositorErrorBadParent SubcompositorError = 1
2023+)
2024+
2025+// SubcompositorHandler handles wl_subcompositor requests.
2026+type SubcompositorHandler interface {
2027+ Destroy(self *Subcompositor)
2028+ GetSubsurface(self *Subcompositor, id uint32, surface *Surface, parent *Surface)
2029+}
2030+
2031+func NewSubcompositor(c server.Client, version int32, id uint32, h SubcompositorHandler) (*Subcompositor, error) {
2032+ if h == nil {
2033+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_subcompositor")
2034+ }
2035+ var self *Subcompositor
2036+ r, err := c.CreateResource(SubcompositorInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
2037+ switch opcode {
2038+ case 0:
2039+ h.Destroy(self)
2040+ self.Destroy()
2041+ case 1:
2042+ h.GetSubsurface(self, args[0].NewID(), WrapSurface(args[1].Resource()), WrapSurface(args[2].Resource()))
2043+ }
2044+ })
2045+ if err != nil {
2046+ return nil, err
2047+ }
2048+ self = WrapSubcompositor(r)
2049+ r.Data = self
2050+ return self, nil
2051+}
2052+func NewSubcompositorGlobal(d *server.Display, version int32, bind server.BindFunc) error {
2053+ return d.CreateGlobal(SubcompositorInterface, version, bind)
2054+}
2055+
2056+// Subsurface sub-surface interface to a wl_surface.
2057+type Subsurface struct{ *server.Resource }
2058+
2059+func WrapSubsurface(r *server.Resource) *Subsurface {
2060+ if r == nil {
2061+ return nil
2062+ }
2063+ return &Subsurface{r}
2064+}
2065+
2066+const SubsurfaceRequestDestroy uint32 = 0
2067+const SubsurfaceRequestSetPosition uint32 = 1
2068+const SubsurfaceRequestPlaceAbove uint32 = 2
2069+const SubsurfaceRequestPlaceBelow uint32 = 3
2070+const SubsurfaceRequestSetSync uint32 = 4
2071+const SubsurfaceRequestSetDesync uint32 = 5
2072+
2073+// SubsurfaceError .
2074+type SubsurfaceError uint32
2075+
2076+const (
2077+ SubsurfaceErrorBadSurface SubsurfaceError = 0
2078+)
2079+
2080+// SubsurfaceHandler handles wl_subsurface requests.
2081+type SubsurfaceHandler interface {
2082+ Destroy(self *Subsurface)
2083+ SetPosition(self *Subsurface, x int32, y int32)
2084+ PlaceAbove(self *Subsurface, sibling *Surface)
2085+ PlaceBelow(self *Subsurface, sibling *Surface)
2086+ SetSync(self *Subsurface)
2087+ SetDesync(self *Subsurface)
2088+}
2089+
2090+func NewSubsurface(c server.Client, version int32, id uint32, h SubsurfaceHandler) (*Subsurface, error) {
2091+ if h == nil {
2092+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_subsurface")
2093+ }
2094+ var self *Subsurface
2095+ r, err := c.CreateResource(SubsurfaceInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
2096+ switch opcode {
2097+ case 0:
2098+ h.Destroy(self)
2099+ self.Destroy()
2100+ case 1:
2101+ h.SetPosition(self, args[0].Int(), args[1].Int())
2102+ case 2:
2103+ h.PlaceAbove(self, WrapSurface(args[0].Resource()))
2104+ case 3:
2105+ h.PlaceBelow(self, WrapSurface(args[0].Resource()))
2106+ case 4:
2107+ h.SetSync(self)
2108+ case 5:
2109+ h.SetDesync(self)
2110+ }
2111+ })
2112+ if err != nil {
2113+ return nil, err
2114+ }
2115+ self = WrapSubsurface(r)
2116+ r.Data = self
2117+ return self, nil
2118+}
2119+func NewSubsurfaceGlobal(d *server.Display, version int32, bind server.BindFunc) error {
2120+ return d.CreateGlobal(SubsurfaceInterface, version, bind)
2121+}
2122+
2123+// Fixes wayland protocol fixes.
2124+type Fixes struct{ *server.Resource }
2125+
2126+func WrapFixes(r *server.Resource) *Fixes {
2127+ if r == nil {
2128+ return nil
2129+ }
2130+ return &Fixes{r}
2131+}
2132+
2133+const FixesRequestDestroy uint32 = 0
2134+const FixesRequestDestroyRegistry uint32 = 1
2135+const FixesRequestAckGlobalRemove uint32 = 2
2136+
2137+// FixesError wl_fixes error values.
2138+type FixesError uint32
2139+
2140+const (
2141+ FixesErrorInvalidAckRemove FixesError = 0
2142+)
2143+
2144+// FixesHandler handles wl_fixes requests.
2145+type FixesHandler interface {
2146+ Destroy(self *Fixes)
2147+ DestroyRegistry(self *Fixes, registry *Registry)
2148+ AckGlobalRemove(self *Fixes, registry *Registry, name uint32)
2149+}
2150+
2151+func NewFixes(c server.Client, version int32, id uint32, h FixesHandler) (*Fixes, error) {
2152+ if h == nil {
2153+ return nil, fmt.Errorf("purego-libwayland: nil handler for wl_fixes")
2154+ }
2155+ var self *Fixes
2156+ r, err := c.CreateResource(FixesInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
2157+ switch opcode {
2158+ case 0:
2159+ h.Destroy(self)
2160+ self.Destroy()
2161+ case 1:
2162+ h.DestroyRegistry(self, WrapRegistry(args[0].Resource()))
2163+ case 2:
2164+ h.AckGlobalRemove(self, WrapRegistry(args[0].Resource()), args[1].Uint())
2165+ }
2166+ })
2167+ if err != nil {
2168+ return nil, err
2169+ }
2170+ self = WrapFixes(r)
2171+ r.Data = self
2172+ return self, nil
2173+}
2174+func NewFixesGlobal(d *server.Display, version int32, bind server.BindFunc) error {
2175+ return d.CreateGlobal(FixesInterface, version, bind)
2176+}
2177+func resourceOf(v interface{ GetResource() *server.Resource }) *server.Resource {
2178+ if v == nil {
2179+ return nil
2180+ }
2181+ return v.GetResource()
2182+}
2183+func (self *Display) GetResource() *server.Resource {
2184+ if self == nil {
2185+ return nil
2186+ }
2187+ return self.Resource
2188+}
2189+func (self *Registry) GetResource() *server.Resource {
2190+ if self == nil {
2191+ return nil
2192+ }
2193+ return self.Resource
2194+}
2195+func (self *Callback) GetResource() *server.Resource {
2196+ if self == nil {
2197+ return nil
2198+ }
2199+ return self.Resource
2200+}
2201+func (self *Compositor) GetResource() *server.Resource {
2202+ if self == nil {
2203+ return nil
2204+ }
2205+ return self.Resource
2206+}
2207+func (self *ShmPool) GetResource() *server.Resource {
2208+ if self == nil {
2209+ return nil
2210+ }
2211+ return self.Resource
2212+}
2213+func (self *Shm) GetResource() *server.Resource {
2214+ if self == nil {
2215+ return nil
2216+ }
2217+ return self.Resource
2218+}
2219+func (self *Buffer) GetResource() *server.Resource {
2220+ if self == nil {
2221+ return nil
2222+ }
2223+ return self.Resource
2224+}
2225+func (self *DataOffer) GetResource() *server.Resource {
2226+ if self == nil {
2227+ return nil
2228+ }
2229+ return self.Resource
2230+}
2231+func (self *DataSource) GetResource() *server.Resource {
2232+ if self == nil {
2233+ return nil
2234+ }
2235+ return self.Resource
2236+}
2237+func (self *DataDevice) GetResource() *server.Resource {
2238+ if self == nil {
2239+ return nil
2240+ }
2241+ return self.Resource
2242+}
2243+func (self *DataDeviceManager) GetResource() *server.Resource {
2244+ if self == nil {
2245+ return nil
2246+ }
2247+ return self.Resource
2248+}
2249+func (self *Shell) GetResource() *server.Resource {
2250+ if self == nil {
2251+ return nil
2252+ }
2253+ return self.Resource
2254+}
2255+func (self *ShellSurface) GetResource() *server.Resource {
2256+ if self == nil {
2257+ return nil
2258+ }
2259+ return self.Resource
2260+}
2261+func (self *Surface) GetResource() *server.Resource {
2262+ if self == nil {
2263+ return nil
2264+ }
2265+ return self.Resource
2266+}
2267+func (self *Seat) GetResource() *server.Resource {
2268+ if self == nil {
2269+ return nil
2270+ }
2271+ return self.Resource
2272+}
2273+func (self *Pointer) GetResource() *server.Resource {
2274+ if self == nil {
2275+ return nil
2276+ }
2277+ return self.Resource
2278+}
2279+func (self *Keyboard) GetResource() *server.Resource {
2280+ if self == nil {
2281+ return nil
2282+ }
2283+ return self.Resource
2284+}
2285+func (self *Touch) GetResource() *server.Resource {
2286+ if self == nil {
2287+ return nil
2288+ }
2289+ return self.Resource
2290+}
2291+func (self *Output) GetResource() *server.Resource {
2292+ if self == nil {
2293+ return nil
2294+ }
2295+ return self.Resource
2296+}
2297+func (self *Region) GetResource() *server.Resource {
2298+ if self == nil {
2299+ return nil
2300+ }
2301+ return self.Resource
2302+}
2303+func (self *Subcompositor) GetResource() *server.Resource {
2304+ if self == nil {
2305+ return nil
2306+ }
2307+ return self.Resource
2308+}
2309+func (self *Subsurface) GetResource() *server.Resource {
2310+ if self == nil {
2311+ return nil
2312+ }
2313+ return self.Resource
2314+}
2315+func (self *Fixes) GetResource() *server.Resource {
2316+ if self == nil {
2317+ return nil
2318+ }
2319+ return self.Resource
2320+}
A protocol/wayland/wayland_test.go +25 -0
@@ -0,0 +1,25 @@
1+package wayland
2+
3+import (
4+ "github.com/bnema/purego-libwayland/server"
5+ "testing"
6+)
7+
8+func TestNilHandlerRejected(t *testing.T) {
9+ if _, err := NewCompositor(server.Client{}, 1, 1, nil); err == nil {
10+ t.Fatal("nil handler accepted")
11+ }
12+}
13+
14+func TestForwardReferences(t *testing.T) {
15+ for _, tc := range []struct {
16+ name string
17+ got, want interface{}
18+ }{
19+ {"create_surface", CompositorInterface.Requests[0].Types[0], SurfaceInterface},
20+ } {
21+ if tc.got == nil || tc.got != tc.want {
22+ t.Fatalf("%s type=%v want %v", tc.name, tc.got, tc.want)
23+ }
24+ }
25+}
A protocol/xdgshell/xdgshell.go +643 -0
@@ -0,0 +1,643 @@
1+// Code generated by wlgen; DO NOT EDIT.
2+package xdgshell
3+
4+import (
5+ "fmt"
6+ wayland "github.com/bnema/purego-libwayland/protocol/wayland"
7+ "github.com/bnema/purego-libwayland/server"
8+ "runtime"
9+)
10+
11+var WmBaseInterface *server.Interface
12+var PositionerInterface *server.Interface
13+var SurfaceInterface *server.Interface
14+var ToplevelInterface *server.Interface
15+var PopupInterface *server.Interface
16+
17+func init() {
18+ WmBaseInterface = &server.Interface{Name: "xdg_wm_base", Version: 7}
19+ PositionerInterface = &server.Interface{Name: "xdg_positioner", Version: 7}
20+ SurfaceInterface = &server.Interface{Name: "xdg_surface", Version: 7}
21+ ToplevelInterface = &server.Interface{Name: "xdg_toplevel", Version: 7}
22+ PopupInterface = &server.Interface{Name: "xdg_popup", Version: 7}
23+ WmBaseInterface.Requests = []server.Message{
24+ {Name: "destroy", Signature: "", Types: []*server.Interface{}},
25+ {Name: "create_positioner", Signature: "n", Types: []*server.Interface{PositionerInterface}},
26+ {Name: "get_xdg_surface", Signature: "no", Types: []*server.Interface{SurfaceInterface, wayland.SurfaceInterface}},
27+ {Name: "pong", Signature: "u", Types: []*server.Interface{nil}},
28+ }
29+ WmBaseInterface.Events = []server.Message{
30+ {Name: "ping", Signature: "u", Types: []*server.Interface{nil}},
31+ }
32+ PositionerInterface.Requests = []server.Message{
33+ {Name: "destroy", Signature: "", Types: []*server.Interface{}},
34+ {Name: "set_size", Signature: "ii", Types: []*server.Interface{nil, nil}},
35+ {Name: "set_anchor_rect", Signature: "iiii", Types: []*server.Interface{nil, nil, nil, nil}},
36+ {Name: "set_anchor", Signature: "u", Types: []*server.Interface{nil}},
37+ {Name: "set_gravity", Signature: "u", Types: []*server.Interface{nil}},
38+ {Name: "set_constraint_adjustment", Signature: "u", Types: []*server.Interface{nil}},
39+ {Name: "set_offset", Signature: "ii", Types: []*server.Interface{nil, nil}},
40+ {Name: "set_reactive", Signature: "3", Types: []*server.Interface{}},
41+ {Name: "set_parent_size", Signature: "3ii", Types: []*server.Interface{nil, nil}},
42+ {Name: "set_parent_configure", Signature: "3u", Types: []*server.Interface{nil}},
43+ }
44+ PositionerInterface.Events = []server.Message{}
45+ SurfaceInterface.Requests = []server.Message{
46+ {Name: "destroy", Signature: "", Types: []*server.Interface{}},
47+ {Name: "get_toplevel", Signature: "n", Types: []*server.Interface{ToplevelInterface}},
48+ {Name: "get_popup", Signature: "n?oo", Types: []*server.Interface{PopupInterface, SurfaceInterface, PositionerInterface}},
49+ {Name: "set_window_geometry", Signature: "iiii", Types: []*server.Interface{nil, nil, nil, nil}},
50+ {Name: "ack_configure", Signature: "u", Types: []*server.Interface{nil}},
51+ }
52+ SurfaceInterface.Events = []server.Message{
53+ {Name: "configure", Signature: "u", Types: []*server.Interface{nil}},
54+ }
55+ ToplevelInterface.Requests = []server.Message{
56+ {Name: "destroy", Signature: "", Types: []*server.Interface{}},
57+ {Name: "set_parent", Signature: "?o", Types: []*server.Interface{ToplevelInterface}},
58+ {Name: "set_title", Signature: "s", Types: []*server.Interface{nil}},
59+ {Name: "set_app_id", Signature: "s", Types: []*server.Interface{nil}},
60+ {Name: "show_window_menu", Signature: "ouii", Types: []*server.Interface{wayland.SeatInterface, nil, nil, nil}},
61+ {Name: "move", Signature: "ou", Types: []*server.Interface{wayland.SeatInterface, nil}},
62+ {Name: "resize", Signature: "ouu", Types: []*server.Interface{wayland.SeatInterface, nil, nil}},
63+ {Name: "set_max_size", Signature: "ii", Types: []*server.Interface{nil, nil}},
64+ {Name: "set_min_size", Signature: "ii", Types: []*server.Interface{nil, nil}},
65+ {Name: "set_maximized", Signature: "", Types: []*server.Interface{}},
66+ {Name: "unset_maximized", Signature: "", Types: []*server.Interface{}},
67+ {Name: "set_fullscreen", Signature: "?o", Types: []*server.Interface{wayland.OutputInterface}},
68+ {Name: "unset_fullscreen", Signature: "", Types: []*server.Interface{}},
69+ {Name: "set_minimized", Signature: "", Types: []*server.Interface{}},
70+ }
71+ ToplevelInterface.Events = []server.Message{
72+ {Name: "configure", Signature: "iia", Types: []*server.Interface{nil, nil, nil}},
73+ {Name: "close", Signature: "", Types: []*server.Interface{}},
74+ {Name: "configure_bounds", Signature: "4ii", Types: []*server.Interface{nil, nil}},
75+ {Name: "wm_capabilities", Signature: "5a", Types: []*server.Interface{nil}},
76+ }
77+ PopupInterface.Requests = []server.Message{
78+ {Name: "destroy", Signature: "", Types: []*server.Interface{}},
79+ {Name: "grab", Signature: "ou", Types: []*server.Interface{wayland.SeatInterface, nil}},
80+ {Name: "reposition", Signature: "3ou", Types: []*server.Interface{PositionerInterface, nil}},
81+ }
82+ PopupInterface.Events = []server.Message{
83+ {Name: "configure", Signature: "iiii", Types: []*server.Interface{nil, nil, nil, nil}},
84+ {Name: "popup_done", Signature: "", Types: []*server.Interface{}},
85+ {Name: "repositioned", Signature: "3u", Types: []*server.Interface{nil}},
86+ }
87+ if err := server.NewInterfaces(WmBaseInterface, PositionerInterface, SurfaceInterface, ToplevelInterface, PopupInterface); err != nil {
88+ panic(err)
89+ }
90+}
91+
92+// WmBase create desktop-style surfaces.
93+type WmBase struct{ *server.Resource }
94+
95+func WrapWmBase(r *server.Resource) *WmBase {
96+ if r == nil {
97+ return nil
98+ }
99+ return &WmBase{r}
100+}
101+
102+const WmBaseRequestDestroy uint32 = 0
103+const WmBaseRequestCreatePositioner uint32 = 1
104+const WmBaseRequestGetXdgSurface uint32 = 2
105+const WmBaseRequestPong uint32 = 3
106+const WmBaseEventPing uint32 = 0
107+
108+// WmBaseError .
109+type WmBaseError uint32
110+
111+const (
112+ WmBaseErrorRole WmBaseError = 0
113+ WmBaseErrorDefunctSurfaces WmBaseError = 1
114+ WmBaseErrorNotTheTopmostPopup WmBaseError = 2
115+ WmBaseErrorInvalidPopupParent WmBaseError = 3
116+ WmBaseErrorInvalidSurfaceState WmBaseError = 4
117+ WmBaseErrorInvalidPositioner WmBaseError = 5
118+ WmBaseErrorUnresponsive WmBaseError = 6
119+)
120+
121+// WmBaseHandler handles xdg_wm_base requests.
122+type WmBaseHandler interface {
123+ Destroy(self *WmBase)
124+ CreatePositioner(self *WmBase, id uint32)
125+ GetXdgSurface(self *WmBase, id uint32, surface *wayland.Surface)
126+ Pong(self *WmBase, serial uint32)
127+}
128+
129+func NewWmBase(c server.Client, version int32, id uint32, h WmBaseHandler) (*WmBase, error) {
130+ if h == nil {
131+ return nil, fmt.Errorf("purego-libwayland: nil handler for xdg_wm_base")
132+ }
133+ var self *WmBase
134+ r, err := c.CreateResource(WmBaseInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
135+ switch opcode {
136+ case 0:
137+ h.Destroy(self)
138+ self.Destroy()
139+ case 1:
140+ h.CreatePositioner(self, args[0].NewID())
141+ case 2:
142+ h.GetXdgSurface(self, args[0].NewID(), wayland.WrapSurface(args[1].Resource()))
143+ case 3:
144+ h.Pong(self, args[0].Uint())
145+ }
146+ })
147+ if err != nil {
148+ return nil, err
149+ }
150+ self = WrapWmBase(r)
151+ r.Data = self
152+ return self, nil
153+}
154+
155+// SendPing check if the client is alive.
156+func (self *WmBase) SendPing(serial uint32) {
157+ self.PostEvent(WmBaseEventPing, server.Uint(serial))
158+}
159+func NewWmBaseGlobal(d *server.Display, version int32, bind server.BindFunc) error {
160+ return d.CreateGlobal(WmBaseInterface, version, bind)
161+}
162+
163+// Positioner child surface positioner.
164+type Positioner struct{ *server.Resource }
165+
166+func WrapPositioner(r *server.Resource) *Positioner {
167+ if r == nil {
168+ return nil
169+ }
170+ return &Positioner{r}
171+}
172+
173+const PositionerRequestDestroy uint32 = 0
174+const PositionerRequestSetSize uint32 = 1
175+const PositionerRequestSetAnchorRect uint32 = 2
176+const PositionerRequestSetAnchor uint32 = 3
177+const PositionerRequestSetGravity uint32 = 4
178+const PositionerRequestSetConstraintAdjustment uint32 = 5
179+const PositionerRequestSetOffset uint32 = 6
180+const PositionerRequestSetReactive uint32 = 7
181+const PositionerRequestSetParentSize uint32 = 8
182+const PositionerRequestSetParentConfigure uint32 = 9
183+
184+// PositionerError .
185+type PositionerError uint32
186+
187+const (
188+ PositionerErrorInvalidInput PositionerError = 0
189+)
190+
191+// PositionerAnchor .
192+type PositionerAnchor uint32
193+
194+const (
195+ PositionerAnchorNone PositionerAnchor = 0
196+ PositionerAnchorTop PositionerAnchor = 1
197+ PositionerAnchorBottom PositionerAnchor = 2
198+ PositionerAnchorLeft PositionerAnchor = 3
199+ PositionerAnchorRight PositionerAnchor = 4
200+ PositionerAnchorTopLeft PositionerAnchor = 5
201+ PositionerAnchorBottomLeft PositionerAnchor = 6
202+ PositionerAnchorTopRight PositionerAnchor = 7
203+ PositionerAnchorBottomRight PositionerAnchor = 8
204+)
205+
206+// PositionerGravity .
207+type PositionerGravity uint32
208+
209+const (
210+ PositionerGravityNone PositionerGravity = 0
211+ PositionerGravityTop PositionerGravity = 1
212+ PositionerGravityBottom PositionerGravity = 2
213+ PositionerGravityLeft PositionerGravity = 3
214+ PositionerGravityRight PositionerGravity = 4
215+ PositionerGravityTopLeft PositionerGravity = 5
216+ PositionerGravityBottomLeft PositionerGravity = 6
217+ PositionerGravityTopRight PositionerGravity = 7
218+ PositionerGravityBottomRight PositionerGravity = 8
219+)
220+
221+// PositionerConstraintAdjustment constraint adjustments (bitfield).
222+type PositionerConstraintAdjustment uint32
223+
224+const (
225+ PositionerConstraintAdjustmentNone PositionerConstraintAdjustment = 0
226+ PositionerConstraintAdjustmentSlideX PositionerConstraintAdjustment = 1
227+ PositionerConstraintAdjustmentSlideY PositionerConstraintAdjustment = 2
228+ PositionerConstraintAdjustmentFlipX PositionerConstraintAdjustment = 4
229+ PositionerConstraintAdjustmentFlipY PositionerConstraintAdjustment = 8
230+ PositionerConstraintAdjustmentResizeX PositionerConstraintAdjustment = 16
231+ PositionerConstraintAdjustmentResizeY PositionerConstraintAdjustment = 32
232+)
233+
234+// PositionerHandler handles xdg_positioner requests.
235+type PositionerHandler interface {
236+ Destroy(self *Positioner)
237+ SetSize(self *Positioner, width int32, height int32)
238+ SetAnchorRect(self *Positioner, x int32, y int32, width int32, height int32)
239+ SetAnchor(self *Positioner, anchor uint32)
240+ SetGravity(self *Positioner, gravity uint32)
241+ SetConstraintAdjustment(self *Positioner, constraintAdjustment uint32)
242+ SetOffset(self *Positioner, x int32, y int32)
243+ SetReactive(self *Positioner)
244+ SetParentSize(self *Positioner, parentWidth int32, parentHeight int32)
245+ SetParentConfigure(self *Positioner, serial uint32)
246+}
247+
248+func NewPositioner(c server.Client, version int32, id uint32, h PositionerHandler) (*Positioner, error) {
249+ if h == nil {
250+ return nil, fmt.Errorf("purego-libwayland: nil handler for xdg_positioner")
251+ }
252+ var self *Positioner
253+ r, err := c.CreateResource(PositionerInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
254+ switch opcode {
255+ case 0:
256+ h.Destroy(self)
257+ self.Destroy()
258+ case 1:
259+ h.SetSize(self, args[0].Int(), args[1].Int())
260+ case 2:
261+ h.SetAnchorRect(self, args[0].Int(), args[1].Int(), args[2].Int(), args[3].Int())
262+ case 3:
263+ h.SetAnchor(self, args[0].Uint())
264+ case 4:
265+ h.SetGravity(self, args[0].Uint())
266+ case 5:
267+ h.SetConstraintAdjustment(self, args[0].Uint())
268+ case 6:
269+ h.SetOffset(self, args[0].Int(), args[1].Int())
270+ case 7:
271+ h.SetReactive(self)
272+ case 8:
273+ h.SetParentSize(self, args[0].Int(), args[1].Int())
274+ case 9:
275+ h.SetParentConfigure(self, args[0].Uint())
276+ }
277+ })
278+ if err != nil {
279+ return nil, err
280+ }
281+ self = WrapPositioner(r)
282+ r.Data = self
283+ return self, nil
284+}
285+func NewPositionerGlobal(d *server.Display, version int32, bind server.BindFunc) error {
286+ return d.CreateGlobal(PositionerInterface, version, bind)
287+}
288+
289+// Surface desktop user interface surface base interface.
290+type Surface struct{ *server.Resource }
291+
292+func WrapSurface(r *server.Resource) *Surface {
293+ if r == nil {
294+ return nil
295+ }
296+ return &Surface{r}
297+}
298+
299+const SurfaceRequestDestroy uint32 = 0
300+const SurfaceRequestGetToplevel uint32 = 1
301+const SurfaceRequestGetPopup uint32 = 2
302+const SurfaceRequestSetWindowGeometry uint32 = 3
303+const SurfaceRequestAckConfigure uint32 = 4
304+const SurfaceEventConfigure uint32 = 0
305+
306+// SurfaceError .
307+type SurfaceError uint32
308+
309+const (
310+ SurfaceErrorNotConstructed SurfaceError = 1
311+ SurfaceErrorAlreadyConstructed SurfaceError = 2
312+ SurfaceErrorUnconfiguredBuffer SurfaceError = 3
313+ SurfaceErrorInvalidSerial SurfaceError = 4
314+ SurfaceErrorInvalidSize SurfaceError = 5
315+ SurfaceErrorDefunctRoleObject SurfaceError = 6
316+)
317+
318+// SurfaceHandler handles xdg_surface requests.
319+type SurfaceHandler interface {
320+ Destroy(self *Surface)
321+ GetToplevel(self *Surface, id uint32)
322+ GetPopup(self *Surface, id uint32, parent *Surface, positioner *Positioner)
323+ SetWindowGeometry(self *Surface, x int32, y int32, width int32, height int32)
324+ AckConfigure(self *Surface, serial uint32)
325+}
326+
327+func NewSurface(c server.Client, version int32, id uint32, h SurfaceHandler) (*Surface, error) {
328+ if h == nil {
329+ return nil, fmt.Errorf("purego-libwayland: nil handler for xdg_surface")
330+ }
331+ var self *Surface
332+ r, err := c.CreateResource(SurfaceInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
333+ switch opcode {
334+ case 0:
335+ h.Destroy(self)
336+ self.Destroy()
337+ case 1:
338+ h.GetToplevel(self, args[0].NewID())
339+ case 2:
340+ h.GetPopup(self, args[0].NewID(), WrapSurface(args[1].Resource()), WrapPositioner(args[2].Resource()))
341+ case 3:
342+ h.SetWindowGeometry(self, args[0].Int(), args[1].Int(), args[2].Int(), args[3].Int())
343+ case 4:
344+ h.AckConfigure(self, args[0].Uint())
345+ }
346+ })
347+ if err != nil {
348+ return nil, err
349+ }
350+ self = WrapSurface(r)
351+ r.Data = self
352+ return self, nil
353+}
354+
355+// SendConfigure suggest a surface change.
356+func (self *Surface) SendConfigure(serial uint32) {
357+ self.PostEvent(SurfaceEventConfigure, server.Uint(serial))
358+}
359+func NewSurfaceGlobal(d *server.Display, version int32, bind server.BindFunc) error {
360+ return d.CreateGlobal(SurfaceInterface, version, bind)
361+}
362+
363+// Toplevel toplevel surface.
364+type Toplevel struct{ *server.Resource }
365+
366+func WrapToplevel(r *server.Resource) *Toplevel {
367+ if r == nil {
368+ return nil
369+ }
370+ return &Toplevel{r}
371+}
372+
373+const ToplevelRequestDestroy uint32 = 0
374+const ToplevelRequestSetParent uint32 = 1
375+const ToplevelRequestSetTitle uint32 = 2
376+const ToplevelRequestSetAppId uint32 = 3
377+const ToplevelRequestShowWindowMenu uint32 = 4
378+const ToplevelRequestMove uint32 = 5
379+const ToplevelRequestResize uint32 = 6
380+const ToplevelRequestSetMaxSize uint32 = 7
381+const ToplevelRequestSetMinSize uint32 = 8
382+const ToplevelRequestSetMaximized uint32 = 9
383+const ToplevelRequestUnsetMaximized uint32 = 10
384+const ToplevelRequestSetFullscreen uint32 = 11
385+const ToplevelRequestUnsetFullscreen uint32 = 12
386+const ToplevelRequestSetMinimized uint32 = 13
387+const ToplevelEventConfigure uint32 = 0
388+const ToplevelEventClose uint32 = 1
389+const ToplevelEventConfigureBounds uint32 = 2
390+const ToplevelEventWmCapabilities uint32 = 3
391+
392+// ToplevelError .
393+type ToplevelError uint32
394+
395+const (
396+ ToplevelErrorInvalidResizeEdge ToplevelError = 0
397+ ToplevelErrorInvalidParent ToplevelError = 1
398+ ToplevelErrorInvalidSize ToplevelError = 2
399+)
400+
401+// ToplevelResizeEdge edge values for resizing.
402+type ToplevelResizeEdge uint32
403+
404+const (
405+ ToplevelResizeEdgeNone ToplevelResizeEdge = 0
406+ ToplevelResizeEdgeTop ToplevelResizeEdge = 1
407+ ToplevelResizeEdgeBottom ToplevelResizeEdge = 2
408+ ToplevelResizeEdgeLeft ToplevelResizeEdge = 4
409+ ToplevelResizeEdgeTopLeft ToplevelResizeEdge = 5
410+ ToplevelResizeEdgeBottomLeft ToplevelResizeEdge = 6
411+ ToplevelResizeEdgeRight ToplevelResizeEdge = 8
412+ ToplevelResizeEdgeTopRight ToplevelResizeEdge = 9
413+ ToplevelResizeEdgeBottomRight ToplevelResizeEdge = 10
414+)
415+
416+// ToplevelState types of state on the surface.
417+type ToplevelState uint32
418+
419+const (
420+ ToplevelStateMaximized ToplevelState = 1
421+ ToplevelStateFullscreen ToplevelState = 2
422+ ToplevelStateResizing ToplevelState = 3
423+ ToplevelStateActivated ToplevelState = 4
424+ ToplevelStateTiledLeft ToplevelState = 5
425+ ToplevelStateTiledRight ToplevelState = 6
426+ ToplevelStateTiledTop ToplevelState = 7
427+ ToplevelStateTiledBottom ToplevelState = 8
428+ ToplevelStateSuspended ToplevelState = 9
429+ ToplevelStateConstrainedLeft ToplevelState = 10
430+ ToplevelStateConstrainedRight ToplevelState = 11
431+ ToplevelStateConstrainedTop ToplevelState = 12
432+ ToplevelStateConstrainedBottom ToplevelState = 13
433+)
434+
435+// ToplevelWmCapabilities .
436+type ToplevelWmCapabilities uint32
437+
438+const (
439+ ToplevelWmCapabilitiesWindowMenu ToplevelWmCapabilities = 1
440+ ToplevelWmCapabilitiesMaximize ToplevelWmCapabilities = 2
441+ ToplevelWmCapabilitiesFullscreen ToplevelWmCapabilities = 3
442+ ToplevelWmCapabilitiesMinimize ToplevelWmCapabilities = 4
443+)
444+
445+// ToplevelHandler handles xdg_toplevel requests.
446+type ToplevelHandler interface {
447+ Destroy(self *Toplevel)
448+ SetParent(self *Toplevel, parent *Toplevel)
449+ SetTitle(self *Toplevel, title string)
450+ SetAppId(self *Toplevel, appId string)
451+ ShowWindowMenu(self *Toplevel, seat *wayland.Seat, serial uint32, x int32, y int32)
452+ Move(self *Toplevel, seat *wayland.Seat, serial uint32)
453+ Resize(self *Toplevel, seat *wayland.Seat, serial uint32, edges uint32)
454+ SetMaxSize(self *Toplevel, width int32, height int32)
455+ SetMinSize(self *Toplevel, width int32, height int32)
456+ SetMaximized(self *Toplevel)
457+ UnsetMaximized(self *Toplevel)
458+ SetFullscreen(self *Toplevel, output *wayland.Output)
459+ UnsetFullscreen(self *Toplevel)
460+ SetMinimized(self *Toplevel)
461+}
462+
463+func NewToplevel(c server.Client, version int32, id uint32, h ToplevelHandler) (*Toplevel, error) {
464+ if h == nil {
465+ return nil, fmt.Errorf("purego-libwayland: nil handler for xdg_toplevel")
466+ }
467+ var self *Toplevel
468+ r, err := c.CreateResource(ToplevelInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
469+ switch opcode {
470+ case 0:
471+ h.Destroy(self)
472+ self.Destroy()
473+ case 1:
474+ h.SetParent(self, WrapToplevel(args[0].Resource()))
475+ case 2:
476+ h.SetTitle(self, args[0].String())
477+ case 3:
478+ h.SetAppId(self, args[0].String())
479+ case 4:
480+ h.ShowWindowMenu(self, wayland.WrapSeat(args[0].Resource()), args[1].Uint(), args[2].Int(), args[3].Int())
481+ case 5:
482+ h.Move(self, wayland.WrapSeat(args[0].Resource()), args[1].Uint())
483+ case 6:
484+ h.Resize(self, wayland.WrapSeat(args[0].Resource()), args[1].Uint(), args[2].Uint())
485+ case 7:
486+ h.SetMaxSize(self, args[0].Int(), args[1].Int())
487+ case 8:
488+ h.SetMinSize(self, args[0].Int(), args[1].Int())
489+ case 9:
490+ h.SetMaximized(self)
491+ case 10:
492+ h.UnsetMaximized(self)
493+ case 11:
494+ h.SetFullscreen(self, wayland.WrapOutput(args[0].Resource()))
495+ case 12:
496+ h.UnsetFullscreen(self)
497+ case 13:
498+ h.SetMinimized(self)
499+ }
500+ })
501+ if err != nil {
502+ return nil, err
503+ }
504+ self = WrapToplevel(r)
505+ r.Data = self
506+ return self, nil
507+}
508+
509+// SendConfigure suggest a surface change.
510+func (self *Toplevel) SendConfigure(width int32, height int32, states []byte) {
511+ var p runtime.Pinner
512+ defer p.Unpin()
513+ self.PostEvent(ToplevelEventConfigure, server.Int(width), server.Int(height), server.Array(&p, states))
514+}
515+
516+// SendClose surface wants to be closed.
517+func (self *Toplevel) SendClose() {
518+ self.PostEvent(ToplevelEventClose)
519+}
520+
521+// SendConfigureBounds recommended window geometry bounds (since version 4).
522+func (self *Toplevel) SendConfigureBounds(width int32, height int32) {
523+ self.PostEvent(ToplevelEventConfigureBounds, server.Int(width), server.Int(height))
524+}
525+
526+// SendWmCapabilities compositor capabilities (since version 5).
527+func (self *Toplevel) SendWmCapabilities(capabilities []byte) {
528+ var p runtime.Pinner
529+ defer p.Unpin()
530+ self.PostEvent(ToplevelEventWmCapabilities, server.Array(&p, capabilities))
531+}
532+func NewToplevelGlobal(d *server.Display, version int32, bind server.BindFunc) error {
533+ return d.CreateGlobal(ToplevelInterface, version, bind)
534+}
535+
536+// Popup short-lived, popup surfaces for menus.
537+type Popup struct{ *server.Resource }
538+
539+func WrapPopup(r *server.Resource) *Popup {
540+ if r == nil {
541+ return nil
542+ }
543+ return &Popup{r}
544+}
545+
546+const PopupRequestDestroy uint32 = 0
547+const PopupRequestGrab uint32 = 1
548+const PopupRequestReposition uint32 = 2
549+const PopupEventConfigure uint32 = 0
550+const PopupEventPopupDone uint32 = 1
551+const PopupEventRepositioned uint32 = 2
552+
553+// PopupError .
554+type PopupError uint32
555+
556+const (
557+ PopupErrorInvalidGrab PopupError = 0
558+)
559+
560+// PopupHandler handles xdg_popup requests.
561+type PopupHandler interface {
562+ Destroy(self *Popup)
563+ Grab(self *Popup, seat *wayland.Seat, serial uint32)
564+ Reposition(self *Popup, positioner *Positioner, token uint32)
565+}
566+
567+func NewPopup(c server.Client, version int32, id uint32, h PopupHandler) (*Popup, error) {
568+ if h == nil {
569+ return nil, fmt.Errorf("purego-libwayland: nil handler for xdg_popup")
570+ }
571+ var self *Popup
572+ r, err := c.CreateResource(PopupInterface, version, id, func(_ *server.Resource, opcode uint32, args []server.Arg) {
573+ switch opcode {
574+ case 0:
575+ h.Destroy(self)
576+ self.Destroy()
577+ case 1:
578+ h.Grab(self, wayland.WrapSeat(args[0].Resource()), args[1].Uint())
579+ case 2:
580+ h.Reposition(self, WrapPositioner(args[0].Resource()), args[1].Uint())
581+ }
582+ })
583+ if err != nil {
584+ return nil, err
585+ }
586+ self = WrapPopup(r)
587+ r.Data = self
588+ return self, nil
589+}
590+
591+// SendConfigure configure the popup surface.
592+func (self *Popup) SendConfigure(x int32, y int32, width int32, height int32) {
593+ self.PostEvent(PopupEventConfigure, server.Int(x), server.Int(y), server.Int(width), server.Int(height))
594+}
595+
596+// SendPopupDone popup interaction is done.
597+func (self *Popup) SendPopupDone() {
598+ self.PostEvent(PopupEventPopupDone)
599+}
600+
601+// SendRepositioned signal the completion of a repositioned request (since version 3).
602+func (self *Popup) SendRepositioned(token uint32) {
603+ self.PostEvent(PopupEventRepositioned, server.Uint(token))
604+}
605+func NewPopupGlobal(d *server.Display, version int32, bind server.BindFunc) error {
606+ return d.CreateGlobal(PopupInterface, version, bind)
607+}
608+func resourceOf(v interface{ GetResource() *server.Resource }) *server.Resource {
609+ if v == nil {
610+ return nil
611+ }
612+ return v.GetResource()
613+}
614+func (self *WmBase) GetResource() *server.Resource {
615+ if self == nil {
616+ return nil
617+ }
618+ return self.Resource
619+}
620+func (self *Positioner) GetResource() *server.Resource {
621+ if self == nil {
622+ return nil
623+ }
624+ return self.Resource
625+}
626+func (self *Surface) GetResource() *server.Resource {
627+ if self == nil {
628+ return nil
629+ }
630+ return self.Resource
631+}
632+func (self *Toplevel) GetResource() *server.Resource {
633+ if self == nil {
634+ return nil
635+ }
636+ return self.Resource
637+}
638+func (self *Popup) GetResource() *server.Resource {
639+ if self == nil {
640+ return nil
641+ }
642+ return self.Resource
643+}
A protocol/xdgshell/xdgshell_test.go +9 -0
@@ -0,0 +1,9 @@
1+package xdgshell
2+
3+import "testing"
4+
5+func TestForwardReference(t *testing.T) {
6+ if got := WmBaseInterface.Requests[2].Types[0]; got == nil || got != SurfaceInterface {
7+ t.Fatalf("get_xdg_surface type=%v want %v", got, SurfaceInterface)
8+ }
9+}
A protocols/wayland.xml +3442 -0 large diff (3442 lines changed): collapsed
A protocols/xdg-shell.xml +1420 -0
@@ -0,0 +1,1420 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<protocol name="xdg_shell">
3+
4+ <copyright>
5+ Copyright © 2008-2013 Kristian Høgsberg
6+ Copyright © 2013 Rafael Antognolli
7+ Copyright © 2013 Jasper St. Pierre
8+ Copyright © 2010-2013 Intel Corporation
9+ Copyright © 2015-2017 Samsung Electronics Co., Ltd
10+ Copyright © 2015-2017 Red Hat Inc.
11+
12+ Permission is hereby granted, free of charge, to any person obtaining a
13+ copy of this software and associated documentation files (the "Software"),
14+ to deal in the Software without restriction, including without limitation
15+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
16+ and/or sell copies of the Software, and to permit persons to whom the
17+ Software is furnished to do so, subject to the following conditions:
18+
19+ The above copyright notice and this permission notice (including the next
20+ paragraph) shall be included in all copies or substantial portions of the
21+ Software.
22+
23+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29+ DEALINGS IN THE SOFTWARE.
30+ </copyright>
31+
32+ <interface name="xdg_wm_base" version="7">
33+ <description summary="create desktop-style surfaces">
34+ The xdg_wm_base interface is exposed as a global object enabling clients
35+ to turn their wl_surfaces into windows in a desktop environment. It
36+ defines the basic functionality needed for clients and the compositor to
37+ create windows that can be dragged, resized, maximized, etc, as well as
38+ creating transient windows such as popup menus.
39+ </description>
40+
41+ <enum name="error">
42+ <entry name="role" value="0" summary="given wl_surface has another role"/>
43+ <entry name="defunct_surfaces" value="1"
44+ summary="xdg_wm_base was destroyed before children"/>
45+ <entry name="not_the_topmost_popup" value="2"
46+ summary="the client tried to map or destroy a non-topmost popup"/>
47+ <entry name="invalid_popup_parent" value="3"
48+ summary="the client specified an invalid popup parent surface"/>
49+ <entry name="invalid_surface_state" value="4"
50+ summary="the client provided an invalid surface state"/>
51+ <entry name="invalid_positioner" value="5"
52+ summary="the client provided an invalid positioner"/>
53+ <entry name="unresponsive" value="6"
54+ summary="the client didn’t respond to a ping event in time"/>
55+ </enum>
56+
57+ <request name="destroy" type="destructor">
58+ <description summary="destroy xdg_wm_base">
59+ Destroy this xdg_wm_base object.
60+
61+ Destroying a bound xdg_wm_base object while there are surfaces
62+ still alive created by this xdg_wm_base object instance is illegal
63+ and will result in a defunct_surfaces error.
64+ </description>
65+ </request>
66+
67+ <request name="create_positioner">
68+ <description summary="create a positioner object">
69+ Create a positioner object. A positioner object is used to position
70+ surfaces relative to some parent surface. See the interface description
71+ and xdg_surface.get_popup for details.
72+ </description>
73+ <arg name="id" type="new_id" interface="xdg_positioner"/>
74+ </request>
75+
76+ <request name="get_xdg_surface">
77+ <description summary="create a shell surface from a surface">
78+ This creates an xdg_surface for the given surface. An xdg_surface is
79+ used as basis to define a role to a given surface, such as xdg_toplevel
80+ or xdg_popup. It also manages functionality shared between xdg_surface
81+ based surface roles.
82+
83+ While xdg_surface itself is not a role, the corresponding surface may
84+ only be assigned a role extending xdg_surface, such as xdg_toplevel or
85+ xdg_popup. It is illegal to create an xdg_surface for a wl_surface which
86+ already has anassigned role and this will result in a role error.
87+
88+ See the documentation of xdg_surface for more details about what an
89+ xdg_surface is and how it is used.
90+ </description>
91+ <arg name="id" type="new_id" interface="xdg_surface"/>
92+ <arg name="surface" type="object" interface="wl_surface"/>
93+ </request>
94+
95+ <request name="pong">
96+ <description summary="respond to a ping event">
97+ A client must respond to a ping event with a pong request or
98+ the client may be deemed unresponsive. See xdg_wm_base.ping
99+ and xdg_wm_base.error.unresponsive.
100+ </description>
101+ <arg name="serial" type="uint" summary="serial of the ping event"/>
102+ </request>
103+
104+ <event name="ping">
105+ <description summary="check if the client is alive">
106+ The ping event asks the client if it's still alive. Pass the
107+ serial specified in the event back to the compositor by sending
108+ a "pong" request back with the specified serial. See xdg_wm_base.pong.
109+
110+ Compositors can use this to determine if the client is still
111+ alive. It's unspecified what will happen if the client doesn't
112+ respond to the ping request, or in what timeframe. Clients should
113+ try to respond in a reasonable amount of time. The “unresponsive”
114+ error is provided for compositors that wish to disconnect unresponsive
115+ clients.
116+
117+ A compositor is free to ping in any way it wants, but a client must
118+ always respond to any xdg_wm_base object it created.
119+ </description>
120+ <arg name="serial" type="uint" summary="pass this to the pong request"/>
121+ </event>
122+ </interface>
123+
124+ <interface name="xdg_positioner" version="7">
125+ <description summary="child surface positioner">
126+ The xdg_positioner provides a collection of rules for the placement of a
127+ child surface relative to a parent surface. Rules can be defined to ensure
128+ the child surface remains within the visible area's borders, and to
129+ specify how the child surface changes its position, such as sliding along
130+ an axis, or flipping around a rectangle. These positioner-created rules are
131+ constrained by the requirement that a child surface must intersect with or
132+ be at least partially adjacent to its parent surface.
133+
134+ See the various requests for details about possible rules.
135+
136+ At the time of the request, the compositor makes a copy of the rules
137+ specified by the xdg_positioner. Thus, after the request is complete the
138+ xdg_positioner object can be destroyed or reused; further changes to the
139+ object will have no effect on previous usages.
140+
141+ For an xdg_positioner object to be considered complete, it must have a
142+ non-zero size set by set_size, and a non-zero anchor rectangle set by
143+ set_anchor_rect. Passing an incomplete xdg_positioner object when
144+ positioning a surface raises an invalid_positioner error.
145+ </description>
146+
147+ <enum name="error">
148+ <entry name="invalid_input" value="0" summary="invalid input provided"/>
149+ </enum>
150+
151+ <request name="destroy" type="destructor">
152+ <description summary="destroy the xdg_positioner object">
153+ Notify the compositor that the xdg_positioner will no longer be used.
154+ </description>
155+ </request>
156+
157+ <request name="set_size">
158+ <description summary="set the size of the to-be positioned rectangle">
159+ Set the size of the surface that is to be positioned with the positioner
160+ object. The size is in surface-local coordinates and corresponds to the
161+ window geometry. See xdg_surface.set_window_geometry.
162+
163+ If a zero or negative size is set the invalid_input error is raised.
164+ </description>
165+ <arg name="width" type="int" summary="width of positioned rectangle"/>
166+ <arg name="height" type="int" summary="height of positioned rectangle"/>
167+ </request>
168+
169+ <request name="set_anchor_rect">
170+ <description summary="set the anchor rectangle within the parent surface">
171+ Specify the anchor rectangle within the parent surface that the child
172+ surface will be placed relative to. The rectangle is relative to the
173+ window geometry as defined by xdg_surface.set_window_geometry of the
174+ parent surface.
175+
176+ When the xdg_positioner object is used to position a child surface, the
177+ anchor rectangle may not extend outside the window geometry of the
178+ positioned child's parent surface.
179+
180+ If a negative size is set the invalid_input error is raised.
181+ </description>
182+ <arg name="x" type="int" summary="x position of anchor rectangle"/>
183+ <arg name="y" type="int" summary="y position of anchor rectangle"/>
184+ <arg name="width" type="int" summary="width of anchor rectangle"/>
185+ <arg name="height" type="int" summary="height of anchor rectangle"/>
186+ </request>
187+
188+ <enum name="anchor">
189+ <entry name="none" value="0"/>
190+ <entry name="top" value="1"/>
191+ <entry name="bottom" value="2"/>
192+ <entry name="left" value="3"/>
193+ <entry name="right" value="4"/>
194+ <entry name="top_left" value="5"/>
195+ <entry name="bottom_left" value="6"/>
196+ <entry name="top_right" value="7"/>
197+ <entry name="bottom_right" value="8"/>
198+ </enum>
199+
200+ <request name="set_anchor">
201+ <description summary="set anchor rectangle anchor">
202+ Defines the anchor point for the anchor rectangle. The specified anchor
203+ is used to derive an anchor point that the child surface will be
204+ positioned relative to. If a corner anchor is set (e.g. 'top_left' or
205+ 'bottom_right'), the anchor point will be at the specified corner;
206+ otherwise, the derived anchor point will be centered on the specified
207+ edge, or in the center of the anchor rectangle if no edge is specified.
208+ </description>
209+ <arg name="anchor" type="uint" enum="anchor"
210+ summary="anchor point"/>
211+ </request>
212+
213+ <enum name="gravity">
214+ <entry name="none" value="0"/>
215+ <entry name="top" value="1"/>
216+ <entry name="bottom" value="2"/>
217+ <entry name="left" value="3"/>
218+ <entry name="right" value="4"/>
219+ <entry name="top_left" value="5"/>
220+ <entry name="bottom_left" value="6"/>
221+ <entry name="top_right" value="7"/>
222+ <entry name="bottom_right" value="8"/>
223+ </enum>
224+
225+ <request name="set_gravity">
226+ <description summary="set child surface gravity">
227+ Defines in what direction a surface should be positioned, relative to
228+ the anchor point of the parent surface. If a corner gravity is
229+ specified (e.g. 'bottom_right' or 'top_left'), then the child surface
230+ will be placed towards the specified gravity; otherwise, the child
231+ surface will be centered over the anchor point on any axis that had no
232+ gravity specified. If the gravity is not in the ‘gravity’ enum, an
233+ invalid_input error is raised.
234+ </description>
235+ <arg name="gravity" type="uint" enum="gravity"
236+ summary="gravity direction"/>
237+ </request>
238+
239+ <enum name="constraint_adjustment" bitfield="true">
240+ <description summary="constraint adjustments">
241+ The constraint adjustment value define ways the compositor will adjust
242+ the position of the surface, if the unadjusted position would result
243+ in the surface being partly constrained.
244+
245+ Whether a surface is considered 'constrained' is left to the compositor
246+ to determine. For example, the surface may be partly outside the
247+ compositor's defined 'work area', thus necessitating the child surface's
248+ position be adjusted until it is entirely inside the work area.
249+
250+ The adjustments can be combined, according to a defined precedence: 1)
251+ Flip, 2) Slide, 3) Resize.
252+ </description>
253+ <entry name="none" value="0">
254+ <description summary="don't move the child surface when constrained">
255+ Don't alter the surface position even if it is constrained on some
256+ axis, for example partially outside the edge of an output.
257+ </description>
258+ </entry>
259+ <entry name="slide_x" value="1">
260+ <description summary="move along the x axis until unconstrained">
261+ Slide the surface along the x axis until it is no longer constrained.
262+
263+ First try to slide towards the direction of the gravity on the x axis
264+ until either the edge in the opposite direction of the gravity is
265+ unconstrained or the edge in the direction of the gravity is
266+ constrained.
267+
268+ Then try to slide towards the opposite direction of the gravity on the
269+ x axis until either the edge in the direction of the gravity is
270+ unconstrained or the edge in the opposite direction of the gravity is
271+ constrained.
272+ </description>
273+ </entry>
274+ <entry name="slide_y" value="2">
275+ <description summary="move along the y axis until unconstrained">
276+ Slide the surface along the y axis until it is no longer constrained.
277+
278+ First try to slide towards the direction of the gravity on the y axis
279+ until either the edge in the opposite direction of the gravity is
280+ unconstrained or the edge in the direction of the gravity is
281+ constrained.
282+
283+ Then try to slide towards the opposite direction of the gravity on the
284+ y axis until either the edge in the direction of the gravity is
285+ unconstrained or the edge in the opposite direction of the gravity is
286+ constrained.
287+ </description>
288+ </entry>
289+ <entry name="flip_x" value="4">
290+ <description summary="invert the anchor and gravity on the x axis">
291+ Invert the anchor and gravity on the x axis if the surface is
292+ constrained on the x axis. For example, if the left edge of the
293+ surface is constrained, the gravity is 'left' and the anchor is
294+ 'left', change the gravity to 'right' and the anchor to 'right'.
295+
296+ If the adjusted position also ends up being constrained, the resulting
297+ position of the flip_x adjustment will be the one before the
298+ adjustment.
299+ </description>
300+ </entry>
301+ <entry name="flip_y" value="8">
302+ <description summary="invert the anchor and gravity on the y axis">
303+ Invert the anchor and gravity on the y axis if the surface is
304+ constrained on the y axis. For example, if the bottom edge of the
305+ surface is constrained, the gravity is 'bottom' and the anchor is
306+ 'bottom', change the gravity to 'top' and the anchor to 'top'.
307+
308+ The adjusted position is calculated given the original anchor
309+ rectangle and offset, but with the new flipped anchor and gravity
310+ values.
311+
312+ If the adjusted position also ends up being constrained, the resulting
313+ position of the flip_y adjustment will be the one before the
314+ adjustment.
315+ </description>
316+ </entry>
317+ <entry name="resize_x" value="16">
318+ <description summary="horizontally resize the surface">
319+ Resize the surface horizontally so that it is completely
320+ unconstrained.
321+ </description>
322+ </entry>
323+ <entry name="resize_y" value="32">
324+ <description summary="vertically resize the surface">
325+ Resize the surface vertically so that it is completely unconstrained.
326+ </description>
327+ </entry>
328+ </enum>
329+
330+ <request name="set_constraint_adjustment">
331+ <description summary="set the adjustment to be done when constrained">
332+ Specify how the window should be positioned if the originally intended
333+ position caused the surface to be constrained, meaning at least
334+ partially outside positioning boundaries set by the compositor. The
335+ adjustment is set by constructing a bitmask describing the adjustment to
336+ be made when the surface is constrained on that axis.
337+
338+ If no bit for one axis is set, the compositor will assume that the child
339+ surface should not change its position on that axis when constrained.
340+
341+ If more than one bit for one axis is set, the order of how adjustments
342+ are applied is specified in the corresponding adjustment descriptions.
343+
344+ The default adjustment is none.
345+ </description>
346+ <arg name="constraint_adjustment" type="uint" enum="constraint_adjustment"
347+ summary="bit mask of constraint adjustments"/>
348+ </request>
349+
350+ <request name="set_offset">
351+ <description summary="set surface position offset">
352+ Specify the surface position offset relative to the position of the
353+ anchor on the anchor rectangle and the anchor on the surface. For
354+ example if the anchor of the anchor rectangle is at (x, y), the surface
355+ has the gravity bottom|right, and the offset is (ox, oy), the calculated
356+ surface position will be (x + ox, y + oy). The offset position of the
357+ surface is the one used for constraint testing. See
358+ set_constraint_adjustment.
359+
360+ An example use case is placing a popup menu on top of a user interface
361+ element, while aligning the user interface element of the parent surface
362+ with some user interface element placed somewhere in the popup surface.
363+ </description>
364+ <arg name="x" type="int" summary="surface position x offset"/>
365+ <arg name="y" type="int" summary="surface position y offset"/>
366+ </request>
367+
368+ <!-- Version 3 additions -->
369+
370+ <request name="set_reactive" since="3">
371+ <description summary="continuously reconstrain the surface">
372+ When set reactive, the surface is reconstrained if the conditions used
373+ for constraining changed, e.g. the parent window moved.
374+
375+ If the conditions changed and the popup was reconstrained, an
376+ xdg_popup.configure event is sent with updated geometry, followed by an
377+ xdg_surface.configure event.
378+ </description>
379+ </request>
380+
381+ <request name="set_parent_size" since="3">
382+ <description summary="set parent size">
383+ Set the parent window geometry the compositor should use when
384+ positioning the popup. The compositor may use this information to
385+ determine the future state the popup should be constrained using. If
386+ this doesn't match the dimension of the parent the popup is eventually
387+ positioned against, the behavior is undefined.
388+
389+ The arguments are given in the surface-local coordinate space.
390+ </description>
391+ <arg name="parent_width" type="int"
392+ summary="future window geometry width of parent"/>
393+ <arg name="parent_height" type="int"
394+ summary="future window geometry height of parent"/>
395+ </request>
396+
397+ <request name="set_parent_configure" since="3">
398+ <description summary="set parent configure this is a response to">
399+ Set the serial of an xdg_surface.configure event this positioner will be
400+ used in response to. The compositor may use this information together
401+ with set_parent_size to determine what future state the popup should be
402+ constrained using.
403+ </description>
404+ <arg name="serial" type="uint"
405+ summary="serial of parent configure event"/>
406+ </request>
407+ </interface>
408+
409+ <interface name="xdg_surface" version="7">
410+ <description summary="desktop user interface surface base interface">
411+ An interface that may be implemented by a wl_surface, for
412+ implementations that provide a desktop-style user interface.
413+
414+ It provides a base set of functionality required to construct user
415+ interface elements requiring management by the compositor, such as
416+ toplevel windows, menus, etc. The types of functionality are split into
417+ xdg_surface roles.
418+
419+ Creating an xdg_surface does not set the role for a wl_surface. In order
420+ to map an xdg_surface, the client must create a role-specific object
421+ using, e.g., get_toplevel, get_popup. The wl_surface for any given
422+ xdg_surface can have at most one role, and may not be assigned any role
423+ not based on xdg_surface.
424+
425+ A role must be assigned before any other requests are made to the
426+ xdg_surface object.
427+
428+ The client must call wl_surface.commit on the corresponding wl_surface
429+ for the xdg_surface state to take effect.
430+
431+ Creating an xdg_surface from a wl_surface which has a buffer attached or
432+ committed is a client error, and any attempts by a client to attach or
433+ manipulate a buffer prior to the first xdg_surface.configure call must
434+ also be treated as errors.
435+
436+ After creating a role-specific object and setting it up (e.g. by sending
437+ the title, app ID, size constraints, parent, etc), the client must
438+ perform an initial commit without any buffer attached. The compositor
439+ will reply with initial wl_surface state such as
440+ wl_surface.preferred_buffer_scale followed by an xdg_surface.configure
441+ event. The client must acknowledge it and is then allowed to attach a
442+ buffer to map the surface.
443+
444+ Mapping an xdg_surface-based role surface is defined as making it
445+ possible for the surface to be shown by the compositor. Note that
446+ a mapped surface is not guaranteed to be visible once it is mapped.
447+
448+ For an xdg_surface to be mapped by the compositor, the following
449+ conditions must be met:
450+ (1) the client has assigned an xdg_surface-based role to the surface
451+ (2) the client has set and committed the xdg_surface state and the
452+ role-dependent state to the surface
453+ (3) the client has committed a buffer to the surface
454+
455+ A newly-unmapped surface is considered to have met condition (1) out
456+ of the 3 required conditions for mapping a surface if its role surface
457+ has not been destroyed, i.e. the client must perform the initial commit
458+ again before attaching a buffer.
459+ </description>
460+
461+ <enum name="error">
462+ <entry name="not_constructed" value="1"
463+ summary="Surface was not fully constructed"/>
464+ <entry name="already_constructed" value="2"
465+ summary="Surface was already constructed"/>
466+ <entry name="unconfigured_buffer" value="3"
467+ summary="Attaching a buffer to an unconfigured surface"/>
468+ <entry name="invalid_serial" value="4"
469+ summary="Invalid serial number when acking a configure event"/>
470+ <entry name="invalid_size" value="5"
471+ summary="Width or height was zero or negative"/>
472+ <entry name="defunct_role_object" value="6"
473+ summary="Surface was destroyed before its role object"/>
474+ </enum>
475+
476+ <request name="destroy" type="destructor">
477+ <description summary="destroy the xdg_surface">
478+ Destroy the xdg_surface object. An xdg_surface must only be destroyed
479+ after its role object has been destroyed, otherwise
480+ a defunct_role_object error is raised.
481+ </description>
482+ </request>
483+
484+ <request name="get_toplevel">
485+ <description summary="assign the xdg_toplevel surface role">
486+ This creates an xdg_toplevel object for the given xdg_surface and gives
487+ the associated wl_surface the xdg_toplevel role.
488+
489+ See the documentation of xdg_toplevel for more details about what an
490+ xdg_toplevel is and how it is used.
491+ </description>
492+ <arg name="id" type="new_id" interface="xdg_toplevel"/>
493+ </request>
494+
495+ <request name="get_popup">
496+ <description summary="assign the xdg_popup surface role">
497+ This creates an xdg_popup object for the given xdg_surface and gives
498+ the associated wl_surface the xdg_popup role.
499+
500+ If null is passed as a parent, a parent surface must be specified using
501+ some other protocol, before committing the initial state.
502+
503+ See the documentation of xdg_popup for more details about what an
504+ xdg_popup is and how it is used.
505+ </description>
506+ <arg name="id" type="new_id" interface="xdg_popup"/>
507+ <arg name="parent" type="object" interface="xdg_surface" allow-null="true" summary="parent surface for this popup"/>
508+ <arg name="positioner" type="object" interface="xdg_positioner" summary="positioner for this popup"/>
509+ </request>
510+
511+ <request name="set_window_geometry">
512+ <description summary="set the new window geometry">
513+ The window geometry of a surface is its "visible bounds" from the
514+ user's perspective. Client-side decorations often have invisible
515+ portions like drop-shadows which should be ignored for the
516+ purposes of aligning, placing and constraining windows. Note that
517+ in some situations, compositors may clip rendering to the window
518+ geometry, so the client should avoid putting functional elements
519+ outside of it.
520+
521+ The window geometry is double-buffered state, see wl_surface.commit.
522+
523+ When maintaining a position, the compositor should treat the (x, y)
524+ coordinate of the window geometry as the top left corner of the window.
525+ A client changing the (x, y) window geometry coordinate should in
526+ general not alter the position of the window.
527+
528+ Once the window geometry of the surface is set, it is not possible to
529+ unset it, and it will remain the same until set_window_geometry is
530+ called again, even if a new subsurface or buffer is attached.
531+
532+ If never set, the value is the full bounds of the surface,
533+ including any subsurfaces. This updates dynamically on every
534+ commit. This unset is meant for extremely simple clients.
535+
536+ The arguments are given in the surface-local coordinate space of
537+ the wl_surface associated with this xdg_surface, and may extend outside
538+ of the wl_surface itself to mark parts of the subsurface tree as part of
539+ the window geometry.
540+
541+ When applied, the effective window geometry will be the set window
542+ geometry clamped to the bounding rectangle of the combined
543+ geometry of the surface of the xdg_surface and the associated
544+ subsurfaces.
545+
546+ The effective geometry will not be recalculated unless a new call to
547+ set_window_geometry is done and the new pending surface state is
548+ subsequently applied.
549+
550+ The width and height of the effective window geometry must be
551+ greater than zero. Setting an invalid size will raise an
552+ invalid_size error.
553+ </description>
554+ <arg name="x" type="int" summary="x coordinate of the top-left corner of the window inside this surface"/>
555+ <arg name="y" type="int" summary="y coordinate of the top-left corner of the window inside this surface"/>
556+ <arg name="width" type="int" summary="width of the window"/>
557+ <arg name="height" type="int" summary="height of the window"/>
558+ </request>
559+
560+ <request name="ack_configure">
561+ <description summary="ack a configure event">
562+ When a configure event is received, if a client commits the
563+ surface in response to the configure event, then the client
564+ must make an ack_configure request sometime before the commit
565+ request, passing along the serial of the configure event.
566+
567+ For instance, for toplevel surfaces the compositor might use this
568+ information to move a surface to the top left only when the client has
569+ drawn itself for the maximized or fullscreen state.
570+
571+ If the client receives multiple configure events before it
572+ can respond to one, it only has to ack the last configure event.
573+ Acking a configure event that was never sent raises an invalid_serial
574+ error.
575+
576+ A client is not required to commit immediately after sending
577+ an ack_configure request - it may even ack_configure several times
578+ before its next surface commit.
579+
580+ A client may send multiple ack_configure requests before committing, but
581+ only the last request sent before a commit indicates which configure
582+ event the client really is responding to.
583+
584+ Sending an ack_configure request consumes the serial number sent with
585+ the request, as well as serial numbers sent by all configure events
586+ sent on this xdg_surface prior to the configure event referenced by
587+ the committed serial.
588+
589+ It is an error to issue multiple ack_configure requests referencing a
590+ serial from the same configure event, or to issue an ack_configure
591+ request referencing a serial from a configure event issued before the
592+ event identified by the last ack_configure request for the same
593+ xdg_surface. Doing so will raise an invalid_serial error.
594+ </description>
595+ <arg name="serial" type="uint" summary="the serial from the configure event"/>
596+ </request>
597+
598+ <event name="configure">
599+ <description summary="suggest a surface change">
600+ The configure event marks the end of a configure sequence. A configure
601+ sequence is a set of one or more events configuring the state of the
602+ xdg_surface, including the final xdg_surface.configure event.
603+
604+ Where applicable, xdg_surface surface roles will during a configure
605+ sequence extend this event as a latched state sent as events before the
606+ xdg_surface.configure event. Such events should be considered to make up
607+ a set of atomically applied configuration states, where the
608+ xdg_surface.configure commits the accumulated state.
609+
610+ Clients should arrange their surface for the new states, and then send
611+ an ack_configure request with the serial sent in this configure event at
612+ some point before committing the new surface.
613+
614+ If the client receives multiple configure events before it can respond
615+ to one, it is free to discard all but the last event it received.
616+ </description>
617+ <arg name="serial" type="uint" summary="serial of the configure event"/>
618+ </event>
619+
620+ </interface>
621+
622+ <interface name="xdg_toplevel" version="7">
623+ <description summary="toplevel surface">
624+ This interface defines an xdg_surface role which allows a surface to,
625+ among other things, set window-like properties such as maximize,
626+ fullscreen, and minimize, set application-specific metadata like title and
627+ id, and well as trigger user interactive operations such as interactive
628+ resize and move.
629+
630+ An xdg_toplevel by default is responsible for providing the full intended
631+ visual representation of the toplevel, which depending on the window
632+ state, may mean things like a title bar, window controls and drop shadow.
633+
634+ Unmapping an xdg_toplevel means that the surface cannot be shown
635+ by the compositor until it is explicitly mapped again.
636+ All active operations (e.g., move, resize) are canceled and all
637+ attributes (e.g. title, state, stacking, ...) are discarded for
638+ an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to
639+ the state it had right after xdg_surface.get_toplevel. The client
640+ can re-map the toplevel by performing a commit without any buffer
641+ attached, waiting for a configure event and handling it as usual (see
642+ xdg_surface description).
643+
644+ Attaching a null buffer to a toplevel unmaps the surface.
645+ </description>
646+
647+ <request name="destroy" type="destructor">
648+ <description summary="destroy the xdg_toplevel">
649+ This request destroys the role surface and unmaps the surface;
650+ see "Unmapping" behavior in interface section for details.
651+ </description>
652+ </request>
653+
654+ <enum name="error">
655+ <entry name="invalid_resize_edge" value="0" summary="provided value is
656+ not a valid variant of the resize_edge enum"/>
657+ <entry name="invalid_parent" value="1"
658+ summary="invalid parent toplevel"/>
659+ <entry name="invalid_size" value="2"
660+ summary="client provided an invalid min or max size"/>
661+ </enum>
662+
663+ <request name="set_parent">
664+ <description summary="set the parent of this surface">
665+ Set the "parent" of this surface. This surface should be stacked
666+ above the parent surface and all other ancestor surfaces.
667+
668+ Parent surfaces should be set on dialogs, toolboxes, or other
669+ "auxiliary" surfaces, so that the parent is raised when the dialog
670+ is raised.
671+
672+ Setting a null parent for a child surface unsets its parent. Setting
673+ a null parent for a surface which currently has no parent is a no-op.
674+
675+ Only mapped surfaces can have child surfaces. Setting a parent which
676+ is not mapped is equivalent to setting a null parent. If a surface
677+ becomes unmapped, its children's parent is set to the parent of
678+ the now-unmapped surface. If the now-unmapped surface has no parent,
679+ its children's parent is unset. If the now-unmapped surface becomes
680+ mapped again, its parent-child relationship is not restored.
681+
682+ The parent toplevel must not be one of the child toplevel's
683+ descendants, and the parent must be different from the child toplevel,
684+ otherwise the invalid_parent protocol error is raised.
685+ </description>
686+ <arg name="parent" type="object" interface="xdg_toplevel" allow-null="true" summary="parent surface for this surface"/>
687+ </request>
688+
689+ <request name="set_title">
690+ <description summary="set surface title">
691+ Set a short title for the surface.
692+
693+ This string may be used to identify the surface in a task bar,
694+ window list, or other user interface elements provided by the
695+ compositor.
696+
697+ The string must be encoded in UTF-8.
698+ </description>
699+ <arg name="title" type="string" summary="title of the surface"/>
700+ </request>
701+
702+ <request name="set_app_id">
703+ <description summary="set application ID">
704+ Set an application identifier for the surface.
705+
706+ The app ID identifies the general class of applications to which
707+ the surface belongs. The compositor can use this to group multiple
708+ surfaces together, or to determine how to launch a new application.
709+
710+ For D-Bus activatable applications, the app ID is used as the D-Bus
711+ service name.
712+
713+ The compositor shell will try to group application surfaces together
714+ by their app ID. As a best practice, it is suggested to select app
715+ ID's that match the basename of the application's .desktop file.
716+ For example, "org.freedesktop.FooViewer" where the .desktop file is
717+ "org.freedesktop.FooViewer.desktop".
718+
719+ Like other properties, a set_app_id request can be sent after the
720+ xdg_toplevel has been mapped to update the property.
721+
722+ See the desktop-entry specification [0] for more details on
723+ application identifiers and how they relate to well-known D-Bus
724+ names and .desktop files.
725+
726+ [0] https://standards.freedesktop.org/desktop-entry-spec/
727+ </description>
728+ <arg name="app_id" type="string" summary="application identifier surface belongs to"/>
729+ </request>
730+
731+ <request name="show_window_menu">
732+ <description summary="show the window menu">
733+ Clients implementing client-side decorations might want to show
734+ a context menu when right-clicking on the decorations, giving the
735+ user a menu that they can use to maximize or minimize the window.
736+
737+ This request asks the compositor to pop up such a window menu at
738+ the given position, relative to the local surface coordinates of
739+ the parent surface. There are no guarantees as to what menu items
740+ the window menu contains, or even if a window menu will be drawn
741+ at all.
742+
743+ This request must be used in response to some sort of user action
744+ like a button press, key press, or touch down event.
745+ </description>
746+ <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
747+ <arg name="serial" type="uint" summary="the serial of the user event"/>
748+ <arg name="x" type="int" summary="the x position to pop up the window menu at"/>
749+ <arg name="y" type="int" summary="the y position to pop up the window menu at"/>
750+ </request>
751+
752+ <request name="move">
753+ <description summary="start an interactive move">
754+ Start an interactive, user-driven move of the surface.
755+
756+ This request must be used in response to some sort of user action
757+ like a button press, key press, or touch down event. The passed
758+ serial is used to determine the type of interactive move (touch,
759+ pointer, etc).
760+
761+ The server may ignore move requests depending on the state of
762+ the surface (e.g. fullscreen or maximized), or if the passed serial
763+ is no longer valid.
764+
765+ If triggered, the surface will lose the focus of the device
766+ (wl_pointer, wl_touch, etc) used for the move. It is up to the
767+ compositor to visually indicate that the move is taking place, such as
768+ updating a pointer cursor, during the move. There is no guarantee
769+ that the device focus will return when the move is completed.
770+ </description>
771+ <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
772+ <arg name="serial" type="uint" summary="the serial of the user event"/>
773+ </request>
774+
775+ <enum name="resize_edge">
776+ <description summary="edge values for resizing">
777+ These values are used to indicate which edge of a surface
778+ is being dragged in a resize operation.
779+ </description>
780+ <entry name="none" value="0"/>
781+ <entry name="top" value="1"/>
782+ <entry name="bottom" value="2"/>
783+ <entry name="left" value="4"/>
784+ <entry name="top_left" value="5"/>
785+ <entry name="bottom_left" value="6"/>
786+ <entry name="right" value="8"/>
787+ <entry name="top_right" value="9"/>
788+ <entry name="bottom_right" value="10"/>
789+ </enum>
790+
791+ <request name="resize">
792+ <description summary="start an interactive resize">
793+ Start a user-driven, interactive resize of the surface.
794+
795+ This request must be used in response to some sort of user action
796+ like a button press, key press, or touch down event. The passed
797+ serial is used to determine the type of interactive resize (touch,
798+ pointer, etc).
799+
800+ The server may ignore resize requests depending on the state of
801+ the surface (e.g. fullscreen or maximized).
802+
803+ If triggered, the client will receive configure events with the
804+ "resize" state enum value and the expected sizes. See the "resize"
805+ enum value for more details about what is required. The client
806+ must also acknowledge configure events using "ack_configure". After
807+ the resize is completed, the client will receive another "configure"
808+ event without the resize state.
809+
810+ If triggered, the surface also will lose the focus of the device
811+ (wl_pointer, wl_touch, etc) used for the resize. It is up to the
812+ compositor to visually indicate that the resize is taking place,
813+ such as updating a pointer cursor, during the resize. There is no
814+ guarantee that the device focus will return when the resize is
815+ completed.
816+
817+ The edges parameter specifies how the surface should be resized, and
818+ is one of the values of the resize_edge enum. Values not matching
819+ a variant of the enum will cause the invalid_resize_edge protocol error.
820+ The compositor may use this information to update the surface position
821+ for example when dragging the top left corner. The compositor may also
822+ use this information to adapt its behavior, e.g. choose an appropriate
823+ cursor image.
824+ </description>
825+ <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
826+ <arg name="serial" type="uint" summary="the serial of the user event"/>
827+ <arg name="edges" type="uint" enum="resize_edge" summary="which edge or corner is being dragged"/>
828+ </request>
829+
830+ <enum name="state">
831+ <description summary="types of state on the surface">
832+ The different state values used on the surface. This is designed for
833+ state values like maximized, fullscreen. It is paired with the
834+ configure event to ensure that both the client and the compositor
835+ setting the state can be synchronized.
836+
837+ States set in this way are double-buffered, see wl_surface.commit.
838+ </description>
839+ <entry name="maximized" value="1" summary="the surface is maximized">
840+ <description summary="the surface is maximized">
841+ The surface is maximized. The window geometry specified in the configure
842+ event must be obeyed by the client, or the xdg_wm_base.invalid_surface_state
843+ error is raised.
844+
845+ The client should draw without shadow or other
846+ decoration outside of the window geometry.
847+ </description>
848+ </entry>
849+ <entry name="fullscreen" value="2" summary="the surface is fullscreen">
850+ <description summary="the surface is fullscreen">
851+ The surface is fullscreen. The window geometry specified in the
852+ configure event is a maximum; the client cannot resize beyond it. For
853+ a surface to cover the whole fullscreened area, the geometry
854+ dimensions must be obeyed by the client. For more details, see
855+ xdg_toplevel.set_fullscreen.
856+ </description>
857+ </entry>
858+ <entry name="resizing" value="3" summary="the surface is being resized">
859+ <description summary="the surface is being resized">
860+ The surface is being resized. The window geometry specified in the
861+ configure event is a maximum; the client cannot resize beyond it.
862+ Clients that have aspect ratio or cell sizing configuration can use
863+ a smaller size, however.
864+ </description>
865+ </entry>
866+ <entry name="activated" value="4" summary="the surface is now activated">
867+ <description summary="the surface is now activated">
868+ Client window decorations should be painted as if the window is
869+ active. Do not assume this means that the window actually has
870+ keyboard or pointer focus.
871+ </description>
872+ </entry>
873+ <entry name="tiled_left" value="5" since="2">
874+ <description summary="the surface’s left edge is tiled">
875+ The window is currently in a tiled layout and the left edge is
876+ considered to be adjacent to another part of the tiling grid.
877+
878+ The client should draw without shadow or other decoration outside of
879+ the window geometry on the left edge.
880+ </description>
881+ </entry>
882+ <entry name="tiled_right" value="6" since="2">
883+ <description summary="the surface’s right edge is tiled">
884+ The window is currently in a tiled layout and the right edge is
885+ considered to be adjacent to another part of the tiling grid.
886+
887+ The client should draw without shadow or other decoration outside of
888+ the window geometry on the right edge.
889+ </description>
890+ </entry>
891+ <entry name="tiled_top" value="7" since="2">
892+ <description summary="the surface’s top edge is tiled">
893+ The window is currently in a tiled layout and the top edge is
894+ considered to be adjacent to another part of the tiling grid.
895+
896+ The client should draw without shadow or other decoration outside of
897+ the window geometry on the top edge.
898+ </description>
899+ </entry>
900+ <entry name="tiled_bottom" value="8" since="2">
901+ <description summary="the surface’s bottom edge is tiled">
902+ The window is currently in a tiled layout and the bottom edge is
903+ considered to be adjacent to another part of the tiling grid.
904+
905+ The client should draw without shadow or other decoration outside of
906+ the window geometry on the bottom edge.
907+ </description>
908+ </entry>
909+ <entry name="suspended" value="9" since="6">
910+ <description summary="surface repaint is suspended">
911+ The surface is currently not ordinarily being repainted; for
912+ example because its content is occluded by another window, or its
913+ outputs are switched off due to screen locking.
914+ </description>
915+ </entry>
916+ <entry name="constrained_left" value="10" since="7">
917+ <description summary="the surface’s left edge is constrained">
918+ The left edge of the window is currently constrained, meaning it
919+ shouldn't attempt to resize from that edge. It can for example mean
920+ it's tiled next to a monitor edge on the constrained side of the
921+ window.
922+ </description>
923+ </entry>
924+ <entry name="constrained_right" value="11" since="7">
925+ <description summary="the surface’s right edge is constrained">
926+ The right edge of the window is currently constrained, meaning it
927+ shouldn't attempt to resize from that edge. It can for example mean
928+ it's tiled next to a monitor edge on the constrained side of the
929+ window.
930+ </description>
931+ </entry>
932+ <entry name="constrained_top" value="12" since="7">
933+ <description summary="the surface’s top edge is constrained">
934+ The top edge of the window is currently constrained, meaning it
935+ shouldn't attempt to resize from that edge. It can for example mean
936+ it's tiled next to a monitor edge on the constrained side of the
937+ window.
938+ </description>
939+ </entry>
940+ <entry name="constrained_bottom" value="13" since="7">
941+ <description summary="the surface’s bottom edge is constrained">
942+ The bottom edge of the window is currently constrained, meaning it
943+ shouldn't attempt to resize from that edge. It can for example mean
944+ it's tiled next to a monitor edge on the constrained side of the
945+ window.
946+ </description>
947+ </entry>
948+ </enum>
949+
950+ <request name="set_max_size">
951+ <description summary="set the maximum size">
952+ Set a maximum size for the window.
953+
954+ The client can specify a maximum size so that the compositor does
955+ not try to configure the window beyond this size.
956+
957+ The width and height arguments are in window geometry coordinates.
958+ See xdg_surface.set_window_geometry.
959+
960+ Values set in this way are double-buffered, see wl_surface.commit.
961+
962+ The compositor can use this information to allow or disallow
963+ different states like maximize or fullscreen and draw accurate
964+ animations.
965+
966+ Similarly, a tiling window manager may use this information to
967+ place and resize client windows in a more effective way.
968+
969+ The client should not rely on the compositor to obey the maximum
970+ size. The compositor may decide to ignore the values set by the
971+ client and request a larger size.
972+
973+ If never set, or a value of zero in the request, means that the
974+ client has no expected maximum size in the given dimension.
975+ As a result, a client wishing to reset the maximum size
976+ to an unspecified state can use zero for width and height in the
977+ request.
978+
979+ Requesting a maximum size to be smaller than the minimum size of
980+ a surface is illegal and will result in an invalid_size error.
981+
982+ The width and height must be greater than or equal to zero. Using
983+ strictly negative values for width or height will result in an
984+ invalid_size error.
985+ </description>
986+ <arg name="width" type="int" summary="maximum width of the window"/>
987+ <arg name="height" type="int" summary="maximum height of the window"/>
988+ </request>
989+
990+ <request name="set_min_size">
991+ <description summary="set the minimum size">
992+ Set a minimum size for the window.
993+
994+ The client can specify a minimum size so that the compositor does
995+ not try to configure the window below this size.
996+
997+ The width and height arguments are in window geometry coordinates.
998+ See xdg_surface.set_window_geometry.
999+
1000+ Values set in this way are double-buffered, see wl_surface.commit.
1001+
1002+ The compositor can use this information to allow or disallow
1003+ different states like maximize or fullscreen and draw accurate
1004+ animations.
1005+
1006+ Similarly, a tiling window manager may use this information to
1007+ place and resize client windows in a more effective way.
1008+
1009+ The client should not rely on the compositor to obey the minimum
1010+ size. The compositor may decide to ignore the values set by the
1011+ client and request a smaller size.
1012+
1013+ If never set, or a value of zero in the request, means that the
1014+ client has no expected minimum size in the given dimension.
1015+ As a result, a client wishing to reset the minimum size
1016+ to an unspecified state can use zero for width and height in the
1017+ request.
1018+
1019+ Requesting a minimum size to be larger than the maximum size of
1020+ a surface is illegal and will result in an invalid_size error.
1021+
1022+ The width and height must be greater than or equal to zero. Using
1023+ strictly negative values for width and height will result in an
1024+ invalid_size error.
1025+ </description>
1026+ <arg name="width" type="int" summary="minimum width of the window"/>
1027+ <arg name="height" type="int" summary="minimum height of the window"/>
1028+ </request>
1029+
1030+ <request name="set_maximized">
1031+ <description summary="maximize the window">
1032+ Maximize the surface.
1033+
1034+ After requesting that the surface should be maximized, the compositor
1035+ will respond by emitting a configure event. Whether this configure
1036+ actually sets the window maximized is subject to compositor policies.
1037+ The client must then update its content, drawing in the configured
1038+ state. The client must also acknowledge the configure when committing
1039+ the new content (see ack_configure).
1040+
1041+ It is up to the compositor to decide how and where to maximize the
1042+ surface, for example which output and what region of the screen should
1043+ be used.
1044+
1045+ If the surface was already maximized, the compositor will still emit
1046+ a configure event with the "maximized" state.
1047+
1048+ If the surface is in a fullscreen state, this request has no direct
1049+ effect. It may alter the state the surface is returned to when
1050+ unmaximized unless overridden by the compositor.
1051+ </description>
1052+ </request>
1053+
1054+ <request name="unset_maximized">
1055+ <description summary="unmaximize the window">
1056+ Unmaximize the surface.
1057+
1058+ After requesting that the surface should be unmaximized, the compositor
1059+ will respond by emitting a configure event. Whether this actually
1060+ un-maximizes the window is subject to compositor policies.
1061+ If available and applicable, the compositor will include the window
1062+ geometry dimensions the window had prior to being maximized in the
1063+ configure event. The client must then update its content, drawing it in
1064+ the configured state. The client must also acknowledge the configure
1065+ when committing the new content (see ack_configure).
1066+
1067+ It is up to the compositor to position the surface after it was
1068+ unmaximized; usually the position the surface had before maximizing, if
1069+ applicable.
1070+
1071+ If the surface was already not maximized, the compositor will still
1072+ emit a configure event without the "maximized" state.
1073+
1074+ If the surface is in a fullscreen state, this request has no direct
1075+ effect. It may alter the state the surface is returned to when
1076+ unmaximized unless overridden by the compositor.
1077+ </description>
1078+ </request>
1079+
1080+ <request name="set_fullscreen">
1081+ <description summary="set the window as fullscreen on an output">
1082+ Make the surface fullscreen.
1083+
1084+ After requesting that the surface should be fullscreened, the
1085+ compositor will respond by emitting a configure event. Whether the
1086+ client is actually put into a fullscreen state is subject to compositor
1087+ policies. The client must also acknowledge the configure when
1088+ committing the new content (see ack_configure).
1089+
1090+ The output passed by the request indicates the client's preference as
1091+ to which display it should be set fullscreen on. If this value is NULL,
1092+ it's up to the compositor to choose which display will be used to map
1093+ this surface.
1094+
1095+ If the surface doesn't cover the whole output, the compositor will
1096+ position the surface in the center of the output and compensate with
1097+ border fill covering the rest of the output. The content of the
1098+ border fill is undefined, but should be assumed to be in some way that
1099+ attempts to blend into the surrounding area (e.g. solid black).
1100+
1101+ If the fullscreened surface is not opaque, the compositor must make
1102+ sure that other screen content not part of the same surface tree (made
1103+ up of subsurfaces, popups or similarly coupled surfaces) are not
1104+ visible below the fullscreened surface.
1105+ </description>
1106+ <arg name="output" type="object" interface="wl_output" allow-null="true" summary="preferred output to place surface on"/>
1107+ </request>
1108+
1109+ <request name="unset_fullscreen">
1110+ <description summary="unset the window as fullscreen">
1111+ Make the surface no longer fullscreen.
1112+
1113+ After requesting that the surface should be unfullscreened, the
1114+ compositor will respond by emitting a configure event.
1115+ Whether this actually removes the fullscreen state of the client is
1116+ subject to compositor policies.
1117+
1118+ Making a surface unfullscreen sets states for the surface based on the following:
1119+ * the state(s) it may have had before becoming fullscreen
1120+ * any state(s) decided by the compositor
1121+ * any state(s) requested by the client while the surface was fullscreen
1122+
1123+ The compositor may include the previous window geometry dimensions in
1124+ the configure event, if applicable.
1125+
1126+ The client must also acknowledge the configure when committing the new
1127+ content (see ack_configure).
1128+ </description>
1129+ </request>
1130+
1131+ <request name="set_minimized">
1132+ <description summary="set the window as minimized">
1133+ Request that the compositor minimize your surface. There is no
1134+ way to know if the surface is currently minimized, nor is there
1135+ any way to unset minimization on this surface.
1136+
1137+ If you are looking to throttle redrawing when minimized, please
1138+ instead use the wl_surface.frame event for this, as this will
1139+ also work with live previews on windows in Alt-Tab, Expose or
1140+ similar compositor features.
1141+ </description>
1142+ </request>
1143+
1144+ <event name="configure">
1145+ <description summary="suggest a surface change">
1146+ This configure event asks the client to resize its toplevel surface or
1147+ to change its state. The configured state should not be applied
1148+ immediately. See xdg_surface.configure for details.
1149+
1150+ The width and height arguments specify a hint to the window
1151+ about how its surface should be resized in window geometry
1152+ coordinates. See set_window_geometry.
1153+
1154+ If the width or height arguments are zero, it means the client
1155+ should decide its own window dimension. This may happen when the
1156+ compositor needs to configure the state of the surface but doesn't
1157+ have any information about any previous or expected dimension.
1158+
1159+ The states listed in the event specify how the width/height
1160+ arguments should be interpreted, and possibly how it should be
1161+ drawn.
1162+
1163+ The states are sent as an array of 32-bit unsigned integers in
1164+ native endianness. State values are defined in the state enum.
1165+
1166+ Clients must send an ack_configure in response to this event. See
1167+ xdg_surface.configure and xdg_surface.ack_configure for details.
1168+ </description>
1169+ <arg name="width" type="int" summary="suggested width of window"/>
1170+ <arg name="height" type="int" summary="suggested height of window"/>
1171+ <arg name="states" type="array" summary="suggested states of the window"/>
1172+ </event>
1173+
1174+ <event name="close">
1175+ <description summary="surface wants to be closed">
1176+ The close event is sent by the compositor when the user
1177+ wants the surface to be closed. This should be equivalent to
1178+ the user clicking the close button in client-side decorations,
1179+ if your application has any.
1180+
1181+ This is only a request that the user intends to close the
1182+ window. The client may choose to ignore this request, or show
1183+ a dialog to ask the user to save their data, etc.
1184+ </description>
1185+ </event>
1186+
1187+ <!-- Version 4 additions -->
1188+
1189+ <event name="configure_bounds" since="4">
1190+ <description summary="recommended window geometry bounds">
1191+ The configure_bounds event may be sent prior to a xdg_toplevel.configure
1192+ event to communicate the bounds a window geometry size is recommended
1193+ to constrain to.
1194+
1195+ The passed width and height are in surface coordinate space. If width
1196+ and height are 0, it means bounds is unknown and equivalent to as if no
1197+ configure_bounds event was ever sent for this surface.
1198+
1199+ The bounds can for example correspond to the size of a monitor excluding
1200+ any panels or other shell components, so that a surface isn't created in
1201+ a way that it cannot fit.
1202+
1203+ The bounds may change at any point, and in such a case, a new
1204+ xdg_toplevel.configure_bounds will be sent, followed by
1205+ xdg_toplevel.configure and xdg_surface.configure.
1206+ </description>
1207+ <arg name="width" type="int" summary="suggested maximum width of surface"/>
1208+ <arg name="height" type="int" summary="suggested maximum height of surface"/>
1209+ </event>
1210+
1211+ <!-- Version 5 additions -->
1212+
1213+ <enum name="wm_capabilities" since="5">
1214+ <entry name="window_menu" value="1" summary="show_window_menu is available"/>
1215+ <entry name="maximize" value="2" summary="set_maximized and unset_maximized are available"/>
1216+ <entry name="fullscreen" value="3" summary="set_fullscreen and unset_fullscreen are available"/>
1217+ <entry name="minimize" value="4" summary="set_minimized is available"/>
1218+ </enum>
1219+
1220+ <event name="wm_capabilities" since="5">
1221+ <description summary="compositor capabilities">
1222+ This event advertises the capabilities supported by the compositor. If
1223+ a capability isn't supported, clients should hide or disable the UI
1224+ elements that expose this functionality. For instance, if the
1225+ compositor doesn't advertise support for minimized toplevels, a button
1226+ triggering the set_minimized request should not be displayed.
1227+
1228+ The compositor will ignore requests it doesn't support. For instance,
1229+ a compositor which doesn't advertise support for minimized will ignore
1230+ set_minimized requests.
1231+
1232+ Compositors must send this event once before the first
1233+ xdg_surface.configure event. When the capabilities change, compositors
1234+ must send this event again and then send an xdg_surface.configure
1235+ event.
1236+
1237+ The configured state should not be applied immediately. See
1238+ xdg_surface.configure for details.
1239+
1240+ The capabilities are sent as an array of 32-bit unsigned integers in
1241+ native endianness. Capability values are defined in the wm_capabilities enum.
1242+ </description>
1243+ <arg name="capabilities" type="array" summary="array of 32-bit capabilities"/>
1244+ </event>
1245+ </interface>
1246+
1247+ <interface name="xdg_popup" version="7">
1248+ <description summary="short-lived, popup surfaces for menus">
1249+ A popup surface is a short-lived, temporary surface. It can be used to
1250+ implement for example menus, popovers, tooltips and other similar user
1251+ interface concepts.
1252+
1253+ A popup can be made to take an explicit grab. See xdg_popup.grab for
1254+ details.
1255+
1256+ When the popup is dismissed, a popup_done event will be sent out, and at
1257+ the same time the surface will be unmapped. See the xdg_popup.popup_done
1258+ event for details.
1259+
1260+ Explicitly destroying the xdg_popup object will also dismiss the popup and
1261+ unmap the surface. Clients that want to dismiss the popup when another
1262+ surface of their own is clicked should dismiss the popup using the destroy
1263+ request.
1264+
1265+ A newly created xdg_popup will be stacked on top of all previously created
1266+ xdg_popup surfaces associated with the same xdg_toplevel.
1267+
1268+ The parent of an xdg_popup must be mapped (see the xdg_surface
1269+ description) before the xdg_popup itself.
1270+
1271+ The client must call wl_surface.commit on the corresponding wl_surface
1272+ for the xdg_popup state to take effect.
1273+ </description>
1274+
1275+ <enum name="error">
1276+ <entry name="invalid_grab" value="0"
1277+ summary="tried to grab after being mapped"/>
1278+ </enum>
1279+
1280+ <request name="destroy" type="destructor">
1281+ <description summary="remove xdg_popup interface">
1282+ This destroys the popup. Explicitly destroying the xdg_popup
1283+ object will also dismiss the popup, and unmap the surface.
1284+
1285+ If this xdg_popup is not the "topmost" popup, the
1286+ xdg_wm_base.not_the_topmost_popup protocol error will be sent.
1287+ </description>
1288+ </request>
1289+
1290+ <request name="grab">
1291+ <description summary="make the popup take an explicit grab">
1292+ This request makes the created popup take an explicit grab. An explicit
1293+ grab will be dismissed when the user dismisses the popup, or when the
1294+ client destroys the xdg_popup. This can be done by the user clicking
1295+ outside the surface, using the keyboard, or even locking the screen
1296+ through closing the lid or a timeout.
1297+
1298+ If the compositor denies the grab, the popup will be immediately
1299+ dismissed.
1300+
1301+ This request must be used in response to some sort of user action like a
1302+ button press, key press, or touch down event. The serial number of the
1303+ event should be passed as 'serial'.
1304+
1305+ The parent of a grabbing popup must either be an xdg_toplevel surface or
1306+ another xdg_popup with an explicit grab. If the parent is another
1307+ xdg_popup it means that the popups are nested, with this popup now being
1308+ the topmost popup.
1309+
1310+ Nested popups must be destroyed in the reverse order they were created
1311+ in, e.g. the only popup you are allowed to destroy at all times is the
1312+ topmost one.
1313+
1314+ When compositors choose to dismiss a popup, they may dismiss every
1315+ nested grabbing popup as well. When a compositor dismisses popups, it
1316+ will follow the same dismissing order as required from the client.
1317+
1318+ If the topmost grabbing popup is destroyed, the grab will be returned to
1319+ the parent of the popup, if that parent previously had an explicit grab.
1320+
1321+ If the parent is a grabbing popup which has already been dismissed, this
1322+ popup will be immediately dismissed. If the parent is a popup that did
1323+ not take an explicit grab, an error will be raised.
1324+
1325+ During a popup grab, the client owning the grab will receive pointer
1326+ and touch events for all their surfaces as normal (similar to an
1327+ "owner-events" grab in X11 parlance), while the top most grabbing popup
1328+ will always have keyboard focus.
1329+ </description>
1330+ <arg name="seat" type="object" interface="wl_seat"
1331+ summary="the wl_seat of the user event"/>
1332+ <arg name="serial" type="uint" summary="the serial of the user event"/>
1333+ </request>
1334+
1335+ <event name="configure">
1336+ <description summary="configure the popup surface">
1337+ This event asks the popup surface to configure itself given the
1338+ configuration. The configured state should not be applied immediately.
1339+ See xdg_surface.configure for details.
1340+
1341+ The x and y arguments represent the position the popup was placed at
1342+ given the xdg_positioner rule, relative to the upper left corner of the
1343+ window geometry of the parent surface.
1344+
1345+ For version 2 or older, the configure event for an xdg_popup is only
1346+ ever sent once for the initial configuration. Starting with version 3,
1347+ it may be sent again if the popup is setup with an xdg_positioner with
1348+ set_reactive requested, or in response to xdg_popup.reposition requests.
1349+ </description>
1350+ <arg name="x" type="int"
1351+ summary="x position relative to parent surface window geometry"/>
1352+ <arg name="y" type="int"
1353+ summary="y position relative to parent surface window geometry"/>
1354+ <arg name="width" type="int" summary="window geometry width"/>
1355+ <arg name="height" type="int" summary="window geometry height"/>
1356+ </event>
1357+
1358+ <event name="popup_done">
1359+ <description summary="popup interaction is done">
1360+ The popup_done event is sent out when a popup is dismissed by the
1361+ compositor. The client should destroy the xdg_popup object at this
1362+ point.
1363+ </description>
1364+ </event>
1365+
1366+ <!-- Version 3 additions -->
1367+
1368+ <request name="reposition" since="3">
1369+ <description summary="recalculate the popup's location">
1370+ Reposition an already-mapped popup. The popup will be placed given the
1371+ details in the passed xdg_positioner object, and a
1372+ xdg_popup.repositioned followed by xdg_popup.configure and
1373+ xdg_surface.configure will be emitted in response. Any parameters set
1374+ by the previous positioner will be discarded.
1375+
1376+ The passed token will be sent in the corresponding
1377+ xdg_popup.repositioned event. The new popup position will not take
1378+ effect until the corresponding configure event is acknowledged by the
1379+ client. See xdg_popup.repositioned for details. The token itself is
1380+ opaque, and has no other special meaning.
1381+
1382+ If multiple reposition requests are sent, the compositor may skip all
1383+ but the last one.
1384+
1385+ If the popup is repositioned in response to a configure event for its
1386+ parent, the client should send an xdg_positioner.set_parent_configure
1387+ and possibly an xdg_positioner.set_parent_size request to allow the
1388+ compositor to properly constrain the popup.
1389+
1390+ If the popup is repositioned together with a parent that is being
1391+ resized, but not in response to a configure event, the client should
1392+ send an xdg_positioner.set_parent_size request.
1393+ </description>
1394+ <arg name="positioner" type="object" interface="xdg_positioner"/>
1395+ <arg name="token" type="uint" summary="reposition request token"/>
1396+ </request>
1397+
1398+ <event name="repositioned" since="3">
1399+ <description summary="signal the completion of a repositioned request">
1400+ The repositioned event is sent as part of a popup configuration
1401+ sequence, together with xdg_popup.configure and lastly
1402+ xdg_surface.configure to notify the completion of a reposition request.
1403+
1404+ The repositioned event is to notify about the completion of a
1405+ xdg_popup.reposition request. The token argument is the token passed
1406+ in the xdg_popup.reposition request.
1407+
1408+ Immediately after this event is emitted, xdg_popup.configure and
1409+ xdg_surface.configure will be sent with the updated size and position,
1410+ as well as a new configure serial.
1411+
1412+ The client should optionally update the content of the popup, but must
1413+ acknowledge the new popup configuration for the new position to take
1414+ effect. See xdg_surface.ack_configure for details.
1415+ </description>
1416+ <arg name="token" type="uint" summary="reposition request token"/>
1417+ </event>
1418+
1419+ </interface>
1420+</protocol>
M server/arena.go +18 -5
@@ -10,26 +10,39 @@ import (
1010
1111 // arena is C-visible memory the Go GC never moves or frees. It holds
1212 // wl_interface and wl_message tables and their strings for the whole
13-// process lifetime.
13+// process lifetime. It grows by mapping new chunks; chunks are never unmapped.
1414 type arena struct {
1515 mem []byte
1616 base uintptr
1717 off int
1818 }
1919
20-func newArena(size int) (*arena, error) {
20+const arenaChunk = 1 << 20
21+
22+func (a *arena) grow(n int) error {
23+ size := max(arenaChunk, n)
2124 mem, err := unix.Mmap(-1, 0, size, unix.PROT_READ|unix.PROT_WRITE, unix.MAP_PRIVATE|unix.MAP_ANONYMOUS)
2225 if err != nil {
23- return nil, fmt.Errorf("arena: mmap: %w", err)
26+ return fmt.Errorf("purego-libwayland: arena mmap: %w", err)
27+ }
28+ a.mem, a.base, a.off = mem, uintptr(unsafe.Pointer(&mem[0])), 0
29+ return nil
30+}
31+
32+// reserve makes sure n more bytes fit in the current chunk. Callers reserve
33+// the whole size of a table set up front so offsets stay in one chunk.
34+func (a *arena) reserve(n int) error {
35+ if a.mem != nil && ((a.off+7)&^7)+n <= len(a.mem) {
36+ return nil
2437 }
25- return &arena{mem: mem, base: uintptr(unsafe.Pointer(&mem[0]))}, nil
38+ return a.grow(n)
2639 }
2740
2841 // alloc returns the offset and C address of n zeroed, 8-byte aligned bytes.
2942 func (a *arena) alloc(n int) (int, uintptr) {
3043 a.off = (a.off + 7) &^ 7
3144 if a.off+n > len(a.mem) {
32- panic("purego-libwayland: arena exhausted")
45+ panic("purego-libwayland: arena reservation too small")
3346 }
3447 off := a.off
3548 a.off += n
A server/args.go +99 -0
@@ -0,0 +1,99 @@
1+package server
2+
3+import (
4+ "math"
5+ "runtime"
6+ "unsafe"
7+)
8+
9+// Arg is one raw union wl_argument value.
10+type Arg uint64
11+
12+// Fixed is a wl_fixed_t: a signed 24.8 fixed-point number.
13+type Fixed int32
14+
15+func FixedFromFloat(v float64) Fixed { return Fixed(math.Round(v * 256)) }
16+func (f Fixed) Float() float64 { return float64(f) / 256 }
17+
18+// Argument constructors for PostEvent.
19+func Uint(v uint32) Arg { return Arg(v) }
20+func Int(v int32) Arg { return Arg(uint32(v)) }
21+func FixedArg(v Fixed) Arg { return Arg(uint32(v)) }
22+
23+// Fd passes a file descriptor. libwayland duplicates it, so the caller keeps
24+// ownership.
25+func Fd(fd int) Arg { return Arg(uint32(int32(fd))) }
26+
27+// Object passes a resource, or a null object when r is nil.
28+func Object(r *Resource) Arg {
29+ if r == nil {
30+ return 0
31+ }
32+ return Arg(r.c)
33+}
34+
35+// NewID passes a resource created for a new_id event argument.
36+func NewID(r *Resource) Arg { return Object(r) }
37+
38+// String passes a string. The bytes stay pinned until p is unpinned, which
39+// must happen after PostEvent returns. With null set, "" is sent as NULL.
40+func String(p *runtime.Pinner, s string, null bool) Arg {
41+ if null && s == "" {
42+ return 0
43+ }
44+ b := make([]byte, len(s)+1)
45+ copy(b, s)
46+ p.Pin(&b[0])
47+ return Arg(uintptr(unsafe.Pointer(&b[0])))
48+}
49+
50+// wlArray matches struct wl_array on LP64 (size_t, size_t, void *).
51+type wlArray struct {
52+ size uintptr
53+ alloc uintptr
54+ data unsafe.Pointer
55+}
56+
57+// Array passes a byte array. See String for the pinning rule.
58+func Array(p *runtime.Pinner, b []byte) Arg {
59+ a := &wlArray{size: uintptr(len(b)), alloc: uintptr(len(b))}
60+ if len(b) > 0 {
61+ p.Pin(&b[0])
62+ a.data = unsafe.Pointer(&b[0])
63+ }
64+ p.Pin(a)
65+ return Arg(uintptr(unsafe.Pointer(a)))
66+}
67+
68+// Request argument accessors. Values are only valid during dispatch; the
69+// String and Array accessors copy.
70+func (a Arg) Uint() uint32 { return uint32(a) }
71+func (a Arg) Int() int32 { return int32(uint32(a)) }
72+func (a Arg) Fixed() Fixed { return Fixed(int32(uint32(a))) }
73+func (a Arg) NewID() uint32 { return uint32(a) }
74+func (a Arg) Resource() *Resource { return live.resources[uintptr(a)] }
75+
76+// Fd returns a received file descriptor. The handler owns it and must close it.
77+func (a Arg) Fd() int { return int(int32(uint32(a))) }
78+
79+// String copies a received string; NULL becomes "".
80+func (a Arg) String() string {
81+ p := *(*unsafe.Pointer)(unsafe.Pointer(&a)) // C memory owned by libwayland
82+ if p == nil {
83+ return ""
84+ }
85+ n := 0
86+ for *(*byte)(unsafe.Add(p, n)) != 0 {
87+ n++
88+ }
89+ return string(unsafe.Slice((*byte)(p), n))
90+}
91+
92+// Array copies a received wl_array.
93+func (a Arg) Array() []byte {
94+ arr := (*wlArray)(*(*unsafe.Pointer)(unsafe.Pointer(&a))) // C memory owned by libwayland
95+ if arr == nil || arr.size == 0 {
96+ return nil
97+ }
98+ return append([]byte(nil), unsafe.Slice((*byte)(arr.data), arr.size)...)
99+}
M server/display.go +61 -16
@@ -5,20 +5,11 @@ import (
55 "errors"
66 "fmt"
77 "runtime"
8+ "strings"
89 "unsafe"
9-)
10-
11-// Arg is one raw union wl_argument value (int, uint, fixed, object pointer,
12-// new_id, or fd).
13-type Arg uint64
1410
15-func Uint(v uint32) Arg { return Arg(v) }
16-func Int(v int32) Arg { return Arg(uint32(v)) }
17-func Object(r *Resource) Arg { return Arg(r.c) }
18-func (a Arg) Uint() uint32 { return uint32(a) }
19-func (a Arg) Int() int32 { return int32(uint32(a)) }
20-func (a Arg) NewID() uint32 { return uint32(a) }
21-func (a Arg) Resource() *Resource { return live.resources[uintptr(a)] }
11+ "golang.org/x/sys/unix"
12+)
2213
2314 // Handler receives every request sent to a resource.
2415 type Handler func(r *Resource, opcode uint32, args []Arg)
@@ -35,6 +26,10 @@ type Resource struct {
3526 iface *Interface
3627 handler Handler
3728 OnDestroy func()
29+ gone bool
30+
31+ // Data holds the owner's state, typically the generated wrapper.
32+ Data any
3833 }
3934
4035 // live holds Go state reachable from C callbacks. It is only touched on the
@@ -128,24 +123,54 @@ func (c Client) CreateResource(iface *Interface, version int32, id uint32, h Han
128123 func (r *Resource) ID() uint32 { return wlResourceGetID(r.c) }
129124 func (r *Resource) Version() int32 { return wlResourceGetVersion(r.c) }
130125 func (r *Resource) Client() Client { return Client{wlResourceGetClient(r.c)} }
131-func (r *Resource) Destroy() { wlResourceDestroy(r.c) }
132126 func (r *Resource) Iface() *Interface { return r.iface }
133127
134-// PostEvent sends an event. String and array arguments are not supported yet.
128+// Destroy frees the resource. It is a no-op once the resource is gone, so
129+// generated destructor requests and handlers may both call it.
130+func (r *Resource) Destroy() {
131+ if !r.gone {
132+ wlResourceDestroy(r.c)
133+ }
134+}
135+
136+// PostEvent sends an event. Arguments must match the event signature; build
137+// string and array arguments with a Pinner and unpin it after this returns.
135138 func (r *Resource) PostEvent(opcode uint32, args ...Arg) {
136139 var p unsafe.Pointer
137140 if len(args) > 0 {
138141 p = unsafe.Pointer(&args[0])
139142 }
143+ var pin runtime.Pinner
144+ if p != nil {
145+ pin.Pin(p)
146+ defer pin.Unpin()
147+ }
140148 wlResourcePostEventArr(r.c, opcode, p)
141149 runtime.KeepAlive(args)
142150 }
143151
152+// PostError sends a protocol error and disconnects the client.
153+func (r *Resource) PostError(code uint32, msg string) {
154+ // wl_resource_post_error takes a printf format; escape it and pass no
155+ // variadic arguments (purego clears AL, as SysV varargs require).
156+ b := append([]byte(strings.ReplaceAll(msg, "%", "%%")), 0)
157+ var pin runtime.Pinner
158+ pin.Pin(&b[0])
159+ defer pin.Unpin()
160+ wlResourcePostError(r.c, code, uintptr(unsafe.Pointer(&b[0])))
161+ runtime.KeepAlive(b)
162+}
163+
144164 // implMarker is a non-nil implementation pointer. libwayland only passes it
145165 // back to our dispatcher.
146166 func implMarker() uintptr {
147167 if marker == 0 {
168+ tablesMu.Lock()
169+ if err := tables.reserve(8); err != nil {
170+ panic(err)
171+ }
148172 _, marker = tables.alloc(8)
173+ tablesMu.Unlock()
149174 }
150175 return marker
151176 }
@@ -156,10 +181,12 @@ var marker uintptr
156181
157182 func dispatch(_ uintptr, target uintptr, opcode uint32, msg unsafe.Pointer, args unsafe.Pointer) int32 {
158183 r := live.resources[target]
184+ sig := msgSignature(msg)
159185 if r == nil || r.handler == nil {
186+ closeRequestFDs(sig, args)
160187 return 0
161188 }
162- n := argCount(msgSignature(msg))
189+ n := argCount(sig)
163190 var a []Arg
164191 if n > 0 {
165192 a = append([]Arg(nil), unsafe.Slice((*Arg)(args), n)...)
@@ -171,7 +198,11 @@ func dispatch(_ uintptr, target uintptr, opcode uint32, msg unsafe.Pointer, args
171198 func destroyed(res uintptr) {
172199 r := live.resources[res]
173200 delete(live.resources, res)
174- if r != nil && r.OnDestroy != nil {
201+ if r == nil {
202+ return
203+ }
204+ r.gone = true
205+ if r.OnDestroy != nil {
175206 r.OnDestroy()
176207 }
177208 }
@@ -192,6 +223,20 @@ func msgSignature(msg unsafe.Pointer) string {
192223 return string(unsafe.Slice((*byte)(p), n))
193224 }
194225
226+// closeRequestFDs takes ownership of fd arguments when there is no handler.
227+func closeRequestFDs(sig string, args unsafe.Pointer) {
228+ i := 0
229+ for _, ch := range sig {
230+ if ch == '?' || (ch >= '0' && ch <= '9') {
231+ continue
232+ }
233+ if ch == 'h' {
234+ _ = unix.Close((*Arg)(unsafe.Add(args, i*8)).Fd())
235+ }
236+ i++
237+ }
238+}
239+
195240 // argCount counts arguments in a libwayland signature ("?oii", "2n", ...).
196241 func argCount(sig string) int {
197242 n := 0
A server/display_test.go +32 -0
@@ -0,0 +1,32 @@
1+package server
2+
3+import (
4+ "golang.org/x/sys/unix"
5+ "testing"
6+ "unsafe"
7+)
8+
9+func TestNoHandlerClosesFDs(t *testing.T) {
10+ for _, sig := range []string{"2?oh", "12uhu"} {
11+ fds := []int{0, 0}
12+ if err := unix.Pipe(fds); err != nil {
13+ t.Fatal(err)
14+ }
15+ defer unix.Close(fds[1])
16+ args := make([]Arg, argCount(sig))
17+ i := 0
18+ for _, ch := range sig {
19+ if ch == '?' || (ch >= '0' && ch <= '9') {
20+ continue
21+ }
22+ if ch == 'h' {
23+ args[i] = Fd(fds[0])
24+ }
25+ i++
26+ }
27+ closeRequestFDs(sig, unsafe.Pointer(&args[0]))
28+ if _, err := unix.FcntlInt(uintptr(fds[0]), unix.F_GETFD, 0); err != unix.EBADF {
29+ t.Fatalf("signature %s: fd not closed: %v", sig, err)
30+ }
31+ }
32+}
M server/interface.go +41 -17
@@ -1,16 +1,19 @@
11 package server
22
3+import "sync"
4+
35 // Message describes one request or event. Signature uses the libwayland
4-// format ("n", "?oii", ...). Types holds one entry per argument; entries are
5-// non-nil only for typed new_id and object arguments.
6+// format ("n", "?oii", "2u", ...). Types holds one entry per argument, and may
7+// be shorter than the argument list; entries are non-nil only for typed
8+// new_id and object arguments.
69 type Message struct {
710 Name string
811 Signature string
912 Types []*Interface
1013 }
1114
12-// Interface describes a protocol interface. Build it once with
13-// NewInterfaces; its C table lives for the process lifetime.
15+// Interface describes a protocol interface. Build its C table once with
16+// NewInterfaces; the table lives for the process lifetime.
1417 type Interface struct {
1518 Name string
1619 Version int32
@@ -30,22 +33,21 @@ const (
3033 sizeInterface = 40
3134 )
3235
33-var tables *arena
36+var (
37+ tablesMu sync.Mutex
38+ tables arena
39+)
3440
3541 // NewInterfaces writes C tables for a set of interfaces that may reference
36-// each other. It must be called before any interface is used.
42+// each other. Interfaces from other sets must already be built. It does not
43+// load libwayland, so generated packages call it from init.
3744 func NewInterfaces(ifaces ...*Interface) error {
38- if err := load(); err != nil {
45+ tablesMu.Lock()
46+ defer tablesMu.Unlock()
47+ if err := tables.reserve(tableSize(ifaces)); err != nil {
3948 return err
4049 }
41- if tables == nil {
42- a, err := newArena(1 << 20)
43- if err != nil {
44- return err
45- }
46- tables = a
47- }
48- a := tables
50+ a := &tables
4951 // Pass 1: reserve every wl_interface so cross references resolve.
5052 offs := make([]int, len(ifaces))
5153 for i, it := range ifaces {
@@ -64,6 +66,25 @@ func NewInterfaces(ifaces ...*Interface) error {
6466 return nil
6567 }
6668
69+// tableSize is an upper bound of the arena bytes NewInterfaces uses,
70+// counting 7 bytes of alignment padding per allocation.
71+func tableSize(ifaces []*Interface) int {
72+ n := 0
73+ for _, it := range ifaces {
74+ n += sizeInterface + 7 + len(it.Name) + 1 + 7
75+ for _, msgs := range [][]Message{it.Requests, it.Events} {
76+ n += sizeMessage*len(msgs) + 7
77+ for _, m := range msgs {
78+ n += len(m.Name) + 1 + 7 + len(m.Signature) + 1 + 7 + 8*argCount(m.Signature) + 7
79+ }
80+ }
81+ }
82+ return n
83+}
84+
85+// writeMessages writes a wl_message array. Every message with arguments gets
86+// a types array, because libwayland reads it for each object and new_id
87+// argument even when the interface is unknown.
6788 func writeMessages(a *arena, msgs []Message) uintptr {
6889 if len(msgs) == 0 {
6990 return 0
@@ -71,8 +92,11 @@ func writeMessages(a *arena, msgs []Message) uintptr {
7192 off, addr := a.alloc(sizeMessage * len(msgs))
7293 for i, m := range msgs {
7394 var types uintptr
74- if len(m.Types) > 0 {
75- toff, taddr := a.alloc(8 * len(m.Types))
95+ if n := argCount(m.Signature); n > 0 {
96+ if len(m.Types) > n {
97+ panic("purego-libwayland: " + m.Name + " has more types than arguments")
98+ }
99+ toff, taddr := a.alloc(8 * n)
76100 for j, t := range m.Types {
77101 if t != nil {
78102 if t.c == 0 {
A server/interface_test.go +24 -0
@@ -0,0 +1,24 @@
1+package server
2+
3+import (
4+ "testing"
5+ "unsafe"
6+)
7+
8+func TestForwardReferenceCTable(t *testing.T) {
9+ first := &Interface{Name: "test_first", Version: 1}
10+ later := &Interface{Name: "test_later", Version: 1}
11+ first.Requests = []Message{{Name: "make", Signature: "n", Types: []*Interface{later}}}
12+ if err := NewInterfaces(first, later); err != nil {
13+ t.Fatal(err)
14+ }
15+ messages := *(*unsafe.Pointer)(unsafe.Add(unsafe.Pointer(&tables.mem[0]), first.c-tables.base+16))
16+ types := *(*unsafe.Pointer)(unsafe.Add(messages, 16))
17+ if types == nil {
18+ t.Fatal("missing C types array")
19+ }
20+ target := uintptr(*(*unsafe.Pointer)(types))
21+ if target == 0 || target != later.c {
22+ t.Fatalf("forward reference C types: target=%#x want=%#x", target, later.c)
23+ }
24+}

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 14

↑↓ moveenter openesc close