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 captures chan ports.CaptureRequest
50 // Every admitted capture owns one reply slot until wayland consumes it.
51 // Keep this capacity tied to admission so output routing never waits.
52 captured chan ports.CaptureDone
53
54 outputFormats chan ports.OutputFormats
55 outputHeads chan ports.OutputHeads
56 leaseRequests chan ports.LeaseMessage
57 leaseEvents chan ports.LeaseMessage
58 applyOutput chan ports.OutputApply
59 appliedOutput chan ports.OutputApplied
60
61 // D-Bus idle inhibition and SimulateUserActivity (screensaver), for
62 // wayland's idle notifications. Activity sends never block: capacity 1
63 // coalesces them.
64 idleInhibited chan bool
65 idleActivity chan struct{}
66}
67
68func newPipes(realSession bool) *pipes {
69 p := &pipes{
70 securityChanges: make(chan ports.SecurityState, 8),
71 securityEvents: make(chan ports.SecurityBackendEvent, 64),
72
73 client: make(chan ports.ClientEvent, 32),
74 input: make(chan ports.InputEvent, 32),
75 output: make(chan ports.OutputEvent, 32),
76 commands: make(chan ports.ClientCommand, 32),
77 spawn: make(chan ports.SpawnRequest, 32),
78
79 scenes: make(chan []ports.Scene, 1),
80 renderScenes: make(chan []ports.Scene, 1),
81 layouts: make(chan ports.Layout, 1),
82 constraints: make(chan ports.PointerConstraint, 1),
83 states: make(chan ports.State, 1),
84 workspaces: make(chan ports.Workspaces, 1),
85 cursorChanges: make(chan ports.CursorChange, 1),
86 keymaps: make(chan *xkb.Keymap, 1),
87 deviceConfigs: make(chan ports.InputDevicesConfig, 1),
88
89 watched: make(chan ports.ConfigChanged, 8),
90 filtered: make(chan ports.ConfigChanged, 8),
91 configured: make(chan ports.ConfigChanged, 8),
92 configErrors: make(chan error, 8),
93
94 frames: make(chan ports.OutputFrame, 8),
95
96 captures: make(chan ports.CaptureRequest, ports.MaxCaptureInflight),
97 captured: make(chan ports.CaptureDone, ports.MaxCaptureInflight),
98
99 outputFormats: make(chan ports.OutputFormats, 8),
100 outputHeads: make(chan ports.OutputHeads, 8),
101 leaseRequests: make(chan ports.LeaseMessage, 32),
102 leaseEvents: make(chan ports.LeaseMessage, 32),
103 applyOutput: make(chan ports.OutputApply, 8),
104 appliedOutput: make(chan ports.OutputApplied, 8),
105
106 idleInhibited: make(chan bool, 1),
107 idleActivity: make(chan struct{}, 1),
108 }
109 if realSession {
110 p.scales = make(chan ports.ScaleChanged, 8)
111 }
112 return p
113}
114
115// core is core's side: channels only. The security gate, clock and terminal
116// flag are not channels; assembleSession passes them as core.Options.
117func (p *pipes) core() core.Channels {
118 return core.Channels{
119 Client: p.client,
120 Input: p.input,
121 Output: p.output,
122 Config: p.configured,
123 Commands: p.commands,
124 Spawn: p.spawn,
125 Scenes: p.scenes,
126 Layouts: p.layouts,
127 Constraints: p.constraints,
128 State: p.states,
129 Workspaces: p.workspaces,
130 ConfigErrors: p.configErrors,
131 Scales: p.scales,
132 Frames: p.frames,
133 }
134}
135
136// wayland is the wayland server's side.
137func (p *pipes) wayland() wayland.Channels {
138 return wayland.Channels{
139 SecurityChanges: p.securityChanges,
140 SecurityEvents: p.securityEvents,
141 Events: p.client,
142 Commands: p.commands,
143 Workspaces: p.workspaces,
144 Cursors: p.cursorChanges,
145 Captures: p.captures,
146 Captured: p.captured,
147 OutputFormats: p.outputFormats,
148 OutputHeads: p.outputHeads,
149 LeaseRequests: p.leaseRequests,
150 LeaseEvents: p.leaseEvents,
151 OutputApply: p.applyOutput,
152 OutputApplied: p.appliedOutput,
153 IdleInhibited: p.idleInhibited,
154 IdleActivity: p.idleActivity,
155 }
156}
157
158// outputs is the outputs' side (DRM or headless).
159func (p *pipes) outputs(security ports.SessionSecurity, presented ports.PresentationSink, content contentAttacher) outputChannels {
160 return outputChannels{
161 security: security,
162 securityChanges: p.securityChanges,
163 securityEvents: p.securityEvents,
164 events: p.output,
165 scenes: p.renderScenes,
166 cursorChanges: p.cursorChanges,
167 presented: presented,
168 content: content,
169 frames: p.frames,
170 captures: p.captures,
171 captured: p.captured,
172 formats: p.outputFormats,
173 heads: p.outputHeads,
174 leaseRequests: p.leaseRequests,
175 leaseEvents: p.leaseEvents,
176 reloads: p.filtered,
177 configured: p.configured,
178 requests: p.applyOutput,
179 replies: p.appliedOutput,
180 }
181}