v0.4.0 b6be3a8

inhibit_test.go RawHistoryFolder

1package wayland
2
3import (
4	"testing"
5	"time"
6
7	"github.com/bnema/go-wayland-bindings/server/idleinhibit"
8	"github.com/bnema/go-wayland-bindings/server/keyboardshortcutsinhibit"
9	"github.com/bnema/neferwl/internal/ports"
10	"github.com/bnema/wlturbo"
11)
12
13type inhibitorProxy struct {
14	wlturbo.BaseProxy
15	states chan bool
16}
17
18func (p *inhibitorProxy) Dispatch(e *wlturbo.Event) {
19	p.states <- uint32(e.Opcode) == keyboardshortcutsinhibit.ZwpKeyboardShortcutsInhibitorV1EventActive
20}
21
22// clientEvent waits for the next client event of type T.
23func clientEvent[T ports.ClientEvent](t *testing.T, events <-chan ports.ClientEvent) T {
24	t.Helper()
25	deadline := time.After(2 * time.Second)
26	for {
27		select {
28		case ev := <-events:
29			if v, ok := ev.(T); ok {
30				return v
31			}
32		case <-deadline:
33			var zero T
34			t.Fatalf("no %T", zero)
35			return zero
36		}
37	}
38}
39
40func TestShortcutsInhibitor(t *testing.T) {
41	s, events, commands, _, dir := contentServer(t)
42	c := protocolClient(t, s, dir)
43	w, surf, _ := surfaceMapper(t, c, events)()
44	seat := bindProtocol(t, c, "wl_seat")
45	registerProtocol(t, c, seat)
46	mgr := bindProtocol(t, c, "zwp_keyboard_shortcuts_inhibit_manager_v1")
47	in := c.AllocateID()
48	p := &inhibitorProxy{states: make(chan bool, 4)}
49	p.SetID(in)
50	registerWireProxy(c, p)
51	requestProtocol(t, c, mgr, keyboardshortcutsinhibit.ZwpKeyboardShortcutsInhibitManagerV1RequestInhibitShortcuts, in, surf, seat)
52	if v := clientEvent[ports.ShortcutsInhibit](t, events); v != (ports.ShortcutsInhibit{Window: w.ID, Active: true}) {
53		t.Fatal(v)
54	}
55	// Core decides: active, then inactive.
56	state := func(active bool) {
57		t.Helper()
58		commands <- ports.ShortcutsInhibitState{Window: w.ID, Active: active}
59		deadline := time.Now().Add(2 * time.Second)
60		for time.Now().Before(deadline) {
61			if err := c.Roundtrip(); err != nil {
62				t.Fatal(err)
63			}
64			select {
65			case got := <-p.states:
66				if got != active {
67					t.Fatalf("state %v", got)
68				}
69				return
70			case <-time.After(5 * time.Millisecond):
71			}
72		}
73		t.Fatal("no active/inactive event")
74	}
75	state(true)
76	state(false)
77	// Destroying it tells core.
78	requestProtocol(t, c, in, keyboardshortcutsinhibit.ZwpKeyboardShortcutsInhibitorV1RequestDestroy)
79	if v := clientEvent[ports.ShortcutsInhibit](t, events); v.Active {
80		t.Fatal(v)
81	}
82	// A second inhibitor on the same surface is a protocol error.
83	requestProtocol(t, c, mgr, keyboardshortcutsinhibit.ZwpKeyboardShortcutsInhibitManagerV1RequestInhibitShortcuts, c.AllocateID(), surf, seat)
84	requestProtocol(t, c, mgr, keyboardshortcutsinhibit.ZwpKeyboardShortcutsInhibitManagerV1RequestInhibitShortcuts, c.AllocateID(), surf, seat)
85	expectProtocolError(t, c, mgr, uint32(keyboardshortcutsinhibit.ZwpKeyboardShortcutsInhibitManagerV1ErrorAlreadyInhibited))
86}
87
88// Idle inhibitors: several per surface, the window is reported once and
89// released when the last one goes.
90func TestIdleInhibitors(t *testing.T) {
91	s, events, _, _, dir := contentServer(t)
92	c := protocolClient(t, s, dir)
93	w, surf, _ := surfaceMapper(t, c, events)()
94	mgr := bindProtocol(t, c, "zwp_idle_inhibit_manager_v1")
95	a, b := c.AllocateID(), c.AllocateID()
96	registerProtocol(t, c, a)
97	registerProtocol(t, c, b)
98	requestProtocol(t, c, mgr, idleinhibit.ZwpIdleInhibitManagerV1RequestCreateInhibitor, a, surf)
99	requestProtocol(t, c, mgr, idleinhibit.ZwpIdleInhibitManagerV1RequestCreateInhibitor, b, surf)
100	if v := clientEvent[ports.IdleInhibit](t, events); v != (ports.IdleInhibit{Window: w.ID, Active: true}) {
101		t.Fatal(v)
102	}
103	requestProtocol(t, c, a, idleinhibit.ZwpIdleInhibitorV1RequestDestroy)
104	requestProtocol(t, c, b, idleinhibit.ZwpIdleInhibitorV1RequestDestroy)
105	if v := clientEvent[ports.IdleInhibit](t, events); v.Active {
106		t.Fatal(v)
107	}
108	if err := c.Roundtrip(); err != nil {
109		t.Fatal(err)
110	}
111	select {
112	case ev := <-events:
113		if _, ok := ev.(ports.IdleInhibit); ok {
114			t.Fatalf("extra %+v", ev)
115		}
116	default:
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 25

Tags 10

↑↓ moveenter openesc close