v0.4.0 b6be3a8

configures.go RawHistoryFolder

1package core
2
3import "github.com/bnema/neferwl/internal/ports"
4
5// configureTarget is where a placement is shown, as the configure needs it.
6type configureTarget struct {
7	output  string
8	area    Rect // the output, to tell whether the window is on screen
9	focused bool // activated: focused on the focused output
10	// client is the placement minus borders; imposed reports core sized a
11	// floating window (native floats pick their own size).
12	client  Rect
13	imposed bool
14	// captureArea is the viewport of the workspace a capture session renders
15	// off screen, when this window belongs to it (captureConfigure).
16	captureArea Rect
17	// realTiled sizes a visible tiled preview from its real client rect.
18	realTiled bool
19	// captured: a capture session renders this window off screen (window
20	// capture), so off screen it is Captured, not suspended.
21	captured bool
22}
23
24// configures owns the last configure sent to each window and decides the
25// next one. Configures are sent only when they change.
26type configures struct {
27	sent map[WindowID]ports.ConfigureWindow
28	seen map[WindowID]bool
29	// answer holds windows whose state request awaits a configure, sent
30	// even unchanged: xdg-shell answers every request, a refused one too.
31	answer map[WindowID]bool
32	// cw is the workspace a capture session renders off screen, if any.
33	cw captureWorkspace
34}
35
36func newConfigures() configures {
37	return configures{sent: map[WindowID]ports.ConfigureWindow{}, seen: map[WindowID]bool{}, answer: map[WindowID]bool{}}
38}
39
40// next returns the configure for p at t and whether it must be sent. The
41// caller records it with mark once sent.
42func (s *configures) next(p Placement, t configureTarget) (ports.ConfigureWindow, bool) {
43	s.seen[p.ID] = true
44	old, ok := s.sent[p.ID]
45	v := build(p, t, old, ok)
46	v.Captured = t.captured && !v.Visible
47	if t.captured && p.Hidden && t.client.W > 0 && t.client.H > 0 {
48		// Hidden but captured: sized for the capture, which follows its real
49		// layout.
50		v.Width, v.Height = t.client.W, t.client.H
51	}
52	return v, !ok || v != old || s.answer[p.ID]
53}
54
55// nextWithCapture is next for a window of a workspace a capture session
56// renders off screen. p is its placement on the physical layout; cp is its
57// real placement on its own workspace, laid out in the viewport
58// t.captureArea (nil: not captured, exactly next).
59//
60// A hidden p is sized from cp like a shown window and stays physically
61// invisible and deactivated (Visible false). Any other p (an overview
62// preview) is configured as usual, keeping its real size; only when the
63// display does not show it does it get Captured, so a capture that draws it
64// does not see it suspended. Captured is set when cp is drawn in the
65// viewport.
66func (s *configures) nextWithCapture(p Placement, t configureTarget, cp *Placement) (ports.ConfigureWindow, bool) {
67	if cp == nil {
68		return s.next(p, t)
69	}
70	s.seen[p.ID] = true
71	old, ok := s.sent[p.ID]
72	var v ports.ConfigureWindow
73	if p.Hidden {
74		t.focused = false
75		v = build(*cp, t, old, ok)
76		v.Activated, v.Visible = false, false
77	} else {
78		v = build(p, t, old, ok)
79	}
80	v.Captured = !v.Visible && (t.captured || !cp.Hidden && cp.Rect.Overlaps(t.captureArea))
81	return v, !ok || v != old || s.answer[p.ID]
82}
83
84// build is the configure for p at t given the last one sent, if any. It
85// never sets Captured: only nextWithCapture does, so a window that leaves a
86// capture session drops the flag with its next configure.
87func build(p Placement, t configureTarget, old ports.ConfigureWindow, ok bool) ports.ConfigureWindow {
88	var v ports.ConfigureWindow
89	switch {
90	case p.Hidden:
91		// A hidden window keeps its size, state and output; it is only
92		// deactivated and marked invisible. One mapped hidden is told so
93		// at once, sized by the client.
94		v = old
95		if !ok {
96			v = ports.ConfigureWindow{ID: p.ID, Floating: p.Floating}
97		}
98		v.Activated, v.Visible, v.Output, v.Captured = false, false, t.output, false
99	case p.Preview > 0:
100		// A preview keeps its client's size: only its focus changes.
101		v = old
102		if !ok {
103			v = ports.ConfigureWindow{ID: p.ID, Width: int(float64(p.Rect.W) / p.Preview), Height: int(float64(p.Rect.H) / p.Preview), Floating: p.Floating}
104			if p.Floating {
105				// A native float picks its own size.
106				v.Width, v.Height = 0, 0
107			}
108		}
109		if p.Fullscreen && !v.Fullscreen {
110			// A float made fullscreen off screen: its preview row shows
111			// it fullscreen, sized for the output, never the preview.
112			v.Width, v.Height, v.Fullscreen, v.Floating = t.area.W, t.area.H, true, false
113		}
114		if t.realTiled {
115			v.Width, v.Height = t.client.W, t.client.H
116		}
117		v.Activated, v.Visible, v.Output, v.Captured = t.focused, onScreen(p, t.area), t.output, false
118	default:
119		v = ports.ConfigureWindow{ID: p.ID, Width: t.client.W, Height: t.client.H, Fullscreen: p.Fullscreen, Activated: t.focused, Floating: p.Floating && !p.Fullscreen, Output: t.output, Visible: onScreen(p, t.area)}
120		if v.Floating && !t.imposed {
121			v.Width, v.Height = 0, 0
122		}
123	}
124	return v
125}
126
127// mark records v as sent.
128func (s *configures) mark(v ports.ConfigureWindow) {
129	s.sent[v.ID] = v
130	delete(s.answer, v.ID)
131}
132
133// keep marks id as seen without a configure: a window drawn while it leaves
134// keeps what was sent to it. Only for a window the layout still holds (a
135// hidden stash window): a destroyed one is forgotten (forget).
136func (s *configures) keep(id WindowID) { s.seen[id] = true }
137
138// forget drops what was sent to id: the window is unmapped. A toplevel
139// that maps again keeps its ID, so it must start from nothing, or an
140// unchanged first configure would be withheld.
141func (s *configures) forget(id WindowID) {
142	delete(s.sent, id)
143	delete(s.answer, id)
144	delete(s.seen, id)
145}
146
147// prune forgets the windows no next call saw since the last prune: they
148// left the layout.
149func (s *configures) prune() {
150	for id := range s.sent {
151		if !s.seen[id] {
152			delete(s.sent, id)
153		}
154	}
155	for id := range s.answer {
156		if !s.seen[id] {
157			delete(s.answer, id)
158		}
159	}
160	clear(s.seen)
161}

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 25

Tags 10

↑↓ moveenter openesc close