clientgesture.go RawHistoryFolder

1package core
2
3import (
4	"context"
5	"time"
6
7	"github.com/bnema/neferwl/internal/ports"
8)
9
10// Touchpad gestures the compositor does not use go to the client under the
11// pointer (zwp_pointer_gestures_v1): swipes of any finger count but three
12// and four, every pinch and every hold. Like scrolling, they follow the
13// pointer focus. Three- and four-finger swipes stay with the compositor
14// (gesture.go).
15
16// clientGesture is the gesture being forwarded to a client. Input streams
17// one gesture at a time. A gesture that begins with no pointer focus, or
18// whose focus moved, still takes its stream (on stays set) so the rest of
19// it never reaches the compositor or another window.
20type clientGesture struct {
21	on   bool
22	kind ports.GestureKind
23	// id is the window that got the begin; 0 once cancelled or when none had
24	// the pointer.
25	id WindowID
26	// at is the device time of the latest event, for a cancellation.
27	at time.Duration
28}
29
30// forwardsSwipe reports whether the compositor leaves a swipe of that many
31// fingers to the client.
32func forwardsSwipe(fingers int) bool { return fingers != 3 && fingers != 4 }
33
34// gestureBegin starts forwarding a gesture to the window with the pointer
35// focus. One still running (its end was lost) ends cancelled first.
36func (c *Core) gestureBegin(ctx context.Context, kind ports.GestureKind, fingers int, at time.Duration) error {
37	if err := c.gestureAbort(ctx, at); err != nil {
38		return err
39	}
40	c.gesture = clientGesture{on: true, kind: kind, at: at}
41	if c.pointer == 0 || c.drag != nil {
42		return nil
43	}
44	c.gesture.id = c.pointer
45	return c.command(ctx, ports.GestureBeginTo{ID: c.pointer, Kind: kind, Fingers: fingers, Time: at})
46}
47
48// gestureUpdate moves the forwarded gesture of that kind. A window that
49// lost the pointer meanwhile gets its gesture cancelled.
50func (c *Core) gestureUpdate(ctx context.Context, u ports.GestureUpdateTo) error {
51	g := &c.gesture
52	if !g.on || g.kind != u.Kind {
53		return nil
54	}
55	g.at = u.Time
56	if g.id == 0 {
57		return nil
58	}
59	if g.id != c.pointer {
60		return c.gestureCancel(ctx)
61	}
62	u.ID = g.id
63	return c.command(ctx, u)
64}
65
66// gestureEnd ends the forwarded gesture of that kind.
67func (c *Core) gestureEnd(ctx context.Context, kind ports.GestureKind, cancelled bool, at time.Duration) error {
68	g := c.gesture
69	if !g.on || g.kind != kind {
70		return nil
71	}
72	c.gesture = clientGesture{}
73	if g.id == 0 {
74		return nil
75	}
76	if at == 0 {
77		// A removed device's end has no time: the client's clock must
78		// not run backwards.
79		at = g.at
80	}
81	return c.command(ctx, ports.GestureEndTo{ID: g.id, Kind: kind, Cancelled: cancelled || g.id != c.pointer, Time: at})
82}
83
84// gestureAbort ends whatever gesture is forwarded, cancelled.
85func (c *Core) gestureAbort(ctx context.Context, at time.Duration) error {
86	if !c.gesture.on {
87		return nil
88	}
89	return c.gestureEnd(ctx, c.gesture.kind, true, at)
90}
91
92// gestureCancel ends the gesture of the window that lost the pointer, as
93// cancelled. The rest of the device's gesture is swallowed.
94func (c *Core) gestureCancel(ctx context.Context) error {
95	g := &c.gesture
96	if !g.on || g.id == 0 {
97		return nil
98	}
99	id := g.id
100	g.id = 0
101	return c.command(ctx, ports.GestureEndTo{ID: id, Kind: g.kind, Cancelled: true, Time: g.at})
102}
103
104// pointerFocus sends a pointer focus change; the window leaving the
105// pointer first gets its gesture cancelled, so its client sees the end
106// before the leave.
107func (c *Core) pointerFocus(ctx context.Context, f ports.PointerFocus) error {
108	if c.gesture.id != 0 && c.gesture.id != f.ID {
109		if err := c.gestureCancel(ctx); err != nil {
110			return err
111		}
112	}
113	return c.command(ctx, f)
114}

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