v0.10.0 d5d679d

dialog_test.go RawHistoryFolder

1package wayland
2
3import (
4	"testing"
5	"time"
6
7	"github.com/bnema/go-wayland-bindings/server/wayland"
8	"github.com/bnema/go-wayland-bindings/server/xdgdialog"
9	"github.com/bnema/go-wayland-bindings/server/xdgshell"
10	"github.com/bnema/neferwl/internal/ports"
11	"golang.org/x/sys/unix"
12)
13
14// A modal dialog maps with its state, and later changes reach core. A
15// second dialog object for the same toplevel is a protocol error.
16func TestDialogModal(t *testing.T) {
17	s, events, _, dir := lifecycleServer(t)
18	c := protocolClient(t, s, dir)
19	parent, _, parentXDG := surfaceMapper(t, c, events)()
20	// surfaceMapper allocates the toplevel right after its xdg_surface.
21	parentTop := parentXDG + 1
22
23	comp := bindProtocol(t, c, "wl_compositor")
24	wm := bindProtocol(t, c, "xdg_wm_base")
25	shm := bindProtocol(t, c, "wl_shm")
26	registerProtocol(t, c, shm)
27	dialogs := bindProtocol(t, c, "xdg_wm_dialog_v1")
28	fd, err := unix.MemfdCreate("dialog-buffer", 0)
29	if err != nil {
30		t.Fatal(err)
31	}
32	defer unix.Close(fd)
33	if err := unix.Ftruncate(fd, 4); err != nil {
34		t.Fatal(err)
35	}
36	pool, buffer := c.AllocateID(), c.AllocateID()
37	registerProtocol(t, c, pool)
38	registerProtocol(t, c, buffer)
39	if err := wireRequest(c, shm, uint16(wayland.ShmRequestCreatePool), []int{fd}, pool, int32(4)); err != nil {
40		t.Fatal(err)
41	}
42	requestProtocol(t, c, pool, wayland.ShmPoolRequestCreateBuffer, buffer, int32(0), int32(1), int32(1), int32(4), uint32(0))
43
44	// The dialog toplevel: modal before its first frame.
45	surf, xdg, top, dlg := c.AllocateID(), c.AllocateID(), c.AllocateID(), c.AllocateID()
46	requestProtocol(t, c, comp, wayland.CompositorRequestCreateSurface, surf)
47	registerProtocol(t, c, surf)
48	requestProtocol(t, c, wm, xdgshell.WmBaseRequestGetXdgSurface, xdg, surf)
49	serials := make(chan uint32, 1)
50	xp := &configureProxy{serial: serials}
51	xp.SetID(xdg)
52	registerWireProxy(c, xp)
53	registerProtocol(t, c, top)
54	requestProtocol(t, c, xdg, xdgshell.SurfaceRequestGetToplevel, top)
55	registerProtocol(t, c, dlg)
56	requestProtocol(t, c, dialogs, xdgdialog.WmDialogV1RequestGetXdgDialog, dlg, top)
57	requestProtocol(t, c, dlg, xdgdialog.DialogV1RequestSetModal)
58	requestProtocol(t, c, top, xdgshell.ToplevelRequestSetParent, parentTop)
59	requestProtocol(t, c, surf, wayland.SurfaceRequestCommit)
60	if err := c.Roundtrip(); err != nil {
61		t.Fatal(err)
62	}
63	select {
64	case serial := <-serials:
65		requestProtocol(t, c, xdg, xdgshell.SurfaceRequestAckConfigure, serial)
66	default:
67		t.Fatal("missing configure")
68	}
69	requestProtocol(t, c, surf, wayland.SurfaceRequestAttach, buffer, int32(0), int32(0))
70	requestProtocol(t, c, surf, wayland.SurfaceRequestCommit)
71	if err := c.Roundtrip(); err != nil {
72		t.Fatal(err)
73	}
74	d := mapped(t, events, 2*time.Second)
75	if !d.Modal || d.Parent != parent.ID || !d.Floating {
76		t.Fatalf("dialog %+v, want modal over %d", d, parent.ID)
77	}
78
79	modal := func(want bool) {
80		t.Helper()
81		if err := c.Roundtrip(); err != nil {
82			t.Fatal(err)
83		}
84		for deadline := time.After(2 * time.Second); ; {
85			select {
86			case ev := <-events:
87				if m, ok := ev.(ports.WindowModal); ok {
88					if m.ID != d.ID || m.Modal != want {
89						t.Fatalf("modal change %+v, want %v", m, want)
90					}
91					return
92				}
93			case <-deadline:
94				t.Fatal("no modal change")
95			}
96		}
97	}
98	requestProtocol(t, c, dlg, xdgdialog.DialogV1RequestUnsetModal)
99	modal(false)
100	requestProtocol(t, c, dlg, xdgdialog.DialogV1RequestSetModal)
101	modal(true)
102	// Destroying the object ends the modal state.
103	requestProtocol(t, c, dlg, xdgdialog.DialogV1RequestDestroy)
104	modal(false)
105
106	// A toplevel gets one dialog object at a time.
107	first, second := c.AllocateID(), c.AllocateID()
108	registerProtocol(t, c, first)
109	registerProtocol(t, c, second)
110	requestProtocol(t, c, dialogs, xdgdialog.WmDialogV1RequestGetXdgDialog, first, top)
111	requestProtocol(t, c, dialogs, xdgdialog.WmDialogV1RequestGetXdgDialog, second, top)
112	expectProtocolError(t, c, dialogs, uint32(xdgdialog.WmDialogV1ErrorAlreadyUsed))
113}

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