feat: add surface event kinds, Handler methods and shared types
- commit
- cd00fc05677d9913e26830434673ec126f5ed22c
- author
- brice · · 2026-10-01 16:32 UTC
- parent
- 23ac271
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· 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 { | |||
| 579 | 579 | if c.efd >= 0 { | |
| 580 | 580 | _ = unix.Close(c.efd) | |
| 581 | 581 | } | |
| 582 | + | c.q.closeFDs() // both producers are gone: close what nobody will drain | |
| 582 | 583 | return err | |
| 583 | 584 | } | |
| @@ -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 err | 583 | return err | ||
| 583 | } | 584 | } | ||
M handler.go +35 -0
| @@ -23,6 +23,33 @@ type Handler interface { | |||
| 23 | 23 | // a wl_output that could not be bound. Fatal transport errors are returned | |
| 24 | 24 | // by Dispatch instead. | |
| 25 | 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 | 55 | // NopHandler implements every Handler method as a no-op. Embed it in a handler | |
| @@ -34,3 +61,11 @@ func (NopHandler) OutputAdded(*Output) {} | |||
| 34 | 61 | func (NopHandler) OutputRemoved(uint32) {} | |
| 35 | 62 | func (NopHandler) FDReady(uint64) {} | |
| 36 | 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() {} | |
| @@ -23,6 +23,33 @@ type Handler interface { | |||||
| 23 | // a wl_output that could not be bound. Fatal transport errors are returned | 23 | // 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 handler | 55 | // 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 { | |||
| 45 | 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 | 140 | // Error provides a mock function for the type MockHandler | |
| 49 | 141 | func (_mock *MockHandler) Error(err error) { | |
| 50 | 142 | _mock.Called(err) | |
| @@ -125,6 +217,152 @@ func (_c *MockHandler_FDReady_Call) RunAndReturn(run func(id uint64)) *MockHandl | |||
| 125 | 217 | 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 | 366 | // OutputAdded provides a mock function for the type MockHandler | |
| 129 | 367 | func (_mock *MockHandler) OutputAdded(out *neferclient.Output) { | |
| 130 | 368 | _mock.Called(out) | |
| @@ -204,3 +442,49 @@ func (_c *MockHandler_OutputRemoved_Call) RunAndReturn(run func(global uint32)) | |||
| 204 | 442 | _c.Run(run) | |
| 205 | 443 | 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 | + | } | |
| @@ -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 MockHandler | 140 | // 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 _c | 217 | 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 MockHandler | 366 | // 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 _c | 443 | 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 | |||
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "sync" | |
| 5 | + | ||
| 6 | + | "golang.org/x/sys/unix" | |
| 5 | 7 | ) | |
| 6 | 8 | ||
| 7 | 9 | const ( | |
| @@ -19,6 +21,24 @@ const ( | |||
| 19 | 21 | evOutputMode // flags, a = width, b = height, global | |
| 20 | 22 | evOutputDone // global | |
| 21 | 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 | 44 | // event is the only thing the reader and the epoll goroutine hand to the | |
| @@ -30,11 +50,29 @@ type event struct { | |||
| 30 | 50 | global uint32 | |
| 31 | 51 | version uint32 | |
| 32 | 52 | 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 | |
| 34 | 56 | a, b int32 | |
| 57 | + | dev uint64 | |
| 35 | 58 | 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 | 76 | func (e *event) setName(s string) { | |
| 39 | 77 | e.nameLen = uint8(copy(e.name[:], s)) | |
| 40 | 78 | } | |
| @@ -87,6 +125,7 @@ func (q *queue) post(ev *event) { | |||
| 87 | 125 | switch { | |
| 88 | 126 | case q.stopped: | |
| 89 | 127 | q.mu.Unlock() | |
| 128 | + | ev.closeFD() | |
| 90 | 129 | return | |
| 91 | 130 | case q.pausing: | |
| 92 | 131 | q.held = append(q.held, *ev) | |
| @@ -111,6 +150,7 @@ func (q *queue) pop(ev *event) bool { | |||
| 111 | 150 | return false | |
| 112 | 151 | } | |
| 113 | 152 | *ev = q.ring[q.head] | |
| 153 | + | q.ring[q.head].kind = 0 // ownership of a carried descriptor moved to ev | |
| 114 | 154 | q.head = (q.head + 1) % ringSize | |
| 115 | 155 | full := q.n == ringSize | |
| 116 | 156 | q.n-- | |
| @@ -240,6 +280,19 @@ func (q *queue) takeHeld() []event { | |||
| 240 | 280 | 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 | 296 | // length reports how many events are queued. | |
| 244 | 297 | func (q *queue) length() int { | |
| 245 | 298 | 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, global | 21 | evOutputMode // flags, a = width, b = height, global | ||
| 20 | evOutputDone // global | 22 | 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 the | 44 | // event is the only thing the reader and the epoll goroutine hand to the | ||
| @@ -30,11 +50,29 @@ type event struct { | |||||
| 30 | global uint32 | 50 | global uint32 | ||
| 31 | version uint32 | 51 | version uint32 | ||
| 32 | flags uint32 | 52 | 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 | |||
| 34 | a, b int32 | 56 | a, b int32 | ||
| 57 | + | dev uint64 | |||
| 35 | name [maxNameLen]byte | 58 | 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 | return | 129 | 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 false | 150 | 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) % ringSize | 154 | q.head = (q.head + 1) % ringSize | ||
| 115 | full := q.n == ringSize | 155 | full := q.n == ringSize | ||
| 116 | q.n-- | 156 | q.n-- | ||
| @@ -240,6 +280,19 @@ func (q *queue) takeHeld() []event { | |||||
| 240 | return held | 280 | 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 } | |||