detached 8bce9bf

feat(screencast): add the adapter skeleton, seams and run loop

commit
8bce9bf5adc2d94eedca516afc58a62d6157cbc7
author
brice · · 2026-10-14 20:13 UTC
committer
brice · · 2026-10-14 21:39 UTC
parent
9fb27a4
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
15 files · +2594 -0
M .mockery.yml +37 -0
@@ -111,3 +111,40 @@ packages:
111111 dir: internal/adapters/statefile
112112 pkgname: statefile
113113 filename: proc_tree_mock_test.go
114+ github.com/bnema/neferwl/internal/adapters/screencast:
115+ interfaces:
116+ bus:
117+ config:
118+ dir: internal/adapters/screencast
119+ pkgname: screencast
120+ filename: bus_mock_test.go
121+ videoSource:
122+ config:
123+ dir: internal/adapters/screencast
124+ pkgname: screencast
125+ filename: video_source_mock_test.go
126+ videoCore:
127+ config:
128+ dir: internal/adapters/screencast
129+ pkgname: screencast
130+ filename: video_core_mock_test.go
131+ peerResolver:
132+ config:
133+ dir: internal/adapters/screencast
134+ pkgname: screencast
135+ filename: peer_resolver_mock_test.go
136+ runner:
137+ config:
138+ dir: internal/adapters/screencast
139+ pkgname: screencast
140+ filename: runner_mock_test.go
141+ dialer:
142+ config:
143+ dir: internal/adapters/screencast
144+ pkgname: screencast
145+ filename: dialer_mock_test.go
146+ pipewireOpener:
147+ config:
148+ dir: internal/adapters/screencast
149+ pkgname: screencast
150+ filename: pipewire_opener_mock_test.go
@@ -111,3 +111,40 @@ packages:
111 dir: internal/adapters/statefile111 dir: internal/adapters/statefile
112 pkgname: statefile112 pkgname: statefile
113 filename: proc_tree_mock_test.go113 filename: proc_tree_mock_test.go
114+ github.com/bnema/neferwl/internal/adapters/screencast:
115+ interfaces:
116+ bus:
117+ config:
118+ dir: internal/adapters/screencast
119+ pkgname: screencast
120+ filename: bus_mock_test.go
121+ videoSource:
122+ config:
123+ dir: internal/adapters/screencast
124+ pkgname: screencast
125+ filename: video_source_mock_test.go
126+ videoCore:
127+ config:
128+ dir: internal/adapters/screencast
129+ pkgname: screencast
130+ filename: video_core_mock_test.go
131+ peerResolver:
132+ config:
133+ dir: internal/adapters/screencast
134+ pkgname: screencast
135+ filename: peer_resolver_mock_test.go
136+ runner:
137+ config:
138+ dir: internal/adapters/screencast
139+ pkgname: screencast
140+ filename: runner_mock_test.go
141+ dialer:
142+ config:
143+ dir: internal/adapters/screencast
144+ pkgname: screencast
145+ filename: dialer_mock_test.go
146+ pipewireOpener:
147+ config:
148+ dir: internal/adapters/screencast
149+ pkgname: screencast
150+ filename: pipewire_opener_mock_test.go
A internal/adapters/screencast/bus.go +29 -0
@@ -0,0 +1,29 @@
1+package screencast
2+
3+import "github.com/bnema/zerobus"
4+
5+// request is a decoded method call: every string is copied and capped, so it
6+// outlives the receive buffer while it waits for the caller check.
7+type request struct {
8+ sender string
9+ serial uint32
10+ noWait bool // the caller expects no reply
11+}
12+
13+// session is one org.gnome.Mutter.ScreenCast.Session.
14+type session struct {
15+ used bool
16+ owner string
17+}
18+
19+func (s *Service) onMessage(m *zerobus.Message) { _ = m }
20+
21+func (s *Service) forEachSession(f func(*session)) {
22+ for i := range s.sessions {
23+ if s.sessions[i].used {
24+ f(&s.sessions[i])
25+ }
26+ }
27+}
28+
29+func (s *Service) closeSession(sess *session, signal bool) { _, _ = sess, signal }
@@ -0,0 +1,29 @@
1+package screencast
2+
3+import "github.com/bnema/zerobus"
4+
5+// request is a decoded method call: every string is copied and capped, so it
6+// outlives the receive buffer while it waits for the caller check.
7+type request struct {
8+ sender string
9+ serial uint32
10+ noWait bool // the caller expects no reply
11+}
12+
13+// session is one org.gnome.Mutter.ScreenCast.Session.
14+type session struct {
15+ used bool
16+ owner string
17+}
18+
19+func (s *Service) onMessage(m *zerobus.Message) { _ = m }
20+
21+func (s *Service) forEachSession(f func(*session)) {
22+ for i := range s.sessions {
23+ if s.sessions[i].used {
24+ f(&s.sessions[i])
25+ }
26+ }
27+}
28+
29+func (s *Service) closeSession(sess *session, signal bool) { _, _ = sess, signal }
A internal/adapters/screencast/bus_mock_test.go +774 -0
@@ -0,0 +1,774 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package screencast
6+
7+import (
8+ "syscall"
9+
10+ "github.com/bnema/zerobus"
11+ mock "github.com/stretchr/testify/mock"
12+)
13+
14+// newMockbus creates a new instance of mockbus. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
15+// The first argument is typically a *testing.T value.
16+func newMockbus(t interface {
17+ mock.TestingT
18+ Cleanup(func())
19+}) *mockbus {
20+ if helper, ok := t.(interface{ Helper() }); ok {
21+ helper.Helper()
22+ }
23+
24+ mock := &mockbus{}
25+ mock.Mock.Test(t)
26+
27+ t.Cleanup(func() {
28+ if helper, ok := t.(interface{ Helper() }); ok {
29+ helper.Helper()
30+ }
31+ mock.AssertExpectations(t)
32+ })
33+
34+ return mock
35+}
36+
37+// mockbus is an autogenerated mock type for the bus type
38+type mockbus struct {
39+ mock.Mock
40+}
41+
42+type mockbus_Expecter struct {
43+ mock *mock.Mock
44+}
45+
46+func (_m *mockbus) EXPECT() *mockbus_Expecter {
47+ return &mockbus_Expecter{mock: &_m.Mock}
48+}
49+
50+// AddMatch provides a mock function for the type mockbus
51+func (_mock *mockbus) AddMatch(rule string) error {
52+ ret := _mock.Called(rule)
53+
54+ if len(ret) == 0 {
55+ panic("no return value specified for AddMatch")
56+ }
57+
58+ var r0 error
59+ if returnFunc, ok := ret.Get(0).(func(string) error); ok {
60+ r0 = returnFunc(rule)
61+ } else {
62+ r0 = ret.Error(0)
63+ }
64+ return r0
65+}
66+
67+// mockbus_AddMatch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddMatch'
68+type mockbus_AddMatch_Call struct {
69+ *mock.Call
70+}
71+
72+// AddMatch is a helper method to define mock.On call
73+// - rule string
74+func (_e *mockbus_Expecter) AddMatch(rule any) *mockbus_AddMatch_Call {
75+ return &mockbus_AddMatch_Call{Call: _e.mock.On("AddMatch", rule)}
76+}
77+
78+func (_c *mockbus_AddMatch_Call) Run(run func(rule string)) *mockbus_AddMatch_Call {
79+ _c.Call.Run(func(args mock.Arguments) {
80+ var arg0 string
81+ if args[0] != nil {
82+ arg0 = args[0].(string)
83+ }
84+ run(
85+ arg0,
86+ )
87+ })
88+ return _c
89+}
90+
91+func (_c *mockbus_AddMatch_Call) Return(err error) *mockbus_AddMatch_Call {
92+ _c.Call.Return(err)
93+ return _c
94+}
95+
96+func (_c *mockbus_AddMatch_Call) RunAndReturn(run func(rule string) error) *mockbus_AddMatch_Call {
97+ _c.Call.Return(run)
98+ return _c
99+}
100+
101+// Buffered provides a mock function for the type mockbus
102+func (_mock *mockbus) Buffered() bool {
103+ ret := _mock.Called()
104+
105+ if len(ret) == 0 {
106+ panic("no return value specified for Buffered")
107+ }
108+
109+ var r0 bool
110+ if returnFunc, ok := ret.Get(0).(func() bool); ok {
111+ r0 = returnFunc()
112+ } else {
113+ r0 = ret.Get(0).(bool)
114+ }
115+ return r0
116+}
117+
118+// mockbus_Buffered_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Buffered'
119+type mockbus_Buffered_Call struct {
120+ *mock.Call
121+}
122+
123+// Buffered is a helper method to define mock.On call
124+func (_e *mockbus_Expecter) Buffered() *mockbus_Buffered_Call {
125+ return &mockbus_Buffered_Call{Call: _e.mock.On("Buffered")}
126+}
127+
128+func (_c *mockbus_Buffered_Call) Run(run func()) *mockbus_Buffered_Call {
129+ _c.Call.Run(func(args mock.Arguments) {
130+ run()
131+ })
132+ return _c
133+}
134+
135+func (_c *mockbus_Buffered_Call) Return(b bool) *mockbus_Buffered_Call {
136+ _c.Call.Return(b)
137+ return _c
138+}
139+
140+func (_c *mockbus_Buffered_Call) RunAndReturn(run func() bool) *mockbus_Buffered_Call {
141+ _c.Call.Return(run)
142+ return _c
143+}
144+
145+// Close provides a mock function for the type mockbus
146+func (_mock *mockbus) Close() error {
147+ ret := _mock.Called()
148+
149+ if len(ret) == 0 {
150+ panic("no return value specified for Close")
151+ }
152+
153+ var r0 error
154+ if returnFunc, ok := ret.Get(0).(func() error); ok {
155+ r0 = returnFunc()
156+ } else {
157+ r0 = ret.Error(0)
158+ }
159+ return r0
160+}
161+
162+// mockbus_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
163+type mockbus_Close_Call struct {
164+ *mock.Call
165+}
166+
167+// Close is a helper method to define mock.On call
168+func (_e *mockbus_Expecter) Close() *mockbus_Close_Call {
169+ return &mockbus_Close_Call{Call: _e.mock.On("Close")}
170+}
171+
172+func (_c *mockbus_Close_Call) Run(run func()) *mockbus_Close_Call {
173+ _c.Call.Run(func(args mock.Arguments) {
174+ run()
175+ })
176+ return _c
177+}
178+
179+func (_c *mockbus_Close_Call) Return(err error) *mockbus_Close_Call {
180+ _c.Call.Return(err)
181+ return _c
182+}
183+
184+func (_c *mockbus_Close_Call) RunAndReturn(run func() error) *mockbus_Close_Call {
185+ _c.Call.Return(run)
186+ return _c
187+}
188+
189+// NewError provides a mock function for the type mockbus
190+func (_mock *mockbus) NewError(m *zerobus.Message, name string, sig string) *zerobus.Encoder {
191+ ret := _mock.Called(m, name, sig)
192+
193+ if len(ret) == 0 {
194+ panic("no return value specified for NewError")
195+ }
196+
197+ var r0 *zerobus.Encoder
198+ if returnFunc, ok := ret.Get(0).(func(*zerobus.Message, string, string) *zerobus.Encoder); ok {
199+ r0 = returnFunc(m, name, sig)
200+ } else {
201+ if ret.Get(0) != nil {
202+ r0 = ret.Get(0).(*zerobus.Encoder)
203+ }
204+ }
205+ return r0
206+}
207+
208+// mockbus_NewError_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewError'
209+type mockbus_NewError_Call struct {
210+ *mock.Call
211+}
212+
213+// NewError is a helper method to define mock.On call
214+// - m *zerobus.Message
215+// - name string
216+// - sig string
217+func (_e *mockbus_Expecter) NewError(m any, name any, sig any) *mockbus_NewError_Call {
218+ return &mockbus_NewError_Call{Call: _e.mock.On("NewError", m, name, sig)}
219+}
220+
221+func (_c *mockbus_NewError_Call) Run(run func(m *zerobus.Message, name string, sig string)) *mockbus_NewError_Call {
222+ _c.Call.Run(func(args mock.Arguments) {
223+ var arg0 *zerobus.Message
224+ if args[0] != nil {
225+ arg0 = args[0].(*zerobus.Message)
226+ }
227+ var arg1 string
228+ if args[1] != nil {
229+ arg1 = args[1].(string)
230+ }
231+ var arg2 string
232+ if args[2] != nil {
233+ arg2 = args[2].(string)
234+ }
235+ run(
236+ arg0,
237+ arg1,
238+ arg2,
239+ )
240+ })
241+ return _c
242+}
243+
244+func (_c *mockbus_NewError_Call) Return(encoder *zerobus.Encoder) *mockbus_NewError_Call {
245+ _c.Call.Return(encoder)
246+ return _c
247+}
248+
249+func (_c *mockbus_NewError_Call) RunAndReturn(run func(m *zerobus.Message, name string, sig string) *zerobus.Encoder) *mockbus_NewError_Call {
250+ _c.Call.Return(run)
251+ return _c
252+}
253+
254+// NewMethodCall provides a mock function for the type mockbus
255+func (_mock *mockbus) NewMethodCall(dest string, path string, iface string, member string, sig string) (*zerobus.Encoder, uint32) {
256+ ret := _mock.Called(dest, path, iface, member, sig)
257+
258+ if len(ret) == 0 {
259+ panic("no return value specified for NewMethodCall")
260+ }
261+
262+ var r0 *zerobus.Encoder
263+ var r1 uint32
264+ if returnFunc, ok := ret.Get(0).(func(string, string, string, string, string) (*zerobus.Encoder, uint32)); ok {
265+ return returnFunc(dest, path, iface, member, sig)
266+ }
267+ if returnFunc, ok := ret.Get(0).(func(string, string, string, string, string) *zerobus.Encoder); ok {
268+ r0 = returnFunc(dest, path, iface, member, sig)
269+ } else {
270+ if ret.Get(0) != nil {
271+ r0 = ret.Get(0).(*zerobus.Encoder)
272+ }
273+ }
274+ if returnFunc, ok := ret.Get(1).(func(string, string, string, string, string) uint32); ok {
275+ r1 = returnFunc(dest, path, iface, member, sig)
276+ } else {
277+ r1 = ret.Get(1).(uint32)
278+ }
279+ return r0, r1
280+}
281+
282+// mockbus_NewMethodCall_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewMethodCall'
283+type mockbus_NewMethodCall_Call struct {
284+ *mock.Call
285+}
286+
287+// NewMethodCall is a helper method to define mock.On call
288+// - dest string
289+// - path string
290+// - iface string
291+// - member string
292+// - sig string
293+func (_e *mockbus_Expecter) NewMethodCall(dest any, path any, iface any, member any, sig any) *mockbus_NewMethodCall_Call {
294+ return &mockbus_NewMethodCall_Call{Call: _e.mock.On("NewMethodCall", dest, path, iface, member, sig)}
295+}
296+
297+func (_c *mockbus_NewMethodCall_Call) Run(run func(dest string, path string, iface string, member string, sig string)) *mockbus_NewMethodCall_Call {
298+ _c.Call.Run(func(args mock.Arguments) {
299+ var arg0 string
300+ if args[0] != nil {
301+ arg0 = args[0].(string)
302+ }
303+ var arg1 string
304+ if args[1] != nil {
305+ arg1 = args[1].(string)
306+ }
307+ var arg2 string
308+ if args[2] != nil {
309+ arg2 = args[2].(string)
310+ }
311+ var arg3 string
312+ if args[3] != nil {
313+ arg3 = args[3].(string)
314+ }
315+ var arg4 string
316+ if args[4] != nil {
317+ arg4 = args[4].(string)
318+ }
319+ run(
320+ arg0,
321+ arg1,
322+ arg2,
323+ arg3,
324+ arg4,
325+ )
326+ })
327+ return _c
328+}
329+
330+func (_c *mockbus_NewMethodCall_Call) Return(encoder *zerobus.Encoder, v uint32) *mockbus_NewMethodCall_Call {
331+ _c.Call.Return(encoder, v)
332+ return _c
333+}
334+
335+func (_c *mockbus_NewMethodCall_Call) RunAndReturn(run func(dest string, path string, iface string, member string, sig string) (*zerobus.Encoder, uint32)) *mockbus_NewMethodCall_Call {
336+ _c.Call.Return(run)
337+ return _c
338+}
339+
340+// NewReply provides a mock function for the type mockbus
341+func (_mock *mockbus) NewReply(m *zerobus.Message, sig string) *zerobus.Encoder {
342+ ret := _mock.Called(m, sig)
343+
344+ if len(ret) == 0 {
345+ panic("no return value specified for NewReply")
346+ }
347+
348+ var r0 *zerobus.Encoder
349+ if returnFunc, ok := ret.Get(0).(func(*zerobus.Message, string) *zerobus.Encoder); ok {
350+ r0 = returnFunc(m, sig)
351+ } else {
352+ if ret.Get(0) != nil {
353+ r0 = ret.Get(0).(*zerobus.Encoder)
354+ }
355+ }
356+ return r0
357+}
358+
359+// mockbus_NewReply_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewReply'
360+type mockbus_NewReply_Call struct {
361+ *mock.Call
362+}
363+
364+// NewReply is a helper method to define mock.On call
365+// - m *zerobus.Message
366+// - sig string
367+func (_e *mockbus_Expecter) NewReply(m any, sig any) *mockbus_NewReply_Call {
368+ return &mockbus_NewReply_Call{Call: _e.mock.On("NewReply", m, sig)}
369+}
370+
371+func (_c *mockbus_NewReply_Call) Run(run func(m *zerobus.Message, sig string)) *mockbus_NewReply_Call {
372+ _c.Call.Run(func(args mock.Arguments) {
373+ var arg0 *zerobus.Message
374+ if args[0] != nil {
375+ arg0 = args[0].(*zerobus.Message)
376+ }
377+ var arg1 string
378+ if args[1] != nil {
379+ arg1 = args[1].(string)
380+ }
381+ run(
382+ arg0,
383+ arg1,
384+ )
385+ })
386+ return _c
387+}
388+
389+func (_c *mockbus_NewReply_Call) Return(encoder *zerobus.Encoder) *mockbus_NewReply_Call {
390+ _c.Call.Return(encoder)
391+ return _c
392+}
393+
394+func (_c *mockbus_NewReply_Call) RunAndReturn(run func(m *zerobus.Message, sig string) *zerobus.Encoder) *mockbus_NewReply_Call {
395+ _c.Call.Return(run)
396+ return _c
397+}
398+
399+// NewSignal provides a mock function for the type mockbus
400+func (_mock *mockbus) NewSignal(path string, iface string, member string, sig string) *zerobus.Encoder {
401+ ret := _mock.Called(path, iface, member, sig)
402+
403+ if len(ret) == 0 {
404+ panic("no return value specified for NewSignal")
405+ }
406+
407+ var r0 *zerobus.Encoder
408+ if returnFunc, ok := ret.Get(0).(func(string, string, string, string) *zerobus.Encoder); ok {
409+ r0 = returnFunc(path, iface, member, sig)
410+ } else {
411+ if ret.Get(0) != nil {
412+ r0 = ret.Get(0).(*zerobus.Encoder)
413+ }
414+ }
415+ return r0
416+}
417+
418+// mockbus_NewSignal_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewSignal'
419+type mockbus_NewSignal_Call struct {
420+ *mock.Call
421+}
422+
423+// NewSignal is a helper method to define mock.On call
424+// - path string
425+// - iface string
426+// - member string
427+// - sig string
428+func (_e *mockbus_Expecter) NewSignal(path any, iface any, member any, sig any) *mockbus_NewSignal_Call {
429+ return &mockbus_NewSignal_Call{Call: _e.mock.On("NewSignal", path, iface, member, sig)}
430+}
431+
432+func (_c *mockbus_NewSignal_Call) Run(run func(path string, iface string, member string, sig string)) *mockbus_NewSignal_Call {
433+ _c.Call.Run(func(args mock.Arguments) {
434+ var arg0 string
435+ if args[0] != nil {
436+ arg0 = args[0].(string)
437+ }
438+ var arg1 string
439+ if args[1] != nil {
440+ arg1 = args[1].(string)
441+ }
442+ var arg2 string
443+ if args[2] != nil {
444+ arg2 = args[2].(string)
445+ }
446+ var arg3 string
447+ if args[3] != nil {
448+ arg3 = args[3].(string)
449+ }
450+ run(
451+ arg0,
452+ arg1,
453+ arg2,
454+ arg3,
455+ )
456+ })
457+ return _c
458+}
459+
460+func (_c *mockbus_NewSignal_Call) Return(encoder *zerobus.Encoder) *mockbus_NewSignal_Call {
461+ _c.Call.Return(encoder)
462+ return _c
463+}
464+
465+func (_c *mockbus_NewSignal_Call) RunAndReturn(run func(path string, iface string, member string, sig string) *zerobus.Encoder) *mockbus_NewSignal_Call {
466+ _c.Call.Return(run)
467+ return _c
468+}
469+
470+// NewSignalTo provides a mock function for the type mockbus
471+func (_mock *mockbus) NewSignalTo(dest string, path string, iface string, member string, sig string) *zerobus.Encoder {
472+ ret := _mock.Called(dest, path, iface, member, sig)
473+
474+ if len(ret) == 0 {
475+ panic("no return value specified for NewSignalTo")
476+ }
477+
478+ var r0 *zerobus.Encoder
479+ if returnFunc, ok := ret.Get(0).(func(string, string, string, string, string) *zerobus.Encoder); ok {
480+ r0 = returnFunc(dest, path, iface, member, sig)
481+ } else {
482+ if ret.Get(0) != nil {
483+ r0 = ret.Get(0).(*zerobus.Encoder)
484+ }
485+ }
486+ return r0
487+}
488+
489+// mockbus_NewSignalTo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewSignalTo'
490+type mockbus_NewSignalTo_Call struct {
491+ *mock.Call
492+}
493+
494+// NewSignalTo is a helper method to define mock.On call
495+// - dest string
496+// - path string
497+// - iface string
498+// - member string
499+// - sig string
500+func (_e *mockbus_Expecter) NewSignalTo(dest any, path any, iface any, member any, sig any) *mockbus_NewSignalTo_Call {
501+ return &mockbus_NewSignalTo_Call{Call: _e.mock.On("NewSignalTo", dest, path, iface, member, sig)}
502+}
503+
504+func (_c *mockbus_NewSignalTo_Call) Run(run func(dest string, path string, iface string, member string, sig string)) *mockbus_NewSignalTo_Call {
505+ _c.Call.Run(func(args mock.Arguments) {
506+ var arg0 string
507+ if args[0] != nil {
508+ arg0 = args[0].(string)
509+ }
510+ var arg1 string
511+ if args[1] != nil {
512+ arg1 = args[1].(string)
513+ }
514+ var arg2 string
515+ if args[2] != nil {
516+ arg2 = args[2].(string)
517+ }
518+ var arg3 string
519+ if args[3] != nil {
520+ arg3 = args[3].(string)
521+ }
522+ var arg4 string
523+ if args[4] != nil {
524+ arg4 = args[4].(string)
525+ }
526+ run(
527+ arg0,
528+ arg1,
529+ arg2,
530+ arg3,
531+ arg4,
532+ )
533+ })
534+ return _c
535+}
536+
537+func (_c *mockbus_NewSignalTo_Call) Return(encoder *zerobus.Encoder) *mockbus_NewSignalTo_Call {
538+ _c.Call.Return(encoder)
539+ return _c
540+}
541+
542+func (_c *mockbus_NewSignalTo_Call) RunAndReturn(run func(dest string, path string, iface string, member string, sig string) *zerobus.Encoder) *mockbus_NewSignalTo_Call {
543+ _c.Call.Return(run)
544+ return _c
545+}
546+
547+// ReadMessage provides a mock function for the type mockbus
548+func (_mock *mockbus) ReadMessage() (*zerobus.Message, error) {
549+ ret := _mock.Called()
550+
551+ if len(ret) == 0 {
552+ panic("no return value specified for ReadMessage")
553+ }
554+
555+ var r0 *zerobus.Message
556+ var r1 error
557+ if returnFunc, ok := ret.Get(0).(func() (*zerobus.Message, error)); ok {
558+ return returnFunc()
559+ }
560+ if returnFunc, ok := ret.Get(0).(func() *zerobus.Message); ok {
561+ r0 = returnFunc()
562+ } else {
563+ if ret.Get(0) != nil {
564+ r0 = ret.Get(0).(*zerobus.Message)
565+ }
566+ }
567+ if returnFunc, ok := ret.Get(1).(func() error); ok {
568+ r1 = returnFunc()
569+ } else {
570+ r1 = ret.Error(1)
571+ }
572+ return r0, r1
573+}
574+
575+// mockbus_ReadMessage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReadMessage'
576+type mockbus_ReadMessage_Call struct {
577+ *mock.Call
578+}
579+
580+// ReadMessage is a helper method to define mock.On call
581+func (_e *mockbus_Expecter) ReadMessage() *mockbus_ReadMessage_Call {
582+ return &mockbus_ReadMessage_Call{Call: _e.mock.On("ReadMessage")}
583+}
584+
585+func (_c *mockbus_ReadMessage_Call) Run(run func()) *mockbus_ReadMessage_Call {
586+ _c.Call.Run(func(args mock.Arguments) {
587+ run()
588+ })
589+ return _c
590+}
591+
592+func (_c *mockbus_ReadMessage_Call) Return(message *zerobus.Message, err error) *mockbus_ReadMessage_Call {
593+ _c.Call.Return(message, err)
594+ return _c
595+}
596+
597+func (_c *mockbus_ReadMessage_Call) RunAndReturn(run func() (*zerobus.Message, error)) *mockbus_ReadMessage_Call {
598+ _c.Call.Return(run)
599+ return _c
600+}
601+
602+// RequestName provides a mock function for the type mockbus
603+func (_mock *mockbus) RequestName(name string, flags uint32) (uint32, error) {
604+ ret := _mock.Called(name, flags)
605+
606+ if len(ret) == 0 {
607+ panic("no return value specified for RequestName")
608+ }
609+
610+ var r0 uint32
611+ var r1 error
612+ if returnFunc, ok := ret.Get(0).(func(string, uint32) (uint32, error)); ok {
613+ return returnFunc(name, flags)
614+ }
615+ if returnFunc, ok := ret.Get(0).(func(string, uint32) uint32); ok {
616+ r0 = returnFunc(name, flags)
617+ } else {
618+ r0 = ret.Get(0).(uint32)
619+ }
620+ if returnFunc, ok := ret.Get(1).(func(string, uint32) error); ok {
621+ r1 = returnFunc(name, flags)
622+ } else {
623+ r1 = ret.Error(1)
624+ }
625+ return r0, r1
626+}
627+
628+// mockbus_RequestName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RequestName'
629+type mockbus_RequestName_Call struct {
630+ *mock.Call
631+}
632+
633+// RequestName is a helper method to define mock.On call
634+// - name string
635+// - flags uint32
636+func (_e *mockbus_Expecter) RequestName(name any, flags any) *mockbus_RequestName_Call {
637+ return &mockbus_RequestName_Call{Call: _e.mock.On("RequestName", name, flags)}
638+}
639+
640+func (_c *mockbus_RequestName_Call) Run(run func(name string, flags uint32)) *mockbus_RequestName_Call {
641+ _c.Call.Run(func(args mock.Arguments) {
642+ var arg0 string
643+ if args[0] != nil {
644+ arg0 = args[0].(string)
645+ }
646+ var arg1 uint32
647+ if args[1] != nil {
648+ arg1 = args[1].(uint32)
649+ }
650+ run(
651+ arg0,
652+ arg1,
653+ )
654+ })
655+ return _c
656+}
657+
658+func (_c *mockbus_RequestName_Call) Return(v uint32, err error) *mockbus_RequestName_Call {
659+ _c.Call.Return(v, err)
660+ return _c
661+}
662+
663+func (_c *mockbus_RequestName_Call) RunAndReturn(run func(name string, flags uint32) (uint32, error)) *mockbus_RequestName_Call {
664+ _c.Call.Return(run)
665+ return _c
666+}
667+
668+// Send provides a mock function for the type mockbus
669+func (_mock *mockbus) Send() (uint32, error) {
670+ ret := _mock.Called()
671+
672+ if len(ret) == 0 {
673+ panic("no return value specified for Send")
674+ }
675+
676+ var r0 uint32
677+ var r1 error
678+ if returnFunc, ok := ret.Get(0).(func() (uint32, error)); ok {
679+ return returnFunc()
680+ }
681+ if returnFunc, ok := ret.Get(0).(func() uint32); ok {
682+ r0 = returnFunc()
683+ } else {
684+ r0 = ret.Get(0).(uint32)
685+ }
686+ if returnFunc, ok := ret.Get(1).(func() error); ok {
687+ r1 = returnFunc()
688+ } else {
689+ r1 = ret.Error(1)
690+ }
691+ return r0, r1
692+}
693+
694+// mockbus_Send_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Send'
695+type mockbus_Send_Call struct {
696+ *mock.Call
697+}
698+
699+// Send is a helper method to define mock.On call
700+func (_e *mockbus_Expecter) Send() *mockbus_Send_Call {
701+ return &mockbus_Send_Call{Call: _e.mock.On("Send")}
702+}
703+
704+func (_c *mockbus_Send_Call) Run(run func()) *mockbus_Send_Call {
705+ _c.Call.Run(func(args mock.Arguments) {
706+ run()
707+ })
708+ return _c
709+}
710+
711+func (_c *mockbus_Send_Call) Return(v uint32, err error) *mockbus_Send_Call {
712+ _c.Call.Return(v, err)
713+ return _c
714+}
715+
716+func (_c *mockbus_Send_Call) RunAndReturn(run func() (uint32, error)) *mockbus_Send_Call {
717+ _c.Call.Return(run)
718+ return _c
719+}
720+
721+// SyscallConn provides a mock function for the type mockbus
722+func (_mock *mockbus) SyscallConn() (syscall.RawConn, error) {
723+ ret := _mock.Called()
724+
725+ if len(ret) == 0 {
726+ panic("no return value specified for SyscallConn")
727+ }
728+
729+ var r0 syscall.RawConn
730+ var r1 error
731+ if returnFunc, ok := ret.Get(0).(func() (syscall.RawConn, error)); ok {
732+ return returnFunc()
733+ }
734+ if returnFunc, ok := ret.Get(0).(func() syscall.RawConn); ok {
735+ r0 = returnFunc()
736+ } else {
737+ if ret.Get(0) != nil {
738+ r0 = ret.Get(0).(syscall.RawConn)
739+ }
740+ }
741+ if returnFunc, ok := ret.Get(1).(func() error); ok {
742+ r1 = returnFunc()
743+ } else {
744+ r1 = ret.Error(1)
745+ }
746+ return r0, r1
747+}
748+
749+// mockbus_SyscallConn_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SyscallConn'
750+type mockbus_SyscallConn_Call struct {
751+ *mock.Call
752+}
753+
754+// SyscallConn is a helper method to define mock.On call
755+func (_e *mockbus_Expecter) SyscallConn() *mockbus_SyscallConn_Call {
756+ return &mockbus_SyscallConn_Call{Call: _e.mock.On("SyscallConn")}
757+}
758+
759+func (_c *mockbus_SyscallConn_Call) Run(run func()) *mockbus_SyscallConn_Call {
760+ _c.Call.Run(func(args mock.Arguments) {
761+ run()
762+ })
763+ return _c
764+}
765+
766+func (_c *mockbus_SyscallConn_Call) Return(rawConn syscall.RawConn, err error) *mockbus_SyscallConn_Call {
767+ _c.Call.Return(rawConn, err)
768+ return _c
769+}
770+
771+func (_c *mockbus_SyscallConn_Call) RunAndReturn(run func() (syscall.RawConn, error)) *mockbus_SyscallConn_Call {
772+ _c.Call.Return(run)
773+ return _c
774+}
@@ -0,0 +1,774 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package screencast
6+
7+import (
8+ "syscall"
9+
10+ "github.com/bnema/zerobus"
11+ mock "github.com/stretchr/testify/mock"
12+)
13+
14+// newMockbus creates a new instance of mockbus. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
15+// The first argument is typically a *testing.T value.
16+func newMockbus(t interface {
17+ mock.TestingT
18+ Cleanup(func())
19+}) *mockbus {
20+ if helper, ok := t.(interface{ Helper() }); ok {
21+ helper.Helper()
22+ }
23+
24+ mock := &mockbus{}
25+ mock.Mock.Test(t)
26+
27+ t.Cleanup(func() {
28+ if helper, ok := t.(interface{ Helper() }); ok {
29+ helper.Helper()
30+ }
31+ mock.AssertExpectations(t)
32+ })
33+
34+ return mock
35+}
36+
37+// mockbus is an autogenerated mock type for the bus type
38+type mockbus struct {
39+ mock.Mock
40+}
41+
42+type mockbus_Expecter struct {
43+ mock *mock.Mock
44+}
45+
46+func (_m *mockbus) EXPECT() *mockbus_Expecter {
47+ return &mockbus_Expecter{mock: &_m.Mock}
48+}
49+
50+// AddMatch provides a mock function for the type mockbus
51+func (_mock *mockbus) AddMatch(rule string) error {
52+ ret := _mock.Called(rule)
53+
54+ if len(ret) == 0 {
55+ panic("no return value specified for AddMatch")
56+ }
57+
58+ var r0 error
59+ if returnFunc, ok := ret.Get(0).(func(string) error); ok {
60+ r0 = returnFunc(rule)
61+ } else {
62+ r0 = ret.Error(0)
63+ }
64+ return r0
65+}
66+
67+// mockbus_AddMatch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddMatch'
68+type mockbus_AddMatch_Call struct {
69+ *mock.Call
70+}
71+
72+// AddMatch is a helper method to define mock.On call
73+// - rule string
74+func (_e *mockbus_Expecter) AddMatch(rule any) *mockbus_AddMatch_Call {
75+ return &mockbus_AddMatch_Call{Call: _e.mock.On("AddMatch", rule)}
76+}
77+
78+func (_c *mockbus_AddMatch_Call) Run(run func(rule string)) *mockbus_AddMatch_Call {
79+ _c.Call.Run(func(args mock.Arguments) {
80+ var arg0 string
81+ if args[0] != nil {
82+ arg0 = args[0].(string)
83+ }
84+ run(
85+ arg0,
86+ )
87+ })
88+ return _c
89+}
90+
91+func (_c *mockbus_AddMatch_Call) Return(err error) *mockbus_AddMatch_Call {
92+ _c.Call.Return(err)
93+ return _c
94+}
95+
96+func (_c *mockbus_AddMatch_Call) RunAndReturn(run func(rule string) error) *mockbus_AddMatch_Call {
97+ _c.Call.Return(run)
98+ return _c
99+}
100+
101+// Buffered provides a mock function for the type mockbus
102+func (_mock *mockbus) Buffered() bool {
103+ ret := _mock.Called()
104+
105+ if len(ret) == 0 {
106+ panic("no return value specified for Buffered")
107+ }
108+
109+ var r0 bool
110+ if returnFunc, ok := ret.Get(0).(func() bool); ok {
111+ r0 = returnFunc()
112+ } else {
113+ r0 = ret.Get(0).(bool)
114+ }
115+ return r0
116+}
117+
118+// mockbus_Buffered_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Buffered'
119+type mockbus_Buffered_Call struct {
120+ *mock.Call
121+}
122+
123+// Buffered is a helper method to define mock.On call
124+func (_e *mockbus_Expecter) Buffered() *mockbus_Buffered_Call {
125+ return &mockbus_Buffered_Call{Call: _e.mock.On("Buffered")}
126+}
127+
128+func (_c *mockbus_Buffered_Call) Run(run func()) *mockbus_Buffered_Call {
129+ _c.Call.Run(func(args mock.Arguments) {
130+ run()
131+ })
132+ return _c
133+}
134+
135+func (_c *mockbus_Buffered_Call) Return(b bool) *mockbus_Buffered_Call {
136+ _c.Call.Return(b)
137+ return _c
138+}
139+
140+func (_c *mockbus_Buffered_Call) RunAndReturn(run func() bool) *mockbus_Buffered_Call {
141+ _c.Call.Return(run)
142+ return _c
143+}
144+
145+// Close provides a mock function for the type mockbus
146+func (_mock *mockbus) Close() error {
147+ ret := _mock.Called()
148+
149+ if len(ret) == 0 {
150+ panic("no return value specified for Close")
151+ }
152+
153+ var r0 error
154+ if returnFunc, ok := ret.Get(0).(func() error); ok {
155+ r0 = returnFunc()
156+ } else {
157+ r0 = ret.Error(0)
158+ }
159+ return r0
160+}
161+
162+// mockbus_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
163+type mockbus_Close_Call struct {
164+ *mock.Call
165+}
166+
167+// Close is a helper method to define mock.On call
168+func (_e *mockbus_Expecter) Close() *mockbus_Close_Call {
169+ return &mockbus_Close_Call{Call: _e.mock.On("Close")}
170+}
171+
172+func (_c *mockbus_Close_Call) Run(run func()) *mockbus_Close_Call {
173+ _c.Call.Run(func(args mock.Arguments) {
174+ run()
175+ })
176+ return _c
177+}
178+
179+func (_c *mockbus_Close_Call) Return(err error) *mockbus_Close_Call {
180+ _c.Call.Return(err)
181+ return _c
182+}
183+
184+func (_c *mockbus_Close_Call) RunAndReturn(run func() error) *mockbus_Close_Call {
185+ _c.Call.Return(run)
186+ return _c
187+}
188+
189+// NewError provides a mock function for the type mockbus
190+func (_mock *mockbus) NewError(m *zerobus.Message, name string, sig string) *zerobus.Encoder {
191+ ret := _mock.Called(m, name, sig)
192+
193+ if len(ret) == 0 {
194+ panic("no return value specified for NewError")
195+ }
196+
197+ var r0 *zerobus.Encoder
198+ if returnFunc, ok := ret.Get(0).(func(*zerobus.Message, string, string) *zerobus.Encoder); ok {
199+ r0 = returnFunc(m, name, sig)
200+ } else {
201+ if ret.Get(0) != nil {
202+ r0 = ret.Get(0).(*zerobus.Encoder)
203+ }
204+ }
205+ return r0
206+}
207+
208+// mockbus_NewError_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewError'
209+type mockbus_NewError_Call struct {
210+ *mock.Call
211+}
212+
213+// NewError is a helper method to define mock.On call
214+// - m *zerobus.Message
215+// - name string
216+// - sig string
217+func (_e *mockbus_Expecter) NewError(m any, name any, sig any) *mockbus_NewError_Call {
218+ return &mockbus_NewError_Call{Call: _e.mock.On("NewError", m, name, sig)}
219+}
220+
221+func (_c *mockbus_NewError_Call) Run(run func(m *zerobus.Message, name string, sig string)) *mockbus_NewError_Call {
222+ _c.Call.Run(func(args mock.Arguments) {
223+ var arg0 *zerobus.Message
224+ if args[0] != nil {
225+ arg0 = args[0].(*zerobus.Message)
226+ }
227+ var arg1 string
228+ if args[1] != nil {
229+ arg1 = args[1].(string)
230+ }
231+ var arg2 string
232+ if args[2] != nil {
233+ arg2 = args[2].(string)
234+ }
235+ run(
236+ arg0,
237+ arg1,
238+ arg2,
239+ )
240+ })
241+ return _c
242+}
243+
244+func (_c *mockbus_NewError_Call) Return(encoder *zerobus.Encoder) *mockbus_NewError_Call {
245+ _c.Call.Return(encoder)
246+ return _c
247+}
248+
249+func (_c *mockbus_NewError_Call) RunAndReturn(run func(m *zerobus.Message, name string, sig string) *zerobus.Encoder) *mockbus_NewError_Call {
250+ _c.Call.Return(run)
251+ return _c
252+}
253+
254+// NewMethodCall provides a mock function for the type mockbus
255+func (_mock *mockbus) NewMethodCall(dest string, path string, iface string, member string, sig string) (*zerobus.Encoder, uint32) {
256+ ret := _mock.Called(dest, path, iface, member, sig)
257+
258+ if len(ret) == 0 {
259+ panic("no return value specified for NewMethodCall")
260+ }
261+
262+ var r0 *zerobus.Encoder
263+ var r1 uint32
264+ if returnFunc, ok := ret.Get(0).(func(string, string, string, string, string) (*zerobus.Encoder, uint32)); ok {
265+ return returnFunc(dest, path, iface, member, sig)
266+ }
267+ if returnFunc, ok := ret.Get(0).(func(string, string, string, string, string) *zerobus.Encoder); ok {
268+ r0 = returnFunc(dest, path, iface, member, sig)
269+ } else {
270+ if ret.Get(0) != nil {
271+ r0 = ret.Get(0).(*zerobus.Encoder)
272+ }
273+ }
274+ if returnFunc, ok := ret.Get(1).(func(string, string, string, string, string) uint32); ok {
275+ r1 = returnFunc(dest, path, iface, member, sig)
276+ } else {
277+ r1 = ret.Get(1).(uint32)
278+ }
279+ return r0, r1
280+}
281+
282+// mockbus_NewMethodCall_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewMethodCall'
283+type mockbus_NewMethodCall_Call struct {
284+ *mock.Call
285+}
286+
287+// NewMethodCall is a helper method to define mock.On call
288+// - dest string
289+// - path string
290+// - iface string
291+// - member string
292+// - sig string
293+func (_e *mockbus_Expecter) NewMethodCall(dest any, path any, iface any, member any, sig any) *mockbus_NewMethodCall_Call {
294+ return &mockbus_NewMethodCall_Call{Call: _e.mock.On("NewMethodCall", dest, path, iface, member, sig)}
295+}
296+
297+func (_c *mockbus_NewMethodCall_Call) Run(run func(dest string, path string, iface string, member string, sig string)) *mockbus_NewMethodCall_Call {
298+ _c.Call.Run(func(args mock.Arguments) {
299+ var arg0 string
300+ if args[0] != nil {
301+ arg0 = args[0].(string)
302+ }
303+ var arg1 string
304+ if args[1] != nil {
305+ arg1 = args[1].(string)
306+ }
307+ var arg2 string
308+ if args[2] != nil {
309+ arg2 = args[2].(string)
310+ }
311+ var arg3 string
312+ if args[3] != nil {
313+ arg3 = args[3].(string)
314+ }
315+ var arg4 string
316+ if args[4] != nil {
317+ arg4 = args[4].(string)
318+ }
319+ run(
320+ arg0,
321+ arg1,
322+ arg2,
323+ arg3,
324+ arg4,
325+ )
326+ })
327+ return _c
328+}
329+
330+func (_c *mockbus_NewMethodCall_Call) Return(encoder *zerobus.Encoder, v uint32) *mockbus_NewMethodCall_Call {
331+ _c.Call.Return(encoder, v)
332+ return _c
333+}
334+
335+func (_c *mockbus_NewMethodCall_Call) RunAndReturn(run func(dest string, path string, iface string, member string, sig string) (*zerobus.Encoder, uint32)) *mockbus_NewMethodCall_Call {
336+ _c.Call.Return(run)
337+ return _c
338+}
339+
340+// NewReply provides a mock function for the type mockbus
341+func (_mock *mockbus) NewReply(m *zerobus.Message, sig string) *zerobus.Encoder {
342+ ret := _mock.Called(m, sig)
343+
344+ if len(ret) == 0 {
345+ panic("no return value specified for NewReply")
346+ }
347+
348+ var r0 *zerobus.Encoder
349+ if returnFunc, ok := ret.Get(0).(func(*zerobus.Message, string) *zerobus.Encoder); ok {
350+ r0 = returnFunc(m, sig)
351+ } else {
352+ if ret.Get(0) != nil {
353+ r0 = ret.Get(0).(*zerobus.Encoder)
354+ }
355+ }
356+ return r0
357+}
358+
359+// mockbus_NewReply_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewReply'
360+type mockbus_NewReply_Call struct {
361+ *mock.Call
362+}
363+
364+// NewReply is a helper method to define mock.On call
365+// - m *zerobus.Message
366+// - sig string
367+func (_e *mockbus_Expecter) NewReply(m any, sig any) *mockbus_NewReply_Call {
368+ return &mockbus_NewReply_Call{Call: _e.mock.On("NewReply", m, sig)}
369+}
370+
371+func (_c *mockbus_NewReply_Call) Run(run func(m *zerobus.Message, sig string)) *mockbus_NewReply_Call {
372+ _c.Call.Run(func(args mock.Arguments) {
373+ var arg0 *zerobus.Message
374+ if args[0] != nil {
375+ arg0 = args[0].(*zerobus.Message)
376+ }
377+ var arg1 string
378+ if args[1] != nil {
379+ arg1 = args[1].(string)
380+ }
381+ run(
382+ arg0,
383+ arg1,
384+ )
385+ })
386+ return _c
387+}
388+
389+func (_c *mockbus_NewReply_Call) Return(encoder *zerobus.Encoder) *mockbus_NewReply_Call {
390+ _c.Call.Return(encoder)
391+ return _c
392+}
393+
394+func (_c *mockbus_NewReply_Call) RunAndReturn(run func(m *zerobus.Message, sig string) *zerobus.Encoder) *mockbus_NewReply_Call {
395+ _c.Call.Return(run)
396+ return _c
397+}
398+
399+// NewSignal provides a mock function for the type mockbus
400+func (_mock *mockbus) NewSignal(path string, iface string, member string, sig string) *zerobus.Encoder {
401+ ret := _mock.Called(path, iface, member, sig)
402+
403+ if len(ret) == 0 {
404+ panic("no return value specified for NewSignal")
405+ }
406+
407+ var r0 *zerobus.Encoder
408+ if returnFunc, ok := ret.Get(0).(func(string, string, string, string) *zerobus.Encoder); ok {
409+ r0 = returnFunc(path, iface, member, sig)
410+ } else {
411+ if ret.Get(0) != nil {
412+ r0 = ret.Get(0).(*zerobus.Encoder)
413+ }
414+ }
415+ return r0
416+}
417+
418+// mockbus_NewSignal_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewSignal'
419+type mockbus_NewSignal_Call struct {
420+ *mock.Call
421+}
422+
423+// NewSignal is a helper method to define mock.On call
424+// - path string
425+// - iface string
426+// - member string
427+// - sig string
428+func (_e *mockbus_Expecter) NewSignal(path any, iface any, member any, sig any) *mockbus_NewSignal_Call {
429+ return &mockbus_NewSignal_Call{Call: _e.mock.On("NewSignal", path, iface, member, sig)}
430+}
431+
432+func (_c *mockbus_NewSignal_Call) Run(run func(path string, iface string, member string, sig string)) *mockbus_NewSignal_Call {
433+ _c.Call.Run(func(args mock.Arguments) {
434+ var arg0 string
435+ if args[0] != nil {
436+ arg0 = args[0].(string)
437+ }
438+ var arg1 string
439+ if args[1] != nil {
440+ arg1 = args[1].(string)
441+ }
442+ var arg2 string
443+ if args[2] != nil {
444+ arg2 = args[2].(string)
445+ }
446+ var arg3 string
447+ if args[3] != nil {
448+ arg3 = args[3].(string)
449+ }
450+ run(
451+ arg0,
452+ arg1,
453+ arg2,
454+ arg3,
455+ )
456+ })
457+ return _c
458+}
459+
460+func (_c *mockbus_NewSignal_Call) Return(encoder *zerobus.Encoder) *mockbus_NewSignal_Call {
461+ _c.Call.Return(encoder)
462+ return _c
463+}
464+
465+func (_c *mockbus_NewSignal_Call) RunAndReturn(run func(path string, iface string, member string, sig string) *zerobus.Encoder) *mockbus_NewSignal_Call {
466+ _c.Call.Return(run)
467+ return _c
468+}
469+
470+// NewSignalTo provides a mock function for the type mockbus
471+func (_mock *mockbus) NewSignalTo(dest string, path string, iface string, member string, sig string) *zerobus.Encoder {
472+ ret := _mock.Called(dest, path, iface, member, sig)
473+
474+ if len(ret) == 0 {
475+ panic("no return value specified for NewSignalTo")
476+ }
477+
478+ var r0 *zerobus.Encoder
479+ if returnFunc, ok := ret.Get(0).(func(string, string, string, string, string) *zerobus.Encoder); ok {
480+ r0 = returnFunc(dest, path, iface, member, sig)
481+ } else {
482+ if ret.Get(0) != nil {
483+ r0 = ret.Get(0).(*zerobus.Encoder)
484+ }
485+ }
486+ return r0
487+}
488+
489+// mockbus_NewSignalTo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewSignalTo'
490+type mockbus_NewSignalTo_Call struct {
491+ *mock.Call
492+}
493+
494+// NewSignalTo is a helper method to define mock.On call
495+// - dest string
496+// - path string
497+// - iface string
498+// - member string
499+// - sig string
500+func (_e *mockbus_Expecter) NewSignalTo(dest any, path any, iface any, member any, sig any) *mockbus_NewSignalTo_Call {
501+ return &mockbus_NewSignalTo_Call{Call: _e.mock.On("NewSignalTo", dest, path, iface, member, sig)}
502+}
503+
504+func (_c *mockbus_NewSignalTo_Call) Run(run func(dest string, path string, iface string, member string, sig string)) *mockbus_NewSignalTo_Call {
505+ _c.Call.Run(func(args mock.Arguments) {
506+ var arg0 string
507+ if args[0] != nil {
508+ arg0 = args[0].(string)
509+ }
510+ var arg1 string
511+ if args[1] != nil {
512+ arg1 = args[1].(string)
513+ }
514+ var arg2 string
515+ if args[2] != nil {
516+ arg2 = args[2].(string)
517+ }
518+ var arg3 string
519+ if args[3] != nil {
520+ arg3 = args[3].(string)
521+ }
522+ var arg4 string
523+ if args[4] != nil {
524+ arg4 = args[4].(string)
525+ }
526+ run(
527+ arg0,
528+ arg1,
529+ arg2,
530+ arg3,
531+ arg4,
532+ )
533+ })
534+ return _c
535+}
536+
537+func (_c *mockbus_NewSignalTo_Call) Return(encoder *zerobus.Encoder) *mockbus_NewSignalTo_Call {
538+ _c.Call.Return(encoder)
539+ return _c
540+}
541+
542+func (_c *mockbus_NewSignalTo_Call) RunAndReturn(run func(dest string, path string, iface string, member string, sig string) *zerobus.Encoder) *mockbus_NewSignalTo_Call {
543+ _c.Call.Return(run)
544+ return _c
545+}
546+
547+// ReadMessage provides a mock function for the type mockbus
548+func (_mock *mockbus) ReadMessage() (*zerobus.Message, error) {
549+ ret := _mock.Called()
550+
551+ if len(ret) == 0 {
552+ panic("no return value specified for ReadMessage")
553+ }
554+
555+ var r0 *zerobus.Message
556+ var r1 error
557+ if returnFunc, ok := ret.Get(0).(func() (*zerobus.Message, error)); ok {
558+ return returnFunc()
559+ }
560+ if returnFunc, ok := ret.Get(0).(func() *zerobus.Message); ok {
561+ r0 = returnFunc()
562+ } else {
563+ if ret.Get(0) != nil {
564+ r0 = ret.Get(0).(*zerobus.Message)
565+ }
566+ }
567+ if returnFunc, ok := ret.Get(1).(func() error); ok {
568+ r1 = returnFunc()
569+ } else {
570+ r1 = ret.Error(1)
571+ }
572+ return r0, r1
573+}
574+
575+// mockbus_ReadMessage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReadMessage'
576+type mockbus_ReadMessage_Call struct {
577+ *mock.Call
578+}
579+
580+// ReadMessage is a helper method to define mock.On call
581+func (_e *mockbus_Expecter) ReadMessage() *mockbus_ReadMessage_Call {
582+ return &mockbus_ReadMessage_Call{Call: _e.mock.On("ReadMessage")}
583+}
584+
585+func (_c *mockbus_ReadMessage_Call) Run(run func()) *mockbus_ReadMessage_Call {
586+ _c.Call.Run(func(args mock.Arguments) {
587+ run()
588+ })
589+ return _c
590+}
591+
592+func (_c *mockbus_ReadMessage_Call) Return(message *zerobus.Message, err error) *mockbus_ReadMessage_Call {
593+ _c.Call.Return(message, err)
594+ return _c
595+}
596+
597+func (_c *mockbus_ReadMessage_Call) RunAndReturn(run func() (*zerobus.Message, error)) *mockbus_ReadMessage_Call {
598+ _c.Call.Return(run)
599+ return _c
600+}
601+
602+// RequestName provides a mock function for the type mockbus
603+func (_mock *mockbus) RequestName(name string, flags uint32) (uint32, error) {
604+ ret := _mock.Called(name, flags)
605+
606+ if len(ret) == 0 {
607+ panic("no return value specified for RequestName")
608+ }
609+
610+ var r0 uint32
611+ var r1 error
612+ if returnFunc, ok := ret.Get(0).(func(string, uint32) (uint32, error)); ok {
613+ return returnFunc(name, flags)
614+ }
615+ if returnFunc, ok := ret.Get(0).(func(string, uint32) uint32); ok {
616+ r0 = returnFunc(name, flags)
617+ } else {
618+ r0 = ret.Get(0).(uint32)
619+ }
620+ if returnFunc, ok := ret.Get(1).(func(string, uint32) error); ok {
621+ r1 = returnFunc(name, flags)
622+ } else {
623+ r1 = ret.Error(1)
624+ }
625+ return r0, r1
626+}
627+
628+// mockbus_RequestName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RequestName'
629+type mockbus_RequestName_Call struct {
630+ *mock.Call
631+}
632+
633+// RequestName is a helper method to define mock.On call
634+// - name string
635+// - flags uint32
636+func (_e *mockbus_Expecter) RequestName(name any, flags any) *mockbus_RequestName_Call {
637+ return &mockbus_RequestName_Call{Call: _e.mock.On("RequestName", name, flags)}
638+}
639+
640+func (_c *mockbus_RequestName_Call) Run(run func(name string, flags uint32)) *mockbus_RequestName_Call {
641+ _c.Call.Run(func(args mock.Arguments) {
642+ var arg0 string
643+ if args[0] != nil {
644+ arg0 = args[0].(string)
645+ }
646+ var arg1 uint32
647+ if args[1] != nil {
648+ arg1 = args[1].(uint32)
649+ }
650+ run(
651+ arg0,
652+ arg1,
653+ )
654+ })
655+ return _c
656+}
657+
658+func (_c *mockbus_RequestName_Call) Return(v uint32, err error) *mockbus_RequestName_Call {
659+ _c.Call.Return(v, err)
660+ return _c
661+}
662+
663+func (_c *mockbus_RequestName_Call) RunAndReturn(run func(name string, flags uint32) (uint32, error)) *mockbus_RequestName_Call {
664+ _c.Call.Return(run)
665+ return _c
666+}
667+
668+// Send provides a mock function for the type mockbus
669+func (_mock *mockbus) Send() (uint32, error) {
670+ ret := _mock.Called()
671+
672+ if len(ret) == 0 {
673+ panic("no return value specified for Send")
674+ }
675+
676+ var r0 uint32
677+ var r1 error
678+ if returnFunc, ok := ret.Get(0).(func() (uint32, error)); ok {
679+ return returnFunc()
680+ }
681+ if returnFunc, ok := ret.Get(0).(func() uint32); ok {
682+ r0 = returnFunc()
683+ } else {
684+ r0 = ret.Get(0).(uint32)
685+ }
686+ if returnFunc, ok := ret.Get(1).(func() error); ok {
687+ r1 = returnFunc()
688+ } else {
689+ r1 = ret.Error(1)
690+ }
691+ return r0, r1
692+}
693+
694+// mockbus_Send_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Send'
695+type mockbus_Send_Call struct {
696+ *mock.Call
697+}
698+
699+// Send is a helper method to define mock.On call
700+func (_e *mockbus_Expecter) Send() *mockbus_Send_Call {
701+ return &mockbus_Send_Call{Call: _e.mock.On("Send")}
702+}
703+
704+func (_c *mockbus_Send_Call) Run(run func()) *mockbus_Send_Call {
705+ _c.Call.Run(func(args mock.Arguments) {
706+ run()
707+ })
708+ return _c
709+}
710+
711+func (_c *mockbus_Send_Call) Return(v uint32, err error) *mockbus_Send_Call {
712+ _c.Call.Return(v, err)
713+ return _c
714+}
715+
716+func (_c *mockbus_Send_Call) RunAndReturn(run func() (uint32, error)) *mockbus_Send_Call {
717+ _c.Call.Return(run)
718+ return _c
719+}
720+
721+// SyscallConn provides a mock function for the type mockbus
722+func (_mock *mockbus) SyscallConn() (syscall.RawConn, error) {
723+ ret := _mock.Called()
724+
725+ if len(ret) == 0 {
726+ panic("no return value specified for SyscallConn")
727+ }
728+
729+ var r0 syscall.RawConn
730+ var r1 error
731+ if returnFunc, ok := ret.Get(0).(func() (syscall.RawConn, error)); ok {
732+ return returnFunc()
733+ }
734+ if returnFunc, ok := ret.Get(0).(func() syscall.RawConn); ok {
735+ r0 = returnFunc()
736+ } else {
737+ if ret.Get(0) != nil {
738+ r0 = ret.Get(0).(syscall.RawConn)
739+ }
740+ }
741+ if returnFunc, ok := ret.Get(1).(func() error); ok {
742+ r1 = returnFunc()
743+ } else {
744+ r1 = ret.Error(1)
745+ }
746+ return r0, r1
747+}
748+
749+// mockbus_SyscallConn_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SyscallConn'
750+type mockbus_SyscallConn_Call struct {
751+ *mock.Call
752+}
753+
754+// SyscallConn is a helper method to define mock.On call
755+func (_e *mockbus_Expecter) SyscallConn() *mockbus_SyscallConn_Call {
756+ return &mockbus_SyscallConn_Call{Call: _e.mock.On("SyscallConn")}
757+}
758+
759+func (_c *mockbus_SyscallConn_Call) Run(run func()) *mockbus_SyscallConn_Call {
760+ _c.Call.Run(func(args mock.Arguments) {
761+ run()
762+ })
763+ return _c
764+}
765+
766+func (_c *mockbus_SyscallConn_Call) Return(rawConn syscall.RawConn, err error) *mockbus_SyscallConn_Call {
767+ _c.Call.Return(rawConn, err)
768+ return _c
769+}
770+
771+func (_c *mockbus_SyscallConn_Call) RunAndReturn(run func() (syscall.RawConn, error)) *mockbus_SyscallConn_Call {
772+ _c.Call.Return(run)
773+ return _c
774+}
A internal/adapters/screencast/caller.go +42 -0
@@ -0,0 +1,42 @@
1+package screencast
2+
3+import "os"
4+
5+// callerState is how far the proof of a D-Bus peer's executable got.
6+type callerState uint8
7+
8+const (
9+ callerFree callerState = iota
10+ // callerPid: waiting for the bus to name the peer's pid.
11+ callerPid
12+ // callerConfirm: a pidfd was opened; waiting for the bus to name the same
13+ // pid again, which proves the pidfd names the peer.
14+ callerConfirm
15+ // callerKnown: exe is the executable of the peer.
16+ callerKnown
17+)
18+
19+// caller is one checked unique bus name. The pidfd stays open for as long
20+// as the name is cached, so the executable can be read again at the
21+// privileged entry points.
22+type caller struct {
23+ state callerState
24+ name string // unique name, ":1.42"
25+ serial uint32 // the outstanding GetConnectionUnixProcessID request
26+ pid int
27+ pidfd *os.File
28+ exe string
29+}
30+
31+func (c *caller) release() {
32+ if c.pidfd != nil {
33+ _ = c.pidfd.Close()
34+ }
35+ *c = caller{}
36+}
37+
38+// pending is a request parked until its sender's check ends.
39+type pending struct {
40+ used bool
41+ req request
42+}
@@ -0,0 +1,42 @@
1+package screencast
2+
3+import "os"
4+
5+// callerState is how far the proof of a D-Bus peer's executable got.
6+type callerState uint8
7+
8+const (
9+ callerFree callerState = iota
10+ // callerPid: waiting for the bus to name the peer's pid.
11+ callerPid
12+ // callerConfirm: a pidfd was opened; waiting for the bus to name the same
13+ // pid again, which proves the pidfd names the peer.
14+ callerConfirm
15+ // callerKnown: exe is the executable of the peer.
16+ callerKnown
17+)
18+
19+// caller is one checked unique bus name. The pidfd stays open for as long
20+// as the name is cached, so the executable can be read again at the
21+// privileged entry points.
22+type caller struct {
23+ state callerState
24+ name string // unique name, ":1.42"
25+ serial uint32 // the outstanding GetConnectionUnixProcessID request
26+ pid int
27+ pidfd *os.File
28+ exe string
29+}
30+
31+func (c *caller) release() {
32+ if c.pidfd != nil {
33+ _ = c.pidfd.Close()
34+ }
35+ *c = caller{}
36+}
37+
38+// pending is a request parked until its sender's check ends.
39+type pending struct {
40+ used bool
41+ req request
42+}
A internal/adapters/screencast/dialer_mock_test.go +107 -0
@@ -0,0 +1,107 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package screencast
6+
7+import (
8+ mock "github.com/stretchr/testify/mock"
9+)
10+
11+// newMockdialer creates a new instance of mockdialer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
12+// The first argument is typically a *testing.T value.
13+func newMockdialer(t interface {
14+ mock.TestingT
15+ Cleanup(func())
16+}) *mockdialer {
17+ if helper, ok := t.(interface{ Helper() }); ok {
18+ helper.Helper()
19+ }
20+
21+ mock := &mockdialer{}
22+ mock.Mock.Test(t)
23+
24+ t.Cleanup(func() {
25+ if helper, ok := t.(interface{ Helper() }); ok {
26+ helper.Helper()
27+ }
28+ mock.AssertExpectations(t)
29+ })
30+
31+ return mock
32+}
33+
34+// mockdialer is an autogenerated mock type for the dialer type
35+type mockdialer struct {
36+ mock.Mock
37+}
38+
39+type mockdialer_Expecter struct {
40+ mock *mock.Mock
41+}
42+
43+func (_m *mockdialer) EXPECT() *mockdialer_Expecter {
44+ return &mockdialer_Expecter{mock: &_m.Mock}
45+}
46+
47+// Dial provides a mock function for the type mockdialer
48+func (_mock *mockdialer) Dial(address string) (bus, error) {
49+ ret := _mock.Called(address)
50+
51+ if len(ret) == 0 {
52+ panic("no return value specified for Dial")
53+ }
54+
55+ var r0 bus
56+ var r1 error
57+ if returnFunc, ok := ret.Get(0).(func(string) (bus, error)); ok {
58+ return returnFunc(address)
59+ }
60+ if returnFunc, ok := ret.Get(0).(func(string) bus); ok {
61+ r0 = returnFunc(address)
62+ } else {
63+ if ret.Get(0) != nil {
64+ r0 = ret.Get(0).(bus)
65+ }
66+ }
67+ if returnFunc, ok := ret.Get(1).(func(string) error); ok {
68+ r1 = returnFunc(address)
69+ } else {
70+ r1 = ret.Error(1)
71+ }
72+ return r0, r1
73+}
74+
75+// mockdialer_Dial_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Dial'
76+type mockdialer_Dial_Call struct {
77+ *mock.Call
78+}
79+
80+// Dial is a helper method to define mock.On call
81+// - address string
82+func (_e *mockdialer_Expecter) Dial(address any) *mockdialer_Dial_Call {
83+ return &mockdialer_Dial_Call{Call: _e.mock.On("Dial", address)}
84+}
85+
86+func (_c *mockdialer_Dial_Call) Run(run func(address string)) *mockdialer_Dial_Call {
87+ _c.Call.Run(func(args mock.Arguments) {
88+ var arg0 string
89+ if args[0] != nil {
90+ arg0 = args[0].(string)
91+ }
92+ run(
93+ arg0,
94+ )
95+ })
96+ return _c
97+}
98+
99+func (_c *mockdialer_Dial_Call) Return(busMoqParam bus, err error) *mockdialer_Dial_Call {
100+ _c.Call.Return(busMoqParam, err)
101+ return _c
102+}
103+
104+func (_c *mockdialer_Dial_Call) RunAndReturn(run func(address string) (bus, error)) *mockdialer_Dial_Call {
105+ _c.Call.Return(run)
106+ return _c
107+}
@@ -0,0 +1,107 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package screencast
6+
7+import (
8+ mock "github.com/stretchr/testify/mock"
9+)
10+
11+// newMockdialer creates a new instance of mockdialer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
12+// The first argument is typically a *testing.T value.
13+func newMockdialer(t interface {
14+ mock.TestingT
15+ Cleanup(func())
16+}) *mockdialer {
17+ if helper, ok := t.(interface{ Helper() }); ok {
18+ helper.Helper()
19+ }
20+
21+ mock := &mockdialer{}
22+ mock.Mock.Test(t)
23+
24+ t.Cleanup(func() {
25+ if helper, ok := t.(interface{ Helper() }); ok {
26+ helper.Helper()
27+ }
28+ mock.AssertExpectations(t)
29+ })
30+
31+ return mock
32+}
33+
34+// mockdialer is an autogenerated mock type for the dialer type
35+type mockdialer struct {
36+ mock.Mock
37+}
38+
39+type mockdialer_Expecter struct {
40+ mock *mock.Mock
41+}
42+
43+func (_m *mockdialer) EXPECT() *mockdialer_Expecter {
44+ return &mockdialer_Expecter{mock: &_m.Mock}
45+}
46+
47+// Dial provides a mock function for the type mockdialer
48+func (_mock *mockdialer) Dial(address string) (bus, error) {
49+ ret := _mock.Called(address)
50+
51+ if len(ret) == 0 {
52+ panic("no return value specified for Dial")
53+ }
54+
55+ var r0 bus
56+ var r1 error
57+ if returnFunc, ok := ret.Get(0).(func(string) (bus, error)); ok {
58+ return returnFunc(address)
59+ }
60+ if returnFunc, ok := ret.Get(0).(func(string) bus); ok {
61+ r0 = returnFunc(address)
62+ } else {
63+ if ret.Get(0) != nil {
64+ r0 = ret.Get(0).(bus)
65+ }
66+ }
67+ if returnFunc, ok := ret.Get(1).(func(string) error); ok {
68+ r1 = returnFunc(address)
69+ } else {
70+ r1 = ret.Error(1)
71+ }
72+ return r0, r1
73+}
74+
75+// mockdialer_Dial_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Dial'
76+type mockdialer_Dial_Call struct {
77+ *mock.Call
78+}
79+
80+// Dial is a helper method to define mock.On call
81+// - address string
82+func (_e *mockdialer_Expecter) Dial(address any) *mockdialer_Dial_Call {
83+ return &mockdialer_Dial_Call{Call: _e.mock.On("Dial", address)}
84+}
85+
86+func (_c *mockdialer_Dial_Call) Run(run func(address string)) *mockdialer_Dial_Call {
87+ _c.Call.Run(func(args mock.Arguments) {
88+ var arg0 string
89+ if args[0] != nil {
90+ arg0 = args[0].(string)
91+ }
92+ run(
93+ arg0,
94+ )
95+ })
96+ return _c
97+}
98+
99+func (_c *mockdialer_Dial_Call) Return(busMoqParam bus, err error) *mockdialer_Dial_Call {
100+ _c.Call.Return(busMoqParam, err)
101+ return _c
102+}
103+
104+func (_c *mockdialer_Dial_Call) RunAndReturn(run func(address string) (bus, error)) *mockdialer_Dial_Call {
105+ _c.Call.Return(run)
106+ return _c
107+}
A internal/adapters/screencast/inventory.go +5 -0
@@ -0,0 +1,5 @@
1+package screencast
2+
3+import "github.com/bnema/neferwl/internal/ports"
4+
5+func (s *Service) applyInventory(inv ports.CastInventory) { s.inv, s.haveInv = inv, true }
@@ -0,0 +1,5 @@
1+package screencast
2+
3+import "github.com/bnema/neferwl/internal/ports"
4+
5+func (s *Service) applyInventory(inv ports.CastInventory) { s.inv, s.haveInv = inv, true }
A internal/adapters/screencast/peer_resolver_mock_test.go +175 -0
@@ -0,0 +1,175 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package screencast
6+
7+import (
8+ "os"
9+
10+ mock "github.com/stretchr/testify/mock"
11+)
12+
13+// newMockpeerResolver creates a new instance of mockpeerResolver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
14+// The first argument is typically a *testing.T value.
15+func newMockpeerResolver(t interface {
16+ mock.TestingT
17+ Cleanup(func())
18+}) *mockpeerResolver {
19+ if helper, ok := t.(interface{ Helper() }); ok {
20+ helper.Helper()
21+ }
22+
23+ mock := &mockpeerResolver{}
24+ mock.Mock.Test(t)
25+
26+ t.Cleanup(func() {
27+ if helper, ok := t.(interface{ Helper() }); ok {
28+ helper.Helper()
29+ }
30+ mock.AssertExpectations(t)
31+ })
32+
33+ return mock
34+}
35+
36+// mockpeerResolver is an autogenerated mock type for the peerResolver type
37+type mockpeerResolver struct {
38+ mock.Mock
39+}
40+
41+type mockpeerResolver_Expecter struct {
42+ mock *mock.Mock
43+}
44+
45+func (_m *mockpeerResolver) EXPECT() *mockpeerResolver_Expecter {
46+ return &mockpeerResolver_Expecter{mock: &_m.Mock}
47+}
48+
49+// Exe provides a mock function for the type mockpeerResolver
50+func (_mock *mockpeerResolver) Exe(pidfd *os.File) (string, int, error) {
51+ ret := _mock.Called(pidfd)
52+
53+ if len(ret) == 0 {
54+ panic("no return value specified for Exe")
55+ }
56+
57+ var r0 string
58+ var r1 int
59+ var r2 error
60+ if returnFunc, ok := ret.Get(0).(func(*os.File) (string, int, error)); ok {
61+ return returnFunc(pidfd)
62+ }
63+ if returnFunc, ok := ret.Get(0).(func(*os.File) string); ok {
64+ r0 = returnFunc(pidfd)
65+ } else {
66+ r0 = ret.Get(0).(string)
67+ }
68+ if returnFunc, ok := ret.Get(1).(func(*os.File) int); ok {
69+ r1 = returnFunc(pidfd)
70+ } else {
71+ r1 = ret.Get(1).(int)
72+ }
73+ if returnFunc, ok := ret.Get(2).(func(*os.File) error); ok {
74+ r2 = returnFunc(pidfd)
75+ } else {
76+ r2 = ret.Error(2)
77+ }
78+ return r0, r1, r2
79+}
80+
81+// mockpeerResolver_Exe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Exe'
82+type mockpeerResolver_Exe_Call struct {
83+ *mock.Call
84+}
85+
86+// Exe is a helper method to define mock.On call
87+// - pidfd *os.File
88+func (_e *mockpeerResolver_Expecter) Exe(pidfd any) *mockpeerResolver_Exe_Call {
89+ return &mockpeerResolver_Exe_Call{Call: _e.mock.On("Exe", pidfd)}
90+}
91+
92+func (_c *mockpeerResolver_Exe_Call) Run(run func(pidfd *os.File)) *mockpeerResolver_Exe_Call {
93+ _c.Call.Run(func(args mock.Arguments) {
94+ var arg0 *os.File
95+ if args[0] != nil {
96+ arg0 = args[0].(*os.File)
97+ }
98+ run(
99+ arg0,
100+ )
101+ })
102+ return _c
103+}
104+
105+func (_c *mockpeerResolver_Exe_Call) Return(exe string, pid int, err error) *mockpeerResolver_Exe_Call {
106+ _c.Call.Return(exe, pid, err)
107+ return _c
108+}
109+
110+func (_c *mockpeerResolver_Exe_Call) RunAndReturn(run func(pidfd *os.File) (string, int, error)) *mockpeerResolver_Exe_Call {
111+ _c.Call.Return(run)
112+ return _c
113+}
114+
115+// Open provides a mock function for the type mockpeerResolver
116+func (_mock *mockpeerResolver) Open(pid int) (*os.File, error) {
117+ ret := _mock.Called(pid)
118+
119+ if len(ret) == 0 {
120+ panic("no return value specified for Open")
121+ }
122+
123+ var r0 *os.File
124+ var r1 error
125+ if returnFunc, ok := ret.Get(0).(func(int) (*os.File, error)); ok {
126+ return returnFunc(pid)
127+ }
128+ if returnFunc, ok := ret.Get(0).(func(int) *os.File); ok {
129+ r0 = returnFunc(pid)
130+ } else {
131+ if ret.Get(0) != nil {
132+ r0 = ret.Get(0).(*os.File)
133+ }
134+ }
135+ if returnFunc, ok := ret.Get(1).(func(int) error); ok {
136+ r1 = returnFunc(pid)
137+ } else {
138+ r1 = ret.Error(1)
139+ }
140+ return r0, r1
141+}
142+
143+// mockpeerResolver_Open_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Open'
144+type mockpeerResolver_Open_Call struct {
145+ *mock.Call
146+}
147+
148+// Open is a helper method to define mock.On call
149+// - pid int
150+func (_e *mockpeerResolver_Expecter) Open(pid any) *mockpeerResolver_Open_Call {
151+ return &mockpeerResolver_Open_Call{Call: _e.mock.On("Open", pid)}
152+}
153+
154+func (_c *mockpeerResolver_Open_Call) Run(run func(pid int)) *mockpeerResolver_Open_Call {
155+ _c.Call.Run(func(args mock.Arguments) {
156+ var arg0 int
157+ if args[0] != nil {
158+ arg0 = args[0].(int)
159+ }
160+ run(
161+ arg0,
162+ )
163+ })
164+ return _c
165+}
166+
167+func (_c *mockpeerResolver_Open_Call) Return(file *os.File, err error) *mockpeerResolver_Open_Call {
168+ _c.Call.Return(file, err)
169+ return _c
170+}
171+
172+func (_c *mockpeerResolver_Open_Call) RunAndReturn(run func(pid int) (*os.File, error)) *mockpeerResolver_Open_Call {
173+ _c.Call.Return(run)
174+ return _c
175+}
@@ -0,0 +1,175 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package screencast
6+
7+import (
8+ "os"
9+
10+ mock "github.com/stretchr/testify/mock"
11+)
12+
13+// newMockpeerResolver creates a new instance of mockpeerResolver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
14+// The first argument is typically a *testing.T value.
15+func newMockpeerResolver(t interface {
16+ mock.TestingT
17+ Cleanup(func())
18+}) *mockpeerResolver {
19+ if helper, ok := t.(interface{ Helper() }); ok {
20+ helper.Helper()
21+ }
22+
23+ mock := &mockpeerResolver{}
24+ mock.Mock.Test(t)
25+
26+ t.Cleanup(func() {
27+ if helper, ok := t.(interface{ Helper() }); ok {
28+ helper.Helper()
29+ }
30+ mock.AssertExpectations(t)
31+ })
32+
33+ return mock
34+}
35+
36+// mockpeerResolver is an autogenerated mock type for the peerResolver type
37+type mockpeerResolver struct {
38+ mock.Mock
39+}
40+
41+type mockpeerResolver_Expecter struct {
42+ mock *mock.Mock
43+}
44+
45+func (_m *mockpeerResolver) EXPECT() *mockpeerResolver_Expecter {
46+ return &mockpeerResolver_Expecter{mock: &_m.Mock}
47+}
48+
49+// Exe provides a mock function for the type mockpeerResolver
50+func (_mock *mockpeerResolver) Exe(pidfd *os.File) (string, int, error) {
51+ ret := _mock.Called(pidfd)
52+
53+ if len(ret) == 0 {
54+ panic("no return value specified for Exe")
55+ }
56+
57+ var r0 string
58+ var r1 int
59+ var r2 error
60+ if returnFunc, ok := ret.Get(0).(func(*os.File) (string, int, error)); ok {
61+ return returnFunc(pidfd)
62+ }
63+ if returnFunc, ok := ret.Get(0).(func(*os.File) string); ok {
64+ r0 = returnFunc(pidfd)
65+ } else {
66+ r0 = ret.Get(0).(string)
67+ }
68+ if returnFunc, ok := ret.Get(1).(func(*os.File) int); ok {
69+ r1 = returnFunc(pidfd)
70+ } else {
71+ r1 = ret.Get(1).(int)
72+ }
73+ if returnFunc, ok := ret.Get(2).(func(*os.File) error); ok {
74+ r2 = returnFunc(pidfd)
75+ } else {
76+ r2 = ret.Error(2)
77+ }
78+ return r0, r1, r2
79+}
80+
81+// mockpeerResolver_Exe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Exe'
82+type mockpeerResolver_Exe_Call struct {
83+ *mock.Call
84+}
85+
86+// Exe is a helper method to define mock.On call
87+// - pidfd *os.File
88+func (_e *mockpeerResolver_Expecter) Exe(pidfd any) *mockpeerResolver_Exe_Call {
89+ return &mockpeerResolver_Exe_Call{Call: _e.mock.On("Exe", pidfd)}
90+}
91+
92+func (_c *mockpeerResolver_Exe_Call) Run(run func(pidfd *os.File)) *mockpeerResolver_Exe_Call {
93+ _c.Call.Run(func(args mock.Arguments) {
94+ var arg0 *os.File
95+ if args[0] != nil {
96+ arg0 = args[0].(*os.File)
97+ }
98+ run(
99+ arg0,
100+ )
101+ })
102+ return _c
103+}
104+
105+func (_c *mockpeerResolver_Exe_Call) Return(exe string, pid int, err error) *mockpeerResolver_Exe_Call {
106+ _c.Call.Return(exe, pid, err)
107+ return _c
108+}
109+
110+func (_c *mockpeerResolver_Exe_Call) RunAndReturn(run func(pidfd *os.File) (string, int, error)) *mockpeerResolver_Exe_Call {
111+ _c.Call.Return(run)
112+ return _c
113+}
114+
115+// Open provides a mock function for the type mockpeerResolver
116+func (_mock *mockpeerResolver) Open(pid int) (*os.File, error) {
117+ ret := _mock.Called(pid)
118+
119+ if len(ret) == 0 {
120+ panic("no return value specified for Open")
121+ }
122+
123+ var r0 *os.File
124+ var r1 error
125+ if returnFunc, ok := ret.Get(0).(func(int) (*os.File, error)); ok {
126+ return returnFunc(pid)
127+ }
128+ if returnFunc, ok := ret.Get(0).(func(int) *os.File); ok {
129+ r0 = returnFunc(pid)
130+ } else {
131+ if ret.Get(0) != nil {
132+ r0 = ret.Get(0).(*os.File)
133+ }
134+ }
135+ if returnFunc, ok := ret.Get(1).(func(int) error); ok {
136+ r1 = returnFunc(pid)
137+ } else {
138+ r1 = ret.Error(1)
139+ }
140+ return r0, r1
141+}
142+
143+// mockpeerResolver_Open_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Open'
144+type mockpeerResolver_Open_Call struct {
145+ *mock.Call
146+}
147+
148+// Open is a helper method to define mock.On call
149+// - pid int
150+func (_e *mockpeerResolver_Expecter) Open(pid any) *mockpeerResolver_Open_Call {
151+ return &mockpeerResolver_Open_Call{Call: _e.mock.On("Open", pid)}
152+}
153+
154+func (_c *mockpeerResolver_Open_Call) Run(run func(pid int)) *mockpeerResolver_Open_Call {
155+ _c.Call.Run(func(args mock.Arguments) {
156+ var arg0 int
157+ if args[0] != nil {
158+ arg0 = args[0].(int)
159+ }
160+ run(
161+ arg0,
162+ )
163+ })
164+ return _c
165+}
166+
167+func (_c *mockpeerResolver_Open_Call) Return(file *os.File, err error) *mockpeerResolver_Open_Call {
168+ _c.Call.Return(file, err)
169+ return _c
170+}
171+
172+func (_c *mockpeerResolver_Open_Call) RunAndReturn(run func(pid int) (*os.File, error)) *mockpeerResolver_Open_Call {
173+ _c.Call.Return(run)
174+ return _c
175+}
A internal/adapters/screencast/pipewire_opener_mock_test.go +100 -0
@@ -0,0 +1,100 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package screencast
6+
7+import (
8+ mock "github.com/stretchr/testify/mock"
9+)
10+
11+// newMockpipewireOpener creates a new instance of mockpipewireOpener. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
12+// The first argument is typically a *testing.T value.
13+func newMockpipewireOpener(t interface {
14+ mock.TestingT
15+ Cleanup(func())
16+}) *mockpipewireOpener {
17+ if helper, ok := t.(interface{ Helper() }); ok {
18+ helper.Helper()
19+ }
20+
21+ mock := &mockpipewireOpener{}
22+ mock.Mock.Test(t)
23+
24+ t.Cleanup(func() {
25+ if helper, ok := t.(interface{ Helper() }); ok {
26+ helper.Helper()
27+ }
28+ mock.AssertExpectations(t)
29+ })
30+
31+ return mock
32+}
33+
34+// mockpipewireOpener is an autogenerated mock type for the pipewireOpener type
35+type mockpipewireOpener struct {
36+ mock.Mock
37+}
38+
39+type mockpipewireOpener_Expecter struct {
40+ mock *mock.Mock
41+}
42+
43+func (_m *mockpipewireOpener) EXPECT() *mockpipewireOpener_Expecter {
44+ return &mockpipewireOpener_Expecter{mock: &_m.Mock}
45+}
46+
47+// Open provides a mock function for the type mockpipewireOpener
48+func (_mock *mockpipewireOpener) Open() (videoCore, error) {
49+ ret := _mock.Called()
50+
51+ if len(ret) == 0 {
52+ panic("no return value specified for Open")
53+ }
54+
55+ var r0 videoCore
56+ var r1 error
57+ if returnFunc, ok := ret.Get(0).(func() (videoCore, error)); ok {
58+ return returnFunc()
59+ }
60+ if returnFunc, ok := ret.Get(0).(func() videoCore); ok {
61+ r0 = returnFunc()
62+ } else {
63+ if ret.Get(0) != nil {
64+ r0 = ret.Get(0).(videoCore)
65+ }
66+ }
67+ if returnFunc, ok := ret.Get(1).(func() error); ok {
68+ r1 = returnFunc()
69+ } else {
70+ r1 = ret.Error(1)
71+ }
72+ return r0, r1
73+}
74+
75+// mockpipewireOpener_Open_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Open'
76+type mockpipewireOpener_Open_Call struct {
77+ *mock.Call
78+}
79+
80+// Open is a helper method to define mock.On call
81+func (_e *mockpipewireOpener_Expecter) Open() *mockpipewireOpener_Open_Call {
82+ return &mockpipewireOpener_Open_Call{Call: _e.mock.On("Open")}
83+}
84+
85+func (_c *mockpipewireOpener_Open_Call) Run(run func()) *mockpipewireOpener_Open_Call {
86+ _c.Call.Run(func(args mock.Arguments) {
87+ run()
88+ })
89+ return _c
90+}
91+
92+func (_c *mockpipewireOpener_Open_Call) Return(videoCoreMoqParam videoCore, err error) *mockpipewireOpener_Open_Call {
93+ _c.Call.Return(videoCoreMoqParam, err)
94+ return _c
95+}
96+
97+func (_c *mockpipewireOpener_Open_Call) RunAndReturn(run func() (videoCore, error)) *mockpipewireOpener_Open_Call {
98+ _c.Call.Return(run)
99+ return _c
100+}
@@ -0,0 +1,100 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package screencast
6+
7+import (
8+ mock "github.com/stretchr/testify/mock"
9+)
10+
11+// newMockpipewireOpener creates a new instance of mockpipewireOpener. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
12+// The first argument is typically a *testing.T value.
13+func newMockpipewireOpener(t interface {
14+ mock.TestingT
15+ Cleanup(func())
16+}) *mockpipewireOpener {
17+ if helper, ok := t.(interface{ Helper() }); ok {
18+ helper.Helper()
19+ }
20+
21+ mock := &mockpipewireOpener{}
22+ mock.Mock.Test(t)
23+
24+ t.Cleanup(func() {
25+ if helper, ok := t.(interface{ Helper() }); ok {
26+ helper.Helper()
27+ }
28+ mock.AssertExpectations(t)
29+ })
30+
31+ return mock
32+}
33+
34+// mockpipewireOpener is an autogenerated mock type for the pipewireOpener type
35+type mockpipewireOpener struct {
36+ mock.Mock
37+}
38+
39+type mockpipewireOpener_Expecter struct {
40+ mock *mock.Mock
41+}
42+
43+func (_m *mockpipewireOpener) EXPECT() *mockpipewireOpener_Expecter {
44+ return &mockpipewireOpener_Expecter{mock: &_m.Mock}
45+}
46+
47+// Open provides a mock function for the type mockpipewireOpener
48+func (_mock *mockpipewireOpener) Open() (videoCore, error) {
49+ ret := _mock.Called()
50+
51+ if len(ret) == 0 {
52+ panic("no return value specified for Open")
53+ }
54+
55+ var r0 videoCore
56+ var r1 error
57+ if returnFunc, ok := ret.Get(0).(func() (videoCore, error)); ok {
58+ return returnFunc()
59+ }
60+ if returnFunc, ok := ret.Get(0).(func() videoCore); ok {
61+ r0 = returnFunc()
62+ } else {
63+ if ret.Get(0) != nil {
64+ r0 = ret.Get(0).(videoCore)
65+ }
66+ }
67+ if returnFunc, ok := ret.Get(1).(func() error); ok {
68+ r1 = returnFunc()
69+ } else {
70+ r1 = ret.Error(1)
71+ }
72+ return r0, r1
73+}
74+
75+// mockpipewireOpener_Open_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Open'
76+type mockpipewireOpener_Open_Call struct {
77+ *mock.Call
78+}
79+
80+// Open is a helper method to define mock.On call
81+func (_e *mockpipewireOpener_Expecter) Open() *mockpipewireOpener_Open_Call {
82+ return &mockpipewireOpener_Open_Call{Call: _e.mock.On("Open")}
83+}
84+
85+func (_c *mockpipewireOpener_Open_Call) Run(run func()) *mockpipewireOpener_Open_Call {
86+ _c.Call.Run(func(args mock.Arguments) {
87+ run()
88+ })
89+ return _c
90+}
91+
92+func (_c *mockpipewireOpener_Open_Call) Return(videoCoreMoqParam videoCore, err error) *mockpipewireOpener_Open_Call {
93+ _c.Call.Return(videoCoreMoqParam, err)
94+ return _c
95+}
96+
97+func (_c *mockpipewireOpener_Open_Call) RunAndReturn(run func() (videoCore, error)) *mockpipewireOpener_Open_Call {
98+ _c.Call.Return(run)
99+ return _c
100+}
A internal/adapters/screencast/runner_mock_test.go +104 -0
@@ -0,0 +1,104 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package screencast
6+
7+import (
8+ "context"
9+
10+ mock "github.com/stretchr/testify/mock"
11+)
12+
13+// newMockrunner creates a new instance of mockrunner. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
14+// The first argument is typically a *testing.T value.
15+func newMockrunner(t interface {
16+ mock.TestingT
17+ Cleanup(func())
18+}) *mockrunner {
19+ if helper, ok := t.(interface{ Helper() }); ok {
20+ helper.Helper()
21+ }
22+
23+ mock := &mockrunner{}
24+ mock.Mock.Test(t)
25+
26+ t.Cleanup(func() {
27+ if helper, ok := t.(interface{ Helper() }); ok {
28+ helper.Helper()
29+ }
30+ mock.AssertExpectations(t)
31+ })
32+
33+ return mock
34+}
35+
36+// mockrunner is an autogenerated mock type for the runner type
37+type mockrunner struct {
38+ mock.Mock
39+}
40+
41+type mockrunner_Expecter struct {
42+ mock *mock.Mock
43+}
44+
45+func (_m *mockrunner) EXPECT() *mockrunner_Expecter {
46+ return &mockrunner_Expecter{mock: &_m.Mock}
47+}
48+
49+// Run provides a mock function for the type mockrunner
50+func (_mock *mockrunner) Run(ctx context.Context, args []string) error {
51+ ret := _mock.Called(ctx, args)
52+
53+ if len(ret) == 0 {
54+ panic("no return value specified for Run")
55+ }
56+
57+ var r0 error
58+ if returnFunc, ok := ret.Get(0).(func(context.Context, []string) error); ok {
59+ r0 = returnFunc(ctx, args)
60+ } else {
61+ r0 = ret.Error(0)
62+ }
63+ return r0
64+}
65+
66+// mockrunner_Run_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Run'
67+type mockrunner_Run_Call struct {
68+ *mock.Call
69+}
70+
71+// Run is a helper method to define mock.On call
72+// - ctx context.Context
73+// - args []string
74+func (_e *mockrunner_Expecter) Run(ctx any, args any) *mockrunner_Run_Call {
75+ return &mockrunner_Run_Call{Call: _e.mock.On("Run", ctx, args)}
76+}
77+
78+func (_c *mockrunner_Run_Call) Run(run func(ctx context.Context, args []string)) *mockrunner_Run_Call {
79+ _c.Call.Run(func(args mock.Arguments) {
80+ var arg0 context.Context
81+ if args[0] != nil {
82+ arg0 = args[0].(context.Context)
83+ }
84+ var arg1 []string
85+ if args[1] != nil {
86+ arg1 = args[1].([]string)
87+ }
88+ run(
89+ arg0,
90+ arg1,
91+ )
92+ })
93+ return _c
94+}
95+
96+func (_c *mockrunner_Run_Call) Return(err error) *mockrunner_Run_Call {
97+ _c.Call.Return(err)
98+ return _c
99+}
100+
101+func (_c *mockrunner_Run_Call) RunAndReturn(run func(ctx context.Context, args []string) error) *mockrunner_Run_Call {
102+ _c.Call.Return(run)
103+ return _c
104+}
@@ -0,0 +1,104 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package screencast
6+
7+import (
8+ "context"
9+
10+ mock "github.com/stretchr/testify/mock"
11+)
12+
13+// newMockrunner creates a new instance of mockrunner. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
14+// The first argument is typically a *testing.T value.
15+func newMockrunner(t interface {
16+ mock.TestingT
17+ Cleanup(func())
18+}) *mockrunner {
19+ if helper, ok := t.(interface{ Helper() }); ok {
20+ helper.Helper()
21+ }
22+
23+ mock := &mockrunner{}
24+ mock.Mock.Test(t)
25+
26+ t.Cleanup(func() {
27+ if helper, ok := t.(interface{ Helper() }); ok {
28+ helper.Helper()
29+ }
30+ mock.AssertExpectations(t)
31+ })
32+
33+ return mock
34+}
35+
36+// mockrunner is an autogenerated mock type for the runner type
37+type mockrunner struct {
38+ mock.Mock
39+}
40+
41+type mockrunner_Expecter struct {
42+ mock *mock.Mock
43+}
44+
45+func (_m *mockrunner) EXPECT() *mockrunner_Expecter {
46+ return &mockrunner_Expecter{mock: &_m.Mock}
47+}
48+
49+// Run provides a mock function for the type mockrunner
50+func (_mock *mockrunner) Run(ctx context.Context, args []string) error {
51+ ret := _mock.Called(ctx, args)
52+
53+ if len(ret) == 0 {
54+ panic("no return value specified for Run")
55+ }
56+
57+ var r0 error
58+ if returnFunc, ok := ret.Get(0).(func(context.Context, []string) error); ok {
59+ r0 = returnFunc(ctx, args)
60+ } else {
61+ r0 = ret.Error(0)
62+ }
63+ return r0
64+}
65+
66+// mockrunner_Run_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Run'
67+type mockrunner_Run_Call struct {
68+ *mock.Call
69+}
70+
71+// Run is a helper method to define mock.On call
72+// - ctx context.Context
73+// - args []string
74+func (_e *mockrunner_Expecter) Run(ctx any, args any) *mockrunner_Run_Call {
75+ return &mockrunner_Run_Call{Call: _e.mock.On("Run", ctx, args)}
76+}
77+
78+func (_c *mockrunner_Run_Call) Run(run func(ctx context.Context, args []string)) *mockrunner_Run_Call {
79+ _c.Call.Run(func(args mock.Arguments) {
80+ var arg0 context.Context
81+ if args[0] != nil {
82+ arg0 = args[0].(context.Context)
83+ }
84+ var arg1 []string
85+ if args[1] != nil {
86+ arg1 = args[1].([]string)
87+ }
88+ run(
89+ arg0,
90+ arg1,
91+ )
92+ })
93+ return _c
94+}
95+
96+func (_c *mockrunner_Run_Call) Return(err error) *mockrunner_Run_Call {
97+ _c.Call.Return(err)
98+ return _c
99+}
100+
101+func (_c *mockrunner_Run_Call) RunAndReturn(run func(ctx context.Context, args []string) error) *mockrunner_Run_Call {
102+ _c.Call.Return(run)
103+ return _c
104+}
A internal/adapters/screencast/screencast.go +367 -0
@@ -0,0 +1,367 @@
1+// Package screencast serves the GNOME screen cast and screenshot D-Bus
2+// interfaces (org.gnome.Mutter.ScreenCast, org.gnome.Mutter.DisplayConfig,
3+// org.gnome.Shell.Introspect, org.gnome.Shell.Screenshot) so that
4+// xdg-desktop-portal-gnome can offer monitor and window sharing and
5+// screenshots. A cast is a PipeWire Video/Source node whose frames the
6+// wayland server renders into the node's buffers (ports.CastCommand), and a
7+// screenshot is taken by running nefercap.
8+//
9+// One owner goroutine, locked to its OS thread, owns all state: the D-Bus
10+// connection, the PipeWire loop, the sessions and the streams. It waits for
11+// the bus, the PipeWire loop and wake-ups from other goroutines (the wayland
12+// sink and screenshot jobs) in a single poll. Callers are checked against
13+// the capture allowlist through a pidfd before anything is dispatched.
14+package screencast
15+
16+import (
17+ "context"
18+ "errors"
19+ "os"
20+ "runtime"
21+ "sync"
22+ "time"
23+
24+ "github.com/bnema/neferwl/internal/adapters/busretry"
25+ "github.com/bnema/neferwl/internal/adapters/captureallow"
26+ "github.com/bnema/neferwl/internal/adapters/clock"
27+ "github.com/bnema/neferwl/internal/adapters/fdwait"
28+ "github.com/bnema/neferwl/internal/ports"
29+ "github.com/bnema/zerobus"
30+ "github.com/bnema/zerowrap"
31+ "golang.org/x/sys/unix"
32+)
33+
34+// The bus names served, and the bounds of the fixed tables.
35+const (
36+ nameScreenCast = "org.gnome.Mutter.ScreenCast"
37+ nameDisplayConfig = "org.gnome.Mutter.DisplayConfig"
38+ nameIntrospect = "org.gnome.Shell.Introspect"
39+ nameScreenshot = "org.gnome.Shell.Screenshot"
40+ busDaemon = "org.freedesktop.DBus"
41+ busDaemonPath = "/org/freedesktop/DBus"
42+
43+ maxSessions = 8 // live sessions
44+ maxStreams = 4 // streams per session
45+ maxPending = 16 // requests waiting for a caller check
46+ maxCallers = 32 // checked D-Bus peers
47+ maxArg = 128
48+
49+ // sinkCap bounds the wayland events waiting for the owner. Damage past
50+ // it is merged into a flag; nothing else is dropped.
51+ sinkCap = 256
52+
53+ // shotTimeout bounds a nefercap run.
54+ shotTimeout = 60 * time.Second
55+
56+ // shutdownWait bounds the wait for frames still in flight at shutdown.
57+ shutdownWait = 2 * time.Second
58+)
59+
60+var _ ports.CastSink = (*Service)(nil)
61+
62+// Service is the screencast adapter. Create it with New and run it once
63+// with Run; Push and Inventory are the only methods other goroutines call.
64+type Service struct {
65+ policy func() *captureallow.Policy
66+ cmds chan<- ports.CastCommand
67+ log zerowrap.Logger
68+
69+ poller *fdwait.Poller
70+ initErr error
71+
72+ // Seams; tests replace them before Run.
73+ clock ports.Clock
74+ dial dialer
75+ pw pipewireOpener
76+ peers peerResolver
77+ runner runner
78+ address string // session bus when empty
79+ env []string
80+
81+ // Transport: filled by other goroutines, drained by the owner.
82+ mu sync.Mutex
83+ queue []ports.CastEvent
84+ spare []ports.CastEvent
85+ lost bool // damage was merged away
86+ woken bool
87+ invNew *ports.CastInventory
88+ shotRes shotResult
89+
90+ // Owner state.
91+ ctx context.Context
92+ conn bus
93+ pwc videoCore
94+ owns [4]bool // nameScreenCast, nameDisplayConfig, nameIntrospect, nameScreenshot
95+ inv ports.CastInventory
96+ haveInv bool
97+ callers [maxCallers]caller
98+ pending [maxPending]pending
99+ sessions [maxSessions]session
100+ nextSess uint32
101+ nextStrm uint32
102+ nextCast uint64
103+ waitFor time.Duration // time to the next paced frame, 0 when none
104+ shot shotState
105+ fatal error
106+ jobs sync.WaitGroup
107+}
108+
109+// New creates the service. policy returns the capture allowlist in force;
110+// cmds carries the commands for the wayland server.
111+func New(policy func() *captureallow.Policy, cmds chan<- ports.CastCommand, log zerowrap.Logger) *Service {
112+ s := &Service{
113+ policy: policy,
114+ cmds: cmds,
115+ log: log,
116+ clock: clock.System{},
117+ dial: zerobusDialer{},
118+ pw: realPipeWire{},
119+ peers: pidfdPeers{},
120+ queue: make([]ports.CastEvent, 0, sinkCap),
121+ spare: make([]ports.CastEvent, 0, sinkCap),
122+ }
123+ s.poller, s.initErr = fdwait.New()
124+ return s
125+}
126+
127+// SetEnv sets the environment nefercap runs in (WAYLAND_DISPLAY names this
128+// compositor). Call it before Run.
129+func (s *Service) SetEnv(env []string) { s.env = env }
130+
131+// Push queues an event of the wayland server for the owner. It never blocks.
132+func (s *Service) Push(ev ports.CastEvent) {
133+ s.mu.Lock()
134+ if ev.Kind == ports.CastDamage && len(s.queue) >= sinkCap {
135+ s.lost = true
136+ } else {
137+ s.queue = append(s.queue, ev)
138+ }
139+ wake := !s.woken
140+ s.woken = true
141+ s.mu.Unlock()
142+ if wake {
143+ s.wake()
144+ }
145+}
146+
147+// Inventory takes the new outputs and windows; the owner publishes them.
148+func (s *Service) Inventory(inv ports.CastInventory) {
149+ s.mu.Lock()
150+ s.invNew = &inv
151+ wake := !s.woken
152+ s.woken = true
153+ s.mu.Unlock()
154+ if wake {
155+ s.wake()
156+ }
157+}
158+
159+func (s *Service) wake() {
160+ if s.poller != nil {
161+ s.poller.Wake()
162+ }
163+}
164+
165+// take swaps out what other goroutines queued. The events stay valid until
166+// the next take.
167+func (s *Service) take() (evs []ports.CastEvent, lost bool, inv *ports.CastInventory, shot *shotResult) {
168+ s.mu.Lock()
169+ s.spare, s.queue = s.queue, s.spare[:0]
170+ evs, lost, inv = s.spare, s.lost, s.invNew
171+ s.lost, s.invNew, s.woken = false, nil, false
172+ if s.shotRes.ready {
173+ r := s.shotRes
174+ s.shotRes = shotResult{}
175+ shot = &r
176+ }
177+ s.mu.Unlock()
178+ return evs, lost, inv, shot
179+}
180+
181+// Run serves until ctx ends. A lost bus or a name that others own is tried
182+// again after retry, growing to a minute. It returns once every job and
183+// stream is released.
184+func (s *Service) Run(ctx context.Context, retry time.Duration) {
185+ if s.initErr != nil {
186+ s.log.Warn().Err(s.initErr).Msg("screencast disabled")
187+ return
188+ }
189+ defer s.poller.Close()
190+ s.poller.StopOn(ctx)
191+ if s.runner == nil {
192+ s.runner = execRunner{env: s.env}
193+ }
194+ busretry.Run(ctx, retry, "D-Bus screencast", s.log, s.attempt)
195+ s.jobs.Wait()
196+}
197+
198+// attempt is one connection of the service to the buses.
199+func (s *Service) attempt(ctx context.Context) (err error) {
200+ // The PipeWire loop belongs to this OS thread for its whole life.
201+ runtime.LockOSThread()
202+ defer runtime.UnlockOSThread()
203+ conn, err := s.dial.Dial(s.address)
204+ if err != nil {
205+ return err
206+ }
207+ defer func() { _ = conn.Close() }()
208+ s.reset(ctx, conn)
209+ if s.pwc, err = s.pw.Open(); err != nil {
210+ s.pwc = nil
211+ s.log.Warn().Err(err).Msg("PipeWire unavailable: screen casting is not offered")
212+ }
213+ defer s.shutdown()
214+ if err = s.start(); err != nil {
215+ return err
216+ }
217+ return s.loop(ctx)
218+}
219+
220+// reset clears the owner state of a previous attempt.
221+func (s *Service) reset(ctx context.Context, conn bus) {
222+ s.ctx, s.conn, s.fatal = ctx, conn, nil
223+ s.owns = [4]bool{}
224+ s.haveInv = false
225+ s.callers = [maxCallers]caller{}
226+ s.pending = [maxPending]pending{}
227+ s.sessions = [maxSessions]session{}
228+ s.shot = shotState{}
229+}
230+
231+// start watches departures and takes the names.
232+func (s *Service) start() error {
233+ rule := "type='signal',sender='" + busDaemon + "',interface='" + busDaemon + "',member='NameOwnerChanged',arg2=''"
234+ if err := s.conn.AddMatch(rule); err != nil {
235+ return err
236+ }
237+ names := [4]string{nameScreenCast, nameDisplayConfig, nameIntrospect, nameScreenshot}
238+ got := 0
239+ for i, name := range names {
240+ if i == 0 && s.pwc == nil {
241+ continue
242+ }
243+ code, err := s.conn.RequestName(name, zerobus.NameFlagDoNotQueue)
244+ if err != nil {
245+ return err
246+ }
247+ if code != zerobus.NamePrimaryOwner && code != zerobus.NameAlreadyOwner {
248+ s.log.Warn().Str("name", name).Msg("name owned by another program; not served")
249+ continue
250+ }
251+ s.owns[i] = true
252+ got++
253+ s.log.Info().Str("name", name).Msg("serving")
254+ }
255+ if got == 0 {
256+ return errors.New("no D-Bus name acquired")
257+ }
258+ return nil
259+}
260+
261+// loop waits for the bus, PipeWire and other goroutines and serves them.
262+func (s *Service) loop(ctx context.Context) error {
263+ rc, err := s.conn.SyscallConn()
264+ if err != nil {
265+ return err
266+ }
267+ busFD := int32(-1)
268+ if err := rc.Control(func(fd uintptr) { busFD = int32(fd) }); err != nil {
269+ return err
270+ }
271+ var fds [2]unix.PollFd
272+ for ctx.Err() == nil {
273+ for s.fatal == nil && s.conn.Buffered() {
274+ s.readOne()
275+ }
276+ if s.pwc != nil {
277+ s.pwc.Iterate()
278+ }
279+ s.service()
280+ if s.fatal != nil {
281+ return s.fatal
282+ }
283+ fds[0] = unix.PollFd{Fd: busFD, Events: unix.POLLIN}
284+ n := 1
285+ if s.pwc != nil {
286+ fds[1] = unix.PollFd{Fd: int32(s.pwc.Fd()), Events: unix.POLLIN}
287+ n = 2
288+ }
289+ if _, err := s.poller.Poll(fds[:n], s.timeout()); err != nil {
290+ return err
291+ }
292+ if fds[0].Revents != 0 {
293+ s.readOne()
294+ }
295+ }
296+ return nil
297+}
298+
299+// readOne reads and handles one message; the read may wait for the rest of
300+// a message that arrived in part.
301+func (s *Service) readOne() {
302+ m, err := s.conn.ReadMessage()
303+ if err != nil {
304+ s.fatal = err
305+ return
306+ }
307+ s.onMessage(m)
308+}
309+
310+// service applies everything the other goroutines queued, then produces the
311+// frames that are due.
312+func (s *Service) service() {
313+ evs, lost, inv, shot := s.take()
314+ if inv != nil {
315+ s.applyInventory(*inv)
316+ }
317+ if lost {
318+ s.forEachStream(func(st *stream) { st.dirty = true })
319+ }
320+ for i := range evs {
321+ s.onCastEvent(&evs[i])
322+ }
323+ if shot != nil {
324+ s.onShotDone(shot)
325+ }
326+ s.pumpAll(s.clock.Now())
327+ s.reap()
328+}
329+
330+// shutdown ends every session and releases PipeWire. A frame still in
331+// flight is waited for: its buffer is lent to the wayland server.
332+func (s *Service) shutdown() {
333+ s.forEachSession(func(sess *session) { s.closeSession(sess, true) })
334+ deadline := time.Now().Add(shutdownWait)
335+ for s.streamsLive() && time.Now().Before(deadline) {
336+ evs, _, _, _ := s.take()
337+ for i := range evs {
338+ s.onCastEvent(&evs[i])
339+ }
340+ s.reap()
341+ if s.streamsLive() {
342+ time.Sleep(5 * time.Millisecond)
343+ }
344+ }
345+ if s.streamsLive() {
346+ s.log.Warn().Msg("frames still in flight at shutdown; PipeWire resources are left to the process exit")
347+ s.pwc = nil
348+ }
349+ if s.pwc != nil {
350+ s.pwc.Close()
351+ s.pwc = nil
352+ }
353+}
354+
355+// timeout is the poll timeout in milliseconds: the time to the next frame
356+// that only waits for its interval, or -1.
357+func (s *Service) timeout() int {
358+ wait := s.waitFor
359+ s.waitFor = 0
360+ if wait <= 0 {
361+ return -1
362+ }
363+ return int((wait + time.Millisecond - 1) / time.Millisecond)
364+}
365+
366+// runtimeDir is where screenshots are written.
367+func runtimeDir() string { return os.Getenv("XDG_RUNTIME_DIR") }
@@ -0,0 +1,367 @@
1+// Package screencast serves the GNOME screen cast and screenshot D-Bus
2+// interfaces (org.gnome.Mutter.ScreenCast, org.gnome.Mutter.DisplayConfig,
3+// org.gnome.Shell.Introspect, org.gnome.Shell.Screenshot) so that
4+// xdg-desktop-portal-gnome can offer monitor and window sharing and
5+// screenshots. A cast is a PipeWire Video/Source node whose frames the
6+// wayland server renders into the node's buffers (ports.CastCommand), and a
7+// screenshot is taken by running nefercap.
8+//
9+// One owner goroutine, locked to its OS thread, owns all state: the D-Bus
10+// connection, the PipeWire loop, the sessions and the streams. It waits for
11+// the bus, the PipeWire loop and wake-ups from other goroutines (the wayland
12+// sink and screenshot jobs) in a single poll. Callers are checked against
13+// the capture allowlist through a pidfd before anything is dispatched.
14+package screencast
15+
16+import (
17+ "context"
18+ "errors"
19+ "os"
20+ "runtime"
21+ "sync"
22+ "time"
23+
24+ "github.com/bnema/neferwl/internal/adapters/busretry"
25+ "github.com/bnema/neferwl/internal/adapters/captureallow"
26+ "github.com/bnema/neferwl/internal/adapters/clock"
27+ "github.com/bnema/neferwl/internal/adapters/fdwait"
28+ "github.com/bnema/neferwl/internal/ports"
29+ "github.com/bnema/zerobus"
30+ "github.com/bnema/zerowrap"
31+ "golang.org/x/sys/unix"
32+)
33+
34+// The bus names served, and the bounds of the fixed tables.
35+const (
36+ nameScreenCast = "org.gnome.Mutter.ScreenCast"
37+ nameDisplayConfig = "org.gnome.Mutter.DisplayConfig"
38+ nameIntrospect = "org.gnome.Shell.Introspect"
39+ nameScreenshot = "org.gnome.Shell.Screenshot"
40+ busDaemon = "org.freedesktop.DBus"
41+ busDaemonPath = "/org/freedesktop/DBus"
42+
43+ maxSessions = 8 // live sessions
44+ maxStreams = 4 // streams per session
45+ maxPending = 16 // requests waiting for a caller check
46+ maxCallers = 32 // checked D-Bus peers
47+ maxArg = 128
48+
49+ // sinkCap bounds the wayland events waiting for the owner. Damage past
50+ // it is merged into a flag; nothing else is dropped.
51+ sinkCap = 256
52+
53+ // shotTimeout bounds a nefercap run.
54+ shotTimeout = 60 * time.Second
55+
56+ // shutdownWait bounds the wait for frames still in flight at shutdown.
57+ shutdownWait = 2 * time.Second
58+)
59+
60+var _ ports.CastSink = (*Service)(nil)
61+
62+// Service is the screencast adapter. Create it with New and run it once
63+// with Run; Push and Inventory are the only methods other goroutines call.
64+type Service struct {
65+ policy func() *captureallow.Policy
66+ cmds chan<- ports.CastCommand
67+ log zerowrap.Logger
68+
69+ poller *fdwait.Poller
70+ initErr error
71+
72+ // Seams; tests replace them before Run.
73+ clock ports.Clock
74+ dial dialer
75+ pw pipewireOpener
76+ peers peerResolver
77+ runner runner
78+ address string // session bus when empty
79+ env []string
80+
81+ // Transport: filled by other goroutines, drained by the owner.
82+ mu sync.Mutex
83+ queue []ports.CastEvent
84+ spare []ports.CastEvent
85+ lost bool // damage was merged away
86+ woken bool
87+ invNew *ports.CastInventory
88+ shotRes shotResult
89+
90+ // Owner state.
91+ ctx context.Context
92+ conn bus
93+ pwc videoCore
94+ owns [4]bool // nameScreenCast, nameDisplayConfig, nameIntrospect, nameScreenshot
95+ inv ports.CastInventory
96+ haveInv bool
97+ callers [maxCallers]caller
98+ pending [maxPending]pending
99+ sessions [maxSessions]session
100+ nextSess uint32
101+ nextStrm uint32
102+ nextCast uint64
103+ waitFor time.Duration // time to the next paced frame, 0 when none
104+ shot shotState
105+ fatal error
106+ jobs sync.WaitGroup
107+}
108+
109+// New creates the service. policy returns the capture allowlist in force;
110+// cmds carries the commands for the wayland server.
111+func New(policy func() *captureallow.Policy, cmds chan<- ports.CastCommand, log zerowrap.Logger) *Service {
112+ s := &Service{
113+ policy: policy,
114+ cmds: cmds,
115+ log: log,
116+ clock: clock.System{},
117+ dial: zerobusDialer{},
118+ pw: realPipeWire{},
119+ peers: pidfdPeers{},
120+ queue: make([]ports.CastEvent, 0, sinkCap),
121+ spare: make([]ports.CastEvent, 0, sinkCap),
122+ }
123+ s.poller, s.initErr = fdwait.New()
124+ return s
125+}
126+
127+// SetEnv sets the environment nefercap runs in (WAYLAND_DISPLAY names this
128+// compositor). Call it before Run.
129+func (s *Service) SetEnv(env []string) { s.env = env }
130+
131+// Push queues an event of the wayland server for the owner. It never blocks.
132+func (s *Service) Push(ev ports.CastEvent) {
133+ s.mu.Lock()
134+ if ev.Kind == ports.CastDamage && len(s.queue) >= sinkCap {
135+ s.lost = true
136+ } else {
137+ s.queue = append(s.queue, ev)
138+ }
139+ wake := !s.woken
140+ s.woken = true
141+ s.mu.Unlock()
142+ if wake {
143+ s.wake()
144+ }
145+}
146+
147+// Inventory takes the new outputs and windows; the owner publishes them.
148+func (s *Service) Inventory(inv ports.CastInventory) {
149+ s.mu.Lock()
150+ s.invNew = &inv
151+ wake := !s.woken
152+ s.woken = true
153+ s.mu.Unlock()
154+ if wake {
155+ s.wake()
156+ }
157+}
158+
159+func (s *Service) wake() {
160+ if s.poller != nil {
161+ s.poller.Wake()
162+ }
163+}
164+
165+// take swaps out what other goroutines queued. The events stay valid until
166+// the next take.
167+func (s *Service) take() (evs []ports.CastEvent, lost bool, inv *ports.CastInventory, shot *shotResult) {
168+ s.mu.Lock()
169+ s.spare, s.queue = s.queue, s.spare[:0]
170+ evs, lost, inv = s.spare, s.lost, s.invNew
171+ s.lost, s.invNew, s.woken = false, nil, false
172+ if s.shotRes.ready {
173+ r := s.shotRes
174+ s.shotRes = shotResult{}
175+ shot = &r
176+ }
177+ s.mu.Unlock()
178+ return evs, lost, inv, shot
179+}
180+
181+// Run serves until ctx ends. A lost bus or a name that others own is tried
182+// again after retry, growing to a minute. It returns once every job and
183+// stream is released.
184+func (s *Service) Run(ctx context.Context, retry time.Duration) {
185+ if s.initErr != nil {
186+ s.log.Warn().Err(s.initErr).Msg("screencast disabled")
187+ return
188+ }
189+ defer s.poller.Close()
190+ s.poller.StopOn(ctx)
191+ if s.runner == nil {
192+ s.runner = execRunner{env: s.env}
193+ }
194+ busretry.Run(ctx, retry, "D-Bus screencast", s.log, s.attempt)
195+ s.jobs.Wait()
196+}
197+
198+// attempt is one connection of the service to the buses.
199+func (s *Service) attempt(ctx context.Context) (err error) {
200+ // The PipeWire loop belongs to this OS thread for its whole life.
201+ runtime.LockOSThread()
202+ defer runtime.UnlockOSThread()
203+ conn, err := s.dial.Dial(s.address)
204+ if err != nil {
205+ return err
206+ }
207+ defer func() { _ = conn.Close() }()
208+ s.reset(ctx, conn)
209+ if s.pwc, err = s.pw.Open(); err != nil {
210+ s.pwc = nil
211+ s.log.Warn().Err(err).Msg("PipeWire unavailable: screen casting is not offered")
212+ }
213+ defer s.shutdown()
214+ if err = s.start(); err != nil {
215+ return err
216+ }
217+ return s.loop(ctx)
218+}
219+
220+// reset clears the owner state of a previous attempt.
221+func (s *Service) reset(ctx context.Context, conn bus) {
222+ s.ctx, s.conn, s.fatal = ctx, conn, nil
223+ s.owns = [4]bool{}
224+ s.haveInv = false
225+ s.callers = [maxCallers]caller{}
226+ s.pending = [maxPending]pending{}
227+ s.sessions = [maxSessions]session{}
228+ s.shot = shotState{}
229+}
230+
231+// start watches departures and takes the names.
232+func (s *Service) start() error {
233+ rule := "type='signal',sender='" + busDaemon + "',interface='" + busDaemon + "',member='NameOwnerChanged',arg2=''"
234+ if err := s.conn.AddMatch(rule); err != nil {
235+ return err
236+ }
237+ names := [4]string{nameScreenCast, nameDisplayConfig, nameIntrospect, nameScreenshot}
238+ got := 0
239+ for i, name := range names {
240+ if i == 0 && s.pwc == nil {
241+ continue
242+ }
243+ code, err := s.conn.RequestName(name, zerobus.NameFlagDoNotQueue)
244+ if err != nil {
245+ return err
246+ }
247+ if code != zerobus.NamePrimaryOwner && code != zerobus.NameAlreadyOwner {
248+ s.log.Warn().Str("name", name).Msg("name owned by another program; not served")
249+ continue
250+ }
251+ s.owns[i] = true
252+ got++
253+ s.log.Info().Str("name", name).Msg("serving")
254+ }
255+ if got == 0 {
256+ return errors.New("no D-Bus name acquired")
257+ }
258+ return nil
259+}
260+
261+// loop waits for the bus, PipeWire and other goroutines and serves them.
262+func (s *Service) loop(ctx context.Context) error {
263+ rc, err := s.conn.SyscallConn()
264+ if err != nil {
265+ return err
266+ }
267+ busFD := int32(-1)
268+ if err := rc.Control(func(fd uintptr) { busFD = int32(fd) }); err != nil {
269+ return err
270+ }
271+ var fds [2]unix.PollFd
272+ for ctx.Err() == nil {
273+ for s.fatal == nil && s.conn.Buffered() {
274+ s.readOne()
275+ }
276+ if s.pwc != nil {
277+ s.pwc.Iterate()
278+ }
279+ s.service()
280+ if s.fatal != nil {
281+ return s.fatal
282+ }
283+ fds[0] = unix.PollFd{Fd: busFD, Events: unix.POLLIN}
284+ n := 1
285+ if s.pwc != nil {
286+ fds[1] = unix.PollFd{Fd: int32(s.pwc.Fd()), Events: unix.POLLIN}
287+ n = 2
288+ }
289+ if _, err := s.poller.Poll(fds[:n], s.timeout()); err != nil {
290+ return err
291+ }
292+ if fds[0].Revents != 0 {
293+ s.readOne()
294+ }
295+ }
296+ return nil
297+}
298+
299+// readOne reads and handles one message; the read may wait for the rest of
300+// a message that arrived in part.
301+func (s *Service) readOne() {
302+ m, err := s.conn.ReadMessage()
303+ if err != nil {
304+ s.fatal = err
305+ return
306+ }
307+ s.onMessage(m)
308+}
309+
310+// service applies everything the other goroutines queued, then produces the
311+// frames that are due.
312+func (s *Service) service() {
313+ evs, lost, inv, shot := s.take()
314+ if inv != nil {
315+ s.applyInventory(*inv)
316+ }
317+ if lost {
318+ s.forEachStream(func(st *stream) { st.dirty = true })
319+ }
320+ for i := range evs {
321+ s.onCastEvent(&evs[i])
322+ }
323+ if shot != nil {
324+ s.onShotDone(shot)
325+ }
326+ s.pumpAll(s.clock.Now())
327+ s.reap()
328+}
329+
330+// shutdown ends every session and releases PipeWire. A frame still in
331+// flight is waited for: its buffer is lent to the wayland server.
332+func (s *Service) shutdown() {
333+ s.forEachSession(func(sess *session) { s.closeSession(sess, true) })
334+ deadline := time.Now().Add(shutdownWait)
335+ for s.streamsLive() && time.Now().Before(deadline) {
336+ evs, _, _, _ := s.take()
337+ for i := range evs {
338+ s.onCastEvent(&evs[i])
339+ }
340+ s.reap()
341+ if s.streamsLive() {
342+ time.Sleep(5 * time.Millisecond)
343+ }
344+ }
345+ if s.streamsLive() {
346+ s.log.Warn().Msg("frames still in flight at shutdown; PipeWire resources are left to the process exit")
347+ s.pwc = nil
348+ }
349+ if s.pwc != nil {
350+ s.pwc.Close()
351+ s.pwc = nil
352+ }
353+}
354+
355+// timeout is the poll timeout in milliseconds: the time to the next frame
356+// that only waits for its interval, or -1.
357+func (s *Service) timeout() int {
358+ wait := s.waitFor
359+ s.waitFor = 0
360+ if wait <= 0 {
361+ return -1
362+ }
363+ return int((wait + time.Millisecond - 1) / time.Millisecond)
364+}
365+
366+// runtimeDir is where screenshots are written.
367+func runtimeDir() string { return os.Getenv("XDG_RUNTIME_DIR") }
A internal/adapters/screencast/screenshot.go +12 -0
@@ -0,0 +1,12 @@
1+package screencast
2+
3+// shotState is the screenshot in flight; one at most.
4+type shotState struct{ busy bool }
5+
6+// shotResult is what a finished nefercap run leaves for the owner.
7+type shotResult struct {
8+ ready bool
9+ err error
10+}
11+
12+func (s *Service) onShotDone(r *shotResult) { _ = r }
@@ -0,0 +1,12 @@
1+package screencast
2+
3+// shotState is the screenshot in flight; one at most.
4+type shotState struct{ busy bool }
5+
6+// shotResult is what a finished nefercap run leaves for the owner.
7+type shotResult struct {
8+ ready bool
9+ err error
10+}
11+
12+func (s *Service) onShotDone(r *shotResult) { _ = r }
A internal/adapters/screencast/seams.go +189 -0
@@ -0,0 +1,189 @@
1+package screencast
2+
3+import (
4+ "context"
5+ "errors"
6+ "fmt"
7+ "os"
8+ "os/exec"
9+ "runtime"
10+ "syscall"
11+ "time"
12+
13+ "github.com/bnema/neferwl/internal/adapters/peerexe"
14+ "github.com/bnema/purego-pipewire/pipewire"
15+ "github.com/bnema/zerobus"
16+)
17+
18+// bus is the part of a zerobus connection the service uses. Only Send and
19+// ReadMessage are used after startup: a connection has one encoder and one
20+// receive buffer, so Call and Handle are off limits.
21+type bus interface {
22+ NewReply(m *zerobus.Message, sig string) *zerobus.Encoder
23+ NewError(m *zerobus.Message, name, sig string) *zerobus.Encoder
24+ NewSignal(path, iface, member, sig string) *zerobus.Encoder
25+ NewSignalTo(dest, path, iface, member, sig string) *zerobus.Encoder
26+ NewMethodCall(dest, path, iface, member, sig string) (*zerobus.Encoder, uint32)
27+ Send() (uint32, error)
28+ ReadMessage() (*zerobus.Message, error)
29+ Buffered() bool
30+ SyscallConn() (syscall.RawConn, error)
31+ AddMatch(rule string) error
32+ RequestName(name string, flags uint32) (uint32, error)
33+ Close() error
34+}
35+
36+// videoSource is the part of a pipewire.VideoSource the producer uses. All
37+// calls run on the loop thread.
38+type videoSource interface {
39+ NodeID() uint32
40+ State() int32
41+ Dequeue() *pipewire.VideoBuffer
42+ Queue(b *pipewire.VideoBuffer, seq uint64, pts time.Duration, corrupted bool)
43+ Release(b *pipewire.VideoBuffer)
44+ Trigger()
45+ Resize(w, h int) error
46+ Destroy()
47+}
48+
49+// videoCore is a PipeWire connection driven by the service's own poll loop.
50+type videoCore interface {
51+ // Fd is the pollable descriptor of the loop.
52+ Fd() int
53+ // Iterate dispatches pending events; handler callbacks run inside it.
54+ Iterate()
55+ NewVideoSource(cfg pipewire.VideoConfig, h pipewire.VideoHandler) (videoSource, error)
56+ Close()
57+}
58+
59+// peerResolver proves which executable a D-Bus peer runs: Open pins the
60+// process behind a pid, Exe reads the executable through that pin.
61+type peerResolver interface {
62+ Open(pid int) (*os.File, error)
63+ Exe(pidfd *os.File) (exe string, pid int, err error)
64+}
65+
66+// runner runs nefercap with args.
67+type runner interface {
68+ Run(ctx context.Context, args []string) error
69+}
70+
71+// dialer connects the session bus (address empty) or the bus at address.
72+type dialer interface {
73+ Dial(address string) (bus, error)
74+}
75+
76+type zerobusDialer struct{}
77+
78+func (zerobusDialer) Dial(address string) (bus, error) {
79+ if address == "" {
80+ return zerobus.SessionBus()
81+ }
82+ return zerobus.Dial(address)
83+}
84+
85+// pipewireOpener connects to the PipeWire daemon. Open runs on the goroutine
86+// that stays locked to its OS thread: the loop belongs to that thread.
87+type pipewireOpener interface {
88+ Open() (videoCore, error)
89+}
90+
91+type realPipeWire struct{}
92+
93+func (realPipeWire) Open() (videoCore, error) { return openPipeWire() }
94+
95+// pidfdPeers is peerResolver over the pidfd proof of package peerexe.
96+type pidfdPeers struct{}
97+
98+func (pidfdPeers) Open(pid int) (*os.File, error) { return peerexe.Open(pid) }
99+
100+func (pidfdPeers) Exe(pidfd *os.File) (string, int, error) {
101+ exe, pid, err := peerexe.ExeOfPidfd(int(pidfd.Fd()))
102+ runtime.KeepAlive(pidfd)
103+ return exe, pid, err
104+}
105+
106+// nefercap is the program that takes the screenshots.
107+const nefercap = "nefercap"
108+
109+// execRunner runs nefercap in the session's environment (WAYLAND_DISPLAY
110+// names this compositor).
111+type execRunner struct{ env []string }
112+
113+func (r execRunner) Run(ctx context.Context, args []string) error {
114+ bin, err := exec.LookPath(nefercap)
115+ if err != nil {
116+ return err
117+ }
118+ cmd := exec.CommandContext(ctx, bin, args...)
119+ if len(r.env) > 0 {
120+ cmd.Env = r.env
121+ }
122+ out, err := cmd.CombinedOutput()
123+ if err != nil {
124+ if len(out) > 256 {
125+ out = out[len(out)-256:]
126+ }
127+ return fmt.Errorf("%s: %w: %s", nefercap, err, out)
128+ }
129+ return nil
130+}
131+
132+// pwLoop is videoCore over a real PipeWire loop, context and core.
133+type pwLoop struct {
134+ rt pipewire.Runtime
135+ loop pipewire.Loop
136+ ctx pipewire.Context
137+ core pipewire.Core
138+}
139+
140+// openPipeWire connects to the PipeWire daemon.
141+func openPipeWire() (videoCore, error) {
142+ rt, err := pipewire.Init()
143+ if err != nil {
144+ return nil, err
145+ }
146+ p := &pwLoop{rt: rt}
147+ if p.loop, err = rt.NewLoop(); err != nil {
148+ p.Close()
149+ return nil, err
150+ }
151+ if p.ctx, err = rt.NewContext(p.loop); err != nil {
152+ p.Close()
153+ return nil, err
154+ }
155+ if p.core, err = p.ctx.Connect(); err != nil {
156+ p.Close()
157+ return nil, err
158+ }
159+ return p, nil
160+}
161+
162+func (p *pwLoop) Fd() int { return p.loop.Fd() }
163+
164+func (p *pwLoop) Iterate() { p.loop.Iterate() }
165+
166+func (p *pwLoop) NewVideoSource(cfg pipewire.VideoConfig, h pipewire.VideoHandler) (videoSource, error) {
167+ vs, err := p.core.NewVideoSource(cfg, h)
168+ if err != nil {
169+ return nil, err
170+ }
171+ if vs == nil {
172+ return nil, errors.New("pipewire returned no video source")
173+ }
174+ return vs, nil
175+}
176+
177+// Close releases the connection, innermost first. Destroy the sources first.
178+func (p *pwLoop) Close() {
179+ if p.core != nil {
180+ p.core.Disconnect()
181+ }
182+ if p.ctx != nil {
183+ p.ctx.Destroy()
184+ }
185+ if p.loop != nil {
186+ p.loop.Destroy()
187+ }
188+ p.rt.Deinit()
189+}
@@ -0,0 +1,189 @@
1+package screencast
2+
3+import (
4+ "context"
5+ "errors"
6+ "fmt"
7+ "os"
8+ "os/exec"
9+ "runtime"
10+ "syscall"
11+ "time"
12+
13+ "github.com/bnema/neferwl/internal/adapters/peerexe"
14+ "github.com/bnema/purego-pipewire/pipewire"
15+ "github.com/bnema/zerobus"
16+)
17+
18+// bus is the part of a zerobus connection the service uses. Only Send and
19+// ReadMessage are used after startup: a connection has one encoder and one
20+// receive buffer, so Call and Handle are off limits.
21+type bus interface {
22+ NewReply(m *zerobus.Message, sig string) *zerobus.Encoder
23+ NewError(m *zerobus.Message, name, sig string) *zerobus.Encoder
24+ NewSignal(path, iface, member, sig string) *zerobus.Encoder
25+ NewSignalTo(dest, path, iface, member, sig string) *zerobus.Encoder
26+ NewMethodCall(dest, path, iface, member, sig string) (*zerobus.Encoder, uint32)
27+ Send() (uint32, error)
28+ ReadMessage() (*zerobus.Message, error)
29+ Buffered() bool
30+ SyscallConn() (syscall.RawConn, error)
31+ AddMatch(rule string) error
32+ RequestName(name string, flags uint32) (uint32, error)
33+ Close() error
34+}
35+
36+// videoSource is the part of a pipewire.VideoSource the producer uses. All
37+// calls run on the loop thread.
38+type videoSource interface {
39+ NodeID() uint32
40+ State() int32
41+ Dequeue() *pipewire.VideoBuffer
42+ Queue(b *pipewire.VideoBuffer, seq uint64, pts time.Duration, corrupted bool)
43+ Release(b *pipewire.VideoBuffer)
44+ Trigger()
45+ Resize(w, h int) error
46+ Destroy()
47+}
48+
49+// videoCore is a PipeWire connection driven by the service's own poll loop.
50+type videoCore interface {
51+ // Fd is the pollable descriptor of the loop.
52+ Fd() int
53+ // Iterate dispatches pending events; handler callbacks run inside it.
54+ Iterate()
55+ NewVideoSource(cfg pipewire.VideoConfig, h pipewire.VideoHandler) (videoSource, error)
56+ Close()
57+}
58+
59+// peerResolver proves which executable a D-Bus peer runs: Open pins the
60+// process behind a pid, Exe reads the executable through that pin.
61+type peerResolver interface {
62+ Open(pid int) (*os.File, error)
63+ Exe(pidfd *os.File) (exe string, pid int, err error)
64+}
65+
66+// runner runs nefercap with args.
67+type runner interface {
68+ Run(ctx context.Context, args []string) error
69+}
70+
71+// dialer connects the session bus (address empty) or the bus at address.
72+type dialer interface {
73+ Dial(address string) (bus, error)
74+}
75+
76+type zerobusDialer struct{}
77+
78+func (zerobusDialer) Dial(address string) (bus, error) {
79+ if address == "" {
80+ return zerobus.SessionBus()
81+ }
82+ return zerobus.Dial(address)
83+}
84+
85+// pipewireOpener connects to the PipeWire daemon. Open runs on the goroutine
86+// that stays locked to its OS thread: the loop belongs to that thread.
87+type pipewireOpener interface {
88+ Open() (videoCore, error)
89+}
90+
91+type realPipeWire struct{}
92+
93+func (realPipeWire) Open() (videoCore, error) { return openPipeWire() }
94+
95+// pidfdPeers is peerResolver over the pidfd proof of package peerexe.
96+type pidfdPeers struct{}
97+
98+func (pidfdPeers) Open(pid int) (*os.File, error) { return peerexe.Open(pid) }
99+
100+func (pidfdPeers) Exe(pidfd *os.File) (string, int, error) {
101+ exe, pid, err := peerexe.ExeOfPidfd(int(pidfd.Fd()))
102+ runtime.KeepAlive(pidfd)
103+ return exe, pid, err
104+}
105+
106+// nefercap is the program that takes the screenshots.
107+const nefercap = "nefercap"
108+
109+// execRunner runs nefercap in the session's environment (WAYLAND_DISPLAY
110+// names this compositor).
111+type execRunner struct{ env []string }
112+
113+func (r execRunner) Run(ctx context.Context, args []string) error {
114+ bin, err := exec.LookPath(nefercap)
115+ if err != nil {
116+ return err
117+ }
118+ cmd := exec.CommandContext(ctx, bin, args...)
119+ if len(r.env) > 0 {
120+ cmd.Env = r.env
121+ }
122+ out, err := cmd.CombinedOutput()
123+ if err != nil {
124+ if len(out) > 256 {
125+ out = out[len(out)-256:]
126+ }
127+ return fmt.Errorf("%s: %w: %s", nefercap, err, out)
128+ }
129+ return nil
130+}
131+
132+// pwLoop is videoCore over a real PipeWire loop, context and core.
133+type pwLoop struct {
134+ rt pipewire.Runtime
135+ loop pipewire.Loop
136+ ctx pipewire.Context
137+ core pipewire.Core
138+}
139+
140+// openPipeWire connects to the PipeWire daemon.
141+func openPipeWire() (videoCore, error) {
142+ rt, err := pipewire.Init()
143+ if err != nil {
144+ return nil, err
145+ }
146+ p := &pwLoop{rt: rt}
147+ if p.loop, err = rt.NewLoop(); err != nil {
148+ p.Close()
149+ return nil, err
150+ }
151+ if p.ctx, err = rt.NewContext(p.loop); err != nil {
152+ p.Close()
153+ return nil, err
154+ }
155+ if p.core, err = p.ctx.Connect(); err != nil {
156+ p.Close()
157+ return nil, err
158+ }
159+ return p, nil
160+}
161+
162+func (p *pwLoop) Fd() int { return p.loop.Fd() }
163+
164+func (p *pwLoop) Iterate() { p.loop.Iterate() }
165+
166+func (p *pwLoop) NewVideoSource(cfg pipewire.VideoConfig, h pipewire.VideoHandler) (videoSource, error) {
167+ vs, err := p.core.NewVideoSource(cfg, h)
168+ if err != nil {
169+ return nil, err
170+ }
171+ if vs == nil {
172+ return nil, errors.New("pipewire returned no video source")
173+ }
174+ return vs, nil
175+}
176+
177+// Close releases the connection, innermost first. Destroy the sources first.
178+func (p *pwLoop) Close() {
179+ if p.core != nil {
180+ p.core.Disconnect()
181+ }
182+ if p.ctx != nil {
183+ p.ctx.Destroy()
184+ }
185+ if p.loop != nil {
186+ p.loop.Destroy()
187+ }
188+ p.rt.Deinit()
189+}
A internal/adapters/screencast/stream.go +26 -0
@@ -0,0 +1,26 @@
1+package screencast
2+
3+import (
4+ "time"
5+
6+ "github.com/bnema/neferwl/internal/ports"
7+)
8+
9+// stream is one cast of a session.
10+type stream struct {
11+ used bool
12+ dirty bool
13+}
14+
15+func (s *Service) onCastEvent(ev *ports.CastEvent) { _ = ev }
16+
17+func (s *Service) forEachStream(f func(*stream)) {
18+ for i := range s.sessions {
19+ _ = f
20+ _ = i
21+ }
22+}
23+
24+func (s *Service) pumpAll(now time.Time) {}
25+func (s *Service) reap() {}
26+func (s *Service) streamsLive() bool { return false }
@@ -0,0 +1,26 @@
1+package screencast
2+
3+import (
4+ "time"
5+
6+ "github.com/bnema/neferwl/internal/ports"
7+)
8+
9+// stream is one cast of a session.
10+type stream struct {
11+ used bool
12+ dirty bool
13+}
14+
15+func (s *Service) onCastEvent(ev *ports.CastEvent) { _ = ev }
16+
17+func (s *Service) forEachStream(f func(*stream)) {
18+ for i := range s.sessions {
19+ _ = f
20+ _ = i
21+ }
22+}
23+
24+func (s *Service) pumpAll(now time.Time) {}
25+func (s *Service) reap() {}
26+func (s *Service) streamsLive() bool { return false }
A internal/adapters/screencast/video_core_mock_test.go +224 -0
@@ -0,0 +1,224 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package screencast
6+
7+import (
8+ "github.com/bnema/purego-pipewire/pipewire"
9+ mock "github.com/stretchr/testify/mock"
10+)
11+
12+// newMockvideoCore creates a new instance of mockvideoCore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
13+// The first argument is typically a *testing.T value.
14+func newMockvideoCore(t interface {
15+ mock.TestingT
16+ Cleanup(func())
17+}) *mockvideoCore {
18+ if helper, ok := t.(interface{ Helper() }); ok {
19+ helper.Helper()
20+ }
21+
22+ mock := &mockvideoCore{}
23+ mock.Mock.Test(t)
24+
25+ t.Cleanup(func() {
26+ if helper, ok := t.(interface{ Helper() }); ok {
27+ helper.Helper()
28+ }
29+ mock.AssertExpectations(t)
30+ })
31+
32+ return mock
33+}
34+
35+// mockvideoCore is an autogenerated mock type for the videoCore type
36+type mockvideoCore struct {
37+ mock.Mock
38+}
39+
40+type mockvideoCore_Expecter struct {
41+ mock *mock.Mock
42+}
43+
44+func (_m *mockvideoCore) EXPECT() *mockvideoCore_Expecter {
45+ return &mockvideoCore_Expecter{mock: &_m.Mock}
46+}
47+
48+// Close provides a mock function for the type mockvideoCore
49+func (_mock *mockvideoCore) Close() {
50+ _mock.Called()
51+ return
52+}
53+
54+// mockvideoCore_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
55+type mockvideoCore_Close_Call struct {
56+ *mock.Call
57+}
58+
59+// Close is a helper method to define mock.On call
60+func (_e *mockvideoCore_Expecter) Close() *mockvideoCore_Close_Call {
61+ return &mockvideoCore_Close_Call{Call: _e.mock.On("Close")}
62+}
63+
64+func (_c *mockvideoCore_Close_Call) Run(run func()) *mockvideoCore_Close_Call {
65+ _c.Call.Run(func(args mock.Arguments) {
66+ run()
67+ })
68+ return _c
69+}
70+
71+func (_c *mockvideoCore_Close_Call) Return() *mockvideoCore_Close_Call {
72+ _c.Call.Return()
73+ return _c
74+}
75+
76+func (_c *mockvideoCore_Close_Call) RunAndReturn(run func()) *mockvideoCore_Close_Call {
77+ _c.Run(run)
78+ return _c
79+}
80+
81+// Fd provides a mock function for the type mockvideoCore
82+func (_mock *mockvideoCore) Fd() int {
83+ ret := _mock.Called()
84+
85+ if len(ret) == 0 {
86+ panic("no return value specified for Fd")
87+ }
88+
89+ var r0 int
90+ if returnFunc, ok := ret.Get(0).(func() int); ok {
91+ r0 = returnFunc()
92+ } else {
93+ r0 = ret.Get(0).(int)
94+ }
95+ return r0
96+}
97+
98+// mockvideoCore_Fd_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Fd'
99+type mockvideoCore_Fd_Call struct {
100+ *mock.Call
101+}
102+
103+// Fd is a helper method to define mock.On call
104+func (_e *mockvideoCore_Expecter) Fd() *mockvideoCore_Fd_Call {
105+ return &mockvideoCore_Fd_Call{Call: _e.mock.On("Fd")}
106+}
107+
108+func (_c *mockvideoCore_Fd_Call) Run(run func()) *mockvideoCore_Fd_Call {
109+ _c.Call.Run(func(args mock.Arguments) {
110+ run()
111+ })
112+ return _c
113+}
114+
115+func (_c *mockvideoCore_Fd_Call) Return(n int) *mockvideoCore_Fd_Call {
116+ _c.Call.Return(n)
117+ return _c
118+}
119+
120+func (_c *mockvideoCore_Fd_Call) RunAndReturn(run func() int) *mockvideoCore_Fd_Call {
121+ _c.Call.Return(run)
122+ return _c
123+}
124+
125+// Iterate provides a mock function for the type mockvideoCore
126+func (_mock *mockvideoCore) Iterate() {
127+ _mock.Called()
128+ return
129+}
130+
131+// mockvideoCore_Iterate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Iterate'
132+type mockvideoCore_Iterate_Call struct {
133+ *mock.Call
134+}
135+
136+// Iterate is a helper method to define mock.On call
137+func (_e *mockvideoCore_Expecter) Iterate() *mockvideoCore_Iterate_Call {
138+ return &mockvideoCore_Iterate_Call{Call: _e.mock.On("Iterate")}
139+}
140+
141+func (_c *mockvideoCore_Iterate_Call) Run(run func()) *mockvideoCore_Iterate_Call {
142+ _c.Call.Run(func(args mock.Arguments) {
143+ run()
144+ })
145+ return _c
146+}
147+
148+func (_c *mockvideoCore_Iterate_Call) Return() *mockvideoCore_Iterate_Call {
149+ _c.Call.Return()
150+ return _c
151+}
152+
153+func (_c *mockvideoCore_Iterate_Call) RunAndReturn(run func()) *mockvideoCore_Iterate_Call {
154+ _c.Run(run)
155+ return _c
156+}
157+
158+// NewVideoSource provides a mock function for the type mockvideoCore
159+func (_mock *mockvideoCore) NewVideoSource(cfg pipewire.VideoConfig, h pipewire.VideoHandler) (videoSource, error) {
160+ ret := _mock.Called(cfg, h)
161+
162+ if len(ret) == 0 {
163+ panic("no return value specified for NewVideoSource")
164+ }
165+
166+ var r0 videoSource
167+ var r1 error
168+ if returnFunc, ok := ret.Get(0).(func(pipewire.VideoConfig, pipewire.VideoHandler) (videoSource, error)); ok {
169+ return returnFunc(cfg, h)
170+ }
171+ if returnFunc, ok := ret.Get(0).(func(pipewire.VideoConfig, pipewire.VideoHandler) videoSource); ok {
172+ r0 = returnFunc(cfg, h)
173+ } else {
174+ if ret.Get(0) != nil {
175+ r0 = ret.Get(0).(videoSource)
176+ }
177+ }
178+ if returnFunc, ok := ret.Get(1).(func(pipewire.VideoConfig, pipewire.VideoHandler) error); ok {
179+ r1 = returnFunc(cfg, h)
180+ } else {
181+ r1 = ret.Error(1)
182+ }
183+ return r0, r1
184+}
185+
186+// mockvideoCore_NewVideoSource_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewVideoSource'
187+type mockvideoCore_NewVideoSource_Call struct {
188+ *mock.Call
189+}
190+
191+// NewVideoSource is a helper method to define mock.On call
192+// - cfg pipewire.VideoConfig
193+// - h pipewire.VideoHandler
194+func (_e *mockvideoCore_Expecter) NewVideoSource(cfg any, h any) *mockvideoCore_NewVideoSource_Call {
195+ return &mockvideoCore_NewVideoSource_Call{Call: _e.mock.On("NewVideoSource", cfg, h)}
196+}
197+
198+func (_c *mockvideoCore_NewVideoSource_Call) Run(run func(cfg pipewire.VideoConfig, h pipewire.VideoHandler)) *mockvideoCore_NewVideoSource_Call {
199+ _c.Call.Run(func(args mock.Arguments) {
200+ var arg0 pipewire.VideoConfig
201+ if args[0] != nil {
202+ arg0 = args[0].(pipewire.VideoConfig)
203+ }
204+ var arg1 pipewire.VideoHandler
205+ if args[1] != nil {
206+ arg1 = args[1].(pipewire.VideoHandler)
207+ }
208+ run(
209+ arg0,
210+ arg1,
211+ )
212+ })
213+ return _c
214+}
215+
216+func (_c *mockvideoCore_NewVideoSource_Call) Return(videoSourceMoqParam videoSource, err error) *mockvideoCore_NewVideoSource_Call {
217+ _c.Call.Return(videoSourceMoqParam, err)
218+ return _c
219+}
220+
221+func (_c *mockvideoCore_NewVideoSource_Call) RunAndReturn(run func(cfg pipewire.VideoConfig, h pipewire.VideoHandler) (videoSource, error)) *mockvideoCore_NewVideoSource_Call {
222+ _c.Call.Return(run)
223+ return _c
224+}
@@ -0,0 +1,224 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package screencast
6+
7+import (
8+ "github.com/bnema/purego-pipewire/pipewire"
9+ mock "github.com/stretchr/testify/mock"
10+)
11+
12+// newMockvideoCore creates a new instance of mockvideoCore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
13+// The first argument is typically a *testing.T value.
14+func newMockvideoCore(t interface {
15+ mock.TestingT
16+ Cleanup(func())
17+}) *mockvideoCore {
18+ if helper, ok := t.(interface{ Helper() }); ok {
19+ helper.Helper()
20+ }
21+
22+ mock := &mockvideoCore{}
23+ mock.Mock.Test(t)
24+
25+ t.Cleanup(func() {
26+ if helper, ok := t.(interface{ Helper() }); ok {
27+ helper.Helper()
28+ }
29+ mock.AssertExpectations(t)
30+ })
31+
32+ return mock
33+}
34+
35+// mockvideoCore is an autogenerated mock type for the videoCore type
36+type mockvideoCore struct {
37+ mock.Mock
38+}
39+
40+type mockvideoCore_Expecter struct {
41+ mock *mock.Mock
42+}
43+
44+func (_m *mockvideoCore) EXPECT() *mockvideoCore_Expecter {
45+ return &mockvideoCore_Expecter{mock: &_m.Mock}
46+}
47+
48+// Close provides a mock function for the type mockvideoCore
49+func (_mock *mockvideoCore) Close() {
50+ _mock.Called()
51+ return
52+}
53+
54+// mockvideoCore_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
55+type mockvideoCore_Close_Call struct {
56+ *mock.Call
57+}
58+
59+// Close is a helper method to define mock.On call
60+func (_e *mockvideoCore_Expecter) Close() *mockvideoCore_Close_Call {
61+ return &mockvideoCore_Close_Call{Call: _e.mock.On("Close")}
62+}
63+
64+func (_c *mockvideoCore_Close_Call) Run(run func()) *mockvideoCore_Close_Call {
65+ _c.Call.Run(func(args mock.Arguments) {
66+ run()
67+ })
68+ return _c
69+}
70+
71+func (_c *mockvideoCore_Close_Call) Return() *mockvideoCore_Close_Call {
72+ _c.Call.Return()
73+ return _c
74+}
75+
76+func (_c *mockvideoCore_Close_Call) RunAndReturn(run func()) *mockvideoCore_Close_Call {
77+ _c.Run(run)
78+ return _c
79+}
80+
81+// Fd provides a mock function for the type mockvideoCore
82+func (_mock *mockvideoCore) Fd() int {
83+ ret := _mock.Called()
84+
85+ if len(ret) == 0 {
86+ panic("no return value specified for Fd")
87+ }
88+
89+ var r0 int
90+ if returnFunc, ok := ret.Get(0).(func() int); ok {
91+ r0 = returnFunc()
92+ } else {
93+ r0 = ret.Get(0).(int)
94+ }
95+ return r0
96+}
97+
98+// mockvideoCore_Fd_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Fd'
99+type mockvideoCore_Fd_Call struct {
100+ *mock.Call
101+}
102+
103+// Fd is a helper method to define mock.On call
104+func (_e *mockvideoCore_Expecter) Fd() *mockvideoCore_Fd_Call {
105+ return &mockvideoCore_Fd_Call{Call: _e.mock.On("Fd")}
106+}
107+
108+func (_c *mockvideoCore_Fd_Call) Run(run func()) *mockvideoCore_Fd_Call {
109+ _c.Call.Run(func(args mock.Arguments) {
110+ run()
111+ })
112+ return _c
113+}
114+
115+func (_c *mockvideoCore_Fd_Call) Return(n int) *mockvideoCore_Fd_Call {
116+ _c.Call.Return(n)
117+ return _c
118+}
119+
120+func (_c *mockvideoCore_Fd_Call) RunAndReturn(run func() int) *mockvideoCore_Fd_Call {
121+ _c.Call.Return(run)
122+ return _c
123+}
124+
125+// Iterate provides a mock function for the type mockvideoCore
126+func (_mock *mockvideoCore) Iterate() {
127+ _mock.Called()
128+ return
129+}
130+
131+// mockvideoCore_Iterate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Iterate'
132+type mockvideoCore_Iterate_Call struct {
133+ *mock.Call
134+}
135+
136+// Iterate is a helper method to define mock.On call
137+func (_e *mockvideoCore_Expecter) Iterate() *mockvideoCore_Iterate_Call {
138+ return &mockvideoCore_Iterate_Call{Call: _e.mock.On("Iterate")}
139+}
140+
141+func (_c *mockvideoCore_Iterate_Call) Run(run func()) *mockvideoCore_Iterate_Call {
142+ _c.Call.Run(func(args mock.Arguments) {
143+ run()
144+ })
145+ return _c
146+}
147+
148+func (_c *mockvideoCore_Iterate_Call) Return() *mockvideoCore_Iterate_Call {
149+ _c.Call.Return()
150+ return _c
151+}
152+
153+func (_c *mockvideoCore_Iterate_Call) RunAndReturn(run func()) *mockvideoCore_Iterate_Call {
154+ _c.Run(run)
155+ return _c
156+}
157+
158+// NewVideoSource provides a mock function for the type mockvideoCore
159+func (_mock *mockvideoCore) NewVideoSource(cfg pipewire.VideoConfig, h pipewire.VideoHandler) (videoSource, error) {
160+ ret := _mock.Called(cfg, h)
161+
162+ if len(ret) == 0 {
163+ panic("no return value specified for NewVideoSource")
164+ }
165+
166+ var r0 videoSource
167+ var r1 error
168+ if returnFunc, ok := ret.Get(0).(func(pipewire.VideoConfig, pipewire.VideoHandler) (videoSource, error)); ok {
169+ return returnFunc(cfg, h)
170+ }
171+ if returnFunc, ok := ret.Get(0).(func(pipewire.VideoConfig, pipewire.VideoHandler) videoSource); ok {
172+ r0 = returnFunc(cfg, h)
173+ } else {
174+ if ret.Get(0) != nil {
175+ r0 = ret.Get(0).(videoSource)
176+ }
177+ }
178+ if returnFunc, ok := ret.Get(1).(func(pipewire.VideoConfig, pipewire.VideoHandler) error); ok {
179+ r1 = returnFunc(cfg, h)
180+ } else {
181+ r1 = ret.Error(1)
182+ }
183+ return r0, r1
184+}
185+
186+// mockvideoCore_NewVideoSource_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewVideoSource'
187+type mockvideoCore_NewVideoSource_Call struct {
188+ *mock.Call
189+}
190+
191+// NewVideoSource is a helper method to define mock.On call
192+// - cfg pipewire.VideoConfig
193+// - h pipewire.VideoHandler
194+func (_e *mockvideoCore_Expecter) NewVideoSource(cfg any, h any) *mockvideoCore_NewVideoSource_Call {
195+ return &mockvideoCore_NewVideoSource_Call{Call: _e.mock.On("NewVideoSource", cfg, h)}
196+}
197+
198+func (_c *mockvideoCore_NewVideoSource_Call) Run(run func(cfg pipewire.VideoConfig, h pipewire.VideoHandler)) *mockvideoCore_NewVideoSource_Call {
199+ _c.Call.Run(func(args mock.Arguments) {
200+ var arg0 pipewire.VideoConfig
201+ if args[0] != nil {
202+ arg0 = args[0].(pipewire.VideoConfig)
203+ }
204+ var arg1 pipewire.VideoHandler
205+ if args[1] != nil {
206+ arg1 = args[1].(pipewire.VideoHandler)
207+ }
208+ run(
209+ arg0,
210+ arg1,
211+ )
212+ })
213+ return _c
214+}
215+
216+func (_c *mockvideoCore_NewVideoSource_Call) Return(videoSourceMoqParam videoSource, err error) *mockvideoCore_NewVideoSource_Call {
217+ _c.Call.Return(videoSourceMoqParam, err)
218+ return _c
219+}
220+
221+func (_c *mockvideoCore_NewVideoSource_Call) RunAndReturn(run func(cfg pipewire.VideoConfig, h pipewire.VideoHandler) (videoSource, error)) *mockvideoCore_NewVideoSource_Call {
222+ _c.Call.Return(run)
223+ return _c
224+}
A internal/adapters/screencast/video_source_mock_test.go +403 -0
@@ -0,0 +1,403 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package screencast
6+
7+import (
8+ "time"
9+
10+ "github.com/bnema/purego-pipewire/pipewire"
11+ mock "github.com/stretchr/testify/mock"
12+)
13+
14+// newMockvideoSource creates a new instance of mockvideoSource. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
15+// The first argument is typically a *testing.T value.
16+func newMockvideoSource(t interface {
17+ mock.TestingT
18+ Cleanup(func())
19+}) *mockvideoSource {
20+ if helper, ok := t.(interface{ Helper() }); ok {
21+ helper.Helper()
22+ }
23+
24+ mock := &mockvideoSource{}
25+ mock.Mock.Test(t)
26+
27+ t.Cleanup(func() {
28+ if helper, ok := t.(interface{ Helper() }); ok {
29+ helper.Helper()
30+ }
31+ mock.AssertExpectations(t)
32+ })
33+
34+ return mock
35+}
36+
37+// mockvideoSource is an autogenerated mock type for the videoSource type
38+type mockvideoSource struct {
39+ mock.Mock
40+}
41+
42+type mockvideoSource_Expecter struct {
43+ mock *mock.Mock
44+}
45+
46+func (_m *mockvideoSource) EXPECT() *mockvideoSource_Expecter {
47+ return &mockvideoSource_Expecter{mock: &_m.Mock}
48+}
49+
50+// Dequeue provides a mock function for the type mockvideoSource
51+func (_mock *mockvideoSource) Dequeue() *pipewire.VideoBuffer {
52+ ret := _mock.Called()
53+
54+ if len(ret) == 0 {
55+ panic("no return value specified for Dequeue")
56+ }
57+
58+ var r0 *pipewire.VideoBuffer
59+ if returnFunc, ok := ret.Get(0).(func() *pipewire.VideoBuffer); ok {
60+ r0 = returnFunc()
61+ } else {
62+ if ret.Get(0) != nil {
63+ r0 = ret.Get(0).(*pipewire.VideoBuffer)
64+ }
65+ }
66+ return r0
67+}
68+
69+// mockvideoSource_Dequeue_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Dequeue'
70+type mockvideoSource_Dequeue_Call struct {
71+ *mock.Call
72+}
73+
74+// Dequeue is a helper method to define mock.On call
75+func (_e *mockvideoSource_Expecter) Dequeue() *mockvideoSource_Dequeue_Call {
76+ return &mockvideoSource_Dequeue_Call{Call: _e.mock.On("Dequeue")}
77+}
78+
79+func (_c *mockvideoSource_Dequeue_Call) Run(run func()) *mockvideoSource_Dequeue_Call {
80+ _c.Call.Run(func(args mock.Arguments) {
81+ run()
82+ })
83+ return _c
84+}
85+
86+func (_c *mockvideoSource_Dequeue_Call) Return(videoBuffer *pipewire.VideoBuffer) *mockvideoSource_Dequeue_Call {
87+ _c.Call.Return(videoBuffer)
88+ return _c
89+}
90+
91+func (_c *mockvideoSource_Dequeue_Call) RunAndReturn(run func() *pipewire.VideoBuffer) *mockvideoSource_Dequeue_Call {
92+ _c.Call.Return(run)
93+ return _c
94+}
95+
96+// Destroy provides a mock function for the type mockvideoSource
97+func (_mock *mockvideoSource) Destroy() {
98+ _mock.Called()
99+ return
100+}
101+
102+// mockvideoSource_Destroy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Destroy'
103+type mockvideoSource_Destroy_Call struct {
104+ *mock.Call
105+}
106+
107+// Destroy is a helper method to define mock.On call
108+func (_e *mockvideoSource_Expecter) Destroy() *mockvideoSource_Destroy_Call {
109+ return &mockvideoSource_Destroy_Call{Call: _e.mock.On("Destroy")}
110+}
111+
112+func (_c *mockvideoSource_Destroy_Call) Run(run func()) *mockvideoSource_Destroy_Call {
113+ _c.Call.Run(func(args mock.Arguments) {
114+ run()
115+ })
116+ return _c
117+}
118+
119+func (_c *mockvideoSource_Destroy_Call) Return() *mockvideoSource_Destroy_Call {
120+ _c.Call.Return()
121+ return _c
122+}
123+
124+func (_c *mockvideoSource_Destroy_Call) RunAndReturn(run func()) *mockvideoSource_Destroy_Call {
125+ _c.Run(run)
126+ return _c
127+}
128+
129+// NodeID provides a mock function for the type mockvideoSource
130+func (_mock *mockvideoSource) NodeID() uint32 {
131+ ret := _mock.Called()
132+
133+ if len(ret) == 0 {
134+ panic("no return value specified for NodeID")
135+ }
136+
137+ var r0 uint32
138+ if returnFunc, ok := ret.Get(0).(func() uint32); ok {
139+ r0 = returnFunc()
140+ } else {
141+ r0 = ret.Get(0).(uint32)
142+ }
143+ return r0
144+}
145+
146+// mockvideoSource_NodeID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NodeID'
147+type mockvideoSource_NodeID_Call struct {
148+ *mock.Call
149+}
150+
151+// NodeID is a helper method to define mock.On call
152+func (_e *mockvideoSource_Expecter) NodeID() *mockvideoSource_NodeID_Call {
153+ return &mockvideoSource_NodeID_Call{Call: _e.mock.On("NodeID")}
154+}
155+
156+func (_c *mockvideoSource_NodeID_Call) Run(run func()) *mockvideoSource_NodeID_Call {
157+ _c.Call.Run(func(args mock.Arguments) {
158+ run()
159+ })
160+ return _c
161+}
162+
163+func (_c *mockvideoSource_NodeID_Call) Return(v uint32) *mockvideoSource_NodeID_Call {
164+ _c.Call.Return(v)
165+ return _c
166+}
167+
168+func (_c *mockvideoSource_NodeID_Call) RunAndReturn(run func() uint32) *mockvideoSource_NodeID_Call {
169+ _c.Call.Return(run)
170+ return _c
171+}
172+
173+// Queue provides a mock function for the type mockvideoSource
174+func (_mock *mockvideoSource) Queue(b *pipewire.VideoBuffer, seq uint64, pts time.Duration, corrupted bool) {
175+ _mock.Called(b, seq, pts, corrupted)
176+ return
177+}
178+
179+// mockvideoSource_Queue_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Queue'
180+type mockvideoSource_Queue_Call struct {
181+ *mock.Call
182+}
183+
184+// Queue is a helper method to define mock.On call
185+// - b *pipewire.VideoBuffer
186+// - seq uint64
187+// - pts time.Duration
188+// - corrupted bool
189+func (_e *mockvideoSource_Expecter) Queue(b any, seq any, pts any, corrupted any) *mockvideoSource_Queue_Call {
190+ return &mockvideoSource_Queue_Call{Call: _e.mock.On("Queue", b, seq, pts, corrupted)}
191+}
192+
193+func (_c *mockvideoSource_Queue_Call) Run(run func(b *pipewire.VideoBuffer, seq uint64, pts time.Duration, corrupted bool)) *mockvideoSource_Queue_Call {
194+ _c.Call.Run(func(args mock.Arguments) {
195+ var arg0 *pipewire.VideoBuffer
196+ if args[0] != nil {
197+ arg0 = args[0].(*pipewire.VideoBuffer)
198+ }
199+ var arg1 uint64
200+ if args[1] != nil {
201+ arg1 = args[1].(uint64)
202+ }
203+ var arg2 time.Duration
204+ if args[2] != nil {
205+ arg2 = args[2].(time.Duration)
206+ }
207+ var arg3 bool
208+ if args[3] != nil {
209+ arg3 = args[3].(bool)
210+ }
211+ run(
212+ arg0,
213+ arg1,
214+ arg2,
215+ arg3,
216+ )
217+ })
218+ return _c
219+}
220+
221+func (_c *mockvideoSource_Queue_Call) Return() *mockvideoSource_Queue_Call {
222+ _c.Call.Return()
223+ return _c
224+}
225+
226+func (_c *mockvideoSource_Queue_Call) RunAndReturn(run func(b *pipewire.VideoBuffer, seq uint64, pts time.Duration, corrupted bool)) *mockvideoSource_Queue_Call {
227+ _c.Run(run)
228+ return _c
229+}
230+
231+// Release provides a mock function for the type mockvideoSource
232+func (_mock *mockvideoSource) Release(b *pipewire.VideoBuffer) {
233+ _mock.Called(b)
234+ return
235+}
236+
237+// mockvideoSource_Release_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Release'
238+type mockvideoSource_Release_Call struct {
239+ *mock.Call
240+}
241+
242+// Release is a helper method to define mock.On call
243+// - b *pipewire.VideoBuffer
244+func (_e *mockvideoSource_Expecter) Release(b any) *mockvideoSource_Release_Call {
245+ return &mockvideoSource_Release_Call{Call: _e.mock.On("Release", b)}
246+}
247+
248+func (_c *mockvideoSource_Release_Call) Run(run func(b *pipewire.VideoBuffer)) *mockvideoSource_Release_Call {
249+ _c.Call.Run(func(args mock.Arguments) {
250+ var arg0 *pipewire.VideoBuffer
251+ if args[0] != nil {
252+ arg0 = args[0].(*pipewire.VideoBuffer)
253+ }
254+ run(
255+ arg0,
256+ )
257+ })
258+ return _c
259+}
260+
261+func (_c *mockvideoSource_Release_Call) Return() *mockvideoSource_Release_Call {
262+ _c.Call.Return()
263+ return _c
264+}
265+
266+func (_c *mockvideoSource_Release_Call) RunAndReturn(run func(b *pipewire.VideoBuffer)) *mockvideoSource_Release_Call {
267+ _c.Run(run)
268+ return _c
269+}
270+
271+// Resize provides a mock function for the type mockvideoSource
272+func (_mock *mockvideoSource) Resize(w int, h int) error {
273+ ret := _mock.Called(w, h)
274+
275+ if len(ret) == 0 {
276+ panic("no return value specified for Resize")
277+ }
278+
279+ var r0 error
280+ if returnFunc, ok := ret.Get(0).(func(int, int) error); ok {
281+ r0 = returnFunc(w, h)
282+ } else {
283+ r0 = ret.Error(0)
284+ }
285+ return r0
286+}
287+
288+// mockvideoSource_Resize_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Resize'
289+type mockvideoSource_Resize_Call struct {
290+ *mock.Call
291+}
292+
293+// Resize is a helper method to define mock.On call
294+// - w int
295+// - h int
296+func (_e *mockvideoSource_Expecter) Resize(w any, h any) *mockvideoSource_Resize_Call {
297+ return &mockvideoSource_Resize_Call{Call: _e.mock.On("Resize", w, h)}
298+}
299+
300+func (_c *mockvideoSource_Resize_Call) Run(run func(w int, h int)) *mockvideoSource_Resize_Call {
301+ _c.Call.Run(func(args mock.Arguments) {
302+ var arg0 int
303+ if args[0] != nil {
304+ arg0 = args[0].(int)
305+ }
306+ var arg1 int
307+ if args[1] != nil {
308+ arg1 = args[1].(int)
309+ }
310+ run(
311+ arg0,
312+ arg1,
313+ )
314+ })
315+ return _c
316+}
317+
318+func (_c *mockvideoSource_Resize_Call) Return(err error) *mockvideoSource_Resize_Call {
319+ _c.Call.Return(err)
320+ return _c
321+}
322+
323+func (_c *mockvideoSource_Resize_Call) RunAndReturn(run func(w int, h int) error) *mockvideoSource_Resize_Call {
324+ _c.Call.Return(run)
325+ return _c
326+}
327+
328+// State provides a mock function for the type mockvideoSource
329+func (_mock *mockvideoSource) State() int32 {
330+ ret := _mock.Called()
331+
332+ if len(ret) == 0 {
333+ panic("no return value specified for State")
334+ }
335+
336+ var r0 int32
337+ if returnFunc, ok := ret.Get(0).(func() int32); ok {
338+ r0 = returnFunc()
339+ } else {
340+ r0 = ret.Get(0).(int32)
341+ }
342+ return r0
343+}
344+
345+// mockvideoSource_State_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'State'
346+type mockvideoSource_State_Call struct {
347+ *mock.Call
348+}
349+
350+// State is a helper method to define mock.On call
351+func (_e *mockvideoSource_Expecter) State() *mockvideoSource_State_Call {
352+ return &mockvideoSource_State_Call{Call: _e.mock.On("State")}
353+}
354+
355+func (_c *mockvideoSource_State_Call) Run(run func()) *mockvideoSource_State_Call {
356+ _c.Call.Run(func(args mock.Arguments) {
357+ run()
358+ })
359+ return _c
360+}
361+
362+func (_c *mockvideoSource_State_Call) Return(n int32) *mockvideoSource_State_Call {
363+ _c.Call.Return(n)
364+ return _c
365+}
366+
367+func (_c *mockvideoSource_State_Call) RunAndReturn(run func() int32) *mockvideoSource_State_Call {
368+ _c.Call.Return(run)
369+ return _c
370+}
371+
372+// Trigger provides a mock function for the type mockvideoSource
373+func (_mock *mockvideoSource) Trigger() {
374+ _mock.Called()
375+ return
376+}
377+
378+// mockvideoSource_Trigger_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Trigger'
379+type mockvideoSource_Trigger_Call struct {
380+ *mock.Call
381+}
382+
383+// Trigger is a helper method to define mock.On call
384+func (_e *mockvideoSource_Expecter) Trigger() *mockvideoSource_Trigger_Call {
385+ return &mockvideoSource_Trigger_Call{Call: _e.mock.On("Trigger")}
386+}
387+
388+func (_c *mockvideoSource_Trigger_Call) Run(run func()) *mockvideoSource_Trigger_Call {
389+ _c.Call.Run(func(args mock.Arguments) {
390+ run()
391+ })
392+ return _c
393+}
394+
395+func (_c *mockvideoSource_Trigger_Call) Return() *mockvideoSource_Trigger_Call {
396+ _c.Call.Return()
397+ return _c
398+}
399+
400+func (_c *mockvideoSource_Trigger_Call) RunAndReturn(run func()) *mockvideoSource_Trigger_Call {
401+ _c.Run(run)
402+ return _c
403+}
@@ -0,0 +1,403 @@
1+// Code generated by mockery; DO NOT EDIT.
2+// github.com/vektra/mockery
3+// template: testify
4+
5+package screencast
6+
7+import (
8+ "time"
9+
10+ "github.com/bnema/purego-pipewire/pipewire"
11+ mock "github.com/stretchr/testify/mock"
12+)
13+
14+// newMockvideoSource creates a new instance of mockvideoSource. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
15+// The first argument is typically a *testing.T value.
16+func newMockvideoSource(t interface {
17+ mock.TestingT
18+ Cleanup(func())
19+}) *mockvideoSource {
20+ if helper, ok := t.(interface{ Helper() }); ok {
21+ helper.Helper()
22+ }
23+
24+ mock := &mockvideoSource{}
25+ mock.Mock.Test(t)
26+
27+ t.Cleanup(func() {
28+ if helper, ok := t.(interface{ Helper() }); ok {
29+ helper.Helper()
30+ }
31+ mock.AssertExpectations(t)
32+ })
33+
34+ return mock
35+}
36+
37+// mockvideoSource is an autogenerated mock type for the videoSource type
38+type mockvideoSource struct {
39+ mock.Mock
40+}
41+
42+type mockvideoSource_Expecter struct {
43+ mock *mock.Mock
44+}
45+
46+func (_m *mockvideoSource) EXPECT() *mockvideoSource_Expecter {
47+ return &mockvideoSource_Expecter{mock: &_m.Mock}
48+}
49+
50+// Dequeue provides a mock function for the type mockvideoSource
51+func (_mock *mockvideoSource) Dequeue() *pipewire.VideoBuffer {
52+ ret := _mock.Called()
53+
54+ if len(ret) == 0 {
55+ panic("no return value specified for Dequeue")
56+ }
57+
58+ var r0 *pipewire.VideoBuffer
59+ if returnFunc, ok := ret.Get(0).(func() *pipewire.VideoBuffer); ok {
60+ r0 = returnFunc()
61+ } else {
62+ if ret.Get(0) != nil {
63+ r0 = ret.Get(0).(*pipewire.VideoBuffer)
64+ }
65+ }
66+ return r0
67+}
68+
69+// mockvideoSource_Dequeue_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Dequeue'
70+type mockvideoSource_Dequeue_Call struct {
71+ *mock.Call
72+}
73+
74+// Dequeue is a helper method to define mock.On call
75+func (_e *mockvideoSource_Expecter) Dequeue() *mockvideoSource_Dequeue_Call {
76+ return &mockvideoSource_Dequeue_Call{Call: _e.mock.On("Dequeue")}
77+}
78+
79+func (_c *mockvideoSource_Dequeue_Call) Run(run func()) *mockvideoSource_Dequeue_Call {
80+ _c.Call.Run(func(args mock.Arguments) {
81+ run()
82+ })
83+ return _c
84+}
85+
86+func (_c *mockvideoSource_Dequeue_Call) Return(videoBuffer *pipewire.VideoBuffer) *mockvideoSource_Dequeue_Call {
87+ _c.Call.Return(videoBuffer)
88+ return _c
89+}
90+
91+func (_c *mockvideoSource_Dequeue_Call) RunAndReturn(run func() *pipewire.VideoBuffer) *mockvideoSource_Dequeue_Call {
92+ _c.Call.Return(run)
93+ return _c
94+}
95+
96+// Destroy provides a mock function for the type mockvideoSource
97+func (_mock *mockvideoSource) Destroy() {
98+ _mock.Called()
99+ return
100+}
101+
102+// mockvideoSource_Destroy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Destroy'
103+type mockvideoSource_Destroy_Call struct {
104+ *mock.Call
105+}
106+
107+// Destroy is a helper method to define mock.On call
108+func (_e *mockvideoSource_Expecter) Destroy() *mockvideoSource_Destroy_Call {
109+ return &mockvideoSource_Destroy_Call{Call: _e.mock.On("Destroy")}
110+}
111+
112+func (_c *mockvideoSource_Destroy_Call) Run(run func()) *mockvideoSource_Destroy_Call {
113+ _c.Call.Run(func(args mock.Arguments) {
114+ run()
115+ })
116+ return _c
117+}
118+
119+func (_c *mockvideoSource_Destroy_Call) Return() *mockvideoSource_Destroy_Call {
120+ _c.Call.Return()
121+ return _c
122+}
123+
124+func (_c *mockvideoSource_Destroy_Call) RunAndReturn(run func()) *mockvideoSource_Destroy_Call {
125+ _c.Run(run)
126+ return _c
127+}
128+
129+// NodeID provides a mock function for the type mockvideoSource
130+func (_mock *mockvideoSource) NodeID() uint32 {
131+ ret := _mock.Called()
132+
133+ if len(ret) == 0 {
134+ panic("no return value specified for NodeID")
135+ }
136+
137+ var r0 uint32
138+ if returnFunc, ok := ret.Get(0).(func() uint32); ok {
139+ r0 = returnFunc()
140+ } else {
141+ r0 = ret.Get(0).(uint32)
142+ }
143+ return r0
144+}
145+
146+// mockvideoSource_NodeID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NodeID'
147+type mockvideoSource_NodeID_Call struct {
148+ *mock.Call
149+}
150+
151+// NodeID is a helper method to define mock.On call
152+func (_e *mockvideoSource_Expecter) NodeID() *mockvideoSource_NodeID_Call {
153+ return &mockvideoSource_NodeID_Call{Call: _e.mock.On("NodeID")}
154+}
155+
156+func (_c *mockvideoSource_NodeID_Call) Run(run func()) *mockvideoSource_NodeID_Call {
157+ _c.Call.Run(func(args mock.Arguments) {
158+ run()
159+ })
160+ return _c
161+}
162+
163+func (_c *mockvideoSource_NodeID_Call) Return(v uint32) *mockvideoSource_NodeID_Call {
164+ _c.Call.Return(v)
165+ return _c
166+}
167+
168+func (_c *mockvideoSource_NodeID_Call) RunAndReturn(run func() uint32) *mockvideoSource_NodeID_Call {
169+ _c.Call.Return(run)
170+ return _c
171+}
172+
173+// Queue provides a mock function for the type mockvideoSource
174+func (_mock *mockvideoSource) Queue(b *pipewire.VideoBuffer, seq uint64, pts time.Duration, corrupted bool) {
175+ _mock.Called(b, seq, pts, corrupted)
176+ return
177+}
178+
179+// mockvideoSource_Queue_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Queue'
180+type mockvideoSource_Queue_Call struct {
181+ *mock.Call
182+}
183+
184+// Queue is a helper method to define mock.On call
185+// - b *pipewire.VideoBuffer
186+// - seq uint64
187+// - pts time.Duration
188+// - corrupted bool
189+func (_e *mockvideoSource_Expecter) Queue(b any, seq any, pts any, corrupted any) *mockvideoSource_Queue_Call {
190+ return &mockvideoSource_Queue_Call{Call: _e.mock.On("Queue", b, seq, pts, corrupted)}
191+}
192+
193+func (_c *mockvideoSource_Queue_Call) Run(run func(b *pipewire.VideoBuffer, seq uint64, pts time.Duration, corrupted bool)) *mockvideoSource_Queue_Call {
194+ _c.Call.Run(func(args mock.Arguments) {
195+ var arg0 *pipewire.VideoBuffer
196+ if args[0] != nil {
197+ arg0 = args[0].(*pipewire.VideoBuffer)
198+ }
199+ var arg1 uint64
200+ if args[1] != nil {
201+ arg1 = args[1].(uint64)
202+ }
203+ var arg2 time.Duration
204+ if args[2] != nil {
205+ arg2 = args[2].(time.Duration)
206+ }
207+ var arg3 bool
208+ if args[3] != nil {
209+ arg3 = args[3].(bool)
210+ }
211+ run(
212+ arg0,
213+ arg1,
214+ arg2,
215+ arg3,
216+ )
217+ })
218+ return _c
219+}
220+
221+func (_c *mockvideoSource_Queue_Call) Return() *mockvideoSource_Queue_Call {
222+ _c.Call.Return()
223+ return _c
224+}
225+
226+func (_c *mockvideoSource_Queue_Call) RunAndReturn(run func(b *pipewire.VideoBuffer, seq uint64, pts time.Duration, corrupted bool)) *mockvideoSource_Queue_Call {
227+ _c.Run(run)
228+ return _c
229+}
230+
231+// Release provides a mock function for the type mockvideoSource
232+func (_mock *mockvideoSource) Release(b *pipewire.VideoBuffer) {
233+ _mock.Called(b)
234+ return
235+}
236+
237+// mockvideoSource_Release_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Release'
238+type mockvideoSource_Release_Call struct {
239+ *mock.Call
240+}
241+
242+// Release is a helper method to define mock.On call
243+// - b *pipewire.VideoBuffer
244+func (_e *mockvideoSource_Expecter) Release(b any) *mockvideoSource_Release_Call {
245+ return &mockvideoSource_Release_Call{Call: _e.mock.On("Release", b)}
246+}
247+
248+func (_c *mockvideoSource_Release_Call) Run(run func(b *pipewire.VideoBuffer)) *mockvideoSource_Release_Call {
249+ _c.Call.Run(func(args mock.Arguments) {
250+ var arg0 *pipewire.VideoBuffer
251+ if args[0] != nil {
252+ arg0 = args[0].(*pipewire.VideoBuffer)
253+ }
254+ run(
255+ arg0,
256+ )
257+ })
258+ return _c
259+}
260+
261+func (_c *mockvideoSource_Release_Call) Return() *mockvideoSource_Release_Call {
262+ _c.Call.Return()
263+ return _c
264+}
265+
266+func (_c *mockvideoSource_Release_Call) RunAndReturn(run func(b *pipewire.VideoBuffer)) *mockvideoSource_Release_Call {
267+ _c.Run(run)
268+ return _c
269+}
270+
271+// Resize provides a mock function for the type mockvideoSource
272+func (_mock *mockvideoSource) Resize(w int, h int) error {
273+ ret := _mock.Called(w, h)
274+
275+ if len(ret) == 0 {
276+ panic("no return value specified for Resize")
277+ }
278+
279+ var r0 error
280+ if returnFunc, ok := ret.Get(0).(func(int, int) error); ok {
281+ r0 = returnFunc(w, h)
282+ } else {
283+ r0 = ret.Error(0)
284+ }
285+ return r0
286+}
287+
288+// mockvideoSource_Resize_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Resize'
289+type mockvideoSource_Resize_Call struct {
290+ *mock.Call
291+}
292+
293+// Resize is a helper method to define mock.On call
294+// - w int
295+// - h int
296+func (_e *mockvideoSource_Expecter) Resize(w any, h any) *mockvideoSource_Resize_Call {
297+ return &mockvideoSource_Resize_Call{Call: _e.mock.On("Resize", w, h)}
298+}
299+
300+func (_c *mockvideoSource_Resize_Call) Run(run func(w int, h int)) *mockvideoSource_Resize_Call {
301+ _c.Call.Run(func(args mock.Arguments) {
302+ var arg0 int
303+ if args[0] != nil {
304+ arg0 = args[0].(int)
305+ }
306+ var arg1 int
307+ if args[1] != nil {
308+ arg1 = args[1].(int)
309+ }
310+ run(
311+ arg0,
312+ arg1,
313+ )
314+ })
315+ return _c
316+}
317+
318+func (_c *mockvideoSource_Resize_Call) Return(err error) *mockvideoSource_Resize_Call {
319+ _c.Call.Return(err)
320+ return _c
321+}
322+
323+func (_c *mockvideoSource_Resize_Call) RunAndReturn(run func(w int, h int) error) *mockvideoSource_Resize_Call {
324+ _c.Call.Return(run)
325+ return _c
326+}
327+
328+// State provides a mock function for the type mockvideoSource
329+func (_mock *mockvideoSource) State() int32 {
330+ ret := _mock.Called()
331+
332+ if len(ret) == 0 {
333+ panic("no return value specified for State")
334+ }
335+
336+ var r0 int32
337+ if returnFunc, ok := ret.Get(0).(func() int32); ok {
338+ r0 = returnFunc()
339+ } else {
340+ r0 = ret.Get(0).(int32)
341+ }
342+ return r0
343+}
344+
345+// mockvideoSource_State_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'State'
346+type mockvideoSource_State_Call struct {
347+ *mock.Call
348+}
349+
350+// State is a helper method to define mock.On call
351+func (_e *mockvideoSource_Expecter) State() *mockvideoSource_State_Call {
352+ return &mockvideoSource_State_Call{Call: _e.mock.On("State")}
353+}
354+
355+func (_c *mockvideoSource_State_Call) Run(run func()) *mockvideoSource_State_Call {
356+ _c.Call.Run(func(args mock.Arguments) {
357+ run()
358+ })
359+ return _c
360+}
361+
362+func (_c *mockvideoSource_State_Call) Return(n int32) *mockvideoSource_State_Call {
363+ _c.Call.Return(n)
364+ return _c
365+}
366+
367+func (_c *mockvideoSource_State_Call) RunAndReturn(run func() int32) *mockvideoSource_State_Call {
368+ _c.Call.Return(run)
369+ return _c
370+}
371+
372+// Trigger provides a mock function for the type mockvideoSource
373+func (_mock *mockvideoSource) Trigger() {
374+ _mock.Called()
375+ return
376+}
377+
378+// mockvideoSource_Trigger_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Trigger'
379+type mockvideoSource_Trigger_Call struct {
380+ *mock.Call
381+}
382+
383+// Trigger is a helper method to define mock.On call
384+func (_e *mockvideoSource_Expecter) Trigger() *mockvideoSource_Trigger_Call {
385+ return &mockvideoSource_Trigger_Call{Call: _e.mock.On("Trigger")}
386+}
387+
388+func (_c *mockvideoSource_Trigger_Call) Run(run func()) *mockvideoSource_Trigger_Call {
389+ _c.Call.Run(func(args mock.Arguments) {
390+ run()
391+ })
392+ return _c
393+}
394+
395+func (_c *mockvideoSource_Trigger_Call) Return() *mockvideoSource_Trigger_Call {
396+ _c.Call.Return()
397+ return _c
398+}
399+
400+func (_c *mockvideoSource_Trigger_Call) RunAndReturn(run func()) *mockvideoSource_Trigger_Call {
401+ _c.Run(run)
402+ return _c
403+}

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 24

Tags 10

↑↓ moveenter openesc close