surfaces.go RawHistoryFolder

1// Package surfaces keeps the latest content of every window for an output's
2// renderer, and the last content of a window that closed while the scene
3// still draws it.
4package surfaces
5
6import (
7	"github.com/bnema/neferwl/internal/adapters/outputkit/capture"
8	"github.com/bnema/neferwl/internal/ports"
9)
10
11// Table is what an output passes to Renderer.Render: the latest content per
12// window. Its owner goroutine is the only user.
13//
14// A window that unmaps sends an empty content right after the core learns
15// of it; the scene that follows may keep drawing the window while it fades
16// out (ports.SceneWindow of a leaving window). The table then keeps the
17// window's last content until a scene no longer lists it, so the renderer
18// draws it from the buffer it already imported or copied: no new upload,
19// no copy. Its Acquire fence is dropped: the first frame that drew the
20// content waited on it, and wayland closes it once the buffer is released.
21//
22// Buffer lifetime: wayland releases the buffer to the client once the
23// output reports the empty content as seen, so the client may draw into,
24// destroy or reuse it during the fade. A kept content is therefore only
25// ever composed by the renderer, from what it already holds: the dmabuf
26// import (its own duplicated descriptors keep the memory alive; a reused
27// buffer shows stale pixels at worst) or the GPU copy of the wl_shm buffer
28// (the GPU never reads the pool mapping, and a pool's fd close does not
29// unmap it). A kept content is never scanned out on a plane and never
30// reported as shown: outputs ask Kept. Window capture never reaches it:
31// core resolves a window session through its workspace, which the closed
32// window has left, so the session ends (CaptureReasonWindowGone) before
33// the leaving scene; an output or workspace capture composes the fading
34// window like the screen does.
35// Every Acquire fence of the kept content (root and children) is dropped:
36// the frame that first drew it waited on them, and wayland closes them
37// when the buffers are released.
38type Table struct {
39	m map[ports.WindowID]ports.SurfaceContent
40	// kept are the windows drawn from a content their client withdrew.
41	kept map[ports.WindowID]struct{}
42}
43
44// New returns an empty table.
45func New() *Table {
46	return &Table{m: make(map[ports.WindowID]ports.SurfaceContent), kept: make(map[ports.WindowID]struct{})}
47}
48
49// Map is the contents the renderer draws from. It is the table's own map:
50// read it, never keep it across an Update or Prune.
51func (t *Table) Map() map[ports.WindowID]ports.SurfaceContent { return t.m }
52
53// Update takes a window's new content. An empty one (the window unmapped)
54// keeps the previous content, without its Acquire fence, while scene draws
55// the window; it drops it otherwise.
56func (t *Table) Update(c ports.SurfaceContent, scene ports.Scene) {
57	if !c.Empty() {
58		t.m[c.ID] = c
59		delete(t.kept, c.ID)
60		return
61	}
62	prev, ok := t.m[c.ID]
63	if !ok || !capture.Shows(scene, c.ID) {
64		delete(t.m, c.ID)
65		delete(t.kept, c.ID)
66		return
67	}
68	prev.Acquire = nil
69	if len(prev.Children) > 0 {
70		// The slice is shared with wayland's publication: copy before
71		// zeroing (one allocation per unmap).
72		children := make([]ports.Subsurface, len(prev.Children))
73		copy(children, prev.Children)
74		for i := range children {
75			children[i].Acquire = nil
76		}
77		prev.Children = children
78	}
79	t.m[c.ID] = prev
80	t.kept[c.ID] = struct{}{}
81}
82
83// Prune drops the kept contents of windows scene no longer draws. Outputs
84// call it with every scene they accept.
85func (t *Table) Prune(scene ports.Scene) {
86	for id := range t.kept {
87		if !capture.Shows(scene, id) {
88			delete(t.m, id)
89			delete(t.kept, id)
90		}
91	}
92}
93
94// Kept reports whether id is drawn from a content its client withdrew: a
95// buffer the client may have got back. Outputs compose it only: no plane
96// scans it out, no capture or presentation report counts it as shown.
97func (t *Table) Kept(id ports.WindowID) bool {
98	_, ok := t.kept[id]
99	return ok
100}
101
102// Shown is the presentation rule both output backends report with: id was
103// shown to its client when scene draws it and its content is not kept. A
104// nil kept counts nothing as kept.
105func Shown(scene ports.Scene, id ports.WindowID, kept func(ports.WindowID) bool) bool {
106	return scene.Shows(id) && (kept == nil || !kept(id))
107}
108
109// FillShown clears dst and fills it with the windows of seen that scene
110// showed to their client (Shown), at their seen Seq.
111func FillShown(dst, seen map[ports.WindowID]uint64, scene ports.Scene, kept func(ports.WindowID) bool) {
112	clear(dst)
113	for id, seq := range seen {
114		if Shown(scene, id, kept) {
115			dst[id] = seq
116		}
117	}
118}

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