refactor/kvconf 3462c76

gestures.go RawHistoryFolder

1package wayland
2
3import (
4	"time"
5
6	"github.com/bnema/go-wayland-bindings/server/pointergestures"
7	"github.com/bnema/go-wayland-bindings/server/wayland"
8	"github.com/bnema/neferwl/internal/ports"
9	"github.com/bnema/purego-libwayland/server"
10)
11
12// zwp_pointer_gestures_v1: touchpad swipes (other than the compositor's own
13// three and four fingers), pinches and holds go to the client under the
14// pointer. A gesture belongs to the window that had the pointer when it
15// began; it ends cancelled when the pointer leaves that window.
16
17// gestureObject is one swipe, pinch or hold object of a client. Exactly one
18// of the three is set.
19type gestureObject struct {
20	swipe *pointergestures.ZwpPointerGestureSwipeV1
21	pinch *pointergestures.ZwpPointerGesturePinchV1
22	hold  *pointergestures.ZwpPointerGestureHoldV1
23}
24
25func (g *gestureObject) alive() bool {
26	switch {
27	case g.swipe != nil:
28		return g.swipe.Resource.Alive()
29	case g.pinch != nil:
30		return g.pinch.Resource.Alive()
31	case g.hold != nil:
32		return g.hold.Resource.Alive()
33	}
34	return false
35}
36
37func (g *gestureObject) kind() ports.GestureKind {
38	switch {
39	case g.pinch != nil:
40		return ports.GesturePinch
41	case g.hold != nil:
42		return ports.GestureHold
43	}
44	return ports.GestureSwipe
45}
46
47func (g *gestureObject) begin(serial uint32, at uint32, surf *wayland.Surface, fingers uint32) {
48	switch {
49	case g.swipe != nil:
50		g.swipe.SendBegin(serial, at, surf, fingers)
51	case g.pinch != nil:
52		g.pinch.SendBegin(serial, at, surf, fingers)
53	case g.hold != nil:
54		g.hold.SendBegin(serial, at, surf, fingers)
55	}
56}
57
58func (g *gestureObject) update(u ports.GestureUpdateTo) {
59	at := wireMsec(u.Time)
60	dx, dy := server.FixedFromFloat(u.DX), server.FixedFromFloat(u.DY)
61	switch {
62	case g.swipe != nil:
63		g.swipe.SendUpdate(at, dx, dy)
64	case g.pinch != nil:
65		g.pinch.SendUpdate(at, dx, dy, server.FixedFromFloat(u.Scale), server.FixedFromFloat(u.Rotation))
66	}
67}
68
69func (g *gestureObject) end(serial uint32, at uint32, cancelled int32) {
70	switch {
71	case g.swipe != nil:
72		g.swipe.SendEnd(serial, at, cancelled)
73	case g.pinch != nil:
74		g.pinch.SendEnd(serial, at, cancelled)
75	case g.hold != nil:
76		g.hold.SendEnd(serial, at, cancelled)
77	}
78}
79
80// activeGesture is the gesture sent to a window: the objects that got its
81// begin are the ones that get the rest, even when a client makes more
82// meanwhile.
83type activeGesture struct {
84	id   ports.WindowID
85	kind ports.GestureKind
86	objs []*gestureObject
87	// at is the latest device time sent, for a cancellation.
88	at time.Duration
89}
90
91func registerPointerGestures(d *server.Display, s *Server) error {
92	return pointergestures.NewZwpPointerGesturesV1Global(d, 3, func(c server.Client, v, id uint32) {
93		_, _ = pointergestures.NewZwpPointerGesturesV1(c, int32(v), id, gestureManager{s})
94	})
95}
96
97// gestureManager is zwp_pointer_gestures_v1. Releasing it leaves the
98// gesture objects it made alive, as the protocol says.
99type gestureManager struct{ server *Server }
100
101func (gestureManager) Release(*pointergestures.ZwpPointerGesturesV1) {}
102
103// gestureDestroy handles the destroy request of the three gesture objects;
104// the resource's OnDestroy forgets the object.
105type gestureDestroy struct{}
106
107func (gestureDestroy) Destroy(*pointergestures.ZwpPointerGestureSwipeV1) {}
108
109type pinchDestroy struct{}
110
111func (pinchDestroy) Destroy(*pointergestures.ZwpPointerGesturePinchV1) {}
112
113type holdDestroy struct{}
114
115func (holdDestroy) Destroy(*pointergestures.ZwpPointerGestureHoldV1) {}
116
117func (m gestureManager) GetSwipeGesture(r *pointergestures.ZwpPointerGesturesV1, id uint32, _ *wayland.Pointer) {
118	if res, err := pointergestures.NewZwpPointerGestureSwipeV1(r.Client(), r.Version(), id, gestureDestroy{}); err == nil {
119		m.server.addGesture(r.Client(), &gestureObject{swipe: res}, res.Resource)
120	}
121}
122
123func (m gestureManager) GetPinchGesture(r *pointergestures.ZwpPointerGesturesV1, id uint32, _ *wayland.Pointer) {
124	if res, err := pointergestures.NewZwpPointerGesturePinchV1(r.Client(), r.Version(), id, pinchDestroy{}); err == nil {
125		m.server.addGesture(r.Client(), &gestureObject{pinch: res}, res.Resource)
126	}
127}
128
129func (m gestureManager) GetHoldGesture(r *pointergestures.ZwpPointerGesturesV1, id uint32, _ *wayland.Pointer) {
130	if res, err := pointergestures.NewZwpPointerGestureHoldV1(r.Client(), r.Version(), id, holdDestroy{}); err == nil {
131		m.server.addGesture(r.Client(), &gestureObject{hold: res}, res.Resource)
132	}
133}
134
135// addGesture lists a client's gesture object until its resource dies.
136func (s *Server) addGesture(c server.Client, o *gestureObject, res *server.Resource) {
137	s.gestures[c] = append(s.gestures[c], o)
138	res.OnDestroy = func() {
139		if list := removeItem(s.gestures[c], o); len(list) > 0 {
140			s.gestures[c] = list
141		} else {
142			delete(s.gestures, c)
143		}
144	}
145}
146
147// beginGesture sends the begin of a gesture to the objects of the kind that
148// the client of the pointer-focus window made. A gesture still running
149// ends cancelled first. Nothing is recorded when the client has no object.
150func (s *Server) beginGesture(c ports.GestureBeginTo) {
151	s.cancelGesture()
152	if c.ID != s.seat.pointerFocus || c.Fingers <= 0 {
153		return
154	}
155	surf, _, _, _ := s.pointerSurface(c.ID, 0, 0)
156	if surf == nil {
157		return
158	}
159	var objs []*gestureObject
160	for _, o := range s.gestures[surf.Client()] {
161		if o.kind() == c.Kind && o.alive() {
162			objs = append(objs, o)
163		}
164	}
165	if len(objs) == 0 {
166		return
167	}
168	s.seat.gesture = &activeGesture{id: c.ID, kind: c.Kind, objs: objs, at: c.Time}
169	s.serial++
170	for _, o := range objs {
171		o.begin(s.serial, wireMsec(c.Time), surf, uint32(c.Fingers))
172	}
173}
174
175// updateGesture moves the running gesture of the window.
176func (s *Server) updateGesture(c ports.GestureUpdateTo) {
177	g := s.seat.gesture
178	if g == nil || g.id != c.ID || g.kind != c.Kind {
179		return
180	}
181	g.at = c.Time
182	for _, o := range g.objs {
183		if o.alive() {
184			o.update(c)
185		}
186	}
187}
188
189// endGesture ends the running gesture of the window.
190func (s *Server) endGesture(c ports.GestureEndTo) {
191	g := s.seat.gesture
192	if g == nil || g.id != c.ID || g.kind != c.Kind {
193		return
194	}
195	g.at = c.Time
196	s.finishGesture(c.Cancelled)
197}
198
199// cancelGesture ends the running gesture, if any, as cancelled: the
200// pointer left its window or the window went.
201func (s *Server) cancelGesture() {
202	if s.seat.gesture != nil {
203		s.finishGesture(true)
204	}
205}
206
207func (s *Server) finishGesture(cancelled bool) {
208	g := s.seat.gesture
209	s.seat.gesture = nil
210	state := int32(0)
211	if cancelled {
212		state = 1
213	}
214	s.serial++
215	for _, o := range g.objs {
216		if o.alive() {
217			o.end(s.serial, wireMsec(g.at), state)
218		}
219	}
220}

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