1package testserver
2
3import (
4 "github.com/bnema/purego-libwayland/protocol/extimagecapturesource"
5 "github.com/bnema/purego-libwayland/protocol/wayland"
6 "github.com/bnema/purego-libwayland/server"
7 "golang.org/x/sys/unix"
8)
9
10func (s *Server) addOutput(spec OutputSpec, must func(error)) {
11 o := &output{spec: spec}
12 v := spec.Version
13 if v == 0 {
14 v = 4
15 }
16 g, err := s.d.AddGlobal(wayland.OutputInterface, int32(v), func(c server.Client, ver, id uint32) {
17 res, err := wayland.NewOutput(c, int32(ver), id, outputHandler{})
18 if err != nil {
19 must(err)
20 return
21 }
22 o.res = append(o.res, res)
23 res.SendGeometry(0, 0, 0, 0, 0, "test", "test", 0)
24 res.SendMode(1, int32(spec.Width), int32(spec.Height), 60000)
25 if ver >= 2 {
26 scale := spec.Scale
27 if scale == 0 {
28 scale = 1
29 }
30 res.SendScale(scale)
31 }
32 if ver >= 4 {
33 res.SendName(spec.Name)
34 }
35 if ver >= 2 {
36 res.SendDone()
37 }
38 })
39 must(err)
40 o.global = g
41 s.outputs = append(s.outputs, o)
42}
43
44type outputHandler struct{}
45
46func (outputHandler) Release(*wayland.Output) {}
47
48func (s *Server) outputOf(r *server.Resource) *output {
49 for _, o := range s.outputs {
50 for _, res := range o.res {
51 if res.Resource == r {
52 return o
53 }
54 }
55 }
56 return nil
57}
58
59// RemoveOutput withdraws the named output's global and stops its sessions.
60func (s *Server) RemoveOutput(name string) {
61 s.Do(func() {
62 for _, o := range s.outputs {
63 if o.spec.Name == name && !o.removed {
64 o.removed = true
65 o.global.Remove()
66 for _, c := range s.sessions {
67 if c.out == o {
68 c.stop()
69 }
70 }
71 }
72 }
73 })
74}
75
76// pool is one wl_shm_pool mapping, shared by the buffers made from it.
77type pool struct {
78 data []byte
79 refs int
80 destroyed bool
81}
82
83func (p *pool) release() {
84 if p.refs == 0 && p.destroyed && p.data != nil {
85 _ = unix.Munmap(p.data)
86 p.data = nil
87 }
88}
89
90type buffer struct {
91 p *pool
92 offset int
93 width, height, stride, format uint32
94}
95
96func (b *buffer) bytes() []byte {
97 n := int(b.stride) * int(b.height)
98 if b.p.data == nil || b.offset+n > len(b.p.data) {
99 return nil
100 }
101 return b.p.data[b.offset : b.offset+n]
102}
103
104type shmHandler struct{ s *Server }
105
106func (h shmHandler) CreatePool(self *wayland.Shm, id uint32, fd int, size int32) {
107 defer unix.Close(fd)
108 data, err := unix.Mmap(fd, 0, int(size), unix.PROT_READ|unix.PROT_WRITE, unix.MAP_SHARED)
109 if err != nil {
110 self.PostError(0, "mmap failed")
111 return
112 }
113 _, _ = wayland.NewShmPool(self.Client(), 1, id, &poolHandler{s: h.s, p: &pool{data: data}})
114}
115func (shmHandler) Release(*wayland.Shm) {}
116
117type poolHandler struct {
118 s *Server
119 p *pool
120}
121
122func (h *poolHandler) CreateBuffer(self *wayland.ShmPool, id uint32, offset, width, height, stride int32, format uint32) {
123 b := &buffer{p: h.p, offset: int(offset), width: uint32(width), height: uint32(height), stride: uint32(stride), format: format}
124 res, err := wayland.NewBuffer(self.Client(), 1, id, bufferHandler{h.s, b})
125 if err != nil {
126 return
127 }
128 h.p.refs++
129 h.s.bufs[res.Resource] = b
130 h.s.stats.Buffers++
131 res.OnDestroy = func() {
132 delete(h.s.bufs, res.Resource)
133 h.s.stats.DestroyedBuffers++
134 h.p.refs--
135 h.p.release()
136 }
137}
138func (h *poolHandler) Destroy(*wayland.ShmPool) { h.p.destroyed = true; h.p.release() }
139func (h *poolHandler) Resize(*wayland.ShmPool, int32) {}
140
141type bufferHandler struct {
142 s *Server
143 b *buffer
144}
145
146func (bufferHandler) Destroy(*wayland.Buffer) {}
147
148type outputSourceManager struct{ s *Server }
149
150func (m outputSourceManager) CreateSource(self *extimagecapturesource.ExtOutputImageCaptureSourceManagerV1, id uint32, out *wayland.Output) {
151 m.s.newSource(self.Client(), id, &source{kind: "output", out: m.s.outputOf(out.Resource)})
152}
153func (outputSourceManager) Destroy(*extimagecapturesource.ExtOutputImageCaptureSourceManagerV1) {}
154
155type source struct {
156 kind string // output, region, workspace
157 out *output
158 region [4]int32
159 ws *workspace
160 gone bool // the workspace handle was already removed
161}
162
163func (s *Server) newSource(c server.Client, id uint32, src *source) {
164 res, err := extimagecapturesource.NewExtImageCaptureSourceV1(c, 1, id, sourceHandler{})
165 if err != nil {
166 return
167 }
168 s.sources[res.Resource] = src
169 res.OnDestroy = func() { delete(s.sources, res.Resource) } // sessions keep their own pointer
170}
171
172type sourceHandler struct{}
173
174func (sourceHandler) Destroy(*extimagecapturesource.ExtImageCaptureSourceV1) {}