v0.4.0 b6be3a8

tearing_test.go RawHistoryFolder

1package wayland
2
3import (
4	"testing"
5	"time"
6
7	"github.com/bnema/go-wayland-bindings/server/tearingcontrol"
8	"github.com/bnema/go-wayland-bindings/server/wayland"
9	"github.com/bnema/neferwl/internal/ports"
10)
11
12// asyncContent waits for a content of window id with the given hint.
13func asyncContent(t *testing.T, contents <-chan ports.SurfaceContent, id ports.WindowID, async bool) {
14	t.Helper()
15	deadline := time.After(2 * time.Second)
16	for {
17		select {
18		case c := <-contents:
19			if c.ID == id && c.Async == async {
20				return
21			}
22		case <-deadline:
23			t.Fatalf("no content with async=%v", async)
24		}
25	}
26}
27
28// A subsurface carries its own hint in the window's content, even when a
29// commit changes only the hint after the tree was cached (Wine presents
30// the game in a subsurface that the output scans out).
31func TestTearingHintOnSubsurface(t *testing.T) {
32	s, events, _, contents, dir := contentServer(t)
33	c := protocolClient(t, s, dir)
34	w, root, _ := surfaceMapper(t, c, events)()
35	comp := bindProtocol(t, c, "wl_compositor")
36	subc := bindProtocol(t, c, "wl_subcompositor")
37	child := c.AllocateID()
38	requestProtocol(t, c, comp, wayland.CompositorRequestCreateSurface, child)
39	registerProtocol(t, c, child)
40	sub := c.AllocateID()
41	requestProtocol(t, c, subc, wayland.SubcompositorRequestGetSubsurface, sub, child, root)
42	registerProtocol(t, c, sub)
43	requestProtocol(t, c, child, wayland.SurfaceRequestAttach, shmBuffer(t, c), int32(0), int32(0))
44	requestProtocol(t, c, child, wayland.SurfaceRequestCommit)
45	requestProtocol(t, c, root, wayland.SurfaceRequestCommit)
46	if err := c.Roundtrip(); err != nil {
47		t.Fatal(err)
48	}
49	childAsync := func(want bool) {
50		t.Helper()
51		deadline := time.After(2 * time.Second)
52		for {
53			select {
54			case got := <-contents:
55				if got.ID == w.ID && len(got.Children) == 1 && got.Children[0].Async == want {
56					if got.Async {
57						t.Fatal("child hint leaked to the root")
58					}
59					return
60				}
61			case <-deadline:
62				t.Fatalf("no content with child async=%v", want)
63			}
64		}
65	}
66	childAsync(false)
67
68	manager := bindProtocol(t, c, "wp_tearing_control_manager_v1")
69	control := c.AllocateID()
70	registerProtocol(t, c, control)
71	requestProtocol(t, c, manager, tearingcontrol.WpTearingControlManagerV1RequestGetTearingControl, control, child)
72	requestProtocol(t, c, control, tearingcontrol.WpTearingControlV1RequestSetPresentationHint, uint32(tearingcontrol.WpTearingControlV1PresentationHintAsync))
73	requestProtocol(t, c, child, wayland.SurfaceRequestCommit)
74	requestProtocol(t, c, root, wayland.SurfaceRequestCommit)
75	if err := c.Roundtrip(); err != nil {
76		t.Fatal(err)
77	}
78	childAsync(true)
79}
80
81func TestTearingHintAppliesOnCommit(t *testing.T) {
82	s, events, _, contents, dir := contentServer(t)
83	c := protocolClient(t, s, dir)
84	w, surf, _ := surfaceMapper(t, c, events)()
85	manager := bindProtocol(t, c, "wp_tearing_control_manager_v1")
86	control := c.AllocateID()
87	registerProtocol(t, c, control)
88	requestProtocol(t, c, manager, tearingcontrol.WpTearingControlManagerV1RequestGetTearingControl, control, surf)
89	requestProtocol(t, c, control, tearingcontrol.WpTearingControlV1RequestSetPresentationHint, uint32(tearingcontrol.WpTearingControlV1PresentationHintAsync))
90	if err := c.Roundtrip(); err != nil {
91		t.Fatal(err)
92	}
93	// Double-buffered: nothing changes before the commit.
94	select {
95	case got := <-contents:
96		if got.Async {
97			t.Fatal("hint applied before commit")
98		}
99	case <-time.After(50 * time.Millisecond):
100	}
101	requestProtocol(t, c, surf, wayland.SurfaceRequestCommit)
102	if err := c.Roundtrip(); err != nil {
103		t.Fatal(err)
104	}
105	asyncContent(t, contents, w.ID, true)
106
107	// Destroying the control goes back to vsync on the next commit.
108	requestProtocol(t, c, control, tearingcontrol.WpTearingControlV1RequestDestroy)
109	requestProtocol(t, c, surf, wayland.SurfaceRequestCommit)
110	if err := c.Roundtrip(); err != nil {
111		t.Fatal(err)
112	}
113	asyncContent(t, contents, w.ID, false)
114
115	// A control outliving its surface is inert.
116	inert := c.AllocateID()
117	registerProtocol(t, c, inert)
118	requestProtocol(t, c, manager, tearingcontrol.WpTearingControlManagerV1RequestGetTearingControl, inert, surf)
119	requestProtocol(t, c, surf, wayland.SurfaceRequestDestroy)
120	requestProtocol(t, c, inert, tearingcontrol.WpTearingControlV1RequestSetPresentationHint, uint32(tearingcontrol.WpTearingControlV1PresentationHintAsync))
121	if err := c.Roundtrip(); err != nil {
122		t.Fatal(err)
123	}
124	unmapped(t, events, w.ID)
125
126	// A surface has at most one control.
127	_, other, _ := surfaceMapper(t, c, events)()
128	first, second := c.AllocateID(), c.AllocateID()
129	registerProtocol(t, c, first)
130	registerProtocol(t, c, second)
131	requestProtocol(t, c, manager, tearingcontrol.WpTearingControlManagerV1RequestGetTearingControl, first, other)
132	requestProtocol(t, c, manager, tearingcontrol.WpTearingControlManagerV1RequestGetTearingControl, second, other)
133	expectProtocolError(t, c, manager, uint32(tearingcontrol.WpTearingControlManagerV1ErrorTearingControlExists))
134}

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