refactor/kvconf 3462c76

dialog.go RawHistoryFolder

1package wayland
2
3import (
4	"github.com/bnema/go-wayland-bindings/server/xdgdialog"
5	"github.com/bnema/go-wayland-bindings/server/xdgshell"
6	"github.com/bnema/neferwl/internal/ports"
7	"github.com/bnema/purego-libwayland/server"
8)
9
10// xdg-dialog: a client marks a toplevel as modal for its parent (a "Save
11// as…" dialog). The parent itself still comes from xdg_toplevel.set_parent
12// or xdg-foreign; core sends the focus the parent gets to its modal dialog.
13
14func registerDialog(d *server.Display, s *Server) error {
15	return xdgdialog.NewWmDialogV1Global(d, 1, func(c server.Client, v, id uint32) {
16		_, _ = xdgdialog.NewWmDialogV1(c, int32(v), id, wmDialog{s})
17	})
18}
19
20type wmDialog struct{ s *Server }
21
22func (wmDialog) Destroy(*xdgdialog.WmDialogV1) {}
23
24// GetXdgDialog makes the dialog object of a toplevel; a toplevel has at
25// most one.
26func (m wmDialog) GetXdgDialog(r *xdgdialog.WmDialogV1, id uint32, t *xdgshell.Toplevel) {
27	w := m.s.toplevelWindow(t)
28	if w != nil && w.dialog {
29		r.PostError(uint32(xdgdialog.WmDialogV1ErrorAlreadyUsed), "toplevel already has a dialog object")
30		return
31	}
32	res, err := xdgdialog.NewDialogV1(r.Client(), r.Version(), id, dialog{w})
33	if err != nil || w == nil {
34		return
35	}
36	w.dialog = true
37	// Destroying the object ends the modal state. Once the toplevel is
38	// gone the object is inert: its window stays unmapped, nothing is sent.
39	res.OnDestroy = func() {
40		w.dialog = false
41		w.setModal(false)
42	}
43}
44
45type dialog struct{ w *window }
46
47func (dialog) Destroy(*xdgdialog.DialogV1) {}
48func (d dialog) SetModal(*xdgdialog.DialogV1) {
49	if d.w != nil {
50		d.w.setModal(true)
51	}
52}
53func (d dialog) UnsetModal(*xdgdialog.DialogV1) {
54	if d.w != nil {
55		d.w.setModal(false)
56	}
57}
58
59// toplevelWindow is the window of toplevel t, nil when unknown.
60func (s *Server) toplevelWindow(t *xdgshell.Toplevel) *window {
61	if t == nil {
62		return nil
63	}
64	for _, w := range s.windows {
65		if w.toplevel != nil && w.toplevel.Resource == t.Resource {
66			return w
67		}
68	}
69	return nil
70}
71
72// setModal changes the modal state; core follows it once mapped (the map
73// carries the state of the first frame).
74func (w *window) setModal(modal bool) {
75	if w.modal == modal {
76		return
77	}
78	w.modal = modal
79	if w.mapped {
80		w.xdg.server.emit(ports.WindowModal{ID: w.id, Modal: modal})
81	}
82}

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