main 3d41bc5

shm.go RawHistoryFolder

1package wayland
2
3import (
4	"errors"
5	"fmt"
6
7	core "github.com/bnema/go-wayland-bindings/client/wayland"
8	"github.com/bnema/wlturbo"
9	"golang.org/x/sys/unix"
10
11	"github.com/bnema/nefercap/internal/ports"
12)
13
14// bufGeom is the buffer layout announced by the compositor. It is reused only
15// while the compositor keeps announcing the same one.
16type bufGeom struct {
17	format, width, height, stride uint32
18	size                          int
19}
20
21// validate bounds every dimension before any memory is created or mapped.
22func (g *bufGeom) validate() error {
23	if g.width < 1 || g.height < 1 || g.width > ports.MaxDimension || g.height > ports.MaxDimension {
24		return fmt.Errorf("wayland: invalid buffer dimensions %dx%d", g.width, g.height)
25	}
26	if g.stride < g.width*ports.BytesPerPixel || g.stride%ports.BytesPerPixel != 0 || g.stride > ports.MaxFrameBytes/g.height {
27		return fmt.Errorf("wayland: invalid buffer stride %d for %dx%d", g.stride, g.width, g.height)
28	}
29	g.size = int(g.stride) * int(g.height)
30	return nil
31}
32
33// shmBuffer is one wl_shm mapping and wl_buffer reused between captures. A
34// Source has two: one holds the last frame while the next is written. The pool
35// proxy is destroyed right after buffer creation, which the protocol allows:
36// the buffer keeps the compositor-side mapping alive.
37type shmBuffer struct {
38	geom   bufGeom
39	data   []byte
40	buffer *core.Buffer
41}
42
43// ensureBuffer makes s.bufs[i] match g, reusing it when unchanged.
44func (s *Source) ensureBuffer(i int, g bufGeom) error {
45	if s.bufs[i].buffer != nil && s.bufs[i].geom == g {
46		return nil
47	}
48	if err := s.releaseBuffer(i, true); err != nil {
49		s.terminate()
50		return err
51	}
52	fd, err := wlturbo.CreateAnonymousFile(int64(g.size))
53	if err != nil {
54		return fmt.Errorf("wayland: create shm file: %w", err)
55	}
56	data, err := wlturbo.MapMemory(fd, g.size)
57	if err != nil {
58		_ = unix.Close(fd)
59		return fmt.Errorf("wayland: map shm file: %w", err)
60	}
61	// Context.Request closes fd once the message is sent, so on success the
62	// descriptor belongs to the transport (the mapping outlives it). On error
63	// the caller still owns it.
64	pool, err := s.shm.CreatePool(fd, int32(g.size))
65	if err != nil {
66		_ = unix.Close(fd)
67		_ = wlturbo.UnmapMemory(data)
68		s.terminate()
69		return fmt.Errorf("wayland: create pool: %w", err)
70	}
71	buffer, err := pool.CreateBuffer(0, int32(g.width), int32(g.height), int32(g.stride), g.format)
72	_ = pool.Destroy()
73	if err != nil {
74		_ = wlturbo.UnmapMemory(data)
75		s.terminate()
76		return fmt.Errorf("wayland: create buffer: %w", err)
77	}
78	s.bufs[i] = shmBuffer{geom: g, data: data, buffer: buffer}
79	return nil
80}
81
82// releaseBuffer unmaps the storage of s.bufs[i]. With destroy set, and while
83// connected, it also destroys the wl_buffer. The caller holds opMu.
84func (s *Source) releaseBuffer(i int, destroy bool) error {
85	b := s.bufs[i]
86	s.bufs[i] = shmBuffer{}
87	var err error
88	if b.buffer != nil && destroy && !s.dead.Load() {
89		err = b.buffer.Destroy()
90	}
91	if b.data != nil {
92		err = errors.Join(err, wlturbo.UnmapMemory(b.data))
93	}
94	return err
95}
96
97// releaseBuffers releases both buffers without destroying the wl_buffers: the
98// connection is ending.
99func (s *Source) releaseBuffers() error {
100	return errors.Join(s.releaseBuffer(0, false), s.releaseBuffer(1, false))
101}

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 2

Tags 9

↑↓ moveenter openesc close