detached cd00fc0

feat: add surface event kinds, Handler methods and shared types

commit
cd00fc05677d9913e26830434673ec126f5ed22c
author
brice · · 2026-10-01 16:32 UTC
parent
23ac271
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
5 files · +395 -1
M conn.go +1 -0
@@ -579,5 +579,6 @@ func (c *Conn) Close() error {
579579 if c.efd >= 0 {
580580 _ = unix.Close(c.efd)
581581 }
582+ c.q.closeFDs() // both producers are gone: close what nobody will drain
582583 return err
583584 }
@@ -579,5 +579,6 @@ func (c *Conn) Close() error {
579 if c.efd >= 0 {579 if c.efd >= 0 {
580 _ = unix.Close(c.efd)580 _ = unix.Close(c.efd)
581 }581 }
582+ c.q.closeFDs() // both producers are gone: close what nobody will drain
582 return err583 return err
583 }584 }
M handler.go +35 -0
@@ -23,6 +23,33 @@ type Handler interface {
2323 // a wl_output that could not be bound. Fatal transport errors are returned
2424 // by Dispatch instead.
2525 Error(err error)
26+
27+ // Configure reports the logical size of a surface after the compositor's
28+ // configure was acknowledged (the library acks internally). The first
29+ // call makes the surface presentable. For layer surfaces an axis the
30+ // compositor leaves unchanged keeps its previous size.
31+ Configure(id SurfaceID, width, height int32)
32+ // Scale reports a changed preferred scale: fractional (n/120) when the
33+ // compositor supports wp_fractional_scale, else the integer buffer scale.
34+ // Re-read [Surface.PhysicalSize] and render again.
35+ Scale(id SurfaceID, scale float64)
36+ // Frame reports that the frame callback requested by the last
37+ // [Surface.Present] fired; the next Present is allowed.
38+ Frame(id SurfaceID)
39+ // Closed reports that the compositor closed the surface (toplevel close,
40+ // layer surface closed). Call [Surface.Close]; nothing else happens
41+ // automatically.
42+ Closed(id SurfaceID)
43+ // FeedbackDone reports that a complete linux-dmabuf feedback round was
44+ // applied; [Surface.Feedback] holds the new main device and formats. It
45+ // is sent again whenever the compositor changes its preference.
46+ FeedbackDone(id SurfaceID)
47+ // Locked reports ext_session_lock_v1.locked for the live [Lock]: every
48+ // output is protected. Only now may [Lock.Unlock] be called.
49+ Locked()
50+ // LockFinished reports ext_session_lock_v1.finished: the compositor
51+ // refused or ended the lock. Destroy it with [Lock.Close].
52+ LockFinished()
2653 }
2754
2855 // NopHandler implements every Handler method as a no-op. Embed it in a handler
@@ -34,3 +61,11 @@ func (NopHandler) OutputAdded(*Output) {}
3461 func (NopHandler) OutputRemoved(uint32) {}
3562 func (NopHandler) FDReady(uint64) {}
3663 func (NopHandler) Error(error) {}
64+
65+func (NopHandler) Configure(SurfaceID, int32, int32) {}
66+func (NopHandler) Scale(SurfaceID, float64) {}
67+func (NopHandler) Frame(SurfaceID) {}
68+func (NopHandler) Closed(SurfaceID) {}
69+func (NopHandler) FeedbackDone(SurfaceID) {}
70+func (NopHandler) Locked() {}
71+func (NopHandler) LockFinished() {}
@@ -23,6 +23,33 @@ type Handler interface {
23 // a wl_output that could not be bound. Fatal transport errors are returned23 // a wl_output that could not be bound. Fatal transport errors are returned
24 // by Dispatch instead.24 // by Dispatch instead.
25 Error(err error)25 Error(err error)
26+
27+ // Configure reports the logical size of a surface after the compositor's
28+ // configure was acknowledged (the library acks internally). The first
29+ // call makes the surface presentable. For layer surfaces an axis the
30+ // compositor leaves unchanged keeps its previous size.
31+ Configure(id SurfaceID, width, height int32)
32+ // Scale reports a changed preferred scale: fractional (n/120) when the
33+ // compositor supports wp_fractional_scale, else the integer buffer scale.
34+ // Re-read [Surface.PhysicalSize] and render again.
35+ Scale(id SurfaceID, scale float64)
36+ // Frame reports that the frame callback requested by the last
37+ // [Surface.Present] fired; the next Present is allowed.
38+ Frame(id SurfaceID)
39+ // Closed reports that the compositor closed the surface (toplevel close,
40+ // layer surface closed). Call [Surface.Close]; nothing else happens
41+ // automatically.
42+ Closed(id SurfaceID)
43+ // FeedbackDone reports that a complete linux-dmabuf feedback round was
44+ // applied; [Surface.Feedback] holds the new main device and formats. It
45+ // is sent again whenever the compositor changes its preference.
46+ FeedbackDone(id SurfaceID)
47+ // Locked reports ext_session_lock_v1.locked for the live [Lock]: every
48+ // output is protected. Only now may [Lock.Unlock] be called.
49+ Locked()
50+ // LockFinished reports ext_session_lock_v1.finished: the compositor
51+ // refused or ended the lock. Destroy it with [Lock.Close].
52+ LockFinished()
26 }53 }
27 54
28 // NopHandler implements every Handler method as a no-op. Embed it in a handler55 // NopHandler implements every Handler method as a no-op. Embed it in a handler
@@ -34,3 +61,11 @@ func (NopHandler) OutputAdded(*Output) {}
34 func (NopHandler) OutputRemoved(uint32) {}61 func (NopHandler) OutputRemoved(uint32) {}
35 func (NopHandler) FDReady(uint64) {}62 func (NopHandler) FDReady(uint64) {}
36 func (NopHandler) Error(error) {}63 func (NopHandler) Error(error) {}
64+
65+func (NopHandler) Configure(SurfaceID, int32, int32) {}
66+func (NopHandler) Scale(SurfaceID, float64) {}
67+func (NopHandler) Frame(SurfaceID) {}
68+func (NopHandler) Closed(SurfaceID) {}
69+func (NopHandler) FeedbackDone(SurfaceID) {}
70+func (NopHandler) Locked() {}
71+func (NopHandler) LockFinished() {}
M mocks/handler_mock.go +284 -0
@@ -45,6 +45,98 @@ func (_m *MockHandler) EXPECT() *MockHandler_Expecter {
4545 return &MockHandler_Expecter{mock: &_m.Mock}
4646 }
4747
48+// Closed provides a mock function for the type MockHandler
49+func (_mock *MockHandler) Closed(id neferclient.SurfaceID) {
50+ _mock.Called(id)
51+ return
52+}
53+
54+// MockHandler_Closed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Closed'
55+type MockHandler_Closed_Call struct {
56+ *mock.Call
57+}
58+
59+// Closed is a helper method to define mock.On call
60+// - id neferclient.SurfaceID
61+func (_e *MockHandler_Expecter) Closed(id any) *MockHandler_Closed_Call {
62+ return &MockHandler_Closed_Call{Call: _e.mock.On("Closed", id)}
63+}
64+
65+func (_c *MockHandler_Closed_Call) Run(run func(id neferclient.SurfaceID)) *MockHandler_Closed_Call {
66+ _c.Call.Run(func(args mock.Arguments) {
67+ var arg0 neferclient.SurfaceID
68+ if args[0] != nil {
69+ arg0 = args[0].(neferclient.SurfaceID)
70+ }
71+ run(
72+ arg0,
73+ )
74+ })
75+ return _c
76+}
77+
78+func (_c *MockHandler_Closed_Call) Return() *MockHandler_Closed_Call {
79+ _c.Call.Return()
80+ return _c
81+}
82+
83+func (_c *MockHandler_Closed_Call) RunAndReturn(run func(id neferclient.SurfaceID)) *MockHandler_Closed_Call {
84+ _c.Run(run)
85+ return _c
86+}
87+
88+// Configure provides a mock function for the type MockHandler
89+func (_mock *MockHandler) Configure(id neferclient.SurfaceID, width int32, height int32) {
90+ _mock.Called(id, width, height)
91+ return
92+}
93+
94+// MockHandler_Configure_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Configure'
95+type MockHandler_Configure_Call struct {
96+ *mock.Call
97+}
98+
99+// Configure is a helper method to define mock.On call
100+// - id neferclient.SurfaceID
101+// - width int32
102+// - height int32
103+func (_e *MockHandler_Expecter) Configure(id any, width any, height any) *MockHandler_Configure_Call {
104+ return &MockHandler_Configure_Call{Call: _e.mock.On("Configure", id, width, height)}
105+}
106+
107+func (_c *MockHandler_Configure_Call) Run(run func(id neferclient.SurfaceID, width int32, height int32)) *MockHandler_Configure_Call {
108+ _c.Call.Run(func(args mock.Arguments) {
109+ var arg0 neferclient.SurfaceID
110+ if args[0] != nil {
111+ arg0 = args[0].(neferclient.SurfaceID)
112+ }
113+ var arg1 int32
114+ if args[1] != nil {
115+ arg1 = args[1].(int32)
116+ }
117+ var arg2 int32
118+ if args[2] != nil {
119+ arg2 = args[2].(int32)
120+ }
121+ run(
122+ arg0,
123+ arg1,
124+ arg2,
125+ )
126+ })
127+ return _c
128+}
129+
130+func (_c *MockHandler_Configure_Call) Return() *MockHandler_Configure_Call {
131+ _c.Call.Return()
132+ return _c
133+}
134+
135+func (_c *MockHandler_Configure_Call) RunAndReturn(run func(id neferclient.SurfaceID, width int32, height int32)) *MockHandler_Configure_Call {
136+ _c.Run(run)
137+ return _c
138+}
139+
48140 // Error provides a mock function for the type MockHandler
49141 func (_mock *MockHandler) Error(err error) {
50142 _mock.Called(err)
@@ -125,6 +217,152 @@ func (_c *MockHandler_FDReady_Call) RunAndReturn(run func(id uint64)) *MockHandl
125217 return _c
126218 }
127219
220+// FeedbackDone provides a mock function for the type MockHandler
221+func (_mock *MockHandler) FeedbackDone(id neferclient.SurfaceID) {
222+ _mock.Called(id)
223+ return
224+}
225+
226+// MockHandler_FeedbackDone_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FeedbackDone'
227+type MockHandler_FeedbackDone_Call struct {
228+ *mock.Call
229+}
230+
231+// FeedbackDone is a helper method to define mock.On call
232+// - id neferclient.SurfaceID
233+func (_e *MockHandler_Expecter) FeedbackDone(id any) *MockHandler_FeedbackDone_Call {
234+ return &MockHandler_FeedbackDone_Call{Call: _e.mock.On("FeedbackDone", id)}
235+}
236+
237+func (_c *MockHandler_FeedbackDone_Call) Run(run func(id neferclient.SurfaceID)) *MockHandler_FeedbackDone_Call {
238+ _c.Call.Run(func(args mock.Arguments) {
239+ var arg0 neferclient.SurfaceID
240+ if args[0] != nil {
241+ arg0 = args[0].(neferclient.SurfaceID)
242+ }
243+ run(
244+ arg0,
245+ )
246+ })
247+ return _c
248+}
249+
250+func (_c *MockHandler_FeedbackDone_Call) Return() *MockHandler_FeedbackDone_Call {
251+ _c.Call.Return()
252+ return _c
253+}
254+
255+func (_c *MockHandler_FeedbackDone_Call) RunAndReturn(run func(id neferclient.SurfaceID)) *MockHandler_FeedbackDone_Call {
256+ _c.Run(run)
257+ return _c
258+}
259+
260+// Frame provides a mock function for the type MockHandler
261+func (_mock *MockHandler) Frame(id neferclient.SurfaceID) {
262+ _mock.Called(id)
263+ return
264+}
265+
266+// MockHandler_Frame_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Frame'
267+type MockHandler_Frame_Call struct {
268+ *mock.Call
269+}
270+
271+// Frame is a helper method to define mock.On call
272+// - id neferclient.SurfaceID
273+func (_e *MockHandler_Expecter) Frame(id any) *MockHandler_Frame_Call {
274+ return &MockHandler_Frame_Call{Call: _e.mock.On("Frame", id)}
275+}
276+
277+func (_c *MockHandler_Frame_Call) Run(run func(id neferclient.SurfaceID)) *MockHandler_Frame_Call {
278+ _c.Call.Run(func(args mock.Arguments) {
279+ var arg0 neferclient.SurfaceID
280+ if args[0] != nil {
281+ arg0 = args[0].(neferclient.SurfaceID)
282+ }
283+ run(
284+ arg0,
285+ )
286+ })
287+ return _c
288+}
289+
290+func (_c *MockHandler_Frame_Call) Return() *MockHandler_Frame_Call {
291+ _c.Call.Return()
292+ return _c
293+}
294+
295+func (_c *MockHandler_Frame_Call) RunAndReturn(run func(id neferclient.SurfaceID)) *MockHandler_Frame_Call {
296+ _c.Run(run)
297+ return _c
298+}
299+
300+// LockFinished provides a mock function for the type MockHandler
301+func (_mock *MockHandler) LockFinished() {
302+ _mock.Called()
303+ return
304+}
305+
306+// MockHandler_LockFinished_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LockFinished'
307+type MockHandler_LockFinished_Call struct {
308+ *mock.Call
309+}
310+
311+// LockFinished is a helper method to define mock.On call
312+func (_e *MockHandler_Expecter) LockFinished() *MockHandler_LockFinished_Call {
313+ return &MockHandler_LockFinished_Call{Call: _e.mock.On("LockFinished")}
314+}
315+
316+func (_c *MockHandler_LockFinished_Call) Run(run func()) *MockHandler_LockFinished_Call {
317+ _c.Call.Run(func(args mock.Arguments) {
318+ run()
319+ })
320+ return _c
321+}
322+
323+func (_c *MockHandler_LockFinished_Call) Return() *MockHandler_LockFinished_Call {
324+ _c.Call.Return()
325+ return _c
326+}
327+
328+func (_c *MockHandler_LockFinished_Call) RunAndReturn(run func()) *MockHandler_LockFinished_Call {
329+ _c.Run(run)
330+ return _c
331+}
332+
333+// Locked provides a mock function for the type MockHandler
334+func (_mock *MockHandler) Locked() {
335+ _mock.Called()
336+ return
337+}
338+
339+// MockHandler_Locked_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Locked'
340+type MockHandler_Locked_Call struct {
341+ *mock.Call
342+}
343+
344+// Locked is a helper method to define mock.On call
345+func (_e *MockHandler_Expecter) Locked() *MockHandler_Locked_Call {
346+ return &MockHandler_Locked_Call{Call: _e.mock.On("Locked")}
347+}
348+
349+func (_c *MockHandler_Locked_Call) Run(run func()) *MockHandler_Locked_Call {
350+ _c.Call.Run(func(args mock.Arguments) {
351+ run()
352+ })
353+ return _c
354+}
355+
356+func (_c *MockHandler_Locked_Call) Return() *MockHandler_Locked_Call {
357+ _c.Call.Return()
358+ return _c
359+}
360+
361+func (_c *MockHandler_Locked_Call) RunAndReturn(run func()) *MockHandler_Locked_Call {
362+ _c.Run(run)
363+ return _c
364+}
365+
128366 // OutputAdded provides a mock function for the type MockHandler
129367 func (_mock *MockHandler) OutputAdded(out *neferclient.Output) {
130368 _mock.Called(out)
@@ -204,3 +442,49 @@ func (_c *MockHandler_OutputRemoved_Call) RunAndReturn(run func(global uint32))
204442 _c.Run(run)
205443 return _c
206444 }
445+
446+// Scale provides a mock function for the type MockHandler
447+func (_mock *MockHandler) Scale(id neferclient.SurfaceID, scale float64) {
448+ _mock.Called(id, scale)
449+ return
450+}
451+
452+// MockHandler_Scale_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Scale'
453+type MockHandler_Scale_Call struct {
454+ *mock.Call
455+}
456+
457+// Scale is a helper method to define mock.On call
458+// - id neferclient.SurfaceID
459+// - scale float64
460+func (_e *MockHandler_Expecter) Scale(id any, scale any) *MockHandler_Scale_Call {
461+ return &MockHandler_Scale_Call{Call: _e.mock.On("Scale", id, scale)}
462+}
463+
464+func (_c *MockHandler_Scale_Call) Run(run func(id neferclient.SurfaceID, scale float64)) *MockHandler_Scale_Call {
465+ _c.Call.Run(func(args mock.Arguments) {
466+ var arg0 neferclient.SurfaceID
467+ if args[0] != nil {
468+ arg0 = args[0].(neferclient.SurfaceID)
469+ }
470+ var arg1 float64
471+ if args[1] != nil {
472+ arg1 = args[1].(float64)
473+ }
474+ run(
475+ arg0,
476+ arg1,
477+ )
478+ })
479+ return _c
480+}
481+
482+func (_c *MockHandler_Scale_Call) Return() *MockHandler_Scale_Call {
483+ _c.Call.Return()
484+ return _c
485+}
486+
487+func (_c *MockHandler_Scale_Call) RunAndReturn(run func(id neferclient.SurfaceID, scale float64)) *MockHandler_Scale_Call {
488+ _c.Run(run)
489+ return _c
490+}
@@ -45,6 +45,98 @@ func (_m *MockHandler) EXPECT() *MockHandler_Expecter {
45 return &MockHandler_Expecter{mock: &_m.Mock}45 return &MockHandler_Expecter{mock: &_m.Mock}
46 }46 }
47 47
48+// Closed provides a mock function for the type MockHandler
49+func (_mock *MockHandler) Closed(id neferclient.SurfaceID) {
50+ _mock.Called(id)
51+ return
52+}
53+
54+// MockHandler_Closed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Closed'
55+type MockHandler_Closed_Call struct {
56+ *mock.Call
57+}
58+
59+// Closed is a helper method to define mock.On call
60+// - id neferclient.SurfaceID
61+func (_e *MockHandler_Expecter) Closed(id any) *MockHandler_Closed_Call {
62+ return &MockHandler_Closed_Call{Call: _e.mock.On("Closed", id)}
63+}
64+
65+func (_c *MockHandler_Closed_Call) Run(run func(id neferclient.SurfaceID)) *MockHandler_Closed_Call {
66+ _c.Call.Run(func(args mock.Arguments) {
67+ var arg0 neferclient.SurfaceID
68+ if args[0] != nil {
69+ arg0 = args[0].(neferclient.SurfaceID)
70+ }
71+ run(
72+ arg0,
73+ )
74+ })
75+ return _c
76+}
77+
78+func (_c *MockHandler_Closed_Call) Return() *MockHandler_Closed_Call {
79+ _c.Call.Return()
80+ return _c
81+}
82+
83+func (_c *MockHandler_Closed_Call) RunAndReturn(run func(id neferclient.SurfaceID)) *MockHandler_Closed_Call {
84+ _c.Run(run)
85+ return _c
86+}
87+
88+// Configure provides a mock function for the type MockHandler
89+func (_mock *MockHandler) Configure(id neferclient.SurfaceID, width int32, height int32) {
90+ _mock.Called(id, width, height)
91+ return
92+}
93+
94+// MockHandler_Configure_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Configure'
95+type MockHandler_Configure_Call struct {
96+ *mock.Call
97+}
98+
99+// Configure is a helper method to define mock.On call
100+// - id neferclient.SurfaceID
101+// - width int32
102+// - height int32
103+func (_e *MockHandler_Expecter) Configure(id any, width any, height any) *MockHandler_Configure_Call {
104+ return &MockHandler_Configure_Call{Call: _e.mock.On("Configure", id, width, height)}
105+}
106+
107+func (_c *MockHandler_Configure_Call) Run(run func(id neferclient.SurfaceID, width int32, height int32)) *MockHandler_Configure_Call {
108+ _c.Call.Run(func(args mock.Arguments) {
109+ var arg0 neferclient.SurfaceID
110+ if args[0] != nil {
111+ arg0 = args[0].(neferclient.SurfaceID)
112+ }
113+ var arg1 int32
114+ if args[1] != nil {
115+ arg1 = args[1].(int32)
116+ }
117+ var arg2 int32
118+ if args[2] != nil {
119+ arg2 = args[2].(int32)
120+ }
121+ run(
122+ arg0,
123+ arg1,
124+ arg2,
125+ )
126+ })
127+ return _c
128+}
129+
130+func (_c *MockHandler_Configure_Call) Return() *MockHandler_Configure_Call {
131+ _c.Call.Return()
132+ return _c
133+}
134+
135+func (_c *MockHandler_Configure_Call) RunAndReturn(run func(id neferclient.SurfaceID, width int32, height int32)) *MockHandler_Configure_Call {
136+ _c.Run(run)
137+ return _c
138+}
139+
48 // Error provides a mock function for the type MockHandler140 // Error provides a mock function for the type MockHandler
49 func (_mock *MockHandler) Error(err error) {141 func (_mock *MockHandler) Error(err error) {
50 _mock.Called(err)142 _mock.Called(err)
@@ -125,6 +217,152 @@ func (_c *MockHandler_FDReady_Call) RunAndReturn(run func(id uint64)) *MockHandl
125 return _c217 return _c
126 }218 }
127 219
220+// FeedbackDone provides a mock function for the type MockHandler
221+func (_mock *MockHandler) FeedbackDone(id neferclient.SurfaceID) {
222+ _mock.Called(id)
223+ return
224+}
225+
226+// MockHandler_FeedbackDone_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FeedbackDone'
227+type MockHandler_FeedbackDone_Call struct {
228+ *mock.Call
229+}
230+
231+// FeedbackDone is a helper method to define mock.On call
232+// - id neferclient.SurfaceID
233+func (_e *MockHandler_Expecter) FeedbackDone(id any) *MockHandler_FeedbackDone_Call {
234+ return &MockHandler_FeedbackDone_Call{Call: _e.mock.On("FeedbackDone", id)}
235+}
236+
237+func (_c *MockHandler_FeedbackDone_Call) Run(run func(id neferclient.SurfaceID)) *MockHandler_FeedbackDone_Call {
238+ _c.Call.Run(func(args mock.Arguments) {
239+ var arg0 neferclient.SurfaceID
240+ if args[0] != nil {
241+ arg0 = args[0].(neferclient.SurfaceID)
242+ }
243+ run(
244+ arg0,
245+ )
246+ })
247+ return _c
248+}
249+
250+func (_c *MockHandler_FeedbackDone_Call) Return() *MockHandler_FeedbackDone_Call {
251+ _c.Call.Return()
252+ return _c
253+}
254+
255+func (_c *MockHandler_FeedbackDone_Call) RunAndReturn(run func(id neferclient.SurfaceID)) *MockHandler_FeedbackDone_Call {
256+ _c.Run(run)
257+ return _c
258+}
259+
260+// Frame provides a mock function for the type MockHandler
261+func (_mock *MockHandler) Frame(id neferclient.SurfaceID) {
262+ _mock.Called(id)
263+ return
264+}
265+
266+// MockHandler_Frame_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Frame'
267+type MockHandler_Frame_Call struct {
268+ *mock.Call
269+}
270+
271+// Frame is a helper method to define mock.On call
272+// - id neferclient.SurfaceID
273+func (_e *MockHandler_Expecter) Frame(id any) *MockHandler_Frame_Call {
274+ return &MockHandler_Frame_Call{Call: _e.mock.On("Frame", id)}
275+}
276+
277+func (_c *MockHandler_Frame_Call) Run(run func(id neferclient.SurfaceID)) *MockHandler_Frame_Call {
278+ _c.Call.Run(func(args mock.Arguments) {
279+ var arg0 neferclient.SurfaceID
280+ if args[0] != nil {
281+ arg0 = args[0].(neferclient.SurfaceID)
282+ }
283+ run(
284+ arg0,
285+ )
286+ })
287+ return _c
288+}
289+
290+func (_c *MockHandler_Frame_Call) Return() *MockHandler_Frame_Call {
291+ _c.Call.Return()
292+ return _c
293+}
294+
295+func (_c *MockHandler_Frame_Call) RunAndReturn(run func(id neferclient.SurfaceID)) *MockHandler_Frame_Call {
296+ _c.Run(run)
297+ return _c
298+}
299+
300+// LockFinished provides a mock function for the type MockHandler
301+func (_mock *MockHandler) LockFinished() {
302+ _mock.Called()
303+ return
304+}
305+
306+// MockHandler_LockFinished_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LockFinished'
307+type MockHandler_LockFinished_Call struct {
308+ *mock.Call
309+}
310+
311+// LockFinished is a helper method to define mock.On call
312+func (_e *MockHandler_Expecter) LockFinished() *MockHandler_LockFinished_Call {
313+ return &MockHandler_LockFinished_Call{Call: _e.mock.On("LockFinished")}
314+}
315+
316+func (_c *MockHandler_LockFinished_Call) Run(run func()) *MockHandler_LockFinished_Call {
317+ _c.Call.Run(func(args mock.Arguments) {
318+ run()
319+ })
320+ return _c
321+}
322+
323+func (_c *MockHandler_LockFinished_Call) Return() *MockHandler_LockFinished_Call {
324+ _c.Call.Return()
325+ return _c
326+}
327+
328+func (_c *MockHandler_LockFinished_Call) RunAndReturn(run func()) *MockHandler_LockFinished_Call {
329+ _c.Run(run)
330+ return _c
331+}
332+
333+// Locked provides a mock function for the type MockHandler
334+func (_mock *MockHandler) Locked() {
335+ _mock.Called()
336+ return
337+}
338+
339+// MockHandler_Locked_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Locked'
340+type MockHandler_Locked_Call struct {
341+ *mock.Call
342+}
343+
344+// Locked is a helper method to define mock.On call
345+func (_e *MockHandler_Expecter) Locked() *MockHandler_Locked_Call {
346+ return &MockHandler_Locked_Call{Call: _e.mock.On("Locked")}
347+}
348+
349+func (_c *MockHandler_Locked_Call) Run(run func()) *MockHandler_Locked_Call {
350+ _c.Call.Run(func(args mock.Arguments) {
351+ run()
352+ })
353+ return _c
354+}
355+
356+func (_c *MockHandler_Locked_Call) Return() *MockHandler_Locked_Call {
357+ _c.Call.Return()
358+ return _c
359+}
360+
361+func (_c *MockHandler_Locked_Call) RunAndReturn(run func()) *MockHandler_Locked_Call {
362+ _c.Run(run)
363+ return _c
364+}
365+
128 // OutputAdded provides a mock function for the type MockHandler366 // OutputAdded provides a mock function for the type MockHandler
129 func (_mock *MockHandler) OutputAdded(out *neferclient.Output) {367 func (_mock *MockHandler) OutputAdded(out *neferclient.Output) {
130 _mock.Called(out)368 _mock.Called(out)
@@ -204,3 +442,49 @@ func (_c *MockHandler_OutputRemoved_Call) RunAndReturn(run func(global uint32))
204 _c.Run(run)442 _c.Run(run)
205 return _c443 return _c
206 }444 }
445+
446+// Scale provides a mock function for the type MockHandler
447+func (_mock *MockHandler) Scale(id neferclient.SurfaceID, scale float64) {
448+ _mock.Called(id, scale)
449+ return
450+}
451+
452+// MockHandler_Scale_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Scale'
453+type MockHandler_Scale_Call struct {
454+ *mock.Call
455+}
456+
457+// Scale is a helper method to define mock.On call
458+// - id neferclient.SurfaceID
459+// - scale float64
460+func (_e *MockHandler_Expecter) Scale(id any, scale any) *MockHandler_Scale_Call {
461+ return &MockHandler_Scale_Call{Call: _e.mock.On("Scale", id, scale)}
462+}
463+
464+func (_c *MockHandler_Scale_Call) Run(run func(id neferclient.SurfaceID, scale float64)) *MockHandler_Scale_Call {
465+ _c.Call.Run(func(args mock.Arguments) {
466+ var arg0 neferclient.SurfaceID
467+ if args[0] != nil {
468+ arg0 = args[0].(neferclient.SurfaceID)
469+ }
470+ var arg1 float64
471+ if args[1] != nil {
472+ arg1 = args[1].(float64)
473+ }
474+ run(
475+ arg0,
476+ arg1,
477+ )
478+ })
479+ return _c
480+}
481+
482+func (_c *MockHandler_Scale_Call) Return() *MockHandler_Scale_Call {
483+ _c.Call.Return()
484+ return _c
485+}
486+
487+func (_c *MockHandler_Scale_Call) RunAndReturn(run func(id neferclient.SurfaceID, scale float64)) *MockHandler_Scale_Call {
488+ _c.Run(run)
489+ return _c
490+}
M queue.go +54 -1
@@ -2,6 +2,8 @@ package neferclient
22
33 import (
44 "sync"
5+
6+ "golang.org/x/sys/unix"
57 )
68
79 const (
@@ -19,6 +21,24 @@ const (
1921 evOutputMode // flags, a = width, b = height, global
2022 evOutputDone // global
2123 evFDReady // fd (epoll data)
24+
25+ // Surface events. id is the wl_surface object id (SurfaceID).
26+ evPing // serial (xdg_wm_base)
27+ evXdgToplevel // id, a = width, b = height (before the matching evXdgConfigure)
28+ evXdgConfigure // id, serial
29+ evLayerConfigure // id, serial, a = width, b = height
30+ evLockConfigure // id, serial, a = width, b = height
31+ evClosed // id
32+ evFrame // id
33+ evPreferredScale // id, a = fractional scale in 120ths
34+ evBufferScale // id, a = integer factor
35+ evFeedbackTable // id, fd = owned descriptor, flags = size
36+ evFeedbackMainDevice // id, dev
37+ evFeedbackFormats // id, name = one chunk of tranche format indices
38+ evFeedbackDone // id
39+ evLocked // id = lock generation
40+ evLockFinished // id = lock generation
41+ evBadEvent // id, a = badEvent code: the reader met a malformed event
2242 )
2343
2444 // event is the only thing the reader and the epoll goroutine hand to the
@@ -30,11 +50,29 @@ type event struct {
3050 global uint32
3151 version uint32
3252 flags uint32
33- fd int32
53+ id uint32 // wl_surface object id for surface events
54+ serial uint32
55+ fd int32 // epoll data, or a received descriptor owned by the event
3456 a, b int32
57+ dev uint64
3558 name [maxNameLen]byte
3659 }
3760
61+// hasFD reports whether the event owns a received descriptor that must be
62+// closed if the event is dropped.
63+func (e *event) hasFD() bool { return e.kind == evFeedbackTable && e.fd >= 0 }
64+
65+func (e *event) closeFD() {
66+ if e.hasFD() {
67+ _ = unix.Close(int(e.fd))
68+ e.fd = -1
69+ }
70+}
71+
72+func (e *event) setBytes(b []byte) {
73+ e.nameLen = uint8(copy(e.name[:], b))
74+}
75+
3876 func (e *event) setName(s string) {
3977 e.nameLen = uint8(copy(e.name[:], s))
4078 }
@@ -87,6 +125,7 @@ func (q *queue) post(ev *event) {
87125 switch {
88126 case q.stopped:
89127 q.mu.Unlock()
128+ ev.closeFD()
90129 return
91130 case q.pausing:
92131 q.held = append(q.held, *ev)
@@ -111,6 +150,7 @@ func (q *queue) pop(ev *event) bool {
111150 return false
112151 }
113152 *ev = q.ring[q.head]
153+ q.ring[q.head].kind = 0 // ownership of a carried descriptor moved to ev
114154 q.head = (q.head + 1) % ringSize
115155 full := q.n == ringSize
116156 q.n--
@@ -240,6 +280,19 @@ func (q *queue) takeHeld() []event {
240280 return held
241281 }
242282
283+// closeFDs closes the descriptors owned by events nobody will drain. Only
284+// valid once both producers have stopped.
285+func (q *queue) closeFDs() {
286+ q.mu.Lock()
287+ for i := range q.n {
288+ q.ring[(q.head+i)%ringSize].closeFD()
289+ }
290+ for i := range q.held {
291+ q.held[i].closeFD()
292+ }
293+ q.mu.Unlock()
294+}
295+
243296 // length reports how many events are queued.
244297 func (q *queue) length() int {
245298 q.mu.Lock()
@@ -2,6 +2,8 @@ package neferclient
2 2
3 import (3 import (
4 "sync"4 "sync"
5+
6+ "golang.org/x/sys/unix"
5 )7 )
6 8
7 const (9 const (
@@ -19,6 +21,24 @@ const (
19 evOutputMode // flags, a = width, b = height, global21 evOutputMode // flags, a = width, b = height, global
20 evOutputDone // global22 evOutputDone // global
21 evFDReady // fd (epoll data)23 evFDReady // fd (epoll data)
24+
25+ // Surface events. id is the wl_surface object id (SurfaceID).
26+ evPing // serial (xdg_wm_base)
27+ evXdgToplevel // id, a = width, b = height (before the matching evXdgConfigure)
28+ evXdgConfigure // id, serial
29+ evLayerConfigure // id, serial, a = width, b = height
30+ evLockConfigure // id, serial, a = width, b = height
31+ evClosed // id
32+ evFrame // id
33+ evPreferredScale // id, a = fractional scale in 120ths
34+ evBufferScale // id, a = integer factor
35+ evFeedbackTable // id, fd = owned descriptor, flags = size
36+ evFeedbackMainDevice // id, dev
37+ evFeedbackFormats // id, name = one chunk of tranche format indices
38+ evFeedbackDone // id
39+ evLocked // id = lock generation
40+ evLockFinished // id = lock generation
41+ evBadEvent // id, a = badEvent code: the reader met a malformed event
22 )42 )
23 43
24 // event is the only thing the reader and the epoll goroutine hand to the44 // event is the only thing the reader and the epoll goroutine hand to the
@@ -30,11 +50,29 @@ type event struct {
30 global uint3250 global uint32
31 version uint3251 version uint32
32 flags uint3252 flags uint32
33- fd int3253+ id uint32 // wl_surface object id for surface events
54+ serial uint32
55+ fd int32 // epoll data, or a received descriptor owned by the event
34 a, b int3256 a, b int32
57+ dev uint64
35 name [maxNameLen]byte58 name [maxNameLen]byte
36 }59 }
37 60
61+// hasFD reports whether the event owns a received descriptor that must be
62+// closed if the event is dropped.
63+func (e *event) hasFD() bool { return e.kind == evFeedbackTable && e.fd >= 0 }
64+
65+func (e *event) closeFD() {
66+ if e.hasFD() {
67+ _ = unix.Close(int(e.fd))
68+ e.fd = -1
69+ }
70+}
71+
72+func (e *event) setBytes(b []byte) {
73+ e.nameLen = uint8(copy(e.name[:], b))
74+}
75+
38 func (e *event) setName(s string) {76 func (e *event) setName(s string) {
39 e.nameLen = uint8(copy(e.name[:], s))77 e.nameLen = uint8(copy(e.name[:], s))
40 }78 }
@@ -87,6 +125,7 @@ func (q *queue) post(ev *event) {
87 switch {125 switch {
88 case q.stopped:126 case q.stopped:
89 q.mu.Unlock()127 q.mu.Unlock()
128+ ev.closeFD()
90 return129 return
91 case q.pausing:130 case q.pausing:
92 q.held = append(q.held, *ev)131 q.held = append(q.held, *ev)
@@ -111,6 +150,7 @@ func (q *queue) pop(ev *event) bool {
111 return false150 return false
112 }151 }
113 *ev = q.ring[q.head]152 *ev = q.ring[q.head]
153+ q.ring[q.head].kind = 0 // ownership of a carried descriptor moved to ev
114 q.head = (q.head + 1) % ringSize154 q.head = (q.head + 1) % ringSize
115 full := q.n == ringSize155 full := q.n == ringSize
116 q.n--156 q.n--
@@ -240,6 +280,19 @@ func (q *queue) takeHeld() []event {
240 return held280 return held
241 }281 }
242 282
283+// closeFDs closes the descriptors owned by events nobody will drain. Only
284+// valid once both producers have stopped.
285+func (q *queue) closeFDs() {
286+ q.mu.Lock()
287+ for i := range q.n {
288+ q.ring[(q.head+i)%ringSize].closeFD()
289+ }
290+ for i := range q.held {
291+ q.held[i].closeFD()
292+ }
293+ q.mu.Unlock()
294+}
295+
243 // length reports how many events are queued.296 // length reports how many events are queued.
244 func (q *queue) length() int {297 func (q *queue) length() int {
245 q.mu.Lock()298 q.mu.Lock()
A surface_types.go +21 -0
@@ -0,0 +1,21 @@
1+package neferclient
2+
3+// SurfaceID identifies a [Surface] in Handler callbacks. IDs are never
4+// reused within a connection.
5+type SurfaceID uint32
6+
7+// Format is one DRM format and modifier pair from linux-dmabuf feedback.
8+type Format struct {
9+ FourCC uint32
10+ Modifier uint64
11+}
12+
13+// Feedback is the latest complete linux-dmabuf feedback of a surface.
14+type Feedback struct {
15+ MainDevice uint64 // dev_t of the compositor's main device
16+ Formats []Format // every tranche's formats, flattened in tranche order
17+}
18+
19+// Rect is an integer rectangle: surface-local logical pixels for input
20+// regions, buffer pixels for damage.
21+type Rect struct{ X, Y, Width, Height int32 }
@@ -0,0 +1,21 @@
1+package neferclient
2+
3+// SurfaceID identifies a [Surface] in Handler callbacks. IDs are never
4+// reused within a connection.
5+type SurfaceID uint32
6+
7+// Format is one DRM format and modifier pair from linux-dmabuf feedback.
8+type Format struct {
9+ FourCC uint32
10+ Modifier uint64
11+}
12+
13+// Feedback is the latest complete linux-dmabuf feedback of a surface.
14+type Feedback struct {
15+ MainDevice uint64 // dev_t of the compositor's main device
16+ Formats []Format // every tranche's formats, flattened in tranche order
17+}
18+
19+// Rect is an integer rectangle: surface-local logical pixels for input
20+// regions, buffer pixels for damage.
21+type Rect struct{ X, Y, Width, Height int32 }

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 4

↑↓ moveenter openesc close