v0.3.0 cf370a0

scene.go RawHistoryFolder

1package ports
2
3import (
4	"image"
5	"math"
6	"os"
7)
8
9// Scene carries core → renderer immutable snapshots with fresh Windows slices,
10// one per output. Rects and the output size are logical and local to the
11// output; the renderer multiplies by Scale.
12type Scene struct {
13	// Security is the owner epoch captured when this scene was published.
14	// Output owners reject stale scenes rather than showing a queued desktop
15	// or accepting old locker buffers across acquisition/release.
16	Security                  SecurityState
17	Output                    string
18	Seq                       uint64
19	OutputWidth, OutputHeight int
20	Scale                     float64
21	// Transform is how the output target holds this scene
22	// (wl_output.transform); 0 for capture child scenes. OutputWidth and
23	// OutputHeight are already in the transformed (logical) orientation.
24	Transform BufferTransform
25	// Off turns the display off (output power management): nothing is
26	// drawn until a scene without it.
27	Off        bool
28	Background string
29	Border     Border
30	// WorkspaceClip bounds workspace windows, their popups and separators
31	// in logical output coordinates. Zero inherits the full output. Layers
32	// remain output-wide; overview previews do not use this clip.
33	WorkspaceClip Rect
34	// Dim darkens the background, bottom layers and tiles (tile lines
35	// included) inside WorkspaceClip when set, with black at this opacity,
36	// 0 to 1, under the first
37	// visible float. 0 draws nothing.
38	Dim float64
39	// DimBehind draws the Dim veil under every window instead, right over
40	// the background and bottom layers (the overview).
41	DimBehind bool
42	Windows   []SceneWindow
43	// Separators are the lines between windows, drawn in slice order with
44	// the Border colors: tile lines over the tiles, under the floats; a
45	// float's border right after the float.
46	Separators []Separator
47	// DropHints show where a dragged tile lands, filled with Border.Active
48	// over the windows of the workspace, under the top layers. Only the
49	// output under the pointer has them, during a drag.
50	DropHints []Rect
51	// Layers are the shown layer surfaces, drawn in slice order: background
52	// and bottom before windows, top and overlay after. Core leaves out
53	// those a fullscreen window hides (all but the background and a surface
54	// taking the keyboard exclusively); adapters draw every layer given.
55	// Window popups are drawn after the windows, layer popups
56	// (SceneWindow.OverLayers) last, over every layer.
57	Layers []SceneLayer
58	// Capture is the capture state of this output: exclusion and hidden
59	// workspace; nil while nothing is captured (capture.go).
60	Capture *SceneCapture
61	// CaptureScene is the workspace captured off screen (Capture.Workspace)
62	// drawn for capture only: a workspace that is not on screen. Only the
63	// root scene carries it; CaptureScene.Capture and .CaptureScene are nil.
64	CaptureScene *Scene
65	// CaptureIndicators are the marks of live captures of this output,
66	// drawn over everything; nil when none. Captures never hold them: the
67	// capture pipeline serves requests from a scene without them.
68	CaptureIndicators []CaptureIndicator
69}
70
71// Shows reports whether the scene draws the surface of id: only its
72// content changes need a new frame. A window scrolled off the output is
73// not drawn. WorkspaceClip also excludes off-viewport windows; OverLayers
74// popups remain output-wide.
75func (s Scene) Shows(id WindowID) bool {
76	for _, w := range s.Windows {
77		if w.ID == id && !w.Hidden && w.Rect.Overlaps(Rect{W: s.OutputWidth, H: s.OutputHeight}) &&
78			(w.OverLayers || s.WorkspaceClip == (Rect{}) || w.Rect.Overlaps(s.WorkspaceClip)) {
79			return true
80		}
81	}
82	for _, l := range s.Layers {
83		if l.ID == id {
84			return true
85		}
86	}
87	return false
88}
89
90// Border carries the window border style; colors are #rrggbb, "" skips
91// drawing. Width is in logical pixels.
92type Border struct {
93	Width            int
94	Active, Inactive string
95}
96
97// Separator is a line between windows, in logical pixels. Active lines
98// mark the focused window and use Border.Active, others Border.Inactive.
99// Window is the float whose border it is; 0 for lines between tiles.
100type Separator struct {
101	Rect   Rect
102	Active bool
103	Window WindowID
104}
105
106// SceneLayer carries core → renderer layer surface placement.
107type SceneLayer struct {
108	ID    WindowID
109	Layer Layer
110	Rect  Rect
111}
112
113// SurfaceColor is the committed encoding of a surface. Zero means sRGB.
114// PQ+BT.2020 and extended-linear sRGB are color-managed; zero is legacy
115// sRGB. MaxCLL/MaxFALL are in nits. YUV metadata is per surface commit.
116type SurfaceColor struct {
117	TF, Primaries   uint8
118	MaxCLL, MaxFALL uint16
119	// Coefficients/range follow wp_color_representation_v1 (zero =
120	// unspecified, for YUV interpreted as BT.709 limited). Chroma is a
121	// H.273 Chroma420SampleLocType + 1 (zero defaults to type 0).
122	Coefficients, Range, Chroma uint8
123}
124
125const (
126	ColorTFPQ             uint8 = 11 // wp_color_manager_v1 ST2084 PQ
127	ColorTFExtendedLinear uint8 = 5  // wp_color_manager_v1 ext_linear
128	ColorPrimariesBT2020  uint8 = 6  // wp_color_manager_v1 BT.2020
129	ColorPrimariesSRGB    uint8 = 1
130	ColorTFSRGB           uint8 = 9 // wp_color_manager_v1 sRGB
131)
132
133func (c SurfaceColor) IsPQ2020() bool {
134	return c.TF == ColorTFPQ && c.Primaries == ColorPrimariesBT2020
135}
136
137func (c SurfaceColor) IsExtendedLinear() bool {
138	return c.TF == ColorTFExtendedLinear && c.Primaries == ColorPrimariesSRGB
139}
140
141// ContentType is the committed wp_content_type_v1 hint.
142type ContentType uint8
143
144const (
145	ContentNone ContentType = iota
146	ContentPhoto
147	ContentVideo
148	ContentGame
149)
150
151// SurfaceContent carries wayland → output the latest committed content of a
152// window: SHM, a client shared-memory buffer, DMABuf, a GPU buffer, or
153// Solid, a single-pixel buffer. Renderers read them in place and never modify
154// them. Empty means the window
155// has no content. LogicalW and LogicalH are the surface size in logical
156// pixels (buffer scale and viewport applied). Subsurfaces come in Children;
157// Geometry is the part of the surface that is the window (xdg window
158// geometry), the rest being client shadows.
159type SurfaceContent struct {
160	ID          WindowID
161	ContentType ContentType
162	// Surface is a never-reused wl_surface identity; Version identifies its
163	// applied buffer content independently of the window publication Seq.
164	Surface, Version uint64
165	// Seq counts the window's contents (wayland sets it), for release.
166	Seq                uint64
167	Width, Height      int
168	LogicalW, LogicalH int
169	// Source is the committed crop in buffer pixels: x, y, width, height.
170	// Zero width means the entire buffer is used.
171	Source [4]float32
172	// Transform is the wl_output.transform the client applied to the
173	// buffer: readers apply its inverse. Width and Height stay the buffer's.
174	Transform BufferTransform
175	// Opaque ignores the alpha byte: an x format, or an opaque region that
176	// covers the whole surface. It is false while Fade is set.
177	Opaque bool
178	// Fade is how much wp_alpha_modifier_v1 fades the surface: 0 none,
179	// 1 invisible. Its opacity is multiplied by 1-Fade.
180	Fade   float32
181	Color  SurfaceColor
182	SHM    *SHMBuffer
183	DMABuf *DMABuf
184	// Solid is a single-pixel buffer (Width and Height are 1): the surface is
185	// one flat color.
186	Solid *SolidColor
187	// Children are the subsurfaces, bottom to top, flattened.
188	Children []Subsurface
189	// Geometry is in logical pixels from the surface origin; empty means
190	// the whole surface.
191	Geometry Rect
192	// Async asks for tearing presentation (wp_tearing_control_v1); outputs
193	// honour it only in direct scanout.
194	Async bool
195	// Acquire is the explicit-sync fence of this content's root buffer
196	// (wp_linux_drm_syncobj_v1): readers wait on it before reading the
197	// buffer, instead of the buffer's implicit fences. Wayland owns it and
198	// closes it when the buffer is released; a reader that keeps it past
199	// the call duplicates it under Acquire.SyscallConn. nil: implicit sync.
200	// Wayland closes it only after every output reported a later content of
201	// the window as seen, so a reader never gets it already closed.
202	Acquire *os.File
203	// DamageHistory is what changed in the root surface's buffer over the
204	// window's last contents, oldest first, ending with this one (Seq).
205	// A renderer holding an older content redraws the union of the
206	// entries after it, or everything when the history does not reach it.
207	DamageHistory []SeqDamage
208}
209
210// BufferTransform is a wl_output.transform value: bit 0 rotates 90°
211// counter-clockwise, bit 1 rotates 180°, bit 2 flips around the vertical
212// axis first.
213type BufferTransform uint8
214
215// Rotated reports whether width and height swap between buffer and surface.
216func (t BufferTransform) Rotated() bool { return t&1 != 0 }
217
218// Size returns the size of a w×h space seen through t: width and height swap
219// when t is Rotated.
220func (t BufferTransform) Size(w, h int) (int, int) {
221	if t.Rotated() {
222		return h, w
223	}
224	return w, h
225}
226
227// ToBuffer maps a point of a w×h surface (logical, before scale) to the
228// same point of its buffer, in the buffer's untransformed w'×h' axes, where
229// w' and h' swap when the transform is Rotated.
230func (t BufferTransform) ToBuffer(x, y, w, h float64) (float64, float64) {
231	if t&4 != 0 {
232		x = w - x
233	}
234	switch t & 3 {
235	case 1:
236		return y, w - x
237	case 2:
238		return w - x, h - y
239	case 3:
240		return h - y, x
241	}
242	return x, y
243}
244
245// Invert is the transform that maps target points back: for a w×h scene and
246// its w'×h' target, t.Invert().ToBuffer(t.ToBuffer(p, w, h), w', h') == p.
247func (t BufferTransform) Invert() BufferTransform {
248	if t&1 != 0 && t&4 == 0 {
249		return t ^ 2
250	}
251	return t
252}
253
254// RectToBuffer maps a rectangle of a w×h surface to the buffer. Integer
255// rectangles stay integer under these transforms; rounding absorbs float noise.
256func (t BufferTransform) RectToBuffer(r image.Rectangle, w, h int) image.Rectangle {
257	ax, ay := t.ToBuffer(float64(r.Min.X), float64(r.Min.Y), float64(w), float64(h))
258	bx, by := t.ToBuffer(float64(r.Max.X), float64(r.Max.Y), float64(w), float64(h))
259	return image.Rect(int(math.Round(ax)), int(math.Round(ay)), int(math.Round(bx)), int(math.Round(by)))
260}
261
262// SeqDamage is what content Seq changed from the one before: Rects in
263// root buffer pixels, or everything when Full.
264type SeqDamage struct {
265	Seq   uint64
266	Full  bool
267	Rects []Rect
268}
269
270// DamageSince is the union of changes after content seq up to this one,
271// and false when the history does not reach back to seq (redraw all).
272func (c SurfaceContent) DamageSince(seq uint64) ([]Rect, bool) {
273	if seq >= c.Seq {
274		return nil, true
275	}
276	h := c.DamageHistory
277	if len(h) == 0 || h[0].Seq > seq+1 || h[len(h)-1].Seq != c.Seq {
278		return nil, false
279	}
280	var out []Rect
281	for _, d := range h {
282		if d.Seq <= seq {
283			continue
284		}
285		if d.Full {
286			return nil, false
287		}
288		out = append(out, d.Rects...)
289	}
290	return out, true
291}
292
293// Subsurface is a child surface at X, Y logical pixels from the root
294// surface origin. Below children are drawn under the root surface.
295type Subsurface struct {
296	X, Y  int
297	Below bool
298	SurfaceContent
299}
300
301// HasBuffer reports whether the surface itself carries a client buffer.
302func (c SurfaceContent) HasBuffer() bool {
303	return c.SHM != nil || c.DMABuf != nil || c.Solid != nil
304}
305
306// SolidColor is the color of a single-pixel buffer: premultiplied by alpha,
307// 0 to 1, sRGB-encoded like the pixels of client buffers.
308type SolidColor struct{ R, G, B, A float32 }
309
310// Empty reports whether the content has nothing to draw.
311func (c SurfaceContent) Empty() bool {
312	return !c.HasBuffer() && len(c.Children) == 0
313}
314
315// SHMBuffer is a client wl_shm buffer: B8G8R8A8 pixels (argb8888/xrgb8888
316// little-endian) at Offset in the pool File, Stride bytes per row. The
317// client keeps writing the file, so renderers copy from it when they draw.
318// Pool is unique per wl_shm pool for the session: renderers map a pool
319// once. File stays open while the client's buffer exists and follows the
320// DMABuf rules: duplicate it under File.SyscallConn before keeping it. A
321// client may shrink the file at any time, so readers must survive faults.
322type SHMBuffer struct {
323	Pool           uint64
324	File           *os.File
325	Offset, Stride int
326}
327
328// DMABuf is a client GPU buffer (linux-dmabuf). Its files stay open while
329// the client's buffer exists; a renderer that keeps it must duplicate the
330// descriptors under File.SyscallConn so a concurrent close cannot hand it a
331// reused one. ID is unique per buffer for the whole session: renderers key
332// their imports on it.
333type DMABuf struct {
334	ID            uint64
335	Width, Height int
336	Format        uint32 // DRM fourcc
337	Modifier      uint64
338	Planes        []DMABufPlane
339}
340
341// DMABufPlane is one plane of a DMABuf.
342type DMABufPlane struct {
343	File           *os.File
344	Offset, Stride uint32
345}
346
347// DMABufFormat is a DRM fourcc with a modifier the renderer can import.
348type DMABufFormat struct {
349	Format   uint32
350	Modifier uint64
351}
352
353// DMABufSupport is what the renderer imports: the render device (a dev_t,
354// 0 when unknown) and the formats. No formats means no dmabuf.
355type DMABufSupport struct {
356	Device  uint64
357	Formats []DMABufFormat
358}
359
360// SceneWindow carries core → renderer window placement.
361type SceneWindow struct {
362	ID                          WindowID
363	Rect                        Rect
364	Focused, Fullscreen, Hidden bool
365	// Inset sides carry a separator line inside Rect: the client is drawn
366	// inside it.
367	Inset Sides
368	// Floating windows draw at their placed size. Below marks a native
369	// covering float behind the column group.
370	Floating, Below bool
371	// Dim darkens the window, border included, with black at this
372	// opacity, 0 to 1: a stashed window peeking in. 0 draws nothing.
373	Dim float64
374	// FocusEffect, above 0, is the focus indicator's effect at this frame
375	// (focus.animation, focus.effect): the window's surfaces are lifted
376	// toward white by that fraction (screen blend). Renderers without the
377	// effect ignore it.
378	//
379	// Only focus.effect = screen exists, so the effect kind is not carried:
380	// core ignores Config.Focus.Effect and the shaders always apply screen
381	// (compose.frag, compose_hdr.frag, push constant mapy.z). A second effect
382	// needs its kind here and in the push constants (a misc flag).
383	FocusEffect float64
384	// Preview, above 0, draws the window's surfaces that much smaller in
385	// Rect (an overview thumbnail): the client keeps its size.
386	Preview float64
387	// Popups are drawn from their content only: no border, no background.
388	Popup bool
389	// OverLayers popups hang from a layer surface: drawn over the top and
390	// overlay layers. Window popups stay with the windows, under them.
391	OverLayers bool
392}

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