detached 18d8922

refactor(app): attach outputs to the wayland server directly

contentAttacher names its methods AttachOutput/DetachOutput like
*wayland.Server, so session passes the server and the wrapper goes.
commit
18d89229d023200f35cb446b850e557ec03fbddf
author
brice · · 2026-10-13 17:58 UTC
parent
6e5187e
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
6 files · +36 -34
M internal/app/contentattacher_mock_test.go +21 -21
@@ -45,12 +45,12 @@ func (_m *mockcontentAttacher) EXPECT() *mockcontentAttacher_Expecter {
4545 return &mockcontentAttacher_Expecter{mock: &_m.Mock}
4646 }
4747
48-// Attach provides a mock function for the type mockcontentAttacher
49-func (_mock *mockcontentAttacher) Attach(name string) (<-chan *ports.ContentBatch, ports.ContentReturn) {
48+// AttachOutput provides a mock function for the type mockcontentAttacher
49+func (_mock *mockcontentAttacher) AttachOutput(name string) (<-chan *ports.ContentBatch, ports.ContentReturn) {
5050 ret := _mock.Called(name)
5151
5252 if len(ret) == 0 {
53- panic("no return value specified for Attach")
53+ panic("no return value specified for AttachOutput")
5454 }
5555
5656 var r0 <-chan *ports.ContentBatch
@@ -75,18 +75,18 @@ func (_mock *mockcontentAttacher) Attach(name string) (<-chan *ports.ContentBatc
7575 return r0, r1
7676 }
7777
78-// mockcontentAttacher_Attach_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Attach'
79-type mockcontentAttacher_Attach_Call struct {
78+// mockcontentAttacher_AttachOutput_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AttachOutput'
79+type mockcontentAttacher_AttachOutput_Call struct {
8080 *mock.Call
8181 }
8282
83-// Attach is a helper method to define mock.On call
83+// AttachOutput is a helper method to define mock.On call
8484 // - name string
85-func (_e *mockcontentAttacher_Expecter) Attach(name any) *mockcontentAttacher_Attach_Call {
86- return &mockcontentAttacher_Attach_Call{Call: _e.mock.On("Attach", name)}
85+func (_e *mockcontentAttacher_Expecter) AttachOutput(name any) *mockcontentAttacher_AttachOutput_Call {
86+ return &mockcontentAttacher_AttachOutput_Call{Call: _e.mock.On("AttachOutput", name)}
8787 }
8888
89-func (_c *mockcontentAttacher_Attach_Call) Run(run func(name string)) *mockcontentAttacher_Attach_Call {
89+func (_c *mockcontentAttacher_AttachOutput_Call) Run(run func(name string)) *mockcontentAttacher_AttachOutput_Call {
9090 _c.Call.Run(func(args mock.Arguments) {
9191 var arg0 string
9292 if args[0] != nil {
@@ -99,34 +99,34 @@ func (_c *mockcontentAttacher_Attach_Call) Run(run func(name string)) *mockconte
9999 return _c
100100 }
101101
102-func (_c *mockcontentAttacher_Attach_Call) Return(contentBatchCh <-chan *ports.ContentBatch, contentReturn ports.ContentReturn) *mockcontentAttacher_Attach_Call {
102+func (_c *mockcontentAttacher_AttachOutput_Call) Return(contentBatchCh <-chan *ports.ContentBatch, contentReturn ports.ContentReturn) *mockcontentAttacher_AttachOutput_Call {
103103 _c.Call.Return(contentBatchCh, contentReturn)
104104 return _c
105105 }
106106
107-func (_c *mockcontentAttacher_Attach_Call) RunAndReturn(run func(name string) (<-chan *ports.ContentBatch, ports.ContentReturn)) *mockcontentAttacher_Attach_Call {
107+func (_c *mockcontentAttacher_AttachOutput_Call) RunAndReturn(run func(name string) (<-chan *ports.ContentBatch, ports.ContentReturn)) *mockcontentAttacher_AttachOutput_Call {
108108 _c.Call.Return(run)
109109 return _c
110110 }
111111
112-// Detach provides a mock function for the type mockcontentAttacher
113-func (_mock *mockcontentAttacher) Detach(name string) {
112+// DetachOutput provides a mock function for the type mockcontentAttacher
113+func (_mock *mockcontentAttacher) DetachOutput(name string) {
114114 _mock.Called(name)
115115 return
116116 }
117117
118-// mockcontentAttacher_Detach_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Detach'
119-type mockcontentAttacher_Detach_Call struct {
118+// mockcontentAttacher_DetachOutput_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DetachOutput'
119+type mockcontentAttacher_DetachOutput_Call struct {
120120 *mock.Call
121121 }
122122
123-// Detach is a helper method to define mock.On call
123+// DetachOutput is a helper method to define mock.On call
124124 // - name string
125-func (_e *mockcontentAttacher_Expecter) Detach(name any) *mockcontentAttacher_Detach_Call {
126- return &mockcontentAttacher_Detach_Call{Call: _e.mock.On("Detach", name)}
125+func (_e *mockcontentAttacher_Expecter) DetachOutput(name any) *mockcontentAttacher_DetachOutput_Call {
126+ return &mockcontentAttacher_DetachOutput_Call{Call: _e.mock.On("DetachOutput", name)}
127127 }
128128
129-func (_c *mockcontentAttacher_Detach_Call) Run(run func(name string)) *mockcontentAttacher_Detach_Call {
129+func (_c *mockcontentAttacher_DetachOutput_Call) Run(run func(name string)) *mockcontentAttacher_DetachOutput_Call {
130130 _c.Call.Run(func(args mock.Arguments) {
131131 var arg0 string
132132 if args[0] != nil {
@@ -139,12 +139,12 @@ func (_c *mockcontentAttacher_Detach_Call) Run(run func(name string)) *mockconte
139139 return _c
140140 }
141141
142-func (_c *mockcontentAttacher_Detach_Call) Return() *mockcontentAttacher_Detach_Call {
142+func (_c *mockcontentAttacher_DetachOutput_Call) Return() *mockcontentAttacher_DetachOutput_Call {
143143 _c.Call.Return()
144144 return _c
145145 }
146146
147-func (_c *mockcontentAttacher_Detach_Call) RunAndReturn(run func(name string)) *mockcontentAttacher_Detach_Call {
147+func (_c *mockcontentAttacher_DetachOutput_Call) RunAndReturn(run func(name string)) *mockcontentAttacher_DetachOutput_Call {
148148 _c.Run(run)
149149 return _c
150150 }
@@ -45,12 +45,12 @@ func (_m *mockcontentAttacher) EXPECT() *mockcontentAttacher_Expecter {
45 return &mockcontentAttacher_Expecter{mock: &_m.Mock}45 return &mockcontentAttacher_Expecter{mock: &_m.Mock}
46 }46 }
47 47
48-// Attach provides a mock function for the type mockcontentAttacher48+// AttachOutput provides a mock function for the type mockcontentAttacher
49-func (_mock *mockcontentAttacher) Attach(name string) (<-chan *ports.ContentBatch, ports.ContentReturn) {49+func (_mock *mockcontentAttacher) AttachOutput(name string) (<-chan *ports.ContentBatch, ports.ContentReturn) {
50 ret := _mock.Called(name)50 ret := _mock.Called(name)
51 51
52 if len(ret) == 0 {52 if len(ret) == 0 {
53- panic("no return value specified for Attach")53+ panic("no return value specified for AttachOutput")
54 }54 }
55 55
56 var r0 <-chan *ports.ContentBatch56 var r0 <-chan *ports.ContentBatch
@@ -75,18 +75,18 @@ func (_mock *mockcontentAttacher) Attach(name string) (<-chan *ports.ContentBatc
75 return r0, r175 return r0, r1
76 }76 }
77 77
78-// mockcontentAttacher_Attach_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Attach'78+// mockcontentAttacher_AttachOutput_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AttachOutput'
79-type mockcontentAttacher_Attach_Call struct {79+type mockcontentAttacher_AttachOutput_Call struct {
80 *mock.Call80 *mock.Call
81 }81 }
82 82
83-// Attach is a helper method to define mock.On call83+// AttachOutput is a helper method to define mock.On call
84 // - name string84 // - name string
85-func (_e *mockcontentAttacher_Expecter) Attach(name any) *mockcontentAttacher_Attach_Call {85+func (_e *mockcontentAttacher_Expecter) AttachOutput(name any) *mockcontentAttacher_AttachOutput_Call {
86- return &mockcontentAttacher_Attach_Call{Call: _e.mock.On("Attach", name)}86+ return &mockcontentAttacher_AttachOutput_Call{Call: _e.mock.On("AttachOutput", name)}
87 }87 }
88 88
89-func (_c *mockcontentAttacher_Attach_Call) Run(run func(name string)) *mockcontentAttacher_Attach_Call {89+func (_c *mockcontentAttacher_AttachOutput_Call) Run(run func(name string)) *mockcontentAttacher_AttachOutput_Call {
90 _c.Call.Run(func(args mock.Arguments) {90 _c.Call.Run(func(args mock.Arguments) {
91 var arg0 string91 var arg0 string
92 if args[0] != nil {92 if args[0] != nil {
@@ -99,34 +99,34 @@ func (_c *mockcontentAttacher_Attach_Call) Run(run func(name string)) *mockconte
99 return _c99 return _c
100 }100 }
101 101
102-func (_c *mockcontentAttacher_Attach_Call) Return(contentBatchCh <-chan *ports.ContentBatch, contentReturn ports.ContentReturn) *mockcontentAttacher_Attach_Call {102+func (_c *mockcontentAttacher_AttachOutput_Call) Return(contentBatchCh <-chan *ports.ContentBatch, contentReturn ports.ContentReturn) *mockcontentAttacher_AttachOutput_Call {
103 _c.Call.Return(contentBatchCh, contentReturn)103 _c.Call.Return(contentBatchCh, contentReturn)
104 return _c104 return _c
105 }105 }
106 106
107-func (_c *mockcontentAttacher_Attach_Call) RunAndReturn(run func(name string) (<-chan *ports.ContentBatch, ports.ContentReturn)) *mockcontentAttacher_Attach_Call {107+func (_c *mockcontentAttacher_AttachOutput_Call) RunAndReturn(run func(name string) (<-chan *ports.ContentBatch, ports.ContentReturn)) *mockcontentAttacher_AttachOutput_Call {
108 _c.Call.Return(run)108 _c.Call.Return(run)
109 return _c109 return _c
110 }110 }
111 111
112-// Detach provides a mock function for the type mockcontentAttacher112+// DetachOutput provides a mock function for the type mockcontentAttacher
113-func (_mock *mockcontentAttacher) Detach(name string) {113+func (_mock *mockcontentAttacher) DetachOutput(name string) {
114 _mock.Called(name)114 _mock.Called(name)
115 return115 return
116 }116 }
117 117
118-// mockcontentAttacher_Detach_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Detach'118+// mockcontentAttacher_DetachOutput_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DetachOutput'
119-type mockcontentAttacher_Detach_Call struct {119+type mockcontentAttacher_DetachOutput_Call struct {
120 *mock.Call120 *mock.Call
121 }121 }
122 122
123-// Detach is a helper method to define mock.On call123+// DetachOutput is a helper method to define mock.On call
124 // - name string124 // - name string
125-func (_e *mockcontentAttacher_Expecter) Detach(name any) *mockcontentAttacher_Detach_Call {125+func (_e *mockcontentAttacher_Expecter) DetachOutput(name any) *mockcontentAttacher_DetachOutput_Call {
126- return &mockcontentAttacher_Detach_Call{Call: _e.mock.On("Detach", name)}126+ return &mockcontentAttacher_DetachOutput_Call{Call: _e.mock.On("DetachOutput", name)}
127 }127 }
128 128
129-func (_c *mockcontentAttacher_Detach_Call) Run(run func(name string)) *mockcontentAttacher_Detach_Call {129+func (_c *mockcontentAttacher_DetachOutput_Call) Run(run func(name string)) *mockcontentAttacher_DetachOutput_Call {
130 _c.Call.Run(func(args mock.Arguments) {130 _c.Call.Run(func(args mock.Arguments) {
131 var arg0 string131 var arg0 string
132 if args[0] != nil {132 if args[0] != nil {
@@ -139,12 +139,12 @@ func (_c *mockcontentAttacher_Detach_Call) Run(run func(name string)) *mockconte
139 return _c139 return _c
140 }140 }
141 141
142-func (_c *mockcontentAttacher_Detach_Call) Return() *mockcontentAttacher_Detach_Call {142+func (_c *mockcontentAttacher_DetachOutput_Call) Return() *mockcontentAttacher_DetachOutput_Call {
143 _c.Call.Return()143 _c.Call.Return()
144 return _c144 return _c
145 }145 }
146 146
147-func (_c *mockcontentAttacher_Detach_Call) RunAndReturn(run func(name string)) *mockcontentAttacher_Detach_Call {147+func (_c *mockcontentAttacher_DetachOutput_Call) RunAndReturn(run func(name string)) *mockcontentAttacher_DetachOutput_Call {
148 _c.Run(run)148 _c.Run(run)
149 return _c149 return _c
150 }150 }
M internal/app/contentattacher_test.go +4 -4
@@ -34,7 +34,7 @@ func TestOutputSetAttachesAndDetachesContents(t *testing.T) {
3434 <-ctx.Done()
3535 return nil
3636 }
37- attacher.EXPECT().Attach("DP-1").RunAndReturn(func(string) (<-chan *ports.ContentBatch, ports.ContentReturn) {
37+ attacher.EXPECT().AttachOutput("DP-1").RunAndReturn(func(string) (<-chan *ports.ContentBatch, ports.ContentReturn) {
3838 order = append(order, "attach")
3939 // The output is registered with the security backend first.
4040 if len(events) != 1 {
@@ -42,7 +42,7 @@ func TestOutputSetAttachesAndDetachesContents(t *testing.T) {
4242 }
4343 return feed, ret
4444 }).Times(2)
45- attacher.EXPECT().Detach("DP-1").Run(func(string) { order = append(order, "detach") }).Times(2)
45+ attacher.EXPECT().DetachOutput("DP-1").Run(func(string) { order = append(order, "detach") }).Times(2)
4646 for round := range 2 {
4747 if !set.start(ctx, "DP-1", run) {
4848 t.Fatal("start failed")
@@ -75,8 +75,8 @@ func TestOutputSetWaitDetachesContents(t *testing.T) {
7575 set := newOutputSet(ctx, nil)
7676 attacher := newMockcontentAttacher(t)
7777 set.attach = attacher
78- attacher.EXPECT().Attach("A").Return(nil, nil).Once()
79- attacher.EXPECT().Detach("A").Return().Once()
78+ attacher.EXPECT().AttachOutput("A").Return(nil, nil).Once()
79+ attacher.EXPECT().DetachOutput("A").Return().Once()
8080 set.start(ctx, "A", func(ctx context.Context, _ <-chan ports.Scene, _ <-chan *ports.ContentBatch, _ ports.ContentReturn, _ <-chan ports.CursorChange, _ <-chan ports.CaptureRequest, _ <-chan ports.SecurityState, _ ports.OutputInstance) error {
8181 <-ctx.Done()
8282 return nil
@@ -34,7 +34,7 @@ func TestOutputSetAttachesAndDetachesContents(t *testing.T) {
34 <-ctx.Done()34 <-ctx.Done()
35 return nil35 return nil
36 }36 }
37- attacher.EXPECT().Attach("DP-1").RunAndReturn(func(string) (<-chan *ports.ContentBatch, ports.ContentReturn) {37+ attacher.EXPECT().AttachOutput("DP-1").RunAndReturn(func(string) (<-chan *ports.ContentBatch, ports.ContentReturn) {
38 order = append(order, "attach")38 order = append(order, "attach")
39 // The output is registered with the security backend first.39 // The output is registered with the security backend first.
40 if len(events) != 1 {40 if len(events) != 1 {
@@ -42,7 +42,7 @@ func TestOutputSetAttachesAndDetachesContents(t *testing.T) {
42 }42 }
43 return feed, ret43 return feed, ret
44 }).Times(2)44 }).Times(2)
45- attacher.EXPECT().Detach("DP-1").Run(func(string) { order = append(order, "detach") }).Times(2)45+ attacher.EXPECT().DetachOutput("DP-1").Run(func(string) { order = append(order, "detach") }).Times(2)
46 for round := range 2 {46 for round := range 2 {
47 if !set.start(ctx, "DP-1", run) {47 if !set.start(ctx, "DP-1", run) {
48 t.Fatal("start failed")48 t.Fatal("start failed")
@@ -75,8 +75,8 @@ func TestOutputSetWaitDetachesContents(t *testing.T) {
75 set := newOutputSet(ctx, nil)75 set := newOutputSet(ctx, nil)
76 attacher := newMockcontentAttacher(t)76 attacher := newMockcontentAttacher(t)
77 set.attach = attacher77 set.attach = attacher
78- attacher.EXPECT().Attach("A").Return(nil, nil).Once()78+ attacher.EXPECT().AttachOutput("A").Return(nil, nil).Once()
79- attacher.EXPECT().Detach("A").Return().Once()79+ attacher.EXPECT().DetachOutput("A").Return().Once()
80 set.start(ctx, "A", func(ctx context.Context, _ <-chan ports.Scene, _ <-chan *ports.ContentBatch, _ ports.ContentReturn, _ <-chan ports.CursorChange, _ <-chan ports.CaptureRequest, _ <-chan ports.SecurityState, _ ports.OutputInstance) error {80 set.start(ctx, "A", func(ctx context.Context, _ <-chan ports.Scene, _ <-chan *ports.ContentBatch, _ ports.ContentReturn, _ <-chan ports.CursorChange, _ <-chan ports.CaptureRequest, _ <-chan ports.SecurityState, _ ports.OutputInstance) error {
81 <-ctx.Done()81 <-ctx.Done()
82 return nil82 return nil
M internal/app/outputrouting.go +2 -1
@@ -4,7 +4,8 @@ import "github.com/bnema/neferwl/internal/ports"
44
55 // outputChannels is the shared app-to-backend wiring. The backend loop remains
66 // the sole owner of outputSet and outputApply. Security producers use bounded
7-// lossless FIFO forwarders; contents are not routed here: outputs take them from wayland (contentAttacher).
7+// lossless FIFO forwarders; contents are not routed here: each output is
8+// attached to wayland's content feed (contentAttacher).
89 // heads, configured and replies are fed from the outputApply outbox.
910 type outputChannels struct {
1011 security ports.SessionSecurity
@@ -4,7 +4,8 @@ import "github.com/bnema/neferwl/internal/ports"
4 4
5 // outputChannels is the shared app-to-backend wiring. The backend loop remains5 // outputChannels is the shared app-to-backend wiring. The backend loop remains
6 // the sole owner of outputSet and outputApply. Security producers use bounded6 // the sole owner of outputSet and outputApply. Security producers use bounded
7-// lossless FIFO forwarders; contents are not routed here: outputs take them from wayland (contentAttacher).7+// lossless FIFO forwarders; contents are not routed here: each output is
8+// attached to wayland's content feed (contentAttacher).
8 // heads, configured and replies are fed from the outputApply outbox.9 // heads, configured and replies are fed from the outputApply outbox.
9 type outputChannels struct {10 type outputChannels struct {
10 security ports.SessionSecurity11 security ports.SessionSecurity
M internal/app/outputs.go +5 -5
@@ -18,11 +18,11 @@ type outputRun func(ctx context.Context, scenes <-chan ports.Scene, contents <-c
1818 // contentAttacher connects an output to the surface contents: wayland feeds
1919 // every attached output batches of window contents, starting with the latest
2020 // content of each window, and takes the batches back through the returned
21-// ports.ContentReturn. Attach may block on the display goroutine: call it
21+// ports.ContentReturn. AttachOutput may block on the display goroutine: call it
2222 // from outside that goroutine. It returns a nil channel when wayland is gone.
2323 type contentAttacher interface {
24- Attach(name string) (<-chan *ports.ContentBatch, ports.ContentReturn)
25- Detach(name string)
24+ AttachOutput(name string) (<-chan *ports.ContentBatch, ports.ContentReturn)
25+ DetachOutput(name string)
2626 }
2727
2828 // outputSet owns the running outputs and feeds them. Core sends one scene
@@ -101,7 +101,7 @@ func (s *outputSet) start(ctx context.Context, name string, run outputRun, wire
101101 var contents <-chan *ports.ContentBatch
102102 var returns ports.ContentReturn
103103 if s.attach != nil {
104- contents, returns = s.attach.Attach(name)
104+ contents, returns = s.attach.AttachOutput(name)
105105 }
106106 s.outs[name] = r
107107 go func() {
@@ -254,7 +254,7 @@ func (s *outputSet) finish(name string) error {
254254 // detach stops the content feed of an output that has stopped.
255255 func (s *outputSet) detach(name string) {
256256 if s.attach != nil {
257- s.attach.Detach(name)
257+ s.attach.DetachOutput(name)
258258 }
259259 }
260260
@@ -18,11 +18,11 @@ type outputRun func(ctx context.Context, scenes <-chan ports.Scene, contents <-c
18 // contentAttacher connects an output to the surface contents: wayland feeds18 // contentAttacher connects an output to the surface contents: wayland feeds
19 // every attached output batches of window contents, starting with the latest19 // every attached output batches of window contents, starting with the latest
20 // content of each window, and takes the batches back through the returned20 // content of each window, and takes the batches back through the returned
21-// ports.ContentReturn. Attach may block on the display goroutine: call it21+// ports.ContentReturn. AttachOutput may block on the display goroutine: call it
22 // from outside that goroutine. It returns a nil channel when wayland is gone.22 // from outside that goroutine. It returns a nil channel when wayland is gone.
23 type contentAttacher interface {23 type contentAttacher interface {
24- Attach(name string) (<-chan *ports.ContentBatch, ports.ContentReturn)24+ AttachOutput(name string) (<-chan *ports.ContentBatch, ports.ContentReturn)
25- Detach(name string)25+ DetachOutput(name string)
26 }26 }
27 27
28 // outputSet owns the running outputs and feeds them. Core sends one scene28 // outputSet owns the running outputs and feeds them. Core sends one scene
@@ -101,7 +101,7 @@ func (s *outputSet) start(ctx context.Context, name string, run outputRun, wire
101 var contents <-chan *ports.ContentBatch101 var contents <-chan *ports.ContentBatch
102 var returns ports.ContentReturn102 var returns ports.ContentReturn
103 if s.attach != nil {103 if s.attach != nil {
104- contents, returns = s.attach.Attach(name)104+ contents, returns = s.attach.AttachOutput(name)
105 }105 }
106 s.outs[name] = r106 s.outs[name] = r
107 go func() {107 go func() {
@@ -254,7 +254,7 @@ func (s *outputSet) finish(name string) error {
254 // detach stops the content feed of an output that has stopped.254 // detach stops the content feed of an output that has stopped.
255 func (s *outputSet) detach(name string) {255 func (s *outputSet) detach(name string) {
256 if s.attach != nil {256 if s.attach != nil {
257- s.attach.Detach(name)257+ s.attach.DetachOutput(name)
258 }258 }
259 }259 }
260 260
M internal/app/session.go +1 -1
@@ -354,7 +354,7 @@ func (s *session) run(ctx context.Context, inject func(chan<- ports.InputEvent))
354354
355355 go func() {
356356 defer workers.Done()
357- outputIO := p.outputs(security, server.Presentation(), waylandContent{server})
357+ outputIO := p.outputs(security, server.Presentation(), server)
358358 apply := newOutputApply(core.NewOutputOverrides(opts.Config, hw == nil), logging.For(ctx, "app"))
359359 if hw != nil {
360360 done <- safe("output", func() error {
@@ -354,7 +354,7 @@ func (s *session) run(ctx context.Context, inject func(chan<- ports.InputEvent))
354 354
355 go func() {355 go func() {
356 defer workers.Done()356 defer workers.Done()
357- outputIO := p.outputs(security, server.Presentation(), waylandContent{server})357+ outputIO := p.outputs(security, server.Presentation(), server)
358 apply := newOutputApply(core.NewOutputOverrides(opts.Config, hw == nil), logging.For(ctx, "app"))358 apply := newOutputApply(core.NewOutputOverrides(opts.Config, hw == nil), logging.For(ctx, "app"))
359 if hw != nil {359 if hw != nil {
360 done <- safe("output", func() error {360 done <- safe("output", func() error {
M internal/app/wiring.go +3 -2
@@ -41,8 +41,9 @@ type pipes struct {
4141 // config file.
4242 scales chan ports.ScaleChanged
4343
44- // Outputs report to wayland through its presentation sink and tell core
45- // about each flip (frames) to move running slides.
44+ // Outputs report to wayland through its presentation sink and, for each
45+ // flip of an animating scene (Scene.Animating), tell core (frames) to
46+ // move running slides.
4647 frames chan ports.OutputFrame
4748
4849 captures chan ports.CaptureRequest
@@ -41,8 +41,9 @@ type pipes struct {
41 // config file.41 // config file.
42 scales chan ports.ScaleChanged42 scales chan ports.ScaleChanged
43 43
44- // Outputs report to wayland through its presentation sink and tell core44+ // Outputs report to wayland through its presentation sink and, for each
45- // about each flip (frames) to move running slides.45+ // flip of an animating scene (Scene.Animating), tell core (frames) to
46+ // move running slides.
46 frames chan ports.OutputFrame47 frames chan ports.OutputFrame
47 48
48 captures chan ports.CaptureRequest49 captures chan ports.CaptureRequest

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 25

Tags 10

↑↓ moveenter openesc close