feat/hint-hybrid aed7ca4

wiring.go RawHistoryFolder

1package app
2
3import (
4	"github.com/bnema/neferwl/internal/adapters/wayland"
5	"github.com/bnema/neferwl/internal/adapters/xkb"
6	"github.com/bnema/neferwl/internal/core"
7	"github.com/bnema/neferwl/internal/ports"
8)
9
10// pipes are the channels between a session's goroutines. newPipes makes
11// them all, with their buffer sizes; core, wayland and outputs hand each
12// side the ends it uses.
13type pipes struct {
14	securityChanges chan ports.SecurityState
15	securityEvents  chan ports.SecurityBackendEvent
16
17	client   chan ports.ClientEvent
18	input    chan ports.InputEvent
19	output   chan ports.OutputEvent
20	commands chan ports.ClientCommand
21	spawn    chan ports.SpawnRequest
22
23	// Capacity 1: each holds the latest value its sender published.
24	scenes        chan []ports.Scene
25	renderScenes  chan []ports.Scene
26	layouts       chan ports.Layout
27	constraints   chan ports.PointerConstraint
28	states        chan ports.State
29	workspaces    chan ports.Workspaces
30	cursorChanges chan ports.CursorChange
31	keymaps       chan *xkb.Keymap
32	deviceConfigs chan ports.InputDevicesConfig
33
34	// Configuration: watched from the file, filtered by relayConfig, then
35	// configured (overrides included) by outputs for core.
36	watched      chan ports.ConfigChanged
37	filtered     chan ports.ConfigChanged
38	configured   chan ports.ConfigChanged
39	configErrors chan error
40	// scales is nil outside a real session: headless runs never touch the
41	// config file.
42	scales chan ports.ScaleChanged
43
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.
47	frames chan ports.OutputFrame
48
49	// Hint mode: core asks the hints adapter for a scan and gets the result.
50	hintScans   chan ports.HintScanRequest
51	hintResults chan ports.HintScanResult
52
53	captures chan ports.CaptureRequest
54	// Every admitted capture owns one reply slot until routeCaptured takes
55	// it. Keep this capacity tied to admission so output routing never waits.
56	// With hint mode on, the outputs reply on capturedAll and routeCaptured splits the replies by
57	// ports.CaptureIDInternal into captured (the wayland consumer) and
58	// hintCaptured (internal consumers). With hint mode off, capturedAll is
59	// captured itself and there is no routeCaptured.
60	capturedAll chan ports.CaptureDone
61	captured    chan ports.CaptureDone
62	// hintCaptured carries internal capture replies to the hints adapter.
63	hintCaptured chan ports.CaptureDone
64
65	outputFormats chan ports.OutputFormats
66	outputHeads   chan ports.OutputHeads
67	leaseRequests chan ports.LeaseMessage
68	leaseEvents   chan ports.LeaseMessage
69	applyOutput   chan ports.OutputApply
70	appliedOutput chan ports.OutputApplied
71
72	// D-Bus idle inhibition and SimulateUserActivity (screensaver), for
73	// wayland's idle notifications. Activity sends never block: capacity 1
74	// coalesces them.
75	idleInhibited chan bool
76	idleActivity  chan struct{}
77
78	// Screencast commands to wayland (the screencast adapter's side is the
79	// sender); the events come back through wayland.Options.Casts.
80	castCommands chan ports.CastCommand
81}
82
83// newPipes makes the channels. The hint channels exist only with hint set
84// (hint.enable = on): without them core's hint action is a no-op and nothing
85// of hint mode is allocated.
86func newPipes(realSession, hint bool) *pipes {
87	p := &pipes{
88		securityChanges: make(chan ports.SecurityState, 8),
89		securityEvents:  make(chan ports.SecurityBackendEvent, 64),
90
91		client:   make(chan ports.ClientEvent, 32),
92		input:    make(chan ports.InputEvent, 32),
93		output:   make(chan ports.OutputEvent, 32),
94		commands: make(chan ports.ClientCommand, 32),
95		spawn:    make(chan ports.SpawnRequest, 32),
96
97		scenes:        make(chan []ports.Scene, 1),
98		renderScenes:  make(chan []ports.Scene, 1),
99		layouts:       make(chan ports.Layout, 1),
100		constraints:   make(chan ports.PointerConstraint, 1),
101		states:        make(chan ports.State, 1),
102		workspaces:    make(chan ports.Workspaces, 1),
103		cursorChanges: make(chan ports.CursorChange, 1),
104		keymaps:       make(chan *xkb.Keymap, 1),
105		deviceConfigs: make(chan ports.InputDevicesConfig, 1),
106
107		watched:      make(chan ports.ConfigChanged, 8),
108		filtered:     make(chan ports.ConfigChanged, 8),
109		configured:   make(chan ports.ConfigChanged, 8),
110		configErrors: make(chan error, 8),
111
112		frames: make(chan ports.OutputFrame, 8),
113
114		captures: make(chan ports.CaptureRequest, ports.MaxCaptureInflight),
115		captured: make(chan ports.CaptureDone, ports.MaxCaptureInflight),
116
117		outputFormats: make(chan ports.OutputFormats, 8),
118		outputHeads:   make(chan ports.OutputHeads, 8),
119		leaseRequests: make(chan ports.LeaseMessage, 32),
120		leaseEvents:   make(chan ports.LeaseMessage, 32),
121		applyOutput:   make(chan ports.OutputApply, 8),
122		appliedOutput: make(chan ports.OutputApplied, 8),
123
124		idleInhibited: make(chan bool, 1),
125		idleActivity:  make(chan struct{}, 1),
126
127		castCommands: make(chan ports.CastCommand, 64),
128	}
129	// Without hint mode every reply is for the wayland consumer: the outputs
130	// reply on its channel directly and nothing demultiplexes.
131	p.capturedAll = p.captured
132	if hint {
133		p.capturedAll = make(chan ports.CaptureDone, ports.MaxCaptureInflight)
134		p.hintScans = make(chan ports.HintScanRequest, 1)
135		p.hintResults = make(chan ports.HintScanResult, 1)
136		p.hintCaptured = make(chan ports.CaptureDone, 1)
137	}
138	if realSession {
139		p.scales = make(chan ports.ScaleChanged, 8)
140	}
141	return p
142}
143
144// core is core's side: channels only. The security gate, clock and terminal
145// flag are not channels; assembleSession passes them as core.Options.
146func (p *pipes) core() core.Channels {
147	return core.Channels{
148		Client:       p.client,
149		Input:        p.input,
150		Output:       p.output,
151		Config:       p.configured,
152		Commands:     p.commands,
153		Spawn:        p.spawn,
154		Scenes:       p.scenes,
155		Layouts:      p.layouts,
156		Constraints:  p.constraints,
157		State:        p.states,
158		Workspaces:   p.workspaces,
159		ConfigErrors: p.configErrors,
160		Scales:       p.scales,
161		Frames:       p.frames,
162		HintScans:    p.hintScans,
163		Hints:        p.hintResults,
164	}
165}
166
167// internalCaptured is the channel internal capture replies are routed to: the
168// hints adapter reads it.
169func (p *pipes) internalCaptured() chan<- ports.CaptureDone { return p.hintCaptured }
170
171// wayland is the wayland server's side.
172func (p *pipes) wayland() wayland.Channels {
173	return wayland.Channels{
174		SecurityChanges: p.securityChanges,
175		SecurityEvents:  p.securityEvents,
176		Events:          p.client,
177		Commands:        p.commands,
178		Workspaces:      p.workspaces,
179		Cursors:         p.cursorChanges,
180		Captures:        p.captures,
181		Captured:        p.captured,
182		OutputFormats:   p.outputFormats,
183		OutputHeads:     p.outputHeads,
184		LeaseRequests:   p.leaseRequests,
185		LeaseEvents:     p.leaseEvents,
186		OutputApply:     p.applyOutput,
187		OutputApplied:   p.appliedOutput,
188		IdleInhibited:   p.idleInhibited,
189		IdleActivity:    p.idleActivity,
190		CastCommands:    p.castCommands,
191	}
192}
193
194// outputs is the outputs' side (DRM or headless).
195func (p *pipes) outputs(security ports.SessionSecurity, presented ports.PresentationSink, content contentAttacher) outputChannels {
196	return outputChannels{
197		security:        security,
198		securityChanges: p.securityChanges,
199		securityEvents:  p.securityEvents,
200		events:          p.output,
201		scenes:          p.renderScenes,
202		cursorChanges:   p.cursorChanges,
203		presented:       presented,
204		content:         content,
205		frames:          p.frames,
206		captures:        p.captures,
207		captured:        p.capturedAll,
208		formats:         p.outputFormats,
209		heads:           p.outputHeads,
210		leaseRequests:   p.leaseRequests,
211		leaseEvents:     p.leaseEvents,
212		reloads:         p.filtered,
213		configured:      p.configured,
214		requests:        p.applyOutput,
215		replies:         p.appliedOutput,
216	}
217}

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 23

Tags 10

↑↓ moveenter openesc close