From 04894e6618a24af62b921cf81ee34673f32fd545 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 4 Oct 2026 12:46:44 +0200 Subject: [PATCH 01/15] picom: the compositor as a module, claiming node-compositor (hq ADR 0208) Owns its configuration, moved to picom's window rules; started once from the session's xinitrc slot; Go tools restart, rules, window-opacity and toggle, which find the operator's X session from the window manager's environment. --- modules/picom/README.md | 62 +++ modules/picom/cmd/picom-tools/args.go | 97 ++++ modules/picom/cmd/picom-tools/main.go | 89 ++++ .../cmd/picom-tools/manifest_helpers_test.go | 175 ++++++++ .../picom/cmd/picom-tools/manifest_test.go | 61 +++ modules/picom/cmd/picom-tools/picom.go | 293 ++++++++++++ modules/picom/cmd/picom-tools/picom_test.go | 131 ++++++ modules/picom/cmd/picom-tools/session.go | 423 ++++++++++++++++++ modules/picom/cmd/picom-tools/session_test.go | 174 +++++++ modules/picom/files/picom.conf | 32 ++ modules/picom/go.mod | 5 + modules/picom/go.sum | 2 + modules/picom/module.json | 64 +++ 13 files changed, 1608 insertions(+) create mode 100644 modules/picom/README.md create mode 100644 modules/picom/cmd/picom-tools/args.go create mode 100644 modules/picom/cmd/picom-tools/main.go create mode 100644 modules/picom/cmd/picom-tools/manifest_helpers_test.go create mode 100644 modules/picom/cmd/picom-tools/manifest_test.go create mode 100644 modules/picom/cmd/picom-tools/picom.go create mode 100644 modules/picom/cmd/picom-tools/picom_test.go create mode 100644 modules/picom/cmd/picom-tools/session.go create mode 100644 modules/picom/cmd/picom-tools/session_test.go create mode 100644 modules/picom/files/picom.conf create mode 100644 modules/picom/go.mod create mode 100644 modules/picom/go.sum create mode 100644 modules/picom/module.json diff --git a/modules/picom/README.md b/modules/picom/README.md new file mode 100644 index 0000000..827215f --- /dev/null +++ b/modules/picom/README.md @@ -0,0 +1,62 @@ +# picom + +The X compositor as a module (novox/hq ADR 0208, research 026). + +- Installs `picom`, and `xorg-xprop` for setting a window's own opacity. +- Claims the mesh's `node-compositor` seat (no verbs yet, ADR 0208 §2) and requires `x11-display`. + That requirement has the machine's reach: the display server must be held on this module's own + machine, or assignment is refused, naming the seat's holders. +- Owns `~/.config/picom/` and `~/.config/picom/picom.conf`, which it writes whole at every push. +- **Adds no start of its own.** picom's package ships an XDG autostart entry + (`/etc/xdg/autostart/picom.desktop`), which the session runs: the `i3` module's `dex --autostart`. + That is the tool's own grain (ADR 0208 §4) and its one start. The desktop modules follow one rule: + a process has one starter. Its package's autostart entry is that starter where there is one, and + the `xinitrc` slot where there is none. + +## Tools + +Served by the node's runtime as the operator account (ADR 0175). The tools find the operator's X +session from the window manager's own environment, and say so plainly when nobody is logged in. + +| tool | does | +|---|---| +| `picom_restart` | a running picom re-reads its file (`SIGUSR1`); `hard`, or none running, starts a fresh one | +| `picom_rules` | the global options and the window rules in force, in picom's order, and whether it runs | +| `picom_window_opacity` | read or set one window's own opacity, the focused window by default | +| `picom_toggle` | compositing off or on, for a game or a test; the next login starts it again | + +A picom a tool starts runs under the account's own service manager (`systemd-run --user`, unit +`picom`). As a child of the runtime it would die whenever the runtime restarts. + +## What it improves on what was found + +- **Window rules** replace `opacity-rule`, `inactive-opacity` and `inactive-dim`, which picom 12 and + later supersede. The behaviour is the same: only terminals are translucent (95 % focused, 75 % + unfocused). The browser and video "pin to 100 %" rule went, because nothing else is made + translucent any more. +- **Full-screen windows are opaque,** a terminal included. +- **One start.** Today both the window manager's configuration and the autostart entry start picom, + and the second one exits. +- On the desktop, picom was not running at all on the day it was measured, although both starts were + in place. It probably fails to start on that machine's GPU. `picom_restart` with `hard` after + assignment answers with what happened. The next step is the `picom` user unit's journal. + +## What it leaves as found + +The window manager's own `exec --no-startup-id picom` line belongs to the `i3` module's configuration, +which no longer carries it. Nothing else of picom's lies outside the directory this module owns. + +## Migration (ADR 0182) + +- The first push keeps the found `picom.conf` once, then writes the module's. +- Until the `i3` module replaces the hand-kept `~/.config/i3/config`, its `exec picom` line starts a + second picom. The second one exits at once, because a compositor is already running. Nothing to + do, unless the line is still there after `i3` is assigned. + +## Blockers + +- The seat `node-compositor` and the provision `x11-display` are ADR 0208's. + Until the controller knows them, `mctl` reads the claim and the requirement as unknown, and refuses + the module. +- `xorg-xprop` is declared here because the `xorg` module does not install it. If `xorg` comes to + declare it, it leaves this module, since a package is declared once per node. diff --git a/modules/picom/cmd/picom-tools/args.go b/modules/picom/cmd/picom-tools/args.go new file mode 100644 index 0000000..9b5dfcf --- /dev/null +++ b/modules/picom/cmd/picom-tools/args.go @@ -0,0 +1,97 @@ +// Reading a tool's arguments: JSON numbers arrive as float64, and a missing argument is its default. +// The same in every desktop module that carries it. +package main + +import ( + "fmt" + "math" + "strings" + "time" +) + +// text is a string argument, trimmed; required says an empty one is refused. +func text(args map[string]any, key string, required bool) (string, error) { + v, present := args[key] + if !present || v == nil { + if required { + return "", fmt.Errorf("%s is required", key) + } + return "", nil + } + s, ok := v.(string) + if !ok { + return "", fmt.Errorf("%s is a string, not %T", key, v) + } + s = strings.TrimSpace(s) + if s == "" && required { + return "", fmt.Errorf("%s is required", key) + } + return s, nil +} + +// whole is a whole-number argument within [least, most], or def when absent. +func whole(args map[string]any, key string, def, least, most int) (int, error) { + v, present := args[key] + if !present || v == nil { + return def, nil + } + f, ok := v.(float64) + if !ok { + if i, isInt := v.(int); isInt { + f = float64(i) + } else { + return 0, fmt.Errorf("%s is a number, not %T", key, v) + } + } + if f != math.Trunc(f) { + return 0, fmt.Errorf("%s is a whole number, not %v", key, f) + } + n := int(f) + if n < least || n > most { + return 0, fmt.Errorf("%s is %d; it is between %d and %d", key, n, least, most) + } + return n, nil +} + +// flag is a boolean argument, or def when absent. +func flag(args map[string]any, key string, def bool) (bool, error) { + v, present := args[key] + if !present || v == nil { + return def, nil + } + b, ok := v.(bool) + if !ok { + return false, fmt.Errorf("%s is true or false, not %T", key, v) + } + return b, nil +} + +// texts is a list-of-strings argument. +func texts(args map[string]any, key string) ([]string, error) { + v, present := args[key] + if !present || v == nil { + return nil, nil + } + list, ok := v.([]any) + if !ok { + if ss, isStrings := v.([]string); isStrings { + return ss, nil + } + return nil, fmt.Errorf("%s is a list of strings, not %T", key, v) + } + out := make([]string, 0, len(list)) + for i, item := range list { + s, ok := item.(string) + if !ok { + return nil, fmt.Errorf("%s[%d] is a string, not %T", key, i, item) + } + out = append(out, s) + } + return out, nil +} + +// seconds is a timeout argument in seconds, defaulted and bounded below the runtime's call limit. +func seconds(args map[string]any, key string, def, most int) (time.Duration, error) { + n, err := whole(args, key, def, 1, most) + return time.Duration(n) * time.Second, err +} diff --git a/modules/picom/cmd/picom-tools/main.go b/modules/picom/cmd/picom-tools/main.go new file mode 100644 index 0000000..379cd56 --- /dev/null +++ b/modules/picom/cmd/picom-tools/main.go @@ -0,0 +1,89 @@ +// picom's Go tools bundle (novox/hq ADR 0188, ADR 0193, ADR 0208): the compositor's own tools, served +// by the node's runtime as the operator account. node-compositor has no verbs yet (ADR 0208 §2), so +// every tool here is the module's own. +package main + +import ( + "fmt" + "os" + + stdio "git.novox.be/novox/mesh-sdk/go" +) + +func main() { + if err := stdio.Serve("", tools()); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func tools() []stdio.Tool { + return []stdio.Tool{ + { + Name: "picom_restart", + Description: "Make the compositor re-read its configuration: a running picom is told to reinitialise " + + "(SIGUSR1); with hard, or when none runs, a fresh one is started in the operator's session under " + + "their service manager. Answers what was done and the pids.", + Input: map[string]any{ + "hard": map[string]any{"type": "boolean", "description": "end the running picom and start a new one (default false)"}, + }, + Run: func(args map[string]any) (any, error) { + hard, err := flag(args, "hard", false) + if err != nil { + return nil, err + } + return Restart(hard) + }, + }, + { + Name: "picom_rules", + Description: "The compositor's configuration in force: its global options and each window rule " + + "(match, opacity, shadow, fade…) in the order picom applies them, from the file the mesh placed, " + + "and whether picom is running.", + Run: func(map[string]any) (any, error) { return Rules(configPath()) }, + }, + { + Name: "picom_window_opacity", + Description: "Read or set one window's own opacity (_NET_WM_WINDOW_OPACITY), the focused window " + + "unless one is named. A window rule that sets opacity (terminals) outranks it. Lasts as long as " + + "the window; the declared rules are untouched.", + Input: map[string]any{ + "window": map[string]any{"type": "string", "description": "X window id, 0x… or decimal (default: the focused window)"}, + "opacity": map[string]any{"type": "integer", "description": "0-100 to set; 100 removes the window's own value; omit to read"}, + }, + Run: func(args map[string]any) (any, error) { + window, err := text(args, "window", false) + if err != nil { + return nil, err + } + if _, set := args["opacity"]; !set { + return WindowOpacity(window, -1) + } + opacity, err := whole(args, "opacity", 100, 0, 100) + if err != nil { + return nil, err + } + return WindowOpacity(window, opacity) + }, + }, + { + Name: "picom_toggle", + Description: "Turn compositing off or on in the operator's session, for a game or a test: off ends " + + "picom, on starts it. Without `on`, flips it. The session start brings it back at the next login.", + Input: map[string]any{ + "on": map[string]any{"type": "boolean", "description": "true to start, false to stop (default: the opposite of now)"}, + }, + Run: func(args map[string]any) (any, error) { + var want *bool + if _, given := args["on"]; given { + on, err := flag(args, "on", false) + if err != nil { + return nil, err + } + want = &on + } + return Toggle(want) + }, + }, + } +} diff --git a/modules/picom/cmd/picom-tools/manifest_helpers_test.go b/modules/picom/cmd/picom-tools/manifest_helpers_test.go new file mode 100644 index 0000000..d4fb76d --- /dev/null +++ b/modules/picom/cmd/picom-tools/manifest_helpers_test.go @@ -0,0 +1,175 @@ +package main + +import ( + "encoding/json" + "os" + "path/filepath" + "strings" + "testing" +) + +// The module's manifest, read the way the catalogue reads it, for the manifest tests. The same in +// every desktop module that carries it. + +type manifest struct { + Module string `json:"module"` + Version string `json:"version"` + Capabilities []string `json:"capabilities"` + Requires []string `json:"requires"` + Claims []claim `json:"claims"` + Seats []any `json:"seats"` + Tools []string `json:"tools"` + Environment *environment `json:"environment"` + Shell []shellCode `json:"shell"` + Resources []map[string]any `json:"resources"` + Build struct { + Artifacts []map[string]any `json:"artifacts"` + } `json:"build"` +} + +type claim struct { + Name string `json:"name"` + Scope string `json:"scope"` + Serves []string `json:"serves"` +} + +type environment struct { + Variables map[string]string `json:"variables"` + Path []map[string]any `json:"path"` +} + +type shellCode struct { + For string `json:"for"` + Slot string `json:"slot"` + Code string `json:"code"` +} + +func readManifest(t *testing.T) manifest { + t.Helper() + raw, err := os.ReadFile(filepath.Join("..", "..", "module.json")) + if err != nil { + t.Fatal(err) + } + dec := json.NewDecoder(strings.NewReader(string(raw))) + dec.DisallowUnknownFields() + var m manifest + if err := dec.Decode(&m); err != nil { + t.Fatalf("module.json: %v", err) + } + return m +} + +func (m manifest) resource(t *testing.T, id string) map[string]any { + t.Helper() + for _, r := range m.Resources { + if r["id"] == id { + return r + } + } + t.Fatalf("no resource %q", id) + return nil +} + +func (m manifest) packages() (present, absent []string) { + for _, r := range m.Resources { + if r["type"] == "package" { + if r["absent"] == true { + absent = append(absent, r["package"].(string)) + } else { + present = append(present, r["package"].(string)) + } + } + } + return present, absent +} + +// sameAsSource checks that a file resource's content is byte for byte the module's source file, so +// the readable file in the repository is what the machine gets. +func (m manifest) sameAsSource(t *testing.T, id, source string) { + t.Helper() + want, err := os.ReadFile(filepath.Join("..", "..", source)) + if err != nil { + t.Fatal(err) + } + r := m.resource(t, id) + if r["type"] != "file" { + t.Fatalf("%s is a %v, not a file", id, r["type"]) + } + if got, _ := r["content"].(string); got != string(want) { + t.Fatalf("resource %s's content is not %s: edit the source and copy it into module.json", id, source) + } + if r["owner"] != "${machine:account}" && !strings.HasPrefix(r["path"].(string), "/etc/") { + t.Fatalf("%s under the home is the account's", id) + } +} + +// checkTheToolsAgree checks that the manifest lists the module's own tools exactly, that the bundle +// serves each seat verb the claims promise as ., and that the Go bundle is declared. +func checkTheToolsAgree(t *testing.T, m manifest) { + t.Helper() + own, seat := map[string]bool{}, map[string]bool{} + for _, tool := range tools() { + if strings.Contains(tool.Name, ".") { + seat[tool.Name] = true + } else { + own[tool.Name] = true + } + if strings.TrimSpace(tool.Description) == "" { + t.Errorf("%s has no description", tool.Name) + } + } + listed := map[string]bool{} + for _, name := range m.Tools { + listed[name] = true + if !own[name] { + t.Errorf("module.json lists %s, which the bundle does not serve", name) + } + } + for name := range own { + if !listed[name] { + t.Errorf("the bundle serves %s, which module.json does not list", name) + } + if !strings.HasPrefix(name, strings.ReplaceAll(m.Module, "-", "_")+"_") { + t.Errorf("%s is not prefixed with the module's name", name) + } + } + promised := map[string]bool{} + for _, c := range m.Claims { + for _, verb := range c.Serves { + promised[c.Name+"."+verb] = true + if !seat[c.Name+"."+verb] { + t.Errorf("the claim on %s promises %s, which the bundle does not serve", c.Name, verb) + } + } + } + for name := range seat { + if !promised[name] { + t.Errorf("the bundle serves %s, which no claim promises", name) + } + } + var bundle map[string]any + for _, a := range m.Build.Artifacts { + if a["kind"] == "bundle" { + bundle = a + } + } + if bundle == nil || bundle["language"] != "go" || bundle["system"] != "arch" || + bundle["from"] != "cmd/"+m.Module+"-tools" || bundle["binary"] != m.Module+"-tools" { + t.Errorf("the Go tools bundle: %v", bundle) + } +} + +// checkNoSecretsOrInstallationNames refuses what a catalogue manifest must never carry. +func checkNoSecretsOrInstallationNames(t *testing.T) { + t.Helper() + raw, err := os.ReadFile(filepath.Join("..", "..", "module.json")) + if err != nil { + t.Fatal(err) + } + s := strings.ToLower(string(raw)) + for _, never := range []string{"/home/", "jochen", "g14", "shanks", "novox.be", "api_key", ".hal/", "greenclip daemon"} { + if strings.Contains(s, never) { + t.Errorf("module.json names %q", never) + } + } +} diff --git a/modules/picom/cmd/picom-tools/manifest_test.go b/modules/picom/cmd/picom-tools/manifest_test.go new file mode 100644 index 0000000..6f67e50 --- /dev/null +++ b/modules/picom/cmd/picom-tools/manifest_test.go @@ -0,0 +1,61 @@ +package main + +import ( + "reflect" + "strings" + "testing" +) + +// picom's shape (novox/hq ADR 0208): it claims node-compositor and serves no verb of it, requires the +// X display on its own machine, owns its configuration file, and is started once, by its package's +// XDG autostart entry, never by the window manager or the session's start as well. + +func TestItClaimsTheCompositorSeatAndRequiresTheXDisplay(t *testing.T) { + m := readManifest(t) + if m.Module != "picom" || m.Seats != nil { + t.Fatalf("module %q declares seats %v", m.Module, m.Seats) + } + if !reflect.DeepEqual(m.Claims, []claim{{Name: "node-compositor", Scope: "node"}}) { + t.Fatalf("claims: %+v", m.Claims) + } + if !reflect.DeepEqual(m.Requires, []string{"x11-display"}) { + t.Fatalf("requires: %v", m.Requires) + } + if present, absent := m.packages(); !reflect.DeepEqual(present, []string{"picom", "xorg-xprop"}) || absent != nil { + t.Fatalf("packages: %v, absent %v", present, absent) + } +} + +func TestItOwnsItsConfigurationAsWrittenInTheModule(t *testing.T) { + m := readManifest(t) + m.sameAsSource(t, "configuration", "files/picom.conf") + if p := m.resource(t, "configuration")["path"]; p != "${machine:account-home}/.config/picom/picom.conf" { + t.Fatalf("path: %v", p) + } + if d := m.resource(t, "configuration-dir"); d["type"] != "directory" || d["path"] != "${machine:account-home}/.config/picom" { + t.Fatalf("the directory: %v", d) + } +} + +func TestThePackagesAutostartEntryIsItsOnlyStart(t *testing.T) { + m := readManifest(t) + // picom's package ships /etc/xdg/autostart/picom.desktop, which the session's dex runs. A second + // start from here would be a second compositor, refused by the first. + if m.Shell != nil { + t.Fatalf("a session-start line as well as the package's autostart entry: %+v", m.Shell) + } + for _, r := range m.Resources { + if p, _ := r["path"].(string); strings.Contains(p, "i3/config.d") || strings.Contains(p, "autostart") { + t.Fatalf("a second start: %v", r) + } + if r["type"] == "service" || r["type"] == "process" { + t.Fatalf("a unit: %v", r) + } + } +} + +func TestTheToolsAgreeWithTheManifest(t *testing.T) { + m := readManifest(t) + checkTheToolsAgree(t, m) + checkNoSecretsOrInstallationNames(t) +} diff --git a/modules/picom/cmd/picom-tools/picom.go b/modules/picom/cmd/picom-tools/picom.go new file mode 100644 index 0000000..c719df2 --- /dev/null +++ b/modules/picom/cmd/picom-tools/picom.go @@ -0,0 +1,293 @@ +package main + +import ( + "errors" + "fmt" + "math" + "os" + "path/filepath" + "regexp" + "strconv" + "strings" + "syscall" + "time" +) + +// unit is the name picom runs under in the account's service manager when a tool starts it. The +// session start runs its own, and a tool that starts one first ends any other (Toggle, Restart). +const unit = "picom" + +func configPath() string { return filepath.Join(operatorHome(), ".config", "picom", "picom.conf") } + +// Running is picom's processes of this account. +func running() []int { return processesOf("picom") } + +// RestartResult is what picom_restart answers. +type RestartResult struct { + Action string `json:"action"` + PIDs []int `json:"pids"` + Note string `json:"note,omitempty"` +} + +// Restart tells a running picom to reinitialise, or starts one. +func Restart(hard bool) (RestartResult, error) { + if pids := running(); len(pids) > 0 && !hard { + return RestartResult{Action: "reinitialised", PIDs: signalAll("picom", syscall.SIGUSR1), + Note: "picom re-read " + configPath()}, nil + } + s, err := findSession() + if err != nil { + return RestartResult{}, err + } + if err := stopAll(); err != nil { + return RestartResult{}, err + } + if err := s.detach(unit, "picom", "--config", configPath()); err != nil { + return RestartResult{}, err + } + pids := waitFor(func() []int { return running() }, 3*time.Second) + return RestartResult{Action: "started", PIDs: pids, + Note: "started under the account's service manager as " + unit + ".service"}, nil +} + +// stopAll ends every picom of this account and waits for them to go. +func stopAll() error { + signalAll("picom", syscall.SIGTERM) + deadline := time.Now().Add(3 * time.Second) + for time.Now().Before(deadline) { + if len(running()) == 0 { + return nil + } + time.Sleep(100 * time.Millisecond) + } + if left := running(); len(left) > 0 { + return fmt.Errorf("picom %v did not end within 3s", left) + } + return nil +} + +func waitFor(get func() []int, within time.Duration) []int { + deadline := time.Now().Add(within) + for { + if got := get(); len(got) > 0 || time.Now().After(deadline) { + return got + } + time.Sleep(100 * time.Millisecond) + } +} + +// ToggleResult is what picom_toggle answers. +type ToggleResult struct { + Compositing bool `json:"compositing"` + PIDs []int `json:"pids"` + Note string `json:"note"` +} + +// Toggle stops or starts compositing; want nil flips it. +func Toggle(want *bool) (ToggleResult, error) { + on := len(running()) == 0 + if want != nil { + on = *want + } + if !on { + if err := stopAll(); err != nil { + return ToggleResult{}, err + } + return ToggleResult{Compositing: false, PIDs: []int{}, + Note: "picom ended; the session start runs it again at the next login, or call picom_toggle with on"}, nil + } + if pids := running(); len(pids) > 0 { + return ToggleResult{Compositing: true, PIDs: pids, Note: "picom was already running"}, nil + } + r, err := Restart(true) + if err != nil { + return ToggleResult{}, err + } + return ToggleResult{Compositing: len(r.PIDs) > 0, PIDs: r.PIDs, Note: r.Note}, nil +} + +// Rule is one window rule, its options as written. +type Rule struct { + Match string `json:"match"` + Options map[string]string `json:"options"` +} + +// RulesResult is what picom_rules answers. +type RulesResult struct { + File string `json:"file"` + Running []int `json:"running"` + Global map[string]string `json:"global"` + Rules []Rule `json:"rules"` + // Legacy names options that window rules supersede, which picom ignores when rules are set. + Legacy []string `json:"legacy,omitempty"` +} + +var ( + commentLine = regexp.MustCompile(`(?m)^\s*#.*$`) + rulesBlock = regexp.MustCompile(`(?s)\brules\s*[=:]\s*\((.*?)\)\s*;`) + ruleGroup = regexp.MustCompile(`(?s)\{(.*?)\}`) + assignment = regexp.MustCompile(`(?m)^\s*([A-Za-z][A-Za-z0-9-]*)\s*[=:]\s*(.+?)\s*;?\s*$`) +) + +// superseded are the options picom's window rules replace (picom(1), WINDOW RULES). +var superseded = []string{"opacity-rule", "inactive-opacity", "active-opacity", "inactive-dim", + "shadow-exclude", "fade-exclude", "focus-exclude", "rounded-corners-exclude", "blur-background-exclude", + "corner-radius-rules", "wintypes", "inactive-opacity-override", "mark-wmwin-focused"} + +// Rules reads picom's configuration file into its global options and its window rules. +func Rules(path string) (RulesResult, error) { + raw, err := os.ReadFile(path) + if err != nil { + return RulesResult{}, fmt.Errorf("picom's configuration: %w", err) + } + return parseRules(path, string(raw), running()), nil +} + +func parseRules(path, conf string, pids []int) RulesResult { + out := RulesResult{File: path, Running: pids, Global: map[string]string{}, Rules: []Rule{}} + conf = commentLine.ReplaceAllString(conf, "") + rest := conf + if m := rulesBlock.FindStringSubmatchIndex(conf); m != nil { + body := conf[m[2]:m[3]] + rest = conf[:m[0]] + conf[m[1]:] + for _, g := range ruleGroup.FindAllStringSubmatch(body, -1) { + r := Rule{Options: map[string]string{}} + for _, part := range strings.Split(g[1], ";") { + k, v, ok := strings.Cut(part, "=") + if !ok { + continue + } + k, v = strings.TrimSpace(k), strings.TrimSpace(v) + if k == "match" { + r.Match = unquote(v) + } else { + r.Options[k] = unquote(v) + } + } + out.Rules = append(out.Rules, r) + } + } + for _, m := range assignment.FindAllStringSubmatch(rest, -1) { + out.Global[m[1]] = unquote(strings.TrimSuffix(m[2], ";")) + } + if len(out.Rules) > 0 { + for _, name := range superseded { + if _, set := out.Global[name]; set { + out.Legacy = append(out.Legacy, name) + } + } + } + return out +} + +func unquote(v string) string { + v = strings.TrimSpace(v) + if len(v) >= 2 && v[0] == '"' && v[len(v)-1] == '"' { + return v[1 : len(v)-1] + } + return v +} + +// OpacityResult is what picom_window_opacity answers. +type OpacityResult struct { + Window string `json:"window"` + Class string `json:"class,omitempty"` + Title string `json:"title,omitempty"` + // Opacity is the window's own value in percent; nil when it has none. + Opacity *int `json:"opacity"` + Note string `json:"note,omitempty"` +} + +var ( + activeWindow = regexp.MustCompile(`window id # (0x[0-9a-fA-F]+)`) + cardinal = regexp.MustCompile(`_NET_WM_WINDOW_OPACITY\(CARDINAL\) = (\d+)`) + wmClass = regexp.MustCompile(`WM_CLASS\(STRING\) = "[^"]*", "([^"]*)"`) + wmName = regexp.MustCompile(`_NET_WM_NAME\(UTF8_STRING\) = "(.*)"`) +) + +// WindowOpacity reads a window's own opacity, and sets it when percent is 0-100. +func WindowOpacity(window string, percent int) (OpacityResult, error) { + s, err := findSession() + if err != nil { + return OpacityResult{}, err + } + if window == "" { + r, err := s.run(5*time.Second, "", "xprop", "-root", "_NET_ACTIVE_WINDOW") + if err != nil { + return OpacityResult{}, err + } + m := activeWindow.FindStringSubmatch(r.Stdout) + if m == nil || m[1] == "0x0" { + return OpacityResult{}, errors.New("no window is focused") + } + window = m[1] + } + id, err := windowID(window) + if err != nil { + return OpacityResult{}, err + } + if percent >= 0 { + var r Result + if percent == 100 { + r, err = s.run(5*time.Second, "", "xprop", "-id", id, "-remove", "_NET_WM_WINDOW_OPACITY") + } else { + r, err = s.run(5*time.Second, "", "xprop", "-id", id, "-f", "_NET_WM_WINDOW_OPACITY", "32c", + "-set", "_NET_WM_WINDOW_OPACITY", strconv.FormatUint(opacityCardinal(percent), 10)) + } + if err != nil { + return OpacityResult{}, err + } + if r.Code != 0 { + return OpacityResult{}, fmt.Errorf("xprop: %s", strings.TrimSpace(r.Stderr)) + } + } + r, err := s.run(5*time.Second, "", "xprop", "-id", id, "_NET_WM_WINDOW_OPACITY", "WM_CLASS", "_NET_WM_NAME") + if err != nil { + return OpacityResult{}, err + } + if r.Code != 0 { + return OpacityResult{}, fmt.Errorf("window %s: %s", id, strings.TrimSpace(r.Stderr)) + } + out := parseWindow(id, r.Stdout) + if rules, err := Rules(configPath()); err == nil && out.Class != "" { + for _, rule := range rules.Rules { + if _, sets := rule.Options["opacity"]; sets && strings.Contains(rule.Match, "class_g = '"+out.Class+"'") { + out.Note = "a window rule sets the opacity of class " + out.Class + " and outranks the window's own value" + } + } + } + return out, nil +} + +func windowID(w string) (string, error) { + w = strings.TrimSpace(strings.ToLower(w)) + base := 10 + if strings.HasPrefix(w, "0x") { + w, base = w[2:], 16 + } + n, err := strconv.ParseUint(w, base, 32) + if err != nil || n == 0 { + return "", fmt.Errorf("window %q is not an X window id", w) + } + return fmt.Sprintf("0x%x", n), nil +} + +func opacityCardinal(percent int) uint64 { + return uint64(math.Round(float64(percent) / 100 * float64(math.MaxUint32))) +} + +func parseWindow(id, out string) OpacityResult { + r := OpacityResult{Window: id} + if m := cardinal.FindStringSubmatch(out); m != nil { + n, _ := strconv.ParseUint(m[1], 10, 64) + p := int(math.Round(float64(n) / float64(math.MaxUint32) * 100)) + r.Opacity = &p + } + if m := wmClass.FindStringSubmatch(out); m != nil { + r.Class = m[1] + } + if m := wmName.FindStringSubmatch(out); m != nil { + r.Title = m[1] + } + return r +} diff --git a/modules/picom/cmd/picom-tools/picom_test.go b/modules/picom/cmd/picom-tools/picom_test.go new file mode 100644 index 0000000..102ad3e --- /dev/null +++ b/modules/picom/cmd/picom-tools/picom_test.go @@ -0,0 +1,131 @@ +package main + +import ( + "errors" + "os" + "path/filepath" + "strings" + "testing" +) + +// A pid above the kernel's largest, so a signal a test sends reaches nothing. +const nobody = 4194400 + +func TestTheModulesOwnConfigurationReadsAsRulesInOrder(t *testing.T) { + raw, err := os.ReadFile(filepath.Join("..", "..", "files", "picom.conf")) + if err != nil { + t.Fatal(err) + } + r := parseRules("picom.conf", string(raw), nil) + if r.Global["backend"] != "glx" || r.Global["vsync"] != "true" || r.Global["shadow"] != "false" { + t.Fatalf("global options: %v", r.Global) + } + if len(r.Rules) != 5 { + t.Fatalf("five rules: %+v", r.Rules) + } + focused, unfocused := r.Rules[2], r.Rules[3] + if focused.Match != "class_g = 'XTerm' && focused" || focused.Options["opacity"] != "0.95" || + unfocused.Match != "class_g = 'XTerm' && !focused" || unfocused.Options["opacity"] != "0.75" { + t.Fatalf("the terminal rules: %+v %+v", focused, unfocused) + } + if last := r.Rules[4]; last.Match != "fullscreen" || last.Options["opacity"] != "1" { + t.Fatalf("full screen is opaque, and last so it wins: %+v", last) + } + if len(r.Legacy) != 0 { + t.Fatalf("the module's file sets no option the rules supersede: %v", r.Legacy) + } + if _, inGlobal := r.Global["match"]; inGlobal { + t.Fatal("a rule's key leaked into the global options") + } +} + +func TestTodaysFileIsReportedForTheOptionsItsRulesWouldIgnore(t *testing.T) { + conf := "inactive-opacity = 1.0;\nopacity-rule = [ \"95:class_g = 'XTerm'\" ];\nrules = (\n { match = \"focused\"; opacity = 1; }\n);\n" + r := parseRules("x", conf, []int{7}) + if len(r.Rules) != 1 || r.Rules[0].Match != "focused" || len(r.Running) != 1 { + t.Fatalf("%+v", r) + } + if strings.Join(r.Legacy, ",") != "opacity-rule,inactive-opacity" { + t.Fatalf("legacy: %v", r.Legacy) + } +} + +func TestAWindowIdIsHexOrDecimalAndNeverZero(t *testing.T) { + for in, want := range map[string]string{"0x3C00012": "0x3c00012", "62914578": "0x3c00012"} { + if got, err := windowID(in); err != nil || got != want { + t.Errorf("%s: %s, %v", in, got, err) + } + } + for _, bad := range []string{"0", "0x0", "window", "-1", "0x1ffffffff"} { + if _, err := windowID(bad); err == nil { + t.Errorf("%s was accepted", bad) + } + } +} + +func TestOpacityIsAPercentOfTheFullCardinal(t *testing.T) { + if opacityCardinal(0) != 0 || opacityCardinal(100) != 0xffffffff || opacityCardinal(75) != 3221225471 { + t.Fatalf("%d %d %d", opacityCardinal(0), opacityCardinal(100), opacityCardinal(75)) + } + r := parseWindow("0x1", "_NET_WM_WINDOW_OPACITY(CARDINAL) = 3221225471\nWM_CLASS(STRING) = \"xterm\", \"XTerm\"\n_NET_WM_NAME(UTF8_STRING) = \"op@host: ~\"\n") + if r.Opacity == nil || *r.Opacity != 75 || r.Class != "XTerm" || r.Title != "op@host: ~" { + t.Fatalf("%+v", r) + } + if r := parseWindow("0x1", "_NET_WM_WINDOW_OPACITY: not found.\n"); r.Opacity != nil { + t.Fatalf("no value of its own: %+v", r) + } +} + +func TestSettingTheFocusedWindowsOpacityAsksXpropAndNamesTheRuleThatOutranksIt(t *testing.T) { + root := fakeMachine(t) + fakeProcess(t, nobody, "i3", "DISPLAY=:1") + conf := filepath.Join(root, "home", ".config", "picom") + if err := os.MkdirAll(conf, 0o755); err != nil { + t.Fatal(err) + } + src, _ := os.ReadFile(filepath.Join("..", "..", "files", "picom.conf")) + if err := os.WriteFile(filepath.Join(conf, "picom.conf"), src, 0o644); err != nil { + t.Fatal(err) + } + bin := fakeBinaries(t, map[string]string{"xprop": `echo "xprop $* DISPLAY=$DISPLAY" >> "$LOG" +case "$*" in + "-root _NET_ACTIVE_WINDOW") echo "_NET_ACTIVE_WINDOW(WINDOW): window id # 0x3c00012" ;; + *WM_CLASS*) printf '_NET_WM_WINDOW_OPACITY(CARDINAL) = 2147483648\nWM_CLASS(STRING) = "xterm", "XTerm"\n' ;; +esac`}) + t.Setenv("LOG", filepath.Join(bin, "log")) + r, err := WindowOpacity("", 50) + if err != nil { + t.Fatal(err) + } + if r.Window != "0x3c00012" || r.Opacity == nil || *r.Opacity != 50 || !strings.Contains(r.Note, "XTerm") { + t.Fatalf("%+v", r) + } + log, _ := os.ReadFile(filepath.Join(bin, "log")) + if !strings.Contains(string(log), "xprop -id 0x3c00012 -f _NET_WM_WINDOW_OPACITY 32c -set _NET_WM_WINDOW_OPACITY 2147483648 DISPLAY=:1") { + t.Fatalf("xprop was asked:\n%s", log) + } +} + +func TestWithoutASessionTheToolsThatDrawSaySo(t *testing.T) { + fakeMachine(t) + if _, err := WindowOpacity("", -1); !errors.Is(err, ErrNoSession) { + t.Fatalf("window opacity: %v", err) + } + on := true + if _, err := Toggle(&on); !errors.Is(err, ErrNoSession) { + t.Fatalf("toggle on: %v", err) + } +} + +func TestARunningPicomIsToldToReinitialiseNotRestarted(t *testing.T) { + fakeMachine(t) + fakeProcess(t, nobody, "picom", "DISPLAY=:1") + r, err := Restart(false) + if err != nil || r.Action != "reinitialised" { + t.Fatalf("%+v, %v", r, err) + } + on := true + if r, err := Toggle(&on); err != nil || !r.Compositing || r.PIDs[0] != nobody { + t.Fatalf("on while running: %+v, %v", r, err) + } +} diff --git a/modules/picom/cmd/picom-tools/session.go b/modules/picom/cmd/picom-tools/session.go new file mode 100644 index 0000000..dc21774 --- /dev/null +++ b/modules/picom/cmd/picom-tools/session.go @@ -0,0 +1,423 @@ +// The operator's graphical session, as a tool the node's runtime runs finds it (novox/hq ADR 0208). +// +// The runtime is a system service running as the operator account (ADR 0175): it has the account's +// uid and none of the session's environment — no DISPLAY, no XAUTHORITY, no session bus. A tool that +// draws on the screen or talks to the desktop's D-Bus must find them. It reads them from a process of +// the account that is part of the session (the window manager first), the same thing `loginctl` and +// a person's own shell would point at, and says where it found them. +// +// Long-lived programs a tool starts go to the account's own service manager through `systemd-run +// --user`, never as children of the tool: the runtime's unit is a cgroup the service manager empties +// whenever the runtime restarts, and a compositor or a clipboard owner started from inside it would +// die with it. +// +// This file is the same in every desktop module that carries it; it moves into the Go SDK once a +// second consumer outside the desktop wants it. +package main + +import ( + "bytes" + "errors" + "fmt" + "os" + "os/exec" + "path/filepath" + "sort" + "strconv" + "strings" + "syscall" + "time" +) + +// Where the session is looked for. Variables so a test can point them at a fake tree. +var ( + procRoot = "/proc" + runUserDir = "/run/user" + x11Sockets = "/tmp/.X11-unix" +) + +// sessionHolders are the processes whose environment is the session's, best first: the window +// manager is the session, the rest are its children. Anything else carrying DISPLAY ranks after them. +var sessionHolders = []string{"i3", "sway", "i3bar", "picom", "xss-lock", "dunst", "clipmenud", "xterm"} + +// sessionKeys are the variables a session carries that a tool hands on to what it runs. +var sessionKeys = []string{"DISPLAY", "XAUTHORITY", "WAYLAND_DISPLAY", "DBUS_SESSION_BUS_ADDRESS", + "XDG_RUNTIME_DIR", "XDG_SESSION_ID", "I3SOCK"} + +// Session is what a tool needs to reach the operator's desktop. +type Session struct { + UID int `json:"uid"` + Display string `json:"display,omitempty"` + XAuthority string `json:"xauthority,omitempty"` + Wayland string `json:"wayland_display,omitempty"` + Bus string `json:"bus,omitempty"` + RuntimeDir string `json:"runtime_dir,omitempty"` + SessionID string `json:"session_id,omitempty"` + I3Sock string `json:"i3sock,omitempty"` + // From says where the values were found: the tool's own environment, a process, or the socket. + From string `json:"from"` +} + +// ErrNoSession is answered by a tool that needs the desktop when nobody is logged in to it. +var ErrNoSession = errors.New("no graphical session") + +// ErrTimedOut is what run answers for a command ended because it ran past its time. +var ErrTimedOut = errors.New("timed out") + +// ErrNoBus is answered by a tool that needs the session bus when the account has none. +var ErrNoBus = errors.New("no session bus") + +// operatorHome is the account's home: what the runtime was told, else the process's own. +func operatorHome() string { + if h := strings.TrimSpace(os.Getenv("MESH_OPERATOR_HOME")); h != "" { + return h + } + h, _ := os.UserHomeDir() + return h +} + +// findSession finds the graphical session of the account this tool runs as, or answers +// ErrNoSession with what it looked at. +func findSession() (Session, error) { + s := findEnvironment() + if s.Display == "" && s.Wayland == "" { + return s, fmt.Errorf("%w for uid %d on this machine: no process of the account carries DISPLAY "+ + "or WAYLAND_DISPLAY, and no X server socket in %s has an authority file to go with it. "+ + "Is anyone logged in to the desktop?", ErrNoSession, s.UID, x11Sockets) + } + return s, nil +} + +// findBus finds the account's session bus, which a logged-in account has whether or not a desktop +// is running. +func findBus() (Session, error) { + s := findEnvironment() + if s.Bus == "" { + return s, fmt.Errorf("%w for uid %d: DBUS_SESSION_BUS_ADDRESS is not set and %s does not exist "+ + "(the account is not logged in)", ErrNoBus, s.UID, filepath.Join(runUserDir, strconv.Itoa(s.UID), "bus")) + } + return s, nil +} + +func findEnvironment() Session { + uid := os.Getuid() + s := Session{UID: uid} + own := map[string]string{} + for _, k := range sessionKeys { + own[k] = os.Getenv(k) + } + if own["DISPLAY"] != "" || own["WAYLAND_DISPLAY"] != "" { + s.fill(own) + s.From = "the tool's own environment" + } else if pid, comm, env, ok := sessionProcess(uid); ok { + s.fill(env) + s.From = fmt.Sprintf("process %s (pid %d)", comm, pid) + } else if display, ok := lonelyX11Socket(); ok { + if a := filepath.Join(operatorHome(), ".Xauthority"); exists(a) { + s.Display, s.XAuthority = display, a + s.From = "the X server socket and the account's ~/.Xauthority" + } + s.fill(own) + } else { + s.fill(own) + s.From = "nothing: no session found" + } + // The bus and the runtime directory are the account's, whether or not the process named them. + runtime := filepath.Join(runUserDir, strconv.Itoa(uid)) + if s.RuntimeDir == "" && exists(runtime) { + s.RuntimeDir = runtime + } + if s.Bus == "" && s.RuntimeDir != "" && exists(filepath.Join(s.RuntimeDir, "bus")) { + s.Bus = "unix:path=" + filepath.Join(s.RuntimeDir, "bus") + } + return s +} + +func (s *Session) fill(env map[string]string) { + set := func(dst *string, key string) { + if *dst == "" { + *dst = env[key] + } + } + set(&s.Display, "DISPLAY") + set(&s.XAuthority, "XAUTHORITY") + set(&s.Wayland, "WAYLAND_DISPLAY") + set(&s.Bus, "DBUS_SESSION_BUS_ADDRESS") + set(&s.RuntimeDir, "XDG_RUNTIME_DIR") + set(&s.SessionID, "XDG_SESSION_ID") + set(&s.I3Sock, "I3SOCK") +} + +// sessionProcess is the best process of this uid whose environment names a display. +func sessionProcess(uid int) (int, string, map[string]string, bool) { + entries, err := os.ReadDir(procRoot) + if err != nil { + return 0, "", nil, false + } + type candidate struct { + pid int + comm string + env map[string]string + rank int + } + var found []candidate + for _, e := range entries { + pid, err := strconv.Atoi(e.Name()) + if err != nil { + continue + } + dir := filepath.Join(procRoot, e.Name()) + if owner, ok := ownerOf(dir); !ok || owner != uid { + continue + } + raw, err := os.ReadFile(filepath.Join(dir, "environ")) + if err != nil { + continue + } + env := parseEnviron(raw) + if env["DISPLAY"] == "" && env["WAYLAND_DISPLAY"] == "" { + continue + } + comm := readTrimmed(filepath.Join(dir, "comm")) + rank := len(sessionHolders) + for i, h := range sessionHolders { + if h == comm { + rank = i + break + } + } + found = append(found, candidate{pid, comm, env, rank}) + } + if len(found) == 0 { + return 0, "", nil, false + } + sort.Slice(found, func(i, j int) bool { + if found[i].rank != found[j].rank { + return found[i].rank < found[j].rank + } + return found[i].pid > found[j].pid // the newer of two equals + }) + best := found[0] + return best.pid, best.comm, best.env, true +} + +func parseEnviron(raw []byte) map[string]string { + env := map[string]string{} + for _, kv := range bytes.Split(raw, []byte{0}) { + if i := bytes.IndexByte(kv, '='); i > 0 { + env[string(kv[:i])] = string(kv[i+1:]) + } + } + return env +} + +func ownerOf(path string) (int, bool) { + info, err := os.Stat(path) + if err != nil { + return 0, false + } + st, ok := info.Sys().(*syscall.Stat_t) + if !ok { + return 0, false + } + return int(st.Uid), true +} + +// lonelyX11Socket is the display of the one X server socket there is, when there is exactly one. +func lonelyX11Socket() (string, bool) { + entries, err := os.ReadDir(x11Sockets) + if err != nil { + return "", false + } + var displays []string + for _, e := range entries { + if n := strings.TrimPrefix(e.Name(), "X"); n != e.Name() { + if _, err := strconv.Atoi(n); err == nil { + displays = append(displays, ":"+n) + } + } + } + if len(displays) != 1 { + return "", false + } + return displays[0], true +} + +func readTrimmed(path string) string { + b, err := os.ReadFile(path) + if err != nil { + return "" + } + return strings.TrimSpace(string(b)) +} + +func exists(path string) bool { + _, err := os.Stat(path) + return err == nil +} + +// Env is this process's environment with the session's variables in place of its own. +func (s Session) Env() []string { + drop := map[string]bool{} + for _, k := range sessionKeys { + drop[k] = true + } + var env []string + for _, kv := range os.Environ() { + if i := strings.IndexByte(kv, '='); i > 0 && drop[kv[:i]] { + continue + } + env = append(env, kv) + } + add := func(k, v string) { + if v != "" { + env = append(env, k+"="+v) + } + } + add("DISPLAY", s.Display) + add("XAUTHORITY", s.XAuthority) + add("WAYLAND_DISPLAY", s.Wayland) + add("DBUS_SESSION_BUS_ADDRESS", s.Bus) + add("XDG_RUNTIME_DIR", s.RuntimeDir) + add("XDG_SESSION_ID", s.SessionID) + add("I3SOCK", s.I3Sock) + return env +} + +// mostOutput bounds what a command may answer with, per stream. +const mostOutput = 256 << 10 + +// Result is what a command did. +type Result struct { + Stdout string `json:"stdout"` + Stderr string `json:"stderr,omitempty"` + Code int `json:"code"` + Truncated bool `json:"truncated,omitempty"` +} + +// run runs a command in the session's environment, its input given, ended with everything it +// started after timeout. A command that is not installed is an error naming it; one that exits +// non-zero is a Result with its code, for the caller to judge. +func (s Session) run(timeout time.Duration, stdin string, name string, args ...string) (Result, error) { + path, err := exec.LookPath(name) + if err != nil { + return Result{}, fmt.Errorf("%s is not installed on this machine", name) + } + cmd := exec.Command(path, args...) + cmd.Env = s.Env() + if home := operatorHome(); exists(home) { + cmd.Dir = home + } + if stdin != "" { + cmd.Stdin = strings.NewReader(stdin) + } + var out, errOut capped + cmd.Stdout, cmd.Stderr = &out, &errOut + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + if err := cmd.Start(); err != nil { + return Result{}, fmt.Errorf("%s: %w", name, err) + } + done := make(chan error, 1) + go func() { done <- cmd.Wait() }() + select { + case err = <-done: + case <-time.After(timeout): + _ = syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) + <-done + return Result{Stdout: out.String(), Stderr: errOut.String()}, + fmt.Errorf("%s did not finish within %s and was ended: %w", name, timeout, ErrTimedOut) + } + r := Result{Stdout: out.String(), Stderr: errOut.String(), Truncated: out.cut || errOut.cut} + var exit *exec.ExitError + if errors.As(err, &exit) { + r.Code = exit.ExitCode() + } else if err != nil { + return r, fmt.Errorf("%s: %w", name, err) + } + return r, nil +} + +// detach starts a long-lived program under the account's own service manager, as a transient unit +// that carries the session's display, so it outlives the runtime that asked for it. A unit already +// running under the same name is stopped first, so a fixed name means "at most one". +func (s Session) detach(unit string, args ...string) error { + if s.RuntimeDir == "" { + return fmt.Errorf("%w: the account's runtime directory is missing, so its service manager "+ + "cannot be reached", ErrNoBus) + } + _, _ = s.run(5*time.Second, "", "systemctl", "--user", "stop", unit+".service") + call := []string{"--user", "--collect", "--quiet", "--unit=" + unit} + for _, kv := range [][2]string{{"DISPLAY", s.Display}, {"XAUTHORITY", s.XAuthority}, + {"WAYLAND_DISPLAY", s.Wayland}, {"XDG_SESSION_ID", s.SessionID}, {"I3SOCK", s.I3Sock}} { + if kv[1] != "" { + call = append(call, "--setenv="+kv[0]+"="+kv[1]) + } + } + call = append(call, "--") + call = append(call, args...) + r, err := s.run(10*time.Second, "", "systemd-run", call...) + if err != nil { + return err + } + if r.Code != 0 { + return fmt.Errorf("systemd-run %s: %s", unit, strings.TrimSpace(r.Stderr)) + } + return nil +} + +// uniqueUnit is a transient unit name that will not collide with an earlier one. +func uniqueUnit(prefix string) string { + return fmt.Sprintf("%s-%d", prefix, time.Now().UnixNano()) +} + +type capped struct { + bytes.Buffer + cut bool +} + +func (c *capped) Write(p []byte) (int, error) { + if room := mostOutput - c.Len(); room < len(p) { + if room > 0 { + c.Buffer.Write(p[:room]) + } + c.cut = true + return len(p), nil + } + return c.Buffer.Write(p) +} + +// processesOf are the pids of this uid's processes whose command name is comm, oldest first. +func processesOf(comm string) []int { + entries, err := os.ReadDir(procRoot) + if err != nil { + return nil + } + uid := os.Getuid() + var pids []int + for _, e := range entries { + pid, err := strconv.Atoi(e.Name()) + if err != nil { + continue + } + dir := filepath.Join(procRoot, e.Name()) + if owner, ok := ownerOf(dir); !ok || owner != uid { + continue + } + if readTrimmed(filepath.Join(dir, "comm")) == comm { + pids = append(pids, pid) + } + } + sort.Ints(pids) + return pids +} + +// signalAll sends sig to every process of this uid named comm, and answers the pids it reached. +func signalAll(comm string, sig syscall.Signal) []int { + var reached []int + for _, pid := range processesOf(comm) { + if syscall.Kill(pid, sig) == nil { + reached = append(reached, pid) + } + } + return reached +} diff --git a/modules/picom/cmd/picom-tools/session_test.go b/modules/picom/cmd/picom-tools/session_test.go new file mode 100644 index 0000000..800cc6d --- /dev/null +++ b/modules/picom/cmd/picom-tools/session_test.go @@ -0,0 +1,174 @@ +package main + +import ( + "errors" + "os" + "path/filepath" + "strconv" + "strings" + "testing" + "time" +) + +// fakeMachine points the session finder at a temporary /proc, /run/user and X socket directory, with +// none of the test process's own session variables, and gives back the root. +func fakeMachine(t *testing.T) string { + t.Helper() + root := t.TempDir() + procRoot, runUserDir, x11Sockets = filepath.Join(root, "proc"), filepath.Join(root, "run-user"), filepath.Join(root, "x11") + for _, d := range []string{procRoot, runUserDir, x11Sockets} { + if err := os.MkdirAll(d, 0o755); err != nil { + t.Fatal(err) + } + } + for _, k := range sessionKeys { + t.Setenv(k, "") + } + t.Setenv("MESH_OPERATOR_HOME", filepath.Join(root, "home")) + t.Cleanup(func() { procRoot, runUserDir, x11Sockets = "/proc", "/run/user", "/tmp/.X11-unix" }) + return root +} + +func fakeProcess(t *testing.T, pid int, comm string, env ...string) { + t.Helper() + dir := filepath.Join(procRoot, strconv.Itoa(pid)) + if err := os.MkdirAll(dir, 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, "comm"), []byte(comm+"\n"), 0o644); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, "environ"), []byte(strings.Join(env, "\x00")+"\x00"), 0o600); err != nil { + t.Fatal(err) + } +} + +func TestTheSessionIsReadFromTheWindowManagerBeforeAnyOtherProcess(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 900, "xterm", "DISPLAY=:9", "XAUTHORITY=/elsewhere") + fakeProcess(t, 100, "i3", "DISPLAY=:1", "XAUTHORITY=/home/op/.Xauthority", + "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus", "XDG_SESSION_ID=3", "SECRET_TOKEN=never-copied") + fakeProcess(t, 50, "bash", "PATH=/usr/bin") + s, err := findSession() + if err != nil { + t.Fatal(err) + } + if s.Display != ":1" || s.XAuthority != "/home/op/.Xauthority" || s.SessionID != "3" || !strings.Contains(s.From, "i3 (pid 100)") { + t.Fatalf("the window manager's environment: %+v", s) + } + for _, kv := range s.Env() { + if strings.HasPrefix(kv, "SECRET_TOKEN=") { + t.Fatal("a variable of the session process that is not a session variable was handed on") + } + } +} + +func TestAnyProcessCarryingADisplayServesWhenTheWindowManagerIsNotFound(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 10, "firefox", "DISPLAY=:0") + fakeProcess(t, 20, "firefox", "DISPLAY=:2") + s, err := findSession() + if err != nil || s.Display != ":2" { + t.Fatalf("the newest of two equals: %+v, %v", s, err) + } +} + +func TestNoSessionIsAClearAnswerNotAGuess(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 10, "sshd", "PATH=/usr/bin") + _, err := findSession() + if !errors.Is(err, ErrNoSession) || !strings.Contains(err.Error(), "logged in to the desktop") { + t.Fatalf("no session: %v", err) + } +} + +func TestOneXSocketAndTheAccountsAuthorityFileAreASession(t *testing.T) { + root := fakeMachine(t) + if err := os.WriteFile(filepath.Join(x11Sockets, "X0"), nil, 0o644); err != nil { + t.Fatal(err) + } + if err := os.MkdirAll(filepath.Join(root, "home"), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(root, "home", ".Xauthority"), nil, 0o600); err != nil { + t.Fatal(err) + } + s, err := findSession() + if err != nil || s.Display != ":0" || !strings.HasSuffix(s.XAuthority, "/home/.Xauthority") { + t.Fatalf("socket and authority: %+v, %v", s, err) + } +} + +func TestTheBusIsTheAccountsRuntimeDirectoryWhenNoProcessNamesIt(t *testing.T) { + fakeMachine(t) + runtime := filepath.Join(runUserDir, strconv.Itoa(os.Getuid())) + if _, err := findBus(); !errors.Is(err, ErrNoBus) { + t.Fatalf("no runtime directory is no bus: %v", err) + } + if err := os.MkdirAll(runtime, 0o700); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(runtime, "bus"), nil, 0o600); err != nil { + t.Fatal(err) + } + s, err := findBus() + if err != nil || s.Bus != "unix:path="+filepath.Join(runtime, "bus") || s.RuntimeDir != runtime { + t.Fatalf("bus: %+v, %v", s, err) + } + env := strings.Join(s.Env(), "\n") + if !strings.Contains(env, "XDG_RUNTIME_DIR="+runtime) || !strings.Contains(env, "DBUS_SESSION_BUS_ADDRESS=unix:path=") { + t.Fatalf("the bus is handed on: %s", env) + } +} + +func TestACommandIsBoundedAndANonZeroExitIsAResult(t *testing.T) { + fakeMachine(t) + s := Session{} + r, err := s.run(5*time.Second, "in", "sh", "-c", "cat; echo err >&2; exit 3") + if err != nil || r.Stdout != "in" || r.Code != 3 || strings.TrimSpace(r.Stderr) != "err" { + t.Fatalf("result: %+v, %v", r, err) + } + start := time.Now() + if _, err := s.run(200*time.Millisecond, "", "sh", "-c", "sleep 30 & sleep 30"); err == nil || time.Since(start) > 5*time.Second { + t.Fatalf("a command past its time is ended with what it started: %v after %s", err, time.Since(start)) + } + if _, err := s.run(time.Second, "", "no-such-program-here"); err == nil || !strings.Contains(err.Error(), "not installed") { + t.Fatalf("a missing program: %v", err) + } +} + +func TestDetachAsksTheAccountsServiceManagerWithTheSessionsDisplay(t *testing.T) { + fakeMachine(t) + bin := fakeBinaries(t, map[string]string{ + "systemctl": `echo "systemctl $*" >> "$LOG"`, + "systemd-run": `echo "systemd-run $*" >> "$LOG"`, + }) + log := filepath.Join(bin, "log") + t.Setenv("LOG", log) + s := Session{Display: ":1", XAuthority: "/x", RuntimeDir: "/run/user/1"} + if err := s.detach("picom-session", "picom", "--config", "/c"); err != nil { + t.Fatal(err) + } + got, _ := os.ReadFile(log) + want := "systemctl --user stop picom-session.service\n" + + "systemd-run --user --collect --quiet --unit=picom-session --setenv=DISPLAY=:1 --setenv=XAUTHORITY=/x -- picom --config /c\n" + if string(got) != want { + t.Fatalf("detach ran:\n%s\nwant:\n%s", got, want) + } + if err := (Session{}).detach("x", "y"); !errors.Is(err, ErrNoBus) { + t.Fatalf("no runtime directory: %v", err) + } +} + +// fakeBinaries puts shell scripts named for programs first on PATH, and answers their directory. +func fakeBinaries(t *testing.T, scripts map[string]string) string { + t.Helper() + dir := t.TempDir() + for name, body := range scripts { + if err := os.WriteFile(filepath.Join(dir, name), []byte("#!/bin/sh\n"+body+"\n"), 0o755); err != nil { + t.Fatal(err) + } + } + t.Setenv("PATH", dir+string(os.PathListSeparator)+os.Getenv("PATH")) + return dir +} diff --git a/modules/picom/files/picom.conf b/modules/picom/files/picom.conf new file mode 100644 index 0000000..efe5ff2 --- /dev/null +++ b/modules/picom/files/picom.conf @@ -0,0 +1,32 @@ +# picom, the X compositor (module picom, novox/hq ADR 0208). Owned by the mesh: this file is +# replaced at every push. Adopted from the two workstations' file of 2026-10-04 and moved to +# picom's window rules, which supersede opacity-rule, inactive-opacity and inactive-dim. + +backend = "glx"; +vsync = true; + +fading = true; +fade-in-step = 0.05; +fade-out-step = 0.05; + +# Tiled windows hide their shadows and corners, so neither is drawn. +shadow = false; +corner-radius = 0; +blur-method = "none"; + +# "Focused" is i3's _NET_ACTIVE_WINDOW, not X focus events: under i3 those do not reliably reach +# the toplevel picom tracks, and a terminal then never lifts to its focused opacity. +use-ewmh-active-win = true; + +# Window rules are applied in order, and a later match wins. Only terminals are translucent: +# nothing else on screen (browsers, video, games) is touched. A terminal is matched by its class; +# the node's terminal emulator today is xterm (class XTerm). A window's own opacity property is +# used wherever no rule sets one, which is what the window-opacity tool sets. +rules = ( + { match = "window_type = 'tooltip'"; fade = false; opacity = 0.95; }, + { match = "window_type = 'dock' || window_type = 'desktop'"; fade = false; }, + { match = "class_g = 'XTerm' && focused"; opacity = 0.95; }, + { match = "class_g = 'XTerm' && !focused"; opacity = 0.75; }, + # A full-screen window is opaque, a terminal included: a video or a game is never see-through. + { match = "fullscreen"; opacity = 1; } +); diff --git a/modules/picom/go.mod b/modules/picom/go.mod new file mode 100644 index 0000000..c30ad61 --- /dev/null +++ b/modules/picom/go.mod @@ -0,0 +1,5 @@ +module picom + +go 1.22 + +require git.novox.be/novox/mesh-sdk/go v0.1.7 diff --git a/modules/picom/go.sum b/modules/picom/go.sum new file mode 100644 index 0000000..b474419 --- /dev/null +++ b/modules/picom/go.sum @@ -0,0 +1,2 @@ +git.novox.be/novox/mesh-sdk/go v0.1.7 h1:C0sTQmtTiyYH7bnqZb7PusXnqA37gKuT7Nqjn9gG47w= +git.novox.be/novox/mesh-sdk/go v0.1.7/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= diff --git a/modules/picom/module.json b/modules/picom/module.json new file mode 100644 index 0000000..e7dc836 --- /dev/null +++ b/modules/picom/module.json @@ -0,0 +1,64 @@ +{ + "module": "picom", + "version": "1", + "capabilities": [ + "package-manager" + ], + "requires": [ + "x11-display" + ], + "claims": [ + { + "name": "node-compositor", + "scope": "node" + } + ], + "tools": [ + "picom_restart", + "picom_rules", + "picom_window_opacity", + "picom_toggle" + ], + "resources": [ + { + "id": "package", + "type": "package", + "package": "picom" + }, + { + "id": "window-properties", + "type": "package", + "package": "xorg-xprop" + }, + { + "id": "configuration-dir", + "type": "directory", + "path": "${machine:account-home}/.config/picom", + "owner": "${machine:account}", + "mode": "0755" + }, + { + "id": "configuration", + "type": "file", + "path": "${machine:account-home}/.config/picom/picom.conf", + "owner": "${machine:account}", + "mode": "0644", + "content": "# picom, the X compositor (module picom, novox/hq ADR 0208). Owned by the mesh: this file is\n# replaced at every push. Adopted from the two workstations' file of 2026-10-04 and moved to\n# picom's window rules, which supersede opacity-rule, inactive-opacity and inactive-dim.\n\nbackend = \"glx\";\nvsync = true;\n\nfading = true;\nfade-in-step = 0.05;\nfade-out-step = 0.05;\n\n# Tiled windows hide their shadows and corners, so neither is drawn.\nshadow = false;\ncorner-radius = 0;\nblur-method = \"none\";\n\n# \"Focused\" is i3's _NET_ACTIVE_WINDOW, not X focus events: under i3 those do not reliably reach\n# the toplevel picom tracks, and a terminal then never lifts to its focused opacity.\nuse-ewmh-active-win = true;\n\n# Window rules are applied in order, and a later match wins. Only terminals are translucent:\n# nothing else on screen (browsers, video, games) is touched. A terminal is matched by its class;\n# the node's terminal emulator today is xterm (class XTerm). A window's own opacity property is\n# used wherever no rule sets one, which is what the window-opacity tool sets.\nrules = (\n { match = \"window_type = 'tooltip'\"; fade = false; opacity = 0.95; },\n { match = \"window_type = 'dock' || window_type = 'desktop'\"; fade = false; },\n { match = \"class_g = 'XTerm' && focused\"; opacity = 0.95; },\n { match = \"class_g = 'XTerm' && !focused\"; opacity = 0.75; },\n # A full-screen window is opaque, a terminal included: a video or a game is never see-through.\n { match = \"fullscreen\"; opacity = 1; }\n);\n" + } + ], + "build": { + "artifacts": [ + { + "name": "tools", + "kind": "bundle", + "language": "go", + "system": "arch", + "from": "cmd/picom-tools", + "binary": "picom-tools", + "loads": [ + "picom-tools" + ] + } + ] + } +} From f0f0a796235f2e6d290541d2919d10e16409c87f Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 4 Oct 2026 12:51:17 +0200 Subject: [PATCH 02/15] rofi: the launcher as a module, claiming node-launcher and serving menu (hq ADR 0208) Places the seat's dmenu-compatible command, the launcher and power menu, its themes in the decided faces, and its key bindings as an i3 drop-in; Go tools menu, applications, themes and run. --- modules/rofi/README.md | 88 ++++ modules/rofi/cmd/rofi-tools/args.go | 97 ++++ modules/rofi/cmd/rofi-tools/main.go | 100 +++++ .../cmd/rofi-tools/manifest_helpers_test.go | 175 ++++++++ modules/rofi/cmd/rofi-tools/manifest_test.go | 111 +++++ modules/rofi/cmd/rofi-tools/rofi.go | 410 +++++++++++++++++ modules/rofi/cmd/rofi-tools/rofi_test.go | 196 ++++++++ modules/rofi/cmd/rofi-tools/session.go | 423 ++++++++++++++++++ modules/rofi/cmd/rofi-tools/session_test.go | 174 +++++++ modules/rofi/files/bin/dmenu | 26 ++ modules/rofi/files/bin/rofi-launch | 39 ++ modules/rofi/files/bin/rofi-powermenu | 54 +++ modules/rofi/files/config.rasi | 54 +++ modules/rofi/files/i3/50-rofi.conf | 8 + modules/rofi/files/themes/mesh-powermenu.rasi | 172 +++++++ modules/rofi/files/themes/mesh.rasi | 263 +++++++++++ modules/rofi/go.mod | 5 + modules/rofi/go.sum | 2 + modules/rofi/module.json | 116 +++++ 19 files changed, 2513 insertions(+) create mode 100644 modules/rofi/README.md create mode 100644 modules/rofi/cmd/rofi-tools/args.go create mode 100644 modules/rofi/cmd/rofi-tools/main.go create mode 100644 modules/rofi/cmd/rofi-tools/manifest_helpers_test.go create mode 100644 modules/rofi/cmd/rofi-tools/manifest_test.go create mode 100644 modules/rofi/cmd/rofi-tools/rofi.go create mode 100644 modules/rofi/cmd/rofi-tools/rofi_test.go create mode 100644 modules/rofi/cmd/rofi-tools/session.go create mode 100644 modules/rofi/cmd/rofi-tools/session_test.go create mode 100755 modules/rofi/files/bin/dmenu create mode 100755 modules/rofi/files/bin/rofi-launch create mode 100755 modules/rofi/files/bin/rofi-powermenu create mode 100644 modules/rofi/files/config.rasi create mode 100644 modules/rofi/files/i3/50-rofi.conf create mode 100644 modules/rofi/files/themes/mesh-powermenu.rasi create mode 100644 modules/rofi/files/themes/mesh.rasi create mode 100644 modules/rofi/go.mod create mode 100644 modules/rofi/go.sum create mode 100644 modules/rofi/module.json diff --git a/modules/rofi/README.md b/modules/rofi/README.md new file mode 100644 index 0000000..827c8e1 --- /dev/null +++ b/modules/rofi/README.md @@ -0,0 +1,88 @@ +# rofi + +The launcher as a module (novox/hq ADR 0208, research 026/04 and 05). + +- Installs `rofi`, claims the mesh's `node-launcher` seat and serves its verb `menu`. Requires + `x11-display` on its own machine. +- **The seat's dmenu-compatible command.** It places `~/.local/bin/dmenu`: choices on standard input, + the chosen one on standard output, exit 1 when nothing was chosen. It runs `rofi -dmenu`, passing + on dmenu's `-p`, `-l` and `-i` and dropping its look options. A script, a notifier or a clipboard + manager calls `dmenu` and works whichever module holds the seat. On a node where the `dmenu` module + holds `node-launcher` instead, the real dmenu answers the same calls. +- Owns `~/.config/rofi/config.rasi` and the themes `mesh` and `mesh-powermenu` in + `~/.config/rofi/themes/`. The faces are JetBrains Mono Nerd Font for the list and the input, and + Inter for messages. Both are packages of the `fonts` module. +- Places its key bindings as its own i3 drop-in, `~/.config/i3/config.d/50-rofi.conf`. The `i3` + module's configuration includes that directory after it sets `$mod`. +- Starts nothing. rofi runs when a key is pressed. + +| key | runs | +|---|---| +| `$mod+d` | applications (`rofi-launch drun`) | +| `$mod+t` | a command (`rofi-launch run`) | +| `$mod+Shift+t` | a command with sudo, in the terminal (`rofi-launch sudo`) | +| `$mod+Shift+w` | the window switcher (`rofi-launch window`) | +| `$mod+Escape` | the power menu (`rofi-powermenu`) | + +## The power menu is here + +The power menu belongs to the session. It is still the launcher's, because all of it is rofi: its +theme, its buttons and its confirmation. Every action it takes is a verb of logind or the service +manager, so it names no window manager and no locker: + +- **lock** is `loginctl lock-session`, which the holder of `node-lock-screen` answers; +- **log out** is `loginctl terminate-session`; +- **suspend, reboot and shut down** are `systemctl`'s. + +A Wayland session gets the same menu from whichever launcher holds the seat there. + +## Tools + +| tool | does | +|---|---| +| `node-launcher.menu` | show a list in the operator's session and answer the chosen line and its index, or `cancelled` (also when nobody answers within the timeout, 20 s by default, 25 s at most) | +| `rofi_applications` | the desktop entries the launcher offers, the account's own winning an id; filter by words, hidden ones on request | +| `rofi_themes` | every theme (the mesh's, the account's, the distribution's) and the one configured | +| `rofi_run` | start a desktop entry or a command in the session, under the account's service manager | + +## What it improves on what was found + +- **Plain `dmenu` calls work again.** The one found on 2026-10-04 is the notifier's context menu: on + both workstations it called `/usr/bin/dmenu`, which neither had installed. The `dunst` module now + calls `dmenu`, and this module answers it. The operator's own scripts all call `rofi -dmenu`, which + keeps working. +- **The theme is one file per face.** There is no colour file imported from a cloned theme + repository. The faces are the decided ones (research 026/04): Iosevka and Hack are gone. +- **The retry after resume no longer reopens a closed menu.** The found launchers retried + `rofi -dmenu` on any failure, so pressing Escape in the sudo prompt reopened it four times. + `rofi-launch` retries only a failure within half a second, which is a failed keyboard grab. +- **The power menu locks through logind,** so it goes through the one locker. The found one ran + `i3lock` directly and bypassed it. Log out no longer names four window managers. +- `icon-theme` and `window-command` are gone. They named an icon theme and a program (`wmctrl`) that + nothing installs. rofi's defaults serve. + +## What it leaves as found + +- `~/.config/rofi/themes-repo/` (a cloned theme repository), the five symbolic links into it + (`applets`, `images`, `launchers`, `powermenu`, `scripts`), `colors/`, `theme.rasi` and + `powermenu.rasi`. +- The predecessor's scripts in `~/scripts`: `rofi-launcher-normal`, `rofi-launcher-terminal`, + `rofi-launcher-terminal-sudo` and `powermenu` (replaced here), and `theme-picker` with its modes + (settings, once issue 168 closes). + +## Migration (ADR 0182) + +Once the `i3` module carries the main i3 configuration: + +1. Delete `~/.config/rofi/theme.rasi`, `powermenu.rasi`, `colors/`, the five links and `themes-repo/`. + Nothing reads them any more. +2. Delete the four scripts above from `~/scripts`. +3. Your scripts that call `rofi -dmenu` keep working. Calling `dmenu` instead lets them follow the + seat, for example to a Wayland launcher later. + +## Blockers + +- `node-launcher`, `x11-display` and the `i3` drop-in directory are ADR 0208's and the `i3` + module's. Until the controller knows the seat, `mctl` reads the claim as unknown. +- `~/.local/bin` is on `PATH` through the `zsh` module's environment contribution (ADR 0203). The + key bindings name `~/.local/bin/…` in full, so they do not depend on it. Callers of `dmenu` do. diff --git a/modules/rofi/cmd/rofi-tools/args.go b/modules/rofi/cmd/rofi-tools/args.go new file mode 100644 index 0000000..9b5dfcf --- /dev/null +++ b/modules/rofi/cmd/rofi-tools/args.go @@ -0,0 +1,97 @@ +// Reading a tool's arguments: JSON numbers arrive as float64, and a missing argument is its default. +// The same in every desktop module that carries it. +package main + +import ( + "fmt" + "math" + "strings" + "time" +) + +// text is a string argument, trimmed; required says an empty one is refused. +func text(args map[string]any, key string, required bool) (string, error) { + v, present := args[key] + if !present || v == nil { + if required { + return "", fmt.Errorf("%s is required", key) + } + return "", nil + } + s, ok := v.(string) + if !ok { + return "", fmt.Errorf("%s is a string, not %T", key, v) + } + s = strings.TrimSpace(s) + if s == "" && required { + return "", fmt.Errorf("%s is required", key) + } + return s, nil +} + +// whole is a whole-number argument within [least, most], or def when absent. +func whole(args map[string]any, key string, def, least, most int) (int, error) { + v, present := args[key] + if !present || v == nil { + return def, nil + } + f, ok := v.(float64) + if !ok { + if i, isInt := v.(int); isInt { + f = float64(i) + } else { + return 0, fmt.Errorf("%s is a number, not %T", key, v) + } + } + if f != math.Trunc(f) { + return 0, fmt.Errorf("%s is a whole number, not %v", key, f) + } + n := int(f) + if n < least || n > most { + return 0, fmt.Errorf("%s is %d; it is between %d and %d", key, n, least, most) + } + return n, nil +} + +// flag is a boolean argument, or def when absent. +func flag(args map[string]any, key string, def bool) (bool, error) { + v, present := args[key] + if !present || v == nil { + return def, nil + } + b, ok := v.(bool) + if !ok { + return false, fmt.Errorf("%s is true or false, not %T", key, v) + } + return b, nil +} + +// texts is a list-of-strings argument. +func texts(args map[string]any, key string) ([]string, error) { + v, present := args[key] + if !present || v == nil { + return nil, nil + } + list, ok := v.([]any) + if !ok { + if ss, isStrings := v.([]string); isStrings { + return ss, nil + } + return nil, fmt.Errorf("%s is a list of strings, not %T", key, v) + } + out := make([]string, 0, len(list)) + for i, item := range list { + s, ok := item.(string) + if !ok { + return nil, fmt.Errorf("%s[%d] is a string, not %T", key, i, item) + } + out = append(out, s) + } + return out, nil +} + +// seconds is a timeout argument in seconds, defaulted and bounded below the runtime's call limit. +func seconds(args map[string]any, key string, def, most int) (time.Duration, error) { + n, err := whole(args, key, def, 1, most) + return time.Duration(n) * time.Second, err +} diff --git a/modules/rofi/cmd/rofi-tools/main.go b/modules/rofi/cmd/rofi-tools/main.go new file mode 100644 index 0000000..fd7dbb8 --- /dev/null +++ b/modules/rofi/cmd/rofi-tools/main.go @@ -0,0 +1,100 @@ +// rofi's Go tools bundle (novox/hq ADR 0188, ADR 0193, ADR 0208): its implementation of +// node-launcher's verb `menu` — the dmenu-compatible command as a tool — and its own tools, served by +// the node's runtime as the operator account. +package main + +import ( + "fmt" + "os" + + stdio "git.novox.be/novox/mesh-sdk/go" +) + +func main() { + if err := stdio.Serve("", tools()); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func tools() []stdio.Tool { + return []stdio.Tool{ + { + Name: "node-launcher.menu", + Description: fmt.Sprintf("Show a list in the operator's session and answer the line they choose: "+ + "the launcher's dmenu-compatible command as a tool. Answers chosen and its index, or cancelled "+ + "when they closed it or did not answer within timeout_seconds (default %d, at most %d).", menuDefault, menuMost), + Input: map[string]any{ + "type": "object", + "properties": map[string]any{ + "items": map[string]any{"type": "array", "items": map[string]any{"type": "string"}, "description": "the choices, one line each"}, + "prompt": map[string]any{"type": "string", "description": "the prompt (default: Choose)"}, + "message": map[string]any{"type": "string", "description": "a line of explanation above the list"}, + "allow_custom": map[string]any{"type": "boolean", "description": "accept a typed answer that is not in the list (default false)"}, + "timeout_seconds": map[string]any{"type": "integer", "description": fmt.Sprintf("give up after this long (default %d, at most %d)", menuDefault, menuMost)}, + }, + "required": []string{"items"}, + }, + Run: func(args map[string]any) (any, error) { + q, err := menuQuestion(args) + if err != nil { + return nil, err + } + return Menu(q) + }, + }, + { + Name: "rofi_applications", + Description: "The desktop applications the launcher offers on this machine, from every desktop entry " + + "directory in the order the launcher reads them (the account's first): id, name, what it runs, " + + "categories and the file. Hidden entries are left out unless asked for.", + Input: map[string]any{ + "query": map[string]any{"type": "string", "description": "only entries whose name, generic name, keywords or command contain this (any case)"}, + "show_hidden": map[string]any{"type": "boolean", "description": "include entries marked NoDisplay or Hidden (default false)"}, + "limit": map[string]any{"type": "integer", "description": "at most this many (default 200, at most 2000)"}, + }, + Run: func(args map[string]any) (any, error) { + query, err := text(args, "query", false) + if err != nil { + return nil, err + } + hidden, err := flag(args, "show_hidden", false) + if err != nil { + return nil, err + } + limit, err := whole(args, "limit", 200, 1, 2000) + if err != nil { + return nil, err + } + return Applications(applicationDirs(), query, hidden, limit), nil + }, + }, + { + Name: "rofi_themes", + Description: "The launcher's themes on this machine — the mesh's, the operator's own and the " + + "distribution's — each with its file, and which one the configuration uses.", + Run: func(map[string]any) (any, error) { return Themes(themeDirs(), configFile()), nil }, + }, + { + Name: "rofi_run", + Description: "Start a program in the operator's session, as the launcher would: a desktop entry by " + + "its id (firefox.desktop), or a command as its words. It runs under the account's own service " + + "manager, so it outlives this call; answers the unit it runs as and what it ran.", + Input: map[string]any{ + "application": map[string]any{"type": "string", "description": "a desktop entry id, as rofi_applications answers it"}, + "command": map[string]any{"type": "array", "items": map[string]any{"type": "string"}, "description": "a program and its arguments, one word each"}, + }, + Run: func(args map[string]any) (any, error) { + app, err := text(args, "application", false) + if err != nil { + return nil, err + } + command, err := texts(args, "command") + if err != nil { + return nil, err + } + return Run(app, command) + }, + }, + } +} diff --git a/modules/rofi/cmd/rofi-tools/manifest_helpers_test.go b/modules/rofi/cmd/rofi-tools/manifest_helpers_test.go new file mode 100644 index 0000000..d4fb76d --- /dev/null +++ b/modules/rofi/cmd/rofi-tools/manifest_helpers_test.go @@ -0,0 +1,175 @@ +package main + +import ( + "encoding/json" + "os" + "path/filepath" + "strings" + "testing" +) + +// The module's manifest, read the way the catalogue reads it, for the manifest tests. The same in +// every desktop module that carries it. + +type manifest struct { + Module string `json:"module"` + Version string `json:"version"` + Capabilities []string `json:"capabilities"` + Requires []string `json:"requires"` + Claims []claim `json:"claims"` + Seats []any `json:"seats"` + Tools []string `json:"tools"` + Environment *environment `json:"environment"` + Shell []shellCode `json:"shell"` + Resources []map[string]any `json:"resources"` + Build struct { + Artifacts []map[string]any `json:"artifacts"` + } `json:"build"` +} + +type claim struct { + Name string `json:"name"` + Scope string `json:"scope"` + Serves []string `json:"serves"` +} + +type environment struct { + Variables map[string]string `json:"variables"` + Path []map[string]any `json:"path"` +} + +type shellCode struct { + For string `json:"for"` + Slot string `json:"slot"` + Code string `json:"code"` +} + +func readManifest(t *testing.T) manifest { + t.Helper() + raw, err := os.ReadFile(filepath.Join("..", "..", "module.json")) + if err != nil { + t.Fatal(err) + } + dec := json.NewDecoder(strings.NewReader(string(raw))) + dec.DisallowUnknownFields() + var m manifest + if err := dec.Decode(&m); err != nil { + t.Fatalf("module.json: %v", err) + } + return m +} + +func (m manifest) resource(t *testing.T, id string) map[string]any { + t.Helper() + for _, r := range m.Resources { + if r["id"] == id { + return r + } + } + t.Fatalf("no resource %q", id) + return nil +} + +func (m manifest) packages() (present, absent []string) { + for _, r := range m.Resources { + if r["type"] == "package" { + if r["absent"] == true { + absent = append(absent, r["package"].(string)) + } else { + present = append(present, r["package"].(string)) + } + } + } + return present, absent +} + +// sameAsSource checks that a file resource's content is byte for byte the module's source file, so +// the readable file in the repository is what the machine gets. +func (m manifest) sameAsSource(t *testing.T, id, source string) { + t.Helper() + want, err := os.ReadFile(filepath.Join("..", "..", source)) + if err != nil { + t.Fatal(err) + } + r := m.resource(t, id) + if r["type"] != "file" { + t.Fatalf("%s is a %v, not a file", id, r["type"]) + } + if got, _ := r["content"].(string); got != string(want) { + t.Fatalf("resource %s's content is not %s: edit the source and copy it into module.json", id, source) + } + if r["owner"] != "${machine:account}" && !strings.HasPrefix(r["path"].(string), "/etc/") { + t.Fatalf("%s under the home is the account's", id) + } +} + +// checkTheToolsAgree checks that the manifest lists the module's own tools exactly, that the bundle +// serves each seat verb the claims promise as ., and that the Go bundle is declared. +func checkTheToolsAgree(t *testing.T, m manifest) { + t.Helper() + own, seat := map[string]bool{}, map[string]bool{} + for _, tool := range tools() { + if strings.Contains(tool.Name, ".") { + seat[tool.Name] = true + } else { + own[tool.Name] = true + } + if strings.TrimSpace(tool.Description) == "" { + t.Errorf("%s has no description", tool.Name) + } + } + listed := map[string]bool{} + for _, name := range m.Tools { + listed[name] = true + if !own[name] { + t.Errorf("module.json lists %s, which the bundle does not serve", name) + } + } + for name := range own { + if !listed[name] { + t.Errorf("the bundle serves %s, which module.json does not list", name) + } + if !strings.HasPrefix(name, strings.ReplaceAll(m.Module, "-", "_")+"_") { + t.Errorf("%s is not prefixed with the module's name", name) + } + } + promised := map[string]bool{} + for _, c := range m.Claims { + for _, verb := range c.Serves { + promised[c.Name+"."+verb] = true + if !seat[c.Name+"."+verb] { + t.Errorf("the claim on %s promises %s, which the bundle does not serve", c.Name, verb) + } + } + } + for name := range seat { + if !promised[name] { + t.Errorf("the bundle serves %s, which no claim promises", name) + } + } + var bundle map[string]any + for _, a := range m.Build.Artifacts { + if a["kind"] == "bundle" { + bundle = a + } + } + if bundle == nil || bundle["language"] != "go" || bundle["system"] != "arch" || + bundle["from"] != "cmd/"+m.Module+"-tools" || bundle["binary"] != m.Module+"-tools" { + t.Errorf("the Go tools bundle: %v", bundle) + } +} + +// checkNoSecretsOrInstallationNames refuses what a catalogue manifest must never carry. +func checkNoSecretsOrInstallationNames(t *testing.T) { + t.Helper() + raw, err := os.ReadFile(filepath.Join("..", "..", "module.json")) + if err != nil { + t.Fatal(err) + } + s := strings.ToLower(string(raw)) + for _, never := range []string{"/home/", "jochen", "g14", "shanks", "novox.be", "api_key", ".hal/", "greenclip daemon"} { + if strings.Contains(s, never) { + t.Errorf("module.json names %q", never) + } + } +} diff --git a/modules/rofi/cmd/rofi-tools/manifest_test.go b/modules/rofi/cmd/rofi-tools/manifest_test.go new file mode 100644 index 0000000..a9c8265 --- /dev/null +++ b/modules/rofi/cmd/rofi-tools/manifest_test.go @@ -0,0 +1,111 @@ +package main + +import ( + "reflect" + "strings" + "testing" +) + +// rofi's shape (novox/hq ADR 0208, research 026/04): it claims node-launcher and serves its verb +// `menu`, requires the X display on its own machine, owns its configuration and its two themes, and +// places the seat's dmenu-compatible command, its launcher and power menu, and its key bindings as +// its own i3 drop-in. + +func TestItClaimsTheLauncherSeatServingMenuAndRequiresTheXDisplay(t *testing.T) { + m := readManifest(t) + if m.Module != "rofi" || m.Seats != nil { + t.Fatalf("module %q declares seats %v", m.Module, m.Seats) + } + if !reflect.DeepEqual(m.Claims, []claim{{Name: "node-launcher", Scope: "node", Serves: []string{"menu"}}}) { + t.Fatalf("claims: %+v", m.Claims) + } + if !reflect.DeepEqual(m.Requires, []string{"x11-display"}) { + t.Fatalf("requires: %v", m.Requires) + } + if present, absent := m.packages(); !reflect.DeepEqual(present, []string{"rofi"}) || absent != nil { + t.Fatalf("packages: %v, absent %v", present, absent) + } +} + +func TestItOwnsItsFilesAsWrittenInTheModule(t *testing.T) { + m := readManifest(t) + for id, source := range map[string]string{ + "configuration": "files/config.rasi", + "theme": "files/themes/mesh.rasi", + "theme-powermenu": "files/themes/mesh-powermenu.rasi", + "dmenu": "files/bin/dmenu", + "launch": "files/bin/rofi-launch", + "powermenu": "files/bin/rofi-powermenu", + "i3-bindings": "files/i3/50-rofi.conf", + } { + m.sameAsSource(t, id, source) + } + for _, id := range []string{"dmenu", "launch", "powermenu"} { + if m.resource(t, id)["mode"] != "0755" { + t.Errorf("%s is executable", id) + } + } + if p := m.resource(t, "dmenu")["path"]; p != "${machine:account-home}/.local/bin/dmenu" { + t.Fatalf("the seat's command is dmenu on the account's PATH: %v", p) + } +} + +func TestTheThemesAreTheMeshsFacesAndTheConfigurationNamesOne(t *testing.T) { + m := readManifest(t) + conf := m.resource(t, "configuration")["content"].(string) + if !strings.Contains(conf, `@theme "mesh"`) || strings.Contains(conf, "@import") { + t.Fatal("the configuration names the theme mesh and imports nothing") + } + for _, id := range []string{"theme", "theme-powermenu"} { + c := m.resource(t, id)["content"].(string) + if !strings.Contains(c, `"JetBrainsMono Nerd Font`) || strings.Contains(c, "@import") || + strings.Contains(c, "Hack") || strings.Contains(c, "Iosevka") { + t.Errorf("%s: the monospace face, and no imported file", id) + } + } + if !strings.Contains(m.resource(t, "theme")["content"].(string), `"Inter 11"`) { + t.Error("the theme's prose is in the interface face") + } +} + +func TestThePowerMenuNamesNoWindowManagerAndNoLocker(t *testing.T) { + m := readManifest(t) + menu := m.resource(t, "powermenu")["content"].(string) + for _, never := range []string{"i3-msg", "i3lock", "betterlockscreen", "openbox", "bspc", "qdbus", "mpc"} { + if strings.Contains(menu, never) { + t.Errorf("the power menu names %s", never) + } + } + for _, want := range []string{"loginctl lock-session", "loginctl terminate-session", "systemctl suspend", "systemctl reboot", "systemctl poweroff"} { + if !strings.Contains(menu, want) { + t.Errorf("the power menu lacks %s", want) + } + } +} + +func TestTheKeyBindingsAreAnI3DropInRunningTheModulesOwnCommands(t *testing.T) { + m := readManifest(t) + bindings := m.resource(t, "i3-bindings")["content"].(string) + for _, line := range strings.Split(bindings, "\n") { + if line == "" || strings.HasPrefix(line, "#") { + continue + } + if !strings.HasPrefix(line, "bindsym $mod+") || !strings.Contains(line, "exec --no-startup-id ~/.local/bin/rofi-") { + t.Errorf("a binding that is not the launcher's: %s", line) + } + } + for _, key := range []string{"$mod+d ", "$mod+Escape "} { + if !strings.Contains(bindings, "bindsym "+key) { + t.Errorf("no %s", key) + } + } + if m.Shell != nil { + t.Fatalf("the launcher starts nothing at session start: %+v", m.Shell) + } +} + +func TestTheToolsAgreeWithTheManifest(t *testing.T) { + m := readManifest(t) + checkTheToolsAgree(t, m) + checkNoSecretsOrInstallationNames(t) +} diff --git a/modules/rofi/cmd/rofi-tools/rofi.go b/modules/rofi/cmd/rofi-tools/rofi.go new file mode 100644 index 0000000..810f9de --- /dev/null +++ b/modules/rofi/cmd/rofi-tools/rofi.go @@ -0,0 +1,410 @@ +package main + +import ( + "bufio" + "errors" + "fmt" + "os" + "path/filepath" + "regexp" + "sort" + "strings" + "time" +) + +// The menu waits for a person, bounded below the runtime's call limit. +const ( + menuDefault = 20 + menuMost = 25 + mostItems = 1000 +) + +// MenuQuestion is what node-launcher.menu asks. +type MenuQuestion struct { + Items []string + Prompt string + Message string + AllowCustom bool + Timeout time.Duration +} + +func menuQuestion(args map[string]any) (MenuQuestion, error) { + var q MenuQuestion + var err error + if q.Items, err = texts(args, "items"); err != nil { + return q, err + } + if len(q.Items) == 0 { + return q, errors.New("items is required: at least one choice") + } + if len(q.Items) > mostItems { + return q, fmt.Errorf("%d items; a menu shows at most %d", len(q.Items), mostItems) + } + for i, item := range q.Items { + if strings.ContainsAny(item, "\n\r") { + return q, fmt.Errorf("items[%d] spans lines; a choice is one line", i) + } + } + if q.Prompt, err = text(args, "prompt", false); err != nil { + return q, err + } + if q.Prompt == "" { + q.Prompt = "Choose" + } + if q.Message, err = text(args, "message", false); err != nil { + return q, err + } + if q.AllowCustom, err = flag(args, "allow_custom", false); err != nil { + return q, err + } + q.Timeout, err = seconds(args, "timeout_seconds", menuDefault, menuMost) + return q, err +} + +// MenuAnswer is what node-launcher.menu answers. +type MenuAnswer struct { + Chosen string `json:"chosen,omitempty"` + Index int `json:"index"` + Custom bool `json:"custom,omitempty"` + Cancelled bool `json:"cancelled"` + TimedOut bool `json:"timed_out,omitempty"` +} + +// Menu shows the list with `rofi -dmenu` in the operator's session and answers the choice. +func Menu(q MenuQuestion) (MenuAnswer, error) { + s, err := findSession() + if err != nil { + return MenuAnswer{}, err + } + args := []string{"-dmenu", "-i", "-p", q.Prompt, "-format", "s"} + if q.Message != "" { + args = append(args, "-mesg", q.Message) + } + if !q.AllowCustom { + args = append(args, "-no-custom") + } + r, err := s.run(q.Timeout, strings.Join(q.Items, "\n")+"\n", "rofi", args...) + if errors.Is(err, ErrTimedOut) { + return MenuAnswer{Index: -1, Cancelled: true, TimedOut: true}, nil + } + if err != nil { + return MenuAnswer{}, err + } + switch r.Code { + case 0: + case 1: + return MenuAnswer{Index: -1, Cancelled: true}, nil + default: + return MenuAnswer{}, fmt.Errorf("rofi exited %d: %s", r.Code, strings.TrimSpace(r.Stderr)) + } + chosen := strings.TrimRight(r.Stdout, "\n") + for i, item := range q.Items { + if item == chosen { + return MenuAnswer{Chosen: chosen, Index: i}, nil + } + } + return MenuAnswer{Chosen: chosen, Index: -1, Custom: true}, nil +} + +// Application is one desktop entry the launcher offers. +type Application struct { + ID string `json:"id"` + Name string `json:"name"` + GenericName string `json:"generic_name,omitempty"` + Comment string `json:"comment,omitempty"` + Exec string `json:"exec"` + Terminal bool `json:"terminal,omitempty"` + Categories []string `json:"categories,omitempty"` + Hidden bool `json:"hidden,omitempty"` + File string `json:"file"` + keywords string +} + +// ApplicationsResult is what rofi_applications answers. +type ApplicationsResult struct { + Directories []string `json:"directories"` + Count int `json:"count"` + Truncated bool `json:"truncated,omitempty"` + Applications []Application `json:"applications"` +} + +// applicationDirs are the directories desktop entries are read from, the first winning an id: the +// account's own, then XDG_DATA_DIRS (as the session has it), then flatpak's exports. +func applicationDirs() []string { + home := operatorHome() + dirs := []string{filepath.Join(home, ".local", "share", "applications")} + data := os.Getenv("XDG_DATA_DIRS") + if data == "" { + data = "/usr/local/share:/usr/share" + } + for _, d := range strings.Split(data, ":") { + if d != "" { + dirs = append(dirs, filepath.Join(d, "applications")) + } + } + dirs = append(dirs, filepath.Join(home, ".local", "share", "flatpak", "exports", "share", "applications"), + "/var/lib/flatpak/exports/share/applications") + return unique(dirs) +} + +func unique(in []string) []string { + seen := map[string]bool{} + var out []string + for _, s := range in { + if !seen[s] { + seen[s] = true + out = append(out, s) + } + } + return out +} + +// Applications reads every desktop entry in dirs, the first directory winning an id. +func Applications(dirs []string, query string, showHidden bool, limit int) ApplicationsResult { + byID := map[string]Application{} + for _, dir := range dirs { + _ = filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error { + if err != nil || d.IsDir() || !strings.HasSuffix(path, ".desktop") { + return nil + } + rel, _ := filepath.Rel(dir, path) + id := strings.ReplaceAll(rel, string(filepath.Separator), "-") + if _, taken := byID[id]; taken { + return nil + } + if app, ok := readDesktopEntry(path); ok { + app.ID = id + byID[id] = app + } + return nil + }) + } + q := strings.ToLower(query) + out := ApplicationsResult{Directories: dirs, Applications: []Application{}} + ids := make([]string, 0, len(byID)) + for id := range byID { + ids = append(ids, id) + } + sort.Slice(ids, func(i, j int) bool { + a, b := byID[ids[i]], byID[ids[j]] + if strings.ToLower(a.Name) != strings.ToLower(b.Name) { + return strings.ToLower(a.Name) < strings.ToLower(b.Name) + } + return a.ID < b.ID + }) + for _, id := range ids { + app := byID[id] + if app.Hidden && !showHidden { + continue + } + if q != "" && !strings.Contains(strings.ToLower(app.Name+"\x00"+app.GenericName+"\x00"+app.keywords+"\x00"+app.Exec), q) { + continue + } + out.Count++ + if len(out.Applications) < limit { + out.Applications = append(out.Applications, app) + } else { + out.Truncated = true + } + } + return out +} + +// readDesktopEntry reads the [Desktop Entry] group of an application's file, unlocalised. +func readDesktopEntry(path string) (Application, bool) { + f, err := os.Open(path) + if err != nil { + return Application{}, false + } + defer f.Close() + app := Application{File: path} + kind := "" + in := false + scan := bufio.NewScanner(f) + for scan.Scan() { + line := strings.TrimSpace(scan.Text()) + if strings.HasPrefix(line, "[") { + in = line == "[Desktop Entry]" + continue + } + if !in || line == "" || strings.HasPrefix(line, "#") { + continue + } + k, v, ok := strings.Cut(line, "=") + if !ok { + continue + } + k, v = strings.TrimSpace(k), strings.TrimSpace(v) + switch k { + case "Type": + kind = v + case "Name": + app.Name = v + case "GenericName": + app.GenericName = v + case "Comment": + app.Comment = v + case "Exec": + app.Exec = v + case "Keywords": + app.keywords = v + case "Terminal": + app.Terminal = v == "true" + case "Categories": + for _, c := range strings.Split(v, ";") { + if c != "" { + app.Categories = append(app.Categories, c) + } + } + case "NoDisplay", "Hidden": + app.Hidden = app.Hidden || v == "true" + } + } + if kind != "Application" || app.Name == "" { + return Application{}, false + } + return app, true +} + +// Theme is one launcher theme. +type Theme struct { + Name string `json:"name"` + File string `json:"file"` + Source string `json:"source"` +} + +// ThemesResult is what rofi_themes answers. +type ThemesResult struct { + Current string `json:"current"` + Themes []Theme `json:"themes"` +} + +type themeDir struct{ path, source string } + +func configFile() string { return filepath.Join(operatorHome(), ".config", "rofi", "config.rasi") } + +func themeDirs() []themeDir { + home := operatorHome() + return []themeDir{ + {filepath.Join(home, ".config", "rofi", "themes"), "the account's (the mesh places mesh and mesh-powermenu here)"}, + {filepath.Join(home, ".local", "share", "rofi", "themes"), "the account's"}, + {"/usr/share/rofi/themes", "the distribution's"}, + } +} + +var themeLine = regexp.MustCompile(`(?m)^\s*@theme\s+"([^"]+)"`) + +// Themes lists every .rasi theme, the first directory winning a name, and the configured one. +func Themes(dirs []themeDir, config string) ThemesResult { + out := ThemesResult{Themes: []Theme{}} + if raw, err := os.ReadFile(config); err == nil { + if m := themeLine.FindSubmatch(raw); m != nil { + out.Current = string(m[1]) + } + } + seen := map[string]bool{} + for _, d := range dirs { + entries, err := os.ReadDir(d.path) + if err != nil { + continue + } + for _, e := range entries { + name, ok := strings.CutSuffix(e.Name(), ".rasi") + if !ok || e.IsDir() || seen[name] { + continue + } + seen[name] = true + out.Themes = append(out.Themes, Theme{Name: name, File: filepath.Join(d.path, e.Name()), Source: d.source}) + } + } + sort.Slice(out.Themes, func(i, j int) bool { return out.Themes[i].Name < out.Themes[j].Name }) + return out +} + +// RunResult is what rofi_run answers. +type RunResult struct { + Unit string `json:"unit"` + Argv []string `json:"argv"` +} + +// Run starts an application or a command in the session under the account's service manager. +func Run(application string, command []string) (RunResult, error) { + if (application == "") == (len(command) == 0) { + return RunResult{}, errors.New("name an application or give a command, one of the two") + } + argv := command + if application != "" { + var app *Application + for _, a := range Applications(applicationDirs(), "", true, 1<<20).Applications { + if a.ID == application { + a := a + app = &a + break + } + } + if app == nil { + return RunResult{}, fmt.Errorf("no desktop entry %s on this machine", application) + } + var err error + if argv, err = execWords(app.Exec); err != nil { + return RunResult{}, fmt.Errorf("%s: %w", application, err) + } + if app.Terminal { + argv = append([]string{"rofi-sensible-terminal", "-e"}, argv...) + } + } + s, err := findSession() + if err != nil { + return RunResult{}, err + } + unit := uniqueUnit("rofi-run") + if err := s.detach(unit, argv...); err != nil { + return RunResult{}, err + } + return RunResult{Unit: unit + ".service", Argv: argv}, nil +} + +// execWords splits a desktop entry's Exec into words (its quoting rules), dropping the field codes a +// launcher fills with files or URLs, since none are given. +func execWords(exec string) ([]string, error) { + var words []string + var cur strings.Builder + inWord, quoted := false, false + for i := 0; i < len(exec); i++ { + c := exec[i] + switch { + case quoted && c == '\\' && i+1 < len(exec): + i++ + cur.WriteByte(exec[i]) + case c == '"': + quoted = !quoted + inWord = true + case !quoted && (c == ' ' || c == '\t'): + if inWord { + words = append(words, cur.String()) + cur.Reset() + inWord = false + } + default: + cur.WriteByte(c) + inWord = true + } + } + if quoted { + return nil, fmt.Errorf("unbalanced quote in Exec %q", exec) + } + if inWord { + words = append(words, cur.String()) + } + var out []string + for _, w := range words { + if len(w) == 2 && w[0] == '%' { + continue // %f %F %u %U %i %c %k %d %D %n %N %v %m + } + out = append(out, strings.ReplaceAll(w, "%%", "%")) + } + if len(out) == 0 { + return nil, fmt.Errorf("Exec %q names no program", exec) + } + return out, nil +} diff --git a/modules/rofi/cmd/rofi-tools/rofi_test.go b/modules/rofi/cmd/rofi-tools/rofi_test.go new file mode 100644 index 0000000..73d7d3f --- /dev/null +++ b/modules/rofi/cmd/rofi-tools/rofi_test.go @@ -0,0 +1,196 @@ +package main + +import ( + "errors" + "os" + "os/exec" + "path/filepath" + "reflect" + "strconv" + "strings" + "testing" +) + +const nobody = 4194400 + +func withSession(t *testing.T) string { + t.Helper() + root := fakeMachine(t) + fakeProcess(t, nobody, "i3", "DISPLAY=:1", "XDG_SESSION_ID=2") + return root +} + +func TestTheMenuAnswersTheChosenLineAndItsIndex(t *testing.T) { + withSession(t) + bin := fakeBinaries(t, map[string]string{"rofi": `echo "$* DISPLAY=$DISPLAY" > "$LOG"; cat > "$LOG.in"; echo "second"`}) + t.Setenv("LOG", filepath.Join(bin, "log")) + q, err := menuQuestion(map[string]any{"items": []any{"first", "second"}, "prompt": "Pick", "message": "why"}) + if err != nil { + t.Fatal(err) + } + got, err := Menu(q) + if err != nil || got.Chosen != "second" || got.Index != 1 || got.Cancelled || got.Custom { + t.Fatalf("%+v, %v", got, err) + } + asked, _ := os.ReadFile(filepath.Join(bin, "log")) + if strings.TrimSpace(string(asked)) != "-dmenu -i -p Pick -format s -mesg why -no-custom DISPLAY=:1" { + t.Fatalf("rofi was asked: %s", asked) + } + in, _ := os.ReadFile(filepath.Join(bin, "log.in")) + if string(in) != "first\nsecond\n" { + t.Fatalf("the choices, one per line: %q", in) + } +} + +func TestClosingTheMenuOrNotAnsweringIsACancelNotAnError(t *testing.T) { + withSession(t) + fakeBinaries(t, map[string]string{"rofi": `exit 1`}) + got, err := Menu(MenuQuestion{Items: []string{"a"}, Prompt: "p", Timeout: 5e9}) + if err != nil || !got.Cancelled || got.Index != -1 { + t.Fatalf("closed: %+v, %v", got, err) + } + fakeBinaries(t, map[string]string{"rofi": `sleep 30`}) + got, err = Menu(MenuQuestion{Items: []string{"a"}, Prompt: "p", Timeout: 2e8}) + if err != nil || !got.Cancelled || !got.TimedOut { + t.Fatalf("not answered: %+v, %v", got, err) + } + fakeBinaries(t, map[string]string{"rofi": `echo typed`}) + got, err = Menu(MenuQuestion{Items: []string{"a"}, Prompt: "p", AllowCustom: true, Timeout: 5e9}) + if err != nil || got.Chosen != "typed" || !got.Custom || got.Index != -1 { + t.Fatalf("typed: %+v, %v", got, err) + } +} + +func TestAMenuQuestionIsBoundedAndOneLinePerChoice(t *testing.T) { + for _, bad := range []map[string]any{ + {}, + {"items": []any{}}, + {"items": []any{"two\nlines"}}, + {"items": []any{"a"}, "timeout_seconds": float64(60)}, + {"items": []any{3.0}}, + } { + if _, err := menuQuestion(bad); err == nil { + t.Errorf("accepted %v", bad) + } + } + q, err := menuQuestion(map[string]any{"items": []any{"a"}}) + if err != nil || q.Prompt != "Choose" || q.Timeout.Seconds() != menuDefault { + t.Fatalf("defaults: %+v, %v", q, err) + } +} + +func TestWithoutASessionTheMenuSaysSo(t *testing.T) { + fakeMachine(t) + if _, err := Menu(MenuQuestion{Items: []string{"a"}, Timeout: 1e9}); !errors.Is(err, ErrNoSession) { + t.Fatal(err) + } +} + +func writeFile(t *testing.T, path, content string) { + t.Helper() + if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(path, []byte(content), 0o644); err != nil { + t.Fatal(err) + } +} + +func TestApplicationsAreTheDesktopEntriesTheAccountsWinning(t *testing.T) { + root := t.TempDir() + own, system := filepath.Join(root, "own"), filepath.Join(root, "system") + writeFile(t, filepath.Join(system, "firefox.desktop"), "[Desktop Entry]\nType=Application\nName=Firefox\nExec=firefox %u\nCategories=Network;WebBrowser;\n[Desktop Action new]\nName=New Window\nExec=firefox --new-window\n") + writeFile(t, filepath.Join(own, "firefox.desktop"), "[Desktop Entry]\nType=Application\nName=Firefox (mine)\nExec=firefox -P work %u\n") + writeFile(t, filepath.Join(system, "kde", "konsole.desktop"), "[Desktop Entry]\nType=Application\nName=Konsole\nExec=konsole\nTerminal=false\nKeywords=terminal;shell;\n") + writeFile(t, filepath.Join(system, "hidden.desktop"), "[Desktop Entry]\nType=Application\nName=Helper\nExec=helper\nNoDisplay=true\n") + writeFile(t, filepath.Join(system, "link.desktop"), "[Desktop Entry]\nType=Link\nName=A link\nURL=https://example.org\n") + got := Applications([]string{own, system}, "", false, 10) + var names []string + for _, a := range got.Applications { + names = append(names, a.ID+"="+a.Name) + } + if !reflect.DeepEqual(names, []string{"firefox.desktop=Firefox (mine)", "kde-konsole.desktop=Konsole"}) { + t.Fatalf("%v", names) + } + if got := Applications([]string{own, system}, "SHELL", false, 10); got.Count != 1 || got.Applications[0].Name != "Konsole" { + t.Fatalf("by keyword: %+v", got) + } + if got := Applications([]string{own, system}, "", true, 1); got.Count != 3 || !got.Truncated || len(got.Applications) != 1 { + t.Fatalf("hidden and limited: %+v", got) + } +} + +func TestThemesAreListedOnceWithTheConfiguredOne(t *testing.T) { + root := t.TempDir() + mine, system := filepath.Join(root, "mine"), filepath.Join(root, "system") + writeFile(t, filepath.Join(mine, "mesh.rasi"), "*{}") + writeFile(t, filepath.Join(system, "mesh.rasi"), "*{}") + writeFile(t, filepath.Join(system, "Arc.rasi"), "*{}") + conf, _ := os.ReadFile(filepath.Join("..", "..", "files", "config.rasi")) + writeFile(t, filepath.Join(root, "config.rasi"), string(conf)) + got := Themes([]themeDir{{mine, "mine"}, {system, "system"}}, filepath.Join(root, "config.rasi")) + if got.Current != "mesh" || len(got.Themes) != 2 || got.Themes[1].Source != "mine" { + t.Fatalf("%+v", got) + } +} + +func TestExecIsSplitAsTheDesktopEntrySpecQuotesIt(t *testing.T) { + for in, want := range map[string][]string{ + "firefox %u": {"firefox"}, + `sh -c "echo \"a b\"" %F`: {"sh", "-c", `echo "a b"`}, + "printf 100%% --flag": {"printf", "100%", "--flag"}, + `"/opt/My App/run" --x`: {"/opt/My App/run", "--x"}, + } { + got, err := execWords(in) + if err != nil || !reflect.DeepEqual(got, want) { + t.Errorf("%s: %q, %v", in, got, err) + } + } + for _, bad := range []string{`"open`, "%u"} { + if _, err := execWords(bad); err == nil { + t.Errorf("%s was accepted", bad) + } + } +} + +func TestRunStartsAnApplicationUnderTheAccountsServiceManager(t *testing.T) { + root := withSession(t) + writeFile(t, filepath.Join(root, "home", ".local", "share", "applications", "htop.desktop"), + "[Desktop Entry]\nType=Application\nName=htop\nExec=htop\nTerminal=true\n") + t.Setenv("XDG_DATA_DIRS", filepath.Join(root, "none")) + // The account's runtime directory, through which its service manager is reached. + if err := os.MkdirAll(filepath.Join(runUserDir, strconv.Itoa(os.Getuid())), 0o700); err != nil { + t.Fatal(err) + } + bin := fakeBinaries(t, map[string]string{"systemd-run": `echo "$*" > "$LOG"`, "systemctl": `true`}) + t.Setenv("LOG", filepath.Join(bin, "log")) + got, err := Run("htop.desktop", nil) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(got.Argv, []string{"rofi-sensible-terminal", "-e", "htop"}) || !strings.HasPrefix(got.Unit, "rofi-run-") { + t.Fatalf("%+v", got) + } + asked, _ := os.ReadFile(filepath.Join(bin, "log")) + if !strings.Contains(string(asked), "--setenv=DISPLAY=:1 --setenv=XDG_SESSION_ID=2 -- rofi-sensible-terminal -e htop") { + t.Fatalf("systemd-run was asked: %s", asked) + } + if _, err := Run("", nil); err == nil { + t.Fatal("nothing to run was accepted") + } + if _, err := Run("nope.desktop", nil); err == nil { + t.Fatal("a missing entry was accepted") + } +} + +func TestTheDmenuCommandHandsRofiWhatItUnderstands(t *testing.T) { + fakeBinaries(t, map[string]string{"rofi": `for a in "$@"; do printf '[%s]' "$a"; done`}) + shim, _ := filepath.Abs(filepath.Join("..", "..", "files", "bin", "dmenu")) + out, err := exec.Command(shim, "-b", "-fn", "Mono 10", "-l", "8", "-p", "pick one", "-nb", "#000", "-i").Output() + if err != nil { + t.Fatal(err) + } + if string(out) != "[-dmenu][-l][8][-p][pick one][-i]" { + t.Fatalf("rofi was handed %s", out) + } +} diff --git a/modules/rofi/cmd/rofi-tools/session.go b/modules/rofi/cmd/rofi-tools/session.go new file mode 100644 index 0000000..dc21774 --- /dev/null +++ b/modules/rofi/cmd/rofi-tools/session.go @@ -0,0 +1,423 @@ +// The operator's graphical session, as a tool the node's runtime runs finds it (novox/hq ADR 0208). +// +// The runtime is a system service running as the operator account (ADR 0175): it has the account's +// uid and none of the session's environment — no DISPLAY, no XAUTHORITY, no session bus. A tool that +// draws on the screen or talks to the desktop's D-Bus must find them. It reads them from a process of +// the account that is part of the session (the window manager first), the same thing `loginctl` and +// a person's own shell would point at, and says where it found them. +// +// Long-lived programs a tool starts go to the account's own service manager through `systemd-run +// --user`, never as children of the tool: the runtime's unit is a cgroup the service manager empties +// whenever the runtime restarts, and a compositor or a clipboard owner started from inside it would +// die with it. +// +// This file is the same in every desktop module that carries it; it moves into the Go SDK once a +// second consumer outside the desktop wants it. +package main + +import ( + "bytes" + "errors" + "fmt" + "os" + "os/exec" + "path/filepath" + "sort" + "strconv" + "strings" + "syscall" + "time" +) + +// Where the session is looked for. Variables so a test can point them at a fake tree. +var ( + procRoot = "/proc" + runUserDir = "/run/user" + x11Sockets = "/tmp/.X11-unix" +) + +// sessionHolders are the processes whose environment is the session's, best first: the window +// manager is the session, the rest are its children. Anything else carrying DISPLAY ranks after them. +var sessionHolders = []string{"i3", "sway", "i3bar", "picom", "xss-lock", "dunst", "clipmenud", "xterm"} + +// sessionKeys are the variables a session carries that a tool hands on to what it runs. +var sessionKeys = []string{"DISPLAY", "XAUTHORITY", "WAYLAND_DISPLAY", "DBUS_SESSION_BUS_ADDRESS", + "XDG_RUNTIME_DIR", "XDG_SESSION_ID", "I3SOCK"} + +// Session is what a tool needs to reach the operator's desktop. +type Session struct { + UID int `json:"uid"` + Display string `json:"display,omitempty"` + XAuthority string `json:"xauthority,omitempty"` + Wayland string `json:"wayland_display,omitempty"` + Bus string `json:"bus,omitempty"` + RuntimeDir string `json:"runtime_dir,omitempty"` + SessionID string `json:"session_id,omitempty"` + I3Sock string `json:"i3sock,omitempty"` + // From says where the values were found: the tool's own environment, a process, or the socket. + From string `json:"from"` +} + +// ErrNoSession is answered by a tool that needs the desktop when nobody is logged in to it. +var ErrNoSession = errors.New("no graphical session") + +// ErrTimedOut is what run answers for a command ended because it ran past its time. +var ErrTimedOut = errors.New("timed out") + +// ErrNoBus is answered by a tool that needs the session bus when the account has none. +var ErrNoBus = errors.New("no session bus") + +// operatorHome is the account's home: what the runtime was told, else the process's own. +func operatorHome() string { + if h := strings.TrimSpace(os.Getenv("MESH_OPERATOR_HOME")); h != "" { + return h + } + h, _ := os.UserHomeDir() + return h +} + +// findSession finds the graphical session of the account this tool runs as, or answers +// ErrNoSession with what it looked at. +func findSession() (Session, error) { + s := findEnvironment() + if s.Display == "" && s.Wayland == "" { + return s, fmt.Errorf("%w for uid %d on this machine: no process of the account carries DISPLAY "+ + "or WAYLAND_DISPLAY, and no X server socket in %s has an authority file to go with it. "+ + "Is anyone logged in to the desktop?", ErrNoSession, s.UID, x11Sockets) + } + return s, nil +} + +// findBus finds the account's session bus, which a logged-in account has whether or not a desktop +// is running. +func findBus() (Session, error) { + s := findEnvironment() + if s.Bus == "" { + return s, fmt.Errorf("%w for uid %d: DBUS_SESSION_BUS_ADDRESS is not set and %s does not exist "+ + "(the account is not logged in)", ErrNoBus, s.UID, filepath.Join(runUserDir, strconv.Itoa(s.UID), "bus")) + } + return s, nil +} + +func findEnvironment() Session { + uid := os.Getuid() + s := Session{UID: uid} + own := map[string]string{} + for _, k := range sessionKeys { + own[k] = os.Getenv(k) + } + if own["DISPLAY"] != "" || own["WAYLAND_DISPLAY"] != "" { + s.fill(own) + s.From = "the tool's own environment" + } else if pid, comm, env, ok := sessionProcess(uid); ok { + s.fill(env) + s.From = fmt.Sprintf("process %s (pid %d)", comm, pid) + } else if display, ok := lonelyX11Socket(); ok { + if a := filepath.Join(operatorHome(), ".Xauthority"); exists(a) { + s.Display, s.XAuthority = display, a + s.From = "the X server socket and the account's ~/.Xauthority" + } + s.fill(own) + } else { + s.fill(own) + s.From = "nothing: no session found" + } + // The bus and the runtime directory are the account's, whether or not the process named them. + runtime := filepath.Join(runUserDir, strconv.Itoa(uid)) + if s.RuntimeDir == "" && exists(runtime) { + s.RuntimeDir = runtime + } + if s.Bus == "" && s.RuntimeDir != "" && exists(filepath.Join(s.RuntimeDir, "bus")) { + s.Bus = "unix:path=" + filepath.Join(s.RuntimeDir, "bus") + } + return s +} + +func (s *Session) fill(env map[string]string) { + set := func(dst *string, key string) { + if *dst == "" { + *dst = env[key] + } + } + set(&s.Display, "DISPLAY") + set(&s.XAuthority, "XAUTHORITY") + set(&s.Wayland, "WAYLAND_DISPLAY") + set(&s.Bus, "DBUS_SESSION_BUS_ADDRESS") + set(&s.RuntimeDir, "XDG_RUNTIME_DIR") + set(&s.SessionID, "XDG_SESSION_ID") + set(&s.I3Sock, "I3SOCK") +} + +// sessionProcess is the best process of this uid whose environment names a display. +func sessionProcess(uid int) (int, string, map[string]string, bool) { + entries, err := os.ReadDir(procRoot) + if err != nil { + return 0, "", nil, false + } + type candidate struct { + pid int + comm string + env map[string]string + rank int + } + var found []candidate + for _, e := range entries { + pid, err := strconv.Atoi(e.Name()) + if err != nil { + continue + } + dir := filepath.Join(procRoot, e.Name()) + if owner, ok := ownerOf(dir); !ok || owner != uid { + continue + } + raw, err := os.ReadFile(filepath.Join(dir, "environ")) + if err != nil { + continue + } + env := parseEnviron(raw) + if env["DISPLAY"] == "" && env["WAYLAND_DISPLAY"] == "" { + continue + } + comm := readTrimmed(filepath.Join(dir, "comm")) + rank := len(sessionHolders) + for i, h := range sessionHolders { + if h == comm { + rank = i + break + } + } + found = append(found, candidate{pid, comm, env, rank}) + } + if len(found) == 0 { + return 0, "", nil, false + } + sort.Slice(found, func(i, j int) bool { + if found[i].rank != found[j].rank { + return found[i].rank < found[j].rank + } + return found[i].pid > found[j].pid // the newer of two equals + }) + best := found[0] + return best.pid, best.comm, best.env, true +} + +func parseEnviron(raw []byte) map[string]string { + env := map[string]string{} + for _, kv := range bytes.Split(raw, []byte{0}) { + if i := bytes.IndexByte(kv, '='); i > 0 { + env[string(kv[:i])] = string(kv[i+1:]) + } + } + return env +} + +func ownerOf(path string) (int, bool) { + info, err := os.Stat(path) + if err != nil { + return 0, false + } + st, ok := info.Sys().(*syscall.Stat_t) + if !ok { + return 0, false + } + return int(st.Uid), true +} + +// lonelyX11Socket is the display of the one X server socket there is, when there is exactly one. +func lonelyX11Socket() (string, bool) { + entries, err := os.ReadDir(x11Sockets) + if err != nil { + return "", false + } + var displays []string + for _, e := range entries { + if n := strings.TrimPrefix(e.Name(), "X"); n != e.Name() { + if _, err := strconv.Atoi(n); err == nil { + displays = append(displays, ":"+n) + } + } + } + if len(displays) != 1 { + return "", false + } + return displays[0], true +} + +func readTrimmed(path string) string { + b, err := os.ReadFile(path) + if err != nil { + return "" + } + return strings.TrimSpace(string(b)) +} + +func exists(path string) bool { + _, err := os.Stat(path) + return err == nil +} + +// Env is this process's environment with the session's variables in place of its own. +func (s Session) Env() []string { + drop := map[string]bool{} + for _, k := range sessionKeys { + drop[k] = true + } + var env []string + for _, kv := range os.Environ() { + if i := strings.IndexByte(kv, '='); i > 0 && drop[kv[:i]] { + continue + } + env = append(env, kv) + } + add := func(k, v string) { + if v != "" { + env = append(env, k+"="+v) + } + } + add("DISPLAY", s.Display) + add("XAUTHORITY", s.XAuthority) + add("WAYLAND_DISPLAY", s.Wayland) + add("DBUS_SESSION_BUS_ADDRESS", s.Bus) + add("XDG_RUNTIME_DIR", s.RuntimeDir) + add("XDG_SESSION_ID", s.SessionID) + add("I3SOCK", s.I3Sock) + return env +} + +// mostOutput bounds what a command may answer with, per stream. +const mostOutput = 256 << 10 + +// Result is what a command did. +type Result struct { + Stdout string `json:"stdout"` + Stderr string `json:"stderr,omitempty"` + Code int `json:"code"` + Truncated bool `json:"truncated,omitempty"` +} + +// run runs a command in the session's environment, its input given, ended with everything it +// started after timeout. A command that is not installed is an error naming it; one that exits +// non-zero is a Result with its code, for the caller to judge. +func (s Session) run(timeout time.Duration, stdin string, name string, args ...string) (Result, error) { + path, err := exec.LookPath(name) + if err != nil { + return Result{}, fmt.Errorf("%s is not installed on this machine", name) + } + cmd := exec.Command(path, args...) + cmd.Env = s.Env() + if home := operatorHome(); exists(home) { + cmd.Dir = home + } + if stdin != "" { + cmd.Stdin = strings.NewReader(stdin) + } + var out, errOut capped + cmd.Stdout, cmd.Stderr = &out, &errOut + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + if err := cmd.Start(); err != nil { + return Result{}, fmt.Errorf("%s: %w", name, err) + } + done := make(chan error, 1) + go func() { done <- cmd.Wait() }() + select { + case err = <-done: + case <-time.After(timeout): + _ = syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) + <-done + return Result{Stdout: out.String(), Stderr: errOut.String()}, + fmt.Errorf("%s did not finish within %s and was ended: %w", name, timeout, ErrTimedOut) + } + r := Result{Stdout: out.String(), Stderr: errOut.String(), Truncated: out.cut || errOut.cut} + var exit *exec.ExitError + if errors.As(err, &exit) { + r.Code = exit.ExitCode() + } else if err != nil { + return r, fmt.Errorf("%s: %w", name, err) + } + return r, nil +} + +// detach starts a long-lived program under the account's own service manager, as a transient unit +// that carries the session's display, so it outlives the runtime that asked for it. A unit already +// running under the same name is stopped first, so a fixed name means "at most one". +func (s Session) detach(unit string, args ...string) error { + if s.RuntimeDir == "" { + return fmt.Errorf("%w: the account's runtime directory is missing, so its service manager "+ + "cannot be reached", ErrNoBus) + } + _, _ = s.run(5*time.Second, "", "systemctl", "--user", "stop", unit+".service") + call := []string{"--user", "--collect", "--quiet", "--unit=" + unit} + for _, kv := range [][2]string{{"DISPLAY", s.Display}, {"XAUTHORITY", s.XAuthority}, + {"WAYLAND_DISPLAY", s.Wayland}, {"XDG_SESSION_ID", s.SessionID}, {"I3SOCK", s.I3Sock}} { + if kv[1] != "" { + call = append(call, "--setenv="+kv[0]+"="+kv[1]) + } + } + call = append(call, "--") + call = append(call, args...) + r, err := s.run(10*time.Second, "", "systemd-run", call...) + if err != nil { + return err + } + if r.Code != 0 { + return fmt.Errorf("systemd-run %s: %s", unit, strings.TrimSpace(r.Stderr)) + } + return nil +} + +// uniqueUnit is a transient unit name that will not collide with an earlier one. +func uniqueUnit(prefix string) string { + return fmt.Sprintf("%s-%d", prefix, time.Now().UnixNano()) +} + +type capped struct { + bytes.Buffer + cut bool +} + +func (c *capped) Write(p []byte) (int, error) { + if room := mostOutput - c.Len(); room < len(p) { + if room > 0 { + c.Buffer.Write(p[:room]) + } + c.cut = true + return len(p), nil + } + return c.Buffer.Write(p) +} + +// processesOf are the pids of this uid's processes whose command name is comm, oldest first. +func processesOf(comm string) []int { + entries, err := os.ReadDir(procRoot) + if err != nil { + return nil + } + uid := os.Getuid() + var pids []int + for _, e := range entries { + pid, err := strconv.Atoi(e.Name()) + if err != nil { + continue + } + dir := filepath.Join(procRoot, e.Name()) + if owner, ok := ownerOf(dir); !ok || owner != uid { + continue + } + if readTrimmed(filepath.Join(dir, "comm")) == comm { + pids = append(pids, pid) + } + } + sort.Ints(pids) + return pids +} + +// signalAll sends sig to every process of this uid named comm, and answers the pids it reached. +func signalAll(comm string, sig syscall.Signal) []int { + var reached []int + for _, pid := range processesOf(comm) { + if syscall.Kill(pid, sig) == nil { + reached = append(reached, pid) + } + } + return reached +} diff --git a/modules/rofi/cmd/rofi-tools/session_test.go b/modules/rofi/cmd/rofi-tools/session_test.go new file mode 100644 index 0000000..800cc6d --- /dev/null +++ b/modules/rofi/cmd/rofi-tools/session_test.go @@ -0,0 +1,174 @@ +package main + +import ( + "errors" + "os" + "path/filepath" + "strconv" + "strings" + "testing" + "time" +) + +// fakeMachine points the session finder at a temporary /proc, /run/user and X socket directory, with +// none of the test process's own session variables, and gives back the root. +func fakeMachine(t *testing.T) string { + t.Helper() + root := t.TempDir() + procRoot, runUserDir, x11Sockets = filepath.Join(root, "proc"), filepath.Join(root, "run-user"), filepath.Join(root, "x11") + for _, d := range []string{procRoot, runUserDir, x11Sockets} { + if err := os.MkdirAll(d, 0o755); err != nil { + t.Fatal(err) + } + } + for _, k := range sessionKeys { + t.Setenv(k, "") + } + t.Setenv("MESH_OPERATOR_HOME", filepath.Join(root, "home")) + t.Cleanup(func() { procRoot, runUserDir, x11Sockets = "/proc", "/run/user", "/tmp/.X11-unix" }) + return root +} + +func fakeProcess(t *testing.T, pid int, comm string, env ...string) { + t.Helper() + dir := filepath.Join(procRoot, strconv.Itoa(pid)) + if err := os.MkdirAll(dir, 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, "comm"), []byte(comm+"\n"), 0o644); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, "environ"), []byte(strings.Join(env, "\x00")+"\x00"), 0o600); err != nil { + t.Fatal(err) + } +} + +func TestTheSessionIsReadFromTheWindowManagerBeforeAnyOtherProcess(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 900, "xterm", "DISPLAY=:9", "XAUTHORITY=/elsewhere") + fakeProcess(t, 100, "i3", "DISPLAY=:1", "XAUTHORITY=/home/op/.Xauthority", + "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus", "XDG_SESSION_ID=3", "SECRET_TOKEN=never-copied") + fakeProcess(t, 50, "bash", "PATH=/usr/bin") + s, err := findSession() + if err != nil { + t.Fatal(err) + } + if s.Display != ":1" || s.XAuthority != "/home/op/.Xauthority" || s.SessionID != "3" || !strings.Contains(s.From, "i3 (pid 100)") { + t.Fatalf("the window manager's environment: %+v", s) + } + for _, kv := range s.Env() { + if strings.HasPrefix(kv, "SECRET_TOKEN=") { + t.Fatal("a variable of the session process that is not a session variable was handed on") + } + } +} + +func TestAnyProcessCarryingADisplayServesWhenTheWindowManagerIsNotFound(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 10, "firefox", "DISPLAY=:0") + fakeProcess(t, 20, "firefox", "DISPLAY=:2") + s, err := findSession() + if err != nil || s.Display != ":2" { + t.Fatalf("the newest of two equals: %+v, %v", s, err) + } +} + +func TestNoSessionIsAClearAnswerNotAGuess(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 10, "sshd", "PATH=/usr/bin") + _, err := findSession() + if !errors.Is(err, ErrNoSession) || !strings.Contains(err.Error(), "logged in to the desktop") { + t.Fatalf("no session: %v", err) + } +} + +func TestOneXSocketAndTheAccountsAuthorityFileAreASession(t *testing.T) { + root := fakeMachine(t) + if err := os.WriteFile(filepath.Join(x11Sockets, "X0"), nil, 0o644); err != nil { + t.Fatal(err) + } + if err := os.MkdirAll(filepath.Join(root, "home"), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(root, "home", ".Xauthority"), nil, 0o600); err != nil { + t.Fatal(err) + } + s, err := findSession() + if err != nil || s.Display != ":0" || !strings.HasSuffix(s.XAuthority, "/home/.Xauthority") { + t.Fatalf("socket and authority: %+v, %v", s, err) + } +} + +func TestTheBusIsTheAccountsRuntimeDirectoryWhenNoProcessNamesIt(t *testing.T) { + fakeMachine(t) + runtime := filepath.Join(runUserDir, strconv.Itoa(os.Getuid())) + if _, err := findBus(); !errors.Is(err, ErrNoBus) { + t.Fatalf("no runtime directory is no bus: %v", err) + } + if err := os.MkdirAll(runtime, 0o700); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(runtime, "bus"), nil, 0o600); err != nil { + t.Fatal(err) + } + s, err := findBus() + if err != nil || s.Bus != "unix:path="+filepath.Join(runtime, "bus") || s.RuntimeDir != runtime { + t.Fatalf("bus: %+v, %v", s, err) + } + env := strings.Join(s.Env(), "\n") + if !strings.Contains(env, "XDG_RUNTIME_DIR="+runtime) || !strings.Contains(env, "DBUS_SESSION_BUS_ADDRESS=unix:path=") { + t.Fatalf("the bus is handed on: %s", env) + } +} + +func TestACommandIsBoundedAndANonZeroExitIsAResult(t *testing.T) { + fakeMachine(t) + s := Session{} + r, err := s.run(5*time.Second, "in", "sh", "-c", "cat; echo err >&2; exit 3") + if err != nil || r.Stdout != "in" || r.Code != 3 || strings.TrimSpace(r.Stderr) != "err" { + t.Fatalf("result: %+v, %v", r, err) + } + start := time.Now() + if _, err := s.run(200*time.Millisecond, "", "sh", "-c", "sleep 30 & sleep 30"); err == nil || time.Since(start) > 5*time.Second { + t.Fatalf("a command past its time is ended with what it started: %v after %s", err, time.Since(start)) + } + if _, err := s.run(time.Second, "", "no-such-program-here"); err == nil || !strings.Contains(err.Error(), "not installed") { + t.Fatalf("a missing program: %v", err) + } +} + +func TestDetachAsksTheAccountsServiceManagerWithTheSessionsDisplay(t *testing.T) { + fakeMachine(t) + bin := fakeBinaries(t, map[string]string{ + "systemctl": `echo "systemctl $*" >> "$LOG"`, + "systemd-run": `echo "systemd-run $*" >> "$LOG"`, + }) + log := filepath.Join(bin, "log") + t.Setenv("LOG", log) + s := Session{Display: ":1", XAuthority: "/x", RuntimeDir: "/run/user/1"} + if err := s.detach("picom-session", "picom", "--config", "/c"); err != nil { + t.Fatal(err) + } + got, _ := os.ReadFile(log) + want := "systemctl --user stop picom-session.service\n" + + "systemd-run --user --collect --quiet --unit=picom-session --setenv=DISPLAY=:1 --setenv=XAUTHORITY=/x -- picom --config /c\n" + if string(got) != want { + t.Fatalf("detach ran:\n%s\nwant:\n%s", got, want) + } + if err := (Session{}).detach("x", "y"); !errors.Is(err, ErrNoBus) { + t.Fatalf("no runtime directory: %v", err) + } +} + +// fakeBinaries puts shell scripts named for programs first on PATH, and answers their directory. +func fakeBinaries(t *testing.T, scripts map[string]string) string { + t.Helper() + dir := t.TempDir() + for name, body := range scripts { + if err := os.WriteFile(filepath.Join(dir, name), []byte("#!/bin/sh\n"+body+"\n"), 0o755); err != nil { + t.Fatal(err) + } + } + t.Setenv("PATH", dir+string(os.PathListSeparator)+os.Getenv("PATH")) + return dir +} diff --git a/modules/rofi/files/bin/dmenu b/modules/rofi/files/bin/dmenu new file mode 100755 index 0000000..b7460e9 --- /dev/null +++ b/modules/rofi/files/bin/dmenu @@ -0,0 +1,26 @@ +#!/bin/sh +# dmenu, as this node's launcher answers it (module rofi, novox/hq ADR 0208). The node-launcher +# seat's dmenu-compatible command: choices on standard input, the chosen one on standard output, +# exit 1 when nothing was chosen. A script calls `dmenu` and works whichever module holds the seat. +# +# rofi understands dmenu's -p, -l and -i. dmenu's look options (-fn, -nb, -nf, -sb, -sf, -m, -w) +# take a value rofi would misread, so they are dropped with it; -b and -f are dropped alone. The +# look is the launcher's theme. +set -u +n=$# +while [ "$n" -gt 0 ]; do + arg=$1 + shift + n=$((n - 1)) + case $arg in + -fn | -nb | -nf | -sb | -sf | -m | -w) + if [ "$n" -gt 0 ]; then + shift + n=$((n - 1)) + fi + ;; + -b | -f) ;; + *) set -- "$@" "$arg" ;; + esac +done +exec rofi -dmenu "$@" diff --git a/modules/rofi/files/bin/rofi-launch b/modules/rofi/files/bin/rofi-launch new file mode 100755 index 0000000..788f23c --- /dev/null +++ b/modules/rofi/files/bin/rofi-launch @@ -0,0 +1,39 @@ +#!/bin/sh +# rofi-launch drun|run|window|filebrowser|sudo (module rofi, novox/hq ADR 0208): what the launcher's +# key bindings run. +# +# After a resume the keyboard grab can fail for a moment, and rofi then exits at once: a key press +# that opens nothing. So a failure within half a second is tried again, up to five times. A person +# closing the menu takes longer than that, and is never shown it a second time. +set -u +mode=${1:-drun} + +now_ms() { date +%s%3N; } + +attempt() { + i=0 + while [ "$i" -lt 5 ]; do + start=$(now_ms) + "$@" && return 0 + [ $(($(now_ms) - start)) -ge 500 ] && return 1 + i=$((i + 1)) + sleep 0.1 + done + return 1 +} + +case $mode in +drun | run | window | filebrowser) + attempt rofi -show "$mode" + ;; +sudo) + # A command line, run with sudo in the node's terminal. + command=$(attempt rofi -dmenu -p sudo &2 + exit 2 + ;; +esac diff --git a/modules/rofi/files/bin/rofi-powermenu b/modules/rofi/files/bin/rofi-powermenu new file mode 100755 index 0000000..2bdf64c --- /dev/null +++ b/modules/rofi/files/bin/rofi-powermenu @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# rofi-powermenu (module rofi, novox/hq ADR 0208): lock, suspend, log out, reboot, shut down. +# +# It belongs to the session, and it is the launcher's: its whole face is rofi's. Every action is a +# verb of logind or the service manager, so nothing here names a window manager or a locker: +# - lock asks logind to lock the session, which the holder of node-lock-screen answers; +# - log out ends this login session, whichever window manager runs in it. +# Adopted from the workstations' power menu of 2026-10-04 (after adi1090x's powermenu type-2). +set -u + +theme=mesh-powermenu +uptime="$(uptime -p | sed -e 's/^up //')" + +shutdown='󰤂' +reboot='󰜉' +lock='󰌾' +suspend='󰤄' +logout='󰍃' +yes='󰄲' +no='󰅖' + +menu() { + rofi -dmenu -p "Uptime: $uptime" -mesg "Uptime: $uptime" -theme "$theme" +} + +confirm() { + printf '%s\n%s\n' "$yes" "$no" | rofi -dmenu -p 'Confirmation' -mesg 'Are you sure?' -theme "$theme" \ + -theme-str 'window {location: center; anchor: center; fullscreen: false; width: 350px;}' \ + -theme-str 'mainbox {children: [ "message", "listview" ];}' \ + -theme-str 'listview {columns: 2; lines: 1;}' \ + -theme-str 'element-text {horizontal-align: 0.5;}' \ + -theme-str 'textbox {horizontal-align: 0.5;}' +} + +session() { + # The login session this menu runs in: the session's own id, else logind's answer for this process. + if [ -n "${XDG_SESSION_ID:-}" ]; then + echo "$XDG_SESSION_ID" + else + loginctl show-session auto -p Id --value 2>/dev/null + fi +} + +confirmed() { [ "$(confirm)" = "$yes" ]; } + +chosen="$(printf '%s\n' "$lock" "$suspend" "$logout" "$reboot" "$shutdown" | menu)" || exit 0 +case $chosen in +"$lock") loginctl lock-session "$(session)" ;; +"$suspend") confirmed && systemctl suspend ;; +"$logout") confirmed && loginctl terminate-session "$(session)" ;; +"$reboot") confirmed && systemctl reboot ;; +"$shutdown") confirmed && systemctl poweroff ;; +esac +exit 0 diff --git a/modules/rofi/files/config.rasi b/modules/rofi/files/config.rasi new file mode 100644 index 0000000..d123371 --- /dev/null +++ b/modules/rofi/files/config.rasi @@ -0,0 +1,54 @@ +/* rofi, the launcher (module rofi, novox/hq ADR 0208). Owned by the mesh: this file is replaced at + * every push. Adopted from the two workstations' file of 2026-10-04: the settings that differ from + * rofi's defaults, nothing else. Its look is the theme "mesh", in themes/ beside this file. */ + +configuration { + modi: "drun,run,window,filebrowser"; + show-icons: true; + case-sensitive: false; + normalize-match: true; + matching: "normal"; + tokenize: true; + cycle: true; + steal-focus: false; + click-to-exit: true; + sort: false; + + /* Applications: the user's and the system's desktop entries, read fresh each time so a + * program installed a minute ago is there. */ + drun-match-fields: "name,generic,exec,categories,keywords"; + drun-display-format: "{name} [({generic})]"; + drun-show-actions: false; + drun-url-launcher: "xdg-open"; + drun-use-desktop-cache: false; + drun-reload-desktop-cache: false; + run,drun { + fallback-icon: "application-x-addon"; + } + + /* A command run from `run` opens in the node's terminal when it asks for one. */ + terminal: "rofi-sensible-terminal"; + run-shell-command: "{terminal} -e {cmd}"; + ssh-command: "{terminal} -e {ssh-client} {host} [-p {port}]"; + parse-hosts: true; + parse-known-hosts: true; + + window-match-fields: "title,class,role,name,desktop"; + window-format: "{w} - {c} - {t:0}"; + + disable-history: false; + max-history-size: 25; + + filebrowser { + directories-first: true; + sorting-method: "name"; + } + + display-window: "Windows"; + display-run: "Run"; + display-ssh: "SSH"; + display-drun: "Apps"; + display-filebrowser: "Files"; +} + +@theme "mesh" diff --git a/modules/rofi/files/i3/50-rofi.conf b/modules/rofi/files/i3/50-rofi.conf new file mode 100644 index 0000000..1395d2c --- /dev/null +++ b/modules/rofi/files/i3/50-rofi.conf @@ -0,0 +1,8 @@ +# The launcher's key bindings (module rofi, novox/hq ADR 0208). Owned by the mesh: replaced at every +# push. i3 reads this file through its configuration's `include ~/.config/i3/config.d/*.conf`, after +# the variables it sets, so $mod is i3's. +bindsym $mod+d exec --no-startup-id ~/.local/bin/rofi-launch drun +bindsym $mod+t exec --no-startup-id ~/.local/bin/rofi-launch run +bindsym $mod+Shift+t exec --no-startup-id ~/.local/bin/rofi-launch sudo +bindsym $mod+Shift+w exec --no-startup-id ~/.local/bin/rofi-launch window +bindsym $mod+Escape exec --no-startup-id ~/.local/bin/rofi-powermenu diff --git a/modules/rofi/files/themes/mesh-powermenu.rasi b/modules/rofi/files/themes/mesh-powermenu.rasi new file mode 100644 index 0000000..5b837f4 --- /dev/null +++ b/modules/rofi/files/themes/mesh-powermenu.rasi @@ -0,0 +1,172 @@ +/** + * The theme "mesh-powermenu" (module rofi, novox/hq ADR 0208): the power menu's five buttons. + * Owned by the mesh; replaced at every push. Adopted from the workstations' power menu theme of + * 2026-10-04 (after adi1090x's powermenu type-2, style-1), its colours inlined. + **/ + +/*****----- Configuration -----*****/ +configuration { + show-icons: false; +} + +/*****----- Global Properties -----*****/ +* { + background: #000000FF; + background-alt: #282B31FF; + foreground: #FFFFFFFF; + selected: #DE5200FF; + active: #DE5200FF; + urgent: #CC0000FF; + + font: "JetBrainsMono Nerd Font 11"; +} + + +/*****----- Main Window -----*****/ +window { + /* properties for window widget */ + transparency: "real"; + location: center; + anchor: center; + fullscreen: false; + width: 800px; + x-offset: 0px; + y-offset: 0px; + + /* properties for all widgets */ + enabled: true; + margin: 0px; + padding: 0px; + border: 0px solid; + border-radius: 0px; + border-color: @selected; + cursor: "default"; + background-color: @background; +} + +/*****----- Main Box -----*****/ +mainbox { + enabled: true; + spacing: 15px; + margin: 0px; + padding: 30px; + border: 0px solid; + border-radius: 0px; + border-color: @selected; + background-color: transparent; + children: [ "inputbar", "listview" ]; +} + +/*****----- Inputbar -----*****/ +inputbar { + enabled: true; + spacing: 15px; + margin: 0px; + padding: 0px; + border: 0px; + border-radius: 0px; + border-color: @selected; + background-color: transparent; + text-color: @foreground; + children: [ "textbox-prompt-colon", "prompt"]; +} + +dummy { + background-color: transparent; +} + +textbox-prompt-colon { + enabled: true; + expand: false; + str: ""; + padding: 12px 16px; + border-radius: 0px; + background-color: @urgent; + text-color: @background; +} +prompt { + enabled: true; + padding: 12px; + border-radius: 0px; + background-color: @active; + text-color: @background; +} + +/*****----- Message -----*****/ +message { + enabled: true; + margin: 0px; + padding: 12px; + border: 0px solid; + border-radius: 0px; + border-color: @selected; + background-color: @background-alt; + text-color: @foreground; +} +textbox { + background-color: inherit; + text-color: inherit; + vertical-align: 0.5; + horizontal-align: 0.5; + placeholder-color: @foreground; + blink: true; + markup: true; +} +error-message { + padding: 12px; + border: 0px solid; + border-radius: 0px; + border-color: @selected; + background-color: @background; + text-color: @foreground; +} + +/*****----- Listview -----*****/ +listview { + enabled: true; + columns: 5; + lines: 1; + cycle: true; + dynamic: true; + scrollbar: false; + layout: vertical; + reverse: false; + fixed-height: true; + fixed-columns: true; + + spacing: 15px; + margin: 0px; + padding: 0px; + border: 0px solid; + border-radius: 0px; + border-color: @selected; + background-color: transparent; + text-color: @foreground; + cursor: "default"; +} + +/*****----- Elements -----*****/ +element { + enabled: true; + spacing: 0px; + margin: 0px; + padding: 40px 10px; + border: 0px solid; + border-radius: 0px; + border-color: @selected; + background-color: @background-alt; + text-color: @foreground; + cursor: pointer; +} +element-text { + font: "JetBrainsMono Nerd Font Bold 32"; + background-color: transparent; + text-color: inherit; + cursor: inherit; + vertical-align: 0.5; + horizontal-align: 0.5; +} +element selected.normal { + background-color: var(selected); + text-color: var(background); +} diff --git a/modules/rofi/files/themes/mesh.rasi b/modules/rofi/files/themes/mesh.rasi new file mode 100644 index 0000000..8be0f55 --- /dev/null +++ b/modules/rofi/files/themes/mesh.rasi @@ -0,0 +1,263 @@ +/** + * The theme "mesh" (module rofi, novox/hq ADR 0208): every rofi window unless a caller names + * another. Owned by the mesh; replaced at every push. Adopted from the workstations' theme of + * 2026-10-04 (after adi1090x's launcher type-4, style-1), its colour file inlined so the theme is + * one file, and its face the monospace one every desktop module names. + **/ + +/*****----- Global Properties -----*****/ +* { + background: #000000FF; + background-alt: #282B31FF; + foreground: #FFFFFFFF; + selected: #DE5200FF; + active: #DE5200FF; + urgent: #CC0000FF; + + font: "JetBrainsMono Nerd Font 11"; + + border-colour: var(selected); + handle-colour: var(selected); + background-colour: var(background); + foreground-colour: var(foreground); + alternate-background: var(background-alt); + normal-background: var(background); + normal-foreground: var(foreground); + urgent-background: var(urgent); + urgent-foreground: var(background); + active-background: var(active); + active-foreground: var(background); + selected-normal-background: var(selected); + selected-normal-foreground: var(background); + selected-urgent-background: var(active); + selected-urgent-foreground: var(background); + selected-active-background: var(urgent); + selected-active-foreground: var(background); + alternate-normal-background: var(background); + alternate-normal-foreground: var(foreground); + alternate-urgent-background: var(urgent); + alternate-urgent-foreground: var(background); + alternate-active-background: var(active); + alternate-active-foreground: var(background); +} + +/*****----- Main Window -----*****/ +window { + transparency: "real"; + location: center; + anchor: center; + fullscreen: false; + width: 600px; + x-offset: 0px; + y-offset: 0px; + enabled: true; + margin: 0px; + padding: 0px; + border: 1px solid; + border-radius: 0px; + border-color: @border-colour; + cursor: "default"; + background-color: @background-colour; +} + +/*****----- Main Box -----*****/ +mainbox { + enabled: true; + spacing: 10px; + margin: 0px; + padding: 10px; + border: 0px solid; + border-radius: 0px; + border-color: @border-colour; + background-color: transparent; + children: [ "inputbar", "message", "listview", "mode-switcher" ]; +} + +/*****----- Inputbar -----*****/ +inputbar { + enabled: true; + spacing: 10px; + margin: 0px; + padding: 10px; + border: 0px 0px 1px 0px; + border-radius: 0px; + border-color: @border-colour; + background-color: @alternate-background; + text-color: @foreground-colour; + children: [ "prompt", "entry" ]; +} + +prompt { + enabled: true; + background-color: inherit; + text-color: inherit; +} +textbox-prompt-colon { + enabled: true; + expand: false; + str: "::"; + background-color: inherit; + text-color: inherit; +} +entry { + enabled: true; + background-color: inherit; + text-color: inherit; + cursor: text; + placeholder: "Search..."; + placeholder-color: inherit; +} + +/*****----- Listview -----*****/ +listview { + enabled: true; + columns: 1; + lines: 8; + cycle: true; + dynamic: true; + scrollbar: false; + layout: vertical; + reverse: false; + fixed-height: true; + fixed-columns: true; + spacing: 0px; + margin: 0px; + padding: 0px; + border: 0px solid; + border-radius: 0px; + border-color: @border-colour; + background-color: transparent; + text-color: @foreground-colour; + cursor: "default"; +} +scrollbar { + handle-width: 5px; + handle-color: @handle-colour; + border-radius: 0px; + background-color: @alternate-background; +} + +/*****----- Elements -----*****/ +element { + enabled: true; + spacing: 10px; + margin: 0px; + padding: 10px; + border: 0px solid; + border-radius: 0px; + border-color: @border-colour; + background-color: transparent; + text-color: @foreground-colour; + cursor: pointer; +} +element normal.normal { + background-color: var(normal-background); + text-color: var(normal-foreground); +} +element normal.urgent { + background-color: var(urgent-background); + text-color: var(urgent-foreground); +} +element normal.active { + background-color: var(active-background); + text-color: var(active-foreground); +} +element selected.normal { + background-color: var(selected-normal-background); + text-color: var(selected-normal-foreground); +} +element selected.urgent { + background-color: var(selected-urgent-background); + text-color: var(selected-urgent-foreground); +} +element selected.active { + background-color: var(selected-active-background); + text-color: var(selected-active-foreground); +} +element alternate.normal { + background-color: var(alternate-normal-background); + text-color: var(alternate-normal-foreground); +} +element alternate.urgent { + background-color: var(alternate-urgent-background); + text-color: var(alternate-urgent-foreground); +} +element alternate.active { + background-color: var(alternate-active-background); + text-color: var(alternate-active-foreground); +} +element-icon { + background-color: transparent; + text-color: inherit; + size: 24px; + cursor: inherit; +} +element-text { + background-color: transparent; + text-color: inherit; + highlight: inherit; + cursor: inherit; + vertical-align: 0.5; + horizontal-align: 0.0; +} + +/*****----- Mode Switcher -----*****/ +mode-switcher { + enabled: true; + spacing: 10px; + margin: 0px; + padding: 0px; + border: 0px solid; + border-radius: 0px; + border-color: @border-colour; + background-color: transparent; + text-color: @foreground-colour; +} +button { + padding: 10px; + border: 0px solid; + border-radius: 0px; + border-color: @border-colour; + background-color: @alternate-background; + text-color: inherit; + cursor: pointer; +} +button selected { + background-color: var(selected-normal-background); + text-color: var(selected-normal-foreground); +} + +/*****----- Message -----*****/ +message { + enabled: true; + margin: 0px; + padding: 0px; + border: 0px solid; + border-radius: 0px; + border-color: @border-colour; + background-color: transparent; + text-color: @foreground-colour; +} +textbox { + font: "Inter 11"; + padding: 10px; + border: 0px solid; + border-radius: 0px; + border-color: @border-colour; + background-color: @alternate-background; + text-color: @foreground-colour; + vertical-align: 0.5; + horizontal-align: 0.0; + highlight: none; + placeholder-color: @foreground-colour; + blink: true; + markup: true; +} +error-message { + padding: 10px; + border: 0px solid; + border-radius: 0px; + border-color: @border-colour; + background-color: @background-colour; + text-color: @foreground-colour; +} diff --git a/modules/rofi/go.mod b/modules/rofi/go.mod new file mode 100644 index 0000000..db7646b --- /dev/null +++ b/modules/rofi/go.mod @@ -0,0 +1,5 @@ +module rofi + +go 1.22 + +require git.novox.be/novox/mesh-sdk/go v0.1.7 diff --git a/modules/rofi/go.sum b/modules/rofi/go.sum new file mode 100644 index 0000000..b474419 --- /dev/null +++ b/modules/rofi/go.sum @@ -0,0 +1,2 @@ +git.novox.be/novox/mesh-sdk/go v0.1.7 h1:C0sTQmtTiyYH7bnqZb7PusXnqA37gKuT7Nqjn9gG47w= +git.novox.be/novox/mesh-sdk/go v0.1.7/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= diff --git a/modules/rofi/module.json b/modules/rofi/module.json new file mode 100644 index 0000000..85eafab --- /dev/null +++ b/modules/rofi/module.json @@ -0,0 +1,116 @@ +{ + "module": "rofi", + "version": "1", + "capabilities": [ + "package-manager" + ], + "requires": [ + "x11-display" + ], + "claims": [ + { + "name": "node-launcher", + "scope": "node", + "serves": [ + "menu" + ] + } + ], + "tools": [ + "rofi_applications", + "rofi_themes", + "rofi_run" + ], + "resources": [ + { + "id": "package", + "type": "package", + "package": "rofi" + }, + { + "id": "configuration-dir", + "type": "directory", + "path": "${machine:account-home}/.config/rofi", + "owner": "${machine:account}", + "mode": "0755" + }, + { + "id": "themes-dir", + "type": "directory", + "path": "${machine:account-home}/.config/rofi/themes", + "owner": "${machine:account}", + "mode": "0755" + }, + { + "id": "configuration", + "type": "file", + "path": "${machine:account-home}/.config/rofi/config.rasi", + "owner": "${machine:account}", + "mode": "0644", + "content": "/* rofi, the launcher (module rofi, novox/hq ADR 0208). Owned by the mesh: this file is replaced at\n * every push. Adopted from the two workstations' file of 2026-10-04: the settings that differ from\n * rofi's defaults, nothing else. Its look is the theme \"mesh\", in themes/ beside this file. */\n\nconfiguration {\n\tmodi: \"drun,run,window,filebrowser\";\n\tshow-icons: true;\n\tcase-sensitive: false;\n\tnormalize-match: true;\n\tmatching: \"normal\";\n\ttokenize: true;\n\tcycle: true;\n\tsteal-focus: false;\n\tclick-to-exit: true;\n\tsort: false;\n\n\t/* Applications: the user's and the system's desktop entries, read fresh each time so a\n\t * program installed a minute ago is there. */\n\tdrun-match-fields: \"name,generic,exec,categories,keywords\";\n\tdrun-display-format: \"{name} [({generic})]\";\n\tdrun-show-actions: false;\n\tdrun-url-launcher: \"xdg-open\";\n\tdrun-use-desktop-cache: false;\n\tdrun-reload-desktop-cache: false;\n\trun,drun {\n\t\tfallback-icon: \"application-x-addon\";\n\t}\n\n\t/* A command run from `run` opens in the node's terminal when it asks for one. */\n\tterminal: \"rofi-sensible-terminal\";\n\trun-shell-command: \"{terminal} -e {cmd}\";\n\tssh-command: \"{terminal} -e {ssh-client} {host} [-p {port}]\";\n\tparse-hosts: true;\n\tparse-known-hosts: true;\n\n\twindow-match-fields: \"title,class,role,name,desktop\";\n\twindow-format: \"{w} - {c} - {t:0}\";\n\n\tdisable-history: false;\n\tmax-history-size: 25;\n\n\tfilebrowser {\n\t\tdirectories-first: true;\n\t\tsorting-method: \"name\";\n\t}\n\n\tdisplay-window: \"Windows\";\n\tdisplay-run: \"Run\";\n\tdisplay-ssh: \"SSH\";\n\tdisplay-drun: \"Apps\";\n\tdisplay-filebrowser: \"Files\";\n}\n\n@theme \"mesh\"\n" + }, + { + "id": "theme", + "type": "file", + "path": "${machine:account-home}/.config/rofi/themes/mesh.rasi", + "owner": "${machine:account}", + "mode": "0644", + "content": "/**\n * The theme \"mesh\" (module rofi, novox/hq ADR 0208): every rofi window unless a caller names\n * another. Owned by the mesh; replaced at every push. Adopted from the workstations' theme of\n * 2026-10-04 (after adi1090x's launcher type-4, style-1), its colour file inlined so the theme is\n * one file, and its face the monospace one every desktop module names.\n **/\n\n/*****----- Global Properties -----*****/\n* {\n background: #000000FF;\n background-alt: #282B31FF;\n foreground: #FFFFFFFF;\n selected: #DE5200FF;\n active: #DE5200FF;\n urgent: #CC0000FF;\n\n font: \"JetBrainsMono Nerd Font 11\";\n\n border-colour: var(selected);\n handle-colour: var(selected);\n background-colour: var(background);\n foreground-colour: var(foreground);\n alternate-background: var(background-alt);\n normal-background: var(background);\n normal-foreground: var(foreground);\n urgent-background: var(urgent);\n urgent-foreground: var(background);\n active-background: var(active);\n active-foreground: var(background);\n selected-normal-background: var(selected);\n selected-normal-foreground: var(background);\n selected-urgent-background: var(active);\n selected-urgent-foreground: var(background);\n selected-active-background: var(urgent);\n selected-active-foreground: var(background);\n alternate-normal-background: var(background);\n alternate-normal-foreground: var(foreground);\n alternate-urgent-background: var(urgent);\n alternate-urgent-foreground: var(background);\n alternate-active-background: var(active);\n alternate-active-foreground: var(background);\n}\n\n/*****----- Main Window -----*****/\nwindow {\n transparency: \"real\";\n location: center;\n anchor: center;\n fullscreen: false;\n width: 600px;\n x-offset: 0px;\n y-offset: 0px;\n enabled: true;\n margin: 0px;\n padding: 0px;\n border: 1px solid;\n border-radius: 0px;\n border-color: @border-colour;\n cursor: \"default\";\n background-color: @background-colour;\n}\n\n/*****----- Main Box -----*****/\nmainbox {\n enabled: true;\n spacing: 10px;\n margin: 0px;\n padding: 10px;\n border: 0px solid;\n border-radius: 0px;\n border-color: @border-colour;\n background-color: transparent;\n children: [ \"inputbar\", \"message\", \"listview\", \"mode-switcher\" ];\n}\n\n/*****----- Inputbar -----*****/\ninputbar {\n enabled: true;\n spacing: 10px;\n margin: 0px;\n padding: 10px;\n border: 0px 0px 1px 0px;\n border-radius: 0px;\n border-color: @border-colour;\n background-color: @alternate-background;\n text-color: @foreground-colour;\n children: [ \"prompt\", \"entry\" ];\n}\n\nprompt {\n enabled: true;\n background-color: inherit;\n text-color: inherit;\n}\ntextbox-prompt-colon {\n enabled: true;\n expand: false;\n str: \"::\";\n background-color: inherit;\n text-color: inherit;\n}\nentry {\n enabled: true;\n background-color: inherit;\n text-color: inherit;\n cursor: text;\n placeholder: \"Search...\";\n placeholder-color: inherit;\n}\n\n/*****----- Listview -----*****/\nlistview {\n enabled: true;\n columns: 1;\n lines: 8;\n cycle: true;\n dynamic: true;\n scrollbar: false;\n layout: vertical;\n reverse: false;\n fixed-height: true;\n fixed-columns: true;\n spacing: 0px;\n margin: 0px;\n padding: 0px;\n border: 0px solid;\n border-radius: 0px;\n border-color: @border-colour;\n background-color: transparent;\n text-color: @foreground-colour;\n cursor: \"default\";\n}\nscrollbar {\n handle-width: 5px;\n handle-color: @handle-colour;\n border-radius: 0px;\n background-color: @alternate-background;\n}\n\n/*****----- Elements -----*****/\nelement {\n enabled: true;\n spacing: 10px;\n margin: 0px;\n padding: 10px;\n border: 0px solid;\n border-radius: 0px;\n border-color: @border-colour;\n background-color: transparent;\n text-color: @foreground-colour;\n cursor: pointer;\n}\nelement normal.normal {\n background-color: var(normal-background);\n text-color: var(normal-foreground);\n}\nelement normal.urgent {\n background-color: var(urgent-background);\n text-color: var(urgent-foreground);\n}\nelement normal.active {\n background-color: var(active-background);\n text-color: var(active-foreground);\n}\nelement selected.normal {\n background-color: var(selected-normal-background);\n text-color: var(selected-normal-foreground);\n}\nelement selected.urgent {\n background-color: var(selected-urgent-background);\n text-color: var(selected-urgent-foreground);\n}\nelement selected.active {\n background-color: var(selected-active-background);\n text-color: var(selected-active-foreground);\n}\nelement alternate.normal {\n background-color: var(alternate-normal-background);\n text-color: var(alternate-normal-foreground);\n}\nelement alternate.urgent {\n background-color: var(alternate-urgent-background);\n text-color: var(alternate-urgent-foreground);\n}\nelement alternate.active {\n background-color: var(alternate-active-background);\n text-color: var(alternate-active-foreground);\n}\nelement-icon {\n background-color: transparent;\n text-color: inherit;\n size: 24px;\n cursor: inherit;\n}\nelement-text {\n background-color: transparent;\n text-color: inherit;\n highlight: inherit;\n cursor: inherit;\n vertical-align: 0.5;\n horizontal-align: 0.0;\n}\n\n/*****----- Mode Switcher -----*****/\nmode-switcher {\n enabled: true;\n spacing: 10px;\n margin: 0px;\n padding: 0px;\n border: 0px solid;\n border-radius: 0px;\n border-color: @border-colour;\n background-color: transparent;\n text-color: @foreground-colour;\n}\nbutton {\n padding: 10px;\n border: 0px solid;\n border-radius: 0px;\n border-color: @border-colour;\n background-color: @alternate-background;\n text-color: inherit;\n cursor: pointer;\n}\nbutton selected {\n background-color: var(selected-normal-background);\n text-color: var(selected-normal-foreground);\n}\n\n/*****----- Message -----*****/\nmessage {\n enabled: true;\n margin: 0px;\n padding: 0px;\n border: 0px solid;\n border-radius: 0px;\n border-color: @border-colour;\n background-color: transparent;\n text-color: @foreground-colour;\n}\ntextbox {\n font: \"Inter 11\";\n padding: 10px;\n border: 0px solid;\n border-radius: 0px;\n border-color: @border-colour;\n background-color: @alternate-background;\n text-color: @foreground-colour;\n vertical-align: 0.5;\n horizontal-align: 0.0;\n highlight: none;\n placeholder-color: @foreground-colour;\n blink: true;\n markup: true;\n}\nerror-message {\n padding: 10px;\n border: 0px solid;\n border-radius: 0px;\n border-color: @border-colour;\n background-color: @background-colour;\n text-color: @foreground-colour;\n}\n" + }, + { + "id": "theme-powermenu", + "type": "file", + "path": "${machine:account-home}/.config/rofi/themes/mesh-powermenu.rasi", + "owner": "${machine:account}", + "mode": "0644", + "content": "/**\n * The theme \"mesh-powermenu\" (module rofi, novox/hq ADR 0208): the power menu's five buttons.\n * Owned by the mesh; replaced at every push. Adopted from the workstations' power menu theme of\n * 2026-10-04 (after adi1090x's powermenu type-2, style-1), its colours inlined.\n **/\n\n/*****----- Configuration -----*****/\nconfiguration {\n show-icons: false;\n}\n\n/*****----- Global Properties -----*****/\n* {\n background: #000000FF;\n background-alt: #282B31FF;\n foreground: #FFFFFFFF;\n selected: #DE5200FF;\n active: #DE5200FF;\n urgent: #CC0000FF;\n\n font: \"JetBrainsMono Nerd Font 11\";\n}\n\n\n/*****----- Main Window -----*****/\nwindow {\n /* properties for window widget */\n transparency: \"real\";\n location: center;\n anchor: center;\n fullscreen: false;\n width: 800px;\n x-offset: 0px;\n y-offset: 0px;\n\n /* properties for all widgets */\n enabled: true;\n margin: 0px;\n padding: 0px;\n border: 0px solid;\n border-radius: 0px;\n border-color: @selected;\n cursor: \"default\";\n background-color: @background;\n}\n\n/*****----- Main Box -----*****/\nmainbox {\n enabled: true;\n spacing: 15px;\n margin: 0px;\n padding: 30px;\n border: 0px solid;\n border-radius: 0px;\n border-color: @selected;\n background-color: transparent;\n children: [ \"inputbar\", \"listview\" ];\n}\n\n/*****----- Inputbar -----*****/\ninputbar {\n enabled: true;\n spacing: 15px;\n margin: 0px;\n padding: 0px;\n border: 0px;\n border-radius: 0px;\n border-color: @selected;\n background-color: transparent;\n text-color: @foreground;\n children: [ \"textbox-prompt-colon\", \"prompt\"];\n}\n\ndummy {\n background-color: transparent;\n}\n\ntextbox-prompt-colon {\n enabled: true;\n expand: false;\n str: \"\";\n padding: 12px 16px;\n border-radius: 0px;\n background-color: @urgent;\n text-color: @background;\n}\nprompt {\n enabled: true;\n padding: 12px;\n border-radius: 0px;\n background-color: @active;\n text-color: @background;\n}\n\n/*****----- Message -----*****/\nmessage {\n enabled: true;\n margin: 0px;\n padding: 12px;\n border: 0px solid;\n border-radius: 0px;\n border-color: @selected;\n background-color: @background-alt;\n text-color: @foreground;\n}\ntextbox {\n background-color: inherit;\n text-color: inherit;\n vertical-align: 0.5;\n horizontal-align: 0.5;\n placeholder-color: @foreground;\n blink: true;\n markup: true;\n}\nerror-message {\n padding: 12px;\n border: 0px solid;\n border-radius: 0px;\n border-color: @selected;\n background-color: @background;\n text-color: @foreground;\n}\n\n/*****----- Listview -----*****/\nlistview {\n enabled: true;\n columns: 5;\n lines: 1;\n cycle: true;\n dynamic: true;\n scrollbar: false;\n layout: vertical;\n reverse: false;\n fixed-height: true;\n fixed-columns: true;\n\n spacing: 15px;\n margin: 0px;\n padding: 0px;\n border: 0px solid;\n border-radius: 0px;\n border-color: @selected;\n background-color: transparent;\n text-color: @foreground;\n cursor: \"default\";\n}\n\n/*****----- Elements -----*****/\nelement {\n enabled: true;\n spacing: 0px;\n margin: 0px;\n padding: 40px 10px;\n border: 0px solid;\n border-radius: 0px;\n border-color: @selected;\n background-color: @background-alt;\n text-color: @foreground;\n cursor: pointer;\n}\nelement-text {\n font: \"JetBrainsMono Nerd Font Bold 32\";\n background-color: transparent;\n text-color: inherit;\n cursor: inherit;\n vertical-align: 0.5;\n horizontal-align: 0.5;\n}\nelement selected.normal {\n background-color: var(selected);\n text-color: var(background);\n}\n" + }, + { + "id": "dmenu", + "type": "file", + "path": "${machine:account-home}/.local/bin/dmenu", + "owner": "${machine:account}", + "mode": "0755", + "content": "#!/bin/sh\n# dmenu, as this node's launcher answers it (module rofi, novox/hq ADR 0208). The node-launcher\n# seat's dmenu-compatible command: choices on standard input, the chosen one on standard output,\n# exit 1 when nothing was chosen. A script calls `dmenu` and works whichever module holds the seat.\n#\n# rofi understands dmenu's -p, -l and -i. dmenu's look options (-fn, -nb, -nf, -sb, -sf, -m, -w)\n# take a value rofi would misread, so they are dropped with it; -b and -f are dropped alone. The\n# look is the launcher's theme.\nset -u\nn=$#\nwhile [ \"$n\" -gt 0 ]; do\n\targ=$1\n\tshift\n\tn=$((n - 1))\n\tcase $arg in\n\t-fn | -nb | -nf | -sb | -sf | -m | -w)\n\t\tif [ \"$n\" -gt 0 ]; then\n\t\t\tshift\n\t\t\tn=$((n - 1))\n\t\tfi\n\t\t;;\n\t-b | -f) ;;\n\t*) set -- \"$@\" \"$arg\" ;;\n\tesac\ndone\nexec rofi -dmenu \"$@\"\n" + }, + { + "id": "launch", + "type": "file", + "path": "${machine:account-home}/.local/bin/rofi-launch", + "owner": "${machine:account}", + "mode": "0755", + "content": "#!/bin/sh\n# rofi-launch drun|run|window|filebrowser|sudo (module rofi, novox/hq ADR 0208): what the launcher's\n# key bindings run.\n#\n# After a resume the keyboard grab can fail for a moment, and rofi then exits at once: a key press\n# that opens nothing. So a failure within half a second is tried again, up to five times. A person\n# closing the menu takes longer than that, and is never shown it a second time.\nset -u\nmode=${1:-drun}\n\nnow_ms() { date +%s%3N; }\n\nattempt() {\n\ti=0\n\twhile [ \"$i\" -lt 5 ]; do\n\t\tstart=$(now_ms)\n\t\t\"$@\" && return 0\n\t\t[ $(($(now_ms) - start)) -ge 500 ] && return 1\n\t\ti=$((i + 1))\n\t\tsleep 0.1\n\tdone\n\treturn 1\n}\n\ncase $mode in\ndrun | run | window | filebrowser)\n\tattempt rofi -show \"$mode\"\n\t;;\nsudo)\n\t# A command line, run with sudo in the node's terminal.\n\tcommand=$(attempt rofi -dmenu -p sudo &2\n\texit 2\n\t;;\nesac\n" + }, + { + "id": "powermenu", + "type": "file", + "path": "${machine:account-home}/.local/bin/rofi-powermenu", + "owner": "${machine:account}", + "mode": "0755", + "content": "#!/usr/bin/env bash\n# rofi-powermenu (module rofi, novox/hq ADR 0208): lock, suspend, log out, reboot, shut down.\n#\n# It belongs to the session, and it is the launcher's: its whole face is rofi's. Every action is a\n# verb of logind or the service manager, so nothing here names a window manager or a locker:\n# - lock asks logind to lock the session, which the holder of node-lock-screen answers;\n# - log out ends this login session, whichever window manager runs in it.\n# Adopted from the workstations' power menu of 2026-10-04 (after adi1090x's powermenu type-2).\nset -u\n\ntheme=mesh-powermenu\nuptime=\"$(uptime -p | sed -e 's/^up //')\"\n\nshutdown='󰤂'\nreboot='󰜉'\nlock='󰌾'\nsuspend='󰤄'\nlogout='󰍃'\nyes='󰄲'\nno='󰅖'\n\nmenu() {\n\trofi -dmenu -p \"Uptime: $uptime\" -mesg \"Uptime: $uptime\" -theme \"$theme\"\n}\n\nconfirm() {\n\tprintf '%s\\n%s\\n' \"$yes\" \"$no\" | rofi -dmenu -p 'Confirmation' -mesg 'Are you sure?' -theme \"$theme\" \\\n\t\t-theme-str 'window {location: center; anchor: center; fullscreen: false; width: 350px;}' \\\n\t\t-theme-str 'mainbox {children: [ \"message\", \"listview\" ];}' \\\n\t\t-theme-str 'listview {columns: 2; lines: 1;}' \\\n\t\t-theme-str 'element-text {horizontal-align: 0.5;}' \\\n\t\t-theme-str 'textbox {horizontal-align: 0.5;}'\n}\n\nsession() {\n\t# The login session this menu runs in: the session's own id, else logind's answer for this process.\n\tif [ -n \"${XDG_SESSION_ID:-}\" ]; then\n\t\techo \"$XDG_SESSION_ID\"\n\telse\n\t\tloginctl show-session auto -p Id --value 2>/dev/null\n\tfi\n}\n\nconfirmed() { [ \"$(confirm)\" = \"$yes\" ]; }\n\nchosen=\"$(printf '%s\\n' \"$lock\" \"$suspend\" \"$logout\" \"$reboot\" \"$shutdown\" | menu)\" || exit 0\ncase $chosen in\n\"$lock\") loginctl lock-session \"$(session)\" ;;\n\"$suspend\") confirmed && systemctl suspend ;;\n\"$logout\") confirmed && loginctl terminate-session \"$(session)\" ;;\n\"$reboot\") confirmed && systemctl reboot ;;\n\"$shutdown\") confirmed && systemctl poweroff ;;\nesac\nexit 0\n" + }, + { + "id": "i3-bindings", + "type": "file", + "path": "${machine:account-home}/.config/i3/config.d/50-rofi.conf", + "owner": "${machine:account}", + "mode": "0644", + "content": "# The launcher's key bindings (module rofi, novox/hq ADR 0208). Owned by the mesh: replaced at every\n# push. i3 reads this file through its configuration's `include ~/.config/i3/config.d/*.conf`, after\n# the variables it sets, so $mod is i3's.\nbindsym $mod+d exec --no-startup-id ~/.local/bin/rofi-launch drun\nbindsym $mod+t exec --no-startup-id ~/.local/bin/rofi-launch run\nbindsym $mod+Shift+t exec --no-startup-id ~/.local/bin/rofi-launch sudo\nbindsym $mod+Shift+w exec --no-startup-id ~/.local/bin/rofi-launch window\nbindsym $mod+Escape exec --no-startup-id ~/.local/bin/rofi-powermenu\n" + } + ], + "build": { + "artifacts": [ + { + "name": "tools", + "kind": "bundle", + "language": "go", + "system": "arch", + "from": "cmd/rofi-tools", + "binary": "rofi-tools", + "loads": [ + "rofi-tools" + ] + } + ] + } +} From 8bbea4a2ad5d3f0421e86beed78aeff7b69dfa52 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 4 Oct 2026 12:53:39 +0200 Subject: [PATCH 03/15] dunst: the notifier as a module, claiming node-notifier and serving send and history (hq ADR 0208) Owns one dunstrc (the laptop's, in the interface face, its menu on the seat's dmenu command) and the dunstrc.d directory for other modules' rules; D-Bus starts it, so nothing else does. Go tools over the session bus. --- modules/dunst/README.md | 60 +++ modules/dunst/cmd/dunst-tools/args.go | 97 ++++ modules/dunst/cmd/dunst-tools/dunst.go | 355 +++++++++++++++ modules/dunst/cmd/dunst-tools/dunst_test.go | 160 +++++++ modules/dunst/cmd/dunst-tools/main.go | 91 ++++ .../cmd/dunst-tools/manifest_helpers_test.go | 175 ++++++++ .../dunst/cmd/dunst-tools/manifest_test.go | 77 ++++ modules/dunst/cmd/dunst-tools/session.go | 423 ++++++++++++++++++ modules/dunst/cmd/dunst-tools/session_test.go | 174 +++++++ modules/dunst/files/dunstrc | 92 ++++ modules/dunst/go.mod | 5 + modules/dunst/go.sum | 2 + modules/dunst/module.json | 73 +++ 13 files changed, 1784 insertions(+) create mode 100644 modules/dunst/README.md create mode 100644 modules/dunst/cmd/dunst-tools/args.go create mode 100644 modules/dunst/cmd/dunst-tools/dunst.go create mode 100644 modules/dunst/cmd/dunst-tools/dunst_test.go create mode 100644 modules/dunst/cmd/dunst-tools/main.go create mode 100644 modules/dunst/cmd/dunst-tools/manifest_helpers_test.go create mode 100644 modules/dunst/cmd/dunst-tools/manifest_test.go create mode 100644 modules/dunst/cmd/dunst-tools/session.go create mode 100644 modules/dunst/cmd/dunst-tools/session_test.go create mode 100644 modules/dunst/files/dunstrc create mode 100644 modules/dunst/go.mod create mode 100644 modules/dunst/go.sum create mode 100644 modules/dunst/module.json diff --git a/modules/dunst/README.md b/modules/dunst/README.md new file mode 100644 index 0000000..59c90c8 --- /dev/null +++ b/modules/dunst/README.md @@ -0,0 +1,60 @@ +# dunst + +The notifier as a module (novox/hq ADR 0208, research 026/05). + +- Installs `dunst`, and `libnotify` for `notify-send`, the client every program and these tools use. +- Claims the mesh's `node-notifier` seat and serves its verbs `send` and `history`. +- Owns `~/.config/dunst/dunstrc` and the directory `~/.config/dunst/dunstrc.d/`. Another module's + rule is that module's own file in the directory (ADR 0208 §4). dunst reads the directory after + `dunstrc`, so a drop-in outranks it. +- **Starts nothing.** The package registers dunst with D-Bus, which starts it on the first + notification, inside the account's service manager. There is no autostart line, no unit and no + session-start contribution. +- **Requires no display of its own.** dunst speaks both X11 and Wayland and picks the one the session + has, so it serves an X session and a later sway one alike. + +## Tools + +Every tool goes over the account's session bus. None needs the screen, and each answers clearly when +the account is not logged in. + +| tool | does | +|---|---| +| `node-notifier.send` | a notification: title, body, urgency, sender, icon, how long; answers its id | +| `node-notifier.history` | what was shown, newest first, with how long ago | +| `dunst_pause` / `dunst_resume` | do not disturb: notifications are held back, not lost | +| `dunst_close_all` | clear the screen; the history keeps them | +| `dunst_rules` | the rules the running notifier holds, and the files they come from | +| `dunst_count` | shown, waiting, in history, and whether paused | + +## What it chose, and what it improves + +The workstations' files differed: one had the notifications bottom-right, 15 % transparent and with +rounded corners; the other top-right, opaque and square. This module takes the second, because the +rest of the desktop is square and opaque, and the top-right corner sits under the bar that shows the +count. The file keeps only the settings that differ from dunst's defaults. + +- **The context menu works.** It called `/usr/bin/dmenu`, installed on neither machine. It now calls + `dmenu`, the seat command of whichever module holds `node-launcher` (`rofi` on the workstations). +- **The face is the interface one,** Inter (research 026/04), instead of a monospace Nerd font. +- `icon_path`, which named two directories of an icon theme that is not installed, is gone. The icon + theme is looked up recursively. + +## What it leaves as found + +- `~/.config/dunst/dunstrc.d/50-slack.conf`, the Slack rule. It becomes the Slack module's own drop-in + when there is one, and until then it is the operator's file in a directory this module owns. + +## Migration (ADR 0182) + +- The first push keeps the found `dunstrc` once, then writes the module's. +- **The desktop runs two notification daemons** because its session began before the session bus + fix (research 026/01). That ends at the next login, and nothing here starts a second one. + `dunst_count` after logging in again shows the one daemon's counts. + +## Blockers + +- `node-notifier` is ADR 0208's seat. Until the controller knows it, `mctl` reads the claim as + unknown. +- `dunst_rules` and the counts ask the running notifier. When none runs, the bus starts one, which + needs a session to draw on. diff --git a/modules/dunst/cmd/dunst-tools/args.go b/modules/dunst/cmd/dunst-tools/args.go new file mode 100644 index 0000000..9b5dfcf --- /dev/null +++ b/modules/dunst/cmd/dunst-tools/args.go @@ -0,0 +1,97 @@ +// Reading a tool's arguments: JSON numbers arrive as float64, and a missing argument is its default. +// The same in every desktop module that carries it. +package main + +import ( + "fmt" + "math" + "strings" + "time" +) + +// text is a string argument, trimmed; required says an empty one is refused. +func text(args map[string]any, key string, required bool) (string, error) { + v, present := args[key] + if !present || v == nil { + if required { + return "", fmt.Errorf("%s is required", key) + } + return "", nil + } + s, ok := v.(string) + if !ok { + return "", fmt.Errorf("%s is a string, not %T", key, v) + } + s = strings.TrimSpace(s) + if s == "" && required { + return "", fmt.Errorf("%s is required", key) + } + return s, nil +} + +// whole is a whole-number argument within [least, most], or def when absent. +func whole(args map[string]any, key string, def, least, most int) (int, error) { + v, present := args[key] + if !present || v == nil { + return def, nil + } + f, ok := v.(float64) + if !ok { + if i, isInt := v.(int); isInt { + f = float64(i) + } else { + return 0, fmt.Errorf("%s is a number, not %T", key, v) + } + } + if f != math.Trunc(f) { + return 0, fmt.Errorf("%s is a whole number, not %v", key, f) + } + n := int(f) + if n < least || n > most { + return 0, fmt.Errorf("%s is %d; it is between %d and %d", key, n, least, most) + } + return n, nil +} + +// flag is a boolean argument, or def when absent. +func flag(args map[string]any, key string, def bool) (bool, error) { + v, present := args[key] + if !present || v == nil { + return def, nil + } + b, ok := v.(bool) + if !ok { + return false, fmt.Errorf("%s is true or false, not %T", key, v) + } + return b, nil +} + +// texts is a list-of-strings argument. +func texts(args map[string]any, key string) ([]string, error) { + v, present := args[key] + if !present || v == nil { + return nil, nil + } + list, ok := v.([]any) + if !ok { + if ss, isStrings := v.([]string); isStrings { + return ss, nil + } + return nil, fmt.Errorf("%s is a list of strings, not %T", key, v) + } + out := make([]string, 0, len(list)) + for i, item := range list { + s, ok := item.(string) + if !ok { + return nil, fmt.Errorf("%s[%d] is a string, not %T", key, i, item) + } + out = append(out, s) + } + return out, nil +} + +// seconds is a timeout argument in seconds, defaulted and bounded below the runtime's call limit. +func seconds(args map[string]any, key string, def, most int) (time.Duration, error) { + n, err := whole(args, key, def, 1, most) + return time.Duration(n) * time.Second, err +} diff --git a/modules/dunst/cmd/dunst-tools/dunst.go b/modules/dunst/cmd/dunst-tools/dunst.go new file mode 100644 index 0000000..a05c3e9 --- /dev/null +++ b/modules/dunst/cmd/dunst-tools/dunst.go @@ -0,0 +1,355 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + "sort" + "strconv" + "strings" + "syscall" + "time" + "unsafe" +) + +var urgencies = []string{"low", "normal", "critical"} + +const busTimeout = 10 * time.Second + +// Notification is what node-notifier.send shows. +type Notification struct { + Summary string + Body string + Urgency string + AppName string + Icon string + ExpireMS int + Category string + ReplaceID int +} + +func notificationOf(args map[string]any) (Notification, error) { + var n Notification + var err error + if n.Summary, err = text(args, "summary", true); err != nil { + return n, err + } + if n.Body, err = text(args, "body", false); err != nil { + return n, err + } + if n.Urgency, err = text(args, "urgency", false); err != nil { + return n, err + } + if n.Urgency == "" { + n.Urgency = "normal" + } + known := false + for _, u := range urgencies { + known = known || u == n.Urgency + } + if !known { + return n, fmt.Errorf("urgency %q is low, normal or critical", n.Urgency) + } + if n.AppName, err = text(args, "app_name", false); err != nil { + return n, err + } + if n.AppName == "" { + n.AppName = "mesh" + } + if n.Icon, err = text(args, "icon", false); err != nil { + return n, err + } + if n.ExpireMS, err = whole(args, "expire_ms", -1, 0, 24*3600*1000); err != nil { + return n, err + } + if n.Category, err = text(args, "category", false); err != nil { + return n, err + } + n.ReplaceID, err = whole(args, "replace_id", 0, 0, 1<<31-1) + return n, err +} + +// SendResult is what node-notifier.send answers. +type SendResult struct { + ID int `json:"id"` +} + +// Send shows a notification through the desktop's notification service, whichever runs it. +func Send(n Notification) (SendResult, error) { + s, err := findBus() + if err != nil { + return SendResult{}, err + } + args := []string{"--print-id", "--urgency=" + n.Urgency, "--app-name=" + n.AppName} + if n.Icon != "" { + args = append(args, "--icon="+n.Icon) + } + if n.ExpireMS >= 0 { + args = append(args, "--expire-time="+strconv.Itoa(n.ExpireMS)) + } + if n.Category != "" { + args = append(args, "--category="+n.Category) + } + if n.ReplaceID > 0 { + args = append(args, "--replace-id="+strconv.Itoa(n.ReplaceID)) + } + // "--" so a title that starts with a dash is a title. + args = append(args, "--", n.Summary) + if n.Body != "" { + args = append(args, n.Body) + } + r, err := s.run(busTimeout, "", "notify-send", args...) + if err != nil { + return SendResult{}, err + } + if r.Code != 0 { + return SendResult{}, fmt.Errorf("notify-send: %s", strings.TrimSpace(r.Stderr)) + } + id, err := strconv.Atoi(strings.TrimSpace(r.Stdout)) + if err != nil { + return SendResult{}, fmt.Errorf("notify-send answered no id: %q", r.Stdout) + } + return SendResult{ID: id}, nil +} + +// dunstctl runs one dunstctl command over the session bus and answers what it printed. +func dunstctl(args ...string) (string, error) { + s, err := findBus() + if err != nil { + return "", err + } + r, err := s.run(busTimeout, "", "dunstctl", args...) + if err != nil { + return "", err + } + if r.Code != 0 { + return "", fmt.Errorf("dunstctl %s: %s", strings.Join(args, " "), strings.TrimSpace(r.Stderr+r.Stdout)) + } + return r.Stdout, nil +} + +// variantMaps reads busctl's JSON form of an array of dictionaries (aa{sv}), which is how dunstctl +// answers history and rules, into plain maps. +func variantMaps(raw string) ([]map[string]any, error) { + var doc struct { + Type string `json:"type"` + Data [][]map[string]struct { + Data any `json:"data"` + } `json:"data"` + } + if err := json.Unmarshal([]byte(raw), &doc); err != nil { + return nil, fmt.Errorf("dunstctl's answer is not the bus's JSON: %w", err) + } + if doc.Type != "aa{sv}" { + return nil, fmt.Errorf("dunstctl answered %s, not aa{sv}", doc.Type) + } + out := []map[string]any{} + for _, group := range doc.Data { + for _, entry := range group { + m := map[string]any{} + for k, v := range entry { + m[k] = v.Data + } + out = append(out, m) + } + } + return out, nil +} + +// Shown is one notification in the history. +type Shown struct { + ID int `json:"id"` + AppName string `json:"app_name"` + Summary string `json:"summary"` + Body string `json:"body,omitempty"` + Urgency string `json:"urgency"` + Category string `json:"category,omitempty"` + AgeSeconds int64 `json:"age_seconds"` +} + +// HistoryResult is what node-notifier.history answers. +type HistoryResult struct { + Total int `json:"total"` + Notifications []Shown `json:"notifications"` +} + +// History is dunst's history, newest first. +func History(limit int) (HistoryResult, error) { + raw, err := dunstctl("history") + if err != nil { + return HistoryResult{}, err + } + return parseHistory(raw, monotonicMicros(), limit) +} + +func parseHistory(raw string, nowMicros int64, limit int) (HistoryResult, error) { + entries, err := variantMaps(raw) + if err != nil { + return HistoryResult{}, err + } + out := HistoryResult{Total: len(entries), Notifications: []Shown{}} + type stamped struct { + Shown + at int64 + } + var all []stamped + for _, e := range entries { + at := number(e["timestamp"]) + all = append(all, stamped{Shown{ + ID: int(number(e["id"])), AppName: str(e["appname"]), Summary: str(e["summary"]), Body: str(e["body"]), + Urgency: strings.ToLower(str(e["urgency"])), Category: str(e["category"]), + AgeSeconds: max(0, (nowMicros-at)/1_000_000), + }, at}) + } + sort.SliceStable(all, func(i, j int) bool { return all[i].at > all[j].at }) + for i, s := range all { + if i == limit { + break + } + out.Notifications = append(out.Notifications, s.Shown) + } + return out, nil +} + +func number(v any) int64 { + switch n := v.(type) { + case float64: + return int64(n) + case json.Number: + i, _ := n.Int64() + return i + } + return 0 +} + +func str(v any) string { + s, _ := v.(string) + return s +} + +// monotonicMicros is the clock dunst stamps its notifications with (CLOCK_MONOTONIC, microseconds). +func monotonicMicros() int64 { + var ts syscall.Timespec + const clockMonotonic = 1 + if _, _, errno := syscall.Syscall(syscall.SYS_CLOCK_GETTIME, clockMonotonic, uintptr(unsafe.Pointer(&ts)), 0); errno != 0 { + return 0 + } + return ts.Sec*1_000_000 + ts.Nsec/1000 +} + +// PauseResult is what dunst_pause and dunst_resume answer. +type PauseResult struct { + Paused bool `json:"paused"` + Note string `json:"note"` +} + +// SetPaused turns do-not-disturb on or off. +func SetPaused(on bool) (PauseResult, error) { + if _, err := dunstctl("set-paused", strconv.FormatBool(on)); err != nil { + return PauseResult{}, err + } + out, err := dunstctl("is-paused") + if err != nil { + return PauseResult{}, err + } + paused := strings.TrimSpace(out) == "true" + note := "notifications are shown" + if paused { + note = "notifications are held back until dunst_resume; the next login starts unpaused" + } + return PauseResult{Paused: paused, Note: note}, nil +} + +// CloseAll closes what is on screen. +func CloseAll() (CountResult, error) { + if _, err := dunstctl("close-all"); err != nil { + return CountResult{}, err + } + return Count() +} + +// CountResult is what dunst_count answers. +type CountResult struct { + Displayed int `json:"displayed"` + Waiting int `json:"waiting"` + History int `json:"history"` + Paused bool `json:"paused"` +} + +// Count is how many notifications are where. +func Count() (CountResult, error) { + var c CountResult + for _, part := range []struct { + which string + into *int + }{{"displayed", &c.Displayed}, {"waiting", &c.Waiting}, {"history", &c.History}} { + out, err := dunstctl("count", part.which) + if err != nil { + return c, err + } + n, err := strconv.Atoi(strings.TrimSpace(out)) + if err != nil { + return c, fmt.Errorf("dunstctl count %s answered %q", part.which, out) + } + *part.into = n + } + out, err := dunstctl("is-paused") + if err != nil { + return c, err + } + c.Paused = strings.TrimSpace(out) == "true" + return c, nil +} + +// Rule is one notifier rule in force. +type Rule struct { + Name string `json:"name"` + Enabled bool `json:"enabled"` + Sets map[string]any `json:"sets"` +} + +// RulesResult is what dunst_rules answers. +type RulesResult struct { + Files []string `json:"files"` + Rules []Rule `json:"rules"` +} + +// Rules are the rules the running notifier holds, and the files it reads them from. +func Rules() (RulesResult, error) { + raw, err := dunstctl("rules", "--json") + if err != nil { + return RulesResult{}, err + } + return parseRules(raw, configFiles(filepath.Join(operatorHome(), ".config", "dunst"))) +} + +func parseRules(raw string, files []string) (RulesResult, error) { + entries, err := variantMaps(raw) + if err != nil { + return RulesResult{}, err + } + out := RulesResult{Files: files, Rules: []Rule{}} + for _, e := range entries { + r := Rule{Name: str(e["name"]), Enabled: e["enabled"] == true, Sets: map[string]any{}} + for k, v := range e { + if k != "name" && k != "enabled" { + r.Sets[k] = v + } + } + out.Rules = append(out.Rules, r) + } + sort.SliceStable(out.Rules, func(i, j int) bool { return out.Rules[i].Name < out.Rules[j].Name }) + return out, nil +} + +// configFiles are dunstrc and its drop-ins in the order dunst reads them. +func configFiles(dir string) []string { + files := []string{} + if _, err := os.Stat(filepath.Join(dir, "dunstrc")); err == nil { + files = append(files, filepath.Join(dir, "dunstrc")) + } + dropins, _ := filepath.Glob(filepath.Join(dir, "dunstrc.d", "*.conf")) + sort.Strings(dropins) + return append(files, dropins...) +} diff --git a/modules/dunst/cmd/dunst-tools/dunst_test.go b/modules/dunst/cmd/dunst-tools/dunst_test.go new file mode 100644 index 0000000..7faae0f --- /dev/null +++ b/modules/dunst/cmd/dunst-tools/dunst_test.go @@ -0,0 +1,160 @@ +package main + +import ( + "errors" + "os" + "path/filepath" + "reflect" + "strconv" + "strings" + "testing" +) + +// withBus gives the fake machine the account's runtime directory and bus socket. +func withBus(t *testing.T) string { + t.Helper() + root := fakeMachine(t) + runtime := filepath.Join(runUserDir, strconv.Itoa(os.Getuid())) + if err := os.MkdirAll(runtime, 0o700); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(runtime, "bus"), nil, 0o600); err != nil { + t.Fatal(err) + } + return root +} + +// A history as dunstctl answers it (busctl's JSON), two entries out of order. +const history = `{"type":"aa{sv}","data":[[ + {"body":{"type":"s","data":"the build is green"},"summary":{"type":"s","data":"CI"},"appname":{"type":"s","data":"mesh"}, + "category":{"type":"s","data":""},"id":{"type":"i","data":7},"timestamp":{"type":"x","data":100000000},"urgency":{"type":"s","data":"NORMAL"}}, + {"body":{"type":"s","data":""},"summary":{"type":"s","data":"Battery low"},"appname":{"type":"s","data":"upower"}, + "category":{"type":"s","data":"device"},"id":{"type":"i","data":9},"timestamp":{"type":"x","data":160000000},"urgency":{"type":"s","data":"CRITICAL"}} +]]}` + +func TestTheHistoryIsNewestFirstWithAgesFromDunstsOwnClock(t *testing.T) { + got, err := parseHistory(history, 200_000_000, 20) + if err != nil { + t.Fatal(err) + } + want := []Shown{ + {ID: 9, AppName: "upower", Summary: "Battery low", Urgency: "critical", Category: "device", AgeSeconds: 40}, + {ID: 7, AppName: "mesh", Summary: "CI", Body: "the build is green", Urgency: "normal", AgeSeconds: 100}, + } + if got.Total != 2 || !reflect.DeepEqual(got.Notifications, want) { + t.Fatalf("%+v", got) + } + if got, _ := parseHistory(history, 200_000_000, 1); len(got.Notifications) != 1 || got.Total != 2 { + t.Fatalf("limited: %+v", got) + } + if _, err := parseHistory(`{"type":"as","data":[]}`, 0, 1); err == nil { + t.Fatal("an answer of another type was accepted") + } + if monotonicMicros() <= 0 { + t.Fatal("the monotonic clock") + } +} + +func TestSendAsksNotifySendOverTheAccountsBusAndAnswersTheId(t *testing.T) { + withBus(t) + bin := fakeBinaries(t, map[string]string{"notify-send": `for a in "$@"; do printf '[%s]' "$a"; done > "$LOG"; echo >> "$LOG"; echo "bus=$DBUS_SESSION_BUS_ADDRESS" >> "$LOG"; echo 42`}) + t.Setenv("LOG", filepath.Join(bin, "log")) + n, err := notificationOf(map[string]any{"summary": "-dash title", "body": "hello", "urgency": "critical", "expire_ms": float64(0)}) + if err != nil { + t.Fatal(err) + } + got, err := Send(n) + if err != nil || got.ID != 42 { + t.Fatalf("%+v, %v", got, err) + } + asked, _ := os.ReadFile(filepath.Join(bin, "log")) + want := "[--print-id][--urgency=critical][--app-name=mesh][--expire-time=0][--][-dash title][hello]\nbus=unix:path=" + + filepath.Join(runUserDir, strconv.Itoa(os.Getuid()), "bus") + "\n" + if string(asked) != want { + t.Fatalf("notify-send was asked:\n%s\nwant:\n%s", asked, want) + } +} + +func TestANotificationIsRefusedForWhatItCannotBe(t *testing.T) { + for _, bad := range []map[string]any{{}, {"summary": " "}, {"summary": "x", "urgency": "urgent"}, {"summary": "x", "expire_ms": float64(-5)}} { + if _, err := notificationOf(bad); err == nil { + t.Errorf("accepted %v", bad) + } + } + n, _ := notificationOf(map[string]any{"summary": "x"}) + if n.Urgency != "normal" || n.AppName != "mesh" || n.ExpireMS != -1 { + t.Fatalf("defaults: %+v", n) + } +} + +func TestWithoutABusTheToolsSaySo(t *testing.T) { + fakeMachine(t) + if _, err := Send(Notification{Summary: "x"}); !errors.Is(err, ErrNoBus) { + t.Fatal(err) + } + if _, err := Count(); !errors.Is(err, ErrNoBus) { + t.Fatal(err) + } +} + +func TestCountPauseAndCloseAllAreDunstctlsAnswers(t *testing.T) { + withBus(t) + bin := fakeBinaries(t, map[string]string{"dunstctl": `echo "$*" >> "$LOG" +case "$*" in + "count displayed") echo 1 ;; + "count waiting") echo 0 ;; + "count history") echo 12 ;; + is-paused) cat "$STATE" 2>/dev/null || echo false ;; + "set-paused true") echo true > "$STATE" ;; + "set-paused false") echo false > "$STATE" ;; +esac`}) + t.Setenv("LOG", filepath.Join(bin, "log")) + t.Setenv("STATE", filepath.Join(bin, "paused")) + c, err := Count() + if err != nil || c != (CountResult{Displayed: 1, History: 12}) { + t.Fatalf("%+v, %v", c, err) + } + p, err := SetPaused(true) + if err != nil || !p.Paused || !strings.Contains(p.Note, "held back") { + t.Fatalf("%+v, %v", p, err) + } + if c, _ := CloseAll(); !c.Paused { + t.Fatalf("close-all answers the counts: %+v", c) + } + if p, _ := SetPaused(false); p.Paused { + t.Fatalf("resumed: %+v", p) + } + log, _ := os.ReadFile(filepath.Join(bin, "log")) + if !strings.Contains(string(log), "close-all\n") { + t.Fatalf("dunstctl was asked:\n%s", log) + } +} + +func TestRulesAreTheRunningNotifiersWithTheFilesTheyComeFrom(t *testing.T) { + root := t.TempDir() + for _, f := range []string{"dunstrc", "dunstrc.d/50-slack.conf", "dunstrc.d/10-mail.conf", "dunstrc.d/notes.txt"} { + if err := os.MkdirAll(filepath.Dir(filepath.Join(root, f)), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(root, f), nil, 0o644); err != nil { + t.Fatal(err) + } + } + raw := `{"type":"aa{sv}","data":[[{"enabled":{"type":"b","data":true},"appname":{"type":"s","data":"Slack"}, + "fc":{"type":"s","data":"#6715ebff"},"name":{"type":"s","data":"slack"},"timeout":{"type":"x","data":10000000}}]]}` + got, err := parseRules(raw, configFiles(root)) + if err != nil { + t.Fatal(err) + } + if len(got.Rules) != 1 || got.Rules[0].Name != "slack" || !got.Rules[0].Enabled || got.Rules[0].Sets["appname"] != "Slack" { + t.Fatalf("%+v", got) + } + var names []string + for _, f := range got.Files { + rel, _ := filepath.Rel(root, f) + names = append(names, rel) + } + if !reflect.DeepEqual(names, []string{"dunstrc", "dunstrc.d/10-mail.conf", "dunstrc.d/50-slack.conf"}) { + t.Fatalf("files: %v", names) + } +} diff --git a/modules/dunst/cmd/dunst-tools/main.go b/modules/dunst/cmd/dunst-tools/main.go new file mode 100644 index 0000000..bd61453 --- /dev/null +++ b/modules/dunst/cmd/dunst-tools/main.go @@ -0,0 +1,91 @@ +// dunst's Go tools bundle (novox/hq ADR 0188, ADR 0193, ADR 0208): its implementation of +// node-notifier's verbs `send` and `history`, and its own tools, served by the node's runtime as the +// operator account. Everything here goes over the account's session bus; none of it needs the screen. +package main + +import ( + "fmt" + "os" + + stdio "git.novox.be/novox/mesh-sdk/go" +) + +func main() { + if err := stdio.Serve("", tools()); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func tools() []stdio.Tool { + return []stdio.Tool{ + { + Name: "node-notifier.send", + Description: "Show a notification on the operator's desktop: a title, a body, an urgency (low, " + + "normal, critical), and optionally the sending application's name, an icon and how long it stays. " + + "Answers the notification's id.", + Input: map[string]any{ + "type": "object", + "properties": map[string]any{ + "summary": map[string]any{"type": "string", "description": "the title"}, + "body": map[string]any{"type": "string", "description": "the text; simple markup (, , , ) is shown"}, + "urgency": map[string]any{"type": "string", "enum": urgencies, "description": "default normal"}, + "app_name": map[string]any{"type": "string", "description": "who it is from (default: mesh); a notifier rule can match it"}, + "icon": map[string]any{"type": "string", "description": "an icon name from the icon theme, or a file"}, + "expire_ms": map[string]any{"type": "integer", "description": "how long it stays; 0 until dismissed (default: the urgency's own)"}, + "category": map[string]any{"type": "string", "description": "a notification category, e.g. email.arrived"}, + "replace_id": map[string]any{"type": "integer", "description": "replace the notification with this id instead of adding one"}, + }, + "required": []string{"summary"}, + }, + Run: func(args map[string]any) (any, error) { + n, err := notificationOf(args) + if err != nil { + return nil, err + } + return Send(n) + }, + }, + { + Name: "node-notifier.history", + Description: "The notifications the operator was shown, newest first: id, application, title, " + + "body, urgency and how long ago.", + Input: map[string]any{ + "limit": map[string]any{"type": "integer", "description": "at most this many (default 20, at most 200)"}, + }, + Run: func(args map[string]any) (any, error) { + limit, err := whole(args, "limit", 20, 1, 200) + if err != nil { + return nil, err + } + return History(limit) + }, + }, + { + Name: "dunst_pause", + Description: "Do not disturb: hold every new notification back until resumed. They are shown then, not lost.", + Run: func(map[string]any) (any, error) { return SetPaused(true) }, + }, + { + Name: "dunst_resume", + Description: "End do-not-disturb: notifications held back are shown.", + Run: func(map[string]any) (any, error) { return SetPaused(false) }, + }, + { + Name: "dunst_close_all", + Description: "Close every notification on screen. They stay in the history.", + Run: func(map[string]any) (any, error) { return CloseAll() }, + }, + { + Name: "dunst_rules", + Description: "The notifier's rules in force — each rule's name, whether it is enabled, what it " + + "matches and what it sets — and the files they come from (the mesh's dunstrc, then dunstrc.d).", + Run: func(map[string]any) (any, error) { return Rules() }, + }, + { + Name: "dunst_count", + Description: "How many notifications are shown, waiting and in the history, and whether do-not-disturb is on.", + Run: func(map[string]any) (any, error) { return Count() }, + }, + } +} diff --git a/modules/dunst/cmd/dunst-tools/manifest_helpers_test.go b/modules/dunst/cmd/dunst-tools/manifest_helpers_test.go new file mode 100644 index 0000000..d4fb76d --- /dev/null +++ b/modules/dunst/cmd/dunst-tools/manifest_helpers_test.go @@ -0,0 +1,175 @@ +package main + +import ( + "encoding/json" + "os" + "path/filepath" + "strings" + "testing" +) + +// The module's manifest, read the way the catalogue reads it, for the manifest tests. The same in +// every desktop module that carries it. + +type manifest struct { + Module string `json:"module"` + Version string `json:"version"` + Capabilities []string `json:"capabilities"` + Requires []string `json:"requires"` + Claims []claim `json:"claims"` + Seats []any `json:"seats"` + Tools []string `json:"tools"` + Environment *environment `json:"environment"` + Shell []shellCode `json:"shell"` + Resources []map[string]any `json:"resources"` + Build struct { + Artifacts []map[string]any `json:"artifacts"` + } `json:"build"` +} + +type claim struct { + Name string `json:"name"` + Scope string `json:"scope"` + Serves []string `json:"serves"` +} + +type environment struct { + Variables map[string]string `json:"variables"` + Path []map[string]any `json:"path"` +} + +type shellCode struct { + For string `json:"for"` + Slot string `json:"slot"` + Code string `json:"code"` +} + +func readManifest(t *testing.T) manifest { + t.Helper() + raw, err := os.ReadFile(filepath.Join("..", "..", "module.json")) + if err != nil { + t.Fatal(err) + } + dec := json.NewDecoder(strings.NewReader(string(raw))) + dec.DisallowUnknownFields() + var m manifest + if err := dec.Decode(&m); err != nil { + t.Fatalf("module.json: %v", err) + } + return m +} + +func (m manifest) resource(t *testing.T, id string) map[string]any { + t.Helper() + for _, r := range m.Resources { + if r["id"] == id { + return r + } + } + t.Fatalf("no resource %q", id) + return nil +} + +func (m manifest) packages() (present, absent []string) { + for _, r := range m.Resources { + if r["type"] == "package" { + if r["absent"] == true { + absent = append(absent, r["package"].(string)) + } else { + present = append(present, r["package"].(string)) + } + } + } + return present, absent +} + +// sameAsSource checks that a file resource's content is byte for byte the module's source file, so +// the readable file in the repository is what the machine gets. +func (m manifest) sameAsSource(t *testing.T, id, source string) { + t.Helper() + want, err := os.ReadFile(filepath.Join("..", "..", source)) + if err != nil { + t.Fatal(err) + } + r := m.resource(t, id) + if r["type"] != "file" { + t.Fatalf("%s is a %v, not a file", id, r["type"]) + } + if got, _ := r["content"].(string); got != string(want) { + t.Fatalf("resource %s's content is not %s: edit the source and copy it into module.json", id, source) + } + if r["owner"] != "${machine:account}" && !strings.HasPrefix(r["path"].(string), "/etc/") { + t.Fatalf("%s under the home is the account's", id) + } +} + +// checkTheToolsAgree checks that the manifest lists the module's own tools exactly, that the bundle +// serves each seat verb the claims promise as ., and that the Go bundle is declared. +func checkTheToolsAgree(t *testing.T, m manifest) { + t.Helper() + own, seat := map[string]bool{}, map[string]bool{} + for _, tool := range tools() { + if strings.Contains(tool.Name, ".") { + seat[tool.Name] = true + } else { + own[tool.Name] = true + } + if strings.TrimSpace(tool.Description) == "" { + t.Errorf("%s has no description", tool.Name) + } + } + listed := map[string]bool{} + for _, name := range m.Tools { + listed[name] = true + if !own[name] { + t.Errorf("module.json lists %s, which the bundle does not serve", name) + } + } + for name := range own { + if !listed[name] { + t.Errorf("the bundle serves %s, which module.json does not list", name) + } + if !strings.HasPrefix(name, strings.ReplaceAll(m.Module, "-", "_")+"_") { + t.Errorf("%s is not prefixed with the module's name", name) + } + } + promised := map[string]bool{} + for _, c := range m.Claims { + for _, verb := range c.Serves { + promised[c.Name+"."+verb] = true + if !seat[c.Name+"."+verb] { + t.Errorf("the claim on %s promises %s, which the bundle does not serve", c.Name, verb) + } + } + } + for name := range seat { + if !promised[name] { + t.Errorf("the bundle serves %s, which no claim promises", name) + } + } + var bundle map[string]any + for _, a := range m.Build.Artifacts { + if a["kind"] == "bundle" { + bundle = a + } + } + if bundle == nil || bundle["language"] != "go" || bundle["system"] != "arch" || + bundle["from"] != "cmd/"+m.Module+"-tools" || bundle["binary"] != m.Module+"-tools" { + t.Errorf("the Go tools bundle: %v", bundle) + } +} + +// checkNoSecretsOrInstallationNames refuses what a catalogue manifest must never carry. +func checkNoSecretsOrInstallationNames(t *testing.T) { + t.Helper() + raw, err := os.ReadFile(filepath.Join("..", "..", "module.json")) + if err != nil { + t.Fatal(err) + } + s := strings.ToLower(string(raw)) + for _, never := range []string{"/home/", "jochen", "g14", "shanks", "novox.be", "api_key", ".hal/", "greenclip daemon"} { + if strings.Contains(s, never) { + t.Errorf("module.json names %q", never) + } + } +} diff --git a/modules/dunst/cmd/dunst-tools/manifest_test.go b/modules/dunst/cmd/dunst-tools/manifest_test.go new file mode 100644 index 0000000..6c7fb3e --- /dev/null +++ b/modules/dunst/cmd/dunst-tools/manifest_test.go @@ -0,0 +1,77 @@ +package main + +import ( + "reflect" + "strings" + "testing" +) + +// dunst's shape (novox/hq ADR 0208): it claims node-notifier serving send and history, owns its +// dunstrc and the drop-in directory other modules' rules go in, and starts nothing — D-Bus starts it +// on the first notification. It draws only once a notification arrives, through the bus's +// activation, so it requires no display of its own. + +func TestItClaimsTheNotifierSeatServingSendAndHistory(t *testing.T) { + m := readManifest(t) + if m.Module != "dunst" || m.Seats != nil { + t.Fatalf("module %q declares seats %v", m.Module, m.Seats) + } + if !reflect.DeepEqual(m.Claims, []claim{{Name: "node-notifier", Scope: "node", Serves: []string{"send", "history"}}}) { + t.Fatalf("claims: %+v", m.Claims) + } + if present, absent := m.packages(); !reflect.DeepEqual(present, []string{"dunst", "libnotify"}) || absent != nil { + t.Fatalf("packages: %v, absent %v", present, absent) + } +} + +func TestItOwnsItsFileAndTheDropInDirectory(t *testing.T) { + m := readManifest(t) + m.sameAsSource(t, "configuration", "files/dunstrc") + if p := m.resource(t, "configuration")["path"]; p != "${machine:account-home}/.config/dunst/dunstrc" { + t.Fatalf("path: %v", p) + } + if d := m.resource(t, "dropins"); d["type"] != "directory" || d["path"] != "${machine:account-home}/.config/dunst/dunstrc.d" { + t.Fatalf("drop-ins: %v", d) + } + for _, r := range m.Resources { + if p, _ := r["path"].(string); strings.Contains(p, "dunstrc.d/") { + t.Fatalf("a rule of another module's: %v", r) + } + } +} + +func TestTheFileIsTheDecidedOneAndCallsTheSeatsMenu(t *testing.T) { + m := readManifest(t) + c := m.resource(t, "configuration")["content"].(string) + for _, want := range []string{"origin = top-right", "transparency = 0", "corner_radius = 0", "font = Inter 10", "dmenu = dmenu -p dunst"} { + if !strings.Contains(c, " "+want+"\n") { + t.Errorf("lacks %q", want) + } + } + for _, never := range []string{"/usr/bin/dmenu", "Hack", "icon_path", "/home/"} { + if strings.Contains(c, never) { + t.Errorf("names %q", never) + } + } +} + +func TestNothingStartsItButTheBus(t *testing.T) { + m := readManifest(t) + if m.Shell != nil { + t.Fatalf("a session start: %+v", m.Shell) + } + for _, r := range m.Resources { + if r["type"] == "service" || r["type"] == "process" { + t.Fatalf("a unit: %v", r) + } + if p, _ := r["path"].(string); strings.Contains(p, "autostart") || strings.Contains(p, "i3/config.d") { + t.Fatalf("a start: %v", r) + } + } +} + +func TestTheToolsAgreeWithTheManifest(t *testing.T) { + m := readManifest(t) + checkTheToolsAgree(t, m) + checkNoSecretsOrInstallationNames(t) +} diff --git a/modules/dunst/cmd/dunst-tools/session.go b/modules/dunst/cmd/dunst-tools/session.go new file mode 100644 index 0000000..dc21774 --- /dev/null +++ b/modules/dunst/cmd/dunst-tools/session.go @@ -0,0 +1,423 @@ +// The operator's graphical session, as a tool the node's runtime runs finds it (novox/hq ADR 0208). +// +// The runtime is a system service running as the operator account (ADR 0175): it has the account's +// uid and none of the session's environment — no DISPLAY, no XAUTHORITY, no session bus. A tool that +// draws on the screen or talks to the desktop's D-Bus must find them. It reads them from a process of +// the account that is part of the session (the window manager first), the same thing `loginctl` and +// a person's own shell would point at, and says where it found them. +// +// Long-lived programs a tool starts go to the account's own service manager through `systemd-run +// --user`, never as children of the tool: the runtime's unit is a cgroup the service manager empties +// whenever the runtime restarts, and a compositor or a clipboard owner started from inside it would +// die with it. +// +// This file is the same in every desktop module that carries it; it moves into the Go SDK once a +// second consumer outside the desktop wants it. +package main + +import ( + "bytes" + "errors" + "fmt" + "os" + "os/exec" + "path/filepath" + "sort" + "strconv" + "strings" + "syscall" + "time" +) + +// Where the session is looked for. Variables so a test can point them at a fake tree. +var ( + procRoot = "/proc" + runUserDir = "/run/user" + x11Sockets = "/tmp/.X11-unix" +) + +// sessionHolders are the processes whose environment is the session's, best first: the window +// manager is the session, the rest are its children. Anything else carrying DISPLAY ranks after them. +var sessionHolders = []string{"i3", "sway", "i3bar", "picom", "xss-lock", "dunst", "clipmenud", "xterm"} + +// sessionKeys are the variables a session carries that a tool hands on to what it runs. +var sessionKeys = []string{"DISPLAY", "XAUTHORITY", "WAYLAND_DISPLAY", "DBUS_SESSION_BUS_ADDRESS", + "XDG_RUNTIME_DIR", "XDG_SESSION_ID", "I3SOCK"} + +// Session is what a tool needs to reach the operator's desktop. +type Session struct { + UID int `json:"uid"` + Display string `json:"display,omitempty"` + XAuthority string `json:"xauthority,omitempty"` + Wayland string `json:"wayland_display,omitempty"` + Bus string `json:"bus,omitempty"` + RuntimeDir string `json:"runtime_dir,omitempty"` + SessionID string `json:"session_id,omitempty"` + I3Sock string `json:"i3sock,omitempty"` + // From says where the values were found: the tool's own environment, a process, or the socket. + From string `json:"from"` +} + +// ErrNoSession is answered by a tool that needs the desktop when nobody is logged in to it. +var ErrNoSession = errors.New("no graphical session") + +// ErrTimedOut is what run answers for a command ended because it ran past its time. +var ErrTimedOut = errors.New("timed out") + +// ErrNoBus is answered by a tool that needs the session bus when the account has none. +var ErrNoBus = errors.New("no session bus") + +// operatorHome is the account's home: what the runtime was told, else the process's own. +func operatorHome() string { + if h := strings.TrimSpace(os.Getenv("MESH_OPERATOR_HOME")); h != "" { + return h + } + h, _ := os.UserHomeDir() + return h +} + +// findSession finds the graphical session of the account this tool runs as, or answers +// ErrNoSession with what it looked at. +func findSession() (Session, error) { + s := findEnvironment() + if s.Display == "" && s.Wayland == "" { + return s, fmt.Errorf("%w for uid %d on this machine: no process of the account carries DISPLAY "+ + "or WAYLAND_DISPLAY, and no X server socket in %s has an authority file to go with it. "+ + "Is anyone logged in to the desktop?", ErrNoSession, s.UID, x11Sockets) + } + return s, nil +} + +// findBus finds the account's session bus, which a logged-in account has whether or not a desktop +// is running. +func findBus() (Session, error) { + s := findEnvironment() + if s.Bus == "" { + return s, fmt.Errorf("%w for uid %d: DBUS_SESSION_BUS_ADDRESS is not set and %s does not exist "+ + "(the account is not logged in)", ErrNoBus, s.UID, filepath.Join(runUserDir, strconv.Itoa(s.UID), "bus")) + } + return s, nil +} + +func findEnvironment() Session { + uid := os.Getuid() + s := Session{UID: uid} + own := map[string]string{} + for _, k := range sessionKeys { + own[k] = os.Getenv(k) + } + if own["DISPLAY"] != "" || own["WAYLAND_DISPLAY"] != "" { + s.fill(own) + s.From = "the tool's own environment" + } else if pid, comm, env, ok := sessionProcess(uid); ok { + s.fill(env) + s.From = fmt.Sprintf("process %s (pid %d)", comm, pid) + } else if display, ok := lonelyX11Socket(); ok { + if a := filepath.Join(operatorHome(), ".Xauthority"); exists(a) { + s.Display, s.XAuthority = display, a + s.From = "the X server socket and the account's ~/.Xauthority" + } + s.fill(own) + } else { + s.fill(own) + s.From = "nothing: no session found" + } + // The bus and the runtime directory are the account's, whether or not the process named them. + runtime := filepath.Join(runUserDir, strconv.Itoa(uid)) + if s.RuntimeDir == "" && exists(runtime) { + s.RuntimeDir = runtime + } + if s.Bus == "" && s.RuntimeDir != "" && exists(filepath.Join(s.RuntimeDir, "bus")) { + s.Bus = "unix:path=" + filepath.Join(s.RuntimeDir, "bus") + } + return s +} + +func (s *Session) fill(env map[string]string) { + set := func(dst *string, key string) { + if *dst == "" { + *dst = env[key] + } + } + set(&s.Display, "DISPLAY") + set(&s.XAuthority, "XAUTHORITY") + set(&s.Wayland, "WAYLAND_DISPLAY") + set(&s.Bus, "DBUS_SESSION_BUS_ADDRESS") + set(&s.RuntimeDir, "XDG_RUNTIME_DIR") + set(&s.SessionID, "XDG_SESSION_ID") + set(&s.I3Sock, "I3SOCK") +} + +// sessionProcess is the best process of this uid whose environment names a display. +func sessionProcess(uid int) (int, string, map[string]string, bool) { + entries, err := os.ReadDir(procRoot) + if err != nil { + return 0, "", nil, false + } + type candidate struct { + pid int + comm string + env map[string]string + rank int + } + var found []candidate + for _, e := range entries { + pid, err := strconv.Atoi(e.Name()) + if err != nil { + continue + } + dir := filepath.Join(procRoot, e.Name()) + if owner, ok := ownerOf(dir); !ok || owner != uid { + continue + } + raw, err := os.ReadFile(filepath.Join(dir, "environ")) + if err != nil { + continue + } + env := parseEnviron(raw) + if env["DISPLAY"] == "" && env["WAYLAND_DISPLAY"] == "" { + continue + } + comm := readTrimmed(filepath.Join(dir, "comm")) + rank := len(sessionHolders) + for i, h := range sessionHolders { + if h == comm { + rank = i + break + } + } + found = append(found, candidate{pid, comm, env, rank}) + } + if len(found) == 0 { + return 0, "", nil, false + } + sort.Slice(found, func(i, j int) bool { + if found[i].rank != found[j].rank { + return found[i].rank < found[j].rank + } + return found[i].pid > found[j].pid // the newer of two equals + }) + best := found[0] + return best.pid, best.comm, best.env, true +} + +func parseEnviron(raw []byte) map[string]string { + env := map[string]string{} + for _, kv := range bytes.Split(raw, []byte{0}) { + if i := bytes.IndexByte(kv, '='); i > 0 { + env[string(kv[:i])] = string(kv[i+1:]) + } + } + return env +} + +func ownerOf(path string) (int, bool) { + info, err := os.Stat(path) + if err != nil { + return 0, false + } + st, ok := info.Sys().(*syscall.Stat_t) + if !ok { + return 0, false + } + return int(st.Uid), true +} + +// lonelyX11Socket is the display of the one X server socket there is, when there is exactly one. +func lonelyX11Socket() (string, bool) { + entries, err := os.ReadDir(x11Sockets) + if err != nil { + return "", false + } + var displays []string + for _, e := range entries { + if n := strings.TrimPrefix(e.Name(), "X"); n != e.Name() { + if _, err := strconv.Atoi(n); err == nil { + displays = append(displays, ":"+n) + } + } + } + if len(displays) != 1 { + return "", false + } + return displays[0], true +} + +func readTrimmed(path string) string { + b, err := os.ReadFile(path) + if err != nil { + return "" + } + return strings.TrimSpace(string(b)) +} + +func exists(path string) bool { + _, err := os.Stat(path) + return err == nil +} + +// Env is this process's environment with the session's variables in place of its own. +func (s Session) Env() []string { + drop := map[string]bool{} + for _, k := range sessionKeys { + drop[k] = true + } + var env []string + for _, kv := range os.Environ() { + if i := strings.IndexByte(kv, '='); i > 0 && drop[kv[:i]] { + continue + } + env = append(env, kv) + } + add := func(k, v string) { + if v != "" { + env = append(env, k+"="+v) + } + } + add("DISPLAY", s.Display) + add("XAUTHORITY", s.XAuthority) + add("WAYLAND_DISPLAY", s.Wayland) + add("DBUS_SESSION_BUS_ADDRESS", s.Bus) + add("XDG_RUNTIME_DIR", s.RuntimeDir) + add("XDG_SESSION_ID", s.SessionID) + add("I3SOCK", s.I3Sock) + return env +} + +// mostOutput bounds what a command may answer with, per stream. +const mostOutput = 256 << 10 + +// Result is what a command did. +type Result struct { + Stdout string `json:"stdout"` + Stderr string `json:"stderr,omitempty"` + Code int `json:"code"` + Truncated bool `json:"truncated,omitempty"` +} + +// run runs a command in the session's environment, its input given, ended with everything it +// started after timeout. A command that is not installed is an error naming it; one that exits +// non-zero is a Result with its code, for the caller to judge. +func (s Session) run(timeout time.Duration, stdin string, name string, args ...string) (Result, error) { + path, err := exec.LookPath(name) + if err != nil { + return Result{}, fmt.Errorf("%s is not installed on this machine", name) + } + cmd := exec.Command(path, args...) + cmd.Env = s.Env() + if home := operatorHome(); exists(home) { + cmd.Dir = home + } + if stdin != "" { + cmd.Stdin = strings.NewReader(stdin) + } + var out, errOut capped + cmd.Stdout, cmd.Stderr = &out, &errOut + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + if err := cmd.Start(); err != nil { + return Result{}, fmt.Errorf("%s: %w", name, err) + } + done := make(chan error, 1) + go func() { done <- cmd.Wait() }() + select { + case err = <-done: + case <-time.After(timeout): + _ = syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) + <-done + return Result{Stdout: out.String(), Stderr: errOut.String()}, + fmt.Errorf("%s did not finish within %s and was ended: %w", name, timeout, ErrTimedOut) + } + r := Result{Stdout: out.String(), Stderr: errOut.String(), Truncated: out.cut || errOut.cut} + var exit *exec.ExitError + if errors.As(err, &exit) { + r.Code = exit.ExitCode() + } else if err != nil { + return r, fmt.Errorf("%s: %w", name, err) + } + return r, nil +} + +// detach starts a long-lived program under the account's own service manager, as a transient unit +// that carries the session's display, so it outlives the runtime that asked for it. A unit already +// running under the same name is stopped first, so a fixed name means "at most one". +func (s Session) detach(unit string, args ...string) error { + if s.RuntimeDir == "" { + return fmt.Errorf("%w: the account's runtime directory is missing, so its service manager "+ + "cannot be reached", ErrNoBus) + } + _, _ = s.run(5*time.Second, "", "systemctl", "--user", "stop", unit+".service") + call := []string{"--user", "--collect", "--quiet", "--unit=" + unit} + for _, kv := range [][2]string{{"DISPLAY", s.Display}, {"XAUTHORITY", s.XAuthority}, + {"WAYLAND_DISPLAY", s.Wayland}, {"XDG_SESSION_ID", s.SessionID}, {"I3SOCK", s.I3Sock}} { + if kv[1] != "" { + call = append(call, "--setenv="+kv[0]+"="+kv[1]) + } + } + call = append(call, "--") + call = append(call, args...) + r, err := s.run(10*time.Second, "", "systemd-run", call...) + if err != nil { + return err + } + if r.Code != 0 { + return fmt.Errorf("systemd-run %s: %s", unit, strings.TrimSpace(r.Stderr)) + } + return nil +} + +// uniqueUnit is a transient unit name that will not collide with an earlier one. +func uniqueUnit(prefix string) string { + return fmt.Sprintf("%s-%d", prefix, time.Now().UnixNano()) +} + +type capped struct { + bytes.Buffer + cut bool +} + +func (c *capped) Write(p []byte) (int, error) { + if room := mostOutput - c.Len(); room < len(p) { + if room > 0 { + c.Buffer.Write(p[:room]) + } + c.cut = true + return len(p), nil + } + return c.Buffer.Write(p) +} + +// processesOf are the pids of this uid's processes whose command name is comm, oldest first. +func processesOf(comm string) []int { + entries, err := os.ReadDir(procRoot) + if err != nil { + return nil + } + uid := os.Getuid() + var pids []int + for _, e := range entries { + pid, err := strconv.Atoi(e.Name()) + if err != nil { + continue + } + dir := filepath.Join(procRoot, e.Name()) + if owner, ok := ownerOf(dir); !ok || owner != uid { + continue + } + if readTrimmed(filepath.Join(dir, "comm")) == comm { + pids = append(pids, pid) + } + } + sort.Ints(pids) + return pids +} + +// signalAll sends sig to every process of this uid named comm, and answers the pids it reached. +func signalAll(comm string, sig syscall.Signal) []int { + var reached []int + for _, pid := range processesOf(comm) { + if syscall.Kill(pid, sig) == nil { + reached = append(reached, pid) + } + } + return reached +} diff --git a/modules/dunst/cmd/dunst-tools/session_test.go b/modules/dunst/cmd/dunst-tools/session_test.go new file mode 100644 index 0000000..800cc6d --- /dev/null +++ b/modules/dunst/cmd/dunst-tools/session_test.go @@ -0,0 +1,174 @@ +package main + +import ( + "errors" + "os" + "path/filepath" + "strconv" + "strings" + "testing" + "time" +) + +// fakeMachine points the session finder at a temporary /proc, /run/user and X socket directory, with +// none of the test process's own session variables, and gives back the root. +func fakeMachine(t *testing.T) string { + t.Helper() + root := t.TempDir() + procRoot, runUserDir, x11Sockets = filepath.Join(root, "proc"), filepath.Join(root, "run-user"), filepath.Join(root, "x11") + for _, d := range []string{procRoot, runUserDir, x11Sockets} { + if err := os.MkdirAll(d, 0o755); err != nil { + t.Fatal(err) + } + } + for _, k := range sessionKeys { + t.Setenv(k, "") + } + t.Setenv("MESH_OPERATOR_HOME", filepath.Join(root, "home")) + t.Cleanup(func() { procRoot, runUserDir, x11Sockets = "/proc", "/run/user", "/tmp/.X11-unix" }) + return root +} + +func fakeProcess(t *testing.T, pid int, comm string, env ...string) { + t.Helper() + dir := filepath.Join(procRoot, strconv.Itoa(pid)) + if err := os.MkdirAll(dir, 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, "comm"), []byte(comm+"\n"), 0o644); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, "environ"), []byte(strings.Join(env, "\x00")+"\x00"), 0o600); err != nil { + t.Fatal(err) + } +} + +func TestTheSessionIsReadFromTheWindowManagerBeforeAnyOtherProcess(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 900, "xterm", "DISPLAY=:9", "XAUTHORITY=/elsewhere") + fakeProcess(t, 100, "i3", "DISPLAY=:1", "XAUTHORITY=/home/op/.Xauthority", + "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus", "XDG_SESSION_ID=3", "SECRET_TOKEN=never-copied") + fakeProcess(t, 50, "bash", "PATH=/usr/bin") + s, err := findSession() + if err != nil { + t.Fatal(err) + } + if s.Display != ":1" || s.XAuthority != "/home/op/.Xauthority" || s.SessionID != "3" || !strings.Contains(s.From, "i3 (pid 100)") { + t.Fatalf("the window manager's environment: %+v", s) + } + for _, kv := range s.Env() { + if strings.HasPrefix(kv, "SECRET_TOKEN=") { + t.Fatal("a variable of the session process that is not a session variable was handed on") + } + } +} + +func TestAnyProcessCarryingADisplayServesWhenTheWindowManagerIsNotFound(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 10, "firefox", "DISPLAY=:0") + fakeProcess(t, 20, "firefox", "DISPLAY=:2") + s, err := findSession() + if err != nil || s.Display != ":2" { + t.Fatalf("the newest of two equals: %+v, %v", s, err) + } +} + +func TestNoSessionIsAClearAnswerNotAGuess(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 10, "sshd", "PATH=/usr/bin") + _, err := findSession() + if !errors.Is(err, ErrNoSession) || !strings.Contains(err.Error(), "logged in to the desktop") { + t.Fatalf("no session: %v", err) + } +} + +func TestOneXSocketAndTheAccountsAuthorityFileAreASession(t *testing.T) { + root := fakeMachine(t) + if err := os.WriteFile(filepath.Join(x11Sockets, "X0"), nil, 0o644); err != nil { + t.Fatal(err) + } + if err := os.MkdirAll(filepath.Join(root, "home"), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(root, "home", ".Xauthority"), nil, 0o600); err != nil { + t.Fatal(err) + } + s, err := findSession() + if err != nil || s.Display != ":0" || !strings.HasSuffix(s.XAuthority, "/home/.Xauthority") { + t.Fatalf("socket and authority: %+v, %v", s, err) + } +} + +func TestTheBusIsTheAccountsRuntimeDirectoryWhenNoProcessNamesIt(t *testing.T) { + fakeMachine(t) + runtime := filepath.Join(runUserDir, strconv.Itoa(os.Getuid())) + if _, err := findBus(); !errors.Is(err, ErrNoBus) { + t.Fatalf("no runtime directory is no bus: %v", err) + } + if err := os.MkdirAll(runtime, 0o700); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(runtime, "bus"), nil, 0o600); err != nil { + t.Fatal(err) + } + s, err := findBus() + if err != nil || s.Bus != "unix:path="+filepath.Join(runtime, "bus") || s.RuntimeDir != runtime { + t.Fatalf("bus: %+v, %v", s, err) + } + env := strings.Join(s.Env(), "\n") + if !strings.Contains(env, "XDG_RUNTIME_DIR="+runtime) || !strings.Contains(env, "DBUS_SESSION_BUS_ADDRESS=unix:path=") { + t.Fatalf("the bus is handed on: %s", env) + } +} + +func TestACommandIsBoundedAndANonZeroExitIsAResult(t *testing.T) { + fakeMachine(t) + s := Session{} + r, err := s.run(5*time.Second, "in", "sh", "-c", "cat; echo err >&2; exit 3") + if err != nil || r.Stdout != "in" || r.Code != 3 || strings.TrimSpace(r.Stderr) != "err" { + t.Fatalf("result: %+v, %v", r, err) + } + start := time.Now() + if _, err := s.run(200*time.Millisecond, "", "sh", "-c", "sleep 30 & sleep 30"); err == nil || time.Since(start) > 5*time.Second { + t.Fatalf("a command past its time is ended with what it started: %v after %s", err, time.Since(start)) + } + if _, err := s.run(time.Second, "", "no-such-program-here"); err == nil || !strings.Contains(err.Error(), "not installed") { + t.Fatalf("a missing program: %v", err) + } +} + +func TestDetachAsksTheAccountsServiceManagerWithTheSessionsDisplay(t *testing.T) { + fakeMachine(t) + bin := fakeBinaries(t, map[string]string{ + "systemctl": `echo "systemctl $*" >> "$LOG"`, + "systemd-run": `echo "systemd-run $*" >> "$LOG"`, + }) + log := filepath.Join(bin, "log") + t.Setenv("LOG", log) + s := Session{Display: ":1", XAuthority: "/x", RuntimeDir: "/run/user/1"} + if err := s.detach("picom-session", "picom", "--config", "/c"); err != nil { + t.Fatal(err) + } + got, _ := os.ReadFile(log) + want := "systemctl --user stop picom-session.service\n" + + "systemd-run --user --collect --quiet --unit=picom-session --setenv=DISPLAY=:1 --setenv=XAUTHORITY=/x -- picom --config /c\n" + if string(got) != want { + t.Fatalf("detach ran:\n%s\nwant:\n%s", got, want) + } + if err := (Session{}).detach("x", "y"); !errors.Is(err, ErrNoBus) { + t.Fatalf("no runtime directory: %v", err) + } +} + +// fakeBinaries puts shell scripts named for programs first on PATH, and answers their directory. +func fakeBinaries(t *testing.T, scripts map[string]string) string { + t.Helper() + dir := t.TempDir() + for name, body := range scripts { + if err := os.WriteFile(filepath.Join(dir, name), []byte("#!/bin/sh\n"+body+"\n"), 0o755); err != nil { + t.Fatal(err) + } + } + t.Setenv("PATH", dir+string(os.PathListSeparator)+os.Getenv("PATH")) + return dir +} diff --git a/modules/dunst/files/dunstrc b/modules/dunst/files/dunstrc new file mode 100644 index 0000000..f504485 --- /dev/null +++ b/modules/dunst/files/dunstrc @@ -0,0 +1,92 @@ +# dunst, the notifier (module dunst, novox/hq ADR 0208). Owned by the mesh: this file is replaced +# at every push. Adopted from the laptop's file of 2026-10-04 (the two workstations differed in +# position, transparency and corner radius; the laptop's square, opaque, top-right one matches the +# rest of the desktop). Only what differs from dunst's defaults, and what the desktop relies on. +# +# Other modules' rules go in ~/.config/dunst/dunstrc.d/*.conf, which dunst reads after this file, +# so a drop-in outranks it. dunst is started by D-Bus on the first notification: nothing starts it. + +[global] + monitor = 0 + follow = none + + # Geometry + width = 250 + height = (0, 300) + origin = top-right + offset = (10, 50) + notification_limit = 20 + + progress_bar = true + progress_bar_height = 10 + progress_bar_frame_width = 1 + progress_bar_min_width = 150 + progress_bar_max_width = 300 + + indicate_hidden = yes + transparency = 0 + separator_height = 2 + padding = 8 + horizontal_padding = 8 + text_icon_padding = 0 + frame_width = 3 + frame_color = "#de5200" + gap_size = 0 + separator_color = frame + sort = yes + corner_radius = 0 + + # Text: the interface face (research 026/04) + font = Inter 10 + line_height = 0 + markup = full + format = "%s\n%b" + alignment = left + vertical_alignment = center + show_age_threshold = 60 + ellipsize = middle + ignore_newline = no + stack_duplicates = true + hide_duplicate_count = false + show_indicators = yes + + # Icons, from the desktop's icon theme + enable_recursive_icon_lookup = true + icon_theme = Adwaita + icon_position = left + min_icon_size = 32 + max_icon_size = 128 + + # History + sticky_history = yes + history_length = 20 + + # The context menu is the node's dmenu-compatible command, which the holder of node-launcher + # answers (rofi on the workstations). Links open in the desktop's default browser. + dmenu = dmenu -p dunst + browser = /usr/bin/xdg-open + always_run_script = true + + title = Dunst + class = Dunst + ignore_dbusclose = false + + mouse_left_click = close_current + mouse_middle_click = do_action, close_current + mouse_right_click = close_all + +[urgency_low] + background = "#000000" + foreground = "#ffffff" + timeout = 10 + +[urgency_normal] + background = "#000000" + foreground = "#ffffff" + timeout = 10 + +[urgency_critical] + background = "#000000" + foreground = "#ffffff" + frame_color = "#ff0000" + timeout = 0 diff --git a/modules/dunst/go.mod b/modules/dunst/go.mod new file mode 100644 index 0000000..d26e306 --- /dev/null +++ b/modules/dunst/go.mod @@ -0,0 +1,5 @@ +module dunst + +go 1.22 + +require git.novox.be/novox/mesh-sdk/go v0.1.7 diff --git a/modules/dunst/go.sum b/modules/dunst/go.sum new file mode 100644 index 0000000..b474419 --- /dev/null +++ b/modules/dunst/go.sum @@ -0,0 +1,2 @@ +git.novox.be/novox/mesh-sdk/go v0.1.7 h1:C0sTQmtTiyYH7bnqZb7PusXnqA37gKuT7Nqjn9gG47w= +git.novox.be/novox/mesh-sdk/go v0.1.7/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= diff --git a/modules/dunst/module.json b/modules/dunst/module.json new file mode 100644 index 0000000..6718098 --- /dev/null +++ b/modules/dunst/module.json @@ -0,0 +1,73 @@ +{ + "module": "dunst", + "version": "1", + "capabilities": [ + "package-manager" + ], + "claims": [ + { + "name": "node-notifier", + "scope": "node", + "serves": [ + "send", + "history" + ] + } + ], + "tools": [ + "dunst_pause", + "dunst_resume", + "dunst_close_all", + "dunst_rules", + "dunst_count" + ], + "resources": [ + { + "id": "package", + "type": "package", + "package": "dunst" + }, + { + "id": "client", + "type": "package", + "package": "libnotify" + }, + { + "id": "configuration-dir", + "type": "directory", + "path": "${machine:account-home}/.config/dunst", + "owner": "${machine:account}", + "mode": "0755" + }, + { + "id": "dropins", + "type": "directory", + "path": "${machine:account-home}/.config/dunst/dunstrc.d", + "owner": "${machine:account}", + "mode": "0755" + }, + { + "id": "configuration", + "type": "file", + "path": "${machine:account-home}/.config/dunst/dunstrc", + "owner": "${machine:account}", + "mode": "0644", + "content": "# dunst, the notifier (module dunst, novox/hq ADR 0208). Owned by the mesh: this file is replaced\n# at every push. Adopted from the laptop's file of 2026-10-04 (the two workstations differed in\n# position, transparency and corner radius; the laptop's square, opaque, top-right one matches the\n# rest of the desktop). Only what differs from dunst's defaults, and what the desktop relies on.\n#\n# Other modules' rules go in ~/.config/dunst/dunstrc.d/*.conf, which dunst reads after this file,\n# so a drop-in outranks it. dunst is started by D-Bus on the first notification: nothing starts it.\n\n[global]\n monitor = 0\n follow = none\n\n # Geometry\n width = 250\n height = (0, 300)\n origin = top-right\n offset = (10, 50)\n notification_limit = 20\n\n progress_bar = true\n progress_bar_height = 10\n progress_bar_frame_width = 1\n progress_bar_min_width = 150\n progress_bar_max_width = 300\n\n indicate_hidden = yes\n transparency = 0\n separator_height = 2\n padding = 8\n horizontal_padding = 8\n text_icon_padding = 0\n frame_width = 3\n frame_color = \"#de5200\"\n gap_size = 0\n separator_color = frame\n sort = yes\n corner_radius = 0\n\n # Text: the interface face (research 026/04)\n font = Inter 10\n line_height = 0\n markup = full\n format = \"%s\\n%b\"\n alignment = left\n vertical_alignment = center\n show_age_threshold = 60\n ellipsize = middle\n ignore_newline = no\n stack_duplicates = true\n hide_duplicate_count = false\n show_indicators = yes\n\n # Icons, from the desktop's icon theme\n enable_recursive_icon_lookup = true\n icon_theme = Adwaita\n icon_position = left\n min_icon_size = 32\n max_icon_size = 128\n\n # History\n sticky_history = yes\n history_length = 20\n\n # The context menu is the node's dmenu-compatible command, which the holder of node-launcher\n # answers (rofi on the workstations). Links open in the desktop's default browser.\n dmenu = dmenu -p dunst\n browser = /usr/bin/xdg-open\n always_run_script = true\n\n title = Dunst\n class = Dunst\n ignore_dbusclose = false\n\n mouse_left_click = close_current\n mouse_middle_click = do_action, close_current\n mouse_right_click = close_all\n\n[urgency_low]\n background = \"#000000\"\n foreground = \"#ffffff\"\n timeout = 10\n\n[urgency_normal]\n background = \"#000000\"\n foreground = \"#ffffff\"\n timeout = 10\n\n[urgency_critical]\n background = \"#000000\"\n foreground = \"#ffffff\"\n frame_color = \"#ff0000\"\n timeout = 0\n" + } + ], + "build": { + "artifacts": [ + { + "name": "tools", + "kind": "bundle", + "language": "go", + "system": "arch", + "from": "cmd/dunst-tools", + "binary": "dunst-tools", + "loads": [ + "dunst-tools" + ] + } + ] + } +} From 0fa90e5cf210f7983dfd8409af8a78bb440be8b6 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 4 Oct 2026 12:56:35 +0200 Subject: [PATCH 04/15] screen-lock: the lock screen as a module, claiming node-lock-screen and serving lock (hq ADR 0208) The distribution's i3lock behind a locker that releases xss-lock's sleep lock once it is up; timeouts and xss-lock from the session's xinitrc slot, ending with the session; i3lock-color and xscreensaver declared absent; Go tools lock, idle, inhibit and locked. --- modules/screen-lock/README.md | 73 +++ .../screen-lock/cmd/screen-lock-tools/args.go | 97 ++++ .../screen-lock/cmd/screen-lock-tools/lock.go | 337 ++++++++++++++ .../cmd/screen-lock-tools/lock_test.go | 189 ++++++++ .../screen-lock/cmd/screen-lock-tools/main.go | 78 ++++ .../manifest_helpers_test.go | 175 ++++++++ .../cmd/screen-lock-tools/manifest_test.go | 84 ++++ .../cmd/screen-lock-tools/session.go | 423 ++++++++++++++++++ .../cmd/screen-lock-tools/session_test.go | 174 +++++++ modules/screen-lock/files/bin/screen-lock | 34 ++ modules/screen-lock/go.mod | 5 + modules/screen-lock/go.sum | 2 + modules/screen-lock/module.json | 78 ++++ 13 files changed, 1749 insertions(+) create mode 100644 modules/screen-lock/README.md create mode 100644 modules/screen-lock/cmd/screen-lock-tools/args.go create mode 100644 modules/screen-lock/cmd/screen-lock-tools/lock.go create mode 100644 modules/screen-lock/cmd/screen-lock-tools/lock_test.go create mode 100644 modules/screen-lock/cmd/screen-lock-tools/main.go create mode 100644 modules/screen-lock/cmd/screen-lock-tools/manifest_helpers_test.go create mode 100644 modules/screen-lock/cmd/screen-lock-tools/manifest_test.go create mode 100644 modules/screen-lock/cmd/screen-lock-tools/session.go create mode 100644 modules/screen-lock/cmd/screen-lock-tools/session_test.go create mode 100755 modules/screen-lock/files/bin/screen-lock create mode 100644 modules/screen-lock/go.mod create mode 100644 modules/screen-lock/go.sum create mode 100644 modules/screen-lock/module.json diff --git a/modules/screen-lock/README.md b/modules/screen-lock/README.md new file mode 100644 index 0000000..1b3e442 --- /dev/null +++ b/modules/screen-lock/README.md @@ -0,0 +1,73 @@ +# screen-lock + +The lock screen, idle timeouts and display power as one module (novox/hq ADR 0208, research +026/04). + +- Installs `xss-lock` and the distribution's `i3lock`. Claims the mesh's `node-lock-screen` seat and + serves its verb `lock`. Requires `x11-display` on its own machine. +- **Declares absent** (ADR 0180), as replaced and not coming back: + - `i3lock-color`, the colour build from the user repository; + - `xscreensaver`, a second screensaver that was installed and deliberately never started. +- Places the locker `~/.local/bin/screen-lock`. The lock key (`$mod+Delete`) is the `i3` module's. + It asks logind to lock and names no locker, so it does not depend on which module holds the seat. +- At session start, through the `xinitrc` slot `normal`, it: + - sets the timeouts: lock after 30 minutes idle, displays to standby and suspend at 30 minutes and + off at 60; + - starts `xss-lock --transfer-sleep-lock`, which runs the locker on idle, before suspend and on + logind's Lock, so the lock key, a closed lid and a suspend all lead to one locker. + + xss-lock stays out of the units on purpose. It must find its own login session, and a user unit + runs in the service manager's session instead, where xss-lock silently finds none. + +## Tools + +| tool | does | +|---|---| +| `node-lock-screen.lock` | lock now, through logind, so the session's one locker answers; answers since when | +| `screen_lock_idle` | the idle and display power timeouts in force; change any of them for this session | +| `screen_lock_inhibit` | keep the screen on and unlocked for N minutes, then restore; 0 ends it early | +| `screen_lock_locked` | locked or not and since when, whether xss-lock runs, whether an inhibition holds | + +An inhibition runs under the account's service manager (`screen-lock-inhibit.service`). Stopping it +restores the timeouts at once. It holds off the idle lock and display power only: a lock asked for by +hand, by the lid or before suspend still locks. + +## Decided: the distribution's i3lock now + +The colour build lives in the user repository, and the colours are the only difference. The module +uses the official `i3lock` (black, failed attempts shown, an empty Enter ignored). The colour build +can come back as a pinned archive of this module (ADR 0205). That is a follow-up, and only the +locker's options change with it. + +## What it improves on what was found + +- **The machine no longer waits for the unlock to suspend.** The found wrapper started i3lock with + xss-lock's sleep lock inherited, so a suspend was held until logind's delay ran out. The new locker + follows xss-lock's own pattern: the lock is released as soon as i3lock is up. +- **One locker.** A second lock while locked does nothing. The power menu locks through logind + instead of starting its own i3lock. +- **The respawn loop ends with the session.** The found loop kept retrying every two seconds after + logout. +- **The timeouts are set once, in one place.** On the laptop, measured on 2026-10-04, the screensaver + timeout in force was 600 s, not the 1800 s the start script asked for. + +## What it leaves as found + +- `~/.xscreensaver`, xscreensaver's configuration file. Remove it once the package is gone. +- `~/scripts/my-i3lock`, the predecessor's wrapper, which only the colour build understands. + +## Migration (ADR 0182) + +1. **Before the first push,** remove the colour build by hand: `sudo pacman -R i3lock-color`. + `pacman --noconfirm` will not replace a conflicting package. If the host installs `i3lock` before + it removes `i3lock-color`, the first push fails on the conflict. +2. Once the `xorg` module writes the session's start, delete from your own part of `~/.xinitrc`: + - the `xset s` and `xset dpms` lines; + - the `while true; do xss-lock … my-i3lock; …; done &` loop. +3. Delete `~/.xscreensaver` and `~/scripts/my-i3lock`. + +## Blockers + +- `node-lock-screen`, `x11-display` and the `xinitrc` slot are ADR 0208's. Until the controller knows + them, `mctl` reads them as unknown. +- `xset` comes with the display server's module (`xorg`). diff --git a/modules/screen-lock/cmd/screen-lock-tools/args.go b/modules/screen-lock/cmd/screen-lock-tools/args.go new file mode 100644 index 0000000..9b5dfcf --- /dev/null +++ b/modules/screen-lock/cmd/screen-lock-tools/args.go @@ -0,0 +1,97 @@ +// Reading a tool's arguments: JSON numbers arrive as float64, and a missing argument is its default. +// The same in every desktop module that carries it. +package main + +import ( + "fmt" + "math" + "strings" + "time" +) + +// text is a string argument, trimmed; required says an empty one is refused. +func text(args map[string]any, key string, required bool) (string, error) { + v, present := args[key] + if !present || v == nil { + if required { + return "", fmt.Errorf("%s is required", key) + } + return "", nil + } + s, ok := v.(string) + if !ok { + return "", fmt.Errorf("%s is a string, not %T", key, v) + } + s = strings.TrimSpace(s) + if s == "" && required { + return "", fmt.Errorf("%s is required", key) + } + return s, nil +} + +// whole is a whole-number argument within [least, most], or def when absent. +func whole(args map[string]any, key string, def, least, most int) (int, error) { + v, present := args[key] + if !present || v == nil { + return def, nil + } + f, ok := v.(float64) + if !ok { + if i, isInt := v.(int); isInt { + f = float64(i) + } else { + return 0, fmt.Errorf("%s is a number, not %T", key, v) + } + } + if f != math.Trunc(f) { + return 0, fmt.Errorf("%s is a whole number, not %v", key, f) + } + n := int(f) + if n < least || n > most { + return 0, fmt.Errorf("%s is %d; it is between %d and %d", key, n, least, most) + } + return n, nil +} + +// flag is a boolean argument, or def when absent. +func flag(args map[string]any, key string, def bool) (bool, error) { + v, present := args[key] + if !present || v == nil { + return def, nil + } + b, ok := v.(bool) + if !ok { + return false, fmt.Errorf("%s is true or false, not %T", key, v) + } + return b, nil +} + +// texts is a list-of-strings argument. +func texts(args map[string]any, key string) ([]string, error) { + v, present := args[key] + if !present || v == nil { + return nil, nil + } + list, ok := v.([]any) + if !ok { + if ss, isStrings := v.([]string); isStrings { + return ss, nil + } + return nil, fmt.Errorf("%s is a list of strings, not %T", key, v) + } + out := make([]string, 0, len(list)) + for i, item := range list { + s, ok := item.(string) + if !ok { + return nil, fmt.Errorf("%s[%d] is a string, not %T", key, i, item) + } + out = append(out, s) + } + return out, nil +} + +// seconds is a timeout argument in seconds, defaulted and bounded below the runtime's call limit. +func seconds(args map[string]any, key string, def, most int) (time.Duration, error) { + n, err := whole(args, key, def, 1, most) + return time.Duration(n) * time.Second, err +} diff --git a/modules/screen-lock/cmd/screen-lock-tools/lock.go b/modules/screen-lock/cmd/screen-lock-tools/lock.go new file mode 100644 index 0000000..cd74ae9 --- /dev/null +++ b/modules/screen-lock/cmd/screen-lock-tools/lock.go @@ -0,0 +1,337 @@ +package main + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "regexp" + "strconv" + "strings" + "time" +) + +// The declared timeouts, which the session start sets (module.json's xinitrc contribution) and an +// inhibition returns to when it cannot read what was in force. +const ( + declaredLock = 1800 + declaredStandby = 1800 + declaredSuspend = 1800 + declaredOff = 3600 + + mostInhibit = 600 + + inhibitUnit = "screen-lock-inhibit" + lockerUnit = "screen-lock" +) + +// clockTicks is the kernel's USER_HZ, which /proc//stat counts a start time in: 100 on every +// architecture Arch Linux builds for. +const clockTicks = 100 + +func locker() string { return filepath.Join(operatorHome(), ".local", "bin", "screen-lock") } + +// LockState is what lock and locked answer. +type LockState struct { + Locked bool `json:"locked"` + // Since is when the locker started, when it runs. + Since string `json:"since,omitempty"` + PIDs []int `json:"pids"` + LockedHint *bool `json:"locked_hint,omitempty"` + Watcher bool `json:"watcher_running"` + Inhibited bool `json:"inhibited"` + Via string `json:"via,omitempty"` +} + +// Lock locks through logind when the watcher runs, else runs the locker itself. +func Lock() (LockState, error) { + s, err := findSession() + if err != nil { + return LockState{}, err + } + via := "" + switch { + case len(processesOf("i3lock")) > 0: + via = "already locked" + case len(processesOf("xss-lock")) > 0 && s.SessionID != "": + r, err := s.run(10*time.Second, "", "loginctl", "lock-session", s.SessionID) + if err != nil { + return LockState{}, err + } + if r.Code != 0 { + return LockState{}, fmt.Errorf("loginctl lock-session %s: %s", s.SessionID, strings.TrimSpace(r.Stderr)) + } + via = "logind, answered by xss-lock" + default: + // No watcher: the session start's loop is not running (a session begun before this module + // was assigned). The locker is run directly, under the account's service manager. + if err := s.detach(lockerUnit, locker()); err != nil { + return LockState{}, err + } + via = "the locker directly: xss-lock is not running in this session" + } + deadline := time.Now().Add(3 * time.Second) + for len(processesOf("i3lock")) == 0 && time.Now().Before(deadline) { + time.Sleep(100 * time.Millisecond) + } + state := lockState(s) + state.Via = via + if !state.Locked { + return state, errors.New("asked to lock, and no locker is running 3s later") + } + return state, nil +} + +// Locked answers the lock state without changing it. +func Locked() (LockState, error) { + s := findEnvironment() + return lockState(s), nil +} + +func lockState(s Session) LockState { + pids := processesOf("i3lock") + st := LockState{Locked: len(pids) > 0, PIDs: pids, Watcher: len(processesOf("xss-lock")) > 0} + if st.PIDs == nil { + st.PIDs = []int{} + } + if len(pids) > 0 { + if at, ok := startTime(pids[0]); ok { + st.Since = at.Format(time.RFC3339) + } + } + if s.SessionID != "" { + if r, err := s.run(5*time.Second, "", "loginctl", "show-session", s.SessionID, "-p", "LockedHint", "--value"); err == nil && r.Code == 0 { + hint := strings.TrimSpace(r.Stdout) == "yes" + st.LockedHint = &hint + } + } + if s.RuntimeDir != "" { + if r, err := s.run(5*time.Second, "", "systemctl", "--user", "is-active", inhibitUnit+".service"); err == nil { + st.Inhibited = strings.TrimSpace(r.Stdout) == "active" + } + } + return st +} + +// startTime is when a process started, from its start in clock ticks after boot and the boot time. +func startTime(pid int) (time.Time, bool) { + stat, err := os.ReadFile(filepath.Join(procRoot, strconv.Itoa(pid), "stat")) + if err != nil { + return time.Time{}, false + } + // The command name is in parentheses and may hold spaces; the fields after it are fixed. + end := strings.LastIndexByte(string(stat), ')') + if end < 0 { + return time.Time{}, false + } + fields := strings.Fields(string(stat[end+1:])) + // starttime is field 22 of the whole line; after "pid (comm)" it is the 20th. + if len(fields) < 20 { + return time.Time{}, false + } + ticks, err := strconv.ParseInt(fields[19], 10, 64) + if err != nil { + return time.Time{}, false + } + boot, ok := bootTime() + if !ok { + return time.Time{}, false + } + return boot.Add(time.Duration(ticks) * time.Second / clockTicks), true +} + +func bootTime() (time.Time, bool) { + raw, err := os.ReadFile(filepath.Join(procRoot, "stat")) + if err != nil { + return time.Time{}, false + } + for _, line := range strings.Split(string(raw), "\n") { + if v, ok := strings.CutPrefix(line, "btime "); ok { + n, err := strconv.ParseInt(strings.TrimSpace(v), 10, 64) + if err == nil { + return time.Unix(n, 0), true + } + } + } + return time.Time{}, false +} + +// IdleState is the screen's idle timeouts in force. +type IdleState struct { + LockAfterSeconds int `json:"lock_after_seconds"` + CycleSeconds int `json:"cycle_seconds"` + DPMSEnabled bool `json:"dpms_enabled"` + StandbySeconds int `json:"standby_seconds"` + SuspendSeconds int `json:"suspend_seconds"` + OffSeconds int `json:"off_seconds"` + MonitorOn bool `json:"monitor_on"` + Declared string `json:"declared"` + Note string `json:"note,omitempty"` +} + +var ( + screensaverLine = regexp.MustCompile(`timeout:\s+(\d+)\s+cycle:\s+(\d+)`) + dpmsLine = regexp.MustCompile(`Standby:\s+(\d+)\s+Suspend:\s+(\d+)\s+Off:\s+(\d+)`) +) + +func parseXsetQ(out string) (IdleState, error) { + var st IdleState + m := screensaverLine.FindStringSubmatch(out) + if m == nil { + return st, errors.New("xset q shows no screensaver timeout") + } + st.LockAfterSeconds, _ = strconv.Atoi(m[1]) + st.CycleSeconds, _ = strconv.Atoi(m[2]) + if d := dpmsLine.FindStringSubmatch(out); d != nil { + st.StandbySeconds, _ = strconv.Atoi(d[1]) + st.SuspendSeconds, _ = strconv.Atoi(d[2]) + st.OffSeconds, _ = strconv.Atoi(d[3]) + } + st.DPMSEnabled = strings.Contains(out, "DPMS is Enabled") + st.MonitorOn = strings.Contains(out, "Monitor is On") + st.Declared = fmt.Sprintf("lock after %ds; DPMS %d/%d/%d", declaredLock, declaredStandby, declaredSuspend, declaredOff) + return st, nil +} + +// IdleChange is what screen_lock_idle was asked to change; nil fields stay. +type IdleChange struct { + LockAfter, Standby, Suspend, Off *int +} + +func idleChangeOf(args map[string]any) (IdleChange, error) { + var c IdleChange + for key, into := range map[string]**int{ + "lock_after_seconds": &c.LockAfter, "standby_seconds": &c.Standby, + "suspend_seconds": &c.Suspend, "off_seconds": &c.Off, + } { + if _, given := args[key]; !given { + continue + } + n, err := whole(args, key, 0, 0, 24*3600) + if err != nil { + return c, err + } + *into = &n + } + return c, nil +} + +func (c IdleChange) empty() bool { + return c.LockAfter == nil && c.Standby == nil && c.Suspend == nil && c.Off == nil +} + +// Idle reads the timeouts, and changes those asked for. +func Idle(change IdleChange) (IdleState, error) { + s, err := findSession() + if err != nil { + return IdleState{}, err + } + before, err := xsetQ(s) + if err != nil { + return IdleState{}, err + } + if change.empty() { + return before, nil + } + if change.LockAfter != nil { + cycle := before.CycleSeconds + if *change.LockAfter > 0 && cycle == 0 { + cycle = *change.LockAfter + } + if err := xset(s, "s", strconv.Itoa(*change.LockAfter), strconv.Itoa(cycle)); err != nil { + return IdleState{}, err + } + } + if change.Standby != nil || change.Suspend != nil || change.Off != nil { + pick := func(c *int, was int) string { + if c != nil { + return strconv.Itoa(*c) + } + return strconv.Itoa(was) + } + if err := xset(s, "dpms", pick(change.Standby, before.StandbySeconds), pick(change.Suspend, before.SuspendSeconds), + pick(change.Off, before.OffSeconds)); err != nil { + return IdleState{}, err + } + } + after, err := xsetQ(s) + if err != nil { + return IdleState{}, err + } + after.Note = "changed for this session only; the declared timeouts return at the next login" + return after, nil +} + +func xsetQ(s Session) (IdleState, error) { + r, err := s.run(5*time.Second, "", "xset", "q") + if err != nil { + return IdleState{}, err + } + if r.Code != 0 { + return IdleState{}, fmt.Errorf("xset q: %s", strings.TrimSpace(r.Stderr)) + } + return parseXsetQ(r.Stdout) +} + +func xset(s Session, args ...string) error { + r, err := s.run(5*time.Second, "", "xset", args...) + if err != nil { + return err + } + if r.Code != 0 { + return fmt.Errorf("xset %s: %s", strings.Join(args, " "), strings.TrimSpace(r.Stderr)) + } + return nil +} + +// InhibitResult is what screen_lock_inhibit answers. +type InhibitResult struct { + Inhibited bool `json:"inhibited"` + Until string `json:"until,omitempty"` + Restores string `json:"restores,omitempty"` +} + +// Inhibit keeps the screen on for minutes, then restores the timeouts that were in force; 0 ends an +// inhibition now. The waiting runs under the account's service manager, so it outlives this call, +// and stopping it restores at once. +func Inhibit(minutes int) (InhibitResult, error) { + s, err := findSession() + if err != nil { + return InhibitResult{}, err + } + if minutes == 0 { + r, err := s.run(10*time.Second, "", "systemctl", "--user", "stop", inhibitUnit+".service") + if err != nil { + return InhibitResult{}, err + } + if r.Code != 0 { + return InhibitResult{}, fmt.Errorf("ending the inhibition: %s", strings.TrimSpace(r.Stderr)) + } + return InhibitResult{Inhibited: false}, nil + } + // What to return to: what is in force now, unless an inhibition is already holding it at off. + was, err := xsetQ(s) + if err != nil { + return InhibitResult{}, err + } + if lockState(s).Inhibited || (was.LockAfterSeconds == 0 && !was.DPMSEnabled) { + was = IdleState{LockAfterSeconds: declaredLock, CycleSeconds: declaredLock, DPMSEnabled: true, + StandbySeconds: declaredStandby, SuspendSeconds: declaredSuspend, OffSeconds: declaredOff} + } + script := inhibitScript(minutes, was) + if err := s.detach(inhibitUnit, "/bin/sh", "-c", script); err != nil { + return InhibitResult{}, err + } + return InhibitResult{Inhibited: true, Until: time.Now().Add(time.Duration(minutes) * time.Minute).Format(time.RFC3339), + Restores: fmt.Sprintf("lock after %ds; DPMS %d/%d/%d", was.LockAfterSeconds, was.StandbySeconds, was.SuspendSeconds, was.OffSeconds)}, nil +} + +func inhibitScript(minutes int, was IdleState) string { + dpms := "+dpms" + if !was.DPMSEnabled { + dpms = "-dpms" + } + return fmt.Sprintf("restore() { xset s %d %d; xset dpms %d %d %d; xset %s; }; "+ + "trap 'restore; exit 0' TERM INT; xset s off -dpms; sleep %d & wait; restore", + was.LockAfterSeconds, was.CycleSeconds, was.StandbySeconds, was.SuspendSeconds, was.OffSeconds, dpms, minutes*60) +} diff --git a/modules/screen-lock/cmd/screen-lock-tools/lock_test.go b/modules/screen-lock/cmd/screen-lock-tools/lock_test.go new file mode 100644 index 0000000..b6fc042 --- /dev/null +++ b/modules/screen-lock/cmd/screen-lock-tools/lock_test.go @@ -0,0 +1,189 @@ +package main + +import ( + "errors" + "os" + "os/exec" + "path/filepath" + "strconv" + "strings" + "testing" + "time" +) + +const nobody = 4194400 + +// xset q as the laptop answered it on 2026-10-04 (keyboard lines shortened). +const xsetQOutput = `Keyboard Control: + auto repeat: on key click percent: 0 LED mask: 00000000 +Screen Saver: + prefer blanking: yes allow exposures: yes + timeout: 600 cycle: 600 +Colors: + default colormap: 0x20 BlackPixel: 0x0 WhitePixel: 0xffffff +DPMS (Display Power Management Signaling): + Standby: 1800 Suspend: 1800 Off: 3600 + DPMS is Enabled + Monitor is On +` + +func TestTheTimeoutsAreReadFromXset(t *testing.T) { + st, err := parseXsetQ(xsetQOutput) + if err != nil { + t.Fatal(err) + } + if st.LockAfterSeconds != 600 || st.CycleSeconds != 600 || !st.DPMSEnabled || st.StandbySeconds != 1800 || + st.SuspendSeconds != 1800 || st.OffSeconds != 3600 || !st.MonitorOn { + t.Fatalf("%+v", st) + } + if _, err := parseXsetQ("nothing"); err == nil { + t.Fatal("an answer without a screensaver was accepted") + } +} + +func TestAProcessStartsWhenItsStatAndTheBootTimeSay(t *testing.T) { + fakeMachine(t) + fakeProcess(t, nobody, "i3lock") + // A command name with a space and a parenthesis, which a naive split gets wrong. + stat := strconv.Itoa(nobody) + " (i3 lock) x) S 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 12345 0 0\n" + if err := os.WriteFile(filepath.Join(procRoot, strconv.Itoa(nobody), "stat"), []byte(stat), 0o644); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(procRoot, "stat"), []byte("cpu 1 2 3\nbtime 1700000000\n"), 0o644); err != nil { + t.Fatal(err) + } + at, ok := startTime(nobody) + if !ok || !at.Equal(time.Unix(1700000000, 0).Add(123450*time.Millisecond)) { + t.Fatalf("%v %v", at, ok) + } +} + +// lockingMachine is a session whose loginctl, asked to lock, starts a (fake) i3lock. +func lockingMachine(t *testing.T, watcher bool) string { + t.Helper() + fakeMachine(t) + fakeProcess(t, nobody, "i3", "DISPLAY=:1", "XDG_SESSION_ID=4") + if watcher { + fakeProcess(t, nobody+1, "xss-lock", "DISPLAY=:1") + } + if err := os.MkdirAll(filepath.Join(runUserDir, strconv.Itoa(os.Getuid())), 0o700); err != nil { + t.Fatal(err) + } + lockNow := `mkdir -p "$PROC/` + strconv.Itoa(nobody+2) + `" && echo i3lock > "$PROC/` + strconv.Itoa(nobody+2) + `/comm"` + bin := fakeBinaries(t, map[string]string{ + "loginctl": `echo "loginctl $*" >> "$LOG" +case "$1" in lock-session) ` + lockNow + ` ;; show-session) echo yes ;; esac`, + "systemd-run": `echo "systemd-run $*" >> "$LOG"; ` + lockNow, + "systemctl": `echo "systemctl $*" >> "$LOG"; echo inactive`, + }) + t.Setenv("LOG", filepath.Join(bin, "log")) + t.Setenv("PROC", procRoot) + return bin +} + +func TestLockGoesThroughLogindSoTheOneLockerAnswers(t *testing.T) { + bin := lockingMachine(t, true) + st, err := Lock() + if err != nil { + t.Fatal(err) + } + if !st.Locked || !st.Watcher || st.LockedHint == nil || !*st.LockedHint || !strings.Contains(st.Via, "logind") { + t.Fatalf("%+v", st) + } + log, _ := os.ReadFile(filepath.Join(bin, "log")) + if !strings.Contains(string(log), "loginctl lock-session 4\n") || strings.Contains(string(log), "systemd-run") { + t.Fatalf("asked:\n%s", log) + } + again, err := Lock() + if err != nil || again.Via != "already locked" { + t.Fatalf("locking a locked screen: %+v, %v", again, err) + } +} + +func TestWithoutTheWatcherTheLockerRunsUnderTheAccountsServiceManager(t *testing.T) { + bin := lockingMachine(t, false) + st, err := Lock() + if err != nil || !st.Locked || !strings.Contains(st.Via, "xss-lock is not running") { + t.Fatalf("%+v, %v", st, err) + } + log, _ := os.ReadFile(filepath.Join(bin, "log")) + if !strings.Contains(string(log), "--unit=screen-lock --setenv=DISPLAY=:1 --setenv=XDG_SESSION_ID=4 -- ") || + !strings.Contains(string(log), "/.local/bin/screen-lock") { + t.Fatalf("asked:\n%s", log) + } +} + +func TestLockedWithoutASessionIsAnAnswerNotAnError(t *testing.T) { + fakeMachine(t) + st, err := Locked() + if err != nil || st.Locked || st.Watcher || st.PIDs == nil { + t.Fatalf("%+v, %v", st, err) + } + if _, err := Lock(); !errors.Is(err, ErrNoSession) { + t.Fatalf("lock without a session: %v", err) + } +} + +func TestIdleChangesOnlyWhatWasAskedAndSaysForHowLong(t *testing.T) { + fakeMachine(t) + fakeProcess(t, nobody, "i3", "DISPLAY=:1") + bin := fakeBinaries(t, map[string]string{"xset": `echo "xset $*" >> "$LOG"; [ "$1" = q ] && cat "$Q"; true`}) + t.Setenv("LOG", filepath.Join(bin, "log")) + q := filepath.Join(bin, "q") + if err := os.WriteFile(q, []byte(xsetQOutput), 0o644); err != nil { + t.Fatal(err) + } + t.Setenv("Q", q) + if st, err := Idle(IdleChange{}); err != nil || st.Note != "" || st.LockAfterSeconds != 600 { + t.Fatalf("read: %+v, %v", st, err) + } + c, err := idleChangeOf(map[string]any{"lock_after_seconds": float64(900), "off_seconds": float64(7200)}) + if err != nil { + t.Fatal(err) + } + st, err := Idle(c) + if err != nil || !strings.Contains(st.Note, "next login") { + t.Fatalf("%+v, %v", st, err) + } + log, _ := os.ReadFile(filepath.Join(bin, "log")) + if !strings.Contains(string(log), "xset s 900 600\n") || !strings.Contains(string(log), "xset dpms 1800 1800 7200\n") { + t.Fatalf("asked:\n%s", log) + } + if _, err := idleChangeOf(map[string]any{"off_seconds": float64(-1)}); err == nil { + t.Fatal("a negative timeout was accepted") + } +} + +func TestAnInhibitionTurnsIdleOffAndRestoresWhatWasThereWhenItEndsOrIsStopped(t *testing.T) { + was := IdleState{LockAfterSeconds: 1800, CycleSeconds: 1800, DPMSEnabled: true, StandbySeconds: 1800, SuspendSeconds: 1800, OffSeconds: 3600} + script := inhibitScript(2, was) + if !strings.Contains(script, "xset s off -dpms; sleep 120 & wait; restore") || + !strings.Contains(script, "restore() { xset s 1800 1800; xset dpms 1800 1800 3600; xset +dpms; }") || + !strings.Contains(script, "trap 'restore; exit 0' TERM") { + t.Fatalf("%s", script) + } + // Run it for real with a fake xset, stopped early as systemctl stop would. + dir := t.TempDir() + bin := fakeBinaries(t, map[string]string{"xset": `echo "$*" >> "` + filepath.Join(dir, "log") + `"`}) + _ = bin + cmd := exec.Command("/bin/sh", "-c", inhibitScript(1, was)) + if err := cmd.Start(); err != nil { + t.Fatal(err) + } + time.Sleep(300 * time.Millisecond) + _ = cmd.Process.Signal(os.Interrupt) + _ = cmd.Wait() + got, _ := os.ReadFile(filepath.Join(dir, "log")) + if string(got) != "s off -dpms\ns 1800 1800\ndpms 1800 1800 3600\n+dpms\n" { + t.Fatalf("the timeouts were not restored on stop:\n%s", got) + } +} + +func TestTheDeclaredTimeoutsAreTheSessionStartsOwn(t *testing.T) { + m := readManifest(t) + code := m.Shell[0].Code + if !strings.Contains(code, "xset s "+strconv.Itoa(declaredLock)+" "+strconv.Itoa(declaredLock)+"\n") || + !strings.Contains(code, "xset dpms "+strconv.Itoa(declaredStandby)+" "+strconv.Itoa(declaredSuspend)+" "+strconv.Itoa(declaredOff)+"\n") { + t.Fatalf("the tools' declared values and the session start's disagree:\n%s", code) + } +} diff --git a/modules/screen-lock/cmd/screen-lock-tools/main.go b/modules/screen-lock/cmd/screen-lock-tools/main.go new file mode 100644 index 0000000..d5bbab9 --- /dev/null +++ b/modules/screen-lock/cmd/screen-lock-tools/main.go @@ -0,0 +1,78 @@ +// screen-lock's Go tools bundle (novox/hq ADR 0188, ADR 0193, ADR 0208): its implementation of +// node-lock-screen's verb `lock`, and its own tools for the idle timeouts, served by the node's +// runtime as the operator account. +package main + +import ( + "fmt" + "os" + + stdio "git.novox.be/novox/mesh-sdk/go" +) + +func main() { + if err := stdio.Serve("", tools()); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func tools() []stdio.Tool { + return []stdio.Tool{ + { + Name: "node-lock-screen.lock", + Description: "Lock the operator's session now. It goes through logind, so the one locker the " + + "session runs answers it, as the lock key and a closed lid do. Answers whether the screen is " + + "locked and since when.", + Run: func(map[string]any) (any, error) { return Lock() }, + }, + { + Name: "screen_lock_idle", + Description: "The screen's idle timeouts: after how long idle the session locks (the X screensaver) " + + "and when the displays go to standby, suspend and off (DPMS). Give any of them to change it for " + + "this session; the declared ones return at the next login.", + Input: map[string]any{ + "lock_after_seconds": map[string]any{"type": "integer", "description": "idle time before the lock; 0 never"}, + "standby_seconds": map[string]any{"type": "integer", "description": "DPMS standby; 0 never"}, + "suspend_seconds": map[string]any{"type": "integer", "description": "DPMS suspend; 0 never"}, + "off_seconds": map[string]any{"type": "integer", "description": "DPMS off; 0 never"}, + }, + Run: func(args map[string]any) (any, error) { + change, err := idleChangeOf(args) + if err != nil { + return nil, err + } + return Idle(change) + }, + }, + { + Name: "screen_lock_inhibit", + Description: "Keep the screen on and unlocked for a while — a presentation, a film, a long read: " + + "no idle lock and no display power-off for `minutes`, then the timeouts as they were. 0 ends an " + + "inhibition early. A lock asked for by hand, by the lid or before suspend still locks.", + Input: map[string]any{ + "type": "object", + "properties": map[string]any{ + "minutes": map[string]any{"type": "integer", "description": fmt.Sprintf("how long, 1-%d; 0 ends it now", mostInhibit)}, + }, + "required": []string{"minutes"}, + }, + Run: func(args map[string]any) (any, error) { + if _, given := args["minutes"]; !given { + return nil, fmt.Errorf("minutes is required") + } + minutes, err := whole(args, "minutes", 0, 0, mostInhibit) + if err != nil { + return nil, err + } + return Inhibit(minutes) + }, + }, + { + Name: "screen_lock_locked", + Description: "Is the operator's session locked now, and since when; whether the lock watcher " + + "(xss-lock) runs, and whether an inhibition is keeping the screen on.", + Run: func(map[string]any) (any, error) { return Locked() }, + }, + } +} diff --git a/modules/screen-lock/cmd/screen-lock-tools/manifest_helpers_test.go b/modules/screen-lock/cmd/screen-lock-tools/manifest_helpers_test.go new file mode 100644 index 0000000..d4fb76d --- /dev/null +++ b/modules/screen-lock/cmd/screen-lock-tools/manifest_helpers_test.go @@ -0,0 +1,175 @@ +package main + +import ( + "encoding/json" + "os" + "path/filepath" + "strings" + "testing" +) + +// The module's manifest, read the way the catalogue reads it, for the manifest tests. The same in +// every desktop module that carries it. + +type manifest struct { + Module string `json:"module"` + Version string `json:"version"` + Capabilities []string `json:"capabilities"` + Requires []string `json:"requires"` + Claims []claim `json:"claims"` + Seats []any `json:"seats"` + Tools []string `json:"tools"` + Environment *environment `json:"environment"` + Shell []shellCode `json:"shell"` + Resources []map[string]any `json:"resources"` + Build struct { + Artifacts []map[string]any `json:"artifacts"` + } `json:"build"` +} + +type claim struct { + Name string `json:"name"` + Scope string `json:"scope"` + Serves []string `json:"serves"` +} + +type environment struct { + Variables map[string]string `json:"variables"` + Path []map[string]any `json:"path"` +} + +type shellCode struct { + For string `json:"for"` + Slot string `json:"slot"` + Code string `json:"code"` +} + +func readManifest(t *testing.T) manifest { + t.Helper() + raw, err := os.ReadFile(filepath.Join("..", "..", "module.json")) + if err != nil { + t.Fatal(err) + } + dec := json.NewDecoder(strings.NewReader(string(raw))) + dec.DisallowUnknownFields() + var m manifest + if err := dec.Decode(&m); err != nil { + t.Fatalf("module.json: %v", err) + } + return m +} + +func (m manifest) resource(t *testing.T, id string) map[string]any { + t.Helper() + for _, r := range m.Resources { + if r["id"] == id { + return r + } + } + t.Fatalf("no resource %q", id) + return nil +} + +func (m manifest) packages() (present, absent []string) { + for _, r := range m.Resources { + if r["type"] == "package" { + if r["absent"] == true { + absent = append(absent, r["package"].(string)) + } else { + present = append(present, r["package"].(string)) + } + } + } + return present, absent +} + +// sameAsSource checks that a file resource's content is byte for byte the module's source file, so +// the readable file in the repository is what the machine gets. +func (m manifest) sameAsSource(t *testing.T, id, source string) { + t.Helper() + want, err := os.ReadFile(filepath.Join("..", "..", source)) + if err != nil { + t.Fatal(err) + } + r := m.resource(t, id) + if r["type"] != "file" { + t.Fatalf("%s is a %v, not a file", id, r["type"]) + } + if got, _ := r["content"].(string); got != string(want) { + t.Fatalf("resource %s's content is not %s: edit the source and copy it into module.json", id, source) + } + if r["owner"] != "${machine:account}" && !strings.HasPrefix(r["path"].(string), "/etc/") { + t.Fatalf("%s under the home is the account's", id) + } +} + +// checkTheToolsAgree checks that the manifest lists the module's own tools exactly, that the bundle +// serves each seat verb the claims promise as ., and that the Go bundle is declared. +func checkTheToolsAgree(t *testing.T, m manifest) { + t.Helper() + own, seat := map[string]bool{}, map[string]bool{} + for _, tool := range tools() { + if strings.Contains(tool.Name, ".") { + seat[tool.Name] = true + } else { + own[tool.Name] = true + } + if strings.TrimSpace(tool.Description) == "" { + t.Errorf("%s has no description", tool.Name) + } + } + listed := map[string]bool{} + for _, name := range m.Tools { + listed[name] = true + if !own[name] { + t.Errorf("module.json lists %s, which the bundle does not serve", name) + } + } + for name := range own { + if !listed[name] { + t.Errorf("the bundle serves %s, which module.json does not list", name) + } + if !strings.HasPrefix(name, strings.ReplaceAll(m.Module, "-", "_")+"_") { + t.Errorf("%s is not prefixed with the module's name", name) + } + } + promised := map[string]bool{} + for _, c := range m.Claims { + for _, verb := range c.Serves { + promised[c.Name+"."+verb] = true + if !seat[c.Name+"."+verb] { + t.Errorf("the claim on %s promises %s, which the bundle does not serve", c.Name, verb) + } + } + } + for name := range seat { + if !promised[name] { + t.Errorf("the bundle serves %s, which no claim promises", name) + } + } + var bundle map[string]any + for _, a := range m.Build.Artifacts { + if a["kind"] == "bundle" { + bundle = a + } + } + if bundle == nil || bundle["language"] != "go" || bundle["system"] != "arch" || + bundle["from"] != "cmd/"+m.Module+"-tools" || bundle["binary"] != m.Module+"-tools" { + t.Errorf("the Go tools bundle: %v", bundle) + } +} + +// checkNoSecretsOrInstallationNames refuses what a catalogue manifest must never carry. +func checkNoSecretsOrInstallationNames(t *testing.T) { + t.Helper() + raw, err := os.ReadFile(filepath.Join("..", "..", "module.json")) + if err != nil { + t.Fatal(err) + } + s := strings.ToLower(string(raw)) + for _, never := range []string{"/home/", "jochen", "g14", "shanks", "novox.be", "api_key", ".hal/", "greenclip daemon"} { + if strings.Contains(s, never) { + t.Errorf("module.json names %q", never) + } + } +} diff --git a/modules/screen-lock/cmd/screen-lock-tools/manifest_test.go b/modules/screen-lock/cmd/screen-lock-tools/manifest_test.go new file mode 100644 index 0000000..2b20ad7 --- /dev/null +++ b/modules/screen-lock/cmd/screen-lock-tools/manifest_test.go @@ -0,0 +1,84 @@ +package main + +import ( + "reflect" + "strings" + "testing" +) + +// screen-lock's shape (novox/hq ADR 0208, research 026/04): it claims node-lock-screen serving lock, +// requires the X display on its own machine, installs the watcher and the distribution's locker, +// declares the colour build and xscreensaver absent, places its locker, and starts the watcher and +// the timeouts once, from the session's start. The lock key is the window manager's. + +func TestItClaimsTheLockScreenSeatServingLockAndRequiresTheXDisplay(t *testing.T) { + m := readManifest(t) + if m.Module != "screen-lock" || m.Seats != nil { + t.Fatalf("module %q declares seats %v", m.Module, m.Seats) + } + if !reflect.DeepEqual(m.Claims, []claim{{Name: "node-lock-screen", Scope: "node", Serves: []string{"lock"}}}) { + t.Fatalf("claims: %+v", m.Claims) + } + if !reflect.DeepEqual(m.Requires, []string{"x11-display"}) { + t.Fatalf("requires: %v", m.Requires) + } +} + +func TestTheDistributionsLockerReplacesTheColourBuildAndXscreensaverGoes(t *testing.T) { + m := readManifest(t) + present, absent := m.packages() + if !reflect.DeepEqual(present, []string{"xss-lock", "i3lock"}) || !reflect.DeepEqual(absent, []string{"i3lock-color", "xscreensaver"}) { + t.Fatalf("packages: %v, absent %v", present, absent) + } + m.sameAsSource(t, "wrapper", "files/bin/screen-lock") + wrapper := m.resource(t, "wrapper") + if wrapper["mode"] != "0755" || wrapper["path"] != "${machine:account-home}/.local/bin/screen-lock" { + t.Fatalf("the locker: %v", wrapper) + } + c := wrapper["content"].(string) + for _, colourOnly := range []string{"--ring-color", "--blur", "--clock", "--indicator", "--time-str"} { + if strings.Contains(c, colourOnly) { + t.Errorf("the wrapper passes %s, which only the colour build knows", colourOnly) + } + } + if !strings.Contains(c, "XSS_SLEEP_LOCK_FD}<&-") { + t.Error("the locker must not inherit the sleep lock") + } +} + +func TestTheSessionStartSetsTheTimeoutsAndKeepsOneWatcherForTheSession(t *testing.T) { + m := readManifest(t) + if len(m.Shell) != 1 || m.Shell[0].For != "xinitrc" || m.Shell[0].Slot != "normal" { + t.Fatalf("one xinitrc contribution in normal: %+v", m.Shell) + } + code := m.Shell[0].Code + if strings.Count(code, "xss-lock --") != 1 || !strings.Contains(code, "--transfer-sleep-lock") || + !strings.Contains(code, "while kill -0 $$") || !strings.HasSuffix(strings.TrimSpace(code), "&") { + t.Fatalf("the watcher: %q", code) + } + if strings.Contains(code, "xscreensaver") || strings.Contains(code, "my-i3lock") { + t.Fatalf("names what it replaced: %q", code) + } + for _, r := range m.Resources { + if r["type"] == "service" || r["type"] == "process" { + t.Fatalf("xss-lock needs the login session and is never a unit: %v", r) + } + } +} + +func TestTheLockKeyIsTheWindowManagersNotThisModules(t *testing.T) { + m := readManifest(t) + // The i3 module binds $mod+Delete to logind's lock, which names no locker; a binding here as well + // would be i3's duplicate. + for _, r := range m.Resources { + if p, _ := r["path"].(string); strings.Contains(p, "i3/config.d") { + t.Fatalf("a key binding: %v", r) + } + } +} + +func TestTheToolsAgreeWithTheManifest(t *testing.T) { + m := readManifest(t) + checkTheToolsAgree(t, m) + checkNoSecretsOrInstallationNames(t) +} diff --git a/modules/screen-lock/cmd/screen-lock-tools/session.go b/modules/screen-lock/cmd/screen-lock-tools/session.go new file mode 100644 index 0000000..dc21774 --- /dev/null +++ b/modules/screen-lock/cmd/screen-lock-tools/session.go @@ -0,0 +1,423 @@ +// The operator's graphical session, as a tool the node's runtime runs finds it (novox/hq ADR 0208). +// +// The runtime is a system service running as the operator account (ADR 0175): it has the account's +// uid and none of the session's environment — no DISPLAY, no XAUTHORITY, no session bus. A tool that +// draws on the screen or talks to the desktop's D-Bus must find them. It reads them from a process of +// the account that is part of the session (the window manager first), the same thing `loginctl` and +// a person's own shell would point at, and says where it found them. +// +// Long-lived programs a tool starts go to the account's own service manager through `systemd-run +// --user`, never as children of the tool: the runtime's unit is a cgroup the service manager empties +// whenever the runtime restarts, and a compositor or a clipboard owner started from inside it would +// die with it. +// +// This file is the same in every desktop module that carries it; it moves into the Go SDK once a +// second consumer outside the desktop wants it. +package main + +import ( + "bytes" + "errors" + "fmt" + "os" + "os/exec" + "path/filepath" + "sort" + "strconv" + "strings" + "syscall" + "time" +) + +// Where the session is looked for. Variables so a test can point them at a fake tree. +var ( + procRoot = "/proc" + runUserDir = "/run/user" + x11Sockets = "/tmp/.X11-unix" +) + +// sessionHolders are the processes whose environment is the session's, best first: the window +// manager is the session, the rest are its children. Anything else carrying DISPLAY ranks after them. +var sessionHolders = []string{"i3", "sway", "i3bar", "picom", "xss-lock", "dunst", "clipmenud", "xterm"} + +// sessionKeys are the variables a session carries that a tool hands on to what it runs. +var sessionKeys = []string{"DISPLAY", "XAUTHORITY", "WAYLAND_DISPLAY", "DBUS_SESSION_BUS_ADDRESS", + "XDG_RUNTIME_DIR", "XDG_SESSION_ID", "I3SOCK"} + +// Session is what a tool needs to reach the operator's desktop. +type Session struct { + UID int `json:"uid"` + Display string `json:"display,omitempty"` + XAuthority string `json:"xauthority,omitempty"` + Wayland string `json:"wayland_display,omitempty"` + Bus string `json:"bus,omitempty"` + RuntimeDir string `json:"runtime_dir,omitempty"` + SessionID string `json:"session_id,omitempty"` + I3Sock string `json:"i3sock,omitempty"` + // From says where the values were found: the tool's own environment, a process, or the socket. + From string `json:"from"` +} + +// ErrNoSession is answered by a tool that needs the desktop when nobody is logged in to it. +var ErrNoSession = errors.New("no graphical session") + +// ErrTimedOut is what run answers for a command ended because it ran past its time. +var ErrTimedOut = errors.New("timed out") + +// ErrNoBus is answered by a tool that needs the session bus when the account has none. +var ErrNoBus = errors.New("no session bus") + +// operatorHome is the account's home: what the runtime was told, else the process's own. +func operatorHome() string { + if h := strings.TrimSpace(os.Getenv("MESH_OPERATOR_HOME")); h != "" { + return h + } + h, _ := os.UserHomeDir() + return h +} + +// findSession finds the graphical session of the account this tool runs as, or answers +// ErrNoSession with what it looked at. +func findSession() (Session, error) { + s := findEnvironment() + if s.Display == "" && s.Wayland == "" { + return s, fmt.Errorf("%w for uid %d on this machine: no process of the account carries DISPLAY "+ + "or WAYLAND_DISPLAY, and no X server socket in %s has an authority file to go with it. "+ + "Is anyone logged in to the desktop?", ErrNoSession, s.UID, x11Sockets) + } + return s, nil +} + +// findBus finds the account's session bus, which a logged-in account has whether or not a desktop +// is running. +func findBus() (Session, error) { + s := findEnvironment() + if s.Bus == "" { + return s, fmt.Errorf("%w for uid %d: DBUS_SESSION_BUS_ADDRESS is not set and %s does not exist "+ + "(the account is not logged in)", ErrNoBus, s.UID, filepath.Join(runUserDir, strconv.Itoa(s.UID), "bus")) + } + return s, nil +} + +func findEnvironment() Session { + uid := os.Getuid() + s := Session{UID: uid} + own := map[string]string{} + for _, k := range sessionKeys { + own[k] = os.Getenv(k) + } + if own["DISPLAY"] != "" || own["WAYLAND_DISPLAY"] != "" { + s.fill(own) + s.From = "the tool's own environment" + } else if pid, comm, env, ok := sessionProcess(uid); ok { + s.fill(env) + s.From = fmt.Sprintf("process %s (pid %d)", comm, pid) + } else if display, ok := lonelyX11Socket(); ok { + if a := filepath.Join(operatorHome(), ".Xauthority"); exists(a) { + s.Display, s.XAuthority = display, a + s.From = "the X server socket and the account's ~/.Xauthority" + } + s.fill(own) + } else { + s.fill(own) + s.From = "nothing: no session found" + } + // The bus and the runtime directory are the account's, whether or not the process named them. + runtime := filepath.Join(runUserDir, strconv.Itoa(uid)) + if s.RuntimeDir == "" && exists(runtime) { + s.RuntimeDir = runtime + } + if s.Bus == "" && s.RuntimeDir != "" && exists(filepath.Join(s.RuntimeDir, "bus")) { + s.Bus = "unix:path=" + filepath.Join(s.RuntimeDir, "bus") + } + return s +} + +func (s *Session) fill(env map[string]string) { + set := func(dst *string, key string) { + if *dst == "" { + *dst = env[key] + } + } + set(&s.Display, "DISPLAY") + set(&s.XAuthority, "XAUTHORITY") + set(&s.Wayland, "WAYLAND_DISPLAY") + set(&s.Bus, "DBUS_SESSION_BUS_ADDRESS") + set(&s.RuntimeDir, "XDG_RUNTIME_DIR") + set(&s.SessionID, "XDG_SESSION_ID") + set(&s.I3Sock, "I3SOCK") +} + +// sessionProcess is the best process of this uid whose environment names a display. +func sessionProcess(uid int) (int, string, map[string]string, bool) { + entries, err := os.ReadDir(procRoot) + if err != nil { + return 0, "", nil, false + } + type candidate struct { + pid int + comm string + env map[string]string + rank int + } + var found []candidate + for _, e := range entries { + pid, err := strconv.Atoi(e.Name()) + if err != nil { + continue + } + dir := filepath.Join(procRoot, e.Name()) + if owner, ok := ownerOf(dir); !ok || owner != uid { + continue + } + raw, err := os.ReadFile(filepath.Join(dir, "environ")) + if err != nil { + continue + } + env := parseEnviron(raw) + if env["DISPLAY"] == "" && env["WAYLAND_DISPLAY"] == "" { + continue + } + comm := readTrimmed(filepath.Join(dir, "comm")) + rank := len(sessionHolders) + for i, h := range sessionHolders { + if h == comm { + rank = i + break + } + } + found = append(found, candidate{pid, comm, env, rank}) + } + if len(found) == 0 { + return 0, "", nil, false + } + sort.Slice(found, func(i, j int) bool { + if found[i].rank != found[j].rank { + return found[i].rank < found[j].rank + } + return found[i].pid > found[j].pid // the newer of two equals + }) + best := found[0] + return best.pid, best.comm, best.env, true +} + +func parseEnviron(raw []byte) map[string]string { + env := map[string]string{} + for _, kv := range bytes.Split(raw, []byte{0}) { + if i := bytes.IndexByte(kv, '='); i > 0 { + env[string(kv[:i])] = string(kv[i+1:]) + } + } + return env +} + +func ownerOf(path string) (int, bool) { + info, err := os.Stat(path) + if err != nil { + return 0, false + } + st, ok := info.Sys().(*syscall.Stat_t) + if !ok { + return 0, false + } + return int(st.Uid), true +} + +// lonelyX11Socket is the display of the one X server socket there is, when there is exactly one. +func lonelyX11Socket() (string, bool) { + entries, err := os.ReadDir(x11Sockets) + if err != nil { + return "", false + } + var displays []string + for _, e := range entries { + if n := strings.TrimPrefix(e.Name(), "X"); n != e.Name() { + if _, err := strconv.Atoi(n); err == nil { + displays = append(displays, ":"+n) + } + } + } + if len(displays) != 1 { + return "", false + } + return displays[0], true +} + +func readTrimmed(path string) string { + b, err := os.ReadFile(path) + if err != nil { + return "" + } + return strings.TrimSpace(string(b)) +} + +func exists(path string) bool { + _, err := os.Stat(path) + return err == nil +} + +// Env is this process's environment with the session's variables in place of its own. +func (s Session) Env() []string { + drop := map[string]bool{} + for _, k := range sessionKeys { + drop[k] = true + } + var env []string + for _, kv := range os.Environ() { + if i := strings.IndexByte(kv, '='); i > 0 && drop[kv[:i]] { + continue + } + env = append(env, kv) + } + add := func(k, v string) { + if v != "" { + env = append(env, k+"="+v) + } + } + add("DISPLAY", s.Display) + add("XAUTHORITY", s.XAuthority) + add("WAYLAND_DISPLAY", s.Wayland) + add("DBUS_SESSION_BUS_ADDRESS", s.Bus) + add("XDG_RUNTIME_DIR", s.RuntimeDir) + add("XDG_SESSION_ID", s.SessionID) + add("I3SOCK", s.I3Sock) + return env +} + +// mostOutput bounds what a command may answer with, per stream. +const mostOutput = 256 << 10 + +// Result is what a command did. +type Result struct { + Stdout string `json:"stdout"` + Stderr string `json:"stderr,omitempty"` + Code int `json:"code"` + Truncated bool `json:"truncated,omitempty"` +} + +// run runs a command in the session's environment, its input given, ended with everything it +// started after timeout. A command that is not installed is an error naming it; one that exits +// non-zero is a Result with its code, for the caller to judge. +func (s Session) run(timeout time.Duration, stdin string, name string, args ...string) (Result, error) { + path, err := exec.LookPath(name) + if err != nil { + return Result{}, fmt.Errorf("%s is not installed on this machine", name) + } + cmd := exec.Command(path, args...) + cmd.Env = s.Env() + if home := operatorHome(); exists(home) { + cmd.Dir = home + } + if stdin != "" { + cmd.Stdin = strings.NewReader(stdin) + } + var out, errOut capped + cmd.Stdout, cmd.Stderr = &out, &errOut + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + if err := cmd.Start(); err != nil { + return Result{}, fmt.Errorf("%s: %w", name, err) + } + done := make(chan error, 1) + go func() { done <- cmd.Wait() }() + select { + case err = <-done: + case <-time.After(timeout): + _ = syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) + <-done + return Result{Stdout: out.String(), Stderr: errOut.String()}, + fmt.Errorf("%s did not finish within %s and was ended: %w", name, timeout, ErrTimedOut) + } + r := Result{Stdout: out.String(), Stderr: errOut.String(), Truncated: out.cut || errOut.cut} + var exit *exec.ExitError + if errors.As(err, &exit) { + r.Code = exit.ExitCode() + } else if err != nil { + return r, fmt.Errorf("%s: %w", name, err) + } + return r, nil +} + +// detach starts a long-lived program under the account's own service manager, as a transient unit +// that carries the session's display, so it outlives the runtime that asked for it. A unit already +// running under the same name is stopped first, so a fixed name means "at most one". +func (s Session) detach(unit string, args ...string) error { + if s.RuntimeDir == "" { + return fmt.Errorf("%w: the account's runtime directory is missing, so its service manager "+ + "cannot be reached", ErrNoBus) + } + _, _ = s.run(5*time.Second, "", "systemctl", "--user", "stop", unit+".service") + call := []string{"--user", "--collect", "--quiet", "--unit=" + unit} + for _, kv := range [][2]string{{"DISPLAY", s.Display}, {"XAUTHORITY", s.XAuthority}, + {"WAYLAND_DISPLAY", s.Wayland}, {"XDG_SESSION_ID", s.SessionID}, {"I3SOCK", s.I3Sock}} { + if kv[1] != "" { + call = append(call, "--setenv="+kv[0]+"="+kv[1]) + } + } + call = append(call, "--") + call = append(call, args...) + r, err := s.run(10*time.Second, "", "systemd-run", call...) + if err != nil { + return err + } + if r.Code != 0 { + return fmt.Errorf("systemd-run %s: %s", unit, strings.TrimSpace(r.Stderr)) + } + return nil +} + +// uniqueUnit is a transient unit name that will not collide with an earlier one. +func uniqueUnit(prefix string) string { + return fmt.Sprintf("%s-%d", prefix, time.Now().UnixNano()) +} + +type capped struct { + bytes.Buffer + cut bool +} + +func (c *capped) Write(p []byte) (int, error) { + if room := mostOutput - c.Len(); room < len(p) { + if room > 0 { + c.Buffer.Write(p[:room]) + } + c.cut = true + return len(p), nil + } + return c.Buffer.Write(p) +} + +// processesOf are the pids of this uid's processes whose command name is comm, oldest first. +func processesOf(comm string) []int { + entries, err := os.ReadDir(procRoot) + if err != nil { + return nil + } + uid := os.Getuid() + var pids []int + for _, e := range entries { + pid, err := strconv.Atoi(e.Name()) + if err != nil { + continue + } + dir := filepath.Join(procRoot, e.Name()) + if owner, ok := ownerOf(dir); !ok || owner != uid { + continue + } + if readTrimmed(filepath.Join(dir, "comm")) == comm { + pids = append(pids, pid) + } + } + sort.Ints(pids) + return pids +} + +// signalAll sends sig to every process of this uid named comm, and answers the pids it reached. +func signalAll(comm string, sig syscall.Signal) []int { + var reached []int + for _, pid := range processesOf(comm) { + if syscall.Kill(pid, sig) == nil { + reached = append(reached, pid) + } + } + return reached +} diff --git a/modules/screen-lock/cmd/screen-lock-tools/session_test.go b/modules/screen-lock/cmd/screen-lock-tools/session_test.go new file mode 100644 index 0000000..800cc6d --- /dev/null +++ b/modules/screen-lock/cmd/screen-lock-tools/session_test.go @@ -0,0 +1,174 @@ +package main + +import ( + "errors" + "os" + "path/filepath" + "strconv" + "strings" + "testing" + "time" +) + +// fakeMachine points the session finder at a temporary /proc, /run/user and X socket directory, with +// none of the test process's own session variables, and gives back the root. +func fakeMachine(t *testing.T) string { + t.Helper() + root := t.TempDir() + procRoot, runUserDir, x11Sockets = filepath.Join(root, "proc"), filepath.Join(root, "run-user"), filepath.Join(root, "x11") + for _, d := range []string{procRoot, runUserDir, x11Sockets} { + if err := os.MkdirAll(d, 0o755); err != nil { + t.Fatal(err) + } + } + for _, k := range sessionKeys { + t.Setenv(k, "") + } + t.Setenv("MESH_OPERATOR_HOME", filepath.Join(root, "home")) + t.Cleanup(func() { procRoot, runUserDir, x11Sockets = "/proc", "/run/user", "/tmp/.X11-unix" }) + return root +} + +func fakeProcess(t *testing.T, pid int, comm string, env ...string) { + t.Helper() + dir := filepath.Join(procRoot, strconv.Itoa(pid)) + if err := os.MkdirAll(dir, 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, "comm"), []byte(comm+"\n"), 0o644); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, "environ"), []byte(strings.Join(env, "\x00")+"\x00"), 0o600); err != nil { + t.Fatal(err) + } +} + +func TestTheSessionIsReadFromTheWindowManagerBeforeAnyOtherProcess(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 900, "xterm", "DISPLAY=:9", "XAUTHORITY=/elsewhere") + fakeProcess(t, 100, "i3", "DISPLAY=:1", "XAUTHORITY=/home/op/.Xauthority", + "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus", "XDG_SESSION_ID=3", "SECRET_TOKEN=never-copied") + fakeProcess(t, 50, "bash", "PATH=/usr/bin") + s, err := findSession() + if err != nil { + t.Fatal(err) + } + if s.Display != ":1" || s.XAuthority != "/home/op/.Xauthority" || s.SessionID != "3" || !strings.Contains(s.From, "i3 (pid 100)") { + t.Fatalf("the window manager's environment: %+v", s) + } + for _, kv := range s.Env() { + if strings.HasPrefix(kv, "SECRET_TOKEN=") { + t.Fatal("a variable of the session process that is not a session variable was handed on") + } + } +} + +func TestAnyProcessCarryingADisplayServesWhenTheWindowManagerIsNotFound(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 10, "firefox", "DISPLAY=:0") + fakeProcess(t, 20, "firefox", "DISPLAY=:2") + s, err := findSession() + if err != nil || s.Display != ":2" { + t.Fatalf("the newest of two equals: %+v, %v", s, err) + } +} + +func TestNoSessionIsAClearAnswerNotAGuess(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 10, "sshd", "PATH=/usr/bin") + _, err := findSession() + if !errors.Is(err, ErrNoSession) || !strings.Contains(err.Error(), "logged in to the desktop") { + t.Fatalf("no session: %v", err) + } +} + +func TestOneXSocketAndTheAccountsAuthorityFileAreASession(t *testing.T) { + root := fakeMachine(t) + if err := os.WriteFile(filepath.Join(x11Sockets, "X0"), nil, 0o644); err != nil { + t.Fatal(err) + } + if err := os.MkdirAll(filepath.Join(root, "home"), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(root, "home", ".Xauthority"), nil, 0o600); err != nil { + t.Fatal(err) + } + s, err := findSession() + if err != nil || s.Display != ":0" || !strings.HasSuffix(s.XAuthority, "/home/.Xauthority") { + t.Fatalf("socket and authority: %+v, %v", s, err) + } +} + +func TestTheBusIsTheAccountsRuntimeDirectoryWhenNoProcessNamesIt(t *testing.T) { + fakeMachine(t) + runtime := filepath.Join(runUserDir, strconv.Itoa(os.Getuid())) + if _, err := findBus(); !errors.Is(err, ErrNoBus) { + t.Fatalf("no runtime directory is no bus: %v", err) + } + if err := os.MkdirAll(runtime, 0o700); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(runtime, "bus"), nil, 0o600); err != nil { + t.Fatal(err) + } + s, err := findBus() + if err != nil || s.Bus != "unix:path="+filepath.Join(runtime, "bus") || s.RuntimeDir != runtime { + t.Fatalf("bus: %+v, %v", s, err) + } + env := strings.Join(s.Env(), "\n") + if !strings.Contains(env, "XDG_RUNTIME_DIR="+runtime) || !strings.Contains(env, "DBUS_SESSION_BUS_ADDRESS=unix:path=") { + t.Fatalf("the bus is handed on: %s", env) + } +} + +func TestACommandIsBoundedAndANonZeroExitIsAResult(t *testing.T) { + fakeMachine(t) + s := Session{} + r, err := s.run(5*time.Second, "in", "sh", "-c", "cat; echo err >&2; exit 3") + if err != nil || r.Stdout != "in" || r.Code != 3 || strings.TrimSpace(r.Stderr) != "err" { + t.Fatalf("result: %+v, %v", r, err) + } + start := time.Now() + if _, err := s.run(200*time.Millisecond, "", "sh", "-c", "sleep 30 & sleep 30"); err == nil || time.Since(start) > 5*time.Second { + t.Fatalf("a command past its time is ended with what it started: %v after %s", err, time.Since(start)) + } + if _, err := s.run(time.Second, "", "no-such-program-here"); err == nil || !strings.Contains(err.Error(), "not installed") { + t.Fatalf("a missing program: %v", err) + } +} + +func TestDetachAsksTheAccountsServiceManagerWithTheSessionsDisplay(t *testing.T) { + fakeMachine(t) + bin := fakeBinaries(t, map[string]string{ + "systemctl": `echo "systemctl $*" >> "$LOG"`, + "systemd-run": `echo "systemd-run $*" >> "$LOG"`, + }) + log := filepath.Join(bin, "log") + t.Setenv("LOG", log) + s := Session{Display: ":1", XAuthority: "/x", RuntimeDir: "/run/user/1"} + if err := s.detach("picom-session", "picom", "--config", "/c"); err != nil { + t.Fatal(err) + } + got, _ := os.ReadFile(log) + want := "systemctl --user stop picom-session.service\n" + + "systemd-run --user --collect --quiet --unit=picom-session --setenv=DISPLAY=:1 --setenv=XAUTHORITY=/x -- picom --config /c\n" + if string(got) != want { + t.Fatalf("detach ran:\n%s\nwant:\n%s", got, want) + } + if err := (Session{}).detach("x", "y"); !errors.Is(err, ErrNoBus) { + t.Fatalf("no runtime directory: %v", err) + } +} + +// fakeBinaries puts shell scripts named for programs first on PATH, and answers their directory. +func fakeBinaries(t *testing.T, scripts map[string]string) string { + t.Helper() + dir := t.TempDir() + for name, body := range scripts { + if err := os.WriteFile(filepath.Join(dir, name), []byte("#!/bin/sh\n"+body+"\n"), 0o755); err != nil { + t.Fatal(err) + } + } + t.Setenv("PATH", dir+string(os.PathListSeparator)+os.Getenv("PATH")) + return dir +} diff --git a/modules/screen-lock/files/bin/screen-lock b/modules/screen-lock/files/bin/screen-lock new file mode 100755 index 0000000..7e13946 --- /dev/null +++ b/modules/screen-lock/files/bin/screen-lock @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# screen-lock (module screen-lock, novox/hq ADR 0208): the locker. xss-lock runs it on idle, before +# suspend and on logind's Lock, and node-lock-screen's `lock` ends in it. +# +# The distribution's i3lock: a black screen, failed attempts shown, an empty Enter ignored. The colour +# build the predecessor used is not in the distribution; it can come back as a pinned archive +# (ADR 0205), and then only these options change. +# +# Before a suspend, xss-lock hands this script a lock on the sleep (XSS_SLEEP_LOCK_FD) and suspends +# once it is released. The locker must not inherit it, or the machine would wait for the unlock +# before sleeping; it is released once i3lock is up, so the machine never sleeps unlocked. This is +# xss-lock's own documented pattern for i3lock. +set -u + +options=(--color=000000 --show-failed-attempts --ignore-empty-password) + +# One locker: a second press of the key, or a lock while locked, changes nothing. +if pgrep -xu "$EUID" i3lock >/dev/null; then + exit 0 +fi + +if [[ -e /dev/fd/${XSS_SLEEP_LOCK_FD:--1} ]]; then + kill_i3lock() { pkill -xu "$EUID" "$@" i3lock; } + trap kill_i3lock TERM INT + i3lock "${options[@]}" {XSS_SLEEP_LOCK_FD}<&- + exec {XSS_SLEEP_LOCK_FD}<&- + while kill_i3lock -0; do + sleep 0.5 + done +else + trap 'kill %%' TERM INT + i3lock --nofork "${options[@]}" & + wait +fi diff --git a/modules/screen-lock/go.mod b/modules/screen-lock/go.mod new file mode 100644 index 0000000..b049dcf --- /dev/null +++ b/modules/screen-lock/go.mod @@ -0,0 +1,5 @@ +module screenlock + +go 1.22 + +require git.novox.be/novox/mesh-sdk/go v0.1.7 diff --git a/modules/screen-lock/go.sum b/modules/screen-lock/go.sum new file mode 100644 index 0000000..b474419 --- /dev/null +++ b/modules/screen-lock/go.sum @@ -0,0 +1,2 @@ +git.novox.be/novox/mesh-sdk/go v0.1.7 h1:C0sTQmtTiyYH7bnqZb7PusXnqA37gKuT7Nqjn9gG47w= +git.novox.be/novox/mesh-sdk/go v0.1.7/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= diff --git a/modules/screen-lock/module.json b/modules/screen-lock/module.json new file mode 100644 index 0000000..834b301 --- /dev/null +++ b/modules/screen-lock/module.json @@ -0,0 +1,78 @@ +{ + "module": "screen-lock", + "version": "1", + "capabilities": [ + "package-manager" + ], + "requires": [ + "x11-display" + ], + "claims": [ + { + "name": "node-lock-screen", + "scope": "node", + "serves": [ + "lock" + ] + } + ], + "tools": [ + "screen_lock_idle", + "screen_lock_inhibit", + "screen_lock_locked" + ], + "shell": [ + { + "for": "xinitrc", + "slot": "normal", + "code": "# The lock screen (module screen-lock, novox/hq ADR 0208): the session locks after 30 minutes idle,\n# the displays go to standby and suspend then and off after an hour, and xss-lock runs the locker on\n# idle, before suspend and on logind's Lock. xss-lock needs this login session, so it starts here and\n# not as a unit. It is started again if it exits, for as long as this session lasts ($$ is the\n# session's own process, which becomes the window manager).\nxset s 1800 1800\nxset dpms 1800 1800 3600\n(while kill -0 $$ 2>/dev/null; do xss-lock --transfer-sleep-lock -- \"$HOME/.local/bin/screen-lock\"; sleep 2; done) &\n" + } + ], + "resources": [ + { + "id": "watcher", + "type": "package", + "package": "xss-lock" + }, + { + "id": "locker", + "type": "package", + "package": "i3lock" + }, + { + "id": "colour-locker", + "type": "package", + "package": "i3lock-color", + "absent": true + }, + { + "id": "screensaver", + "type": "package", + "package": "xscreensaver", + "absent": true + }, + { + "id": "wrapper", + "type": "file", + "path": "${machine:account-home}/.local/bin/screen-lock", + "owner": "${machine:account}", + "mode": "0755", + "content": "#!/usr/bin/env bash\n# screen-lock (module screen-lock, novox/hq ADR 0208): the locker. xss-lock runs it on idle, before\n# suspend and on logind's Lock, and node-lock-screen's `lock` ends in it.\n#\n# The distribution's i3lock: a black screen, failed attempts shown, an empty Enter ignored. The colour\n# build the predecessor used is not in the distribution; it can come back as a pinned archive\n# (ADR 0205), and then only these options change.\n#\n# Before a suspend, xss-lock hands this script a lock on the sleep (XSS_SLEEP_LOCK_FD) and suspends\n# once it is released. The locker must not inherit it, or the machine would wait for the unlock\n# before sleeping; it is released once i3lock is up, so the machine never sleeps unlocked. This is\n# xss-lock's own documented pattern for i3lock.\nset -u\n\noptions=(--color=000000 --show-failed-attempts --ignore-empty-password)\n\n# One locker: a second press of the key, or a lock while locked, changes nothing.\nif pgrep -xu \"$EUID\" i3lock >/dev/null; then\n\texit 0\nfi\n\nif [[ -e /dev/fd/${XSS_SLEEP_LOCK_FD:--1} ]]; then\n\tkill_i3lock() { pkill -xu \"$EUID\" \"$@\" i3lock; }\n\ttrap kill_i3lock TERM INT\n\ti3lock \"${options[@]}\" {XSS_SLEEP_LOCK_FD}<&-\n\texec {XSS_SLEEP_LOCK_FD}<&-\n\twhile kill_i3lock -0; do\n\t\tsleep 0.5\n\tdone\nelse\n\ttrap 'kill %%' TERM INT\n\ti3lock --nofork \"${options[@]}\" &\n\twait\nfi\n" + } + ], + "build": { + "artifacts": [ + { + "name": "tools", + "kind": "bundle", + "language": "go", + "system": "arch", + "from": "cmd/screen-lock-tools", + "binary": "screen-lock-tools", + "loads": [ + "screen-lock-tools" + ] + } + ] + } +} From c42cd285e25b7a996e4d1ffc25a7b1bd1bee64a4 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 4 Oct 2026 12:59:14 +0200 Subject: [PATCH 05/15] clipmenu: the clipboard manager as a module, claiming node-clipboard and serving history and copy (hq ADR 0208) Replaces the AUR greenclip (declared absent) with the official clipmenu, started once from the session's xinitrc slot, its menu the launcher's dmenu command bound as an i3 drop-in, its history in the runtime directory. Go tools read and change clipmenu's own store under its lock. --- modules/clipmenu/README.md | 69 +++ modules/clipmenu/cmd/clipmenu-tools/args.go | 97 ++++ .../clipmenu/cmd/clipmenu-tools/clipboard.go | 348 ++++++++++++++ .../cmd/clipmenu-tools/clipboard_test.go | 163 +++++++ modules/clipmenu/cmd/clipmenu-tools/main.go | 90 ++++ .../clipmenu-tools/manifest_helpers_test.go | 175 ++++++++ .../cmd/clipmenu-tools/manifest_test.go | 64 +++ .../clipmenu/cmd/clipmenu-tools/session.go | 423 ++++++++++++++++++ .../cmd/clipmenu-tools/session_test.go | 174 +++++++ modules/clipmenu/files/i3/50-clipmenu.conf | 5 + modules/clipmenu/go.mod | 5 + modules/clipmenu/go.sum | 2 + modules/clipmenu/module.json | 75 ++++ 13 files changed, 1690 insertions(+) create mode 100644 modules/clipmenu/README.md create mode 100644 modules/clipmenu/cmd/clipmenu-tools/args.go create mode 100644 modules/clipmenu/cmd/clipmenu-tools/clipboard.go create mode 100644 modules/clipmenu/cmd/clipmenu-tools/clipboard_test.go create mode 100644 modules/clipmenu/cmd/clipmenu-tools/main.go create mode 100644 modules/clipmenu/cmd/clipmenu-tools/manifest_helpers_test.go create mode 100644 modules/clipmenu/cmd/clipmenu-tools/manifest_test.go create mode 100644 modules/clipmenu/cmd/clipmenu-tools/session.go create mode 100644 modules/clipmenu/cmd/clipmenu-tools/session_test.go create mode 100644 modules/clipmenu/files/i3/50-clipmenu.conf create mode 100644 modules/clipmenu/go.mod create mode 100644 modules/clipmenu/go.sum create mode 100644 modules/clipmenu/module.json diff --git a/modules/clipmenu/README.md b/modules/clipmenu/README.md new file mode 100644 index 0000000..6243582 --- /dev/null +++ b/modules/clipmenu/README.md @@ -0,0 +1,69 @@ +# clipmenu + +The clipboard manager as a module (novox/hq ADR 0208, research 026/04). + +- Installs `clipmenu` from the official repositories. It brings `clipnotify`, `xsel`, `xdotool` and + `dmenu` as its own dependencies. +- Claims the mesh's `node-clipboard` seat and serves its verbs `history` and `copy`. Requires + `x11-display` on its own machine. +- **Declares `rofi-greenclip` absent** (ADR 0180). This module replaces it. +- Starts `clipmenud` **once per session**, from the session's start (the `xinitrc` slot `normal`). + It is not a user unit as well. Its packaged unit needs user-scoped units (mesh-host #72, not + merged), and the session start alone is one starter. +- Binds `$mod+period` to `clipmenu`, as its own i3 drop-in (`50-clipmenu.conf`). clipmenu shows the + history through `dmenu`, the seat command of `node-launcher`, so it looks like every other menu. +- Its settings are environment contributions (ADR 0203), read by the daemon, the menu and the tools + alike: + - `CM_SELECTIONS=clipboard`: what was copied, not every highlighted word. The found greenclip did + the same. + - `CM_MAX_CLIPS=500`: how many clips are kept. + - `CM_HISTLENGTH=15`: how many lines the menu shows. + +## Tools + +| tool | does | +|---|---| +| `node-clipboard.history` | the history, newest first, each entry once with its id, first line, time, size and text (cut) | +| `node-clipboard.copy` | put text on the clipboard; it enters the history like any copy | +| `clipmenu_paste` | what the clipboard holds now | +| `clipmenu_clear` | forget the history; the daemon's locks stay | +| `clipmenu_delete` | forget one entry, by id or first line | + +The history is read from clipmenu's own store, in the account's runtime directory, under clipmenu's +own lock, so a copy arriving meanwhile is neither lost nor half-written. `copy` hands the text to an +owner (`xsel`) under the account's service manager. As a child of the tools runtime, the clipboard +would empty whenever the runtime restarted. + +## What it improves on what was found + +- **No AUR package.** greenclip came from the user repository. clipmenu is in the official one. +- **Started once.** greenclip was started by the window manager on both workstations, and on the + desktop by an enabled user unit as well. +- **No absolute home path** in any configuration. greenclip's named one. +- **The history does not outlive a reboot.** greenclip kept it in `~/.cache`, so every password ever + copied stayed on disk. clipmenu keeps it in the runtime directory, which is memory. +- **One menu.** The history appears in the launcher's own menu, through the seat's `dmenu` command, + instead of a theme from a cloned theme repository. + +## What it leaves as found + +- `~/.config/greenclip.toml` and greenclip's history, `~/.cache/greenclip.history`. +- On the desktop: greenclip's enabled user unit link + (`~/.config/systemd/user/default.target.wants/greenclip.service`). It dangles once the package is + gone. + +## Migration (ADR 0182) + +1. After the first push, delete `~/.config/greenclip.toml` and `~/.cache/greenclip.history`. +2. On the desktop: `systemctl --user disable greenclip.service`, before the push if you can. The + package's removal takes the unit file with it. +3. Until the `i3` module carries the main configuration, the found `exec --no-startup-id greenclip + daemon` and `$mod+period` lines stay in `~/.config/i3/config`. i3 reports `$mod+period` as bound + twice. The `i3` module's configuration carries neither. + +## Blockers + +- `node-clipboard`, `x11-display` and the `xinitrc` slot are ADR 0208's. Until the controller knows + them, `mctl` reads them as unknown. +- `CM_*` reach the session through `node-env` (ADR 0203), so the account's environment module must + be assigned too. Without it clipmenu runs on its defaults: both selections, 1000 clips, 8 lines. diff --git a/modules/clipmenu/cmd/clipmenu-tools/args.go b/modules/clipmenu/cmd/clipmenu-tools/args.go new file mode 100644 index 0000000..9b5dfcf --- /dev/null +++ b/modules/clipmenu/cmd/clipmenu-tools/args.go @@ -0,0 +1,97 @@ +// Reading a tool's arguments: JSON numbers arrive as float64, and a missing argument is its default. +// The same in every desktop module that carries it. +package main + +import ( + "fmt" + "math" + "strings" + "time" +) + +// text is a string argument, trimmed; required says an empty one is refused. +func text(args map[string]any, key string, required bool) (string, error) { + v, present := args[key] + if !present || v == nil { + if required { + return "", fmt.Errorf("%s is required", key) + } + return "", nil + } + s, ok := v.(string) + if !ok { + return "", fmt.Errorf("%s is a string, not %T", key, v) + } + s = strings.TrimSpace(s) + if s == "" && required { + return "", fmt.Errorf("%s is required", key) + } + return s, nil +} + +// whole is a whole-number argument within [least, most], or def when absent. +func whole(args map[string]any, key string, def, least, most int) (int, error) { + v, present := args[key] + if !present || v == nil { + return def, nil + } + f, ok := v.(float64) + if !ok { + if i, isInt := v.(int); isInt { + f = float64(i) + } else { + return 0, fmt.Errorf("%s is a number, not %T", key, v) + } + } + if f != math.Trunc(f) { + return 0, fmt.Errorf("%s is a whole number, not %v", key, f) + } + n := int(f) + if n < least || n > most { + return 0, fmt.Errorf("%s is %d; it is between %d and %d", key, n, least, most) + } + return n, nil +} + +// flag is a boolean argument, or def when absent. +func flag(args map[string]any, key string, def bool) (bool, error) { + v, present := args[key] + if !present || v == nil { + return def, nil + } + b, ok := v.(bool) + if !ok { + return false, fmt.Errorf("%s is true or false, not %T", key, v) + } + return b, nil +} + +// texts is a list-of-strings argument. +func texts(args map[string]any, key string) ([]string, error) { + v, present := args[key] + if !present || v == nil { + return nil, nil + } + list, ok := v.([]any) + if !ok { + if ss, isStrings := v.([]string); isStrings { + return ss, nil + } + return nil, fmt.Errorf("%s is a list of strings, not %T", key, v) + } + out := make([]string, 0, len(list)) + for i, item := range list { + s, ok := item.(string) + if !ok { + return nil, fmt.Errorf("%s[%d] is a string, not %T", key, i, item) + } + out = append(out, s) + } + return out, nil +} + +// seconds is a timeout argument in seconds, defaulted and bounded below the runtime's call limit. +func seconds(args map[string]any, key string, def, most int) (time.Duration, error) { + n, err := whole(args, key, def, 1, most) + return time.Duration(n) * time.Second, err +} diff --git a/modules/clipmenu/cmd/clipmenu-tools/clipboard.go b/modules/clipmenu/cmd/clipmenu-tools/clipboard.go new file mode 100644 index 0000000..b025030 --- /dev/null +++ b/modules/clipmenu/cmd/clipmenu-tools/clipboard.go @@ -0,0 +1,348 @@ +package main + +import ( + "bufio" + "errors" + "fmt" + "os" + "os/user" + "path/filepath" + "sort" + "strconv" + "strings" + "syscall" + "time" +) + +const ( + mostCopy = 1 << 20 + mostPaste = 64 << 10 + // majorVersion is clipmenu's store layout: /clipmenu../. + majorVersion = 6 +) + +// account is the user clipmenu's store is named for. +func account() string { + for _, k := range []string{"USER", "MESH_OPERATOR_ACCOUNT", "LOGNAME"} { + if v := strings.TrimSpace(os.Getenv(k)); v != "" { + return v + } + } + if u, err := user.Current(); err == nil { + return u.Username + } + return "" +} + +// storeDir is where clipmenud keeps the history: CM_DIR, else the account's runtime directory. +func storeDir(s Session) (string, error) { + base := os.Getenv("CM_DIR") + if base == "" { + base = s.RuntimeDir + } + if base == "" { + return "", fmt.Errorf("%w: the account's runtime directory, where the clipboard history lives, is missing (the account is not logged in)", ErrNoBus) + } + return filepath.Join(base, fmt.Sprintf("clipmenu.%d.%s", majorVersion, account())), nil +} + +// cksum is POSIX cksum(1) of data: clipmenu names each entry's file by the cksum of its first line +// followed by a newline, as " ". +func cksum(data []byte) string { + var crc uint32 + step := func(b byte) { + crc ^= uint32(b) << 24 + for i := 0; i < 8; i++ { + if crc&0x80000000 != 0 { + crc = crc<<1 ^ 0x04C11DB7 + } else { + crc <<= 1 + } + } + } + for _, b := range data { + step(b) + } + for n := len(data); n != 0; n >>= 8 { + step(byte(n)) + } + return fmt.Sprintf("%d %d", ^crc, len(data)) +} + +func entryID(line string) string { return cksum([]byte(line + "\n")) } + +// Entry is one clip in the history. +type Entry struct { + ID string `json:"id"` + Line string `json:"line"` + At string `json:"at"` + Bytes int `json:"bytes"` + Text string `json:"text,omitempty"` + Truncated bool `json:"truncated,omitempty"` + at int64 +} + +// HistoryResult is what node-clipboard.history answers. +type HistoryResult struct { + Collecting bool `json:"collecting"` + Store string `json:"store"` + Total int `json:"total"` + Entries []Entry `json:"entries"` +} + +// readStore reads clipmenu's line cache: one " " per copy, oldest first, a +// line repeated when the same thing was copied again. The newest copy of each line wins. +func readStore(dir string) ([]Entry, error) { + f, err := os.Open(filepath.Join(dir, "line_cache")) + if errors.Is(err, os.ErrNotExist) { + return []Entry{}, nil + } + if err != nil { + return nil, err + } + defer f.Close() + latest := map[string]int64{} + scan := bufio.NewScanner(f) + scan.Buffer(make([]byte, 64<<10), 1<<20) + for scan.Scan() { + stamp, line, ok := strings.Cut(scan.Text(), " ") + if !ok { + continue + } + ns, err := strconv.ParseInt(stamp, 10, 64) + if err != nil { + continue + } + if ns >= latest[line] { + latest[line] = ns + } + } + out := make([]Entry, 0, len(latest)) + for line, ns := range latest { + out = append(out, Entry{ID: entryID(line), Line: line, at: ns, At: time.Unix(0, ns).Format(time.RFC3339)}) + } + sort.Slice(out, func(i, j int) bool { return out[i].at > out[j].at }) + return out, scan.Err() +} + +// History is the clipboard's history, newest first. +func History(limit, maxBytes int) (HistoryResult, error) { + dir, err := storeDir(findEnvironment()) + if err != nil { + return HistoryResult{}, err + } + entries, err := readStore(dir) + if err != nil { + return HistoryResult{}, err + } + out := HistoryResult{Collecting: len(processesOf("clipmenud")) > 0, Store: dir, Total: len(entries), Entries: []Entry{}} + for i, e := range entries { + if i == limit { + break + } + if info, err := os.Stat(filepath.Join(dir, e.ID)); err == nil { + e.Bytes = int(info.Size()) + if maxBytes > 0 { + raw, _ := os.ReadFile(filepath.Join(dir, e.ID)) + if len(raw) > maxBytes { + raw, e.Truncated = raw[:maxBytes], true + } + e.Text = string(raw) + } + } + out.Entries = append(out.Entries, e) + } + return out, nil +} + +// CopyResult is what node-clipboard.copy answers. +type CopyResult struct { + Bytes int `json:"bytes"` + Unit string `json:"unit"` +} + +// Copy puts text on the clipboard. The clipboard is owned by a process until another copies, so the +// owner (xsel) runs under the account's service manager, not as a child of this tool. +func Copy(text string) (CopyResult, error) { + if len(text) == 0 { + return CopyResult{}, errors.New("text is empty; to empty the clipboard's history, clipmenu_clear") + } + if len(text) > mostCopy { + return CopyResult{}, fmt.Errorf("%d bytes; the clipboard takes at most %d here", len(text), mostCopy) + } + s, err := findSession() + if err != nil { + return CopyResult{}, err + } + if s.RuntimeDir == "" { + return CopyResult{}, fmt.Errorf("%w: no runtime directory to hand the text over in", ErrNoBus) + } + // Handed over in a file only the account can read, which the owner reads and removes. + f, err := os.CreateTemp(s.RuntimeDir, "clipmenu-copy-") + if err != nil { + return CopyResult{}, err + } + if _, err := f.WriteString(text); err != nil { + f.Close() + os.Remove(f.Name()) + return CopyResult{}, err + } + f.Close() + unit := uniqueUnit("clipmenu-copy") + script := `xsel --nodetach --input --clipboard < "$0" & sleep 1; rm -f "$0"; wait` + if err := s.detach(unit, "/bin/sh", "-c", script, f.Name()); err != nil { + os.Remove(f.Name()) + return CopyResult{}, err + } + return CopyResult{Bytes: len(text), Unit: unit + ".service"}, nil +} + +// PasteResult is what clipmenu_paste answers. +type PasteResult struct { + Text string `json:"text"` + Bytes int `json:"bytes"` + Truncated bool `json:"truncated,omitempty"` +} + +// Paste reads the clipboard now. +func Paste() (PasteResult, error) { + s, err := findSession() + if err != nil { + return PasteResult{}, err + } + r, err := s.run(5*time.Second, "", "xsel", "--output", "--clipboard") + if err != nil { + return PasteResult{}, err + } + if r.Code != 0 { + return PasteResult{}, fmt.Errorf("xsel: %s", strings.TrimSpace(r.Stderr)) + } + out := PasteResult{Text: r.Stdout, Bytes: len(r.Stdout), Truncated: r.Truncated} + if len(out.Text) > mostPaste { + out.Text, out.Truncated = out.Text[:mostPaste], true + } + return out, nil +} + +// ChangeResult is what clear and delete answer. +type ChangeResult struct { + Removed int `json:"removed"` + Remaining int `json:"remaining"` +} + +// withStoreLock holds clipmenu's own lock on its store, the one clipmenud and clipdel take, while +// change runs, so a copy arriving meanwhile is neither lost nor half-written. +func withStoreLock(dir string, change func() error) error { + lock, err := os.OpenFile(filepath.Join(dir, "lock"), os.O_CREATE|os.O_WRONLY, 0o600) + if err != nil { + return err + } + defer lock.Close() + deadline := time.Now().Add(2 * time.Second) + for { + err := syscall.Flock(int(lock.Fd()), syscall.LOCK_EX|syscall.LOCK_NB) + if err == nil { + break + } + if time.Now().After(deadline) { + return fmt.Errorf("the clipboard store is locked by clipmenud and did not come free within 2s") + } + time.Sleep(50 * time.Millisecond) + } + defer syscall.Flock(int(lock.Fd()), syscall.LOCK_UN) + return change() +} + +func storeOf() (string, error) { + dir, err := storeDir(findEnvironment()) + if err != nil { + return "", err + } + if _, err := os.Stat(dir); errors.Is(err, os.ErrNotExist) { + return "", fmt.Errorf("there is no clipboard history at %s: clipmenud has not run in this login", dir) + } + return dir, nil +} + +// Clear forgets every entry and its text, keeping the store and its locks (clipdel's own clear +// removes the directory, the daemon's lock with it). +func Clear() (ChangeResult, error) { + dir, err := storeOf() + if err != nil { + return ChangeResult{}, err + } + var out ChangeResult + err = withStoreLock(dir, func() error { + entries, err := readStore(dir) + if err != nil { + return err + } + out.Removed = len(entries) + files, err := os.ReadDir(dir) + if err != nil { + return err + } + for _, f := range files { + switch f.Name() { + case "lock", "session_lock", "line_cache": + continue + } + if f.Type().IsRegular() { + if err := os.Remove(filepath.Join(dir, f.Name())); err != nil { + return err + } + } + } + return os.WriteFile(filepath.Join(dir, "line_cache"), nil, 0o600) + }) + return out, err +} + +// Delete forgets one entry, by id or by its first line. +func Delete(id, line string) (ChangeResult, error) { + if (id == "") == (line == "") { + return ChangeResult{}, errors.New("give the entry's id or its line, one of the two") + } + dir, err := storeOf() + if err != nil { + return ChangeResult{}, err + } + var out ChangeResult + err = withStoreLock(dir, func() error { + raw, err := os.ReadFile(filepath.Join(dir, "line_cache")) + if err != nil && !errors.Is(err, os.ErrNotExist) { + return err + } + var kept []string + for _, l := range strings.Split(strings.TrimRight(string(raw), "\n"), "\n") { + if l == "" { + continue + } + _, text, _ := strings.Cut(l, " ") + if text == line || (id != "" && entryID(text) == id) { + out.Removed++ + _ = os.Remove(filepath.Join(dir, entryID(text))) + continue + } + kept = append(kept, l) + } + if out.Removed == 0 { + return fmt.Errorf("no entry %s%s in the clipboard history", id, line) + } + content := strings.Join(kept, "\n") + if content != "" { + content += "\n" + } + tmp := filepath.Join(dir, ".line_cache.mesh") + if err := os.WriteFile(tmp, []byte(content), 0o600); err != nil { + return err + } + return os.Rename(tmp, filepath.Join(dir, "line_cache")) + }) + if err != nil { + return ChangeResult{}, err + } + entries, _ := readStore(dir) + out.Remaining = len(entries) + return out, nil +} diff --git a/modules/clipmenu/cmd/clipmenu-tools/clipboard_test.go b/modules/clipmenu/cmd/clipmenu-tools/clipboard_test.go new file mode 100644 index 0000000..058b8ae --- /dev/null +++ b/modules/clipmenu/cmd/clipmenu-tools/clipboard_test.go @@ -0,0 +1,163 @@ +package main + +import ( + "errors" + "os" + "os/exec" + "path/filepath" + "strconv" + "strings" + "testing" +) + +const nobody = 4194400 + +func TestEntryIdsAreWhatClipmenuNamesItsFiles(t *testing.T) { + for _, line := range []string{"hello", "", "two words (3 lines)", "ünïcode ✓", strings.Repeat("x", 300)} { + out, err := exec.Command("bash", "-c", `cksum <<< "$1"`, "_", line).Output() + if err != nil { + t.Skip("bash or cksum is missing here") + } + if got, want := entryID(line), strings.TrimSpace(string(out)); got != want { + t.Errorf("%q: %s, cksum says %s", line, got, want) + } + } +} + +// store makes clipmenu's store as clipmenud leaves it, for the account the tools run as. +func store(t *testing.T, clips map[string]string, order ...string) string { + t.Helper() + fakeMachine(t) + runtime := filepath.Join(runUserDir, strconv.Itoa(os.Getuid())) + t.Setenv("USER", "op") + t.Setenv("CM_DIR", "") + dir := filepath.Join(runtime, "clipmenu.6.op") + if err := os.MkdirAll(dir, 0o700); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(runtime, "bus"), nil, 0o600); err != nil { + t.Fatal(err) + } + var cache strings.Builder + for i, line := range order { + cache.WriteString(strconv.FormatInt(1_700_000_000_000_000_000+int64(i)*1_000_000_000, 10) + " " + line + "\n") + if err := os.WriteFile(filepath.Join(dir, entryID(line)), []byte(clips[line]), 0o600); err != nil { + t.Fatal(err) + } + } + if err := os.WriteFile(filepath.Join(dir, "line_cache"), []byte(cache.String()), 0o600); err != nil { + t.Fatal(err) + } + return dir +} + +func TestTheHistoryIsNewestFirstOnceEachWithItsText(t *testing.T) { + store(t, map[string]string{"first": "first", "second (2 lines)": "second\nline two"}, "first", "second (2 lines)", "first") + fakeProcess(t, nobody, "clipmenud") + h, err := History(10, 4096) + if err != nil { + t.Fatal(err) + } + if !h.Collecting || h.Total != 2 || h.Entries[0].Line != "first" || h.Entries[1].Text != "second\nline two" || h.Entries[1].Bytes != 15 { + t.Fatalf("%+v", h) + } + if h, _ := History(1, 3); len(h.Entries) != 1 || h.Entries[0].Text != "fir" || !h.Entries[0].Truncated { + t.Fatalf("limited and cut: %+v", h) + } + if h, _ := History(10, 0); h.Entries[0].Text != "" || h.Entries[0].Bytes != 5 { + t.Fatalf("without text: %+v", h) + } +} + +func TestAnEntryIsDeletedByIdOrLineWithItsText(t *testing.T) { + dir := store(t, map[string]string{"a": "a", "b": "b", "c": "c"}, "a", "b", "c", "a") + r, err := Delete(entryID("a"), "") + if err != nil || r.Removed != 2 || r.Remaining != 2 { + t.Fatalf("by id, both copies: %+v, %v", r, err) + } + if _, err := os.Stat(filepath.Join(dir, entryID("a"))); !errors.Is(err, os.ErrNotExist) { + t.Fatal("the text stayed") + } + if r, err := Delete("", "b"); err != nil || r.Removed != 1 || r.Remaining != 1 { + t.Fatalf("by line: %+v, %v", r, err) + } + if _, err := Delete("", "zzz"); err == nil { + t.Fatal("a missing entry was reported deleted") + } + if _, err := Delete("x", "y"); err == nil { + t.Fatal("both an id and a line were accepted") + } + cache, _ := os.ReadFile(filepath.Join(dir, "line_cache")) + if !strings.HasSuffix(string(cache), " c\n") || strings.Count(string(cache), "\n") != 1 { + t.Fatalf("line cache: %q", cache) + } +} + +func TestClearForgetsEverythingButKeepsTheDaemonsLocks(t *testing.T) { + dir := store(t, map[string]string{"a": "a", "b": "b"}, "a", "b") + if err := os.WriteFile(filepath.Join(dir, "session_lock"), nil, 0o600); err != nil { + t.Fatal(err) + } + r, err := Clear() + if err != nil || r.Removed != 2 { + t.Fatalf("%+v, %v", r, err) + } + left, _ := os.ReadDir(dir) + var names []string + for _, f := range left { + names = append(names, f.Name()) + } + if strings.Join(names, ",") != "line_cache,lock,session_lock" { + t.Fatalf("left: %v", names) + } +} + +func TestCopyHandsTheTextToAnOwnerUnderTheAccountsServiceManager(t *testing.T) { + store(t, nil) + fakeProcess(t, nobody, "i3", "DISPLAY=:1") + bin := fakeBinaries(t, map[string]string{"systemctl": "true", "systemd-run": `echo "$*" > "$LOG"; for last; do :; done; cat "$last" > "$LOG.text"`}) + t.Setenv("LOG", filepath.Join(bin, "log")) + r, err := Copy("secret-free text") + if err != nil || r.Bytes != 16 || !strings.HasPrefix(r.Unit, "clipmenu-copy-") { + t.Fatalf("%+v, %v", r, err) + } + asked, _ := os.ReadFile(filepath.Join(bin, "log")) + if !strings.Contains(string(asked), "--setenv=DISPLAY=:1 -- /bin/sh -c xsel --nodetach --input --clipboard") { + t.Fatalf("asked: %s", asked) + } + handed, _ := os.ReadFile(filepath.Join(bin, "log.text")) + if string(handed) != "secret-free text" { + t.Fatalf("handed over: %q", handed) + } + if _, err := Copy(""); err == nil { + t.Fatal("empty text was accepted") + } +} + +func TestPasteReadsTheClipboardOrSaysThereIsNoSession(t *testing.T) { + fakeMachine(t) + if _, err := Paste(); !errors.Is(err, ErrNoSession) { + t.Fatal(err) + } + fakeProcess(t, nobody, "i3", "DISPLAY=:1") + fakeBinaries(t, map[string]string{"xsel": `[ "$*" = "--output --clipboard" ] && printf 'on the clipboard'`}) + p, err := Paste() + if err != nil || p.Text != "on the clipboard" || p.Bytes != 16 { + t.Fatalf("%+v, %v", p, err) + } +} + +func TestWithoutAStoreTheChangesSayWhy(t *testing.T) { + fakeMachine(t) + runtime := filepath.Join(runUserDir, strconv.Itoa(os.Getuid())) + if err := os.MkdirAll(runtime, 0o700); err != nil { + t.Fatal(err) + } + t.Setenv("USER", "op") + if _, err := Clear(); err == nil || !strings.Contains(err.Error(), "clipmenud has not run") { + t.Fatal(err) + } + if h, err := History(5, 0); err != nil || h.Total != 0 || h.Collecting { + t.Fatalf("an empty history: %+v, %v", h, err) + } +} diff --git a/modules/clipmenu/cmd/clipmenu-tools/main.go b/modules/clipmenu/cmd/clipmenu-tools/main.go new file mode 100644 index 0000000..e8e9212 --- /dev/null +++ b/modules/clipmenu/cmd/clipmenu-tools/main.go @@ -0,0 +1,90 @@ +// clipmenu's Go tools bundle (novox/hq ADR 0188, ADR 0193, ADR 0208): its implementation of +// node-clipboard's verbs `history` and `copy`, and its own tools, served by the node's runtime as the +// operator account. The history is read from clipmenu's own store in the account's runtime directory; +// the clipboard itself is the X session's. +package main + +import ( + "fmt" + "os" + + stdio "git.novox.be/novox/mesh-sdk/go" +) + +func main() { + if err := stdio.Serve("", tools()); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func tools() []stdio.Tool { + return []stdio.Tool{ + { + Name: "node-clipboard.history", + Description: "What the operator copied, newest first: each entry's id, its first line, when, its size " + + "and its text (each cut at max_bytes). Whether the clipboard daemon is collecting.", + Input: map[string]any{ + "limit": map[string]any{"type": "integer", "description": "at most this many entries (default 20, at most 500)"}, + "max_bytes": map[string]any{"type": "integer", "description": "cut each entry's text at this many bytes; 0 leaves the text out (default 4096, at most 65536)"}, + }, + Run: func(args map[string]any) (any, error) { + limit, err := whole(args, "limit", 20, 1, 500) + if err != nil { + return nil, err + } + most, err := whole(args, "max_bytes", 4096, 0, 65536) + if err != nil { + return nil, err + } + return History(limit, most) + }, + }, + { + Name: "node-clipboard.copy", + Description: "Put text on the operator's clipboard, as if they had copied it; it enters the history " + + "like any copy. Answers how many bytes.", + Input: map[string]any{ + "type": "object", + "properties": map[string]any{ + "text": map[string]any{"type": "string", "description": fmt.Sprintf("the text (at most %d bytes)", mostCopy)}, + }, + "required": []string{"text"}, + }, + Run: func(args map[string]any) (any, error) { + t, ok := args["text"].(string) + if !ok { + return nil, fmt.Errorf("text is required, as a string") + } + return Copy(t) + }, + }, + { + Name: "clipmenu_paste", + Description: "What the operator's clipboard holds right now, as text (cut at 64 KiB, said in truncated).", + Run: func(map[string]any) (any, error) { return Paste() }, + }, + { + Name: "clipmenu_clear", + Description: "Forget the whole clipboard history. What is on the clipboard now stays there.", + Run: func(map[string]any) (any, error) { return Clear() }, + }, + { + Name: "clipmenu_delete", + Description: "Forget one entry of the clipboard history, by its id as the history answers it, or by " + + "its first line exactly.", + Input: map[string]any{ + "id": map[string]any{"type": "string", "description": "the entry's id"}, + "line": map[string]any{"type": "string", "description": "the entry's first line, exactly"}, + }, + Run: func(args map[string]any) (any, error) { + id, err := text(args, "id", false) + if err != nil { + return nil, err + } + line, _ := args["line"].(string) + return Delete(id, line) + }, + }, + } +} diff --git a/modules/clipmenu/cmd/clipmenu-tools/manifest_helpers_test.go b/modules/clipmenu/cmd/clipmenu-tools/manifest_helpers_test.go new file mode 100644 index 0000000..d4fb76d --- /dev/null +++ b/modules/clipmenu/cmd/clipmenu-tools/manifest_helpers_test.go @@ -0,0 +1,175 @@ +package main + +import ( + "encoding/json" + "os" + "path/filepath" + "strings" + "testing" +) + +// The module's manifest, read the way the catalogue reads it, for the manifest tests. The same in +// every desktop module that carries it. + +type manifest struct { + Module string `json:"module"` + Version string `json:"version"` + Capabilities []string `json:"capabilities"` + Requires []string `json:"requires"` + Claims []claim `json:"claims"` + Seats []any `json:"seats"` + Tools []string `json:"tools"` + Environment *environment `json:"environment"` + Shell []shellCode `json:"shell"` + Resources []map[string]any `json:"resources"` + Build struct { + Artifacts []map[string]any `json:"artifacts"` + } `json:"build"` +} + +type claim struct { + Name string `json:"name"` + Scope string `json:"scope"` + Serves []string `json:"serves"` +} + +type environment struct { + Variables map[string]string `json:"variables"` + Path []map[string]any `json:"path"` +} + +type shellCode struct { + For string `json:"for"` + Slot string `json:"slot"` + Code string `json:"code"` +} + +func readManifest(t *testing.T) manifest { + t.Helper() + raw, err := os.ReadFile(filepath.Join("..", "..", "module.json")) + if err != nil { + t.Fatal(err) + } + dec := json.NewDecoder(strings.NewReader(string(raw))) + dec.DisallowUnknownFields() + var m manifest + if err := dec.Decode(&m); err != nil { + t.Fatalf("module.json: %v", err) + } + return m +} + +func (m manifest) resource(t *testing.T, id string) map[string]any { + t.Helper() + for _, r := range m.Resources { + if r["id"] == id { + return r + } + } + t.Fatalf("no resource %q", id) + return nil +} + +func (m manifest) packages() (present, absent []string) { + for _, r := range m.Resources { + if r["type"] == "package" { + if r["absent"] == true { + absent = append(absent, r["package"].(string)) + } else { + present = append(present, r["package"].(string)) + } + } + } + return present, absent +} + +// sameAsSource checks that a file resource's content is byte for byte the module's source file, so +// the readable file in the repository is what the machine gets. +func (m manifest) sameAsSource(t *testing.T, id, source string) { + t.Helper() + want, err := os.ReadFile(filepath.Join("..", "..", source)) + if err != nil { + t.Fatal(err) + } + r := m.resource(t, id) + if r["type"] != "file" { + t.Fatalf("%s is a %v, not a file", id, r["type"]) + } + if got, _ := r["content"].(string); got != string(want) { + t.Fatalf("resource %s's content is not %s: edit the source and copy it into module.json", id, source) + } + if r["owner"] != "${machine:account}" && !strings.HasPrefix(r["path"].(string), "/etc/") { + t.Fatalf("%s under the home is the account's", id) + } +} + +// checkTheToolsAgree checks that the manifest lists the module's own tools exactly, that the bundle +// serves each seat verb the claims promise as ., and that the Go bundle is declared. +func checkTheToolsAgree(t *testing.T, m manifest) { + t.Helper() + own, seat := map[string]bool{}, map[string]bool{} + for _, tool := range tools() { + if strings.Contains(tool.Name, ".") { + seat[tool.Name] = true + } else { + own[tool.Name] = true + } + if strings.TrimSpace(tool.Description) == "" { + t.Errorf("%s has no description", tool.Name) + } + } + listed := map[string]bool{} + for _, name := range m.Tools { + listed[name] = true + if !own[name] { + t.Errorf("module.json lists %s, which the bundle does not serve", name) + } + } + for name := range own { + if !listed[name] { + t.Errorf("the bundle serves %s, which module.json does not list", name) + } + if !strings.HasPrefix(name, strings.ReplaceAll(m.Module, "-", "_")+"_") { + t.Errorf("%s is not prefixed with the module's name", name) + } + } + promised := map[string]bool{} + for _, c := range m.Claims { + for _, verb := range c.Serves { + promised[c.Name+"."+verb] = true + if !seat[c.Name+"."+verb] { + t.Errorf("the claim on %s promises %s, which the bundle does not serve", c.Name, verb) + } + } + } + for name := range seat { + if !promised[name] { + t.Errorf("the bundle serves %s, which no claim promises", name) + } + } + var bundle map[string]any + for _, a := range m.Build.Artifacts { + if a["kind"] == "bundle" { + bundle = a + } + } + if bundle == nil || bundle["language"] != "go" || bundle["system"] != "arch" || + bundle["from"] != "cmd/"+m.Module+"-tools" || bundle["binary"] != m.Module+"-tools" { + t.Errorf("the Go tools bundle: %v", bundle) + } +} + +// checkNoSecretsOrInstallationNames refuses what a catalogue manifest must never carry. +func checkNoSecretsOrInstallationNames(t *testing.T) { + t.Helper() + raw, err := os.ReadFile(filepath.Join("..", "..", "module.json")) + if err != nil { + t.Fatal(err) + } + s := strings.ToLower(string(raw)) + for _, never := range []string{"/home/", "jochen", "g14", "shanks", "novox.be", "api_key", ".hal/", "greenclip daemon"} { + if strings.Contains(s, never) { + t.Errorf("module.json names %q", never) + } + } +} diff --git a/modules/clipmenu/cmd/clipmenu-tools/manifest_test.go b/modules/clipmenu/cmd/clipmenu-tools/manifest_test.go new file mode 100644 index 0000000..e0adb4c --- /dev/null +++ b/modules/clipmenu/cmd/clipmenu-tools/manifest_test.go @@ -0,0 +1,64 @@ +package main + +import ( + "reflect" + "strings" + "testing" +) + +// clipmenu's shape (novox/hq ADR 0208, research 026/04): it claims node-clipboard serving history +// and copy, requires the X display on its own machine, replaces greenclip, starts its daemon once +// from the session's start, and binds its menu as an i3 drop-in through the launcher's dmenu command. + +func TestItClaimsTheClipboardSeatServingHistoryAndCopy(t *testing.T) { + m := readManifest(t) + if m.Module != "clipmenu" || m.Seats != nil { + t.Fatalf("module %q declares seats %v", m.Module, m.Seats) + } + if !reflect.DeepEqual(m.Claims, []claim{{Name: "node-clipboard", Scope: "node", Serves: []string{"history", "copy"}}}) { + t.Fatalf("claims: %+v", m.Claims) + } + if !reflect.DeepEqual(m.Requires, []string{"x11-display"}) { + t.Fatalf("requires: %v", m.Requires) + } + present, absent := m.packages() + if !reflect.DeepEqual(present, []string{"clipmenu"}) || !reflect.DeepEqual(absent, []string{"rofi-greenclip"}) { + t.Fatalf("packages: %v, absent %v", present, absent) + } +} + +func TestTheDaemonStartsOnceFromTheSessionsStart(t *testing.T) { + m := readManifest(t) + if len(m.Shell) != 1 || m.Shell[0].For != "xinitrc" || m.Shell[0].Slot != "normal" { + t.Fatalf("%+v", m.Shell) + } + code := m.Shell[0].Code + if strings.Count(code, "\nclipmenud &\n") != 1 || strings.Contains(code, "greenclip") { + t.Fatalf("%q", code) + } + for _, r := range m.Resources { + if r["type"] == "service" || r["type"] == "process" { + t.Fatalf("a second start: %v", r) + } + } +} + +func TestItsSettingsAreEnvironmentAndItsMenuIsTheLaunchersDmenu(t *testing.T) { + m := readManifest(t) + if !reflect.DeepEqual(m.Environment.Variables, map[string]string{"CM_SELECTIONS": "clipboard", "CM_MAX_CLIPS": "500", "CM_HISTLENGTH": "15"}) { + t.Fatalf("%v", m.Environment.Variables) + } + if _, set := m.Environment.Variables["CM_LAUNCHER"]; set { + t.Fatal("the launcher is clipmenu's default, dmenu: the seat's command") + } + m.sameAsSource(t, "i3-bindings", "files/i3/50-clipmenu.conf") + if c := m.resource(t, "i3-bindings")["content"].(string); !strings.Contains(c, "bindsym $mod+period exec --no-startup-id clipmenu") { + t.Fatalf("%s", c) + } +} + +func TestTheToolsAgreeWithTheManifest(t *testing.T) { + m := readManifest(t) + checkTheToolsAgree(t, m) + checkNoSecretsOrInstallationNames(t) +} diff --git a/modules/clipmenu/cmd/clipmenu-tools/session.go b/modules/clipmenu/cmd/clipmenu-tools/session.go new file mode 100644 index 0000000..dc21774 --- /dev/null +++ b/modules/clipmenu/cmd/clipmenu-tools/session.go @@ -0,0 +1,423 @@ +// The operator's graphical session, as a tool the node's runtime runs finds it (novox/hq ADR 0208). +// +// The runtime is a system service running as the operator account (ADR 0175): it has the account's +// uid and none of the session's environment — no DISPLAY, no XAUTHORITY, no session bus. A tool that +// draws on the screen or talks to the desktop's D-Bus must find them. It reads them from a process of +// the account that is part of the session (the window manager first), the same thing `loginctl` and +// a person's own shell would point at, and says where it found them. +// +// Long-lived programs a tool starts go to the account's own service manager through `systemd-run +// --user`, never as children of the tool: the runtime's unit is a cgroup the service manager empties +// whenever the runtime restarts, and a compositor or a clipboard owner started from inside it would +// die with it. +// +// This file is the same in every desktop module that carries it; it moves into the Go SDK once a +// second consumer outside the desktop wants it. +package main + +import ( + "bytes" + "errors" + "fmt" + "os" + "os/exec" + "path/filepath" + "sort" + "strconv" + "strings" + "syscall" + "time" +) + +// Where the session is looked for. Variables so a test can point them at a fake tree. +var ( + procRoot = "/proc" + runUserDir = "/run/user" + x11Sockets = "/tmp/.X11-unix" +) + +// sessionHolders are the processes whose environment is the session's, best first: the window +// manager is the session, the rest are its children. Anything else carrying DISPLAY ranks after them. +var sessionHolders = []string{"i3", "sway", "i3bar", "picom", "xss-lock", "dunst", "clipmenud", "xterm"} + +// sessionKeys are the variables a session carries that a tool hands on to what it runs. +var sessionKeys = []string{"DISPLAY", "XAUTHORITY", "WAYLAND_DISPLAY", "DBUS_SESSION_BUS_ADDRESS", + "XDG_RUNTIME_DIR", "XDG_SESSION_ID", "I3SOCK"} + +// Session is what a tool needs to reach the operator's desktop. +type Session struct { + UID int `json:"uid"` + Display string `json:"display,omitempty"` + XAuthority string `json:"xauthority,omitempty"` + Wayland string `json:"wayland_display,omitempty"` + Bus string `json:"bus,omitempty"` + RuntimeDir string `json:"runtime_dir,omitempty"` + SessionID string `json:"session_id,omitempty"` + I3Sock string `json:"i3sock,omitempty"` + // From says where the values were found: the tool's own environment, a process, or the socket. + From string `json:"from"` +} + +// ErrNoSession is answered by a tool that needs the desktop when nobody is logged in to it. +var ErrNoSession = errors.New("no graphical session") + +// ErrTimedOut is what run answers for a command ended because it ran past its time. +var ErrTimedOut = errors.New("timed out") + +// ErrNoBus is answered by a tool that needs the session bus when the account has none. +var ErrNoBus = errors.New("no session bus") + +// operatorHome is the account's home: what the runtime was told, else the process's own. +func operatorHome() string { + if h := strings.TrimSpace(os.Getenv("MESH_OPERATOR_HOME")); h != "" { + return h + } + h, _ := os.UserHomeDir() + return h +} + +// findSession finds the graphical session of the account this tool runs as, or answers +// ErrNoSession with what it looked at. +func findSession() (Session, error) { + s := findEnvironment() + if s.Display == "" && s.Wayland == "" { + return s, fmt.Errorf("%w for uid %d on this machine: no process of the account carries DISPLAY "+ + "or WAYLAND_DISPLAY, and no X server socket in %s has an authority file to go with it. "+ + "Is anyone logged in to the desktop?", ErrNoSession, s.UID, x11Sockets) + } + return s, nil +} + +// findBus finds the account's session bus, which a logged-in account has whether or not a desktop +// is running. +func findBus() (Session, error) { + s := findEnvironment() + if s.Bus == "" { + return s, fmt.Errorf("%w for uid %d: DBUS_SESSION_BUS_ADDRESS is not set and %s does not exist "+ + "(the account is not logged in)", ErrNoBus, s.UID, filepath.Join(runUserDir, strconv.Itoa(s.UID), "bus")) + } + return s, nil +} + +func findEnvironment() Session { + uid := os.Getuid() + s := Session{UID: uid} + own := map[string]string{} + for _, k := range sessionKeys { + own[k] = os.Getenv(k) + } + if own["DISPLAY"] != "" || own["WAYLAND_DISPLAY"] != "" { + s.fill(own) + s.From = "the tool's own environment" + } else if pid, comm, env, ok := sessionProcess(uid); ok { + s.fill(env) + s.From = fmt.Sprintf("process %s (pid %d)", comm, pid) + } else if display, ok := lonelyX11Socket(); ok { + if a := filepath.Join(operatorHome(), ".Xauthority"); exists(a) { + s.Display, s.XAuthority = display, a + s.From = "the X server socket and the account's ~/.Xauthority" + } + s.fill(own) + } else { + s.fill(own) + s.From = "nothing: no session found" + } + // The bus and the runtime directory are the account's, whether or not the process named them. + runtime := filepath.Join(runUserDir, strconv.Itoa(uid)) + if s.RuntimeDir == "" && exists(runtime) { + s.RuntimeDir = runtime + } + if s.Bus == "" && s.RuntimeDir != "" && exists(filepath.Join(s.RuntimeDir, "bus")) { + s.Bus = "unix:path=" + filepath.Join(s.RuntimeDir, "bus") + } + return s +} + +func (s *Session) fill(env map[string]string) { + set := func(dst *string, key string) { + if *dst == "" { + *dst = env[key] + } + } + set(&s.Display, "DISPLAY") + set(&s.XAuthority, "XAUTHORITY") + set(&s.Wayland, "WAYLAND_DISPLAY") + set(&s.Bus, "DBUS_SESSION_BUS_ADDRESS") + set(&s.RuntimeDir, "XDG_RUNTIME_DIR") + set(&s.SessionID, "XDG_SESSION_ID") + set(&s.I3Sock, "I3SOCK") +} + +// sessionProcess is the best process of this uid whose environment names a display. +func sessionProcess(uid int) (int, string, map[string]string, bool) { + entries, err := os.ReadDir(procRoot) + if err != nil { + return 0, "", nil, false + } + type candidate struct { + pid int + comm string + env map[string]string + rank int + } + var found []candidate + for _, e := range entries { + pid, err := strconv.Atoi(e.Name()) + if err != nil { + continue + } + dir := filepath.Join(procRoot, e.Name()) + if owner, ok := ownerOf(dir); !ok || owner != uid { + continue + } + raw, err := os.ReadFile(filepath.Join(dir, "environ")) + if err != nil { + continue + } + env := parseEnviron(raw) + if env["DISPLAY"] == "" && env["WAYLAND_DISPLAY"] == "" { + continue + } + comm := readTrimmed(filepath.Join(dir, "comm")) + rank := len(sessionHolders) + for i, h := range sessionHolders { + if h == comm { + rank = i + break + } + } + found = append(found, candidate{pid, comm, env, rank}) + } + if len(found) == 0 { + return 0, "", nil, false + } + sort.Slice(found, func(i, j int) bool { + if found[i].rank != found[j].rank { + return found[i].rank < found[j].rank + } + return found[i].pid > found[j].pid // the newer of two equals + }) + best := found[0] + return best.pid, best.comm, best.env, true +} + +func parseEnviron(raw []byte) map[string]string { + env := map[string]string{} + for _, kv := range bytes.Split(raw, []byte{0}) { + if i := bytes.IndexByte(kv, '='); i > 0 { + env[string(kv[:i])] = string(kv[i+1:]) + } + } + return env +} + +func ownerOf(path string) (int, bool) { + info, err := os.Stat(path) + if err != nil { + return 0, false + } + st, ok := info.Sys().(*syscall.Stat_t) + if !ok { + return 0, false + } + return int(st.Uid), true +} + +// lonelyX11Socket is the display of the one X server socket there is, when there is exactly one. +func lonelyX11Socket() (string, bool) { + entries, err := os.ReadDir(x11Sockets) + if err != nil { + return "", false + } + var displays []string + for _, e := range entries { + if n := strings.TrimPrefix(e.Name(), "X"); n != e.Name() { + if _, err := strconv.Atoi(n); err == nil { + displays = append(displays, ":"+n) + } + } + } + if len(displays) != 1 { + return "", false + } + return displays[0], true +} + +func readTrimmed(path string) string { + b, err := os.ReadFile(path) + if err != nil { + return "" + } + return strings.TrimSpace(string(b)) +} + +func exists(path string) bool { + _, err := os.Stat(path) + return err == nil +} + +// Env is this process's environment with the session's variables in place of its own. +func (s Session) Env() []string { + drop := map[string]bool{} + for _, k := range sessionKeys { + drop[k] = true + } + var env []string + for _, kv := range os.Environ() { + if i := strings.IndexByte(kv, '='); i > 0 && drop[kv[:i]] { + continue + } + env = append(env, kv) + } + add := func(k, v string) { + if v != "" { + env = append(env, k+"="+v) + } + } + add("DISPLAY", s.Display) + add("XAUTHORITY", s.XAuthority) + add("WAYLAND_DISPLAY", s.Wayland) + add("DBUS_SESSION_BUS_ADDRESS", s.Bus) + add("XDG_RUNTIME_DIR", s.RuntimeDir) + add("XDG_SESSION_ID", s.SessionID) + add("I3SOCK", s.I3Sock) + return env +} + +// mostOutput bounds what a command may answer with, per stream. +const mostOutput = 256 << 10 + +// Result is what a command did. +type Result struct { + Stdout string `json:"stdout"` + Stderr string `json:"stderr,omitempty"` + Code int `json:"code"` + Truncated bool `json:"truncated,omitempty"` +} + +// run runs a command in the session's environment, its input given, ended with everything it +// started after timeout. A command that is not installed is an error naming it; one that exits +// non-zero is a Result with its code, for the caller to judge. +func (s Session) run(timeout time.Duration, stdin string, name string, args ...string) (Result, error) { + path, err := exec.LookPath(name) + if err != nil { + return Result{}, fmt.Errorf("%s is not installed on this machine", name) + } + cmd := exec.Command(path, args...) + cmd.Env = s.Env() + if home := operatorHome(); exists(home) { + cmd.Dir = home + } + if stdin != "" { + cmd.Stdin = strings.NewReader(stdin) + } + var out, errOut capped + cmd.Stdout, cmd.Stderr = &out, &errOut + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + if err := cmd.Start(); err != nil { + return Result{}, fmt.Errorf("%s: %w", name, err) + } + done := make(chan error, 1) + go func() { done <- cmd.Wait() }() + select { + case err = <-done: + case <-time.After(timeout): + _ = syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) + <-done + return Result{Stdout: out.String(), Stderr: errOut.String()}, + fmt.Errorf("%s did not finish within %s and was ended: %w", name, timeout, ErrTimedOut) + } + r := Result{Stdout: out.String(), Stderr: errOut.String(), Truncated: out.cut || errOut.cut} + var exit *exec.ExitError + if errors.As(err, &exit) { + r.Code = exit.ExitCode() + } else if err != nil { + return r, fmt.Errorf("%s: %w", name, err) + } + return r, nil +} + +// detach starts a long-lived program under the account's own service manager, as a transient unit +// that carries the session's display, so it outlives the runtime that asked for it. A unit already +// running under the same name is stopped first, so a fixed name means "at most one". +func (s Session) detach(unit string, args ...string) error { + if s.RuntimeDir == "" { + return fmt.Errorf("%w: the account's runtime directory is missing, so its service manager "+ + "cannot be reached", ErrNoBus) + } + _, _ = s.run(5*time.Second, "", "systemctl", "--user", "stop", unit+".service") + call := []string{"--user", "--collect", "--quiet", "--unit=" + unit} + for _, kv := range [][2]string{{"DISPLAY", s.Display}, {"XAUTHORITY", s.XAuthority}, + {"WAYLAND_DISPLAY", s.Wayland}, {"XDG_SESSION_ID", s.SessionID}, {"I3SOCK", s.I3Sock}} { + if kv[1] != "" { + call = append(call, "--setenv="+kv[0]+"="+kv[1]) + } + } + call = append(call, "--") + call = append(call, args...) + r, err := s.run(10*time.Second, "", "systemd-run", call...) + if err != nil { + return err + } + if r.Code != 0 { + return fmt.Errorf("systemd-run %s: %s", unit, strings.TrimSpace(r.Stderr)) + } + return nil +} + +// uniqueUnit is a transient unit name that will not collide with an earlier one. +func uniqueUnit(prefix string) string { + return fmt.Sprintf("%s-%d", prefix, time.Now().UnixNano()) +} + +type capped struct { + bytes.Buffer + cut bool +} + +func (c *capped) Write(p []byte) (int, error) { + if room := mostOutput - c.Len(); room < len(p) { + if room > 0 { + c.Buffer.Write(p[:room]) + } + c.cut = true + return len(p), nil + } + return c.Buffer.Write(p) +} + +// processesOf are the pids of this uid's processes whose command name is comm, oldest first. +func processesOf(comm string) []int { + entries, err := os.ReadDir(procRoot) + if err != nil { + return nil + } + uid := os.Getuid() + var pids []int + for _, e := range entries { + pid, err := strconv.Atoi(e.Name()) + if err != nil { + continue + } + dir := filepath.Join(procRoot, e.Name()) + if owner, ok := ownerOf(dir); !ok || owner != uid { + continue + } + if readTrimmed(filepath.Join(dir, "comm")) == comm { + pids = append(pids, pid) + } + } + sort.Ints(pids) + return pids +} + +// signalAll sends sig to every process of this uid named comm, and answers the pids it reached. +func signalAll(comm string, sig syscall.Signal) []int { + var reached []int + for _, pid := range processesOf(comm) { + if syscall.Kill(pid, sig) == nil { + reached = append(reached, pid) + } + } + return reached +} diff --git a/modules/clipmenu/cmd/clipmenu-tools/session_test.go b/modules/clipmenu/cmd/clipmenu-tools/session_test.go new file mode 100644 index 0000000..800cc6d --- /dev/null +++ b/modules/clipmenu/cmd/clipmenu-tools/session_test.go @@ -0,0 +1,174 @@ +package main + +import ( + "errors" + "os" + "path/filepath" + "strconv" + "strings" + "testing" + "time" +) + +// fakeMachine points the session finder at a temporary /proc, /run/user and X socket directory, with +// none of the test process's own session variables, and gives back the root. +func fakeMachine(t *testing.T) string { + t.Helper() + root := t.TempDir() + procRoot, runUserDir, x11Sockets = filepath.Join(root, "proc"), filepath.Join(root, "run-user"), filepath.Join(root, "x11") + for _, d := range []string{procRoot, runUserDir, x11Sockets} { + if err := os.MkdirAll(d, 0o755); err != nil { + t.Fatal(err) + } + } + for _, k := range sessionKeys { + t.Setenv(k, "") + } + t.Setenv("MESH_OPERATOR_HOME", filepath.Join(root, "home")) + t.Cleanup(func() { procRoot, runUserDir, x11Sockets = "/proc", "/run/user", "/tmp/.X11-unix" }) + return root +} + +func fakeProcess(t *testing.T, pid int, comm string, env ...string) { + t.Helper() + dir := filepath.Join(procRoot, strconv.Itoa(pid)) + if err := os.MkdirAll(dir, 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, "comm"), []byte(comm+"\n"), 0o644); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, "environ"), []byte(strings.Join(env, "\x00")+"\x00"), 0o600); err != nil { + t.Fatal(err) + } +} + +func TestTheSessionIsReadFromTheWindowManagerBeforeAnyOtherProcess(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 900, "xterm", "DISPLAY=:9", "XAUTHORITY=/elsewhere") + fakeProcess(t, 100, "i3", "DISPLAY=:1", "XAUTHORITY=/home/op/.Xauthority", + "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus", "XDG_SESSION_ID=3", "SECRET_TOKEN=never-copied") + fakeProcess(t, 50, "bash", "PATH=/usr/bin") + s, err := findSession() + if err != nil { + t.Fatal(err) + } + if s.Display != ":1" || s.XAuthority != "/home/op/.Xauthority" || s.SessionID != "3" || !strings.Contains(s.From, "i3 (pid 100)") { + t.Fatalf("the window manager's environment: %+v", s) + } + for _, kv := range s.Env() { + if strings.HasPrefix(kv, "SECRET_TOKEN=") { + t.Fatal("a variable of the session process that is not a session variable was handed on") + } + } +} + +func TestAnyProcessCarryingADisplayServesWhenTheWindowManagerIsNotFound(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 10, "firefox", "DISPLAY=:0") + fakeProcess(t, 20, "firefox", "DISPLAY=:2") + s, err := findSession() + if err != nil || s.Display != ":2" { + t.Fatalf("the newest of two equals: %+v, %v", s, err) + } +} + +func TestNoSessionIsAClearAnswerNotAGuess(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 10, "sshd", "PATH=/usr/bin") + _, err := findSession() + if !errors.Is(err, ErrNoSession) || !strings.Contains(err.Error(), "logged in to the desktop") { + t.Fatalf("no session: %v", err) + } +} + +func TestOneXSocketAndTheAccountsAuthorityFileAreASession(t *testing.T) { + root := fakeMachine(t) + if err := os.WriteFile(filepath.Join(x11Sockets, "X0"), nil, 0o644); err != nil { + t.Fatal(err) + } + if err := os.MkdirAll(filepath.Join(root, "home"), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(root, "home", ".Xauthority"), nil, 0o600); err != nil { + t.Fatal(err) + } + s, err := findSession() + if err != nil || s.Display != ":0" || !strings.HasSuffix(s.XAuthority, "/home/.Xauthority") { + t.Fatalf("socket and authority: %+v, %v", s, err) + } +} + +func TestTheBusIsTheAccountsRuntimeDirectoryWhenNoProcessNamesIt(t *testing.T) { + fakeMachine(t) + runtime := filepath.Join(runUserDir, strconv.Itoa(os.Getuid())) + if _, err := findBus(); !errors.Is(err, ErrNoBus) { + t.Fatalf("no runtime directory is no bus: %v", err) + } + if err := os.MkdirAll(runtime, 0o700); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(runtime, "bus"), nil, 0o600); err != nil { + t.Fatal(err) + } + s, err := findBus() + if err != nil || s.Bus != "unix:path="+filepath.Join(runtime, "bus") || s.RuntimeDir != runtime { + t.Fatalf("bus: %+v, %v", s, err) + } + env := strings.Join(s.Env(), "\n") + if !strings.Contains(env, "XDG_RUNTIME_DIR="+runtime) || !strings.Contains(env, "DBUS_SESSION_BUS_ADDRESS=unix:path=") { + t.Fatalf("the bus is handed on: %s", env) + } +} + +func TestACommandIsBoundedAndANonZeroExitIsAResult(t *testing.T) { + fakeMachine(t) + s := Session{} + r, err := s.run(5*time.Second, "in", "sh", "-c", "cat; echo err >&2; exit 3") + if err != nil || r.Stdout != "in" || r.Code != 3 || strings.TrimSpace(r.Stderr) != "err" { + t.Fatalf("result: %+v, %v", r, err) + } + start := time.Now() + if _, err := s.run(200*time.Millisecond, "", "sh", "-c", "sleep 30 & sleep 30"); err == nil || time.Since(start) > 5*time.Second { + t.Fatalf("a command past its time is ended with what it started: %v after %s", err, time.Since(start)) + } + if _, err := s.run(time.Second, "", "no-such-program-here"); err == nil || !strings.Contains(err.Error(), "not installed") { + t.Fatalf("a missing program: %v", err) + } +} + +func TestDetachAsksTheAccountsServiceManagerWithTheSessionsDisplay(t *testing.T) { + fakeMachine(t) + bin := fakeBinaries(t, map[string]string{ + "systemctl": `echo "systemctl $*" >> "$LOG"`, + "systemd-run": `echo "systemd-run $*" >> "$LOG"`, + }) + log := filepath.Join(bin, "log") + t.Setenv("LOG", log) + s := Session{Display: ":1", XAuthority: "/x", RuntimeDir: "/run/user/1"} + if err := s.detach("picom-session", "picom", "--config", "/c"); err != nil { + t.Fatal(err) + } + got, _ := os.ReadFile(log) + want := "systemctl --user stop picom-session.service\n" + + "systemd-run --user --collect --quiet --unit=picom-session --setenv=DISPLAY=:1 --setenv=XAUTHORITY=/x -- picom --config /c\n" + if string(got) != want { + t.Fatalf("detach ran:\n%s\nwant:\n%s", got, want) + } + if err := (Session{}).detach("x", "y"); !errors.Is(err, ErrNoBus) { + t.Fatalf("no runtime directory: %v", err) + } +} + +// fakeBinaries puts shell scripts named for programs first on PATH, and answers their directory. +func fakeBinaries(t *testing.T, scripts map[string]string) string { + t.Helper() + dir := t.TempDir() + for name, body := range scripts { + if err := os.WriteFile(filepath.Join(dir, name), []byte("#!/bin/sh\n"+body+"\n"), 0o755); err != nil { + t.Fatal(err) + } + } + t.Setenv("PATH", dir+string(os.PathListSeparator)+os.Getenv("PATH")) + return dir +} diff --git a/modules/clipmenu/files/i3/50-clipmenu.conf b/modules/clipmenu/files/i3/50-clipmenu.conf new file mode 100644 index 0000000..41835e6 --- /dev/null +++ b/modules/clipmenu/files/i3/50-clipmenu.conf @@ -0,0 +1,5 @@ +# The clipboard's history key (module clipmenu, novox/hq ADR 0208). Owned by the mesh: replaced at +# every push. clipmenu shows the history through `dmenu`, the node's dmenu-compatible command, which +# the holder of node-launcher answers (rofi on the workstations); the chosen entry is put back on the +# clipboard. +bindsym $mod+period exec --no-startup-id clipmenu -p Clipboard diff --git a/modules/clipmenu/go.mod b/modules/clipmenu/go.mod new file mode 100644 index 0000000..f6c083d --- /dev/null +++ b/modules/clipmenu/go.mod @@ -0,0 +1,5 @@ +module clipmenu + +go 1.22 + +require git.novox.be/novox/mesh-sdk/go v0.1.7 diff --git a/modules/clipmenu/go.sum b/modules/clipmenu/go.sum new file mode 100644 index 0000000..b474419 --- /dev/null +++ b/modules/clipmenu/go.sum @@ -0,0 +1,2 @@ +git.novox.be/novox/mesh-sdk/go v0.1.7 h1:C0sTQmtTiyYH7bnqZb7PusXnqA37gKuT7Nqjn9gG47w= +git.novox.be/novox/mesh-sdk/go v0.1.7/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= diff --git a/modules/clipmenu/module.json b/modules/clipmenu/module.json new file mode 100644 index 0000000..1cb1991 --- /dev/null +++ b/modules/clipmenu/module.json @@ -0,0 +1,75 @@ +{ + "module": "clipmenu", + "version": "1", + "capabilities": [ + "package-manager" + ], + "requires": [ + "x11-display" + ], + "claims": [ + { + "name": "node-clipboard", + "scope": "node", + "serves": [ + "history", + "copy" + ] + } + ], + "tools": [ + "clipmenu_paste", + "clipmenu_clear", + "clipmenu_delete" + ], + "environment": { + "variables": { + "CM_SELECTIONS": "clipboard", + "CM_MAX_CLIPS": "500", + "CM_HISTLENGTH": "15" + } + }, + "shell": [ + { + "for": "xinitrc", + "slot": "normal", + "code": "# The clipboard's history (module clipmenu, novox/hq ADR 0208): clipmenud collects every copy from\n# here on, once per session. It keeps the history in the account's runtime directory, so a reboot\n# forgets it, and with it every password that was ever copied.\nclipmenud &\n" + } + ], + "resources": [ + { + "id": "package", + "type": "package", + "package": "clipmenu" + }, + { + "id": "greenclip", + "type": "package", + "package": "rofi-greenclip", + "absent": true + }, + { + "id": "i3-bindings", + "type": "file", + "path": "${machine:account-home}/.config/i3/config.d/50-clipmenu.conf", + "owner": "${machine:account}", + "mode": "0644", + "content": "# The clipboard's history key (module clipmenu, novox/hq ADR 0208). Owned by the mesh: replaced at\n# every push. clipmenu shows the history through `dmenu`, the node's dmenu-compatible command, which\n# the holder of node-launcher answers (rofi on the workstations); the chosen entry is put back on the\n# clipboard.\nbindsym $mod+period exec --no-startup-id clipmenu -p Clipboard\n" + } + ], + "build": { + "artifacts": [ + { + "name": "tools", + "kind": "bundle", + "language": "go", + "system": "arch", + "from": "cmd/clipmenu-tools", + "binary": "clipmenu-tools", + "loads": [ + "clipmenu-tools" + ] + } + ] + } +} From 91c6fa6fce2f6100239371dcc21bd49660e24ec6 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 4 Oct 2026 13:00:35 +0200 Subject: [PATCH 06/15] feh: the wallpaper as a module, its image an archive of its own (hq ADR 0208, ADR 0205) ~/.fehbg stops pointing into the predecessor's tree; the session's xinitrc slot runs it once; Go tools set (for the session) and current. --- modules/feh/README.md | 47 ++ modules/feh/cmd/feh-tools/args.go | 97 ++++ modules/feh/cmd/feh-tools/main.go | 53 +++ .../cmd/feh-tools/manifest_helpers_test.go | 175 ++++++++ modules/feh/cmd/feh-tools/manifest_test.go | 79 ++++ modules/feh/cmd/feh-tools/session.go | 423 ++++++++++++++++++ modules/feh/cmd/feh-tools/session_test.go | 174 +++++++ modules/feh/cmd/feh-tools/wallpaper.go | 174 +++++++ modules/feh/cmd/feh-tools/wallpaper_test.go | 92 ++++ modules/feh/files/fehbg | 6 + modules/feh/files/i3/50-feh.conf | 3 + modules/feh/go.mod | 5 + modules/feh/go.sum | 2 + modules/feh/module.json | 71 +++ modules/feh/wallpaper/default.jpg | Bin 0 -> 955517 bytes 15 files changed, 1401 insertions(+) create mode 100644 modules/feh/README.md create mode 100644 modules/feh/cmd/feh-tools/args.go create mode 100644 modules/feh/cmd/feh-tools/main.go create mode 100644 modules/feh/cmd/feh-tools/manifest_helpers_test.go create mode 100644 modules/feh/cmd/feh-tools/manifest_test.go create mode 100644 modules/feh/cmd/feh-tools/session.go create mode 100644 modules/feh/cmd/feh-tools/session_test.go create mode 100644 modules/feh/cmd/feh-tools/wallpaper.go create mode 100644 modules/feh/cmd/feh-tools/wallpaper_test.go create mode 100755 modules/feh/files/fehbg create mode 100644 modules/feh/files/i3/50-feh.conf create mode 100644 modules/feh/go.mod create mode 100644 modules/feh/go.sum create mode 100644 modules/feh/module.json create mode 100644 modules/feh/wallpaper/default.jpg diff --git a/modules/feh/README.md b/modules/feh/README.md new file mode 100644 index 0000000..028506d --- /dev/null +++ b/modules/feh/README.md @@ -0,0 +1,47 @@ +# feh + +The wallpaper as a module (novox/hq ADR 0208, research 026/05). + +- Installs `feh` and requires `x11-display` on its own machine. It holds no seat: a wallpaper is not a + role anything else calls. +- **Carries the wallpaper itself.** `wallpaper/default.jpg` is built into an archive of the module + (ADR 0205) and unpacked into `~/.local/share/feh/wallpapers/`, which the module owns. +- Owns `~/.fehbg`, which sets that image, filled, on every monitor, without rewriting itself + (`--no-fehbg`). +- Runs `~/.fehbg` once per session, from the session's start (the `xinitrc` slot `normal`). +- Binds `$mod+Shift+b` to the same file, as its own i3 drop-in (`50-feh.conf`): the declared wallpaper + back, after a monitor change. + +## Tools + +| tool | does | +|---|---| +| `feh_set` | set images (one for all monitors, or one each) in a mode: fill, center, max, scale, tile. For this session; the declared wallpaper returns at the next login | +| `feh_current` | the declared wallpaper (from `~/.fehbg`) and the one `feh_set` put up in this session | + +`feh_set` never writes `~/.fehbg`. A wallpaper that should stay is a change to this module, or a +setting once issue 168 closes, not a file the next push would overwrite. + +## What it improves on what was found + +- **The wallpaper no longer lives in the predecessor's tree.** `~/.fehbg` pointed into a directory + of the retired predecessor's. Deleting that directory would have left the desktop black, silently. +- **One image file, the same on both workstations.** The image was byte-identical on both. It is now + the module's own. + +## What it leaves as found + +- The predecessor's wallpaper directory. It is part of the predecessor's tree, which goes as a whole. + +## Migration (ADR 0182) + +- The first push keeps the found `~/.fehbg` once, then writes the module's. +- Once the `xorg` module writes the session's start, delete the `~/.fehbg &` line from your own part + of `~/.xinitrc`. +- The image's origin is the predecessor's desktop module. Check that it may be redistributed before + this catalogue is published anywhere public. + +## Blockers + +- `x11-display` and the `xinitrc` slot are ADR 0208's. Until the controller knows them, `mctl` reads + them as unknown. diff --git a/modules/feh/cmd/feh-tools/args.go b/modules/feh/cmd/feh-tools/args.go new file mode 100644 index 0000000..9b5dfcf --- /dev/null +++ b/modules/feh/cmd/feh-tools/args.go @@ -0,0 +1,97 @@ +// Reading a tool's arguments: JSON numbers arrive as float64, and a missing argument is its default. +// The same in every desktop module that carries it. +package main + +import ( + "fmt" + "math" + "strings" + "time" +) + +// text is a string argument, trimmed; required says an empty one is refused. +func text(args map[string]any, key string, required bool) (string, error) { + v, present := args[key] + if !present || v == nil { + if required { + return "", fmt.Errorf("%s is required", key) + } + return "", nil + } + s, ok := v.(string) + if !ok { + return "", fmt.Errorf("%s is a string, not %T", key, v) + } + s = strings.TrimSpace(s) + if s == "" && required { + return "", fmt.Errorf("%s is required", key) + } + return s, nil +} + +// whole is a whole-number argument within [least, most], or def when absent. +func whole(args map[string]any, key string, def, least, most int) (int, error) { + v, present := args[key] + if !present || v == nil { + return def, nil + } + f, ok := v.(float64) + if !ok { + if i, isInt := v.(int); isInt { + f = float64(i) + } else { + return 0, fmt.Errorf("%s is a number, not %T", key, v) + } + } + if f != math.Trunc(f) { + return 0, fmt.Errorf("%s is a whole number, not %v", key, f) + } + n := int(f) + if n < least || n > most { + return 0, fmt.Errorf("%s is %d; it is between %d and %d", key, n, least, most) + } + return n, nil +} + +// flag is a boolean argument, or def when absent. +func flag(args map[string]any, key string, def bool) (bool, error) { + v, present := args[key] + if !present || v == nil { + return def, nil + } + b, ok := v.(bool) + if !ok { + return false, fmt.Errorf("%s is true or false, not %T", key, v) + } + return b, nil +} + +// texts is a list-of-strings argument. +func texts(args map[string]any, key string) ([]string, error) { + v, present := args[key] + if !present || v == nil { + return nil, nil + } + list, ok := v.([]any) + if !ok { + if ss, isStrings := v.([]string); isStrings { + return ss, nil + } + return nil, fmt.Errorf("%s is a list of strings, not %T", key, v) + } + out := make([]string, 0, len(list)) + for i, item := range list { + s, ok := item.(string) + if !ok { + return nil, fmt.Errorf("%s[%d] is a string, not %T", key, i, item) + } + out = append(out, s) + } + return out, nil +} + +// seconds is a timeout argument in seconds, defaulted and bounded below the runtime's call limit. +func seconds(args map[string]any, key string, def, most int) (time.Duration, error) { + n, err := whole(args, key, def, 1, most) + return time.Duration(n) * time.Second, err +} diff --git a/modules/feh/cmd/feh-tools/main.go b/modules/feh/cmd/feh-tools/main.go new file mode 100644 index 0000000..3a42f8e --- /dev/null +++ b/modules/feh/cmd/feh-tools/main.go @@ -0,0 +1,53 @@ +// feh's Go tools bundle (novox/hq ADR 0188, ADR 0193, ADR 0208): the wallpaper's tools, served by the +// node's runtime as the operator account. +package main + +import ( + "fmt" + "os" + + stdio "git.novox.be/novox/mesh-sdk/go" +) + +func main() { + if err := stdio.Serve("", tools()); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func tools() []stdio.Tool { + return []stdio.Tool{ + { + Name: "feh_set", + Description: "Set the wallpaper in the operator's session: one image for every monitor, or one per " + + "monitor in the X screen order, filled, centred, scaled to fit, stretched or tiled. Lasts until the " + + "next session start, when the declared wallpaper returns; the declared one is untouched.", + Input: map[string]any{ + "type": "object", + "properties": map[string]any{ + "images": map[string]any{"type": "array", "items": map[string]any{"type": "string"}, "description": "image files on this machine, absolute or under the account's home; one per monitor, or one for all"}, + "mode": map[string]any{"type": "string", "enum": modes, "description": "default fill"}, + }, + "required": []string{"images"}, + }, + Run: func(args map[string]any) (any, error) { + images, err := texts(args, "images") + if err != nil { + return nil, err + } + mode, err := text(args, "mode", false) + if err != nil { + return nil, err + } + return Set(images, mode) + }, + }, + { + Name: "feh_current", + Description: "The wallpaper: the declared one the session start sets (images and mode, read from " + + "~/.fehbg), and the one feh_set put up in this session, if any.", + Run: func(map[string]any) (any, error) { return Current() }, + }, + } +} diff --git a/modules/feh/cmd/feh-tools/manifest_helpers_test.go b/modules/feh/cmd/feh-tools/manifest_helpers_test.go new file mode 100644 index 0000000..d4fb76d --- /dev/null +++ b/modules/feh/cmd/feh-tools/manifest_helpers_test.go @@ -0,0 +1,175 @@ +package main + +import ( + "encoding/json" + "os" + "path/filepath" + "strings" + "testing" +) + +// The module's manifest, read the way the catalogue reads it, for the manifest tests. The same in +// every desktop module that carries it. + +type manifest struct { + Module string `json:"module"` + Version string `json:"version"` + Capabilities []string `json:"capabilities"` + Requires []string `json:"requires"` + Claims []claim `json:"claims"` + Seats []any `json:"seats"` + Tools []string `json:"tools"` + Environment *environment `json:"environment"` + Shell []shellCode `json:"shell"` + Resources []map[string]any `json:"resources"` + Build struct { + Artifacts []map[string]any `json:"artifacts"` + } `json:"build"` +} + +type claim struct { + Name string `json:"name"` + Scope string `json:"scope"` + Serves []string `json:"serves"` +} + +type environment struct { + Variables map[string]string `json:"variables"` + Path []map[string]any `json:"path"` +} + +type shellCode struct { + For string `json:"for"` + Slot string `json:"slot"` + Code string `json:"code"` +} + +func readManifest(t *testing.T) manifest { + t.Helper() + raw, err := os.ReadFile(filepath.Join("..", "..", "module.json")) + if err != nil { + t.Fatal(err) + } + dec := json.NewDecoder(strings.NewReader(string(raw))) + dec.DisallowUnknownFields() + var m manifest + if err := dec.Decode(&m); err != nil { + t.Fatalf("module.json: %v", err) + } + return m +} + +func (m manifest) resource(t *testing.T, id string) map[string]any { + t.Helper() + for _, r := range m.Resources { + if r["id"] == id { + return r + } + } + t.Fatalf("no resource %q", id) + return nil +} + +func (m manifest) packages() (present, absent []string) { + for _, r := range m.Resources { + if r["type"] == "package" { + if r["absent"] == true { + absent = append(absent, r["package"].(string)) + } else { + present = append(present, r["package"].(string)) + } + } + } + return present, absent +} + +// sameAsSource checks that a file resource's content is byte for byte the module's source file, so +// the readable file in the repository is what the machine gets. +func (m manifest) sameAsSource(t *testing.T, id, source string) { + t.Helper() + want, err := os.ReadFile(filepath.Join("..", "..", source)) + if err != nil { + t.Fatal(err) + } + r := m.resource(t, id) + if r["type"] != "file" { + t.Fatalf("%s is a %v, not a file", id, r["type"]) + } + if got, _ := r["content"].(string); got != string(want) { + t.Fatalf("resource %s's content is not %s: edit the source and copy it into module.json", id, source) + } + if r["owner"] != "${machine:account}" && !strings.HasPrefix(r["path"].(string), "/etc/") { + t.Fatalf("%s under the home is the account's", id) + } +} + +// checkTheToolsAgree checks that the manifest lists the module's own tools exactly, that the bundle +// serves each seat verb the claims promise as ., and that the Go bundle is declared. +func checkTheToolsAgree(t *testing.T, m manifest) { + t.Helper() + own, seat := map[string]bool{}, map[string]bool{} + for _, tool := range tools() { + if strings.Contains(tool.Name, ".") { + seat[tool.Name] = true + } else { + own[tool.Name] = true + } + if strings.TrimSpace(tool.Description) == "" { + t.Errorf("%s has no description", tool.Name) + } + } + listed := map[string]bool{} + for _, name := range m.Tools { + listed[name] = true + if !own[name] { + t.Errorf("module.json lists %s, which the bundle does not serve", name) + } + } + for name := range own { + if !listed[name] { + t.Errorf("the bundle serves %s, which module.json does not list", name) + } + if !strings.HasPrefix(name, strings.ReplaceAll(m.Module, "-", "_")+"_") { + t.Errorf("%s is not prefixed with the module's name", name) + } + } + promised := map[string]bool{} + for _, c := range m.Claims { + for _, verb := range c.Serves { + promised[c.Name+"."+verb] = true + if !seat[c.Name+"."+verb] { + t.Errorf("the claim on %s promises %s, which the bundle does not serve", c.Name, verb) + } + } + } + for name := range seat { + if !promised[name] { + t.Errorf("the bundle serves %s, which no claim promises", name) + } + } + var bundle map[string]any + for _, a := range m.Build.Artifacts { + if a["kind"] == "bundle" { + bundle = a + } + } + if bundle == nil || bundle["language"] != "go" || bundle["system"] != "arch" || + bundle["from"] != "cmd/"+m.Module+"-tools" || bundle["binary"] != m.Module+"-tools" { + t.Errorf("the Go tools bundle: %v", bundle) + } +} + +// checkNoSecretsOrInstallationNames refuses what a catalogue manifest must never carry. +func checkNoSecretsOrInstallationNames(t *testing.T) { + t.Helper() + raw, err := os.ReadFile(filepath.Join("..", "..", "module.json")) + if err != nil { + t.Fatal(err) + } + s := strings.ToLower(string(raw)) + for _, never := range []string{"/home/", "jochen", "g14", "shanks", "novox.be", "api_key", ".hal/", "greenclip daemon"} { + if strings.Contains(s, never) { + t.Errorf("module.json names %q", never) + } + } +} diff --git a/modules/feh/cmd/feh-tools/manifest_test.go b/modules/feh/cmd/feh-tools/manifest_test.go new file mode 100644 index 0000000..dbdd9ab --- /dev/null +++ b/modules/feh/cmd/feh-tools/manifest_test.go @@ -0,0 +1,79 @@ +package main + +import ( + "os" + "path/filepath" + "reflect" + "strings" + "testing" +) + +// feh's shape (novox/hq ADR 0208): no seat; it requires the X display on its own machine, carries +// the wallpaper as its own archive (ADR 0205), owns ~/.fehbg pointing at it, and sets it once from +// the session's start. + +func TestItRequiresTheXDisplayAndClaimsNothing(t *testing.T) { + m := readManifest(t) + if m.Module != "feh" || m.Seats != nil || m.Claims != nil { + t.Fatalf("module %q, seats %v, claims %v", m.Module, m.Seats, m.Claims) + } + if !reflect.DeepEqual(m.Requires, []string{"x11-display"}) { + t.Fatalf("requires: %v", m.Requires) + } + if present, absent := m.packages(); !reflect.DeepEqual(present, []string{"feh"}) || absent != nil { + t.Fatalf("packages: %v, absent %v", present, absent) + } +} + +func TestTheWallpaperIsTheModulesOwnArchive(t *testing.T) { + m := readManifest(t) + a := m.resource(t, "wallpapers") + if a["type"] != "archive" || a["artifact"] != "wallpapers" || a["path"] != "${machine:account-home}/.local/share/feh/wallpapers" || a["owner"] != "${machine:account}" { + t.Fatalf("%v", a) + } + found := false + for _, art := range m.Build.Artifacts { + if art["name"] == "wallpapers" && art["kind"] == "archive" && art["from"] == "wallpaper" { + found = true + } + } + if !found { + t.Fatal("no archive artifact built from wallpaper/") + } + info, err := os.Stat(filepath.Join("..", "..", "wallpaper", "default.jpg")) + if err != nil || info.Size() == 0 { + t.Fatalf("the image: %v", err) + } +} + +func TestFehbgIsOwnedAndTheSessionStartRunsItOnce(t *testing.T) { + m := readManifest(t) + m.sameAsSource(t, "fehbg", "files/fehbg") + f := m.resource(t, "fehbg") + if f["path"] != "${machine:account-home}/.fehbg" || f["mode"] != "0755" { + t.Fatalf("%v", f) + } + if c := f["content"].(string); !strings.Contains(c, "$HOME/.local/share/feh/wallpapers/default.jpg") || strings.Contains(c, ".hal") { + t.Fatalf("%s", c) + } + if len(m.Shell) != 1 || m.Shell[0].For != "xinitrc" || m.Shell[0].Slot != "normal" || strings.Count(m.Shell[0].Code, `"$HOME/.fehbg"`) != 1 { + t.Fatalf("%+v", m.Shell) + } +} + +func TestTheKeyThatRestoresTheWallpaperIsAnI3DropIn(t *testing.T) { + m := readManifest(t) + m.sameAsSource(t, "i3-bindings", "files/i3/50-feh.conf") + if p := m.resource(t, "i3-bindings")["path"]; p != "${machine:account-home}/.config/i3/config.d/50-feh.conf" { + t.Fatalf("path: %v", p) + } + if c := m.resource(t, "i3-bindings")["content"].(string); !strings.Contains(c, "bindsym $mod+Shift+b exec --no-startup-id ~/.fehbg\n") { + t.Fatalf("%s", c) + } +} + +func TestTheToolsAgreeWithTheManifest(t *testing.T) { + m := readManifest(t) + checkTheToolsAgree(t, m) + checkNoSecretsOrInstallationNames(t) +} diff --git a/modules/feh/cmd/feh-tools/session.go b/modules/feh/cmd/feh-tools/session.go new file mode 100644 index 0000000..dc21774 --- /dev/null +++ b/modules/feh/cmd/feh-tools/session.go @@ -0,0 +1,423 @@ +// The operator's graphical session, as a tool the node's runtime runs finds it (novox/hq ADR 0208). +// +// The runtime is a system service running as the operator account (ADR 0175): it has the account's +// uid and none of the session's environment — no DISPLAY, no XAUTHORITY, no session bus. A tool that +// draws on the screen or talks to the desktop's D-Bus must find them. It reads them from a process of +// the account that is part of the session (the window manager first), the same thing `loginctl` and +// a person's own shell would point at, and says where it found them. +// +// Long-lived programs a tool starts go to the account's own service manager through `systemd-run +// --user`, never as children of the tool: the runtime's unit is a cgroup the service manager empties +// whenever the runtime restarts, and a compositor or a clipboard owner started from inside it would +// die with it. +// +// This file is the same in every desktop module that carries it; it moves into the Go SDK once a +// second consumer outside the desktop wants it. +package main + +import ( + "bytes" + "errors" + "fmt" + "os" + "os/exec" + "path/filepath" + "sort" + "strconv" + "strings" + "syscall" + "time" +) + +// Where the session is looked for. Variables so a test can point them at a fake tree. +var ( + procRoot = "/proc" + runUserDir = "/run/user" + x11Sockets = "/tmp/.X11-unix" +) + +// sessionHolders are the processes whose environment is the session's, best first: the window +// manager is the session, the rest are its children. Anything else carrying DISPLAY ranks after them. +var sessionHolders = []string{"i3", "sway", "i3bar", "picom", "xss-lock", "dunst", "clipmenud", "xterm"} + +// sessionKeys are the variables a session carries that a tool hands on to what it runs. +var sessionKeys = []string{"DISPLAY", "XAUTHORITY", "WAYLAND_DISPLAY", "DBUS_SESSION_BUS_ADDRESS", + "XDG_RUNTIME_DIR", "XDG_SESSION_ID", "I3SOCK"} + +// Session is what a tool needs to reach the operator's desktop. +type Session struct { + UID int `json:"uid"` + Display string `json:"display,omitempty"` + XAuthority string `json:"xauthority,omitempty"` + Wayland string `json:"wayland_display,omitempty"` + Bus string `json:"bus,omitempty"` + RuntimeDir string `json:"runtime_dir,omitempty"` + SessionID string `json:"session_id,omitempty"` + I3Sock string `json:"i3sock,omitempty"` + // From says where the values were found: the tool's own environment, a process, or the socket. + From string `json:"from"` +} + +// ErrNoSession is answered by a tool that needs the desktop when nobody is logged in to it. +var ErrNoSession = errors.New("no graphical session") + +// ErrTimedOut is what run answers for a command ended because it ran past its time. +var ErrTimedOut = errors.New("timed out") + +// ErrNoBus is answered by a tool that needs the session bus when the account has none. +var ErrNoBus = errors.New("no session bus") + +// operatorHome is the account's home: what the runtime was told, else the process's own. +func operatorHome() string { + if h := strings.TrimSpace(os.Getenv("MESH_OPERATOR_HOME")); h != "" { + return h + } + h, _ := os.UserHomeDir() + return h +} + +// findSession finds the graphical session of the account this tool runs as, or answers +// ErrNoSession with what it looked at. +func findSession() (Session, error) { + s := findEnvironment() + if s.Display == "" && s.Wayland == "" { + return s, fmt.Errorf("%w for uid %d on this machine: no process of the account carries DISPLAY "+ + "or WAYLAND_DISPLAY, and no X server socket in %s has an authority file to go with it. "+ + "Is anyone logged in to the desktop?", ErrNoSession, s.UID, x11Sockets) + } + return s, nil +} + +// findBus finds the account's session bus, which a logged-in account has whether or not a desktop +// is running. +func findBus() (Session, error) { + s := findEnvironment() + if s.Bus == "" { + return s, fmt.Errorf("%w for uid %d: DBUS_SESSION_BUS_ADDRESS is not set and %s does not exist "+ + "(the account is not logged in)", ErrNoBus, s.UID, filepath.Join(runUserDir, strconv.Itoa(s.UID), "bus")) + } + return s, nil +} + +func findEnvironment() Session { + uid := os.Getuid() + s := Session{UID: uid} + own := map[string]string{} + for _, k := range sessionKeys { + own[k] = os.Getenv(k) + } + if own["DISPLAY"] != "" || own["WAYLAND_DISPLAY"] != "" { + s.fill(own) + s.From = "the tool's own environment" + } else if pid, comm, env, ok := sessionProcess(uid); ok { + s.fill(env) + s.From = fmt.Sprintf("process %s (pid %d)", comm, pid) + } else if display, ok := lonelyX11Socket(); ok { + if a := filepath.Join(operatorHome(), ".Xauthority"); exists(a) { + s.Display, s.XAuthority = display, a + s.From = "the X server socket and the account's ~/.Xauthority" + } + s.fill(own) + } else { + s.fill(own) + s.From = "nothing: no session found" + } + // The bus and the runtime directory are the account's, whether or not the process named them. + runtime := filepath.Join(runUserDir, strconv.Itoa(uid)) + if s.RuntimeDir == "" && exists(runtime) { + s.RuntimeDir = runtime + } + if s.Bus == "" && s.RuntimeDir != "" && exists(filepath.Join(s.RuntimeDir, "bus")) { + s.Bus = "unix:path=" + filepath.Join(s.RuntimeDir, "bus") + } + return s +} + +func (s *Session) fill(env map[string]string) { + set := func(dst *string, key string) { + if *dst == "" { + *dst = env[key] + } + } + set(&s.Display, "DISPLAY") + set(&s.XAuthority, "XAUTHORITY") + set(&s.Wayland, "WAYLAND_DISPLAY") + set(&s.Bus, "DBUS_SESSION_BUS_ADDRESS") + set(&s.RuntimeDir, "XDG_RUNTIME_DIR") + set(&s.SessionID, "XDG_SESSION_ID") + set(&s.I3Sock, "I3SOCK") +} + +// sessionProcess is the best process of this uid whose environment names a display. +func sessionProcess(uid int) (int, string, map[string]string, bool) { + entries, err := os.ReadDir(procRoot) + if err != nil { + return 0, "", nil, false + } + type candidate struct { + pid int + comm string + env map[string]string + rank int + } + var found []candidate + for _, e := range entries { + pid, err := strconv.Atoi(e.Name()) + if err != nil { + continue + } + dir := filepath.Join(procRoot, e.Name()) + if owner, ok := ownerOf(dir); !ok || owner != uid { + continue + } + raw, err := os.ReadFile(filepath.Join(dir, "environ")) + if err != nil { + continue + } + env := parseEnviron(raw) + if env["DISPLAY"] == "" && env["WAYLAND_DISPLAY"] == "" { + continue + } + comm := readTrimmed(filepath.Join(dir, "comm")) + rank := len(sessionHolders) + for i, h := range sessionHolders { + if h == comm { + rank = i + break + } + } + found = append(found, candidate{pid, comm, env, rank}) + } + if len(found) == 0 { + return 0, "", nil, false + } + sort.Slice(found, func(i, j int) bool { + if found[i].rank != found[j].rank { + return found[i].rank < found[j].rank + } + return found[i].pid > found[j].pid // the newer of two equals + }) + best := found[0] + return best.pid, best.comm, best.env, true +} + +func parseEnviron(raw []byte) map[string]string { + env := map[string]string{} + for _, kv := range bytes.Split(raw, []byte{0}) { + if i := bytes.IndexByte(kv, '='); i > 0 { + env[string(kv[:i])] = string(kv[i+1:]) + } + } + return env +} + +func ownerOf(path string) (int, bool) { + info, err := os.Stat(path) + if err != nil { + return 0, false + } + st, ok := info.Sys().(*syscall.Stat_t) + if !ok { + return 0, false + } + return int(st.Uid), true +} + +// lonelyX11Socket is the display of the one X server socket there is, when there is exactly one. +func lonelyX11Socket() (string, bool) { + entries, err := os.ReadDir(x11Sockets) + if err != nil { + return "", false + } + var displays []string + for _, e := range entries { + if n := strings.TrimPrefix(e.Name(), "X"); n != e.Name() { + if _, err := strconv.Atoi(n); err == nil { + displays = append(displays, ":"+n) + } + } + } + if len(displays) != 1 { + return "", false + } + return displays[0], true +} + +func readTrimmed(path string) string { + b, err := os.ReadFile(path) + if err != nil { + return "" + } + return strings.TrimSpace(string(b)) +} + +func exists(path string) bool { + _, err := os.Stat(path) + return err == nil +} + +// Env is this process's environment with the session's variables in place of its own. +func (s Session) Env() []string { + drop := map[string]bool{} + for _, k := range sessionKeys { + drop[k] = true + } + var env []string + for _, kv := range os.Environ() { + if i := strings.IndexByte(kv, '='); i > 0 && drop[kv[:i]] { + continue + } + env = append(env, kv) + } + add := func(k, v string) { + if v != "" { + env = append(env, k+"="+v) + } + } + add("DISPLAY", s.Display) + add("XAUTHORITY", s.XAuthority) + add("WAYLAND_DISPLAY", s.Wayland) + add("DBUS_SESSION_BUS_ADDRESS", s.Bus) + add("XDG_RUNTIME_DIR", s.RuntimeDir) + add("XDG_SESSION_ID", s.SessionID) + add("I3SOCK", s.I3Sock) + return env +} + +// mostOutput bounds what a command may answer with, per stream. +const mostOutput = 256 << 10 + +// Result is what a command did. +type Result struct { + Stdout string `json:"stdout"` + Stderr string `json:"stderr,omitempty"` + Code int `json:"code"` + Truncated bool `json:"truncated,omitempty"` +} + +// run runs a command in the session's environment, its input given, ended with everything it +// started after timeout. A command that is not installed is an error naming it; one that exits +// non-zero is a Result with its code, for the caller to judge. +func (s Session) run(timeout time.Duration, stdin string, name string, args ...string) (Result, error) { + path, err := exec.LookPath(name) + if err != nil { + return Result{}, fmt.Errorf("%s is not installed on this machine", name) + } + cmd := exec.Command(path, args...) + cmd.Env = s.Env() + if home := operatorHome(); exists(home) { + cmd.Dir = home + } + if stdin != "" { + cmd.Stdin = strings.NewReader(stdin) + } + var out, errOut capped + cmd.Stdout, cmd.Stderr = &out, &errOut + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + if err := cmd.Start(); err != nil { + return Result{}, fmt.Errorf("%s: %w", name, err) + } + done := make(chan error, 1) + go func() { done <- cmd.Wait() }() + select { + case err = <-done: + case <-time.After(timeout): + _ = syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) + <-done + return Result{Stdout: out.String(), Stderr: errOut.String()}, + fmt.Errorf("%s did not finish within %s and was ended: %w", name, timeout, ErrTimedOut) + } + r := Result{Stdout: out.String(), Stderr: errOut.String(), Truncated: out.cut || errOut.cut} + var exit *exec.ExitError + if errors.As(err, &exit) { + r.Code = exit.ExitCode() + } else if err != nil { + return r, fmt.Errorf("%s: %w", name, err) + } + return r, nil +} + +// detach starts a long-lived program under the account's own service manager, as a transient unit +// that carries the session's display, so it outlives the runtime that asked for it. A unit already +// running under the same name is stopped first, so a fixed name means "at most one". +func (s Session) detach(unit string, args ...string) error { + if s.RuntimeDir == "" { + return fmt.Errorf("%w: the account's runtime directory is missing, so its service manager "+ + "cannot be reached", ErrNoBus) + } + _, _ = s.run(5*time.Second, "", "systemctl", "--user", "stop", unit+".service") + call := []string{"--user", "--collect", "--quiet", "--unit=" + unit} + for _, kv := range [][2]string{{"DISPLAY", s.Display}, {"XAUTHORITY", s.XAuthority}, + {"WAYLAND_DISPLAY", s.Wayland}, {"XDG_SESSION_ID", s.SessionID}, {"I3SOCK", s.I3Sock}} { + if kv[1] != "" { + call = append(call, "--setenv="+kv[0]+"="+kv[1]) + } + } + call = append(call, "--") + call = append(call, args...) + r, err := s.run(10*time.Second, "", "systemd-run", call...) + if err != nil { + return err + } + if r.Code != 0 { + return fmt.Errorf("systemd-run %s: %s", unit, strings.TrimSpace(r.Stderr)) + } + return nil +} + +// uniqueUnit is a transient unit name that will not collide with an earlier one. +func uniqueUnit(prefix string) string { + return fmt.Sprintf("%s-%d", prefix, time.Now().UnixNano()) +} + +type capped struct { + bytes.Buffer + cut bool +} + +func (c *capped) Write(p []byte) (int, error) { + if room := mostOutput - c.Len(); room < len(p) { + if room > 0 { + c.Buffer.Write(p[:room]) + } + c.cut = true + return len(p), nil + } + return c.Buffer.Write(p) +} + +// processesOf are the pids of this uid's processes whose command name is comm, oldest first. +func processesOf(comm string) []int { + entries, err := os.ReadDir(procRoot) + if err != nil { + return nil + } + uid := os.Getuid() + var pids []int + for _, e := range entries { + pid, err := strconv.Atoi(e.Name()) + if err != nil { + continue + } + dir := filepath.Join(procRoot, e.Name()) + if owner, ok := ownerOf(dir); !ok || owner != uid { + continue + } + if readTrimmed(filepath.Join(dir, "comm")) == comm { + pids = append(pids, pid) + } + } + sort.Ints(pids) + return pids +} + +// signalAll sends sig to every process of this uid named comm, and answers the pids it reached. +func signalAll(comm string, sig syscall.Signal) []int { + var reached []int + for _, pid := range processesOf(comm) { + if syscall.Kill(pid, sig) == nil { + reached = append(reached, pid) + } + } + return reached +} diff --git a/modules/feh/cmd/feh-tools/session_test.go b/modules/feh/cmd/feh-tools/session_test.go new file mode 100644 index 0000000..800cc6d --- /dev/null +++ b/modules/feh/cmd/feh-tools/session_test.go @@ -0,0 +1,174 @@ +package main + +import ( + "errors" + "os" + "path/filepath" + "strconv" + "strings" + "testing" + "time" +) + +// fakeMachine points the session finder at a temporary /proc, /run/user and X socket directory, with +// none of the test process's own session variables, and gives back the root. +func fakeMachine(t *testing.T) string { + t.Helper() + root := t.TempDir() + procRoot, runUserDir, x11Sockets = filepath.Join(root, "proc"), filepath.Join(root, "run-user"), filepath.Join(root, "x11") + for _, d := range []string{procRoot, runUserDir, x11Sockets} { + if err := os.MkdirAll(d, 0o755); err != nil { + t.Fatal(err) + } + } + for _, k := range sessionKeys { + t.Setenv(k, "") + } + t.Setenv("MESH_OPERATOR_HOME", filepath.Join(root, "home")) + t.Cleanup(func() { procRoot, runUserDir, x11Sockets = "/proc", "/run/user", "/tmp/.X11-unix" }) + return root +} + +func fakeProcess(t *testing.T, pid int, comm string, env ...string) { + t.Helper() + dir := filepath.Join(procRoot, strconv.Itoa(pid)) + if err := os.MkdirAll(dir, 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, "comm"), []byte(comm+"\n"), 0o644); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, "environ"), []byte(strings.Join(env, "\x00")+"\x00"), 0o600); err != nil { + t.Fatal(err) + } +} + +func TestTheSessionIsReadFromTheWindowManagerBeforeAnyOtherProcess(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 900, "xterm", "DISPLAY=:9", "XAUTHORITY=/elsewhere") + fakeProcess(t, 100, "i3", "DISPLAY=:1", "XAUTHORITY=/home/op/.Xauthority", + "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus", "XDG_SESSION_ID=3", "SECRET_TOKEN=never-copied") + fakeProcess(t, 50, "bash", "PATH=/usr/bin") + s, err := findSession() + if err != nil { + t.Fatal(err) + } + if s.Display != ":1" || s.XAuthority != "/home/op/.Xauthority" || s.SessionID != "3" || !strings.Contains(s.From, "i3 (pid 100)") { + t.Fatalf("the window manager's environment: %+v", s) + } + for _, kv := range s.Env() { + if strings.HasPrefix(kv, "SECRET_TOKEN=") { + t.Fatal("a variable of the session process that is not a session variable was handed on") + } + } +} + +func TestAnyProcessCarryingADisplayServesWhenTheWindowManagerIsNotFound(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 10, "firefox", "DISPLAY=:0") + fakeProcess(t, 20, "firefox", "DISPLAY=:2") + s, err := findSession() + if err != nil || s.Display != ":2" { + t.Fatalf("the newest of two equals: %+v, %v", s, err) + } +} + +func TestNoSessionIsAClearAnswerNotAGuess(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 10, "sshd", "PATH=/usr/bin") + _, err := findSession() + if !errors.Is(err, ErrNoSession) || !strings.Contains(err.Error(), "logged in to the desktop") { + t.Fatalf("no session: %v", err) + } +} + +func TestOneXSocketAndTheAccountsAuthorityFileAreASession(t *testing.T) { + root := fakeMachine(t) + if err := os.WriteFile(filepath.Join(x11Sockets, "X0"), nil, 0o644); err != nil { + t.Fatal(err) + } + if err := os.MkdirAll(filepath.Join(root, "home"), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(root, "home", ".Xauthority"), nil, 0o600); err != nil { + t.Fatal(err) + } + s, err := findSession() + if err != nil || s.Display != ":0" || !strings.HasSuffix(s.XAuthority, "/home/.Xauthority") { + t.Fatalf("socket and authority: %+v, %v", s, err) + } +} + +func TestTheBusIsTheAccountsRuntimeDirectoryWhenNoProcessNamesIt(t *testing.T) { + fakeMachine(t) + runtime := filepath.Join(runUserDir, strconv.Itoa(os.Getuid())) + if _, err := findBus(); !errors.Is(err, ErrNoBus) { + t.Fatalf("no runtime directory is no bus: %v", err) + } + if err := os.MkdirAll(runtime, 0o700); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(runtime, "bus"), nil, 0o600); err != nil { + t.Fatal(err) + } + s, err := findBus() + if err != nil || s.Bus != "unix:path="+filepath.Join(runtime, "bus") || s.RuntimeDir != runtime { + t.Fatalf("bus: %+v, %v", s, err) + } + env := strings.Join(s.Env(), "\n") + if !strings.Contains(env, "XDG_RUNTIME_DIR="+runtime) || !strings.Contains(env, "DBUS_SESSION_BUS_ADDRESS=unix:path=") { + t.Fatalf("the bus is handed on: %s", env) + } +} + +func TestACommandIsBoundedAndANonZeroExitIsAResult(t *testing.T) { + fakeMachine(t) + s := Session{} + r, err := s.run(5*time.Second, "in", "sh", "-c", "cat; echo err >&2; exit 3") + if err != nil || r.Stdout != "in" || r.Code != 3 || strings.TrimSpace(r.Stderr) != "err" { + t.Fatalf("result: %+v, %v", r, err) + } + start := time.Now() + if _, err := s.run(200*time.Millisecond, "", "sh", "-c", "sleep 30 & sleep 30"); err == nil || time.Since(start) > 5*time.Second { + t.Fatalf("a command past its time is ended with what it started: %v after %s", err, time.Since(start)) + } + if _, err := s.run(time.Second, "", "no-such-program-here"); err == nil || !strings.Contains(err.Error(), "not installed") { + t.Fatalf("a missing program: %v", err) + } +} + +func TestDetachAsksTheAccountsServiceManagerWithTheSessionsDisplay(t *testing.T) { + fakeMachine(t) + bin := fakeBinaries(t, map[string]string{ + "systemctl": `echo "systemctl $*" >> "$LOG"`, + "systemd-run": `echo "systemd-run $*" >> "$LOG"`, + }) + log := filepath.Join(bin, "log") + t.Setenv("LOG", log) + s := Session{Display: ":1", XAuthority: "/x", RuntimeDir: "/run/user/1"} + if err := s.detach("picom-session", "picom", "--config", "/c"); err != nil { + t.Fatal(err) + } + got, _ := os.ReadFile(log) + want := "systemctl --user stop picom-session.service\n" + + "systemd-run --user --collect --quiet --unit=picom-session --setenv=DISPLAY=:1 --setenv=XAUTHORITY=/x -- picom --config /c\n" + if string(got) != want { + t.Fatalf("detach ran:\n%s\nwant:\n%s", got, want) + } + if err := (Session{}).detach("x", "y"); !errors.Is(err, ErrNoBus) { + t.Fatalf("no runtime directory: %v", err) + } +} + +// fakeBinaries puts shell scripts named for programs first on PATH, and answers their directory. +func fakeBinaries(t *testing.T, scripts map[string]string) string { + t.Helper() + dir := t.TempDir() + for name, body := range scripts { + if err := os.WriteFile(filepath.Join(dir, name), []byte("#!/bin/sh\n"+body+"\n"), 0o755); err != nil { + t.Fatal(err) + } + } + t.Setenv("PATH", dir+string(os.PathListSeparator)+os.Getenv("PATH")) + return dir +} diff --git a/modules/feh/cmd/feh-tools/wallpaper.go b/modules/feh/cmd/feh-tools/wallpaper.go new file mode 100644 index 0000000..d4b7333 --- /dev/null +++ b/modules/feh/cmd/feh-tools/wallpaper.go @@ -0,0 +1,174 @@ +package main + +import ( + "encoding/json" + "errors" + "fmt" + "os" + "path/filepath" + "regexp" + "strings" + "time" +) + +// modes are feh's background modes, by the word feh_set takes. +var modes = []string{"fill", "center", "max", "scale", "tile"} + +// Wallpaper is images and how they are laid on the screens. +type Wallpaper struct { + Images []string `json:"images"` + Mode string `json:"mode"` + At string `json:"at,omitempty"` +} + +func fehbg() string { return filepath.Join(operatorHome(), ".fehbg") } + +// sessionRecord is where feh_set notes what it put up, for feh_current: in the runtime directory, +// so it lasts exactly as long as the login, like the wallpaper itself. +func sessionRecord(s Session) string { + if s.RuntimeDir == "" { + return "" + } + return filepath.Join(s.RuntimeDir, "feh", "current.json") +} + +// SetResult is what feh_set answers. +type SetResult struct { + Wallpaper + Note string `json:"note"` +} + +// Set puts images up as the wallpaper for this session. +func Set(images []string, mode string) (SetResult, error) { + if mode == "" { + mode = "fill" + } + known := false + for _, m := range modes { + known = known || m == mode + } + if !known { + return SetResult{}, fmt.Errorf("mode %q is one of %s", mode, strings.Join(modes, ", ")) + } + if len(images) == 0 { + return SetResult{}, errors.New("images is required: at least one image") + } + var paths []string + for _, img := range images { + p := img + if strings.HasPrefix(p, "~/") { + p = filepath.Join(operatorHome(), p[2:]) + } + if !filepath.IsAbs(p) { + p = filepath.Join(operatorHome(), p) + } + info, err := os.Stat(p) + if err != nil { + return SetResult{}, fmt.Errorf("image %s: %w", img, err) + } + if info.IsDir() { + return SetResult{}, fmt.Errorf("image %s is a directory", img) + } + paths = append(paths, p) + } + s, err := findSession() + if err != nil { + return SetResult{}, err + } + args := append([]string{"--no-fehbg", "--bg-" + mode}, paths...) + r, err := s.run(15*time.Second, "", "feh", args...) + if err != nil { + return SetResult{}, err + } + if r.Code != 0 { + return SetResult{}, fmt.Errorf("feh: %s", strings.TrimSpace(r.Stderr)) + } + w := Wallpaper{Images: paths, Mode: mode, At: time.Now().Format(time.RFC3339)} + if rec := sessionRecord(s); rec != "" { + if err := os.MkdirAll(filepath.Dir(rec), 0o700); err == nil { + raw, _ := json.Marshal(w) + _ = os.WriteFile(rec, raw, 0o600) + } + } + return SetResult{Wallpaper: w, Note: "for this session; the declared wallpaper returns at the next login"}, nil +} + +// CurrentResult is what feh_current answers. +type CurrentResult struct { + Declared *Wallpaper `json:"declared"` + Session *Wallpaper `json:"session,omitempty"` +} + +var bgMode = regexp.MustCompile(`--bg-(fill|center|max|scale|tile)\b`) + +// Current is the declared wallpaper and the one set in this session. +func Current() (CurrentResult, error) { + var out CurrentResult + if raw, err := os.ReadFile(fehbg()); err == nil { + out.Declared = parseFehbg(string(raw), operatorHome()) + } + if rec := sessionRecord(findEnvironment()); rec != "" { + if raw, err := os.ReadFile(rec); err == nil { + var w Wallpaper + if json.Unmarshal(raw, &w) == nil { + out.Session = &w + } + } + } + return out, nil +} + +// parseFehbg reads the feh line of a ~/.fehbg: its mode and its images, with $HOME expanded. +func parseFehbg(script, home string) *Wallpaper { + for _, line := range strings.Split(script, "\n") { + line = strings.TrimSpace(line) + if !strings.HasPrefix(line, "feh ") { + continue + } + w := &Wallpaper{Images: []string{}} + if m := bgMode.FindStringSubmatch(line); m != nil { + w.Mode = m[1] + } + for _, word := range shellWords(line)[1:] { + if strings.HasPrefix(word, "-") { + continue + } + word = strings.ReplaceAll(strings.ReplaceAll(word, "${HOME}", home), "$HOME", home) + w.Images = append(w.Images, word) + } + return w + } + return nil +} + +// shellWords splits a simple command line on blanks, honouring single and double quotes. +func shellWords(line string) []string { + var words []string + var cur strings.Builder + var quote byte + in := false + for i := 0; i < len(line); i++ { + c := line[i] + switch { + case quote != 0 && c == quote: + quote = 0 + case quote != 0: + cur.WriteByte(c) + case c == '\'' || c == '"': + quote, in = c, true + case c == ' ' || c == '\t': + if in { + words = append(words, cur.String()) + cur.Reset() + in = false + } + default: + cur.WriteByte(c) + in = true + } + } + if in { + words = append(words, cur.String()) + } + return words +} diff --git a/modules/feh/cmd/feh-tools/wallpaper_test.go b/modules/feh/cmd/feh-tools/wallpaper_test.go new file mode 100644 index 0000000..135dc3b --- /dev/null +++ b/modules/feh/cmd/feh-tools/wallpaper_test.go @@ -0,0 +1,92 @@ +package main + +import ( + "errors" + "os" + "path/filepath" + "reflect" + "strconv" + "strings" + "testing" +) + +const nobody = 4194400 + +func TestTheDeclaredWallpaperIsReadFromTheModulesFehbg(t *testing.T) { + raw, err := os.ReadFile(filepath.Join("..", "..", "files", "fehbg")) + if err != nil { + t.Fatal(err) + } + w := parseFehbg(string(raw), "/home/op") + if w == nil || w.Mode != "fill" || !reflect.DeepEqual(w.Images, []string{"/home/op/.local/share/feh/wallpapers/default.jpg"}) { + t.Fatalf("%+v", w) + } + // The form feh writes itself, single-quoted, two monitors. + w = parseFehbg("#!/bin/sh\nfeh --no-fehbg --bg-center '/a b/one.png' '/two.png' \n", "/home/op") + if w.Mode != "center" || !reflect.DeepEqual(w.Images, []string{"/a b/one.png", "/two.png"}) { + t.Fatalf("%+v", w) + } + if parseFehbg("#!/bin/sh\n", "/h") != nil { + t.Fatal("a file without feh declares a wallpaper") + } +} + +func TestSetPutsTheImagesUpForThisSessionAndCurrentSaysSo(t *testing.T) { + root := fakeMachine(t) + fakeProcess(t, nobody, "i3", "DISPLAY=:1") + if err := os.MkdirAll(filepath.Join(runUserDir, strconv.Itoa(os.Getuid())), 0o700); err != nil { + t.Fatal(err) + } + home := filepath.Join(root, "home") + for _, f := range []string{"Pictures/a.jpg", "Pictures/b.jpg"} { + if err := os.MkdirAll(filepath.Dir(filepath.Join(home, f)), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(home, f), []byte("jpg"), 0o644); err != nil { + t.Fatal(err) + } + } + src, _ := os.ReadFile(filepath.Join("..", "..", "files", "fehbg")) + if err := os.WriteFile(filepath.Join(home, ".fehbg"), src, 0o755); err != nil { + t.Fatal(err) + } + bin := fakeBinaries(t, map[string]string{"feh": `echo "$* DISPLAY=$DISPLAY" > "$LOG"`}) + t.Setenv("LOG", filepath.Join(bin, "log")) + got, err := Set([]string{"~/Pictures/a.jpg", "Pictures/b.jpg"}, "scale") + if err != nil || !strings.Contains(got.Note, "next login") { + t.Fatalf("%+v, %v", got, err) + } + asked, _ := os.ReadFile(filepath.Join(bin, "log")) + want := "--no-fehbg --bg-scale " + filepath.Join(home, "Pictures/a.jpg") + " " + filepath.Join(home, "Pictures/b.jpg") + " DISPLAY=:1\n" + if string(asked) != want { + t.Fatalf("feh was asked %q, want %q", asked, want) + } + cur, err := Current() + if err != nil || cur.Declared == nil || cur.Session == nil || cur.Session.Mode != "scale" || len(cur.Session.Images) != 2 || + cur.Declared.Images[0] != filepath.Join(home, ".local/share/feh/wallpapers/default.jpg") { + t.Fatalf("%+v, %v", cur, err) + } +} + +func TestSetRefusesWhatFehCannotShow(t *testing.T) { + fakeMachine(t) + if _, err := Set([]string{"/nowhere.jpg"}, ""); err == nil { + t.Fatal("a missing image was accepted") + } + if _, err := Set([]string{"/"}, ""); err == nil { + t.Fatal("a directory was accepted") + } + if _, err := Set([]string{"/etc/hostname"}, "stretch"); err == nil { + t.Fatal("an unknown mode was accepted") + } + if _, err := Set(nil, ""); err == nil { + t.Fatal("no image was accepted") + } + f := filepath.Join(t.TempDir(), "x.jpg") + if err := os.WriteFile(f, nil, 0o644); err != nil { + t.Fatal(err) + } + if _, err := Set([]string{f}, ""); !errors.Is(err, ErrNoSession) { + t.Fatalf("without a session: %v", err) + } +} diff --git a/modules/feh/files/fehbg b/modules/feh/files/fehbg new file mode 100755 index 0000000..a3159bb --- /dev/null +++ b/modules/feh/files/fehbg @@ -0,0 +1,6 @@ +#!/bin/sh +# The wallpaper (module feh, novox/hq ADR 0208). Owned by the mesh: replaced at every push. The +# session's start runs it, and so may anything that wants the declared wallpaper back. The image is +# the module's own, in ~/.local/share/feh/wallpapers. feh_set changes the wallpaper for a session +# without touching this file. +feh --no-fehbg --bg-fill "$HOME/.local/share/feh/wallpapers/default.jpg" diff --git a/modules/feh/files/i3/50-feh.conf b/modules/feh/files/i3/50-feh.conf new file mode 100644 index 0000000..40ac7da --- /dev/null +++ b/modules/feh/files/i3/50-feh.conf @@ -0,0 +1,3 @@ +# The wallpaper's key (module feh, novox/hq ADR 0208). Owned by the mesh: replaced at every push. +# It puts the declared wallpaper back, after a monitor change or a wallpaper set for the session. +bindsym $mod+Shift+b exec --no-startup-id ~/.fehbg diff --git a/modules/feh/go.mod b/modules/feh/go.mod new file mode 100644 index 0000000..4df3720 --- /dev/null +++ b/modules/feh/go.mod @@ -0,0 +1,5 @@ +module feh + +go 1.22 + +require git.novox.be/novox/mesh-sdk/go v0.1.7 diff --git a/modules/feh/go.sum b/modules/feh/go.sum new file mode 100644 index 0000000..b474419 --- /dev/null +++ b/modules/feh/go.sum @@ -0,0 +1,2 @@ +git.novox.be/novox/mesh-sdk/go v0.1.7 h1:C0sTQmtTiyYH7bnqZb7PusXnqA37gKuT7Nqjn9gG47w= +git.novox.be/novox/mesh-sdk/go v0.1.7/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= diff --git a/modules/feh/module.json b/modules/feh/module.json new file mode 100644 index 0000000..9853e54 --- /dev/null +++ b/modules/feh/module.json @@ -0,0 +1,71 @@ +{ + "module": "feh", + "version": "1", + "capabilities": [ + "package-manager" + ], + "requires": [ + "x11-display" + ], + "tools": [ + "feh_set", + "feh_current" + ], + "shell": [ + { + "for": "xinitrc", + "slot": "normal", + "code": "# The wallpaper (module feh, novox/hq ADR 0208): the declared one, set once per session.\n\"$HOME/.fehbg\"\n" + } + ], + "resources": [ + { + "id": "package", + "type": "package", + "package": "feh" + }, + { + "id": "wallpapers", + "type": "archive", + "path": "${machine:account-home}/.local/share/feh/wallpapers", + "owner": "${machine:account}", + "artifact": "wallpapers" + }, + { + "id": "fehbg", + "type": "file", + "path": "${machine:account-home}/.fehbg", + "owner": "${machine:account}", + "mode": "0755", + "content": "#!/bin/sh\n# The wallpaper (module feh, novox/hq ADR 0208). Owned by the mesh: replaced at every push. The\n# session's start runs it, and so may anything that wants the declared wallpaper back. The image is\n# the module's own, in ~/.local/share/feh/wallpapers. feh_set changes the wallpaper for a session\n# without touching this file.\nfeh --no-fehbg --bg-fill \"$HOME/.local/share/feh/wallpapers/default.jpg\"\n" + }, + { + "id": "i3-bindings", + "type": "file", + "path": "${machine:account-home}/.config/i3/config.d/50-feh.conf", + "owner": "${machine:account}", + "mode": "0644", + "content": "# The wallpaper's key (module feh, novox/hq ADR 0208). Owned by the mesh: replaced at every push.\n# It puts the declared wallpaper back, after a monitor change or a wallpaper set for the session.\nbindsym $mod+Shift+b exec --no-startup-id ~/.fehbg\n" + } + ], + "build": { + "artifacts": [ + { + "name": "wallpapers", + "kind": "archive", + "from": "wallpaper" + }, + { + "name": "tools", + "kind": "bundle", + "language": "go", + "system": "arch", + "from": "cmd/feh-tools", + "binary": "feh-tools", + "loads": [ + "feh-tools" + ] + } + ] + } +} diff --git a/modules/feh/wallpaper/default.jpg b/modules/feh/wallpaper/default.jpg new file mode 100644 index 0000000000000000000000000000000000000000..266ad56c0c1f9ed7e66a8b781ce0109e28c991b0 GIT binary patch literal 955517 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 UiLw!0FIB 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%0A=rZ+ZIt8=78o!n>lZ%!K+XjK?jw3|~L%{$tvC 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 #^<6hNZQX`OhAd}It>OnZo}^o!s<>; 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

02%uO9vSePT;yvW15Vl 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

%zX(`l0? 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ΠVYbE_cvnavn+stJ&c5UeMC`(gI z%K40_0CQ5Ly=7+4QpT(RDYWj7f&Q2;gyRb;97~-xpvxv_=b~1PY_1HH}NPKs$x8nk2J*3$Ou#>d>M19Xg76gK_b*Bd2rO>! z)JlFz>Ss2x)2)XrVnYMOQ-VSfb0ACZ3ZxYb)@}t`1gJ3`R}1Q10@3@G?G8xa6V%!! zOBozMuxv4(n0%5KN2rwNUKX}DJ*Izz-kuXJ0ng~a4_2u_R<=cDgwzbC?JE$ z5mJS`%h@%zbttG>)@MzmYVW8Sm*g#g{6r32FvxEMb#M~GjP7qp;vx$nTP4&Wyu&L? z6g)E_(JuPbYPMVBP!T`LD?^PWYC;$*-SNGgG04l@Fec}gR=OVa|zP&b^3qp92E!w5xLO*}@@Qj8k>GJ4`238ouO z-8{_0W6v=oLvvzUinO%2Wd*kjTtKq6L|=ZRv#6P}BO>t`_(yASghUb97_*H|X7w^B zPNkcHmBUVBj|MSrV9Ly*X&wo1V1LZ2hG9eEQpC8>y4*Oy0>g=^#!LmkPpV`LQ_Q{@ zu6m6^_4}CJcev7PQzruZmzpmSbZ!EcsC8n+@fh;t&m*z{%(Bwp(d7 zWO!=eOK^mEVzfA505@y4XM8KN+m1UohZo!%@4ty~wYC;BH$hbQ0jLFDH50b(FAnlS zfrM5nYla^TtR02G4z$N)=2y^+yTr&HOc~eYWaCpkI+-?G;uhD7epmrf6--eej2l-B zVoH}!3{(^_*gE$qWsMXA1MVRyW{SX=D6m8w!~2f$DR-Gc49*5{hF`2!jI>4(UonJS zFHB{l{{T~1(e*cTImJvW;IA(f=}B6-E&)u?;$+y|Ew)Q)9nL(%>58iJ2g?OnEUSPVgIh!`ge=(Bh_6oxZ2gD2C z_@#h6yr_Sc3xC^wVZew%>xdOy!~w!EI4c+mHLb-= z=_~hr69puxZTWe85F(jH?LE{lqba1>x^7BPQ0pzmKO8>>ZMQ<2!hO zQ@ph*(KZwwgHqA37GK&O3hFTPy+ejrrha9>RGc}F#DuxDZ7uQUlC+Z;b%I5$o0EqVvNv zAtM;|3#_&R1KX(n9*nSj6|>CSpf8H+9mdFcDQVbviiiIIK4ZlXoXOyobUAoBCH9!Q zUT*#-YSM0efgIh`Nt207E19dePv%nb%^%Dzl|~`osA^&FGrT*C4aG%=2y#?BlNQ1e zv+(P}36OIfQY}Nw!MTtdA(IfpafX~hZ-`*d<|Z3NhOzieaVeJ?gH=n3nRMa+4ur%o znqiFY8y1^fVk?|PMH|NxiR(A@C_i-$#X>sFXj|ubjWjEm2}yjp?QoY(UHnS5R>IA|qNt{nd_q}P zUipAP1?BmR)27NFGVOq<#PZ}Bg-uqJycQ5@7&t#@Sm;&Jk^7Z12q}AWHOK*%A$2aM zARU*DOa#kOY#c4~5Y}i*SFFOjLmL2X;KEay^mi$KDql__7q_TLRjU1KR5>I^9hZXTfcCNf~w&s3#qab z6%o}J)H#>LGoTyy0dQUdEZ6TLti{Q4o)q_tq)%~RDpjuK{bsu!COtyCfDHrI;3!x% z1P>V;y1zIeP!U}Q$m)d!GNxP(aZ$eF2Mx7Z)MHcu3V;|mncp42SOpr2DxzblTp>%S zYlwJ@y4(em(?q-ha27FyyDNfL&9>@RqyCc6Kr!ke8mh6lj#oge%L?Zj!4ig%z}ZeB z_jmf2#|z9j1m(Dj z9m3!o@d{@XDn%HzWd#fe3_?oQUSLtbvw}365`s~@`S&n$WDC;>wk~9dsI0T@d@xqAKysrbHLX}7IXIC8Vh6mi#|`tIB?gveo2gZJFHw{( z!|G@{{{S-?f9fy(qOkEP#qAt7jBrc@08;YBHY3K8z*M3eAZ_qVSQVYDjBuW8;RR>i z23bLuSGEuq_bT4c5vH@A;QcUz?LSdhcr&sH;EdNW#+)3@P{S3K9iiqRT_RL6b1zob z7^UIK9Oq~?uws>(nvT3erjHC^Zia5^4&^EMoEgXW_z8NsaDYxyvHeTqnOMZDar=PZ zmL@5?AjsBZfgz54P5{Y{JzsA_27gSZ;NoEzhi~892Dgxp9`Of|CDlR!#BTk@&|Fbs zO65{BUNEw(7Ke;tEDKq7bBF=RnI2g46S_CVTs$?1089kVrGbPCv2ox?E%}sU?0JT~ zT+T1tYQ^yiWa+6{Yg{I$7XwPA5nWu-&Ms;H01tEID;=cMjU=xD_~Hb&blPA8=&tC5Q1*gE%{9M_fa;F$MwmHuE;` z@NYYcvHVP2+g!@Ez~ZIR#b(9_H+&AIyg7{tn~GFeXx{+?(+lJ5KpAUR{{T}F6QVa9 z@@S_oadklI;c|`z zO+3O4%C!AteI@>FHJ9g#U)(*{S#18XDomv^%jOeeRcR(>J*?y$&WV*j#LjoUe*0gf>D|AdSF^*ZC?leMZn+;Q4*E;mLs-xV9ZTT{KaDK zEiAdU{Sa`xwq^ilNAiu2h%3wDRghDeyU7n94GRHZqXp zAq~ue1z%)$9i=thX_rH%Q@Ha^0}Zo+rai1FS7t~%_A zUqRH~ICz;oN++CLbz|J5BH=A5xFYNyXNVNRe4LTfExLl#jp^|Xj#3Q$xQ3AGD}~dP zwfKIec{!T_SVJs$fuSosLJMGYz*1PUmqI;Fmrb=ZS!Bsv#S}DRr86tUAs`pA1Ci|u zT4Ba&TM%cbWt_DYTDTJ_eawJn6&3i$lTS@yDhU8u*ckfU71l!8LXKFQ9xOQ21zFyV z94JH=sjTh04+(Wr_5JR(w zpQ)CzX>rZ_1EeqxPnNb`*K+_cAOhb8#NP9$tRn-@1s1bp9T0BfR{{V1P zaevG!XU;o=PYp>KV`Ex0`~*I)R` z@cqTSF$3mQ7T368oStRwT6l>^7KT$V7$cEgQbDrTAI!|Rt;H}>A*te2RQ8u3gK(*^ zSkW3Ibf_Cg4^ZJ89;3+Pp6SC3TMpSJ=yKc+5mBtSl3A|Nbtt#4pw9as4W18Cwf38t zx?ukRGVS^yt2l2l-C_+REJoUcpK$jr9hD03H5<=!pIwxx&vN@F8Fe4H<^!`+FUx{t zyhHABh)#7WncR3&58`IXXo=LK%cc_1mNoS*;NW<G2vuGbw#Vp zxFMdQK+`r}Ns#N*bVb?UBvF$HN@g#k)e}Rg}J_W1s8Z?P-(o8tP0A|-oB-PUBn>P&G7~^Kt500 zA{6Mwz01g=WmAM1xN>oFg%AzKL`@Bik?+}Z_=f3~r?LRAo!5Ly069163j{Q(DuZ(- zAwMJxMKsLe)CZQ2I7@pM9RvvR8BQ3Ns};3{fpIJgLepHv#sSxL2NvL*Q1=xevp9}j zhNex4a~D{c_8d%hFr>=KLiG(2)JQDR=4vaib> zKcfv^u`(uPRUTAY6Ic3}1kZ4}O!YWg9x!*6T#aSw=H>>c#3h5jJms1?68rdC8++4IbxNrA(rm}p}G<~0E}o1wa# zf}?GnTLF^-G;!Z>Yj&tg-8IL9a+`yR`(=E7qdB;CeAC280A|>C<`Jdv+}dgI`-97_ ztDztF35o%XA4WVi(XN*!hnchTJly}NFnaMW{5pt*p1u2N@b$BxsStY%`SlKF6 z5HEm_iufUlq?FwP?H*gp6_QJ`#A@2K@I@}Oz0_6BOlX&Pu$nP6-4h^j3fam0!~sn- z-sk=V5mxp6O0N+%aRn*V(-Y<_B&d6s{9&+Xh%g3<7djwaIfGW|hffgNhFr!~SDBIS z1gJ2VWXLShaqNSJC;k%Ac?`i5Lz#oRmZrmT)}>8%Jwp{Q;tE%&mQS$MS{nM66>-*n z;`S2lwCyW$=rvh}I3lSdyu{JN4JW+MBu*jdlS5M{zBO^G88w;Bm~C~=8_D@|M=4Q4}Gw1W!giK}!< zz`E;+Z~~SJW`mHFK+y4gzy}3962KKj2f22NYw8eS7B&}%3mXd?lx~FxS&BT$dNmDG zu2|H5m;6M?K*MU)L*$L)wtk^;IL?YP&%fd-*TGqFrucEGVaAZ8Y7!}F_&AM7 zgeJY11BA(@*r>Ax=L{XgfbiyE1%p-GyONx=%ukFmonUiOP^gK7-e6n1^eYgiux`v> zFw-^)@7%y3+#QjWF5&g&RzjL9M5Rz*l;TsgY-aoME_<2GDL$!YC&!p)7+e$!TOyuj z7alG(*b_zqt+;C{V`5fbW79OY9_N7ow-X2Ylv$KG;t-mz(@MeIs6e+P(-d(95&ot} zh%W;%s52N1Fl&Z2!Kff?8tx&|jAjl|Z=A&}qWYp*m4D)(iL~55h?h1jex_Ja@jBKn z8VsL_%obGTU4$;_`iEt{;pBEakt($D3f>u5g2OpUbj>*~E{gc5T;;3WzCkIWlrB%k zqE2goOH};s9w!)z?_0Ti)F_^Mjg{Y11d8JAbrQ57NrLJnw-nJDteTfvs~MS5Drd++ z_-H;GjUj}kiRtmaKSVnhn9aTrBUF`zpch4_Mxh;P&jYh@1^l;2jjECS8(1Z`i-5ei>q?Cm1O1#ZT%iGybz zH!7Vuf~2=RPPJj9nDJ1Ub5g}Zu87$B;t1CaX~{l8HyUNnPGg5ootJrvmxksr>`W&~Sd9j7#tVzo>cRMlh$vKed>~kXK2g1%qXX}E??LUB zq;0uJ)>lNPDTk}wZ{~3qW?+i}gIe(HfCcWG_LS~4t-QivP9Yq5NOylzTKW+^<6b2r ztX@^)wh(axap<_Hnn2lxs#L5c;2ZTf-W@;>_Dkn+3KlhqYY8%^tnbfIc=G{I0k*u# z;N2VWUVdghG{|%Lf~m_?-ouZHYcoLPXA4#!3`I2ayjO-R>n_Jcul!A8u&6v7MvM?q zXNshoR342_<%v7N3JE~XmKhF2HUu4M><|(N#FM}CB$+td0a(gbx|@M-A4e<&*lv_ z1m#ZWnDs5kf~p$1T9u>(Naj|Xe^H4WgBQ%x@%Wezm_!Wc_^jp)`-XjEq34O2=2Uc# zP!Km2pM~49D`&*;!K9kmKZYxdrSI@qq;VCE!cjEGL4uLF)su@eV^ag%7I1M6sDo2) zgf$goY*;FyOTx=%yvvT5Y>cEGxbZApLku91q7zUWNWsQk^hDC|-#tT)Lyj2S*~mM9 z83}-9WfK=~a>oqy#JCWznA$GSaM`w4+^E&YBVDXq-x0Ge6=`NOQjKGKRgD^>fNC{vumv%V$^8tI06B_m9=msG&cD9aU*%m{@L z*c;~9QkxH`E$S#mB67+AQm=>upV#vl8kDUy7;3jX>Nf!mIo!B_v38;xD;{Nt*t)sN z-sO&z>NP1rIG7H_bqf@Ygj}yM=5m2=dtmVJ zu=!?b;Kvff#2K4^Qx)P74!f13ekC+VJZ1)~bB#eRId1ucph_G0nN6!@N54Mz0N6O& z275_HjroK<-AZtKkQj#vqzEp#m6?N8aaCa!aN|;ok>rZJD)hrEMV$zVNVyfJR4#Bk zh|mIoU_lQc<^u;mIJwl>WO`i0zS|_BjTG)s;s$-nw_F~Hq2YurM6;WQ!Q@IBT~>)` za?BR;&2>8P3*nC#-o}ejP3;y&f_z-hwu>jkS)jXsE5r8(K~UYI*!@Ix($UPcc;o>+;B3*!>P^9 z0|d4XHl=!JmDA!mCpm~m1MiiIV^WS_u`Ph`^#n#SeEu{-)ODS}tG+Lo6at}D=5ZxP z*5koE&0eFGyURL_{s=j^h0zkkhi1(R1^|qN4c8EOWN_esN@B-wr&txYoy>@f9wTRS zRyj2hL5E~iiz#>z#v9Fb0Jw4D5qUwxt#I+&S%zjI93zQ!xMxz9m8?q+Ls3z^IE&h) zeL^{L9U?)w=vb*7t{QhKga)TC<0A7bP`5BCl&*I(L%BiE>Ly}ST*SOGkVN4Tm$zL( zomS_6n6B&f8u^hqIhacVOB=02apDzX*EKnL;tRc84w9oMTHDVMs|l^c9IpO|<4X$= zRF`<>rPhMc)J#&Vr`&a-)~4xG0l|e_7R_hyLj%EProDk=EC;D(#w8AT#ZNJ5h)t$r zu)4`|`@6(6IG~zvM(#L{nRIeXi>u>uzy*J(Q(>D|a+6E*#BV)iM9RAaW2Pzbg2{?- zL9{lm*hQCuT(NgL#v!k=5id>mP{R5M1j^03N-}B(?mT`C$2Chj3m!hTJ<4^|Lk!JR zh9DkBG*d+wO~Zl`7snqk8dN#(ANvtSw&Le_l^21Pk3uUgx_~0qNmx9jQFFzQ!ACgwW>`D<$%C z4gwx#Mqu(K*fGNOGCN$%IA#UI2O@fl;%*FCOmfR!;hJ;!6)UYoKJ|1xN+U`V_|XE% z>*f;Ap&OuRU)&GOMIe>}JUk!Vthp9{oqvcqTD|ToS9yAsc>yd2ZW-9AGgyAi=Cy&L z+M;8sv>(A1SGU3qSKe_<-~#evEFy?970Lz8ZnSxRB|T)kx_S7Pw51MWDagIX)`9hy z6m$?Nq00BDpOYV8aI05-ZgSl-)EBh38^e2}gN z3XgA}E?@!(&}T&hyN90ZCx~+MsEmwj0=f*O`znD1Ba7zyj~2@|yXG72OKi5vjyFUoqm{1*z^?PN=a3?g~Vl#!k;s06|&0 z;};O;25RCtPJ(e|;*CWJt6`l(q~bals2-xR6Sl2~>3=avn_GMuj`X^l5MI4P7*Z9j z$`p4kXl%KZAyp1enDED2!C=b+TB&$<7deW^vXLoa#x)Ny6m>AC7Xf-b&a!e(FUn3o*v-5sG(wK zti0eQ1q}=-@hGNd)z4ET?S}b?eFn?mhFie{DE|N`d|BM$HBxIeab*QKUBe|x;t(mR z9EG<~;j+ElK;x{&fD1T_3zDVL19uIK-S-;>N@lm}W-qyzm=;-UDCXjdSYM4rqW=I; zdKf-0+;Dr9Lpa2$a}k!<3#y!Hd`oglFRPTSx-F?@anxaSKINs)v|0e1O3945%nBR5 z#45_qi9v0smNZTHj4D~M)B?bn@fAQRq`^ZC=a-ZxQP9_Ll~S zA_`Cz(>@^x3i)7Ef1Y+lOg+*?hC*DjzJa!&L-1O67tx= zWbvtRrD%*d)-i>FVSpR&m~3Ui>MGFiIH<#Pb1IlDdW-hl21qbU31~tpF-cV>If)R{ zj}qWb=MXrH+a4~1SiuZ|vgyI!-}#BZeR+(^qTHlnXB*4zsufRaE|syIvCOewF~sf>1G@-ShL=#QR;JeLmI&sH z#q9l%I09ZEil@8cT@>SSQdR!|3IRCoF+o#*aHE058nwNdflV!q#b6OxF=2g2n}4Jh z^*jh@>+n30WI_U{VigH!qa4A)%1kiV>O7_3ErRiZcyE6ZWUm(qk#u`N4}3&^hF3TSbT;VNanqY~huvksMtyr!Gu#fiiB^LYFlt)Ug1ujI*8?BnAPG_TbOwv&Bb8s)UGe_RVWxn zQCy;;`;Ll4fcuyiS1UO87r2=++DNcWIM0?Dv142A0s4BK%T&YRY13?6(p9tlO^%oeS%Wx4MWyZuM0*kk7Q=RyhEknyu zZuyzv;xq@jr}SZ7gK&lYbd>YJ^_VEG!*o_J2Mf#^mtxR%jaT(T$f;iuP79a_sdkq9K~B(JGLg|`9K@o$(p}YAGqPIAskUyS z+C_FiiuWjYLkHmzL3V6{>SCv4Ws20L9f;3Qab8&LNw@Hv$5#-9#XpcM$DB)W(>BC# zO~&yz8Jt?dqM2k_NN6zk2e`RvVDcf{T|;T^50t{-$D$d6!NqqyN}8Kr{70qli9|kT z_q&e^iO;_=Gk1m)Z8Z&3rP&s1Ff_12Y&lWfdY+@9E?1!|PaVvV=HNw!{{VL@M8Kp>2)kINMkIl}k!ojK<62(3uQhXiE zI`;aCcpmwb%2y^^?lCjT#-gzRtrET?l!lDglX1yu^D53$7Ua27;3|pu1jV75c1PX1 zXT-DIm^had*xw|gja}Y4hgS(YW+Rdn!-${-16QFppoHn{i;1ub5Ks^s7mJ2lTJjHr(`wi~)s~gNrY5EK)~aISdWg=> zpyo?R)y2SCK8U=ZnE@y~E;Ml(1!hn}G+A8Bz!s@>9x)E=ZJ0L5QF7n&XGhH+)Qj7YCjH08og#wo*9UI&;we5v`Cf zFbN1$@p*(MjerdGEsERsTw4jQ9vl#e+oZuUo}!nbPP>h6hWyMGG#CvH_AiOKLYhN^r^B{KBY(+a5GBHgum8itit9p=scp&*4h z$8!GBteebougY|-N&`d1%14-_EQwnbbSS(A<}65nyI`5AZg_qhEZi+z)HMG96aLge zmnBM(t*hczd@x+)#K);*b3P?=J%U;k@2QSmm_lS!$sB`-*)%-ECEN@595pP>)UB@w zD&3O=&HO^-xGgU+He58Ws(Cw=YBL3nI*wVhGZ7R0Kz7>3<^W2;gmtTwVK>|tUS?`m zWi!(DxJP&eKsFdE85z4~Y_oq7^r~Dv!=qI&Y~~lmRKQ|pFh_q-=)f=3_*EUT%qvWU zlnY!pD8(Fypdr>|sN`u{>1SKKWX>glS`1a|KK>xTbWTjTc`rQPFR4 zT9M7_S^-$Aa~LpCxWT?crbBH!#n?OZFC{ygmPVSq(+Ckk5)dx1Ie%^ z#5Y{ZYi{PzgCrEGWyJxS*UVrHP+8O(ubHUmlpcbP<}32=8JNP-M+{98s~-epjX0T| zN&~riXyrUHiWBt^2H#%ewgq8Xnj7~pFkB1~a}wa{qlIg9vnW=Z^1ufXK+Xq<1gazf zyGL_y3^|RN80d*MYoZpyhq-PshnP8c0Lt#8eU%l6x09uq1bb>*th}sM^BRwA&R}*i zj7kee+>T(XIwPEu!!%rUvZXtQwf_K9anciS5!QUcNYTXDt|I77ZXoH3$HaDyZY3zg z>)axu5q2=_cD~w_m%)AjW8h47NEgbipAncfscQLPslhzs!n_d$W;V;WT*|e!;w$oO zcjwG%Y&luaaaLSy8&uzQ0YN6P>)oc^KX;u^TN z{{V3&0TeBbxjnRhGWs`cA20HifHLU-(@X-6^?bA990g#E-WJ||0Xdxens*Bd+walL z1ZvvQ_H_Nn;u}|IZXcH6Q$1z!c6ya%zY(EM9VX`RQ|XHSp@B$$v&>y);|HMMqCYkS zqtX1Gv1qVdsS&2pAmO93%;Nm$z#B?fZ1~~PSmsqn5!@?`t8vb+UT+ih|0e!yDtM z7>?#nJUmWjN6hG&W^)Z}n?mmqxp?y)8kFpcgD+#Ll$nN^b6}yUxcbkQsGRB6Z(aO*iH|ag>GG+xn+aVaVjghO{-~LmCVuVD2foK zM8ehN;DcB$^$`b8a9}VoC`H}Nfa_5UQrTyy^z|`(xPZ3@Q#G_YA&!Gs{ldpS;w{!D zGn-t@eg2_`6CrlWWKXLe4~Pqs;x*=*f}pXYa794;67f{>@f6k~l7g3P$X6!;2HcuF z!DZ*iiD9O;%P#Ak@eZN{s+EAC*(wJseM_vH&l1*%mBTJPLUdR`ETr!EsZjG8hYC}c zyhisvJNb@aCD|7Y$+PhWFNrbL5sp2h*ULemC<#M-6BrM!nE4hAzS z1!<-M6`T2qS}EQm-#8bIO7U9Pm=zX5-Xo|5YAprK2$aQad6^620;4u~669?+!;)Ii zv_ZYMZtCABr6wC5#C$ezJ$D( z=Yl+>3=cORvjMvW($H+U8g+8{fsaw%Gr8I&L)_vcQ;FsVLcyk^aKiwQ%3b#i)y6ip zOh&YLX9sZd;FX$XQ&HN{+_$q1VO&LA97gPJVoHt^Fw89ZAh6?#j_s<0%!_aOijc3VrJ9?ybZTIn z+_24NTrQp>7gwEkGcKb7qCLc=3+^WDTfXxS!vT+p&+{`&_S7=biWG`?ys;Z8Wbb-q zZ8MT0;H(JDc%~uAgw%w1Gi0)^j-a5qo4I!8CJjt1QB?O68E}}j+{T=77-DV2D+grX z?hk1KuUhjOKHM^;ip3sf4aDe{k~++2I!bC9E+cmuNuQiBD@~NZsW*{4VrO2UJ+%wd zmkLZ1iKW0N>;x=W7MQ-}MYg=4r6bCPH3{k(0nkSch{TR^LmI()#^Y2c+;hMc0AZ}a zs0%5`5x`LM44eM|P|-@Tb9K@b&>HTu2mp8RK%*sfF`R%%VHApO%8nL;gL0+?@@^q2 zSXIUuBC%0kijK>Mna<_h^IDmZ#>jACo>erc>7ptSYLl4m8;G4QTsVEf!JG3m#CBIP zRx}L561(`0+sxMA_(V7Cv3bXTb1)xX<`Y>B#Zz}!V{EFK^#+2WZcRZ~ql@U7Sp}LS z+X^;#h#L}{$T*vAJovwk+SdH5G>mK4G{QM7Q20e#LgB5?9Ka*ib}P4R^#t5 z)?E0PQ3raq^ft3&5i|4u07y05voDmjy8yM&8CW{+(WAwWLfU%tRFOMzj>*nw1|0WkGEPEHmbseao%}nXIRJXaoCSv)HjoI8(DBQO-Y?f%p z@L;Ssl$W-PuBNzL`QglU4qm472ZfHhjmi_320W&oA+Sl5pr-hSzYftcJWH5WPnfnM z>luoS=3**f@Xj$)N1DuHZ*v*_MZ3aLu4Q1%FD(B6WK2XYi*mcv8d{ectG*>K$M~0{ zEp8ds*>i28yN;Kj>NxfMKw#67<49bv^%fu8xq`vxi0-31Rfu6W$D)`BG;5S$7Jw0h ze%OxShLHWssIV4XwYFRH{RlDxOsjI3P+fjWzqSwVQL<{?LwCf&w~Dwl zI*s0{v2fR>J!AL0(I?Zh_WK#l5JG+^@vdq?dsQseG?%8cTh*7NX;3u3i-Uozm5 z(N^Ko_G@y((eQch79ikK2XyloU$0iCHyAb3TuL;)9@PseB?4omZ9I zqx`HK7-FrJ7q=y{?9U`y_7qCjHVUi&f+oiC>IrgOX5iSug^-IK;H8W~^YleS6Y6Z6 zg{rqQ)cp|=@z5wC*EdJWnTl;Wj`g@`FLwont<_8z_}dYvDjQdD zSOMKkIt&PCVPgtp<+yJC$d-TQR6AliJei18r42%{+n;idByQz`jQY%F3+!D*&N;W) z+$fqYMR^IdnJW&Ohef+ZS8y;lRC?wU(B}GMk}*;74pGZ)J;r>P4QZDEQSRlh&wNCm z$;-YWSIvRtO@hJH8&st(nZb;}W47L$Mp=;#^DPy5s2dwtem5z>aLB)jCa8tnBLb@c z{O%lQm=fi2&Z4qcqEp!juGt-tnugkdIDa^5R8KPSavPP8GbGc2DL^qW`*jFC<)~8@ zSRNo8pa<%0f4Ss^(Dyfo?i|HgTa@KM&r>m3=3V&2#CeXfUx1rEN5uFMfcG(E-ON=j zyeEqo=tE08%;xn7flyWT%u4PVzY{CDF&rUS$thDp;IechuN}rf%if{>0jSwQ>m3S# zp>ZfKlFK5VzL8H%b{cd8uRpFVpI=RUGK#aA# z;x!6GWYq#!4-jdwX;N#%U@b0pQMo0!?kEz9`+~yZmZPNY>RLJr#mi*QSn>;>QpP#e zK}@X8R1_ZJj?xs$flRQnvXN3vF$l4@pAxr5$zLr)M1sZRak2}M6**>TVjCH#yLO`y zyGx76#r2owg2$dFqp3o(Qut%JcKSOII2(mn0Q5T;iN?`aa9tU2k0Rl$Qvi;8hl9z0 zuLjugIK$|05v|ogThmg`XiQwD&?>hTG~E}CP+Q%p2kt1Xvdk>cNT-FIsPMt$S)1SzGi2F7{j}TJw^561_^49O6@Vp zb_b>3GtI$6i>YI2$@4R2jtN5G(@}boibF|!#=s9h)D%GEv#6V)4rTF-az%AH zqi66%rNwWw&AU9oRe;%Bj0gi(WO#|mxIyQE{Yo^UX(qk_>pmftC~A*t;-x}jA^t<{ z`kd)OusRM2P{z8fSx1;z>WDq>eYAUx66$xAo(}~QuP@xNFT@JGCLZ4pEUUEILGtAu zqM|9}g>owvq~awRwx|x=<6U?M`l)SWo6+IiVg|za2^bDwuORK@sEUIvtKb>=A2C5I z2sv0di~s`Y+Eddk_-32Cg_qRq_+y1vt*ktfQpZsgem*6yYLq1@prYw;k)T!_Fo4*D z0P`*dxJS8tK}^dm9wsb(LDax?n3|)gxgI6qSna=1s1q)iFwOmt%y-X>uvO={m%g4R zBW|W>m9c}v3d!88r(2G^%%bFO%b&3{7Xm7aVWuId@dlVWm1m60v-p_Y$VU7}OevKN zH!>#3WW=LJQNn4NiKJ=%r&Tixbe2lWl8AQ>Zxt31gbroISPf@6flPbia8*aY)C{XF zHR3ZBWwXq7!MHi|1*5)U&DHfOMKOAg>(#5qVF>79n(k0ZK+qE~7=yqPz6@9{u#+epqgjb1gh*C zwicik&QQv^VwW)>)j?Xhw8=s~NU*WKV*|NHgpTT?SSPs?0Qqqug7R@z)4iays=jcc zLak+u9I#Yl$gBy)DBfm9C1#*AC8^~ddfXP=#Zh5E3!JbP0ADiTs1?_k*R3>Svo?cxpyuAV3!3+ zes(5hVmM>35&RgNJdr7hc@alZ7m8VkHga^zT*baal44ymBcqsx(m|!_2}}oogN29U z4^?_gr8X(N%xPM-V$uP^Y80(uJNyso*EHVKV~s(x z$5U1;ueb&Qm3=Dr0sj$>q5S1~6CT7+gk%>pP=QOhm5>{ON#HqiSDRTogQiV1_W;Zb0 zO@oT0&Gthc;i7{4@db*oY1v^YPMk9+5++T6GVo^JziEvR|L@+99 z9wDenXw~y54N&GdA28hxuMA9>*#m5{{6TJC^AK6)G9Dv2yoqe8xB<*YfmqD4BZo6E zV;38CI3+0?xS`giS=$}Q3E2*ovjsPvs$DP1Erx>Opa9NkEZ z^cV;zD$O<;i472GN0-1TB}NDXK?VX2gaPC0R1^@E(BI4ZFP!T-=X%cl-1q0>L#{hV zwK>MDZGH&XX1&K5zSErcJ!9euy%W{}r zy-9ZNrspYQOXHusQrebuyPmLQN81bC@>Lq<;ezoR|ChSW%P0!+Hl6`|cv8az1iQ&y zhds-O9|Vl~uT+E{0hmhYrLTZ%k|xg|+wzPkhnTF##|vrBedfBI?k}Q}M=Q}=*)U-Y z&e*fD{S@r^yzX*p3FvjtRXo`_WCy272uPYuT^~dZ2MeES=MXb#J0`MzgtCD(4jIP8 zZEZ|Kqa#%|3<(;orm^^~?QJcFIB*_1?P1Uo$GHK)vn7|*?qR#kH{AJm!2)ccX!0!3 zW%GSmdTY|GC^zL4a1~VUWOT-39%sc&oYW_rQZX?)`qh3bi|i^{BZ0Rh{~L4C9WVikhFzVL6j-D9sRBWoJ{DIt zeqaTEjF z?#5hU6W+(@00ZDZjNeY2Aza>PPfyV0SE#J-CO>YmOzl+$fLYEz^bn0G?Jhv<&ylGRVFW{CJs%y%8iqsy!iy zMao7wCXYrCwL=BNqTA@2o=9}wgk}h2sc{)ap68Dk0jjTxmaRLPOcO+rXv4AFm%q6e zeJPqqo?r1iGRivd;2gXR)i8!zGyUah=`>qhL(j9yQ{8L(sBQ@QQ3=QKw_pWcQ3@-= znfs2o*Z&h5rW1D~u}+ z(@TK{!Ckf&PPN(}=5#rcd<22=s8QzjeU?OmzSS?>@V|>P|KRGd8wd+)S}5k9*SOLs zIeZOO8vmHkocaERMnWJW@m;&*caOHEp&_3?50d zQhur)$Di<>6J6kp4beCu+{Qk2q%#L1A9=A#aHxA%_qpzQpCH=;DMBy5cHC7!_Yg;EXx&c!vK zS4m8$1jOA$8T*_4HO(eo8N@6(iwC)P<$Pa~^n1OWGzH4>DkG5%x9m9dk*B=D&g^+R zFL4BG*g&+X*=OA#H-og%ZUp*g+u7GYPf@TYm(T6A9X)^G2XSJVsJN(aJRo0e@MqUF z5*_#6mHO?A2|`OB?N9Yrur?>TOH8Ik1aeN~&KjZlM3l6p*%bS0>LNQzenIx`$&*MG ziG`{P6}#F%v59GNV+06OY@ts;WF>ZnN@%fyKpUa#kKVBL87#vXpVAcz#ix>Y9Y;3% z`PB5XnWxX;UmVq!&2B>ORpz`EI{;x_>hiv|S8pt}oKhuE^B7=Uhf3~Pyxw^Y!9+pr zq~Ef3UcXdg<=;-8W`gG#^^-JvkYx7BiaMBg-P0vb+Qr$W)+dcMnZdD>4PTq0{Lqsc zfWPI&Xa}~cvw$tVkn=?@Eof>?B?A;9F7Y|>qReJ35wl3&NgHSXP(CeSx+$qEc5GL? z`u&b$;ZGj+0O(!$Yn;A;zaD4jXYvk41F&KFfz*qW$Rw{p?Q80zA0eqs^pO$}BwuxR zt_2U3-r6bPTczX#agG_FQHaRR%L`WpX1?t^yw-&MCf9IQc1QiYL*`KObyCAb0LakM z{=KZ<=gY~c*gA0yp$-#GN#W0G5gNR-7?_Wmeb7367D{))zsMeK(&v{Wl>8LN5bX#f zo`7A!66I;M0(j8g>m56|8kl&XUe{=Vmr%glDg|D>;i8ojc-9Gow{^Hso;+Pmh?JKG zfNhxM(?C8I|Kr!`tMmxPV_1h%e|Q;r9|c)P+ifi2EYQ9^_UTh10nSnhsOzq2`3jzkc{a(L)jonB{N5i{n7 zEma<-{4nyo2b1i;C~T^a{bTf`?g16o7QI}L>Ah!=SMAnA@-l^n_%{l~(X%ZdX-}O= zsKhuM@j3fcCzq1$@nuoe!&2cd@8-E10m?mz2{#`^3Yr|+`HG=eEW8TsLN5#WBplWy zd#K6~kpORJv*Zmyl4SFEepPUxJBQp=z+8WfVV#2$N0T%sBVE01tY!I)>SL$p`ejMp zk-AmR&O8ZDABK_}w-^;h6sOgjsk$C_57P6f5Qk+2@n%pUM4JJ$<{MTOuzSFxk`M!i zZzw^gY}ibQVN1N#ExeqtZ4!@I^M)f(!x>TxpPfVR*ZyPt6#$#>SEA(D#~(63#91|y zz21>pjwSamXf9tHnmMLu-yMWIL=hC&SelaPRHhBbK08ix1!)FOq|>(hO0(MO)DWTi zHs%!u<+GnJ=OsHP@xN>%^_Y0O(rg>yX{l2|3*P9)!xVgcxw%Dq_OO*GHoShU&+#!F zH0$kzDK*0184%NVIk8!pT7RW>6W@+{5gp3;z5-`f9Y%Zz=?69=Ql4c&qh`KL!6FYAU(wG7R1GO9ZIDOTOLq4O}o&NAZ`+3+`b zp~}JyFPHh#XzyW4v9cUYW`Vl0EF+fOYl^Q^;y9n-J1V!B+)HgepK(RzkPr-r{ zpl<3JDXEiFxQwZ>DN8`rr0$Pt_dt5GUO?D32B$%!H(`uCM63HjVE|L; zJ}QrgzFRg0FBRX|!1_-PmGyj_-E)~b8gz9u33jo>{^zrwI>&MW@6*_A3M(hLqcX=b zy&Dq|-rsCGr(Vul-6atGBw#QJ!3MZj&3?-Oj7}~5gAUX z;L<0+wL@0jD|m+K)AZn(#MJk)&I^8QkuK8p5B;2$2cB0{7K0K}Xq~LP_dOx|#au`D zn=k`M886Xz6=wW*!MqdeyLe}-kJHX#K-n1lae0}Ay^uCvHi|Z$>{7;VqBqwr-EDvv zj-Km~6|Z%SK^f`#fduc$Oo!jSxbN~C%=W8p|Iwphxy^#leVksu0I&UpX8R0nuq1)t zO^au5nf;KYNHj+Il^WD~lHX#Ngl??R&n&G;ansROYWP;xNE;yCoM~7k;-5m;er#bf z=l0e;H_4jbFFhIj<0{vPE4+;ieq5}2qw-H#VwFXp$0tN(n9<`S_8C~|GDzY~v%sW= zH?o?hwl@hkuT^=f+^+7XI4wqR(v*r;yFIL9{wg=P|6Puzi2drT9 zBHGVn#mfe`nD{)*MN1@)Y6*$xiCL;NZ)&R){*%kj+|qx=JL}$ZkkB3ki7J(?Gr6=1 zy6NJbkOFWdwcDJe_d4W*n$i#JvfGFU&9zwl+~&?BdeuHV3TPs=FJ2AZC^sqlwwW8Z z)0{)Dm{1bblUTX?K_hVYkYDX`(y74hRunm~VL*~L^P7SmWxLmaVAX=r7)*A|Cd+=f z#82QDG$~rlRC%3YWNyWo3IFn;>mW|b?-qF^+PscM(K4MWPEx zp|{snKQ!Vo)Yo~auB*}lZUx0gikX6_e6*lVb$(g%qkD(c)9XCVA!{<5;HT%`RmCT3^OmX(8 zk;B9ko>Il8fgzjJ&aHTEb>-J2XO|2w>&zyEiaDiMkVharCq^GXcKCJIWGY@6Xs?|5 z>I95(XZz*IoNru5VEHfP4lQFR>+|k^io^-4N*Lda<5y3K3F^58axXM@e7G=anhUea zmNPh2?B!X{;u@=ugQP?gJeX-(8^Mp*>T@OlKM3r+(nJro6;N?|)8j(wK9CKa-yx{0 zbyPWxHH+XnzS+($_rb$oK}>M0>%HZodhts`i)N1u>j1XE0hb%K7DBHcVwfJ3s5nN8 zUS5;=pmwSfRC%c9J$s!l%-0YVl;JSa_AbDJULKLUCnt+L(sHH!t@MJT_XsWBO{ep$ zeH#wZkZrk?l?4)fBqcmm0z1?@SWk%_Yrjc60iy4S+;exJo&R?CMm5d(&!lR?qwqcd z2)uYEMV^OPY~G>6ONv`8jO=Q5*v}d-$o3~q3ZqD^=D^o_43i6-t#(p|4B4Lq z%Ulc%9SJ*{S~+m2AJ4nIC`3>+;GJbxvCO(~?bw`jm65Z&UTn;yTWNC|h#V-Cnho8*uOHx^(^1Hp2zF)E z8iK}T3l9WaFqyv;zIYBdzK^{l%|+P`Keo6jW&I^X(&-3N0#5_VY5_Y`qe}i-G*pz> ziL%l@eN^#a^pPH7!1TS@5L72`w2uZ8k!9ues{|QiVjcb8kA!@JowJVKNBf8|dX`hR zbE6I2WDqVM*XQ{F%;_1M^Vl*~dCTualPc8yhfVuL4BAvu;mKrWVDTjc3qys{jMzRh zz0aolcJ~>={zO4qK;d<$P~*)LpgN|XO?5ZhPEj=Lz7`_KR?1_#_MafKJxJm65u+bd zHTJByv=USzLA^o}gwV&1Ocb<^DVXHf!TA?af~~lU*atRTKW7=9$Rn+$L+)LRsSgj3 zYY(1GxueYf6J)l&V>*Y+l*+MR#p{r<6o2yoEamGS zinnNOm|*xri>*IWHWfE|3QiTN1I49Y@8Xe2nhfV0??@WO_ymA5{(|EyeC_-~4$=bk z=mVu6x(7u%`ebB5i(TLzuAb!J?vPkgk6<=a)J-U7woPg3Vf&28wbWcN3#?!2hTuGo!9-g1E`i>FD2T zL>PN!1tJB6-&>Wsn&eT@&Y&D$sAnk;u#$9GKfvc&)?;Q?l)X7;b9fj3qzJpX3QEvv zGmow|-B_{7ZQ)7?H;2x%tg!;=3?nGy6-2K+=m<4bdKz*U ztE1vYjFu5Adsqc!mipyb~!=2 zbyD0xBPE&`E>*`Y(AGmtUBI1~);GlQX8q6$6w7WCO1065F6EZ@o@@kF31sxWhhyeY zwk?xgZ4@nG30%CcG)Lg1V&JA#_;QCQxOQ8(jE6;UCp9*#9>CkqD1Dbs_N83Avcr)= zZBMo?TFZVy489$-5DCl&A}hhf?$lt1?&Z8)Jxike1!$wAM%1%IGv{V)=7**3b*|kz zBvIEtT=bCtS_o}J`?F zm&$<;1=}^G;-YoZGcD*zvx)x4Z5CBQsPH`PwlJJC3M(C_!<=E2)qqQ|e~MVQx)Ph$ z&cW_8?#%p2ty-vg7UE?M@dn318HHiROs?2(kI@YyRyEphAar*3G$MnBxW7wA`zGWt zd#m-!XI+u zgvZqO3^9Dr9jV_gEip;gxk&=j4Wv@SCKsS_4x2{_&A8YO2FTA<>G8RM9xcMFl>@N! zUH$YkYvHJVYyecX_6S|*Zal7ra_pRP@mFc~sdM(S6hv3A3*q?(p47k|CU^eHOobW{ z1RS0<#Tu(nRCaJ1a-4z~M@?SYJPFRViPXd8mGIl)s)TPjomg#wI1B19lC- z%(-`cZhHHP0?ZX?hc12s{~Az7?30r&c}6EvHiC!6V~vf38up)}9^tgMq7{a?cZddREdj4LJjPAVwx~x67pvq62SbKOslRhdqdK@T z?y^Kjeyw%xPwJ|!nZm$l#cMjid3}tPm$FhSg{qGP_abvKd%2EFvB2IPlmnFYzp+ErGU10~Vys=91(DH3z(8%l)NgmLN;-esfIbNLL> z@Z~Jq_9KP<{zbM(uGm>Fj3|_k@@#T__ikHP9j~Iq3MGe}+jsW%j;#-eUWJ}XaS5Ab*!=a6htXpYXyZEMyMn3#+YB2F0>4W)BxZ`)%&-{K{= zkr>^1IpAf5jgg7WzisN zC2?Uzo;LNCBdgXhhF>!&Cq(>RCP0T4$-76(({KI-Wa}B%%sB5d2rt^n^q>Ro7QFlQ z4LbQDk=5@F#f{I0WWONMuA@GH+)??@YG>k#2S$B+0OMN?qhf1&Zke)W77o!$6<{&z z%UpELMWt^E#6?rp{>(8NHGNNEQ=m`4{&d^GmbKnt53QDrJbFH^=vRLar(V87HM-#B z*h_R+T_Kkjw>Hn;XL;5B0=km+KdMM3Yofg+3`o;@eVoz&8aABeM(PNSde8l;)nVLA zJ~nyBx$eq3JR<{z#HM?-y+c?sd=8*%IS`k89T{HuYgXuXDb?GFhxBU2=Qr^kKniM> zny)bR*N<1%4X4RWzS$Kci~TSM+06sSamPlfy2eV=AUOYX%UQMt4Qi8(xj?zz@2vP* z$&4$KCA8k~VfWvy1cz)f8 zv6xYT2a%V@wwjZ1jc)F)f#i-N34n2Kr`FnXu6h~ODaL&Aw>{YG2;y`9DAQS-0xjZB zGuj19nC=L(bJ#lpP8bcR@Hj!5niBrQyTpjl&#-G59FGv3V+ZI5zG2v#uJ1Dv%Ce3a z?cusD2D!qthFT&r*P$wac#UR%m`hz#F|CzZ0H2}l1 zpC`ea^FOMGFE*4-RV2AcBJKl2lvA95-5<>Q>{qn$8JLmR%N;cwXlT7127ODpXBe=F za2&NyktM&X?_7|}ff%m5+g{MQtc5@oV1=ww=gqwKgIWq-$Rb#sYq}A9z)0V-bo)x9 zg8k^_Z9x^3*c*_#A(2g)IK8Xh^Qt61A0y!UKdPet5^`SoIzihIO2w@enYhd{JXzfL zo-jocNbIE1F9ouYyu7!+-FnqZ0lHrdSn9QtuQRI5fvn7%iLK9VCQ~j_=#s|cewn$u z?d_G>S!FW!PqRwRqNy8HL!W|#ZaN}be^~oUhNMf@ zZ79&<8DoBt9R5|e=qU9#8t}j-Ce-eLL=BA(2TZ`5o&W=c%SjaW@L1DkS##L>ITR;p z7fdUr`oIEsM=v?_=_|e&jEl{Bwmd2(o=_K;fSd6O527FRd~v}6|Hy%Lp7{JeYVU8s zqCnNf_RA6btULBN!CNW3qqT(W02Qxyt97)S_oyg!Q_Aej8=C6Oy9msMsr0xsJU5?D%%iE8^8X2VJgrqxd(++u$Uw)SZJjCh zL`hZcw+18l&`tU}uc2uZ=Bqp_fTZVXFhnH=BE{`Ab$2!%lR7RVqGp|v&dMB|1?SE2mvJ6V39jKT zWc*W2;{=uHW%xoAJ_)7XUm`~~t&M%Pz#M9EHT+iUCX70(GYEL8*-vhj>(dXOmD)Bi zt#ZX&IyF-IJ_co<*e}OSzR}NnE>3zjeW=xiEZs~v^gY33_K@@q4zF>GoV()2Lwn)N7@AWl1-kqoAFeM@{)%gy zqj4tIBHyMvXi8PfvjOzXlPskTrPfV6;Zaa-mP%3y!#PRp;9~@{Su)|`3}6Qh13^gv zm$&vU+zuVmh&|>TD@qq$*ZN@5qZp-v1X;y#fl7RKKh}KANjJr|bFa!IF(oVtSL-Z- zeC~felPUcmULi`d12r`b9`#fG1XisM=p2Vn0vsTYoo6r(?|b~*Kh#*QsT134;yex6 z{eoaKWF=_qfpWu;;R$u)j1FU^-J@ba-t|#x-z7p%t~*NSf#Sn~`vM8=s(dZ_!^qm-qR`to|8?_YOH~}6Vc&W*k1(v)&5#0Zy z`a!U4A$Ya=)KSsq?RSc(-HGm|={1nHhyy;J?NS;vj>x+XQ&kN&)lI&vG?0ZyYi&#%-KL>e*DbY363Orcp0j0*ODrj>bi~b5j_1<= zn;cjwepsnPrC9C>{|_R##542396_}u6!7_*HLcY81gEIv?MJFNcHn7M{XpAq%0X%D zMo@Ygz0qZr1VbAUFX@>_$jaM)5Z$SyQV$;+f5?y+$Y|!2uW@Kk$fUB}HNF0KhUftb zRt!-9d2?~J8}Knkj-xHRlon{|KZ;zuV5Vm%whR!=4l?V1BKghuMA;)iF?#eMXI?_c z=+2?!iGnSNpE`L@i>3w60u&;+^VclX5d0X!$ET1o4sBXYsj7cX@)!bLnip<|IBy3t z8y$MgTcH{B;R_rg}dSuP%Ego z=!AD6hBe~BC)7>;Ib)CR!)-laSF02FesAh^4Mavh8etY4E7R9^i6dI1q)WF;rSGO- z4(kLoo)X3kjql)v*!k(94)dFb>}^rVoMf$bPl@1@-lWk%?4_bQ2~>qT%V>^I zZ`lv*Vs~M@pFr|@)F*+OxZ3vvOXcs!ly)5NM#u5mS%?m;gw0+QL)^c+?CiB>`Yd** ztdu}AXYPM~P-4U$ji-%uyOsiKux+Dkk7UzQbanbvCxd7FG@_4fCmgI| zPHwgLTwWk<-OX@+cSx-nLG#OE8k6zKKaQ$hEjGMqK^FlVoF(fuc7QyGt`RIt@diF0 zl!eK!C4Q=s0Q|2m4ad8H>BTj+?wP(@K(b-)HR5O7U{_1#cL4sMK)1{`m_6*RKrxka zi>mA7D7aZC{-Vs`H~+2MLw0w~lGfhWbKW;BWO9B~mBU(hStuhh>!YUa^zdy%9sTM} zg+cdK2pxOKGKH?s?&s_+ip;_S`EmgHO#Bp!OtML^$5oHHjvvv5JLj9{~_ zJ|7&8y(;Xmh#KELWN-GU>qGx1_#q{;U_1CJPA)(Xzj|Kw{EodRKaJxd|E9G~Lr;!P z&QKEmuf!W&T6#Ky$gw;JDJWW5T<8QqVOKsw&c=h1;xy%Y`Pm3iONtMA7)R5E%sI_| z%UCJZDiD+H>M+)~lEpQDMCF`aLiHG?*Q&uRoa@CXOYag!R5eLGMfJFgvisNWV6pPollVkv{E~ugu8V?jEICJ5kL$~;T0fVfpL6vn5Sfhqt+cgEB3onNc?&0`7cHWihXLG&`pxnjb|qIfQ6O4&=b)X>h)? z>Cgy71kj%TQ_aFuPKFZ_%OUGrw!5~Rs+Apan*ZM4yniGL{w3wEQGm=%RS~sh zd`0e8QP+v$o-l3Q$tpE6rbP4pW-;0p!|g~w5-R=OdhH$-Km1xRvZa99A=E_Oi5e?c z)1mv#$<^BrjNHAP-Jxc03zd4g^^C8Exp3zMz>&EvaxLyuH08`}iUHx`eO635tmar1 z<$DsQKAb>{kM$ZbD5VaIscs*(T%-zYHCv&6$(=?&xhgA-?RTz7yY07Bxeyd3fMVR@ zP>oaoR#eG?Q|!Pxxoob{Z!?UBd(koUl`x_5BT~#wH}cmGE~hT+&V07Kihe}J>41%W z9CbO92?<#)#Tp1{H?%RM8p!F}M(NOQ}cvzBL_;Ue4j!y;gwVT8&YMf_R7(Cmb6sipZMhg<6BG`Hjj{e zh=5mdjqY!d(09M39?O@Arj|sDUF2Oysxoxg`%$GBRhSM21U6**v3~y{GEa5@ zBxX(YEPKDH1mg3aR2#dKY6XlRu%de_k_>6I_$}Da-mYsv9iv+z9#IaXy)@W;C}y)S zFiTbwG%oMF$-PtXTO1jy?#y#T1E}ambbJf;9HUp|IAMuT-RFCJL2Q#|_A;X3c2c{icuOT78)JMMz*+-E}Y7Uo8@%VWCxU-5r62*?^6Kg)il$i#lH?J znjY?A58d?b-`{Bx(ZXmM&CQ<{Bv*BxBeonh=ygJO@EXOq9Vt^sv(7F;shV}SBrCL?#-d4_KT?&q z;j$#L+%d0zyDV~*3(ox%U7IbhcU`!#YmUM<8W@TrqICV{=W-Yn)0>O?br_Q2-tQvt z=pkfjLj+ZF%Cnc)8S8WNb%MtVu3HDH;}xdpm!u~pLGcPt^P$7vJwdJMFP~4A#asa+y5;1`05+{3^>zAGxS2U`>#*HP9oWsi|h;FMxul;lx9Ib$* z`~gZmitIPB*>QQgQsm_8#^t6huj2>SrX_d{)Iz$du0n!)wX8)i8%cOU@ZnIG?hqNwV0iZQ}xu>&6;~^xRKx| zbWvVbDt5nQ*IZovlg8KXIW)YK$4>yH^qW3|oxLnDY#l^L}w!WYJ=gftl-EGEZ{ z3Zq$-qs`l&43d`y(JG_)4htt=j#cAtHQ+iITRXFIY zQ;`3$C*ZfQZ#9%V1fvYU$lHglC!{Nfzu^9Fc>I9`D*cPDDvw~R1k0v=&CQ%Xg@aH)_q_7W6eqacI#f6x~x8iUy8kY zGOP9;L&$XJ=EQ4TkOIwpj2Yro_&<>&rs}CKotdQ!IRHATQ9|%t{VkB|)fEYhB3K}5 zk#L18IPkW)^IL#EX^!z5#i>OoCp_j1F63ow4Hb0m`-?Mc(Ez=>G+LD@mo-;{A-pO( zdjeA<%4Q&*htz^{M?5w$y2h?mw55bP^{cvas2gyAwv>!?zGGU%s zyY9(9>W95g5^04g&e1G!uFBfhp_-|!Fzw^3`D9INmFX*n-GDVtaP>Jsnf@M}xy(+E zwi{5!8N?EUjxK6w~K+-}tWJvHL^_fG4S<5NyosqLb`Z=pL%0y}&PqM?e+ zwvA@HV5r@x`thN*9o|MEQi=Y6$K3-Z_j5Wj66N7BGGP{_IXUVm=9c+2%}u;?OBN^b z`%z+v2UzK%Om=E=?m+W^bIHWMmW9Y%&$q({x=8sSl^}f3-QKdjR^W?nn(HIA7Q~`( z&mYb%z0JXkrWlbGzAUX1VCwXtBtV0+;)=ZLHda~VN^tJgGLrF{vIsvE3PZ&}0fh#s z$4=|w+`ctUBc^O1b8p6QZc+NDh$6&ao`hnqmb{PB;Vhra_yc6#D*Mh0(r)$MNWasZ8~`&^}P@zJVt8U%5Hwypkwyk6aVjNsB65D#7lJzN0&Qqdl7DVt=&Ck{jZ@i-=`r@ z(AP8R0JByP_LmHg4x)hx%<7lCT*S47kX(qQq}P%)?*AHA_*+4bg4}*;S8eOxz2#pm zL}6-pZgwowsXh7yeIHsKS;M%%OMBvxIZ!iD^qadhxCivhO6Dsf8qloWT*o_aXIt<2 z*u3SQg)B>6B(s?`?g?pfFW1)T3Y@8ENp>d7+~LBl!{6=D)Xp1QHsw;3PqcY#M(w=k zFuytbbt_yG(z2pE5H$~Th>?e)P9ryb2cHTV&OZqlRi-Wt@@*@DzyO4N9ho?Ot17>- z&*P($|HwhEF<-yS&^|@!LHSSO#lA(Niuo4ge1}Ahbs3so(DTjFb0w377CsQ7v{M5q z4%u$_8(MrHIG~~i`@Sk2MPa^>Kc%hnFlv_?OG}ia^okHFyZZyK4%aTh-jB`j*1EK` zj#4P$-OGiX90?v?DR-l9Vwi-QB;$cUgME``Z!*$U{lMjVkE)X$BZKMZb1iv?PgR8C zNl))5$7u>?Zdy9Wl2`}Hl8N|OwN_IdCHEuxObzNA!85C&BaukDPZR(qNFJXsf1t6tX2Jp_#)s^c2rCJEVUbPp>T-CY0lx~X zd2t`iRC?V{#5cFIM2+H~Gv_mAnmXOhc;@+w;JUn=XRLFZPq-s9S(%pW-4vR-A45c1fD`RkhRbBdxu%*%>J3D(Js zA)imVu7ya1i~1M&o6oS=S(o=xB!~-!7W59tM@TCbfXi&Hq22AYbo-Xh_5iT8x*#k@C(h$+QdHigXx=hj7qS@ETw6v7Kaq zcd*_L^$gkP!)zJwOlG3QPi8;MS_sgD8j`!5Sk zn!Xi^ybOFwov%goQ(D=_G3thVMHx4+`+dla@I*Padnv!(cbV+$vx66{4Yq!f>1Dev zUagF0t{*lHsp*}W0u;uE-5jvr^y1~^FIrRvGe2K{a~9A=Z%60st+bo_6em$lUE5%{ zoPj$od#^epV6n(*?2O6cQ#(-`(<>KpRb;=M=s=a=_YjObudKxW{}9Y_-8%LAP^wUL zrbVD&WM`z8_#Y$&Wl%Eu-g~O*&JmaT9aQzl6FO=+L853Ln3kwh8s5J5G86i*_f=Eg-)8&0KlAi8XjaP71Ur3&!h#8op;GaQx6_> zPmTM}nhvyvk=|onxXjCChq`CjOuv0F`IQtpwv6@KIgi564i1bKa036py(f2+y{i+Z zBvOf$4$ocNlJL-lkyJ~Lm_Yuo1Pw|m}x!;#m>dDZ0Xc=Pvv|`?_t090Bd1X{s&rzrl14 z`kn0j!N$BFZ|;1>R%`O=-j4fc3~`d& zuOXRZsf+$cv%qOJL(cE>@&pO8 znl(>i3cGGP)pSBN#~-D!P>GBE?RftyD|H6zT;QHiFrf7QS!Nn;l8r>K>?K+lj?A%s z1M}#)s+LEl(BV3spQ7!aEG#s{GXGyl}c@vH*&N~Y7 zW=>V@>c865;HPB+tS9%nfZye7yN!@(F5A`!Y-dtYG;lQTbD#%%kei1*Jx<<(` z3hEs4tM_$Rs!rSG6kz^gmF#-^5m3x){JbKbmMLZ>&p#~8Y_KwE?v3B&?DB1+H)vF- z_>=vz=+H{5kD{SkiB&aN3rSO*@^|XU0imGf7t{PUc}s>8_*6aAkQRMlIgk3+6QB<6 zF7})=PUH5}pP)R+R~zOp4a$a?V%?R0i{&$trV-v>pW8?d!&@!h;A_4(jJh{!2z+5} zcx^?wc48GtoVEf%d`A(OzU8`;~4Sx;bGYaOU<-p??N2!7UU) z7x$`}jZvAMDS3%#zGwRB&pfdO2D(`Z%A%Gd{z@2k8b*GL?J6!thkgBgysik8ujQG7 z8aK1h0O}feX!Ety2w4Z=EI^iMq=s7FUJ&%f?p5fc7<_`>>rnGlAgp&v89Xox+oFjj zIjAgYU0ewJTL18Oe&^01+t^~QCg8yx@UYzsuT{5r*kGfVn0d(q8z%VibNw<=p!(cc z+Liyq#w87Jn|zJE!9L7_5=ar2zCKYj3j_22!85bBv;D!U*W+(T4a~#XThNYy?|4Gm zu4t5|;0FXc?;leR16d6AnI`-Of})y|PkeKe7U{*~#A@T|{u3wl;q`Fwaw6#ZPfw(3 zL?`(&ELx-RyBFn0KE4}#!Lo3k8~6MfIAR7E;;j44EGp7$)zixtmD3&#q?o?iurFdJ zkE{M*Q+t$v4@OfUi3pD^~Fu z<%T6h>&56>v|nAGUj%8uV{*f4B01t3(m%ZJe^ds(0gFa_J~b>kyiNlFs&cKLzz81M zZ@%(0%rBsBl4i`jg(-0un(TaRT1Mr##j^2RahiP4yYG0XZWZkhHK5eq^+h~aJbH67 zvD=Za(IXbgV+MtC##6QKi9N=(Qw0hI3 zp!AOkM37xoh1xq$s;zAq?lW8=^@GlM>Xzp-pY8uq<;)j9w%T?^p5+;Kd#VR}Wo!vE zcaZ4#Oe-~1QX9Q)9`bGjI1kXVMP=?Z^Yf_5br{IWRe(PSuBLgUo{TzG;N{ zkcJlGOSzmO(`f2)<hh=qibBcMQFLu z77db2RJUH-;djor^Z5OYR;$jGZc&UbKH|nKlyfcH58+-#k`0KRqxX^2OMWH778)-0 zV-CRIgjLIIu=PIRERi z1DI*66&U)ecen^k*E->7sXkb&-56{nK!}!AWn7Hj!Je=kb2_cv@EyG}Uqal~pJ&oA zs@Mf6lv8@BXe=Yfwd*pEV$OljqF;xf)bX;Fe>JVGDIxaKM$>**k~uBMtlS?tp#?>> znF(>cv@Z>f85e>a=$BZ(34l8px2PoM&HbHC z<8*z7a>J^~qE;8?A(3oSNAY5P|7EjFnRZjcSif$h0FXLOgb+6x5hhOb$jfkdr*|^Txvek=ku_9mpN^s zW>6`p6O|DNK%}^1z7vD8P~nEt?4<5}BU7*iy%uKtvgWlS!NNk-qXX=|Lz2B>Yi5X! z4~F`8kA*}AdRxgm@oCHyPOpoP%tnZhPl$Xe+M!wasQO;z?8juBDh4*IXRapJP;3hb zJGb~hiq89=>i3P~$KHF-jEIBdoMT7X^B{Zgy>o1lY{%XlBN^e?n}d>Z5RMe5tdlr6 z)v1&uqw@Ls{s-^J`-l5}+}HJbJ)ir}9sbVt=G<&|4!KEsdEz?JhS3so%R zeJ6~b?>s=ACnjNdg&oCYLyE?fvT_QQMnp z{V4y>jCG_SxPoV34#iFQ-oIIX8&yaofUX$~(C(b%{1G69fn;_P>8M^t({`=; zX-wQh1HU;F6a|L(!W=@L5FGM$>Ye6-{3~|*YfaaGVVkA_5vqMk0d;(cM~F7*a1GO4 zD{Z~_GVT!`ohIwot$0=i#03LV-S5>t+e|V67zqxOTSF$F6X_u>Qc@SG{{i?UxbM~v zZb&#|UVY9lPh8wCC-Ot8aTBpJ{o#J{vi4TL-G|j%O3|T_dHVgw536hVo-!5u$nOmcPmfZ2WZ7S{%Mh=_sO_qaHL{o(a8dYh9Du6yv5O|VwZ#Igs zZJYucJ%*UK``({gjO(||PlqH3mh8+MLwANAs`?s*HRMvwtby1OD|A8we)ZEY_m()s z=+H&wCMnaVtf@?GuhU0<>HCI(qkr_TO4m|xyMHRlN!FovyQTSQX}2p`W9E_VXs$W- z=x*n;7DeYhoQsSsvh=R09tr``9XQMp`U z{CKZ=Zv~4cV0wmmJkdkqZ3KSBui;wrEE^noo)RP1o1(sj2`<4TF9Pn8@tPxLidxUY zX%!uWa9s{fgC3&6TY7*^SD2Sp&3DB`# zmJ)3raxXm`+RJzP@1ke>0254hc|m9Npkow^kvb!B55i(*FBog33h-yBvWP3qWWu2)mbIBS@YZ+f4$NFRRxzIC| zBn9v|kSyO^O(egPAV(zB_oybD0FJS0dq|P(hri8JPH#gj29PeYi+9hk)XipU`O1Du zeN$>GNd%1Ja2rBve8!rC{?TVCAml$lkgZ;DM2U@<8q4y$QS20SU>UOUuYcn8ABd2c!z?y zYqw^{YFBY&z_dKk<(e2Rs|NhP^N&`?rtm{~Uq4@HA%{}5jC7_rA?qf;PX5wwL-Em) z>Wn4+W2p6IzHl?ME%o~+=FiMN#mnzeigq766x508JNUg+USUg72g!`m-D^WXP~c`j z_Ez3_iR1FI$>Z0g@`CaBc?|=PQ>z2ZxScbr%+%5{0y83`dsxXj7wyJ~;*M_DYnjU1 zw;M8YZ7(YO{{!HueZP)A=z&l&)+#LM8?xWyk#A1=NWRJU!7m~$VPggiVo~_?Ad>#l zAW|-dK}aB%QHcQPrMP*U%092>uj#6vygOXr__78;083wp3a+}9_!hZ|S!O$+9vDJD z6_N9cqtv4qwb;UY9-T_C!%t}CUk=L(s4(>ia%)`^aW4I7vuA_I$LyITr7OAL zn^y3zzG9v2zSRt%7jnh)-teuuv%-*iI6Vs+acbKNonUtm;i9w!pWgoTa<{$RT0CCj zIXI}<=yN(}wc(RvCSA)PLZsaWmwAh;h0A+H75pK>>v2-6@k8QmB0Zc1&$!4F0OwG+ znUF~gyk1#wFzYS5iI2A#oZ(FT0&5>_Be+##Bf@-gceUXPzRi z5}@3JL+_$2TI?8u!at&r9hSccfcbl)3-;1#ZKgaCN*Cgt6*dbdYF_Uvc9bZoO}8+% zTHe-oP5L?&EKF)f7lW=mDrMx=+q9B}|7yS1L@Tc7wJ*1I5k9gLvojkY`kL^raR^PD zwooB>HGFwASCQ1@cmfc|^JUI998>F>HyNiqN0?MD_AP)`o69p>LD?nI{7p}A)&)!b z+`N*3Z*A_@q@C7^Jrf#HU*p@KVH%7CjlUkdDUSYMR)FxU#D>*aTQZ zWf(bkM43{$&70nKrZlm!^iu7VuWfxVi<*U5fPN|Co zUa9b8hlI5=dl0KUs9#Iy0Oy{tij}>y4tY>mCuG8%Mh+b;r&YgV-)!N1HUsz65zOw| zXD3n>xaf!@+PKlGl1QOw`|}i&k6iNg>PETbk2C9$Gah5vQxjrr-k!%~mbNF)mLe|l zUvlAm-Q-k1Vgn}4qd{tnamG$~o;CTmYq8e}Lk_N?);2ANpU2$z6%MKQkH+ZZW^mKD zXY^21ef@y))(da{=^(EWQ+((ME1)^#4s?)mt}12)H+e!Nmz(&QV;?EWm1rVLM+~N& zzuXAkgMJbU~N(m99=Lv{p!* zXw%G{6f_qG3tC&&;S zvP!KE8i$k{3Q7@ON(xFD#u3e^K6OF^e#E@sGYSo*8G^%cwK znRjV;EA*TXy{AQmDS=YLYqX4H zrC#G0t~!gYk@SwX`U|s+bws{AV|%cUBD>e6AYu~DnMnYa@deOnms-sX#^n?u+K#~w zW7T7^W*1cw!N^@(KcfL@vC%5lg=2wM_FBCuiHIRaHB@Zn;2ytJbzaE5Xlf?kxG7or zuT`GaC37VgPpLK^dUJjB9Ls#_X#-h^Y9cCl8L`h6g*;*(vJhPCk;%VfnoB!iO#b!` ztjG%&rQYWHTD|%U!9h@O^RH9`npBy2g96=$4LyDl&O-pM+{akLmt+3v>=3o`&HUv5 z8iwe%`sn*UH)#B#Wc8)y4AQi+>q7%wuAMp(-$au-d^%d;(n9yP+|hN&ZKr-ep0kLh z1#ir6_C*$joEPEZy%%LI|0?827uoIy<^Hd)s!AF(!1Ap}lul=q3T>2ntgDjD!`~^{ z>&^`(os(0yHB)@0h7Kxp@vEcyem399O~10;Gl(|TZ@M%g8PhiXEYR5=ujrhcxA5SJ zz-~mwMrrlIK39BZ-gHU#3wpC6#VV3p^$gdl?dUv1Dd?!P$Nx74X`^Wzu~(}vViA7T zBun1aDNZR(k(;AUpF{|$(_3v|9-{9g%SvkI>)2zSp>%t#Yq3FR_3HAky=wV+X8#e# z&BJS>DL-5~*c1jfmq}k{^2a$JiO|#qF=ofWw)y6>EVoJf4kMO6x4xO$onP&mK4HVk z_E_Y(E?=5k{}7jTxfL?aSquA<;@fijVJY~E_~W8n@#HR2Kro@q^daVZq{xwL$ckkR z+l)#8{b(D^pH)mvl7b~N8sg%RhJ6)F#ebh5idEq;u38W>qUPL^ zyEvem>_s76*@N_1kk`;&vIX=tY+|(lSCp`sy=YePOh!xfE|)k4Y3FFNn8c>0K%x~& zB{XJIih)}4eb7+T({-XB^dhqt-wn+grS4jfpZtbD}R7bf=q z1N2pS!x?X6rx{y(`gTG&e7C6~x+=8TPICIIpSKd3NB-i;fDidTW00GAww|&f?4RC? zmJFTFAnOMbn?$k41ggqQL>{ZB4{MtE?bKo!9Cg1VMm;~gpd>f@>F}kgnTT#t{-lGx zPb(_*!1vSR2RS9+G_7H5{>&HGv$ZpTTGnoSuL{d~v^;f=?x zaC&d*`Rt}0MDA^DH=B}7N(aUIdg;AvET7e11FNI^7#UsxHIQ3cr^cDEe#9@B*w@8C z9tG@Se(thKe493QGD@(&%?tWD*1HFz9 z6|^H7!&39tkO?+g721PD!5eZLFh_f^LcD3_+Ya7*pFpt(zDPx6R%>%5Q-G~I#KyTb z$@k9V>Fw6++A+24k|Eilr2WA-?#uk<#w_-o&0+_T2W`H)X>&r5is9(2r)`z)d$UfL z%w6&>>o~8XFGF7Tkpwv#r)81ip5;`*E!zmZFKh#Paob3Yl?b5M>-i zkym6jg}N^u>Jn1`ZxM#6spo~8ac;2{mNG+?K7GSe8MDDcV&I5#z z5#%Q09Bk^3dEWvEoGtd)1P0aYMR4Qc>I+nVrPaF?%q!s*qsce@OcRN4?nK-aw!S2< z-DfI>h+wH}Yp((oPxJaP7)1U|^&*eH zE4_cmLcCg>xsPg96lzV?_8^5%wmp_JY{{g8NoYf;y{SuE1&($L@ zEs_KQo>6M;#6JGJR7pGbl2Jq)jeDn8rXD0VK0Ob{uj;ojoEF?*qpf{)BRdr?o1%RL z`Re&J$U&w>V5B9Is|#BWTUPRM6V0+*p$zVs*7bgYmLAWe3pL~`R9Mmhl4+ltIs~d3 z{wkwc$T~p1`wwvEPaU=9DK|~qm)}Fecf#KMy$76f==zv+h_K(Qko)5SHM=M$*r2 z&Y{% zwy5AWW&6J{G6QI*U+0LU7>`TOm0nAYo5vT+0IDZ=`W8}wDl*!scG1HgY4BdgQ4?YF zmQzLuZ}kDOC78$X%0WS9oV;E`y%MdLg6?End63#cW8noHO1!QurvgLXe!>szYPH@z z5|K`rM}+EJ2ZCfgcUt*eCjW(ftns0BoRA3pai(7Fr>sC`^{o?GbNey-td{%WkglM% z>D#cqAmJtf{dFniln<~k1p)#|vLHu0Iu28#6SX)&AP4P>^0b3Re&*0}*4RwCsMg|~ zcMo(&1Aga}LgTWP3qu&2>#STu+3;4KWU?KdNgKEhv^n&YUNeX2)KAGTV8B=)+qQUo zB&9jXX-nj*JPK-ms$Qcjj+-5@pne-s7T{v%jJRWN$HFk$<+*Scr}7uuBJiP z3ojyMgI+(|@!KEGQ&wTxh%BM&TR`x;IdpaHNR)o!cu8dF2Z4Yt<;ZW$>2oe)1L0l; z@yL+oYXZixY#v^|h=fn34X$+r<8H&u&RV&;>HHFM%i&`B(cpNik{- z^M>^qMk)!9dDDRmdj*)9euC?qEMsz7Dhg`C~R|k3sQYi3Q$sna%5reI?e1O3l&0W{l@rZUhsZtJ@N4 z56P!vf*fj{p)^Wz-MwYSHY&44BYu)AR;w?v2ULV4I9OOd=TR`wA`0yjyh4fl@F}UC#b_LAU{Kjr_~p%w#9w40r+1j<-0gf z?_zvR;d_MQsLOduu~SAozQ4bG;K{K-Y>`L8JVpudL3aF%#>eK|bMOdwTrdq(slh15 z)xm0-367w)CxRebXsyKD0tDdb=)q1;+#j!q_`4|54D%Utv-2(SU7duKXIg%0F!$7} zU4XQ2su}T}@QNUq^h@<8f!&wY`9zNqIps7Gn@i)h!U98M!g&X(RT*ayHSv*4Vq;jO z$Hvk1-cB_aSi$xL4H0l|X9l$+z2;TXo-#)qDI>T%m5D5hzY`=DjX zuHwkv^LfS^70}$raNFU=WoKz-qM1B`qOZzaB2qfqYLZ5baSBFd_0ISK>jqvE8@9+( z;@A6&#;Q4RFc$Lfnk*_c`?Ifq$ZFoe=jGB;iZNT?i4q@UP2!SMZ;fhRy~%or-SWF{ z;`PsOmko~8z7qPXZDjKd!?CcX9b}%#Md|;wGVs**D>ZK3jV5n~KYiHpYd1)qYEF-LR&=DmfTfEn=mEeqc?qWxX=OJ-k$+%YQr#i$Or zK+G@oy(P7DTEmh+GVgRN&W_U}Fx%sPK|@RTDSHh;CAvdgK7CxZ@&()KYox)#VvDKN zx0J<+CK151Gcvn6&nKA1*X?f&+GNTxJo1ll{c%+ah>iExGb9y0C4nXk4ja7Vcg)3X zDUVyMdch`C4bKi><<09DsPhcl6PBPFQGj%i0<+}9a{{VKGSvSTbN)5y&&DAlZNlQZ zu=-Pwj=6p1?IZ4x7Z_iogKhQ|0(XdA1y>`N{HS&fvMD>MCjD9__v&hQ33i*;~G2p>YCf6P(rk%Xok&$^% z8vQpkmGw?F%Mp!jMP#f0UA@DsJmFV_?&amSCM4Tkx^!0;l|4K&8~iFoG2*@bc^SB! z{oj#A?$RC|vVSSY@zae>;2`t6q)ZX9(XjoU2qyE9A11s`M&TE!Okq9zqU*|TMyq4v zuV`ar`S;2ou}3cUo2q24;6z3BOdD}-E(P6zA5%6|9uUJUHnzc}mr}~gf-aI`uid_u zxm4ex3s%3yNwj3!D)|pUaiN!}Hmb#?sNVKUFj{_Zm?q96)=ExH=mKWmHPxk+F@|oQ zZ>M{6LM3dm8D3=2;g&>hmT1 zwc6g6mN4m3b&p;eL-2N5g(iJ8e_2rDszPs7a)7+%OU%aM5f|9tbou{ww(HVaYHW)bLzev?6(rzy( z0G=1n`lPt7UoR7{#6Ixl3+~l5RD|Iwi3W$F^lD`^7Ei)04iD?vW?9qqg|Nj#FpRB} zOjbA`_!{pu-0sqfY=VpuZzk&V#e;nGehSp!r%3gkqhb>5R<7>ZW%KCYr0Ps-6st2W z`QIg{_^NWk-dda|T%@JMVMoUaM`W#$2II3#`D%QDvlIZ}KovYj&xzX8M3ZbYX%MT2Q)KPXZWFq-3jphpzTvnyAXM)SN4N6h6IgQ|BaPtg8tI5c97V~I} zZYlfcUCB^QYojn;y;bmBO)`@TUg~q?Xf1<}EPLwVPs;2>5zd-pZv7X~V*3_ZKCCOz zLSvRck_$G>9OMfrxq(F~!GrtR)z9Bmsej5;Z-ORbzF$`Ho52wpW(r4}H6~B(ha`QPNa6TsRNADNqiUo2=%c@6?N8 zPT8v^!rQthd3{-0yjZ$}7+MLA&(Z~jGSB%1+$?$)yv{pk{ z{J0Q9+@lHhKZ`ya(L|4_@~QTA!X3?U;uW8E)o`q);~sSo=h6>!o!?$+eCmB{C&LYh z&t+zp^@2RtxiYSQ9v-BM&!y@1yIkQ=zV&=*9;vLic9RJ_hnzN}?G|)CyDQS?>0EZv zL~GI$(Orn|jDN0Qen4|{zng#Oa_TS9>6tQG|s(MlpKhU7+g#7fU^Gik?v zWb8*7S*R8P=GWGS*(FmR=gVvXxkKzI#jybU;2phn-U16U6KNWBl)h|=C@&bHdQBeYZfv>Jl9Wqg2))T?#9yN(%3U#Qqfh&$9j$~svEl%x%hNs@*6CNe}`cdmk-f$tw@iW))=OVuO|eUWaGupmbTH9nBU z3}PTp=}gE_mep^+yX9dFC!3Xh=IY@Ff$X_yN%&&^=%-|XW};e+J4t-;`6BskkCutr zrH(P)aCGPNXO0=&xJ>w%K$j=E2OHm<71O;<0fFM8! zDz)4^adzkHj1mm36FPpLx7ZIS=ayrpRq~^Z^E=*Bn1L`S7uPh=?z)I-uP?48|{yCB8MDdO=XXvf<{{kff(Wkc@X=u3a}c>P(G#rif| zI|aO+yh8H))=64Ra(u1WqlTlk>nw}$vTE!hg#Yd_5h|!pc zhxh~2%X|yf`Y7h%B~Ae#}{z+W~)YzY|HJ>`%}g0^GMO;V!WLJMXn@{p?nGu0+1@ z2*ar)hD|iE^Ltwq37KppvToLaJk5Qs??BHUYRlEVZ)tTNtG8IUBEraYs;c4+0D zRRis2znkHIybs_wdW{3LGWj5{n4vv~#5%Gk+~Sz0J!Oqb(lajC?UZ~WtI9UMV9_2k z21m5@u#wqt)~e^L3~7B?|Xxoykpj65954X;jz51g22rc^gHh#EhomvS96g_AY~AJ zclea&Tw`@1CXVrTm1g?7oLEwUk<<_i z(tF{E3ryEgCa^%1Z-Pvq(5FS@FLUwNXi0?wZP7{;ir`VF#6xGAQ2Y3lcI`1%uhKt+ zd}!S6%ES7=+^dls-|uXbP*D} zlj}!7*IdtpSg$hmoEi&Cl3AK4aMxjTd2v<-fy_98OI_oHyV6Vze>pEdHEOBeWDe0? zrAa^LczO?+MT3tNnAfs3WV+h-%0iQFoFiqyR>hnVNfJaW0R-bM_yIH5pZxb%EjF2c zfv+0so}@$6vP3CvS*z}-_^jN7bCTFRp)4H0C0k9aGsOwI$77z4;qtR{=as?_=jq{$ zAfWzixjvahzF%OaW9<@sEH#$k!_L6%S_*GqbR;5KLlgiL)VorBrkv^oYe8zhM*)gW zyt6KwByo{wddh$!@;-VeA>w6+mMmd9NKTd2T~vND;N5K;3R;@9fHl9`x% z5w#;gN*q}YEIOy|tNOBg_)ri>B<{Owx2L=R@mKbcWsU7~;bT~i_#S=5o~|o| zs41FG37DNSG$iVcE4UpkB*UiU6Sd^A&R48=5(#v% zf4K}CoTbqe+Y;`uafJU^G~W||z>=(Px(dlJuyc{_$E{&^uC>?Ua2g|&4}Si?;R#^lg7=otLl z-+m6K(#Khb{;66#!C1{Qj&~%o+9Od~`8GWk8^84v?ur(5R5}R1x;5Pzt~`913Os7? z>ej=zERKY)d5s^5k`)|USr8jPH6I*-yb817l|tG93{MoiXEHgI+z!uCzLo5Pd%Hv% zCST}4h{=Wm#DjTnarO+O;>tql5uUXz+pM10Crz}Mlt{DYhD4fqlr^#EYmrcu)QybT zs`L-;qZ9R0=w!J^0ZKnaua}rcr&O75zPMh=vk@U}KX7{}IilN$u-CHMFy}{0Yn~H1 ztIwHx`?3afNfL715C)m-Er)BGON(9vv&Sf%YjL@13a9jfWv5-8xMS^6BU1qA8p8(S z>-O8*VYhJBCI-EEZnNg>*>l2k!@3V#g+xxknM5^lX5dWgiCd6{{8-XH8xQpHb;#Sa zre!sh6uD76g=35RQBlpuFX6wPQs|YFCfK zY)@E~N?b$r6I={ekWFAGzLoWjrS|9WBodPiLgS`T-qSnx-jVOV*Xm|n!@W@`{95pm zG=Obn#BaIABa*jKtit>#X=sk(v-vjVuz=z_MWlMcvBJsQW)Vr^HuHEsJ9S5AuIsMA z2&a%O_{}R3dsYhom3o29xOx>dT|X$3^%*u_wNMW*A;QGi>|(p?(fQM0@&rFnCsA;? zmS;^1i_z!6ZqaVJSEUf@<#A>Pr28(XLiXDVCUDHF!tW%F@_a8_q43!(w992KolHN; zC5DSAwrFn181sWhPw`Y|lMx+Q{W#;HCBUe^Dbw&$OIRr z=6kYUq&^xVuyX`LQ1C^>&WBOAj3Cgq z#)uj!l|AF|rA2Q~ z?Y%WHcUbZw^GwQo-s<3$E!$VSapRZ@n;$o60cB$Y-JaI*|IB77mKQl|RB#f2_x>0( zwPtp}$I+Q57WD~*n15JcVA-Gs5>4j7Yf^tA_{-JAFw}+hX*}2O6t0I)KBX}{MqJ+F zUYc}2rrHZ5%q@~) zZ1+msEZ|HUP`@OFBT<^ z-a^JEuO|v*vzMtFRF35oFdzJje+6r0!c>B1ED{|{+YHQG`B}Y7wV_g%HR?gOl8aTE zj1li1T)%egV4KH!CA#rF3bb=!{$Y$*=ZvG#-0v+Kju;DT9{iX$iCIJc8s26xT{Rdc z)p%sr>Z)&IFp%AFqu@~2PMT`oe!}Bm{1nUOj1nx~1D;QKc7qS*BkRVF7~?YRu=Cz_ zGiw4-&vzsSiOi5wA%^DMvcaCJP&+}lRz1@^Sj!X3q~-`+80}X-6`weGRT%7Pfu!5_ z@S#?3XbN*+P0BZ}E2-}Fy_61F1C~hs<9qPsLR2%aMbVmq-ITQmERtmaLd#uDongrm zp5GoZz}`7+U<4f)^ZfE}^40>0$ZYWIA`hp@C5(rqzZE=IO%{+ZuI;h>$tL}5hEc!T zi+fOo;NzJ$-7({X;ejrVhmyqWZFj+m+Ti}Lf9@ZPb0yA<9P^G?p@$9exr64G(~?y|V35irWI?>V#wzrTV0P5U?)IJ}Zgkhr9HKWwe5s?R@IbQsJF@UsDy2!-{>Fa9 z(tLJrjTguDL8P7X2QefS$?voW-;$d3(uC|p>Axb{oH8EShmd=RTazsIndX2W**M;m zX)NZOY0yqK0RMsQW=|RFl;q4oK|=G4_hboxxl*!^*?m*nGH=+>h1RTL$Mi3-zK7#A zwa~GSYNS!o4#>B?eky#hv0K$>6b0y6NdAbBvl_L&VpBev7d{8=!vbG`Q+s8O&Ins+2A_#lm1TgxRFqkHT|e(p1HS~j6&5ZsCMbu3DhwfqeTFI{cxXs%jZ1b z`$?oA;OCOX2g{JCf3sp=4QFUQqLa9<2$5JAWx@UjMlUD4!-JGq+N4jt@rBex3-|{@ z*8(C?xTXwYISPOJbIEMDv0XY^@=a8;y_^2c7&u3~q}f1izf7{((j*<0TT@nsnYlTU z1(6nt9$()AIs6czc^!y?x@)jhc~Y`x65phy6{WeB~DqzKquwPEU$|ZcQ7T(wsUSkbFY_^chRbB zsMKA`wpfG>036Ir=h3w}^8qa#G-?mFa$S8s4fyJ}Pp%dvy87mz_qNC4+rr=34|#-3 zeggT@DF($l7{hkWANuBAjTM^=dSSFwwMANXL6z(&A&rhTApcoI28?!4O|}avOZ9pc zyLD6_&^a2wkXd;|*VmWIPb*?dIpjuhVTw%Q^rbr~WYaQ~eUDPZZ*iup5UhoFuMrVJ z3W6Bom1Ogv&U^Ota(i(SFcdbNzjEz zxx^IVWK$3$hup3$flanIGCdkMpd}q(|Gokp5_Rr+xYJPBuJpa@+8_CbeI!+ky&wkl zd@{cyM>0X=uq_TmbJL%U%jHiMchN_*V>3bKarlbRBa3)1(a$7cl_2vW%||SOIX=x` z_OIzT@F}HYR@Hk%4#1xWBt7y)xBxnUg?Vjy)f38EEBDGKpJi6yGCAgPOpZrOe;$Lp z*|_DaqvkQ9P4Poj5^F?0JrJFULR!SZqw*<5f4pxmmbD`D;j7<;9P0PbV{fRh%T24c z6>NcN6|A2ch{Ay!4pqx7DUO6g{c(Pu)EG2{w2PzToaIxsNXH~mPFGU%ZY3EX+&5ZC zgfQfoCOba%aM{bnGeI(>G36f;dIr09M8=A|NAmi;^Zm-R`mvQ*kmYpGCf_Yyts6f2 z+$S7>`cs;oQ^R5ZoE$(C7)JjH3k3i@l73RGG)D7Cj=zlbY4!o8Vh8+6)BGNoBqz9Gd)86Egsz;{dYe50m_$m zO-({Arm@dv#X?CT5jH`UYgSG44k8cTq>(9I`lsK!BO2m=Ss7|A@NTc}_~`zsoSLY- zyy(};sD_Z|u60d$E2fGY%6JKXi6cMb+PhvHDgR)KUc#34?w0a-*N6$b>M3U7+PI+MRHUkZ1tbEUuqw^WiPv+}Sw+OOIpLLc<4j7)A4Sy}XQ@A}E4RB?APJmN?6-d#3Y0cox zXK+tp&te?7U+oVPlT;JO?&y_)Vph;;W8yWLrj^XJIx@kipc?WI#jmopLyIge~hm9ED?oE=U)1&3*Z zWt`O2r_UD$+rlx*uEr^`bOvF?<)oL_p23>Tzi?{1wp_tXQS*Aez|lk(`8vND?966b z1^#YBV8lbcdBo#&v{`kU64k?drUQu)wE9p)^BB_AkVaf@wmBCJKK zY`R`K7O-mam+{0J;AFm*w^VW06eeqS%HEZQd37DqKPP!^K3v>HJ(HoNx_~`Z4~x5r z1wUTQr@q@LAamEZe8?PV!R(HLhbBnq9aQjJ9l7S?J-U@h7J(b21|j=Vw;%^L=^a`$ zed>+2l2@MJ>Ef1`|9JR0Qb1%N0>|pNYcuzNi8J_9)_ByL_?%yxRWUAOIj@hw_K?HZ zi;@gJamzL@?-*L#$IRR@=wWp6a)_7kzs&qLj}TK&SuS-Arh%p5FX)%l5SK&Q9yGVLE5_%HV?|^+nh07O$mbN9WWxO+;F0M7M#%8}{4O@u_9; z$c(wkqlzi{~Lg+D{&PDC?M^jlgw*pD0)UQjVTLF5f@UXZJo!QT> z1d&OJRgpEJoIDAkuha|J_~^RoSs@JJ&oSTuN{a+#|@w)ym~#7c6Uueil>^*fcwv zA*f;%{vM`57n@oqA-1TXH!z!vp4^~{q*6`tjZmtKtJM7$#?e^RAhWZpcz2IOIsVyn zLlZ)}FUfc93S;*S#xHor_73+E-Mh$uih1~hTVHiT!Z$bt&!`t6h7CUe{s-7iwJgi7 zIi+oW@E?FtUS<8f5o=$b?nrfm4o$Og`lVA`g0TMnV4KOSm_E)J{y*H*yb~FS@}a4Jl>4W0zrS9vU{h`rnlH z4C%N$U_EmIe}#iRkAZMQFmaIq^UrgE1`750(?wDjdE*^?}7+ip_ z!q63 zBL2aPYQ9^ow;&b;59$_Q-br1E(Zqxnf5=9}OU??4-4qYb2-VW*(0^~!SjB07y}H6i zf<`DSJ??sTG-JPMFjTgo_2eFC%s+5tKC-pwPEn8okXil}9X(>LAd|S|a|4fQY_eyS z7^5#ZoZ2pYn|!tV4hMurhqWHYObwj#^~_bcZ`9nv99j{MeQik_P_q z)a<;k$*(epcb0B~%j4yzG_EHWYZN@A#r|ApGD~+bOJJ?983i6mdojVdwSU^a#our< zg8DH8rrkda=0I((coUvXdb$=j?ETxH`&Y-g6pQU9S$JQgnhfN!f=iI{bhNXy+v zKA_gyzoFL&b(2^hkf@YW`-sLpW!gh+J{6BxXOa%{%m2>0p=8l&Nqt7EoAUT!KP2Rc zWo~%@Y^Rp7<8j@VX2mlk4xL9&d{lkj7p*uNlRqUiS9G=OETaU5d8rf56gzba+2&DE z=Qh1*u~O!lW94Smaaj#_6#oN!y>A0C9d6I$=(h}w%bE*gvW_S`HtT){TQ~)?SfSy_ z&reYJAkjS5R#lOa=(l*p{sJv8u+_ln0-am+LrL#J9K+lC0?+ zNuKfmi%JJwlu^{JTU7F;P*WPxDZndAtd$v=X7l~X81y* zIEV%_2vllwilAwWqmD}^3xJ0k@Ml>dY^BIIfesZ|TTkgJCRy5!SPF8<1yf7ql>(L$ zj>EjlVUf1@kc(Dm{yU>A-qe+0@JBsEUph{inY&F?CzKES*G~Wx$n{9zG%IBZEX=g)7V3tBzFVuv{hOKjYXZM4E1->f za^&(BJCu_@gvgd2eF|Oz959MSJ&j8P9Wt+A{?S4cwOfJsDXj#WHMaym^FQsfjJNj21BIN+^&{e7zVfxa0X_ z5~O`iM9fOM>x~ry^hOr zeU$*4E8eQ+fc<}cQ9gV0|5kQ~b_GZG!1{T|-uFK#%@==Q?Fx?4Jb|YD4F8kiOoOCb z`{^h5B=-_2axHhfOlvglLSLp#{%zx=N*HsR;_XoQoOAqKa3dU-@|@y0pP26@@Oswr z-my%c>#vEX`d=bK?GHJjhzFfsNdV1MiI%cW{W+VVfrFZrB+UhRr{~kD?iI5pF|t}; z#rZP$eMjXqEu3!QEbrYhY4>$1X9)1xx3(EL97m?K`;}X0K-=OU>Ipu9*iZk}0v*qw zbTodL2K>{y#avF2ELbE5amP^un>n~&YH8viS>W3!`)n(L6tFigK`>Tkl}J8&(9%r4 zJR$O0EX($h!c;WpvlE$n&^mc%dUPtV+~ z$~F8LB(J$R7Csfv`uySW@V4Q|pVG6_dWrfT$8EC}^d{Tp#40=se?`W@O*zTs2bpV= zX)Iy#AwQW`Z9h7vOw_D^1uA5mYAFKiJnl)Gn8_{xGwBzoQU;`y3*q_v&&EI;rXi~1 zD4eIWEzV@><*cx@s%&{Nb@h?Nixe)@H&Q+5S@>io4%ebn8fnR|({L>*nM)tKhQ^mQ?`Nl^x zf15VB#njCLht(wN_D;N}2??5OZkycXC$uO?MRk-Z6oK}HtMT#G67P;eKCoK0SN7Xe z)6Py;eLv%!BKii&MpG*FCZm7r@U0wMb9Z8s_8w%>Ehu!^CP^I7;k#s_dqY$NlpFHp z{Q3V!(Rs$R)xL3@nzdu^S!zqfuGStkWA7CbHHuKRs&>R~)ksjQMy%E-qBgNZAEYg9 zT0}*gwp#Tl+VcGKe|uh>7w2=IbD#UVe%JR~ZZ9Ckxew@lUA^VjKrUt9b+S-SX~zBG!e0E!T1bD=v

|ewukd?X8G-j3+J%p~8bPYD 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�BTVN+>$5lLH5TPq0>bd=2=>SI!`1Uzw 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≪ns8C9kiwP##vX#)JOKF!>h3s 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 T6NW%{2`@^)gkr%xzX}J=V~kGe;@mA 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 z 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 literal 0 HcmV?d00001 From 838e1c26166d263ed3de2e2e7492fe8b1f0818ed Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 4 Oct 2026 13:04:52 +0200 Subject: [PATCH 07/15] i3status-rust: the bars as a module, claiming node-bar (hq ADR 0208) Owns both bars and their icons, the bar blocks as an i3 drop-in; the battery, GPU and headset blocks leave (hardware and a person's devices), the weather needs no key; the update count and the bar watchdog become module code, the watchdog started once per session. Go tools reload, blocks, block-run and themes. --- modules/i3status-rust/README.md | 86 ++++ .../cmd/i3status-rust-tools/args.go | 97 ++++ .../cmd/i3status-rust-tools/bar.go | 306 +++++++++++++ .../cmd/i3status-rust-tools/bar_test.go | 141 ++++++ .../cmd/i3status-rust-tools/main.go | 81 ++++ .../manifest_helpers_test.go | 175 ++++++++ .../cmd/i3status-rust-tools/manifest_test.go | 71 +++ .../cmd/i3status-rust-tools/session.go | 423 ++++++++++++++++++ .../cmd/i3status-rust-tools/session_test.go | 174 +++++++ .../i3status-rust/files/bin/i3bar-watchdog | 64 +++ .../i3status-rust/files/bin/i3status-updates | 63 +++ modules/i3status-rust/files/bottom-bar.toml | 100 +++++ .../files/i3/60-i3status-rust.conf | 34 ++ .../files/icons/custom-icons.toml | 135 ++++++ modules/i3status-rust/files/top-bar.toml | 33 ++ modules/i3status-rust/go.mod | 5 + modules/i3status-rust/go.sum | 2 + modules/i3status-rust/module.json | 118 +++++ 18 files changed, 2108 insertions(+) create mode 100644 modules/i3status-rust/README.md create mode 100644 modules/i3status-rust/cmd/i3status-rust-tools/args.go create mode 100644 modules/i3status-rust/cmd/i3status-rust-tools/bar.go create mode 100644 modules/i3status-rust/cmd/i3status-rust-tools/bar_test.go create mode 100644 modules/i3status-rust/cmd/i3status-rust-tools/main.go create mode 100644 modules/i3status-rust/cmd/i3status-rust-tools/manifest_helpers_test.go create mode 100644 modules/i3status-rust/cmd/i3status-rust-tools/manifest_test.go create mode 100644 modules/i3status-rust/cmd/i3status-rust-tools/session.go create mode 100644 modules/i3status-rust/cmd/i3status-rust-tools/session_test.go create mode 100755 modules/i3status-rust/files/bin/i3bar-watchdog create mode 100755 modules/i3status-rust/files/bin/i3status-updates create mode 100644 modules/i3status-rust/files/bottom-bar.toml create mode 100644 modules/i3status-rust/files/i3/60-i3status-rust.conf create mode 100644 modules/i3status-rust/files/icons/custom-icons.toml create mode 100644 modules/i3status-rust/files/top-bar.toml create mode 100644 modules/i3status-rust/go.mod create mode 100644 modules/i3status-rust/go.sum create mode 100644 modules/i3status-rust/module.json diff --git a/modules/i3status-rust/README.md b/modules/i3status-rust/README.md new file mode 100644 index 0000000..6759d3c --- /dev/null +++ b/modules/i3status-rust/README.md @@ -0,0 +1,86 @@ +# i3status-rust + +The bars as a module (novox/hq ADR 0208, research 026/05). + +- Installs `i3status-rust`, and `pacman-contrib` for `checkupdates`, which the update block uses. + Claims the mesh's `node-bar` seat (no verbs yet, ADR 0208 §2). Requires `x11-display` on its own + machine: its bars are i3bar's. +- Owns `~/.config/i3status-rust/`, both bars (`top-bar.toml`, `bottom-bar.toml`) and their icon set + (`icons/custom-icons.toml`). +- Places the two `bar { }` blocks as its own i3 drop-in, `~/.config/i3/config.d/60-i3status-rust.conf`: + - the bottom bar shows the machine; + - the top bar shows the focused window and the tray, on the primary output. +- Places two programs in `~/.local/bin`: + - `i3status-updates`, the pending-updates block; + - `i3bar-watchdog`, which brings back a bar that died. +- Starts the watchdog once per session, from the session's start (the `xinitrc` slot `normal`). It ends + with the session's own process. + +## Tools + +| tool | does | +|---|---| +| `i3status_rust_reload` | the running bars re-read their files (i3status-rs restarts in place) | +| `i3status_rust_blocks` | each bar's blocks in order, kind and settings, and what each shows now (one run of the bar) | +| `i3status_rust_block_run` | one block alone, with the bar's theme and icons, to see what it shows or why it errors | +| `i3status_rust_themes` | the themes on the machine and the one each bar uses | + +## The battery, and what else was left out + +A bar block that follows one machine's hardware is that machine model's hardware module's (ADR 0208 +§1), so the bottom bar here has none: + +- **the battery,** which only the laptop has; +- **the GPU,** which was the laptop's AMD block, commented out for NVIDIA on the desktop; +- **three Bluetooth headsets** by hardware address: one person's devices, not the bar's. + +i3status-rust reads no drop-in directory, and ADR 0208's slots cover `xinitrc` and `xresources` only, +so a hardware module has no way into this file yet. Two ways forward, for the operator to choose: + +1. **Give the bar a slot.** A `shell`-style contribution `for: i3status-rust` would let the laptop's + hardware module add its battery block. That is a decision record of its own, extending ADR 0208 §4. +2. **Blocks that show only where they apply.** i3status-rust's common `if_command` option (for + example `test -d /sys/class/power_supply/BAT0`) hides a block on a machine without the hardware. + That is "say it by what is there" (ADR 0112), but the knowledge stays in the bar. + +Until one of them is chosen, **the laptop's bar shows no battery** once this module is assigned. + +## What it improves on what was found + +- **The weather needs no key.** The found block used a weather service with an API key written in + plain text in the file, and a fixed city. It now uses the Norwegian Meteorological Institute, which + needs no key, located automatically. +- **The update count is the module's own,** adopted from the operator's `~/scripts/pkg-updates`. It + counts AUR updates only where an AUR helper is installed. Clicking it lists the updates in the + launcher's menu, instead of a theme from a cloned theme repository. +- **The faces** are JetBrains Mono Nerd Font, not Hack. +- **The watchdog is no longer a hand-enabled user unit** that ran on one workstation and not the + other. It runs on both, once per session, and ends with the session. +- The docker block's click, which ran a program installed on neither machine, is gone. + +## What it leaves as found + +- `~/.config/i3status-rust/scripts/` (a mouse battery script for one device). +- `~/scripts/pkg-updates` and `~/scripts/i3-bar-watchdog`, replaced here. +- The user unit `~/.config/systemd/user/i3-bar-watchdog.service` and its enablement link. + +## Migration (ADR 0182) + +1. **Revoke the weather API key** that was in the found `bottom-bar.toml`. It sat in plain text on + both workstations. The first push keeps the found file once and then writes the module's, which + has no key. +2. Before the first push, on the laptop: `systemctl --user disable --now i3-bar-watchdog.service`. + Otherwise two watchdogs run. Then delete the unit file, `~/scripts/i3-bar-watchdog` and + `~/scripts/pkg-updates`. +3. Until the `i3` module carries the main configuration, the found `~/.config/i3/config` still has its + own two `bar { }` blocks, and i3 shows four bars. The `i3` module's configuration has none. + +## Blockers + +- `node-bar`, `x11-display` and the `xinitrc` slot are ADR 0208's. Until the controller knows them, + `mctl` reads them as unknown. +- The battery block waits for one of the two ways above. +- The watchdog would be a user unit once user-scoped units ship (mesh-host #72). It is not, because it + runs per session and ends with the session, as a session-start line already does. +- `pacman-contrib` is declared here. A future `pacman` module that wants `checkupdates` or `paccache` + takes it over, since a package is declared once per node. diff --git a/modules/i3status-rust/cmd/i3status-rust-tools/args.go b/modules/i3status-rust/cmd/i3status-rust-tools/args.go new file mode 100644 index 0000000..9b5dfcf --- /dev/null +++ b/modules/i3status-rust/cmd/i3status-rust-tools/args.go @@ -0,0 +1,97 @@ +// Reading a tool's arguments: JSON numbers arrive as float64, and a missing argument is its default. +// The same in every desktop module that carries it. +package main + +import ( + "fmt" + "math" + "strings" + "time" +) + +// text is a string argument, trimmed; required says an empty one is refused. +func text(args map[string]any, key string, required bool) (string, error) { + v, present := args[key] + if !present || v == nil { + if required { + return "", fmt.Errorf("%s is required", key) + } + return "", nil + } + s, ok := v.(string) + if !ok { + return "", fmt.Errorf("%s is a string, not %T", key, v) + } + s = strings.TrimSpace(s) + if s == "" && required { + return "", fmt.Errorf("%s is required", key) + } + return s, nil +} + +// whole is a whole-number argument within [least, most], or def when absent. +func whole(args map[string]any, key string, def, least, most int) (int, error) { + v, present := args[key] + if !present || v == nil { + return def, nil + } + f, ok := v.(float64) + if !ok { + if i, isInt := v.(int); isInt { + f = float64(i) + } else { + return 0, fmt.Errorf("%s is a number, not %T", key, v) + } + } + if f != math.Trunc(f) { + return 0, fmt.Errorf("%s is a whole number, not %v", key, f) + } + n := int(f) + if n < least || n > most { + return 0, fmt.Errorf("%s is %d; it is between %d and %d", key, n, least, most) + } + return n, nil +} + +// flag is a boolean argument, or def when absent. +func flag(args map[string]any, key string, def bool) (bool, error) { + v, present := args[key] + if !present || v == nil { + return def, nil + } + b, ok := v.(bool) + if !ok { + return false, fmt.Errorf("%s is true or false, not %T", key, v) + } + return b, nil +} + +// texts is a list-of-strings argument. +func texts(args map[string]any, key string) ([]string, error) { + v, present := args[key] + if !present || v == nil { + return nil, nil + } + list, ok := v.([]any) + if !ok { + if ss, isStrings := v.([]string); isStrings { + return ss, nil + } + return nil, fmt.Errorf("%s is a list of strings, not %T", key, v) + } + out := make([]string, 0, len(list)) + for i, item := range list { + s, ok := item.(string) + if !ok { + return nil, fmt.Errorf("%s[%d] is a string, not %T", key, i, item) + } + out = append(out, s) + } + return out, nil +} + +// seconds is a timeout argument in seconds, defaulted and bounded below the runtime's call limit. +func seconds(args map[string]any, key string, def, most int) (time.Duration, error) { + n, err := whole(args, key, def, 1, most) + return time.Duration(n) * time.Second, err +} diff --git a/modules/i3status-rust/cmd/i3status-rust-tools/bar.go b/modules/i3status-rust/cmd/i3status-rust-tools/bar.go new file mode 100644 index 0000000..7914d41 --- /dev/null +++ b/modules/i3status-rust/cmd/i3status-rust-tools/bar.go @@ -0,0 +1,306 @@ +package main + +import ( + "encoding/json" + "errors" + "fmt" + "os" + "path/filepath" + "regexp" + "sort" + "strconv" + "strings" + "syscall" + "time" +) + +var bars = []string{"top", "bottom"} + +// A bar runs this long when a tool reads its values: long enough for every block's first update. +const runFor = 4 * time.Second + +func configDir() string { return filepath.Join(operatorHome(), ".config", "i3status-rust") } + +func barFile(bar string) string { return filepath.Join(configDir(), bar+"-bar.toml") } + +func barsOf(bar string) ([]string, error) { + if bar == "" { + return bars, nil + } + for _, b := range bars { + if b == bar { + return []string{bar}, nil + } + } + return nil, fmt.Errorf("bar %q is top or bottom", bar) +} + +// ReloadResult is what i3status_rust_reload answers. +type ReloadResult struct { + Reached []int `json:"reached"` + Note string `json:"note"` +} + +// Reload restarts every running i3status-rs in place, which re-reads its file (SIGUSR2). +func Reload() ReloadResult { + reached := signalAll("i3status-rs", syscall.SIGUSR2) + if reached == nil { + return ReloadResult{Reached: []int{}, Note: "no bar is running: i3 starts them with the session"} + } + return ReloadResult{Reached: reached, Note: "each bar re-read its configuration"} +} + +// Config is a bar's file cut into the part before its blocks and each block's own text. +type Config struct { + Header string + Blocks []string +} + +var blockStart = regexp.MustCompile(`(?m)^\[\[block\]\]\s*$`) + +func splitConfig(raw string) Config { + idx := blockStart.FindAllStringIndex(raw, -1) + if len(idx) == 0 { + return Config{Header: raw} + } + c := Config{Header: raw[:idx[0][0]]} + for i, at := range idx { + end := len(raw) + if i+1 < len(idx) { + end = idx[i+1][0] + } + c.Blocks = append(c.Blocks, raw[at[0]:end]) + } + return c +} + +// Block is one block of a bar. +type Block struct { + Index int `json:"index"` + Kind string `json:"block"` + Settings map[string]string `json:"settings"` + Text *string `json:"text,omitempty"` + State string `json:"state,omitempty"` +} + +var keyValue = regexp.MustCompile(`^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.+?)\s*$`) + +// describe reads a block's own top-level settings (not its sub-tables, such as clicks), as written. +func describe(index int, raw string) Block { + b := Block{Index: index, Settings: map[string]string{}} + for _, line := range strings.Split(raw, "\n")[1:] { + line = strings.TrimSpace(line) + if strings.HasPrefix(line, "[") { + break + } + if line == "" || strings.HasPrefix(line, "#") { + continue + } + if m := keyValue.FindStringSubmatch(line); m != nil { + v := strings.Trim(m[2], `"`) + if m[1] == "block" { + b.Kind = v + } else { + b.Settings[m[1]] = v + } + } + } + return b +} + +// BarBlocks is one bar's blocks. +type BarBlocks struct { + Bar string `json:"bar"` + File string `json:"file"` + Blocks []Block `json:"blocks"` + Error string `json:"error,omitempty"` +} + +// Blocks describes each bar's blocks, and with values what each shows now. +func Blocks(bar string, values bool) ([]BarBlocks, error) { + which, err := barsOf(bar) + if err != nil { + return nil, err + } + var out []BarBlocks + for _, b := range which { + file := barFile(b) + raw, err := os.ReadFile(file) + if err != nil { + out = append(out, BarBlocks{Bar: b, File: file, Blocks: []Block{}, Error: err.Error()}) + continue + } + c := splitConfig(string(raw)) + bb := BarBlocks{Bar: b, File: file, Blocks: []Block{}} + for i, text := range c.Blocks { + bb.Blocks = append(bb.Blocks, describe(i, text)) + } + if values { + shown, err := runBar(file) + if err != nil { + bb.Error = err.Error() + } + for i := range bb.Blocks { + if w, ok := shown[i]; ok { + text := w.text + bb.Blocks[i].Text, bb.Blocks[i].State = &text, w.state + } + } + } + out = append(out, bb) + } + return out, nil +} + +type widgetText struct{ text, state string } + +// runBar runs i3status-rs on a file for a moment and answers each block's latest text, by index. +// i3status-rs names each block's widgets by an instance ":…", which is how they are told apart. +func runBar(file string) (map[int]widgetText, error) { + s := findEnvironment() // the session when there is one; blocks that need none run without + r, err := s.run(runFor, "", "i3status-rs", file) + if err != nil && !errors.Is(err, ErrTimedOut) { + return nil, err + } + shown := parseStatus(r.Stdout) + if len(shown) == 0 { + msg := strings.TrimSpace(r.Stderr) + if msg == "" { + msg = "the bar showed nothing within " + runFor.String() + } + return shown, errors.New(msg) + } + return shown, nil +} + +// parseStatus reads i3bar's protocol — a header, "[", then one JSON array per update — and answers +// the last complete update's text per block index. +func parseStatus(stream string) map[int]widgetText { + var last []map[string]any + for _, line := range strings.Split(stream, "\n") { + line = strings.TrimSuffix(strings.TrimPrefix(strings.TrimSpace(line), ","), ",") + if !strings.HasPrefix(line, "[{") && line != "[]" { + continue + } + var update []map[string]any + if json.Unmarshal([]byte(line), &update) == nil { + last = update + } + } + out := map[int]widgetText{} + for _, w := range last { + instance, _ := w["instance"].(string) + head, _, ok := strings.Cut(instance, ":") + if !ok { + continue // a separator + } + i, err := strconv.Atoi(head) + if err != nil { + continue + } + text, _ := w["full_text"].(string) + cur := out[i] + cur.text = strings.TrimSpace(strings.TrimSpace(cur.text) + " " + strings.TrimSpace(text)) + if colour, _ := w["color"].(string); strings.EqualFold(colour, "#FF0000FF") { + cur.state = "critical" + } + out[i] = cur + } + return out +} + +// RunResult is what i3status_rust_block_run answers. +type RunResult struct { + Bar string `json:"bar"` + Block Block `json:"block"` + Error string `json:"error,omitempty"` +} + +// BlockRun runs one block of a bar alone, with the bar's theme and icons. +func BlockRun(bar string, index int) (RunResult, error) { + if _, err := barsOf(bar); err != nil || bar == "" { + return RunResult{}, fmt.Errorf("bar %q is top or bottom", bar) + } + raw, err := os.ReadFile(barFile(bar)) + if err != nil { + return RunResult{}, err + } + c := splitConfig(string(raw)) + if index >= len(c.Blocks) { + return RunResult{}, fmt.Errorf("the %s bar has %d blocks, numbered from 0", bar, len(c.Blocks)) + } + tmp, err := os.CreateTemp("", "i3status-rust-block-*.toml") + if err != nil { + return RunResult{}, err + } + defer os.Remove(tmp.Name()) + if _, err := tmp.WriteString(c.Header + c.Blocks[index]); err != nil { + tmp.Close() + return RunResult{}, err + } + tmp.Close() + out := RunResult{Bar: bar, Block: describe(index, c.Blocks[index])} + shown, err := runBar(tmp.Name()) + if err != nil { + out.Error = err.Error() + } + if w, ok := shown[0]; ok { + text := w.text + out.Block.Text, out.Block.State = &text, w.state + } + return out, nil +} + +// Theme is one bar theme. +type Theme struct { + Name string `json:"name"` + File string `json:"file"` + Source string `json:"source"` +} + +// ThemesResult is what i3status_rust_themes answers. +type ThemesResult struct { + InUse map[string]string `json:"in_use"` + Themes []Theme `json:"themes"` +} + +type themeDir struct{ path, source string } + +func themeDirs() []themeDir { + return []themeDir{ + {filepath.Join(configDir(), "themes"), "the account's"}, + {filepath.Join(operatorHome(), ".local", "share", "i3status-rust", "themes"), "the account's"}, + {"/usr/share/i3status-rust/themes", "the distribution's"}, + } +} + +var themeName = regexp.MustCompile(`(?ms)^\[theme\]\s*$.*?^theme\s*=\s*"([^"]+)"`) + +// Themes lists the themes, the first directory winning a name, and the one each bar names. +func Themes(dirs []themeDir) ThemesResult { + out := ThemesResult{InUse: map[string]string{}, Themes: []Theme{}} + for _, b := range bars { + if raw, err := os.ReadFile(barFile(b)); err == nil { + if m := themeName.FindStringSubmatch(string(raw)); m != nil { + out.InUse[b] = m[1] + } + } + } + seen := map[string]bool{} + for _, d := range dirs { + entries, err := os.ReadDir(d.path) + if err != nil { + continue + } + for _, e := range entries { + name, ok := strings.CutSuffix(e.Name(), ".toml") + if !ok || seen[name] { + continue + } + seen[name] = true + out.Themes = append(out.Themes, Theme{Name: name, File: filepath.Join(d.path, e.Name()), Source: d.source}) + } + } + sort.Slice(out.Themes, func(i, j int) bool { return out.Themes[i].Name < out.Themes[j].Name }) + return out +} diff --git a/modules/i3status-rust/cmd/i3status-rust-tools/bar_test.go b/modules/i3status-rust/cmd/i3status-rust-tools/bar_test.go new file mode 100644 index 0000000..fb1da5d --- /dev/null +++ b/modules/i3status-rust/cmd/i3status-rust-tools/bar_test.go @@ -0,0 +1,141 @@ +package main + +import ( + "os" + "path/filepath" + "reflect" + "strings" + "testing" +) + +func source(t *testing.T, name string) string { + t.Helper() + raw, err := os.ReadFile(filepath.Join("..", "..", "files", name)) + if err != nil { + t.Fatal(err) + } + return string(raw) +} + +func TestTheModulesBarsSplitIntoTheirBlocksInOrder(t *testing.T) { + c := splitConfig(source(t, "bottom-bar.toml")) + var kinds []string + for i, b := range c.Blocks { + kinds = append(kinds, describe(i, b).Kind) + } + want := []string{"tea_timer", "custom", "cpu", "disk_space", "disk_space", "memory", "docker", "sound", "weather", "notify", "time"} + if !reflect.DeepEqual(kinds, want) { + t.Fatalf("%v", kinds) + } + if !strings.Contains(c.Header, `theme = "plain"`) || strings.Contains(c.Header, "[[block]]") { + t.Fatalf("header: %s", c.Header) + } + custom := describe(1, c.Blocks[1]) + if custom.Settings["command"] != "~/.local/bin/i3status-updates 10" || custom.Settings["interval"] != "1800" { + t.Fatalf("a block's own settings, not its click's: %+v", custom) + } + if _, leaked := custom.Settings["cmd"]; leaked { + t.Fatal("the click's cmd was read as the block's") + } + top := splitConfig(source(t, "top-bar.toml")) + if len(top.Blocks) != 2 || describe(0, top.Blocks[0]).Kind != "focused_window" { + t.Fatalf("top: %+v", top.Blocks) + } +} + +// Two updates of i3bar's protocol, as i3status-rs wrote them for the top bar on 2026-10-04. +const stream = `{"version": 1, "click_events": true} +[ +[{"full_text":" | ","color":"#FFFFFFFF","separator":false},{"full_text":" up 1d ","color":"#F1F1F1FF","name":"0","instance":"1:"}], +[{"full_text":" | ","color":"#FFFFFFFF","separator":false},{"full_text":" ","color":"#FF0000FF","name":"0","instance":"0:"},{"full_text":"failed to connect to wayland ","color":"#FF0000FF","name":"0","instance":"0:"},{"full_text":" | "},{"full_text":" up 2d ","color":"#F1F1F1FF","name":"0","instance":"1:"}], +` + +func TestTheLatestUpdateIsReadPerBlockIndex(t *testing.T) { + got := parseStatus(stream) + if got[1].text != "up 2d" || got[1].state != "" || got[0].text != "failed to connect to wayland" || got[0].state != "critical" || len(got) != 2 { + t.Fatalf("%+v", got) + } + if len(parseStatus("garbage\n[\n")) != 0 { + t.Fatal("no update is no blocks") + } +} + +// installBars puts the module's bars where i3status-rs would read them, and a fake i3status-rs. +func installBars(t *testing.T) string { + t.Helper() + root := fakeMachine(t) + dir := filepath.Join(root, "home", ".config", "i3status-rust") + if err := os.MkdirAll(dir, 0o755); err != nil { + t.Fatal(err) + } + for _, f := range []string{"top-bar.toml", "bottom-bar.toml"} { + if err := os.WriteFile(filepath.Join(dir, f), []byte(source(t, f)), 0o644); err != nil { + t.Fatal(err) + } + } + bin := fakeBinaries(t, map[string]string{"i3status-rs": `cp "$1" "$LOG.config" +printf '%s\n' '{"version": 1}' '[' '[{"full_text":"first","instance":"0:"},{"full_text":"second","instance":"1:"}],'`}) + t.Setenv("LOG", filepath.Join(bin, "log")) + return bin +} + +func TestBlocksPairEachBlockWithWhatItShows(t *testing.T) { + installBars(t) + got, err := Blocks("top", true) + if err != nil || len(got) != 1 { + t.Fatalf("%+v, %v", got, err) + } + b := got[0].Blocks + if len(b) != 2 || b[0].Kind != "focused_window" || b[0].Text == nil || *b[0].Text != "first" || *b[1].Text != "second" { + t.Fatalf("%+v", got) + } + if all, _ := Blocks("", false); len(all) != 2 || all[1].Blocks[0].Text != nil { + t.Fatalf("both bars, without values: %+v", all) + } + if _, err := Blocks("side", false); err == nil { + t.Fatal("an unknown bar was accepted") + } +} + +func TestOneBlockRunsAloneWithTheBarsThemeAndIcons(t *testing.T) { + bin := installBars(t) + got, err := BlockRun("bottom", 8) + if err != nil || got.Block.Kind != "weather" || got.Block.Text == nil || *got.Block.Text != "first" { + t.Fatalf("%+v, %v", got, err) + } + ran, _ := os.ReadFile(filepath.Join(bin, "log.config")) + if strings.Count(string(ran), "[[block]]") != 1 || !strings.Contains(string(ran), `name = "metno"`) || + !strings.Contains(string(ran), `icons = "custom-icons"`) { + t.Fatalf("the config it ran:\n%s", ran) + } + if _, err := BlockRun("bottom", 11); err == nil { + t.Fatal("a block past the end was accepted") + } + if _, err := BlockRun("", 0); err == nil { + t.Fatal("no bar was accepted") + } +} + +func TestThemesListEachOnceWithTheOnesInUse(t *testing.T) { + installBars(t) + root := t.TempDir() + for _, f := range []string{"mine/plain.toml", "system/plain.toml", "system/nord-dark.toml", "system/README"} { + if err := os.MkdirAll(filepath.Dir(filepath.Join(root, f)), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(root, f), nil, 0o644); err != nil { + t.Fatal(err) + } + } + got := Themes([]themeDir{{filepath.Join(root, "mine"), "mine"}, {filepath.Join(root, "system"), "system"}}) + if got.InUse["top"] != "plain" || got.InUse["bottom"] != "plain" || len(got.Themes) != 2 || got.Themes[1].Source != "mine" { + t.Fatalf("%+v", got) + } +} + +func TestReloadWithNoBarRunningSaysSo(t *testing.T) { + fakeMachine(t) + if r := Reload(); len(r.Reached) != 0 || !strings.Contains(r.Note, "no bar") { + t.Fatalf("%+v", r) + } +} diff --git a/modules/i3status-rust/cmd/i3status-rust-tools/main.go b/modules/i3status-rust/cmd/i3status-rust-tools/main.go new file mode 100644 index 0000000..90918c1 --- /dev/null +++ b/modules/i3status-rust/cmd/i3status-rust-tools/main.go @@ -0,0 +1,81 @@ +// i3status-rust's Go tools bundle (novox/hq ADR 0188, ADR 0193, ADR 0208): the bars' tools, served by +// the node's runtime as the operator account. node-bar has no verbs yet (ADR 0208 §2), so every tool +// here is the module's own. +package main + +import ( + "fmt" + "os" + + stdio "git.novox.be/novox/mesh-sdk/go" +) + +func main() { + if err := stdio.Serve("", tools()); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +var barInput = map[string]any{"type": "string", "enum": bars, "description": "which bar (default: both)"} + +func tools() []stdio.Tool { + return []stdio.Tool{ + { + Name: "i3status_rust_reload", + Description: "Make the running bars re-read their configuration (i3status-rs restarts in place). " + + "Answers the processes reached.", + Run: func(map[string]any) (any, error) { return Reload(), nil }, + }, + { + Name: "i3status_rust_blocks", + Description: "What each bar shows: every block in order, its kind and settings, and with values " + + "(the default) what it shows right now, from one run of the bar's configuration.", + Input: map[string]any{ + "bar": barInput, + "values": map[string]any{"type": "boolean", "description": "run the bar once to read each block's current text (default true; a few seconds)"}, + }, + Run: func(args map[string]any) (any, error) { + bar, err := text(args, "bar", false) + if err != nil { + return nil, err + } + values, err := flag(args, "values", true) + if err != nil { + return nil, err + } + return Blocks(bar, values) + }, + }, + { + Name: "i3status_rust_block_run", + Description: "Run one block of a bar once, alone, and answer what it shows — to see a block that " + + "errors, or what a click would act on.", + Input: map[string]any{ + "type": "object", + "properties": map[string]any{ + "bar": map[string]any{"type": "string", "enum": bars}, + "index": map[string]any{"type": "integer", "description": "the block's position in the bar, from 0, as i3status_rust_blocks answers it"}, + }, + "required": []string{"bar", "index"}, + }, + Run: func(args map[string]any) (any, error) { + bar, err := text(args, "bar", true) + if err != nil { + return nil, err + } + index, err := whole(args, "index", 0, 0, 200) + if err != nil { + return nil, err + } + return BlockRun(bar, index) + }, + }, + { + Name: "i3status_rust_themes", + Description: "The bar themes on this machine (the distribution's and the account's own) and the " + + "one each bar uses.", + Run: func(map[string]any) (any, error) { return Themes(themeDirs()), nil }, + }, + } +} diff --git a/modules/i3status-rust/cmd/i3status-rust-tools/manifest_helpers_test.go b/modules/i3status-rust/cmd/i3status-rust-tools/manifest_helpers_test.go new file mode 100644 index 0000000..d4fb76d --- /dev/null +++ b/modules/i3status-rust/cmd/i3status-rust-tools/manifest_helpers_test.go @@ -0,0 +1,175 @@ +package main + +import ( + "encoding/json" + "os" + "path/filepath" + "strings" + "testing" +) + +// The module's manifest, read the way the catalogue reads it, for the manifest tests. The same in +// every desktop module that carries it. + +type manifest struct { + Module string `json:"module"` + Version string `json:"version"` + Capabilities []string `json:"capabilities"` + Requires []string `json:"requires"` + Claims []claim `json:"claims"` + Seats []any `json:"seats"` + Tools []string `json:"tools"` + Environment *environment `json:"environment"` + Shell []shellCode `json:"shell"` + Resources []map[string]any `json:"resources"` + Build struct { + Artifacts []map[string]any `json:"artifacts"` + } `json:"build"` +} + +type claim struct { + Name string `json:"name"` + Scope string `json:"scope"` + Serves []string `json:"serves"` +} + +type environment struct { + Variables map[string]string `json:"variables"` + Path []map[string]any `json:"path"` +} + +type shellCode struct { + For string `json:"for"` + Slot string `json:"slot"` + Code string `json:"code"` +} + +func readManifest(t *testing.T) manifest { + t.Helper() + raw, err := os.ReadFile(filepath.Join("..", "..", "module.json")) + if err != nil { + t.Fatal(err) + } + dec := json.NewDecoder(strings.NewReader(string(raw))) + dec.DisallowUnknownFields() + var m manifest + if err := dec.Decode(&m); err != nil { + t.Fatalf("module.json: %v", err) + } + return m +} + +func (m manifest) resource(t *testing.T, id string) map[string]any { + t.Helper() + for _, r := range m.Resources { + if r["id"] == id { + return r + } + } + t.Fatalf("no resource %q", id) + return nil +} + +func (m manifest) packages() (present, absent []string) { + for _, r := range m.Resources { + if r["type"] == "package" { + if r["absent"] == true { + absent = append(absent, r["package"].(string)) + } else { + present = append(present, r["package"].(string)) + } + } + } + return present, absent +} + +// sameAsSource checks that a file resource's content is byte for byte the module's source file, so +// the readable file in the repository is what the machine gets. +func (m manifest) sameAsSource(t *testing.T, id, source string) { + t.Helper() + want, err := os.ReadFile(filepath.Join("..", "..", source)) + if err != nil { + t.Fatal(err) + } + r := m.resource(t, id) + if r["type"] != "file" { + t.Fatalf("%s is a %v, not a file", id, r["type"]) + } + if got, _ := r["content"].(string); got != string(want) { + t.Fatalf("resource %s's content is not %s: edit the source and copy it into module.json", id, source) + } + if r["owner"] != "${machine:account}" && !strings.HasPrefix(r["path"].(string), "/etc/") { + t.Fatalf("%s under the home is the account's", id) + } +} + +// checkTheToolsAgree checks that the manifest lists the module's own tools exactly, that the bundle +// serves each seat verb the claims promise as ., and that the Go bundle is declared. +func checkTheToolsAgree(t *testing.T, m manifest) { + t.Helper() + own, seat := map[string]bool{}, map[string]bool{} + for _, tool := range tools() { + if strings.Contains(tool.Name, ".") { + seat[tool.Name] = true + } else { + own[tool.Name] = true + } + if strings.TrimSpace(tool.Description) == "" { + t.Errorf("%s has no description", tool.Name) + } + } + listed := map[string]bool{} + for _, name := range m.Tools { + listed[name] = true + if !own[name] { + t.Errorf("module.json lists %s, which the bundle does not serve", name) + } + } + for name := range own { + if !listed[name] { + t.Errorf("the bundle serves %s, which module.json does not list", name) + } + if !strings.HasPrefix(name, strings.ReplaceAll(m.Module, "-", "_")+"_") { + t.Errorf("%s is not prefixed with the module's name", name) + } + } + promised := map[string]bool{} + for _, c := range m.Claims { + for _, verb := range c.Serves { + promised[c.Name+"."+verb] = true + if !seat[c.Name+"."+verb] { + t.Errorf("the claim on %s promises %s, which the bundle does not serve", c.Name, verb) + } + } + } + for name := range seat { + if !promised[name] { + t.Errorf("the bundle serves %s, which no claim promises", name) + } + } + var bundle map[string]any + for _, a := range m.Build.Artifacts { + if a["kind"] == "bundle" { + bundle = a + } + } + if bundle == nil || bundle["language"] != "go" || bundle["system"] != "arch" || + bundle["from"] != "cmd/"+m.Module+"-tools" || bundle["binary"] != m.Module+"-tools" { + t.Errorf("the Go tools bundle: %v", bundle) + } +} + +// checkNoSecretsOrInstallationNames refuses what a catalogue manifest must never carry. +func checkNoSecretsOrInstallationNames(t *testing.T) { + t.Helper() + raw, err := os.ReadFile(filepath.Join("..", "..", "module.json")) + if err != nil { + t.Fatal(err) + } + s := strings.ToLower(string(raw)) + for _, never := range []string{"/home/", "jochen", "g14", "shanks", "novox.be", "api_key", ".hal/", "greenclip daemon"} { + if strings.Contains(s, never) { + t.Errorf("module.json names %q", never) + } + } +} diff --git a/modules/i3status-rust/cmd/i3status-rust-tools/manifest_test.go b/modules/i3status-rust/cmd/i3status-rust-tools/manifest_test.go new file mode 100644 index 0000000..0b4dde1 --- /dev/null +++ b/modules/i3status-rust/cmd/i3status-rust-tools/manifest_test.go @@ -0,0 +1,71 @@ +package main + +import ( + "reflect" + "strings" + "testing" +) + +// i3status-rust's shape (novox/hq ADR 0208): it claims node-bar, requires the X display on its own +// machine (its bars are i3bar's), owns its two bars and their icons, places the bars as an i3 drop-in, +// and runs the bar watchdog once per session. No block follows one machine's hardware or one person's +// devices. + +func TestItClaimsTheBarSeatAndRequiresTheXDisplay(t *testing.T) { + m := readManifest(t) + if m.Module != "i3status-rust" || m.Seats != nil { + t.Fatalf("module %q declares seats %v", m.Module, m.Seats) + } + if !reflect.DeepEqual(m.Claims, []claim{{Name: "node-bar", Scope: "node"}}) { + t.Fatalf("claims: %+v", m.Claims) + } + if !reflect.DeepEqual(m.Requires, []string{"x11-display"}) { + t.Fatalf("requires: %v", m.Requires) + } + if present, absent := m.packages(); !reflect.DeepEqual(present, []string{"i3status-rust", "pacman-contrib"}) || absent != nil { + t.Fatalf("packages: %v, absent %v", present, absent) + } +} + +func TestItOwnsItsFilesAsWrittenInTheModule(t *testing.T) { + m := readManifest(t) + for id, src := range map[string]string{ + "top-bar": "files/top-bar.toml", "bottom-bar": "files/bottom-bar.toml", "icons": "files/icons/custom-icons.toml", + "updates": "files/bin/i3status-updates", "watchdog": "files/bin/i3bar-watchdog", "i3-bars": "files/i3/60-i3status-rust.conf", + } { + m.sameAsSource(t, id, src) + } +} + +func TestNoBlockFollowsAMachinesHardwareOrAPersonsDevicesOrCarriesAKey(t *testing.T) { + m := readManifest(t) + bottom := m.resource(t, "bottom-bar")["content"].(string) + for _, never := range []string{`block = "battery"`, `block = "amd_gpu"`, `block = "nvidia_gpu"`, "mac = ", "api_key", "city_id", "openweathermap", "~/scripts/"} { + if strings.Contains(bottom, never) { + t.Errorf("the bottom bar has %s", never) + } + } +} + +func TestTheBarsAreAnI3DropInAndTheWatchdogRunsOncePerSession(t *testing.T) { + m := readManifest(t) + bars := m.resource(t, "i3-bars") + if bars["path"] != "${machine:account-home}/.config/i3/config.d/60-i3status-rust.conf" { + t.Fatalf("%v", bars["path"]) + } + c := bars["content"].(string) + if strings.Count(c, "bar {") != 2 || !strings.Contains(c, "status_command i3status-rs ~/.config/i3status-rust/bottom-bar.toml") || + !strings.Contains(c, "font pango:JetBrainsMono Nerd Font 11") { + t.Fatalf("%s", c) + } + if len(m.Shell) != 1 || m.Shell[0].For != "xinitrc" || m.Shell[0].Slot != "normal" || + !strings.Contains(m.Shell[0].Code, `"$HOME/.local/bin/i3bar-watchdog" "$$" &`) { + t.Fatalf("%+v", m.Shell) + } +} + +func TestTheToolsAgreeWithTheManifest(t *testing.T) { + m := readManifest(t) + checkTheToolsAgree(t, m) + checkNoSecretsOrInstallationNames(t) +} diff --git a/modules/i3status-rust/cmd/i3status-rust-tools/session.go b/modules/i3status-rust/cmd/i3status-rust-tools/session.go new file mode 100644 index 0000000..dc21774 --- /dev/null +++ b/modules/i3status-rust/cmd/i3status-rust-tools/session.go @@ -0,0 +1,423 @@ +// The operator's graphical session, as a tool the node's runtime runs finds it (novox/hq ADR 0208). +// +// The runtime is a system service running as the operator account (ADR 0175): it has the account's +// uid and none of the session's environment — no DISPLAY, no XAUTHORITY, no session bus. A tool that +// draws on the screen or talks to the desktop's D-Bus must find them. It reads them from a process of +// the account that is part of the session (the window manager first), the same thing `loginctl` and +// a person's own shell would point at, and says where it found them. +// +// Long-lived programs a tool starts go to the account's own service manager through `systemd-run +// --user`, never as children of the tool: the runtime's unit is a cgroup the service manager empties +// whenever the runtime restarts, and a compositor or a clipboard owner started from inside it would +// die with it. +// +// This file is the same in every desktop module that carries it; it moves into the Go SDK once a +// second consumer outside the desktop wants it. +package main + +import ( + "bytes" + "errors" + "fmt" + "os" + "os/exec" + "path/filepath" + "sort" + "strconv" + "strings" + "syscall" + "time" +) + +// Where the session is looked for. Variables so a test can point them at a fake tree. +var ( + procRoot = "/proc" + runUserDir = "/run/user" + x11Sockets = "/tmp/.X11-unix" +) + +// sessionHolders are the processes whose environment is the session's, best first: the window +// manager is the session, the rest are its children. Anything else carrying DISPLAY ranks after them. +var sessionHolders = []string{"i3", "sway", "i3bar", "picom", "xss-lock", "dunst", "clipmenud", "xterm"} + +// sessionKeys are the variables a session carries that a tool hands on to what it runs. +var sessionKeys = []string{"DISPLAY", "XAUTHORITY", "WAYLAND_DISPLAY", "DBUS_SESSION_BUS_ADDRESS", + "XDG_RUNTIME_DIR", "XDG_SESSION_ID", "I3SOCK"} + +// Session is what a tool needs to reach the operator's desktop. +type Session struct { + UID int `json:"uid"` + Display string `json:"display,omitempty"` + XAuthority string `json:"xauthority,omitempty"` + Wayland string `json:"wayland_display,omitempty"` + Bus string `json:"bus,omitempty"` + RuntimeDir string `json:"runtime_dir,omitempty"` + SessionID string `json:"session_id,omitempty"` + I3Sock string `json:"i3sock,omitempty"` + // From says where the values were found: the tool's own environment, a process, or the socket. + From string `json:"from"` +} + +// ErrNoSession is answered by a tool that needs the desktop when nobody is logged in to it. +var ErrNoSession = errors.New("no graphical session") + +// ErrTimedOut is what run answers for a command ended because it ran past its time. +var ErrTimedOut = errors.New("timed out") + +// ErrNoBus is answered by a tool that needs the session bus when the account has none. +var ErrNoBus = errors.New("no session bus") + +// operatorHome is the account's home: what the runtime was told, else the process's own. +func operatorHome() string { + if h := strings.TrimSpace(os.Getenv("MESH_OPERATOR_HOME")); h != "" { + return h + } + h, _ := os.UserHomeDir() + return h +} + +// findSession finds the graphical session of the account this tool runs as, or answers +// ErrNoSession with what it looked at. +func findSession() (Session, error) { + s := findEnvironment() + if s.Display == "" && s.Wayland == "" { + return s, fmt.Errorf("%w for uid %d on this machine: no process of the account carries DISPLAY "+ + "or WAYLAND_DISPLAY, and no X server socket in %s has an authority file to go with it. "+ + "Is anyone logged in to the desktop?", ErrNoSession, s.UID, x11Sockets) + } + return s, nil +} + +// findBus finds the account's session bus, which a logged-in account has whether or not a desktop +// is running. +func findBus() (Session, error) { + s := findEnvironment() + if s.Bus == "" { + return s, fmt.Errorf("%w for uid %d: DBUS_SESSION_BUS_ADDRESS is not set and %s does not exist "+ + "(the account is not logged in)", ErrNoBus, s.UID, filepath.Join(runUserDir, strconv.Itoa(s.UID), "bus")) + } + return s, nil +} + +func findEnvironment() Session { + uid := os.Getuid() + s := Session{UID: uid} + own := map[string]string{} + for _, k := range sessionKeys { + own[k] = os.Getenv(k) + } + if own["DISPLAY"] != "" || own["WAYLAND_DISPLAY"] != "" { + s.fill(own) + s.From = "the tool's own environment" + } else if pid, comm, env, ok := sessionProcess(uid); ok { + s.fill(env) + s.From = fmt.Sprintf("process %s (pid %d)", comm, pid) + } else if display, ok := lonelyX11Socket(); ok { + if a := filepath.Join(operatorHome(), ".Xauthority"); exists(a) { + s.Display, s.XAuthority = display, a + s.From = "the X server socket and the account's ~/.Xauthority" + } + s.fill(own) + } else { + s.fill(own) + s.From = "nothing: no session found" + } + // The bus and the runtime directory are the account's, whether or not the process named them. + runtime := filepath.Join(runUserDir, strconv.Itoa(uid)) + if s.RuntimeDir == "" && exists(runtime) { + s.RuntimeDir = runtime + } + if s.Bus == "" && s.RuntimeDir != "" && exists(filepath.Join(s.RuntimeDir, "bus")) { + s.Bus = "unix:path=" + filepath.Join(s.RuntimeDir, "bus") + } + return s +} + +func (s *Session) fill(env map[string]string) { + set := func(dst *string, key string) { + if *dst == "" { + *dst = env[key] + } + } + set(&s.Display, "DISPLAY") + set(&s.XAuthority, "XAUTHORITY") + set(&s.Wayland, "WAYLAND_DISPLAY") + set(&s.Bus, "DBUS_SESSION_BUS_ADDRESS") + set(&s.RuntimeDir, "XDG_RUNTIME_DIR") + set(&s.SessionID, "XDG_SESSION_ID") + set(&s.I3Sock, "I3SOCK") +} + +// sessionProcess is the best process of this uid whose environment names a display. +func sessionProcess(uid int) (int, string, map[string]string, bool) { + entries, err := os.ReadDir(procRoot) + if err != nil { + return 0, "", nil, false + } + type candidate struct { + pid int + comm string + env map[string]string + rank int + } + var found []candidate + for _, e := range entries { + pid, err := strconv.Atoi(e.Name()) + if err != nil { + continue + } + dir := filepath.Join(procRoot, e.Name()) + if owner, ok := ownerOf(dir); !ok || owner != uid { + continue + } + raw, err := os.ReadFile(filepath.Join(dir, "environ")) + if err != nil { + continue + } + env := parseEnviron(raw) + if env["DISPLAY"] == "" && env["WAYLAND_DISPLAY"] == "" { + continue + } + comm := readTrimmed(filepath.Join(dir, "comm")) + rank := len(sessionHolders) + for i, h := range sessionHolders { + if h == comm { + rank = i + break + } + } + found = append(found, candidate{pid, comm, env, rank}) + } + if len(found) == 0 { + return 0, "", nil, false + } + sort.Slice(found, func(i, j int) bool { + if found[i].rank != found[j].rank { + return found[i].rank < found[j].rank + } + return found[i].pid > found[j].pid // the newer of two equals + }) + best := found[0] + return best.pid, best.comm, best.env, true +} + +func parseEnviron(raw []byte) map[string]string { + env := map[string]string{} + for _, kv := range bytes.Split(raw, []byte{0}) { + if i := bytes.IndexByte(kv, '='); i > 0 { + env[string(kv[:i])] = string(kv[i+1:]) + } + } + return env +} + +func ownerOf(path string) (int, bool) { + info, err := os.Stat(path) + if err != nil { + return 0, false + } + st, ok := info.Sys().(*syscall.Stat_t) + if !ok { + return 0, false + } + return int(st.Uid), true +} + +// lonelyX11Socket is the display of the one X server socket there is, when there is exactly one. +func lonelyX11Socket() (string, bool) { + entries, err := os.ReadDir(x11Sockets) + if err != nil { + return "", false + } + var displays []string + for _, e := range entries { + if n := strings.TrimPrefix(e.Name(), "X"); n != e.Name() { + if _, err := strconv.Atoi(n); err == nil { + displays = append(displays, ":"+n) + } + } + } + if len(displays) != 1 { + return "", false + } + return displays[0], true +} + +func readTrimmed(path string) string { + b, err := os.ReadFile(path) + if err != nil { + return "" + } + return strings.TrimSpace(string(b)) +} + +func exists(path string) bool { + _, err := os.Stat(path) + return err == nil +} + +// Env is this process's environment with the session's variables in place of its own. +func (s Session) Env() []string { + drop := map[string]bool{} + for _, k := range sessionKeys { + drop[k] = true + } + var env []string + for _, kv := range os.Environ() { + if i := strings.IndexByte(kv, '='); i > 0 && drop[kv[:i]] { + continue + } + env = append(env, kv) + } + add := func(k, v string) { + if v != "" { + env = append(env, k+"="+v) + } + } + add("DISPLAY", s.Display) + add("XAUTHORITY", s.XAuthority) + add("WAYLAND_DISPLAY", s.Wayland) + add("DBUS_SESSION_BUS_ADDRESS", s.Bus) + add("XDG_RUNTIME_DIR", s.RuntimeDir) + add("XDG_SESSION_ID", s.SessionID) + add("I3SOCK", s.I3Sock) + return env +} + +// mostOutput bounds what a command may answer with, per stream. +const mostOutput = 256 << 10 + +// Result is what a command did. +type Result struct { + Stdout string `json:"stdout"` + Stderr string `json:"stderr,omitempty"` + Code int `json:"code"` + Truncated bool `json:"truncated,omitempty"` +} + +// run runs a command in the session's environment, its input given, ended with everything it +// started after timeout. A command that is not installed is an error naming it; one that exits +// non-zero is a Result with its code, for the caller to judge. +func (s Session) run(timeout time.Duration, stdin string, name string, args ...string) (Result, error) { + path, err := exec.LookPath(name) + if err != nil { + return Result{}, fmt.Errorf("%s is not installed on this machine", name) + } + cmd := exec.Command(path, args...) + cmd.Env = s.Env() + if home := operatorHome(); exists(home) { + cmd.Dir = home + } + if stdin != "" { + cmd.Stdin = strings.NewReader(stdin) + } + var out, errOut capped + cmd.Stdout, cmd.Stderr = &out, &errOut + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + if err := cmd.Start(); err != nil { + return Result{}, fmt.Errorf("%s: %w", name, err) + } + done := make(chan error, 1) + go func() { done <- cmd.Wait() }() + select { + case err = <-done: + case <-time.After(timeout): + _ = syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) + <-done + return Result{Stdout: out.String(), Stderr: errOut.String()}, + fmt.Errorf("%s did not finish within %s and was ended: %w", name, timeout, ErrTimedOut) + } + r := Result{Stdout: out.String(), Stderr: errOut.String(), Truncated: out.cut || errOut.cut} + var exit *exec.ExitError + if errors.As(err, &exit) { + r.Code = exit.ExitCode() + } else if err != nil { + return r, fmt.Errorf("%s: %w", name, err) + } + return r, nil +} + +// detach starts a long-lived program under the account's own service manager, as a transient unit +// that carries the session's display, so it outlives the runtime that asked for it. A unit already +// running under the same name is stopped first, so a fixed name means "at most one". +func (s Session) detach(unit string, args ...string) error { + if s.RuntimeDir == "" { + return fmt.Errorf("%w: the account's runtime directory is missing, so its service manager "+ + "cannot be reached", ErrNoBus) + } + _, _ = s.run(5*time.Second, "", "systemctl", "--user", "stop", unit+".service") + call := []string{"--user", "--collect", "--quiet", "--unit=" + unit} + for _, kv := range [][2]string{{"DISPLAY", s.Display}, {"XAUTHORITY", s.XAuthority}, + {"WAYLAND_DISPLAY", s.Wayland}, {"XDG_SESSION_ID", s.SessionID}, {"I3SOCK", s.I3Sock}} { + if kv[1] != "" { + call = append(call, "--setenv="+kv[0]+"="+kv[1]) + } + } + call = append(call, "--") + call = append(call, args...) + r, err := s.run(10*time.Second, "", "systemd-run", call...) + if err != nil { + return err + } + if r.Code != 0 { + return fmt.Errorf("systemd-run %s: %s", unit, strings.TrimSpace(r.Stderr)) + } + return nil +} + +// uniqueUnit is a transient unit name that will not collide with an earlier one. +func uniqueUnit(prefix string) string { + return fmt.Sprintf("%s-%d", prefix, time.Now().UnixNano()) +} + +type capped struct { + bytes.Buffer + cut bool +} + +func (c *capped) Write(p []byte) (int, error) { + if room := mostOutput - c.Len(); room < len(p) { + if room > 0 { + c.Buffer.Write(p[:room]) + } + c.cut = true + return len(p), nil + } + return c.Buffer.Write(p) +} + +// processesOf are the pids of this uid's processes whose command name is comm, oldest first. +func processesOf(comm string) []int { + entries, err := os.ReadDir(procRoot) + if err != nil { + return nil + } + uid := os.Getuid() + var pids []int + for _, e := range entries { + pid, err := strconv.Atoi(e.Name()) + if err != nil { + continue + } + dir := filepath.Join(procRoot, e.Name()) + if owner, ok := ownerOf(dir); !ok || owner != uid { + continue + } + if readTrimmed(filepath.Join(dir, "comm")) == comm { + pids = append(pids, pid) + } + } + sort.Ints(pids) + return pids +} + +// signalAll sends sig to every process of this uid named comm, and answers the pids it reached. +func signalAll(comm string, sig syscall.Signal) []int { + var reached []int + for _, pid := range processesOf(comm) { + if syscall.Kill(pid, sig) == nil { + reached = append(reached, pid) + } + } + return reached +} diff --git a/modules/i3status-rust/cmd/i3status-rust-tools/session_test.go b/modules/i3status-rust/cmd/i3status-rust-tools/session_test.go new file mode 100644 index 0000000..800cc6d --- /dev/null +++ b/modules/i3status-rust/cmd/i3status-rust-tools/session_test.go @@ -0,0 +1,174 @@ +package main + +import ( + "errors" + "os" + "path/filepath" + "strconv" + "strings" + "testing" + "time" +) + +// fakeMachine points the session finder at a temporary /proc, /run/user and X socket directory, with +// none of the test process's own session variables, and gives back the root. +func fakeMachine(t *testing.T) string { + t.Helper() + root := t.TempDir() + procRoot, runUserDir, x11Sockets = filepath.Join(root, "proc"), filepath.Join(root, "run-user"), filepath.Join(root, "x11") + for _, d := range []string{procRoot, runUserDir, x11Sockets} { + if err := os.MkdirAll(d, 0o755); err != nil { + t.Fatal(err) + } + } + for _, k := range sessionKeys { + t.Setenv(k, "") + } + t.Setenv("MESH_OPERATOR_HOME", filepath.Join(root, "home")) + t.Cleanup(func() { procRoot, runUserDir, x11Sockets = "/proc", "/run/user", "/tmp/.X11-unix" }) + return root +} + +func fakeProcess(t *testing.T, pid int, comm string, env ...string) { + t.Helper() + dir := filepath.Join(procRoot, strconv.Itoa(pid)) + if err := os.MkdirAll(dir, 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, "comm"), []byte(comm+"\n"), 0o644); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, "environ"), []byte(strings.Join(env, "\x00")+"\x00"), 0o600); err != nil { + t.Fatal(err) + } +} + +func TestTheSessionIsReadFromTheWindowManagerBeforeAnyOtherProcess(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 900, "xterm", "DISPLAY=:9", "XAUTHORITY=/elsewhere") + fakeProcess(t, 100, "i3", "DISPLAY=:1", "XAUTHORITY=/home/op/.Xauthority", + "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus", "XDG_SESSION_ID=3", "SECRET_TOKEN=never-copied") + fakeProcess(t, 50, "bash", "PATH=/usr/bin") + s, err := findSession() + if err != nil { + t.Fatal(err) + } + if s.Display != ":1" || s.XAuthority != "/home/op/.Xauthority" || s.SessionID != "3" || !strings.Contains(s.From, "i3 (pid 100)") { + t.Fatalf("the window manager's environment: %+v", s) + } + for _, kv := range s.Env() { + if strings.HasPrefix(kv, "SECRET_TOKEN=") { + t.Fatal("a variable of the session process that is not a session variable was handed on") + } + } +} + +func TestAnyProcessCarryingADisplayServesWhenTheWindowManagerIsNotFound(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 10, "firefox", "DISPLAY=:0") + fakeProcess(t, 20, "firefox", "DISPLAY=:2") + s, err := findSession() + if err != nil || s.Display != ":2" { + t.Fatalf("the newest of two equals: %+v, %v", s, err) + } +} + +func TestNoSessionIsAClearAnswerNotAGuess(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 10, "sshd", "PATH=/usr/bin") + _, err := findSession() + if !errors.Is(err, ErrNoSession) || !strings.Contains(err.Error(), "logged in to the desktop") { + t.Fatalf("no session: %v", err) + } +} + +func TestOneXSocketAndTheAccountsAuthorityFileAreASession(t *testing.T) { + root := fakeMachine(t) + if err := os.WriteFile(filepath.Join(x11Sockets, "X0"), nil, 0o644); err != nil { + t.Fatal(err) + } + if err := os.MkdirAll(filepath.Join(root, "home"), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(root, "home", ".Xauthority"), nil, 0o600); err != nil { + t.Fatal(err) + } + s, err := findSession() + if err != nil || s.Display != ":0" || !strings.HasSuffix(s.XAuthority, "/home/.Xauthority") { + t.Fatalf("socket and authority: %+v, %v", s, err) + } +} + +func TestTheBusIsTheAccountsRuntimeDirectoryWhenNoProcessNamesIt(t *testing.T) { + fakeMachine(t) + runtime := filepath.Join(runUserDir, strconv.Itoa(os.Getuid())) + if _, err := findBus(); !errors.Is(err, ErrNoBus) { + t.Fatalf("no runtime directory is no bus: %v", err) + } + if err := os.MkdirAll(runtime, 0o700); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(runtime, "bus"), nil, 0o600); err != nil { + t.Fatal(err) + } + s, err := findBus() + if err != nil || s.Bus != "unix:path="+filepath.Join(runtime, "bus") || s.RuntimeDir != runtime { + t.Fatalf("bus: %+v, %v", s, err) + } + env := strings.Join(s.Env(), "\n") + if !strings.Contains(env, "XDG_RUNTIME_DIR="+runtime) || !strings.Contains(env, "DBUS_SESSION_BUS_ADDRESS=unix:path=") { + t.Fatalf("the bus is handed on: %s", env) + } +} + +func TestACommandIsBoundedAndANonZeroExitIsAResult(t *testing.T) { + fakeMachine(t) + s := Session{} + r, err := s.run(5*time.Second, "in", "sh", "-c", "cat; echo err >&2; exit 3") + if err != nil || r.Stdout != "in" || r.Code != 3 || strings.TrimSpace(r.Stderr) != "err" { + t.Fatalf("result: %+v, %v", r, err) + } + start := time.Now() + if _, err := s.run(200*time.Millisecond, "", "sh", "-c", "sleep 30 & sleep 30"); err == nil || time.Since(start) > 5*time.Second { + t.Fatalf("a command past its time is ended with what it started: %v after %s", err, time.Since(start)) + } + if _, err := s.run(time.Second, "", "no-such-program-here"); err == nil || !strings.Contains(err.Error(), "not installed") { + t.Fatalf("a missing program: %v", err) + } +} + +func TestDetachAsksTheAccountsServiceManagerWithTheSessionsDisplay(t *testing.T) { + fakeMachine(t) + bin := fakeBinaries(t, map[string]string{ + "systemctl": `echo "systemctl $*" >> "$LOG"`, + "systemd-run": `echo "systemd-run $*" >> "$LOG"`, + }) + log := filepath.Join(bin, "log") + t.Setenv("LOG", log) + s := Session{Display: ":1", XAuthority: "/x", RuntimeDir: "/run/user/1"} + if err := s.detach("picom-session", "picom", "--config", "/c"); err != nil { + t.Fatal(err) + } + got, _ := os.ReadFile(log) + want := "systemctl --user stop picom-session.service\n" + + "systemd-run --user --collect --quiet --unit=picom-session --setenv=DISPLAY=:1 --setenv=XAUTHORITY=/x -- picom --config /c\n" + if string(got) != want { + t.Fatalf("detach ran:\n%s\nwant:\n%s", got, want) + } + if err := (Session{}).detach("x", "y"); !errors.Is(err, ErrNoBus) { + t.Fatalf("no runtime directory: %v", err) + } +} + +// fakeBinaries puts shell scripts named for programs first on PATH, and answers their directory. +func fakeBinaries(t *testing.T, scripts map[string]string) string { + t.Helper() + dir := t.TempDir() + for name, body := range scripts { + if err := os.WriteFile(filepath.Join(dir, name), []byte("#!/bin/sh\n"+body+"\n"), 0o755); err != nil { + t.Fatal(err) + } + } + t.Setenv("PATH", dir+string(os.PathListSeparator)+os.Getenv("PATH")) + return dir +} diff --git a/modules/i3status-rust/files/bin/i3bar-watchdog b/modules/i3status-rust/files/bin/i3bar-watchdog new file mode 100755 index 0000000..63b2b02 --- /dev/null +++ b/modules/i3status-rust/files/bin/i3bar-watchdog @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +# i3bar-watchdog [session-pid] (module i3status-rust, novox/hq ADR 0208): respawns a bar that died. +# +# i3 starts one i3bar per `bar { }` block and never restarts one that exits, and a reload does not +# either. Changing the monitor setup reliably kills the bar that owns the tray. This brings back the +# one missing i3bar, without restarting i3, and logs the outputs at that moment: the evidence for the +# cause, which is i3bar's. +# +# Started once per session from the session's start, with the session's own pid; it ends when that +# process does. Adopted from the predecessor's i3-bar-watchdog user unit of 2026-10-04. +set -uo pipefail + +session_pid="${1:-}" +interval="${I3_BAR_WATCHDOG_INTERVAL:-5}" +# Two misses in a row before acting: an i3 restart tears every bar down and starts them again. +confirm="${I3_BAR_WATCHDOG_CONFIRM:-2}" +# Never respawn the same bar more often than this, so a bar that dies at once is not a tight loop. +cooldown="${I3_BAR_WATCHDOG_COOLDOWN:-30}" + +log() { printf 'i3bar-watchdog: %s\n' "$*" >&2; } + +for tool in i3-msg i3bar pgrep; do + command -v "$tool" >/dev/null 2>&1 || { + log "$tool is missing; not watching" + exit 1 + } +done + +declare -A missed=() fixed=() + +bar_ids() { i3-msg -t get_bar_config 2>/dev/null | grep -oE '"[^"]+"' | tr -d '"'; } +outputs() { xrandr --listmonitors 2>/dev/null | tail -n +2 | awk '{print $2" "$3}' | tr '\n' ' '; } +session_alive() { [ -z "$session_pid" ] || kill -0 "$session_pid" 2>/dev/null; } + +while session_alive; do + sleep "$interval" + socket="$(i3 --get-socketpath 2>/dev/null)" + [ -n "$socket" ] && [ -S "$socket" ] || continue + ids="$(bar_ids)" + [ -n "$ids" ] || continue + while read -r id; do + [ -n "$id" ] || continue + if pgrep -u "$EUID" -f -- "i3bar --bar_id=$id" >/dev/null 2>&1; then + missed[$id]=0 + continue + fi + missed[$id]=$((${missed[$id]:-0} + 1)) + [ "${missed[$id]}" -ge "$confirm" ] || continue + now="$(date +%s)" + if [ $((now - ${fixed[$id]:-0})) -lt "$cooldown" ]; then + continue + fi + log "$id is gone; respawning it. Outputs now: $(outputs)" + nohup i3bar --bar_id="$id" --socket="$socket" >/dev/null 2>&1 & + disown 2>/dev/null || true + fixed[$id]="$now" + sleep 2 + if pgrep -u "$EUID" -f -- "i3bar --bar_id=$id" >/dev/null 2>&1; then + missed[$id]=0 + else + log "$id exited within 2s of respawning; check its status_command" + fi + done <<<"$ids" +done diff --git a/modules/i3status-rust/files/bin/i3status-updates b/modules/i3status-rust/files/bin/i3status-updates new file mode 100755 index 0000000..1a70cf9 --- /dev/null +++ b/modules/i3status-rust/files/bin/i3status-updates @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +# i3status-updates [threshold] (module i3status-rust, novox/hq ADR 0208): the pending updates, for +# the bottom bar's custom block (json = true). Emits one JSON line. +# +# Adopted from the operator's pkg-updates of 2026-10-04. The native `packages` block showed a raw +# red error on every transient network failure, which on a roaming laptop is often. This keeps the +# last good result through a failure and shows an error only after `threshold` failures in a row +# (default 10). Official packages through checkupdates (pacman-contrib, a temporary database, no +# root); AUR packages through paru when it is installed, and none counted when it is not. +set -uo pipefail + +threshold="${1:-10}" +icon="update" +state_dir="${XDG_RUNTIME_DIR:-/tmp}/i3status-updates" +mkdir -p "$state_dir" +last="$state_dir/last_good.json" +failures="$state_dir/failures" + +json() { printf '{"icon":"%s","state":"%s","text":"%s","short_text":"%s"}' "$icon" "$1" "$2" "$3"; } +count() { [ -n "$1" ] && printf '%s\n' "$1" | grep -c . || echo 0; } + +official="$(checkupdates 2>/dev/null)" +official_rc=$? +aur="" aur_rc=0 +if command -v paru >/dev/null 2>&1; then + aur="$(paru -Qua 2>/dev/null)" + aur_rc=$? +fi + +# checkupdates: 0 updates listed, 2 none pending; anything else is a failure. +if { [ "$official_rc" -eq 0 ] || [ "$official_rc" -eq 2 ]; } && [ "$aur_rc" -eq 0 ]; then + o="$(count "$official")" + a="$(count "$aur")" + total=$((o + a)) + if [ "$total" -eq 0 ]; then + payload="$(json Good "up to date" "")" + else + # A kernel update wants a reboot: the one worth not putting off. + state=Info + printf '%s\n' "$official" | grep -qE '^(linux|linux-lts|linux-zen) ' && state=Warning + label="$o + $a = $total updates" + [ "$a" -eq 0 ] && label="$total updates" + [ "$total" -eq 1 ] && label="1 update" + payload="$(json "$state" "$label" "$total")" + fi + printf '%s' "$payload" >"$last" + printf '0' >"$failures" + printf '%s\n' "$payload" + exit 0 +fi + +n=$(($(cat "$failures" 2>/dev/null || echo 0) + 1)) +printf '%s' "$n" >"$failures" +if [ "$n" -ge "$threshold" ]; then + json Critical "update check failing (${n}x)" "!" + echo +elif [ -s "$last" ]; then + cat "$last" + echo +else + json Idle "" "" + echo +fi diff --git a/modules/i3status-rust/files/bottom-bar.toml b/modules/i3status-rust/files/bottom-bar.toml new file mode 100644 index 0000000..8098093 --- /dev/null +++ b/modules/i3status-rust/files/bottom-bar.toml @@ -0,0 +1,100 @@ +# The bottom bar (module i3status-rust, novox/hq ADR 0208). Owned by the mesh: replaced at every +# push. Adopted from the workstations of 2026-10-04 with what follows a machine's hardware or one +# person's devices left out: the battery and the GPU belong to a machine model's hardware module, +# and a headset's address is not the bar's to know. Every block here works the same on any machine. +icons_format = "{icon}" + +[theme] +theme = "plain" +[theme.overrides] +idle_bg = "#000000" +idle_fg = "#f1f1f1" +info_bg = "#000000" +info_fg = "#f1f1f1" +good_bg = "#000000" +good_fg = "#859900" +warning_bg = "#000000" +warning_fg = "#de5200" +critical_bg = "#000000" +critical_fg = "#ff0000" +separator = " | " +separator_fg = "#ffffff" +separator_bg = "#000000" + +[icons] +icons = "custom-icons" + +[[block]] +block = "tea_timer" +format = "$icon{ $minutes:$seconds|}" +done_cmd = "notify-send 'Timer finished'" + +# Pending updates: official and, where an AUR helper is installed, AUR. The script keeps the last good +# count through a network gap and shows an error only after ten failed checks in a row. Click: the +# list, in the launcher's menu. +[[block]] +block = "custom" +command = "~/.local/bin/i3status-updates 10" +json = true +interval = 1800 +[[block.click]] +button = "left" +cmd = "checkupdates | dmenu -l 20 -p Updates" + +[[block]] +block = "cpu" + +[[block]] +block = "disk_space" +path = "/" +info_type = "used" +alert_unit = "GB" +interval = 20 +warning = 850 +alert = 920 +format = "$icon / $used.eng(w:2) ($percentage.eng(w:2))" + +[[block]] +block = "disk_space" +path = "/home" +info_type = "used" +alert_unit = "GB" +interval = 20 +warning = 850 +alert = 920 +format = "$icon /home $used.eng(w:2) ($percentage.eng(w:2))" + +[[block]] +block = "memory" +format = "$icon $mem_total_used.eng(w:2) ($mem_total_used_percents.eng(w:2))" +format_alt = "$icon_swap $swap_used.eng(w:2) ($swap_used_percents.eng(w:2))" + +[[block]] +block = "docker" +interval = 2 +format = "$icon $running/$total" + +[[block]] +block = "sound" +[[block.click]] +button = "left" +cmd = "pavucontrol" + +# The weather from the Norwegian Meteorological Institute, which needs no key, where the machine is. +[[block]] +block = "weather" +format = "$icon $weather_verbose ($location) $temp" +autolocate = true +autolocate_interval = 600 +[block.service] +name = "metno" + +[[block]] +block = "notify" +driver = "dunst" +format = " $icon {($notification_count.eng(w:1))|}" + +[[block]] +block = "time" +interval = 1 +format = "$timestamp.datetime(f:'%a %d/%m %H:%M:%S')" diff --git a/modules/i3status-rust/files/i3/60-i3status-rust.conf b/modules/i3status-rust/files/i3/60-i3status-rust.conf new file mode 100644 index 0000000..20acbb1 --- /dev/null +++ b/modules/i3status-rust/files/i3/60-i3status-rust.conf @@ -0,0 +1,34 @@ +# The bars (module i3status-rust, novox/hq ADR 0208). Owned by the mesh: replaced at every push. +# i3 reads this file through its configuration's `include ~/.config/i3/config.d/*.conf`. The bottom +# bar shows the machine; the top bar the focused window and the tray, on the primary output. The +# face is the monospace one every desktop module names. +bar { + font pango:JetBrainsMono Nerd Font 11 + position bottom + status_command i3status-rs ~/.config/i3status-rust/bottom-bar.toml + tray_output none + colors { + separator #ffffff + background #000000 + statusline #ffffff + # The text on an accent-coloured button is dark: light text on the accent was barely + # legible. + focused_workspace #de5200 #de5200 #000000 + active_workspace #de5200 #de5200 #000000 + inactive_workspace #000000 #000000 #ffffff + urgent_workspace #2f343a #900000 #ffffff + } +} + +bar { + font pango:JetBrainsMono Nerd Font 11 + position top + status_command i3status-rs ~/.config/i3status-rust/top-bar.toml + workspace_buttons no + tray_output primary + colors { + separator #ffffff + background #000000 + statusline #ffffff + } +} diff --git a/modules/i3status-rust/files/icons/custom-icons.toml b/modules/i3status-rust/files/icons/custom-icons.toml new file mode 100644 index 0000000..685c9d3 --- /dev/null +++ b/modules/i3status-rust/files/icons/custom-icons.toml @@ -0,0 +1,135 @@ +# Icons for the bars (module i3status-rust, novox/hq ADR 0208), from the JetBrains Mono Nerd Font. +# Owned by the mesh: replaced at every push. Adopted unchanged from the workstations of 2026-10-04. +# Material from NerdFont +# https://www.nerdfonts.com/cheat-sheet +backlight = [ + "\ue38d", # nf-weather-moon_new + "\ue3d4", # nf-weather-moon_alt_waxing_gibbous_6 + "\ue3d3", # nf-weather-moon_alt_waxing_gibbous_5 + "\ue3d2", # nf-weather-moon_alt_waxing_gibbous_4 + "\ue3d1", # nf-weather-moon_alt_waxing_gibbous_3 + "\ue3d0", # nf-weather-moon_alt_waxing_gibbous_2 + "\ue3cf", # nf-weather-moon_alt_waxing_gibbous_1 + "\ue3ce", # nf-weather-moon_alt_first_quarter + "\ue3cd", # nf-weather-moon_alt_waxing_crescent_6 + "\ue3cc", # nf-weather-moon_alt_waxing_crescent_5 + "\ue3cb", # nf-weather-moon_alt_waxing_crescent_4 + "\ue3ca", # nf-weather-moon_alt_waxing_crescent_3 + "\ue3c9", # nf-weather-moon_alt_waxing_crescent_2 + "\ue3c8", # nf-weather-moon_alt_waxing_crescent_1 + "\ue39b", # nf-weather-moon_full +] +bat_charging = "\U000f0084" # nf-md-battery_charging +bat_not_available = "\U000f0091" # nf-md-battery_unknown +bat = [ + "\U000f007a", # nf-md-battery_10 + "\U000f007b", # nf-md-battery_20 + "\U000f007c", # nf-md-battery_30 + "\U000f007d", # nf-md-battery_40 + "\U000f007e", # nf-md-battery_50 + "\U000f007f", # nf-md-battery_60 + "\U000f0080", # nf-md-battery_70 + "\U000f0081", # nf-md-battery_80 + "\U000f0082", # nf-md-battery_90 + "\U000f0079", # nf-md-battery +] +bell = "\U000f009c" # nf-md-bell_outline +bell-slash = "\U000f009b" # nf-md-bell_off +blackberry = "\uf307" # nf-md-blackberry +bluetooth = "\U000f00af" # nf-md-bluetooth +calendar = "\U000f00ed" # nf-md-calendar +cogs = "\U000f0493" # nf-md-cog +cpu = [ + "\U000F0F86", # nf-md-speedometer_slow + "\U000F0F85", # nf-md-speedometer_medium + "\U000F04C5", # nf-md-speedometer +] +cpu_boost_on = "\U000f0521" # nf-md-toggle_switch +cpu_boost_off = "\U000f0a19" # nf-md-toggle_switch_off_outline +disk_drive = "\U000f02ca" # nf-md-harddisk +docker = "\uf308" # nf-linux-docker +github = "\U000f02a4" # nf-md-github +gpu = "\U000f0379" # nf-md-monitor +headphones = "\U000f02cb" # nf-md-headphones +joystick = "\U000f0297" # nf-md-gamepad_variant +keyboard = "\U000f030c" # nf-md-keyboard +mail = "\U000f01ee" # nf-md-email +memory_mem = "\U000f035b" # nf-md-memory +memory_swap = "\U000f02ca" # nf-md-harddisk +mouse = "\U000f037d" # nf-md-mouse +music = "\U000f075a" # nf-md-music +music_next = "\U000f04ad" # nf-md-skip_next +music_pause = "\U000f03e4" # nf-md-pause +music_play = "\U000f040a" # nf-md-play +music_prev = "\U000f04ae" # nf-md-skip_previous +net_bridge = "\U000f04aa" # nf-md-sitemap +net_down = "\U000f01da" # nf-md-download +net_loopback = "\U000f006f" # nf-md-backup_restore +net_modem = "\U000f03f2" # nf-md-phone +net_cellular = [ + "\U000F08FD", # nf-md-network_strength_off_outline + "\U000F08FE", # nf-md-network_strength_outline + "\U000F08F4", # nf-md-network_strength_1 + "\U000F08F6", # nf-md-network_strength_2 + "\U000F08F8", # nf-md-network_strength_3 + "\U000F08FA", # nf-md-network_strength_4 +] +net_up = "\U000f0552" # nf-md-upload +net_vpn = "\U000f0582" # nf-md-vpn +net_wired = "\U000f0200" # nf-md-ethernet +net_wireless = [ + "\U000F092F", # nf-md-wifi_strength_outline + "\U000F091F", # nf-md-wifi_strength_1 + "\U000F0922", # nf-md-wifi_strength_2 + "\U000F0925", # nf-md-wifi_strength_3 + "\U000F0928", # nf-md-wifi_strength_4 +] +notification = "\U000f009c" # nf-md-bell_outline +phone = "\U000f03f2" # nf-md-phone +phone_disconnected = "\U000f0658" # nf-md-phone_minus +ping = "\U000f051f" # nf-md-timer_sand +pomodoro = "\ue001" # nf-pom-pomodoro_done +pomodoro_break = "\U000f0176" # nf-md-coffee +pomodoro_paused = "\U000f03e4" # nf-md-pause +pomodoro_started = "\U000f040a" # nf-md-play +pomodoro_stopped = "\U000f04db" # nf-md-stop +resolution = "\U000f0293" # nf-md-fullscreen +tasks = "\U000f05c7" # nf-md-playlist_check +tea = "\U000f0d9e" # nf-md-tea +thermometer = [ + "\U000f10c3", # nf-md-thermometer_low + "\U000f050f", # nf-md-thermometer + "\U000f10c2", # nf-md-thermometer_high +] +time = "\U000f0150" # nf-md-clock_outline +toggle_off = "\U000f0a19" # nf-md-toggle_switch_off_outline +toggle_on = "\U000f0521" # nf-md-toggle_switch +unknown = "\U000f0186" # nf-md-comment_question_outline | TODO: Make default? +update = "\U000f03d5" # nf-md-package_up +uptime = "\U000f0153" # nf-md-clock_in +volume_muted = "\U000f075f" # nf-md-volume_mute +volume = [ + "\U000f057f", # nf-md-volume_low + "\U000f0580", # nf-md-volume_medium + "\U000f057e", # nf-md-volume_high +] +microphone_muted = "\U000f036d" # nf-md-microphone_off +microphone = [ + "\U000f036e", # nf-md-microphone_outline + "\U000f036c", # nf-md-microphone + "\U000f036c", # nf-md-microphone +] +xrandr = "\U000f037a" # nf-md-monitor_multiple + +# Weather icons (https://greshake.github.io/i3status-rust/i3status_rs/blocks/weather/index.html) +weather_sun = "\ue30d" # nf-weather-day_sunny (when weather is reported as “Clear” during the day) +weather_moon = "\ue32b" # nf-weather-night_clear (when weather is reported as “Clear” at night) +weather_clouds = "\ue312" # nf-weather-cloudy (when weather is reported as “Clouds” during the day) +weather_clouds_night = "\ue37e" # nf-weather-night_alt_cloudy (when weather is reported as “Clouds” at night) +weather_fog = "\ue313" # nf-weather-fog (when weather is reported as “Fog” or “Mist” during the day) +weather_fog_night = "\ue346" # nf-weather-night_fog (when weather is reported as “Fog” or “Mist” at night) +weather_rain = "\ue318" # nf-weather-rain (when weather is reported as “Rain” or “Drizzle” during the day) +weather_rain_night = "\ue325" # nf-weather-night_alt_rain (when weather is reported as “Rain” or “Drizzle” at night) +weather_snow = "\ue31a" # nf-weather-snow (when weather is reported as “Snow”) +weather_thunder = "\ue31d" # nf-weather-thunderstorm (when weather is reported as “Thunderstorm” during the day) +weather_thunder_night = "\ue32a" # nf-weather-night_alt_thunderstorm (when weather is reported as “Thunderstorm” at night) diff --git a/modules/i3status-rust/files/top-bar.toml b/modules/i3status-rust/files/top-bar.toml new file mode 100644 index 0000000..1166036 --- /dev/null +++ b/modules/i3status-rust/files/top-bar.toml @@ -0,0 +1,33 @@ +# The top bar (module i3status-rust, novox/hq ADR 0208): the focused window's title and the uptime. +# Owned by the mesh: replaced at every push. Adopted unchanged from the workstations of 2026-10-04. +icons_format = "{icon}" + +[theme] +theme = "plain" +[theme.overrides] +idle_bg = "#000000" +idle_fg = "#f1f1f1" +info_bg = "#000000" +info_fg = "#f1f1f1" +good_bg = "#000000" +good_fg = "#859900" +warning_bg = "#000000" +warning_fg = "#de5200" +critical_bg = "#000000" +critical_fg = "#ff0000" +separator = " | " +separator_fg = "#ffffff" +separator_bg = "#000000" + +[icons] +icons = "custom-icons" + +[[block]] +block = "focused_window" +[block.format] +full = " $title.str(max_w:50) |" +short = " $title.str(max_w:100) |" + +[[block]] +block = "uptime" +interval = 60 diff --git a/modules/i3status-rust/go.mod b/modules/i3status-rust/go.mod new file mode 100644 index 0000000..c13caf3 --- /dev/null +++ b/modules/i3status-rust/go.mod @@ -0,0 +1,5 @@ +module i3statusrust + +go 1.22 + +require git.novox.be/novox/mesh-sdk/go v0.1.7 diff --git a/modules/i3status-rust/go.sum b/modules/i3status-rust/go.sum new file mode 100644 index 0000000..b474419 --- /dev/null +++ b/modules/i3status-rust/go.sum @@ -0,0 +1,2 @@ +git.novox.be/novox/mesh-sdk/go v0.1.7 h1:C0sTQmtTiyYH7bnqZb7PusXnqA37gKuT7Nqjn9gG47w= +git.novox.be/novox/mesh-sdk/go v0.1.7/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= diff --git a/modules/i3status-rust/module.json b/modules/i3status-rust/module.json new file mode 100644 index 0000000..4510d6a --- /dev/null +++ b/modules/i3status-rust/module.json @@ -0,0 +1,118 @@ +{ + "module": "i3status-rust", + "version": "1", + "capabilities": [ + "package-manager" + ], + "requires": [ + "x11-display" + ], + "claims": [ + { + "name": "node-bar", + "scope": "node" + } + ], + "tools": [ + "i3status_rust_reload", + "i3status_rust_blocks", + "i3status_rust_block_run", + "i3status_rust_themes" + ], + "shell": [ + { + "for": "xinitrc", + "slot": "normal", + "code": "# The bar watchdog (module i3status-rust, novox/hq ADR 0208): i3 never restarts a bar that dies; this\n# brings it back. Once per session, ending with the session's own process ($$).\n\"$HOME/.local/bin/i3bar-watchdog\" \"$$\" &\n" + } + ], + "resources": [ + { + "id": "package", + "type": "package", + "package": "i3status-rust" + }, + { + "id": "update-check", + "type": "package", + "package": "pacman-contrib" + }, + { + "id": "configuration-dir", + "type": "directory", + "path": "${machine:account-home}/.config/i3status-rust", + "owner": "${machine:account}", + "mode": "0755" + }, + { + "id": "icons-dir", + "type": "directory", + "path": "${machine:account-home}/.config/i3status-rust/icons", + "owner": "${machine:account}", + "mode": "0755" + }, + { + "id": "top-bar", + "type": "file", + "path": "${machine:account-home}/.config/i3status-rust/top-bar.toml", + "owner": "${machine:account}", + "mode": "0644", + "content": "# The top bar (module i3status-rust, novox/hq ADR 0208): the focused window's title and the uptime.\n# Owned by the mesh: replaced at every push. Adopted unchanged from the workstations of 2026-10-04.\nicons_format = \"{icon}\"\n\n[theme]\ntheme = \"plain\"\n[theme.overrides]\nidle_bg = \"#000000\"\nidle_fg = \"#f1f1f1\"\ninfo_bg = \"#000000\"\ninfo_fg = \"#f1f1f1\"\ngood_bg = \"#000000\"\ngood_fg = \"#859900\"\nwarning_bg = \"#000000\"\nwarning_fg = \"#de5200\"\ncritical_bg = \"#000000\"\ncritical_fg = \"#ff0000\"\nseparator = \" | \"\nseparator_fg = \"#ffffff\"\nseparator_bg = \"#000000\"\n\n[icons]\nicons = \"custom-icons\"\n\n[[block]]\nblock = \"focused_window\"\n[block.format]\nfull = \" $title.str(max_w:50) |\"\nshort = \" $title.str(max_w:100) |\"\n\n[[block]]\nblock = \"uptime\"\ninterval = 60\n" + }, + { + "id": "bottom-bar", + "type": "file", + "path": "${machine:account-home}/.config/i3status-rust/bottom-bar.toml", + "owner": "${machine:account}", + "mode": "0644", + "content": "# The bottom bar (module i3status-rust, novox/hq ADR 0208). Owned by the mesh: replaced at every\n# push. Adopted from the workstations of 2026-10-04 with what follows a machine's hardware or one\n# person's devices left out: the battery and the GPU belong to a machine model's hardware module,\n# and a headset's address is not the bar's to know. Every block here works the same on any machine.\nicons_format = \"{icon}\"\n\n[theme]\ntheme = \"plain\"\n[theme.overrides]\nidle_bg = \"#000000\"\nidle_fg = \"#f1f1f1\"\ninfo_bg = \"#000000\"\ninfo_fg = \"#f1f1f1\"\ngood_bg = \"#000000\"\ngood_fg = \"#859900\"\nwarning_bg = \"#000000\"\nwarning_fg = \"#de5200\"\ncritical_bg = \"#000000\"\ncritical_fg = \"#ff0000\"\nseparator = \" | \"\nseparator_fg = \"#ffffff\"\nseparator_bg = \"#000000\"\n\n[icons]\nicons = \"custom-icons\"\n\n[[block]]\nblock = \"tea_timer\"\nformat = \"$icon{ $minutes:$seconds|}\"\ndone_cmd = \"notify-send 'Timer finished'\"\n\n# Pending updates: official and, where an AUR helper is installed, AUR. The script keeps the last good\n# count through a network gap and shows an error only after ten failed checks in a row. Click: the\n# list, in the launcher's menu.\n[[block]]\nblock = \"custom\"\ncommand = \"~/.local/bin/i3status-updates 10\"\njson = true\ninterval = 1800\n[[block.click]]\nbutton = \"left\"\ncmd = \"checkupdates | dmenu -l 20 -p Updates\"\n\n[[block]]\nblock = \"cpu\"\n\n[[block]]\nblock = \"disk_space\"\npath = \"/\"\ninfo_type = \"used\"\nalert_unit = \"GB\"\ninterval = 20\nwarning = 850\nalert = 920\nformat = \"$icon / $used.eng(w:2) ($percentage.eng(w:2))\"\n\n[[block]]\nblock = \"disk_space\"\npath = \"/home\"\ninfo_type = \"used\"\nalert_unit = \"GB\"\ninterval = 20\nwarning = 850\nalert = 920\nformat = \"$icon /home $used.eng(w:2) ($percentage.eng(w:2))\"\n\n[[block]]\nblock = \"memory\"\nformat = \"$icon $mem_total_used.eng(w:2) ($mem_total_used_percents.eng(w:2))\"\nformat_alt = \"$icon_swap $swap_used.eng(w:2) ($swap_used_percents.eng(w:2))\"\n\n[[block]]\nblock = \"docker\"\ninterval = 2\nformat = \"$icon $running/$total\"\n\n[[block]]\nblock = \"sound\"\n[[block.click]]\nbutton = \"left\"\ncmd = \"pavucontrol\"\n\n# The weather from the Norwegian Meteorological Institute, which needs no key, where the machine is.\n[[block]]\nblock = \"weather\"\nformat = \"$icon $weather_verbose ($location) $temp\"\nautolocate = true\nautolocate_interval = 600\n[block.service]\nname = \"metno\"\n\n[[block]]\nblock = \"notify\"\ndriver = \"dunst\"\nformat = \" $icon {($notification_count.eng(w:1))|}\"\n\n[[block]]\nblock = \"time\"\ninterval = 1\nformat = \"$timestamp.datetime(f:'%a %d/%m %H:%M:%S')\"\n" + }, + { + "id": "icons", + "type": "file", + "path": "${machine:account-home}/.config/i3status-rust/icons/custom-icons.toml", + "owner": "${machine:account}", + "mode": "0644", + "content": "# Icons for the bars (module i3status-rust, novox/hq ADR 0208), from the JetBrains Mono Nerd Font.\n# Owned by the mesh: replaced at every push. Adopted unchanged from the workstations of 2026-10-04.\n# Material from NerdFont\n# https://www.nerdfonts.com/cheat-sheet\nbacklight = [\n \"\\ue38d\", # nf-weather-moon_new\n \"\\ue3d4\", # nf-weather-moon_alt_waxing_gibbous_6\n \"\\ue3d3\", # nf-weather-moon_alt_waxing_gibbous_5\n \"\\ue3d2\", # nf-weather-moon_alt_waxing_gibbous_4\n \"\\ue3d1\", # nf-weather-moon_alt_waxing_gibbous_3\n \"\\ue3d0\", # nf-weather-moon_alt_waxing_gibbous_2\n \"\\ue3cf\", # nf-weather-moon_alt_waxing_gibbous_1\n \"\\ue3ce\", # nf-weather-moon_alt_first_quarter\n \"\\ue3cd\", # nf-weather-moon_alt_waxing_crescent_6\n \"\\ue3cc\", # nf-weather-moon_alt_waxing_crescent_5\n \"\\ue3cb\", # nf-weather-moon_alt_waxing_crescent_4\n \"\\ue3ca\", # nf-weather-moon_alt_waxing_crescent_3\n \"\\ue3c9\", # nf-weather-moon_alt_waxing_crescent_2\n \"\\ue3c8\", # nf-weather-moon_alt_waxing_crescent_1\n \"\\ue39b\", # nf-weather-moon_full\n]\nbat_charging = \"\\U000f0084\" # nf-md-battery_charging\nbat_not_available = \"\\U000f0091\" # nf-md-battery_unknown\nbat = [\n \"\\U000f007a\", # nf-md-battery_10\n \"\\U000f007b\", # nf-md-battery_20\n \"\\U000f007c\", # nf-md-battery_30\n \"\\U000f007d\", # nf-md-battery_40\n \"\\U000f007e\", # nf-md-battery_50\n \"\\U000f007f\", # nf-md-battery_60\n \"\\U000f0080\", # nf-md-battery_70\n \"\\U000f0081\", # nf-md-battery_80\n \"\\U000f0082\", # nf-md-battery_90\n \"\\U000f0079\", # nf-md-battery\n]\nbell = \"\\U000f009c\" # nf-md-bell_outline\nbell-slash = \"\\U000f009b\" # nf-md-bell_off\nblackberry = \"\\uf307\" # nf-md-blackberry\nbluetooth = \"\\U000f00af\" # nf-md-bluetooth\ncalendar = \"\\U000f00ed\" # nf-md-calendar\ncogs = \"\\U000f0493\" # nf-md-cog\ncpu = [\n\t\"\\U000F0F86\", # nf-md-speedometer_slow\n\t\"\\U000F0F85\", # nf-md-speedometer_medium\n\t\"\\U000F04C5\", # nf-md-speedometer\n]\ncpu_boost_on = \"\\U000f0521\" # nf-md-toggle_switch\ncpu_boost_off = \"\\U000f0a19\" # nf-md-toggle_switch_off_outline\ndisk_drive = \"\\U000f02ca\" # nf-md-harddisk\ndocker = \"\\uf308\" # nf-linux-docker\ngithub = \"\\U000f02a4\" # nf-md-github\ngpu = \"\\U000f0379\" # nf-md-monitor\nheadphones = \"\\U000f02cb\" # nf-md-headphones\njoystick = \"\\U000f0297\" # nf-md-gamepad_variant\nkeyboard = \"\\U000f030c\" # nf-md-keyboard\nmail = \"\\U000f01ee\" # nf-md-email\nmemory_mem = \"\\U000f035b\" # nf-md-memory\nmemory_swap = \"\\U000f02ca\" # nf-md-harddisk\nmouse = \"\\U000f037d\" # nf-md-mouse\nmusic = \"\\U000f075a\" # nf-md-music\nmusic_next = \"\\U000f04ad\" # nf-md-skip_next\nmusic_pause = \"\\U000f03e4\" # nf-md-pause\nmusic_play = \"\\U000f040a\" # nf-md-play\nmusic_prev = \"\\U000f04ae\" # nf-md-skip_previous\nnet_bridge = \"\\U000f04aa\" # nf-md-sitemap\nnet_down = \"\\U000f01da\" # nf-md-download\nnet_loopback = \"\\U000f006f\" # nf-md-backup_restore\nnet_modem = \"\\U000f03f2\" # nf-md-phone\nnet_cellular = [\n \"\\U000F08FD\", # nf-md-network_strength_off_outline\n \"\\U000F08FE\", # nf-md-network_strength_outline\n \"\\U000F08F4\", # nf-md-network_strength_1\n \"\\U000F08F6\", # nf-md-network_strength_2\n \"\\U000F08F8\", # nf-md-network_strength_3\n \"\\U000F08FA\", # nf-md-network_strength_4\n]\nnet_up = \"\\U000f0552\" # nf-md-upload\nnet_vpn = \"\\U000f0582\" # nf-md-vpn\nnet_wired = \"\\U000f0200\" # nf-md-ethernet\nnet_wireless = [\n\t\"\\U000F092F\", # nf-md-wifi_strength_outline\n\t\"\\U000F091F\", # nf-md-wifi_strength_1\n\t\"\\U000F0922\", # nf-md-wifi_strength_2\n\t\"\\U000F0925\", # nf-md-wifi_strength_3\n\t\"\\U000F0928\", # nf-md-wifi_strength_4\n]\nnotification = \"\\U000f009c\" # nf-md-bell_outline\nphone = \"\\U000f03f2\" # nf-md-phone\nphone_disconnected = \"\\U000f0658\" # nf-md-phone_minus\nping = \"\\U000f051f\" # nf-md-timer_sand\npomodoro = \"\\ue001\" # nf-pom-pomodoro_done\npomodoro_break = \"\\U000f0176\" # nf-md-coffee\npomodoro_paused = \"\\U000f03e4\" # nf-md-pause\npomodoro_started = \"\\U000f040a\" # nf-md-play\npomodoro_stopped = \"\\U000f04db\" # nf-md-stop\nresolution = \"\\U000f0293\" # nf-md-fullscreen\ntasks = \"\\U000f05c7\" # nf-md-playlist_check\ntea = \"\\U000f0d9e\" # nf-md-tea\nthermometer = [\n \"\\U000f10c3\", # nf-md-thermometer_low\n \"\\U000f050f\", # nf-md-thermometer\n \"\\U000f10c2\", # nf-md-thermometer_high\n]\ntime = \"\\U000f0150\" # nf-md-clock_outline\ntoggle_off = \"\\U000f0a19\" # nf-md-toggle_switch_off_outline\ntoggle_on = \"\\U000f0521\" # nf-md-toggle_switch\nunknown = \"\\U000f0186\" # nf-md-comment_question_outline | TODO: Make default?\nupdate = \"\\U000f03d5\" # nf-md-package_up\nuptime = \"\\U000f0153\" # nf-md-clock_in\nvolume_muted = \"\\U000f075f\" # nf-md-volume_mute\nvolume = [\n \"\\U000f057f\", # nf-md-volume_low\n \"\\U000f0580\", # nf-md-volume_medium\n \"\\U000f057e\", # nf-md-volume_high\n]\nmicrophone_muted = \"\\U000f036d\" # nf-md-microphone_off\nmicrophone = [\n\t\"\\U000f036e\", # nf-md-microphone_outline\n \"\\U000f036c\", # nf-md-microphone\n \"\\U000f036c\", # nf-md-microphone\n]\nxrandr = \"\\U000f037a\" # nf-md-monitor_multiple\n\n# Weather icons (https://greshake.github.io/i3status-rust/i3status_rs/blocks/weather/index.html)\nweather_sun = \"\\ue30d\" # nf-weather-day_sunny (when weather is reported as “Clear” during the day)\nweather_moon = \"\\ue32b\" # nf-weather-night_clear (when weather is reported as “Clear” at night)\nweather_clouds = \"\\ue312\" # nf-weather-cloudy (when weather is reported as “Clouds” during the day)\nweather_clouds_night = \"\\ue37e\" # nf-weather-night_alt_cloudy (when weather is reported as “Clouds” at night)\nweather_fog = \"\\ue313\" # nf-weather-fog (when weather is reported as “Fog” or “Mist” during the day)\nweather_fog_night = \"\\ue346\" # nf-weather-night_fog (when weather is reported as “Fog” or “Mist” at night)\nweather_rain = \"\\ue318\" # nf-weather-rain (when weather is reported as “Rain” or “Drizzle” during the day)\nweather_rain_night = \"\\ue325\" # nf-weather-night_alt_rain (when weather is reported as “Rain” or “Drizzle” at night)\nweather_snow = \"\\ue31a\" # nf-weather-snow (when weather is reported as “Snow”)\nweather_thunder = \"\\ue31d\" # nf-weather-thunderstorm (when weather is reported as “Thunderstorm” during the day)\nweather_thunder_night = \"\\ue32a\" # nf-weather-night_alt_thunderstorm (when weather is reported as “Thunderstorm” at night)\n" + }, + { + "id": "updates", + "type": "file", + "path": "${machine:account-home}/.local/bin/i3status-updates", + "owner": "${machine:account}", + "mode": "0755", + "content": "#!/usr/bin/env bash\n# i3status-updates [threshold] (module i3status-rust, novox/hq ADR 0208): the pending updates, for\n# the bottom bar's custom block (json = true). Emits one JSON line.\n#\n# Adopted from the operator's pkg-updates of 2026-10-04. The native `packages` block showed a raw\n# red error on every transient network failure, which on a roaming laptop is often. This keeps the\n# last good result through a failure and shows an error only after `threshold` failures in a row\n# (default 10). Official packages through checkupdates (pacman-contrib, a temporary database, no\n# root); AUR packages through paru when it is installed, and none counted when it is not.\nset -uo pipefail\n\nthreshold=\"${1:-10}\"\nicon=\"update\"\nstate_dir=\"${XDG_RUNTIME_DIR:-/tmp}/i3status-updates\"\nmkdir -p \"$state_dir\"\nlast=\"$state_dir/last_good.json\"\nfailures=\"$state_dir/failures\"\n\njson() { printf '{\"icon\":\"%s\",\"state\":\"%s\",\"text\":\"%s\",\"short_text\":\"%s\"}' \"$icon\" \"$1\" \"$2\" \"$3\"; }\ncount() { [ -n \"$1\" ] && printf '%s\\n' \"$1\" | grep -c . || echo 0; }\n\nofficial=\"$(checkupdates 2>/dev/null)\"\nofficial_rc=$?\naur=\"\" aur_rc=0\nif command -v paru >/dev/null 2>&1; then\n\taur=\"$(paru -Qua 2>/dev/null)\"\n\taur_rc=$?\nfi\n\n# checkupdates: 0 updates listed, 2 none pending; anything else is a failure.\nif { [ \"$official_rc\" -eq 0 ] || [ \"$official_rc\" -eq 2 ]; } && [ \"$aur_rc\" -eq 0 ]; then\n\to=\"$(count \"$official\")\"\n\ta=\"$(count \"$aur\")\"\n\ttotal=$((o + a))\n\tif [ \"$total\" -eq 0 ]; then\n\t\tpayload=\"$(json Good \"up to date\" \"\")\"\n\telse\n\t\t# A kernel update wants a reboot: the one worth not putting off.\n\t\tstate=Info\n\t\tprintf '%s\\n' \"$official\" | grep -qE '^(linux|linux-lts|linux-zen) ' && state=Warning\n\t\tlabel=\"$o + $a = $total updates\"\n\t\t[ \"$a\" -eq 0 ] && label=\"$total updates\"\n\t\t[ \"$total\" -eq 1 ] && label=\"1 update\"\n\t\tpayload=\"$(json \"$state\" \"$label\" \"$total\")\"\n\tfi\n\tprintf '%s' \"$payload\" >\"$last\"\n\tprintf '0' >\"$failures\"\n\tprintf '%s\\n' \"$payload\"\n\texit 0\nfi\n\nn=$(($(cat \"$failures\" 2>/dev/null || echo 0) + 1))\nprintf '%s' \"$n\" >\"$failures\"\nif [ \"$n\" -ge \"$threshold\" ]; then\n\tjson Critical \"update check failing (${n}x)\" \"!\"\n\techo\nelif [ -s \"$last\" ]; then\n\tcat \"$last\"\n\techo\nelse\n\tjson Idle \"\" \"\"\n\techo\nfi\n" + }, + { + "id": "watchdog", + "type": "file", + "path": "${machine:account-home}/.local/bin/i3bar-watchdog", + "owner": "${machine:account}", + "mode": "0755", + "content": "#!/usr/bin/env bash\n# i3bar-watchdog [session-pid] (module i3status-rust, novox/hq ADR 0208): respawns a bar that died.\n#\n# i3 starts one i3bar per `bar { }` block and never restarts one that exits, and a reload does not\n# either. Changing the monitor setup reliably kills the bar that owns the tray. This brings back the\n# one missing i3bar, without restarting i3, and logs the outputs at that moment: the evidence for the\n# cause, which is i3bar's.\n#\n# Started once per session from the session's start, with the session's own pid; it ends when that\n# process does. Adopted from the predecessor's i3-bar-watchdog user unit of 2026-10-04.\nset -uo pipefail\n\nsession_pid=\"${1:-}\"\ninterval=\"${I3_BAR_WATCHDOG_INTERVAL:-5}\"\n# Two misses in a row before acting: an i3 restart tears every bar down and starts them again.\nconfirm=\"${I3_BAR_WATCHDOG_CONFIRM:-2}\"\n# Never respawn the same bar more often than this, so a bar that dies at once is not a tight loop.\ncooldown=\"${I3_BAR_WATCHDOG_COOLDOWN:-30}\"\n\nlog() { printf 'i3bar-watchdog: %s\\n' \"$*\" >&2; }\n\nfor tool in i3-msg i3bar pgrep; do\n\tcommand -v \"$tool\" >/dev/null 2>&1 || {\n\t\tlog \"$tool is missing; not watching\"\n\t\texit 1\n\t}\ndone\n\ndeclare -A missed=() fixed=()\n\nbar_ids() { i3-msg -t get_bar_config 2>/dev/null | grep -oE '\"[^\"]+\"' | tr -d '\"'; }\noutputs() { xrandr --listmonitors 2>/dev/null | tail -n +2 | awk '{print $2\" \"$3}' | tr '\\n' ' '; }\nsession_alive() { [ -z \"$session_pid\" ] || kill -0 \"$session_pid\" 2>/dev/null; }\n\nwhile session_alive; do\n\tsleep \"$interval\"\n\tsocket=\"$(i3 --get-socketpath 2>/dev/null)\"\n\t[ -n \"$socket\" ] && [ -S \"$socket\" ] || continue\n\tids=\"$(bar_ids)\"\n\t[ -n \"$ids\" ] || continue\n\twhile read -r id; do\n\t\t[ -n \"$id\" ] || continue\n\t\tif pgrep -u \"$EUID\" -f -- \"i3bar --bar_id=$id\" >/dev/null 2>&1; then\n\t\t\tmissed[$id]=0\n\t\t\tcontinue\n\t\tfi\n\t\tmissed[$id]=$((${missed[$id]:-0} + 1))\n\t\t[ \"${missed[$id]}\" -ge \"$confirm\" ] || continue\n\t\tnow=\"$(date +%s)\"\n\t\tif [ $((now - ${fixed[$id]:-0})) -lt \"$cooldown\" ]; then\n\t\t\tcontinue\n\t\tfi\n\t\tlog \"$id is gone; respawning it. Outputs now: $(outputs)\"\n\t\tnohup i3bar --bar_id=\"$id\" --socket=\"$socket\" >/dev/null 2>&1 &\n\t\tdisown 2>/dev/null || true\n\t\tfixed[$id]=\"$now\"\n\t\tsleep 2\n\t\tif pgrep -u \"$EUID\" -f -- \"i3bar --bar_id=$id\" >/dev/null 2>&1; then\n\t\t\tmissed[$id]=0\n\t\telse\n\t\t\tlog \"$id exited within 2s of respawning; check its status_command\"\n\t\tfi\n\tdone <<<\"$ids\"\ndone\n" + }, + { + "id": "i3-bars", + "type": "file", + "path": "${machine:account-home}/.config/i3/config.d/60-i3status-rust.conf", + "owner": "${machine:account}", + "mode": "0644", + "content": "# The bars (module i3status-rust, novox/hq ADR 0208). Owned by the mesh: replaced at every push.\n# i3 reads this file through its configuration's `include ~/.config/i3/config.d/*.conf`. The bottom\n# bar shows the machine; the top bar the focused window and the tray, on the primary output. The\n# face is the monospace one every desktop module names.\nbar {\n font pango:JetBrainsMono Nerd Font 11\n position bottom\n status_command i3status-rs ~/.config/i3status-rust/bottom-bar.toml\n tray_output none\n colors {\n separator #ffffff\n background #000000\n statusline #ffffff\n # The text on an accent-coloured button is dark: light text on the accent was barely\n # legible.\n focused_workspace #de5200 #de5200 #000000\n active_workspace #de5200 #de5200 #000000\n inactive_workspace #000000 #000000 #ffffff\n urgent_workspace #2f343a #900000 #ffffff\n }\n}\n\nbar {\n font pango:JetBrainsMono Nerd Font 11\n position top\n status_command i3status-rs ~/.config/i3status-rust/top-bar.toml\n workspace_buttons no\n tray_output primary\n colors {\n separator #ffffff\n background #000000\n statusline #ffffff\n }\n}\n" + } + ], + "build": { + "artifacts": [ + { + "name": "tools", + "kind": "bundle", + "language": "go", + "system": "arch", + "from": "cmd/i3status-rust-tools", + "binary": "i3status-rust-tools", + "loads": [ + "i3status-rust-tools" + ] + } + ] + } +} From e810afb3eb2dd817926cc953fe281231d6b5f180 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 4 Oct 2026 13:07:06 +0200 Subject: [PATCH 08/15] gnome-keyring: the secret service as a module, claiming node-secret-service (hq ADR 0208, ADR 0102) PAM lines written into login and passwd as blocks, so login unlocks the keyring on both workstations; no daemon of its own; gcr's ssh agent named for the session until the environment can say a runtime-directory path. Go tools unlocked, lock, collections and ssh-keys, never reading a secret. --- modules/gnome-keyring/README.md | 101 +++++ .../cmd/gnome-keyring-tools/args.go | 97 ++++ .../cmd/gnome-keyring-tools/keyring.go | 260 +++++++++++ .../cmd/gnome-keyring-tools/keyring_test.go | 131 ++++++ .../cmd/gnome-keyring-tools/main.go | 57 +++ .../manifest_helpers_test.go | 175 ++++++++ .../cmd/gnome-keyring-tools/manifest_test.go | 64 +++ .../cmd/gnome-keyring-tools/session.go | 423 ++++++++++++++++++ .../cmd/gnome-keyring-tools/session_test.go | 174 +++++++ modules/gnome-keyring/files/pam/login | 4 + modules/gnome-keyring/files/pam/passwd | 3 + modules/gnome-keyring/go.mod | 5 + modules/gnome-keyring/go.sum | 2 + modules/gnome-keyring/module.json | 76 ++++ 14 files changed, 1572 insertions(+) create mode 100644 modules/gnome-keyring/README.md create mode 100644 modules/gnome-keyring/cmd/gnome-keyring-tools/args.go create mode 100644 modules/gnome-keyring/cmd/gnome-keyring-tools/keyring.go create mode 100644 modules/gnome-keyring/cmd/gnome-keyring-tools/keyring_test.go create mode 100644 modules/gnome-keyring/cmd/gnome-keyring-tools/main.go create mode 100644 modules/gnome-keyring/cmd/gnome-keyring-tools/manifest_helpers_test.go create mode 100644 modules/gnome-keyring/cmd/gnome-keyring-tools/manifest_test.go create mode 100644 modules/gnome-keyring/cmd/gnome-keyring-tools/session.go create mode 100644 modules/gnome-keyring/cmd/gnome-keyring-tools/session_test.go create mode 100644 modules/gnome-keyring/files/pam/login create mode 100644 modules/gnome-keyring/files/pam/passwd create mode 100644 modules/gnome-keyring/go.mod create mode 100644 modules/gnome-keyring/go.sum create mode 100644 modules/gnome-keyring/module.json diff --git a/modules/gnome-keyring/README.md b/modules/gnome-keyring/README.md new file mode 100644 index 0000000..bf943e9 --- /dev/null +++ b/modules/gnome-keyring/README.md @@ -0,0 +1,101 @@ +# gnome-keyring + +The secret service as a module (novox/hq ADR 0208, ADR 0102). + +- Installs `gnome-keyring` (it brings `gcr-4`, whose ssh agent this uses), `libsecret` (the client + library and `secret-tool`) and `seahorse` (the keyrings' manager, for the operator). +- Claims the mesh's `node-secret-service` seat (no verbs yet, ADR 0208 §2). It requires no display: + the secret service is a D-Bus service, and a Wayland session uses the same module. +- **Writes the PAM lines into the stacks, never over them** (ADR 0102). Each is a marked block at the + end of the file; every other line stays the distribution's. + - `/etc/pam.d/login`: `auth optional pam_gnome_keyring.so` and + `session optional pam_gnome_keyring.so auto_start`. The login manager's stack includes `login`, + so the password typed at the login screen unlocks the login keyring, and the login session starts + the daemon. + - `/etc/pam.d/passwd`: `password optional pam_gnome_keyring.so`, so changing the account's password + changes the keyring's, and the next login still unlocks it. +- **Starts no daemon.** PAM starts it at login, and D-Bus would if PAM had not. +- Names gcr's ssh agent socket for the session, in the `xinitrc` slot `first`: `SSH_AUTH_SOCK` is + `$XDG_RUNTIME_DIR/gcr/ssh`. The agent itself is `gcr-ssh-agent.socket`, a user unit the package + enables by preset. + +## Tools + +None reads a secret. They ask the Secret Service for names, counts and lock states, and the agent for +fingerprints. + +| tool | does | +|---|---| +| `gnome_keyring_unlocked` | the login and default keyrings, locked or not; whether the daemon runs | +| `gnome_keyring_lock` | lock a keyring now (login by default); unlocking stays the operator's | +| `gnome_keyring_collections` | every keyring: id, label, locked, item count, created, changed, default | +| `gnome_keyring_ssh_keys` | the agent's keys by fingerprint, size, type and comment | + +## What it improves on what was found + +- **The desktop's login unlocks the keyring.** Its `/etc/pam.d/login` had no keyring lines, so the + keyring stayed locked after every login, and a script prompted for the password to unlock it. Both + workstations now get the same lines. +- **One daemon.** The session's start ran `gnome-keyring-daemon --start` a second time, asking for an + ssh component that gnome-keyring no longer has, and the window manager ran an unlock-prompt script. + Both go. +- **The session has an ssh agent.** The found `export SSH_AUTH_SOCK` exported nothing: the second + daemon printed no socket. The session's processes had no agent, although gcr's was listening. + +## The default keyring is not the login keyring + +On both workstations, measured on 2026-10-04, the default keyring, where programs store new secrets, +is a second keyring, `Default_keyring`. The login keyring holds one item at most. PAM unlocks only the +login keyring. Another keyring opens with it only if its password is stored in the login keyring +("unlock automatically"). On the desktop the login keyring was locked and the default one unlocked, +which the unlock-prompt script did. + +After the first login with this module: `gnome_keyring_unlocked` shows both. If the default keyring +is still locked, choose one, once, in `seahorse`: + +- tick its *unlock automatically* when prompted; +- or move its items into the login keyring and make that the default. + +Which keyring is the default is the operator's data, never the module's. + +## Blockers and a proposal + +**`SSH_AUTH_SOCK` belongs in the account's environment, and ADR 0203 cannot say it yet.** The value +is a path under the account's runtime directory (`/run/user/`). ADR 0203 forbids `$` in a +contributed value, and no `${machine:…}` fact names that directory. So today the variable reaches +only the X session and what it starts, through the `xinitrc` slot. An ssh login, the login shell's +`execute` and the user manager's services do not get it. + +**Proposed:** a machine fact `${machine:account-runtime-dir}`, resolved like `${machine:account-home}` +from the account's uid. The variable then becomes an environment contribution: + +> `environment.variables.SSH_AUTH_SOCK` = `${machine:account-runtime-dir}/gcr/ssh` + +The slot contribution then goes. That is a progressive insight on ADR 0203, or a small record of its +own. It changes the controller's machine facts, not this module's shape. + +**User-scoped units (mesh-host #72).** `gcr-ssh-agent.socket` and `gnome-keyring-daemon.socket` are +enabled by the package's presets on both workstations, and nothing in the mesh asserts it. Once user +units ship, this module should declare both enabled. + +## What it leaves as found + +- The keyrings themselves (`~/.local/share/keyrings/`): the operator's data, never touched. +- `~/.config/i3/unlock-keyring.sh`, the unlock-prompt script. + +## Migration (ADR 0182) + +1. **On the laptop,** `/etc/pam.d/login` already has the two lines outside any block. After the first + push they are there twice. Delete the two hand-written ones, outside the `# BEGIN mesh` block. +2. Once the `xorg` module writes the session's start, delete from your own part of `~/.xinitrc` the + `eval $(/usr/bin/gnome-keyring-daemon --start …)` line and the `export SSH_AUTH_SOCK` after it. +3. Once the `i3` module carries the main configuration, its `exec … unlock-keyring.sh` line is gone. + Delete `~/.config/i3/unlock-keyring.sh`. +4. **On the desktop,** log in again after the first push. The keyring is unlocked by the login from + then on. + +## Blockers + +- `node-secret-service` and the `xinitrc` slot are ADR 0208's. Until the controller knows them, + `mctl` reads them as unknown. +- The environment fact above, and user-scoped units (mesh-host #72). diff --git a/modules/gnome-keyring/cmd/gnome-keyring-tools/args.go b/modules/gnome-keyring/cmd/gnome-keyring-tools/args.go new file mode 100644 index 0000000..9b5dfcf --- /dev/null +++ b/modules/gnome-keyring/cmd/gnome-keyring-tools/args.go @@ -0,0 +1,97 @@ +// Reading a tool's arguments: JSON numbers arrive as float64, and a missing argument is its default. +// The same in every desktop module that carries it. +package main + +import ( + "fmt" + "math" + "strings" + "time" +) + +// text is a string argument, trimmed; required says an empty one is refused. +func text(args map[string]any, key string, required bool) (string, error) { + v, present := args[key] + if !present || v == nil { + if required { + return "", fmt.Errorf("%s is required", key) + } + return "", nil + } + s, ok := v.(string) + if !ok { + return "", fmt.Errorf("%s is a string, not %T", key, v) + } + s = strings.TrimSpace(s) + if s == "" && required { + return "", fmt.Errorf("%s is required", key) + } + return s, nil +} + +// whole is a whole-number argument within [least, most], or def when absent. +func whole(args map[string]any, key string, def, least, most int) (int, error) { + v, present := args[key] + if !present || v == nil { + return def, nil + } + f, ok := v.(float64) + if !ok { + if i, isInt := v.(int); isInt { + f = float64(i) + } else { + return 0, fmt.Errorf("%s is a number, not %T", key, v) + } + } + if f != math.Trunc(f) { + return 0, fmt.Errorf("%s is a whole number, not %v", key, f) + } + n := int(f) + if n < least || n > most { + return 0, fmt.Errorf("%s is %d; it is between %d and %d", key, n, least, most) + } + return n, nil +} + +// flag is a boolean argument, or def when absent. +func flag(args map[string]any, key string, def bool) (bool, error) { + v, present := args[key] + if !present || v == nil { + return def, nil + } + b, ok := v.(bool) + if !ok { + return false, fmt.Errorf("%s is true or false, not %T", key, v) + } + return b, nil +} + +// texts is a list-of-strings argument. +func texts(args map[string]any, key string) ([]string, error) { + v, present := args[key] + if !present || v == nil { + return nil, nil + } + list, ok := v.([]any) + if !ok { + if ss, isStrings := v.([]string); isStrings { + return ss, nil + } + return nil, fmt.Errorf("%s is a list of strings, not %T", key, v) + } + out := make([]string, 0, len(list)) + for i, item := range list { + s, ok := item.(string) + if !ok { + return nil, fmt.Errorf("%s[%d] is a string, not %T", key, i, item) + } + out = append(out, s) + } + return out, nil +} + +// seconds is a timeout argument in seconds, defaulted and bounded below the runtime's call limit. +func seconds(args map[string]any, key string, def, most int) (time.Duration, error) { + n, err := whole(args, key, def, 1, most) + return time.Duration(n) * time.Second, err +} diff --git a/modules/gnome-keyring/cmd/gnome-keyring-tools/keyring.go b/modules/gnome-keyring/cmd/gnome-keyring-tools/keyring.go new file mode 100644 index 0000000..04d9149 --- /dev/null +++ b/modules/gnome-keyring/cmd/gnome-keyring-tools/keyring.go @@ -0,0 +1,260 @@ +package main + +import ( + "encoding/json" + "fmt" + "path/filepath" + "regexp" + "sort" + "strconv" + "strings" + "time" +) + +const ( + service = "org.freedesktop.secrets" + servicePath = "/org/freedesktop/secrets" + collectionDir = "/org/freedesktop/secrets/collection/" + busTimeout = 10 * time.Second +) + +// busctl runs one busctl call on the account's session bus and answers its JSON. +func busctl(s Session, args ...string) (json.RawMessage, error) { + r, err := s.run(busTimeout, "", "busctl", append([]string{"--user", "--json=short"}, args...)...) + if err != nil { + return nil, err + } + if r.Code != 0 { + return nil, fmt.Errorf("the secret service: %s", strings.TrimSpace(r.Stderr)) + } + var v struct { + Data json.RawMessage `json:"data"` + } + if err := json.Unmarshal([]byte(r.Stdout), &v); err != nil { + return nil, fmt.Errorf("busctl answered no JSON: %w", err) + } + return v.Data, nil +} + +// collectionID is the part of a collection's object path after .../collection/, unescaped the way +// the Secret Service escapes it ("_5f" is "_"). +func collectionID(path string) string { return strings.TrimPrefix(path, collectionDir) } + +func collectionPath(id string) string { return collectionDir + id } + +var validID = regexp.MustCompile(`^[A-Za-z0-9_]+$`) + +// Collection is one keyring. +type Collection struct { + ID string `json:"id"` + Label string `json:"label"` + Locked bool `json:"locked"` + Items int `json:"items"` + Created string `json:"created,omitempty"` + Modified string `json:"modified,omitempty"` + Default bool `json:"default,omitempty"` +} + +// CollectionsResult is what gnome_keyring_collections answers. +type CollectionsResult struct { + Collections []Collection `json:"collections"` +} + +func paths(s Session) ([]string, error) { + raw, err := busctl(s, "get-property", service, servicePath, "org.freedesktop.Secret.Service", "Collections") + if err != nil { + return nil, err + } + var out []string + if err := json.Unmarshal(raw, &out); err != nil { + return nil, fmt.Errorf("the collections: %w", err) + } + return out, nil +} + +func defaultCollection(s Session) string { + raw, err := busctl(s, "call", service, servicePath, "org.freedesktop.Secret.Service", "ReadAlias", "s", "default") + if err != nil { + return "" + } + var out []string + if json.Unmarshal(raw, &out) != nil || len(out) == 0 || out[0] == "/" { + return "" + } + return collectionID(out[0]) +} + +// describe reads a collection's properties: label, lock, the number of items (never the items), times. +func describe(s Session, path string) (Collection, error) { + raw, err := busctl(s, "call", service, path, "org.freedesktop.DBus.Properties", "GetAll", "s", "org.freedesktop.Secret.Collection") + if err != nil { + return Collection{}, err + } + return parseCollection(path, raw) +} + +func parseCollection(path string, raw json.RawMessage) (Collection, error) { + var answer []map[string]struct { + Data json.RawMessage `json:"data"` + } + if err := json.Unmarshal(raw, &answer); err != nil || len(answer) != 1 { + return Collection{}, fmt.Errorf("collection %s: not a property map", path) + } + p := answer[0] + c := Collection{ID: collectionID(path)} + _ = json.Unmarshal(p["Label"].Data, &c.Label) + _ = json.Unmarshal(p["Locked"].Data, &c.Locked) + var items []string + _ = json.Unmarshal(p["Items"].Data, &items) + c.Items = len(items) + for key, into := range map[string]*string{"Created": &c.Created, "Modified": &c.Modified} { + var t int64 + if json.Unmarshal(p[key].Data, &t) == nil && t > 0 { + *into = time.Unix(t, 0).Format(time.RFC3339) + } + } + return c, nil +} + +// Collections are the operator's keyrings. +func Collections() (CollectionsResult, error) { + s, err := findBus() + if err != nil { + return CollectionsResult{}, err + } + ps, err := paths(s) + if err != nil { + return CollectionsResult{}, err + } + def := defaultCollection(s) + out := CollectionsResult{Collections: []Collection{}} + for _, p := range ps { + c, err := describe(s, p) + if err != nil { + return CollectionsResult{}, err + } + c.Default = c.ID == def + out.Collections = append(out.Collections, c) + } + sort.Slice(out.Collections, func(i, j int) bool { return out.Collections[i].ID < out.Collections[j].ID }) + return out, nil +} + +// UnlockedResult is what gnome_keyring_unlocked answers. +type UnlockedResult struct { + Daemon bool `json:"daemon_running"` + Login *Collection `json:"login,omitempty"` + Default *Collection `json:"default,omitempty"` + Note string `json:"note,omitempty"` +} + +// Unlocked is whether the login and default keyrings are unlocked. +func Unlocked() (UnlockedResult, error) { + s, err := findBus() + if err != nil { + return UnlockedResult{}, err + } + // gnome-keyring-daemon, as the kernel shortens a command's name to 15 characters. + out := UnlockedResult{Daemon: len(processesOf("gnome-keyring-d")) > 0} + if c, err := describe(s, collectionPath("login")); err == nil { + out.Login = &c + } else { + out.Note = "no login keyring: " + err.Error() + } + if def := defaultCollection(s); def != "" && def != "login" { + if c, err := describe(s, collectionPath(def)); err == nil { + c.Default = true + out.Default = &c + } + } else if out.Login != nil { + out.Login.Default = def == "login" + } + return out, nil +} + +// LockResult is what gnome_keyring_lock answers. +type LockResult struct { + Collection string `json:"collection"` + Locked bool `json:"locked"` +} + +// Lock locks one keyring. +func Lock(id string) (LockResult, error) { + if id == "" { + id = "login" + } + if !validID.MatchString(id) { + return LockResult{}, fmt.Errorf("collection %q is not a keyring id", id) + } + s, err := findBus() + if err != nil { + return LockResult{}, err + } + if _, err := busctl(s, "call", service, servicePath, "org.freedesktop.Secret.Service", "Lock", "ao", "1", collectionPath(id)); err != nil { + return LockResult{}, err + } + c, err := describe(s, collectionPath(id)) + if err != nil { + return LockResult{}, err + } + return LockResult{Collection: id, Locked: c.Locked}, nil +} + +// Key is one key the ssh agent holds. +type Key struct { + Bits int `json:"bits"` + Fingerprint string `json:"fingerprint"` + Comment string `json:"comment"` + Type string `json:"type"` +} + +// SSHKeysResult is what gnome_keyring_ssh_keys answers. +type SSHKeysResult struct { + Agent string `json:"agent"` + Keys []Key `json:"keys"` + Note string `json:"note,omitempty"` +} + +// agentSocket is gcr's ssh agent socket, which its user socket unit listens on. +func agentSocket(s Session) string { return filepath.Join(s.RuntimeDir, "gcr", "ssh") } + +var keyLine = regexp.MustCompile(`^(\d+)\s+(\S+)\s+(.*?)\s*\(([A-Z0-9-]+)\)$`) + +func parseKeys(out string) []Key { + keys := []Key{} + for _, line := range strings.Split(out, "\n") { + m := keyLine.FindStringSubmatch(strings.TrimSpace(line)) + if m == nil { + continue + } + bits, _ := strconv.Atoi(m[1]) + keys = append(keys, Key{Bits: bits, Fingerprint: m[2], Comment: m[3], Type: m[4]}) + } + return keys +} + +// SSHKeys lists what gcr's ssh agent holds, by fingerprint. +func SSHKeys() (SSHKeysResult, error) { + s, err := findBus() + if err != nil { + return SSHKeysResult{}, err + } + sock := agentSocket(s) + // The agent is named for this one command only; nothing else of the tool's environment changes. + r, err := s.run(busTimeout, "", "env", "SSH_AUTH_SOCK="+sock, "ssh-add", "-l", "-E", "sha256") + if err != nil { + return SSHKeysResult{}, err + } + out := SSHKeysResult{Agent: sock, Keys: parseKeys(r.Stdout)} + switch r.Code { + case 0: + case 1: + out.Note = "the agent holds no keys" + case 127: + return SSHKeysResult{}, fmt.Errorf("ssh-add is not installed on this machine") + default: + return SSHKeysResult{}, fmt.Errorf("the ssh agent at %s does not answer: %s (is gcr-ssh-agent.socket enabled?)", + sock, strings.TrimSpace(r.Stderr)) + } + return out, nil +} diff --git a/modules/gnome-keyring/cmd/gnome-keyring-tools/keyring_test.go b/modules/gnome-keyring/cmd/gnome-keyring-tools/keyring_test.go new file mode 100644 index 0000000..b824495 --- /dev/null +++ b/modules/gnome-keyring/cmd/gnome-keyring-tools/keyring_test.go @@ -0,0 +1,131 @@ +package main + +import ( + "errors" + "os" + "path/filepath" + "strconv" + "strings" + "testing" +) + +const nobody = 4194400 + +// secretService fakes busctl answering as gnome-keyring did on 2026-10-04: a session, a login and a +// default keyring, the login one unlocked; Lock locks it. +func secretService(t *testing.T) string { + t.Helper() + fakeMachine(t) + runtime := filepath.Join(runUserDir, strconv.Itoa(os.Getuid())) + if err := os.MkdirAll(runtime, 0o700); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(runtime, "bus"), nil, 0o600); err != nil { + t.Fatal(err) + } + bin := fakeBinaries(t, map[string]string{"busctl": `echo "$*" >> "$LOG" +locked=false; [ -f "$LOG.locked" ] && locked=true +case "$*" in + *"get-property org.freedesktop.secrets /org/freedesktop/secrets org.freedesktop.Secret.Service Collections") + echo '{"type":"ao","data":["/org/freedesktop/secrets/collection/session","/org/freedesktop/secrets/collection/login","/org/freedesktop/secrets/collection/Default_5fkeyring"]}' ;; + *"ReadAlias s default") echo '{"type":"o","data":["/org/freedesktop/secrets/collection/Default_5fkeyring"]}' ;; + *"/collection/login org.freedesktop.DBus.Properties GetAll"*) + echo '{"type":"a{sv}","data":[{"Items":{"type":"ao","data":["/x/1","/x/2"]},"Label":{"type":"s","data":"Login"},"Locked":{"type":"b","data":'$locked'},"Created":{"type":"t","data":1752488320},"Modified":{"type":"t","data":0}}]}' ;; + *"/collection/"*"GetAll"*) + echo '{"type":"a{sv}","data":[{"Items":{"type":"ao","data":[]},"Label":{"type":"s","data":"Other"},"Locked":{"type":"b","data":true},"Created":{"type":"t","data":0},"Modified":{"type":"t","data":0}}]}' ;; + *"Lock ao 1 /org/freedesktop/secrets/collection/login") touch "$LOG.locked"; echo '{"type":"aoo","data":[["/org/freedesktop/secrets/collection/login"],"/"]}' ;; + *) echo "no such call: $*" >&2; exit 1 ;; +esac`}) + t.Setenv("LOG", filepath.Join(bin, "log")) + return bin +} + +func TestCollectionsAreNamesCountsAndLocksNeverItems(t *testing.T) { + bin := secretService(t) + got, err := Collections() + if err != nil { + t.Fatal(err) + } + if len(got.Collections) != 3 { + t.Fatalf("%+v", got) + } + var login, def Collection + for _, c := range got.Collections { + switch c.ID { + case "login": + login = c + case "Default_5fkeyring": + def = c + } + } + if login.Label != "Login" || login.Locked || login.Items != 2 || login.Created == "" || login.Modified != "" || login.Default { + t.Fatalf("login: %+v", login) + } + if !def.Default || !def.Locked { + t.Fatalf("default: %+v", def) + } + asked, _ := os.ReadFile(filepath.Join(bin, "log")) + if strings.Contains(string(asked), "GetSecret") || strings.Contains(string(asked), "Item") && strings.Contains(string(asked), "Secret.Item") { + t.Fatalf("a secret was asked for:\n%s", asked) + } +} + +func TestUnlockedAnswersTheLoginAndTheDefaultKeyring(t *testing.T) { + secretService(t) + fakeProcess(t, nobody, "gnome-keyring-d") + got, err := Unlocked() + if err != nil || !got.Daemon || got.Login == nil || got.Login.Locked || got.Default == nil || !got.Default.Default { + t.Fatalf("%+v, %v", got, err) + } +} + +func TestLockLocksTheLoginKeyringAndRefusesAPathForAnId(t *testing.T) { + secretService(t) + got, err := Lock("") + if err != nil || got.Collection != "login" || !got.Locked { + t.Fatalf("%+v, %v", got, err) + } + for _, bad := range []string{"../service", "login /org/x", "a b"} { + if _, err := Lock(bad); err == nil { + t.Errorf("%q was accepted", bad) + } + } +} + +func TestTheAgentsKeysAreFingerprints(t *testing.T) { + keys := parseKeys("256 SHA256:x+LmFabc op@laptop (ED25519)\n3072 SHA256:yyy a comment with spaces (RSA)\nThe agent has no identities.\n") + if len(keys) != 2 || keys[0] != (Key{Bits: 256, Fingerprint: "SHA256:x+LmFabc", Comment: "op@laptop", Type: "ED25519"}) || + keys[1].Comment != "a comment with spaces" || keys[1].Type != "RSA" { + t.Fatalf("%+v", keys) + } +} + +func TestSSHKeysAsksGcrsAgentAndSaysWhenItDoesNotAnswer(t *testing.T) { + secretService(t) + bin := fakeBinaries(t, map[string]string{"ssh-add": `echo "$SSH_AUTH_SOCK $*" > "$LOG.ssh"; [ -f "$NOAGENT" ] && { echo "Could not open a connection" >&2; exit 2; }; echo "256 SHA256:abc op (ED25519)"`}) + t.Setenv("NOAGENT", filepath.Join(bin, "noagent")) + got, err := SSHKeys() + if err != nil || len(got.Keys) != 1 || !strings.HasSuffix(got.Agent, "/gcr/ssh") { + t.Fatalf("%+v, %v", got, err) + } + asked, _ := os.ReadFile(os.Getenv("LOG") + ".ssh") + if !strings.HasSuffix(strings.TrimSpace(string(asked)), "/gcr/ssh -l -E sha256") { + t.Fatalf("asked: %s", asked) + } + if err := os.WriteFile(filepath.Join(bin, "noagent"), nil, 0o644); err != nil { + t.Fatal(err) + } + if _, err := SSHKeys(); err == nil || !strings.Contains(err.Error(), "gcr-ssh-agent.socket") { + t.Fatalf("no agent: %v", err) + } +} + +func TestWithoutABusTheToolsSaySo(t *testing.T) { + fakeMachine(t) + if _, err := Collections(); !errors.Is(err, ErrNoBus) { + t.Fatal(err) + } + if _, err := SSHKeys(); !errors.Is(err, ErrNoBus) { + t.Fatal(err) + } +} diff --git a/modules/gnome-keyring/cmd/gnome-keyring-tools/main.go b/modules/gnome-keyring/cmd/gnome-keyring-tools/main.go new file mode 100644 index 0000000..941761f --- /dev/null +++ b/modules/gnome-keyring/cmd/gnome-keyring-tools/main.go @@ -0,0 +1,57 @@ +// gnome-keyring's Go tools bundle (novox/hq ADR 0188, ADR 0193, ADR 0208): the secret service's +// tools, served by the node's runtime as the operator account. node-secret-service has no verbs yet +// (ADR 0208 §2), so every tool here is the module's own. None of them ever reads a secret: they ask the +// Secret Service for names, counts and lock states, and the ssh agent for fingerprints. +package main + +import ( + "fmt" + "os" + + stdio "git.novox.be/novox/mesh-sdk/go" +) + +func main() { + if err := stdio.Serve("", tools()); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func tools() []stdio.Tool { + return []stdio.Tool{ + { + Name: "gnome_keyring_unlocked", + Description: "Is the operator's keyring unlocked: the login keyring and the default one, each locked " + + "or not, and whether the keyring daemon runs.", + Run: func(map[string]any) (any, error) { return Unlocked() }, + }, + { + Name: "gnome_keyring_lock", + Description: "Lock a keyring now (the login keyring unless another is named): programs must ask " + + "for its password again. Unlocking is the operator's, at their desktop.", + Input: map[string]any{ + "collection": map[string]any{"type": "string", "description": "the keyring's id, as gnome_keyring_collections answers it (default login)"}, + }, + Run: func(args map[string]any) (any, error) { + c, err := text(args, "collection", false) + if err != nil { + return nil, err + } + return Lock(c) + }, + }, + { + Name: "gnome_keyring_collections", + Description: "The operator's keyrings: each one's id, label, whether it is locked, how many items it " + + "holds, when it was created and changed, and which is the default. Never an item, never a secret.", + Run: func(map[string]any) (any, error) { return Collections() }, + }, + { + Name: "gnome_keyring_ssh_keys", + Description: "The keys the session's ssh agent (gcr's) holds, by fingerprint, size, type and comment. " + + "Never a key.", + Run: func(map[string]any) (any, error) { return SSHKeys() }, + }, + } +} diff --git a/modules/gnome-keyring/cmd/gnome-keyring-tools/manifest_helpers_test.go b/modules/gnome-keyring/cmd/gnome-keyring-tools/manifest_helpers_test.go new file mode 100644 index 0000000..d4fb76d --- /dev/null +++ b/modules/gnome-keyring/cmd/gnome-keyring-tools/manifest_helpers_test.go @@ -0,0 +1,175 @@ +package main + +import ( + "encoding/json" + "os" + "path/filepath" + "strings" + "testing" +) + +// The module's manifest, read the way the catalogue reads it, for the manifest tests. The same in +// every desktop module that carries it. + +type manifest struct { + Module string `json:"module"` + Version string `json:"version"` + Capabilities []string `json:"capabilities"` + Requires []string `json:"requires"` + Claims []claim `json:"claims"` + Seats []any `json:"seats"` + Tools []string `json:"tools"` + Environment *environment `json:"environment"` + Shell []shellCode `json:"shell"` + Resources []map[string]any `json:"resources"` + Build struct { + Artifacts []map[string]any `json:"artifacts"` + } `json:"build"` +} + +type claim struct { + Name string `json:"name"` + Scope string `json:"scope"` + Serves []string `json:"serves"` +} + +type environment struct { + Variables map[string]string `json:"variables"` + Path []map[string]any `json:"path"` +} + +type shellCode struct { + For string `json:"for"` + Slot string `json:"slot"` + Code string `json:"code"` +} + +func readManifest(t *testing.T) manifest { + t.Helper() + raw, err := os.ReadFile(filepath.Join("..", "..", "module.json")) + if err != nil { + t.Fatal(err) + } + dec := json.NewDecoder(strings.NewReader(string(raw))) + dec.DisallowUnknownFields() + var m manifest + if err := dec.Decode(&m); err != nil { + t.Fatalf("module.json: %v", err) + } + return m +} + +func (m manifest) resource(t *testing.T, id string) map[string]any { + t.Helper() + for _, r := range m.Resources { + if r["id"] == id { + return r + } + } + t.Fatalf("no resource %q", id) + return nil +} + +func (m manifest) packages() (present, absent []string) { + for _, r := range m.Resources { + if r["type"] == "package" { + if r["absent"] == true { + absent = append(absent, r["package"].(string)) + } else { + present = append(present, r["package"].(string)) + } + } + } + return present, absent +} + +// sameAsSource checks that a file resource's content is byte for byte the module's source file, so +// the readable file in the repository is what the machine gets. +func (m manifest) sameAsSource(t *testing.T, id, source string) { + t.Helper() + want, err := os.ReadFile(filepath.Join("..", "..", source)) + if err != nil { + t.Fatal(err) + } + r := m.resource(t, id) + if r["type"] != "file" { + t.Fatalf("%s is a %v, not a file", id, r["type"]) + } + if got, _ := r["content"].(string); got != string(want) { + t.Fatalf("resource %s's content is not %s: edit the source and copy it into module.json", id, source) + } + if r["owner"] != "${machine:account}" && !strings.HasPrefix(r["path"].(string), "/etc/") { + t.Fatalf("%s under the home is the account's", id) + } +} + +// checkTheToolsAgree checks that the manifest lists the module's own tools exactly, that the bundle +// serves each seat verb the claims promise as ., and that the Go bundle is declared. +func checkTheToolsAgree(t *testing.T, m manifest) { + t.Helper() + own, seat := map[string]bool{}, map[string]bool{} + for _, tool := range tools() { + if strings.Contains(tool.Name, ".") { + seat[tool.Name] = true + } else { + own[tool.Name] = true + } + if strings.TrimSpace(tool.Description) == "" { + t.Errorf("%s has no description", tool.Name) + } + } + listed := map[string]bool{} + for _, name := range m.Tools { + listed[name] = true + if !own[name] { + t.Errorf("module.json lists %s, which the bundle does not serve", name) + } + } + for name := range own { + if !listed[name] { + t.Errorf("the bundle serves %s, which module.json does not list", name) + } + if !strings.HasPrefix(name, strings.ReplaceAll(m.Module, "-", "_")+"_") { + t.Errorf("%s is not prefixed with the module's name", name) + } + } + promised := map[string]bool{} + for _, c := range m.Claims { + for _, verb := range c.Serves { + promised[c.Name+"."+verb] = true + if !seat[c.Name+"."+verb] { + t.Errorf("the claim on %s promises %s, which the bundle does not serve", c.Name, verb) + } + } + } + for name := range seat { + if !promised[name] { + t.Errorf("the bundle serves %s, which no claim promises", name) + } + } + var bundle map[string]any + for _, a := range m.Build.Artifacts { + if a["kind"] == "bundle" { + bundle = a + } + } + if bundle == nil || bundle["language"] != "go" || bundle["system"] != "arch" || + bundle["from"] != "cmd/"+m.Module+"-tools" || bundle["binary"] != m.Module+"-tools" { + t.Errorf("the Go tools bundle: %v", bundle) + } +} + +// checkNoSecretsOrInstallationNames refuses what a catalogue manifest must never carry. +func checkNoSecretsOrInstallationNames(t *testing.T) { + t.Helper() + raw, err := os.ReadFile(filepath.Join("..", "..", "module.json")) + if err != nil { + t.Fatal(err) + } + s := strings.ToLower(string(raw)) + for _, never := range []string{"/home/", "jochen", "g14", "shanks", "novox.be", "api_key", ".hal/", "greenclip daemon"} { + if strings.Contains(s, never) { + t.Errorf("module.json names %q", never) + } + } +} diff --git a/modules/gnome-keyring/cmd/gnome-keyring-tools/manifest_test.go b/modules/gnome-keyring/cmd/gnome-keyring-tools/manifest_test.go new file mode 100644 index 0000000..67754e0 --- /dev/null +++ b/modules/gnome-keyring/cmd/gnome-keyring-tools/manifest_test.go @@ -0,0 +1,64 @@ +package main + +import ( + "reflect" + "strings" + "testing" +) + +// gnome-keyring's shape (novox/hq ADR 0208, ADR 0102): it claims node-secret-service, writes its PAM +// lines into the login and passwd stacks as marked blocks (never over the files), and starts no daemon +// of its own: PAM and D-Bus do. + +func TestItClaimsTheSecretServiceSeat(t *testing.T) { + m := readManifest(t) + if m.Module != "gnome-keyring" || m.Seats != nil || m.Requires != nil { + t.Fatalf("module %q, seats %v, requires %v", m.Module, m.Seats, m.Requires) + } + if !reflect.DeepEqual(m.Claims, []claim{{Name: "node-secret-service", Scope: "node"}}) { + t.Fatalf("claims: %+v", m.Claims) + } + if present, absent := m.packages(); !reflect.DeepEqual(present, []string{"gnome-keyring", "libsecret", "seahorse"}) || absent != nil { + t.Fatalf("packages: %v, absent %v", present, absent) + } +} + +func TestThePAMLinesAreBlocksWrittenIntoTheStacks(t *testing.T) { + m := readManifest(t) + for id, want := range map[string]struct{ path, source string }{ + "pam-login": {"/etc/pam.d/login", "files/pam/login"}, + "pam-passwd": {"/etc/pam.d/passwd", "files/pam/passwd"}, + } { + m.sameAsSource(t, id, want.source) + r := m.resource(t, id) + if r["path"] != want.path || r["into"] != "block" || r["at"] != "end" || r["owner"] != nil { + t.Errorf("%s: %v", id, r) + } + } + login := m.resource(t, "pam-login")["content"].(string) + if !strings.Contains(login, "\nauth optional pam_gnome_keyring.so\n") || + !strings.Contains(login, "\nsession optional pam_gnome_keyring.so auto_start\n") { + t.Fatalf("%s", login) + } +} + +func TestItStartsNoDaemonAndOnlyNamesTheAgentsSocket(t *testing.T) { + m := readManifest(t) + if len(m.Shell) != 1 || m.Shell[0].For != "xinitrc" || m.Shell[0].Slot != "first" { + t.Fatalf("%+v", m.Shell) + } + code := m.Shell[0].Code + if strings.Contains(code, "gnome-keyring-daemon") || strings.Contains(code, "--unlock") || + !strings.Contains(code, `SSH_AUTH_SOCK="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/gcr/ssh"`) { + t.Fatalf("%q", code) + } + if m.Environment != nil { + t.Fatal("SSH_AUTH_SOCK needs the runtime directory, which ADR 0203 forbids in a value; it is not an environment contribution yet") + } +} + +func TestTheToolsAgreeWithTheManifest(t *testing.T) { + m := readManifest(t) + checkTheToolsAgree(t, m) + checkNoSecretsOrInstallationNames(t) +} diff --git a/modules/gnome-keyring/cmd/gnome-keyring-tools/session.go b/modules/gnome-keyring/cmd/gnome-keyring-tools/session.go new file mode 100644 index 0000000..dc21774 --- /dev/null +++ b/modules/gnome-keyring/cmd/gnome-keyring-tools/session.go @@ -0,0 +1,423 @@ +// The operator's graphical session, as a tool the node's runtime runs finds it (novox/hq ADR 0208). +// +// The runtime is a system service running as the operator account (ADR 0175): it has the account's +// uid and none of the session's environment — no DISPLAY, no XAUTHORITY, no session bus. A tool that +// draws on the screen or talks to the desktop's D-Bus must find them. It reads them from a process of +// the account that is part of the session (the window manager first), the same thing `loginctl` and +// a person's own shell would point at, and says where it found them. +// +// Long-lived programs a tool starts go to the account's own service manager through `systemd-run +// --user`, never as children of the tool: the runtime's unit is a cgroup the service manager empties +// whenever the runtime restarts, and a compositor or a clipboard owner started from inside it would +// die with it. +// +// This file is the same in every desktop module that carries it; it moves into the Go SDK once a +// second consumer outside the desktop wants it. +package main + +import ( + "bytes" + "errors" + "fmt" + "os" + "os/exec" + "path/filepath" + "sort" + "strconv" + "strings" + "syscall" + "time" +) + +// Where the session is looked for. Variables so a test can point them at a fake tree. +var ( + procRoot = "/proc" + runUserDir = "/run/user" + x11Sockets = "/tmp/.X11-unix" +) + +// sessionHolders are the processes whose environment is the session's, best first: the window +// manager is the session, the rest are its children. Anything else carrying DISPLAY ranks after them. +var sessionHolders = []string{"i3", "sway", "i3bar", "picom", "xss-lock", "dunst", "clipmenud", "xterm"} + +// sessionKeys are the variables a session carries that a tool hands on to what it runs. +var sessionKeys = []string{"DISPLAY", "XAUTHORITY", "WAYLAND_DISPLAY", "DBUS_SESSION_BUS_ADDRESS", + "XDG_RUNTIME_DIR", "XDG_SESSION_ID", "I3SOCK"} + +// Session is what a tool needs to reach the operator's desktop. +type Session struct { + UID int `json:"uid"` + Display string `json:"display,omitempty"` + XAuthority string `json:"xauthority,omitempty"` + Wayland string `json:"wayland_display,omitempty"` + Bus string `json:"bus,omitempty"` + RuntimeDir string `json:"runtime_dir,omitempty"` + SessionID string `json:"session_id,omitempty"` + I3Sock string `json:"i3sock,omitempty"` + // From says where the values were found: the tool's own environment, a process, or the socket. + From string `json:"from"` +} + +// ErrNoSession is answered by a tool that needs the desktop when nobody is logged in to it. +var ErrNoSession = errors.New("no graphical session") + +// ErrTimedOut is what run answers for a command ended because it ran past its time. +var ErrTimedOut = errors.New("timed out") + +// ErrNoBus is answered by a tool that needs the session bus when the account has none. +var ErrNoBus = errors.New("no session bus") + +// operatorHome is the account's home: what the runtime was told, else the process's own. +func operatorHome() string { + if h := strings.TrimSpace(os.Getenv("MESH_OPERATOR_HOME")); h != "" { + return h + } + h, _ := os.UserHomeDir() + return h +} + +// findSession finds the graphical session of the account this tool runs as, or answers +// ErrNoSession with what it looked at. +func findSession() (Session, error) { + s := findEnvironment() + if s.Display == "" && s.Wayland == "" { + return s, fmt.Errorf("%w for uid %d on this machine: no process of the account carries DISPLAY "+ + "or WAYLAND_DISPLAY, and no X server socket in %s has an authority file to go with it. "+ + "Is anyone logged in to the desktop?", ErrNoSession, s.UID, x11Sockets) + } + return s, nil +} + +// findBus finds the account's session bus, which a logged-in account has whether or not a desktop +// is running. +func findBus() (Session, error) { + s := findEnvironment() + if s.Bus == "" { + return s, fmt.Errorf("%w for uid %d: DBUS_SESSION_BUS_ADDRESS is not set and %s does not exist "+ + "(the account is not logged in)", ErrNoBus, s.UID, filepath.Join(runUserDir, strconv.Itoa(s.UID), "bus")) + } + return s, nil +} + +func findEnvironment() Session { + uid := os.Getuid() + s := Session{UID: uid} + own := map[string]string{} + for _, k := range sessionKeys { + own[k] = os.Getenv(k) + } + if own["DISPLAY"] != "" || own["WAYLAND_DISPLAY"] != "" { + s.fill(own) + s.From = "the tool's own environment" + } else if pid, comm, env, ok := sessionProcess(uid); ok { + s.fill(env) + s.From = fmt.Sprintf("process %s (pid %d)", comm, pid) + } else if display, ok := lonelyX11Socket(); ok { + if a := filepath.Join(operatorHome(), ".Xauthority"); exists(a) { + s.Display, s.XAuthority = display, a + s.From = "the X server socket and the account's ~/.Xauthority" + } + s.fill(own) + } else { + s.fill(own) + s.From = "nothing: no session found" + } + // The bus and the runtime directory are the account's, whether or not the process named them. + runtime := filepath.Join(runUserDir, strconv.Itoa(uid)) + if s.RuntimeDir == "" && exists(runtime) { + s.RuntimeDir = runtime + } + if s.Bus == "" && s.RuntimeDir != "" && exists(filepath.Join(s.RuntimeDir, "bus")) { + s.Bus = "unix:path=" + filepath.Join(s.RuntimeDir, "bus") + } + return s +} + +func (s *Session) fill(env map[string]string) { + set := func(dst *string, key string) { + if *dst == "" { + *dst = env[key] + } + } + set(&s.Display, "DISPLAY") + set(&s.XAuthority, "XAUTHORITY") + set(&s.Wayland, "WAYLAND_DISPLAY") + set(&s.Bus, "DBUS_SESSION_BUS_ADDRESS") + set(&s.RuntimeDir, "XDG_RUNTIME_DIR") + set(&s.SessionID, "XDG_SESSION_ID") + set(&s.I3Sock, "I3SOCK") +} + +// sessionProcess is the best process of this uid whose environment names a display. +func sessionProcess(uid int) (int, string, map[string]string, bool) { + entries, err := os.ReadDir(procRoot) + if err != nil { + return 0, "", nil, false + } + type candidate struct { + pid int + comm string + env map[string]string + rank int + } + var found []candidate + for _, e := range entries { + pid, err := strconv.Atoi(e.Name()) + if err != nil { + continue + } + dir := filepath.Join(procRoot, e.Name()) + if owner, ok := ownerOf(dir); !ok || owner != uid { + continue + } + raw, err := os.ReadFile(filepath.Join(dir, "environ")) + if err != nil { + continue + } + env := parseEnviron(raw) + if env["DISPLAY"] == "" && env["WAYLAND_DISPLAY"] == "" { + continue + } + comm := readTrimmed(filepath.Join(dir, "comm")) + rank := len(sessionHolders) + for i, h := range sessionHolders { + if h == comm { + rank = i + break + } + } + found = append(found, candidate{pid, comm, env, rank}) + } + if len(found) == 0 { + return 0, "", nil, false + } + sort.Slice(found, func(i, j int) bool { + if found[i].rank != found[j].rank { + return found[i].rank < found[j].rank + } + return found[i].pid > found[j].pid // the newer of two equals + }) + best := found[0] + return best.pid, best.comm, best.env, true +} + +func parseEnviron(raw []byte) map[string]string { + env := map[string]string{} + for _, kv := range bytes.Split(raw, []byte{0}) { + if i := bytes.IndexByte(kv, '='); i > 0 { + env[string(kv[:i])] = string(kv[i+1:]) + } + } + return env +} + +func ownerOf(path string) (int, bool) { + info, err := os.Stat(path) + if err != nil { + return 0, false + } + st, ok := info.Sys().(*syscall.Stat_t) + if !ok { + return 0, false + } + return int(st.Uid), true +} + +// lonelyX11Socket is the display of the one X server socket there is, when there is exactly one. +func lonelyX11Socket() (string, bool) { + entries, err := os.ReadDir(x11Sockets) + if err != nil { + return "", false + } + var displays []string + for _, e := range entries { + if n := strings.TrimPrefix(e.Name(), "X"); n != e.Name() { + if _, err := strconv.Atoi(n); err == nil { + displays = append(displays, ":"+n) + } + } + } + if len(displays) != 1 { + return "", false + } + return displays[0], true +} + +func readTrimmed(path string) string { + b, err := os.ReadFile(path) + if err != nil { + return "" + } + return strings.TrimSpace(string(b)) +} + +func exists(path string) bool { + _, err := os.Stat(path) + return err == nil +} + +// Env is this process's environment with the session's variables in place of its own. +func (s Session) Env() []string { + drop := map[string]bool{} + for _, k := range sessionKeys { + drop[k] = true + } + var env []string + for _, kv := range os.Environ() { + if i := strings.IndexByte(kv, '='); i > 0 && drop[kv[:i]] { + continue + } + env = append(env, kv) + } + add := func(k, v string) { + if v != "" { + env = append(env, k+"="+v) + } + } + add("DISPLAY", s.Display) + add("XAUTHORITY", s.XAuthority) + add("WAYLAND_DISPLAY", s.Wayland) + add("DBUS_SESSION_BUS_ADDRESS", s.Bus) + add("XDG_RUNTIME_DIR", s.RuntimeDir) + add("XDG_SESSION_ID", s.SessionID) + add("I3SOCK", s.I3Sock) + return env +} + +// mostOutput bounds what a command may answer with, per stream. +const mostOutput = 256 << 10 + +// Result is what a command did. +type Result struct { + Stdout string `json:"stdout"` + Stderr string `json:"stderr,omitempty"` + Code int `json:"code"` + Truncated bool `json:"truncated,omitempty"` +} + +// run runs a command in the session's environment, its input given, ended with everything it +// started after timeout. A command that is not installed is an error naming it; one that exits +// non-zero is a Result with its code, for the caller to judge. +func (s Session) run(timeout time.Duration, stdin string, name string, args ...string) (Result, error) { + path, err := exec.LookPath(name) + if err != nil { + return Result{}, fmt.Errorf("%s is not installed on this machine", name) + } + cmd := exec.Command(path, args...) + cmd.Env = s.Env() + if home := operatorHome(); exists(home) { + cmd.Dir = home + } + if stdin != "" { + cmd.Stdin = strings.NewReader(stdin) + } + var out, errOut capped + cmd.Stdout, cmd.Stderr = &out, &errOut + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + if err := cmd.Start(); err != nil { + return Result{}, fmt.Errorf("%s: %w", name, err) + } + done := make(chan error, 1) + go func() { done <- cmd.Wait() }() + select { + case err = <-done: + case <-time.After(timeout): + _ = syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) + <-done + return Result{Stdout: out.String(), Stderr: errOut.String()}, + fmt.Errorf("%s did not finish within %s and was ended: %w", name, timeout, ErrTimedOut) + } + r := Result{Stdout: out.String(), Stderr: errOut.String(), Truncated: out.cut || errOut.cut} + var exit *exec.ExitError + if errors.As(err, &exit) { + r.Code = exit.ExitCode() + } else if err != nil { + return r, fmt.Errorf("%s: %w", name, err) + } + return r, nil +} + +// detach starts a long-lived program under the account's own service manager, as a transient unit +// that carries the session's display, so it outlives the runtime that asked for it. A unit already +// running under the same name is stopped first, so a fixed name means "at most one". +func (s Session) detach(unit string, args ...string) error { + if s.RuntimeDir == "" { + return fmt.Errorf("%w: the account's runtime directory is missing, so its service manager "+ + "cannot be reached", ErrNoBus) + } + _, _ = s.run(5*time.Second, "", "systemctl", "--user", "stop", unit+".service") + call := []string{"--user", "--collect", "--quiet", "--unit=" + unit} + for _, kv := range [][2]string{{"DISPLAY", s.Display}, {"XAUTHORITY", s.XAuthority}, + {"WAYLAND_DISPLAY", s.Wayland}, {"XDG_SESSION_ID", s.SessionID}, {"I3SOCK", s.I3Sock}} { + if kv[1] != "" { + call = append(call, "--setenv="+kv[0]+"="+kv[1]) + } + } + call = append(call, "--") + call = append(call, args...) + r, err := s.run(10*time.Second, "", "systemd-run", call...) + if err != nil { + return err + } + if r.Code != 0 { + return fmt.Errorf("systemd-run %s: %s", unit, strings.TrimSpace(r.Stderr)) + } + return nil +} + +// uniqueUnit is a transient unit name that will not collide with an earlier one. +func uniqueUnit(prefix string) string { + return fmt.Sprintf("%s-%d", prefix, time.Now().UnixNano()) +} + +type capped struct { + bytes.Buffer + cut bool +} + +func (c *capped) Write(p []byte) (int, error) { + if room := mostOutput - c.Len(); room < len(p) { + if room > 0 { + c.Buffer.Write(p[:room]) + } + c.cut = true + return len(p), nil + } + return c.Buffer.Write(p) +} + +// processesOf are the pids of this uid's processes whose command name is comm, oldest first. +func processesOf(comm string) []int { + entries, err := os.ReadDir(procRoot) + if err != nil { + return nil + } + uid := os.Getuid() + var pids []int + for _, e := range entries { + pid, err := strconv.Atoi(e.Name()) + if err != nil { + continue + } + dir := filepath.Join(procRoot, e.Name()) + if owner, ok := ownerOf(dir); !ok || owner != uid { + continue + } + if readTrimmed(filepath.Join(dir, "comm")) == comm { + pids = append(pids, pid) + } + } + sort.Ints(pids) + return pids +} + +// signalAll sends sig to every process of this uid named comm, and answers the pids it reached. +func signalAll(comm string, sig syscall.Signal) []int { + var reached []int + for _, pid := range processesOf(comm) { + if syscall.Kill(pid, sig) == nil { + reached = append(reached, pid) + } + } + return reached +} diff --git a/modules/gnome-keyring/cmd/gnome-keyring-tools/session_test.go b/modules/gnome-keyring/cmd/gnome-keyring-tools/session_test.go new file mode 100644 index 0000000..800cc6d --- /dev/null +++ b/modules/gnome-keyring/cmd/gnome-keyring-tools/session_test.go @@ -0,0 +1,174 @@ +package main + +import ( + "errors" + "os" + "path/filepath" + "strconv" + "strings" + "testing" + "time" +) + +// fakeMachine points the session finder at a temporary /proc, /run/user and X socket directory, with +// none of the test process's own session variables, and gives back the root. +func fakeMachine(t *testing.T) string { + t.Helper() + root := t.TempDir() + procRoot, runUserDir, x11Sockets = filepath.Join(root, "proc"), filepath.Join(root, "run-user"), filepath.Join(root, "x11") + for _, d := range []string{procRoot, runUserDir, x11Sockets} { + if err := os.MkdirAll(d, 0o755); err != nil { + t.Fatal(err) + } + } + for _, k := range sessionKeys { + t.Setenv(k, "") + } + t.Setenv("MESH_OPERATOR_HOME", filepath.Join(root, "home")) + t.Cleanup(func() { procRoot, runUserDir, x11Sockets = "/proc", "/run/user", "/tmp/.X11-unix" }) + return root +} + +func fakeProcess(t *testing.T, pid int, comm string, env ...string) { + t.Helper() + dir := filepath.Join(procRoot, strconv.Itoa(pid)) + if err := os.MkdirAll(dir, 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, "comm"), []byte(comm+"\n"), 0o644); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, "environ"), []byte(strings.Join(env, "\x00")+"\x00"), 0o600); err != nil { + t.Fatal(err) + } +} + +func TestTheSessionIsReadFromTheWindowManagerBeforeAnyOtherProcess(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 900, "xterm", "DISPLAY=:9", "XAUTHORITY=/elsewhere") + fakeProcess(t, 100, "i3", "DISPLAY=:1", "XAUTHORITY=/home/op/.Xauthority", + "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus", "XDG_SESSION_ID=3", "SECRET_TOKEN=never-copied") + fakeProcess(t, 50, "bash", "PATH=/usr/bin") + s, err := findSession() + if err != nil { + t.Fatal(err) + } + if s.Display != ":1" || s.XAuthority != "/home/op/.Xauthority" || s.SessionID != "3" || !strings.Contains(s.From, "i3 (pid 100)") { + t.Fatalf("the window manager's environment: %+v", s) + } + for _, kv := range s.Env() { + if strings.HasPrefix(kv, "SECRET_TOKEN=") { + t.Fatal("a variable of the session process that is not a session variable was handed on") + } + } +} + +func TestAnyProcessCarryingADisplayServesWhenTheWindowManagerIsNotFound(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 10, "firefox", "DISPLAY=:0") + fakeProcess(t, 20, "firefox", "DISPLAY=:2") + s, err := findSession() + if err != nil || s.Display != ":2" { + t.Fatalf("the newest of two equals: %+v, %v", s, err) + } +} + +func TestNoSessionIsAClearAnswerNotAGuess(t *testing.T) { + fakeMachine(t) + fakeProcess(t, 10, "sshd", "PATH=/usr/bin") + _, err := findSession() + if !errors.Is(err, ErrNoSession) || !strings.Contains(err.Error(), "logged in to the desktop") { + t.Fatalf("no session: %v", err) + } +} + +func TestOneXSocketAndTheAccountsAuthorityFileAreASession(t *testing.T) { + root := fakeMachine(t) + if err := os.WriteFile(filepath.Join(x11Sockets, "X0"), nil, 0o644); err != nil { + t.Fatal(err) + } + if err := os.MkdirAll(filepath.Join(root, "home"), 0o755); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(root, "home", ".Xauthority"), nil, 0o600); err != nil { + t.Fatal(err) + } + s, err := findSession() + if err != nil || s.Display != ":0" || !strings.HasSuffix(s.XAuthority, "/home/.Xauthority") { + t.Fatalf("socket and authority: %+v, %v", s, err) + } +} + +func TestTheBusIsTheAccountsRuntimeDirectoryWhenNoProcessNamesIt(t *testing.T) { + fakeMachine(t) + runtime := filepath.Join(runUserDir, strconv.Itoa(os.Getuid())) + if _, err := findBus(); !errors.Is(err, ErrNoBus) { + t.Fatalf("no runtime directory is no bus: %v", err) + } + if err := os.MkdirAll(runtime, 0o700); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(runtime, "bus"), nil, 0o600); err != nil { + t.Fatal(err) + } + s, err := findBus() + if err != nil || s.Bus != "unix:path="+filepath.Join(runtime, "bus") || s.RuntimeDir != runtime { + t.Fatalf("bus: %+v, %v", s, err) + } + env := strings.Join(s.Env(), "\n") + if !strings.Contains(env, "XDG_RUNTIME_DIR="+runtime) || !strings.Contains(env, "DBUS_SESSION_BUS_ADDRESS=unix:path=") { + t.Fatalf("the bus is handed on: %s", env) + } +} + +func TestACommandIsBoundedAndANonZeroExitIsAResult(t *testing.T) { + fakeMachine(t) + s := Session{} + r, err := s.run(5*time.Second, "in", "sh", "-c", "cat; echo err >&2; exit 3") + if err != nil || r.Stdout != "in" || r.Code != 3 || strings.TrimSpace(r.Stderr) != "err" { + t.Fatalf("result: %+v, %v", r, err) + } + start := time.Now() + if _, err := s.run(200*time.Millisecond, "", "sh", "-c", "sleep 30 & sleep 30"); err == nil || time.Since(start) > 5*time.Second { + t.Fatalf("a command past its time is ended with what it started: %v after %s", err, time.Since(start)) + } + if _, err := s.run(time.Second, "", "no-such-program-here"); err == nil || !strings.Contains(err.Error(), "not installed") { + t.Fatalf("a missing program: %v", err) + } +} + +func TestDetachAsksTheAccountsServiceManagerWithTheSessionsDisplay(t *testing.T) { + fakeMachine(t) + bin := fakeBinaries(t, map[string]string{ + "systemctl": `echo "systemctl $*" >> "$LOG"`, + "systemd-run": `echo "systemd-run $*" >> "$LOG"`, + }) + log := filepath.Join(bin, "log") + t.Setenv("LOG", log) + s := Session{Display: ":1", XAuthority: "/x", RuntimeDir: "/run/user/1"} + if err := s.detach("picom-session", "picom", "--config", "/c"); err != nil { + t.Fatal(err) + } + got, _ := os.ReadFile(log) + want := "systemctl --user stop picom-session.service\n" + + "systemd-run --user --collect --quiet --unit=picom-session --setenv=DISPLAY=:1 --setenv=XAUTHORITY=/x -- picom --config /c\n" + if string(got) != want { + t.Fatalf("detach ran:\n%s\nwant:\n%s", got, want) + } + if err := (Session{}).detach("x", "y"); !errors.Is(err, ErrNoBus) { + t.Fatalf("no runtime directory: %v", err) + } +} + +// fakeBinaries puts shell scripts named for programs first on PATH, and answers their directory. +func fakeBinaries(t *testing.T, scripts map[string]string) string { + t.Helper() + dir := t.TempDir() + for name, body := range scripts { + if err := os.WriteFile(filepath.Join(dir, name), []byte("#!/bin/sh\n"+body+"\n"), 0o755); err != nil { + t.Fatal(err) + } + } + t.Setenv("PATH", dir+string(os.PathListSeparator)+os.Getenv("PATH")) + return dir +} diff --git a/modules/gnome-keyring/files/pam/login b/modules/gnome-keyring/files/pam/login new file mode 100644 index 0000000..47833d9 --- /dev/null +++ b/modules/gnome-keyring/files/pam/login @@ -0,0 +1,4 @@ +# The login keyring (module gnome-keyring, novox/hq ADR 0208, ADR 0102): the password typed at the +# login screen unlocks the keyring, and the login session starts the keyring daemon with it. +auth optional pam_gnome_keyring.so +session optional pam_gnome_keyring.so auto_start diff --git a/modules/gnome-keyring/files/pam/passwd b/modules/gnome-keyring/files/pam/passwd new file mode 100644 index 0000000..dd43bb8 --- /dev/null +++ b/modules/gnome-keyring/files/pam/passwd @@ -0,0 +1,3 @@ +# The login keyring (module gnome-keyring, novox/hq ADR 0208, ADR 0102): changing the account's +# password changes the login keyring's with it, so the next login still unlocks it. +password optional pam_gnome_keyring.so diff --git a/modules/gnome-keyring/go.mod b/modules/gnome-keyring/go.mod new file mode 100644 index 0000000..f917a5c --- /dev/null +++ b/modules/gnome-keyring/go.mod @@ -0,0 +1,5 @@ +module gnomekeyring + +go 1.22 + +require git.novox.be/novox/mesh-sdk/go v0.1.7 diff --git a/modules/gnome-keyring/go.sum b/modules/gnome-keyring/go.sum new file mode 100644 index 0000000..b474419 --- /dev/null +++ b/modules/gnome-keyring/go.sum @@ -0,0 +1,2 @@ +git.novox.be/novox/mesh-sdk/go v0.1.7 h1:C0sTQmtTiyYH7bnqZb7PusXnqA37gKuT7Nqjn9gG47w= +git.novox.be/novox/mesh-sdk/go v0.1.7/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY= diff --git a/modules/gnome-keyring/module.json b/modules/gnome-keyring/module.json new file mode 100644 index 0000000..0c796fc --- /dev/null +++ b/modules/gnome-keyring/module.json @@ -0,0 +1,76 @@ +{ + "module": "gnome-keyring", + "version": "1", + "capabilities": [ + "package-manager" + ], + "claims": [ + { + "name": "node-secret-service", + "scope": "node" + } + ], + "tools": [ + "gnome_keyring_unlocked", + "gnome_keyring_lock", + "gnome_keyring_collections", + "gnome_keyring_ssh_keys" + ], + "shell": [ + { + "for": "xinitrc", + "slot": "first", + "code": "# The ssh agent (module gnome-keyring, novox/hq ADR 0208): gcr's, which the account's service manager\n# starts on first use from its socket. Named here, for the session and every terminal it starts, until\n# the account's environment can say a path under the runtime directory (see the module's README).\nSSH_AUTH_SOCK=\"${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/gcr/ssh\"\nexport SSH_AUTH_SOCK\n" + } + ], + "resources": [ + { + "id": "package", + "type": "package", + "package": "gnome-keyring" + }, + { + "id": "library", + "type": "package", + "package": "libsecret" + }, + { + "id": "manager", + "type": "package", + "package": "seahorse" + }, + { + "id": "pam-login", + "type": "file", + "path": "/etc/pam.d/login", + "mode": "0644", + "into": "block", + "at": "end", + "content": "# The login keyring (module gnome-keyring, novox/hq ADR 0208, ADR 0102): the password typed at the\n# login screen unlocks the keyring, and the login session starts the keyring daemon with it.\nauth optional pam_gnome_keyring.so\nsession optional pam_gnome_keyring.so auto_start\n" + }, + { + "id": "pam-passwd", + "type": "file", + "path": "/etc/pam.d/passwd", + "mode": "0644", + "into": "block", + "at": "end", + "content": "# The login keyring (module gnome-keyring, novox/hq ADR 0208, ADR 0102): changing the account's\n# password changes the login keyring's with it, so the next login still unlocks it.\npassword optional pam_gnome_keyring.so\n" + } + ], + "build": { + "artifacts": [ + { + "name": "tools", + "kind": "bundle", + "language": "go", + "system": "arch", + "from": "cmd/gnome-keyring-tools", + "binary": "gnome-keyring-tools", + "loads": [ + "gnome-keyring-tools" + ] + } + ] + } +} From 6d06648bc16c456ee394df1d559cd6956b2bcd85 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 4 Oct 2026 13:16:02 +0200 Subject: [PATCH 09/15] i3status-rust: no domain names in the icon file's comments (the catalogue check refuses them) --- modules/i3status-rust/files/icons/custom-icons.toml | 4 ++-- modules/i3status-rust/module.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/i3status-rust/files/icons/custom-icons.toml b/modules/i3status-rust/files/icons/custom-icons.toml index 685c9d3..9636a82 100644 --- a/modules/i3status-rust/files/icons/custom-icons.toml +++ b/modules/i3status-rust/files/icons/custom-icons.toml @@ -1,7 +1,7 @@ # Icons for the bars (module i3status-rust, novox/hq ADR 0208), from the JetBrains Mono Nerd Font. # Owned by the mesh: replaced at every push. Adopted unchanged from the workstations of 2026-10-04. # Material from NerdFont -# https://www.nerdfonts.com/cheat-sheet +# Codepoints from the Nerd Fonts cheat sheet backlight = [ "\ue38d", # nf-weather-moon_new "\ue3d4", # nf-weather-moon_alt_waxing_gibbous_6 @@ -121,7 +121,7 @@ microphone = [ ] xrandr = "\U000f037a" # nf-md-monitor_multiple -# Weather icons (https://greshake.github.io/i3status-rust/i3status_rs/blocks/weather/index.html) +# Weather icons (the names the weather block documents) weather_sun = "\ue30d" # nf-weather-day_sunny (when weather is reported as “Clear” during the day) weather_moon = "\ue32b" # nf-weather-night_clear (when weather is reported as “Clear” at night) weather_clouds = "\ue312" # nf-weather-cloudy (when weather is reported as “Clouds” during the day) diff --git a/modules/i3status-rust/module.json b/modules/i3status-rust/module.json index 4510d6a..f0249c1 100644 --- a/modules/i3status-rust/module.json +++ b/modules/i3status-rust/module.json @@ -73,7 +73,7 @@ "path": "${machine:account-home}/.config/i3status-rust/icons/custom-icons.toml", "owner": "${machine:account}", "mode": "0644", - "content": "# Icons for the bars (module i3status-rust, novox/hq ADR 0208), from the JetBrains Mono Nerd Font.\n# Owned by the mesh: replaced at every push. Adopted unchanged from the workstations of 2026-10-04.\n# Material from NerdFont\n# https://www.nerdfonts.com/cheat-sheet\nbacklight = [\n \"\\ue38d\", # nf-weather-moon_new\n \"\\ue3d4\", # nf-weather-moon_alt_waxing_gibbous_6\n \"\\ue3d3\", # nf-weather-moon_alt_waxing_gibbous_5\n \"\\ue3d2\", # nf-weather-moon_alt_waxing_gibbous_4\n \"\\ue3d1\", # nf-weather-moon_alt_waxing_gibbous_3\n \"\\ue3d0\", # nf-weather-moon_alt_waxing_gibbous_2\n \"\\ue3cf\", # nf-weather-moon_alt_waxing_gibbous_1\n \"\\ue3ce\", # nf-weather-moon_alt_first_quarter\n \"\\ue3cd\", # nf-weather-moon_alt_waxing_crescent_6\n \"\\ue3cc\", # nf-weather-moon_alt_waxing_crescent_5\n \"\\ue3cb\", # nf-weather-moon_alt_waxing_crescent_4\n \"\\ue3ca\", # nf-weather-moon_alt_waxing_crescent_3\n \"\\ue3c9\", # nf-weather-moon_alt_waxing_crescent_2\n \"\\ue3c8\", # nf-weather-moon_alt_waxing_crescent_1\n \"\\ue39b\", # nf-weather-moon_full\n]\nbat_charging = \"\\U000f0084\" # nf-md-battery_charging\nbat_not_available = \"\\U000f0091\" # nf-md-battery_unknown\nbat = [\n \"\\U000f007a\", # nf-md-battery_10\n \"\\U000f007b\", # nf-md-battery_20\n \"\\U000f007c\", # nf-md-battery_30\n \"\\U000f007d\", # nf-md-battery_40\n \"\\U000f007e\", # nf-md-battery_50\n \"\\U000f007f\", # nf-md-battery_60\n \"\\U000f0080\", # nf-md-battery_70\n \"\\U000f0081\", # nf-md-battery_80\n \"\\U000f0082\", # nf-md-battery_90\n \"\\U000f0079\", # nf-md-battery\n]\nbell = \"\\U000f009c\" # nf-md-bell_outline\nbell-slash = \"\\U000f009b\" # nf-md-bell_off\nblackberry = \"\\uf307\" # nf-md-blackberry\nbluetooth = \"\\U000f00af\" # nf-md-bluetooth\ncalendar = \"\\U000f00ed\" # nf-md-calendar\ncogs = \"\\U000f0493\" # nf-md-cog\ncpu = [\n\t\"\\U000F0F86\", # nf-md-speedometer_slow\n\t\"\\U000F0F85\", # nf-md-speedometer_medium\n\t\"\\U000F04C5\", # nf-md-speedometer\n]\ncpu_boost_on = \"\\U000f0521\" # nf-md-toggle_switch\ncpu_boost_off = \"\\U000f0a19\" # nf-md-toggle_switch_off_outline\ndisk_drive = \"\\U000f02ca\" # nf-md-harddisk\ndocker = \"\\uf308\" # nf-linux-docker\ngithub = \"\\U000f02a4\" # nf-md-github\ngpu = \"\\U000f0379\" # nf-md-monitor\nheadphones = \"\\U000f02cb\" # nf-md-headphones\njoystick = \"\\U000f0297\" # nf-md-gamepad_variant\nkeyboard = \"\\U000f030c\" # nf-md-keyboard\nmail = \"\\U000f01ee\" # nf-md-email\nmemory_mem = \"\\U000f035b\" # nf-md-memory\nmemory_swap = \"\\U000f02ca\" # nf-md-harddisk\nmouse = \"\\U000f037d\" # nf-md-mouse\nmusic = \"\\U000f075a\" # nf-md-music\nmusic_next = \"\\U000f04ad\" # nf-md-skip_next\nmusic_pause = \"\\U000f03e4\" # nf-md-pause\nmusic_play = \"\\U000f040a\" # nf-md-play\nmusic_prev = \"\\U000f04ae\" # nf-md-skip_previous\nnet_bridge = \"\\U000f04aa\" # nf-md-sitemap\nnet_down = \"\\U000f01da\" # nf-md-download\nnet_loopback = \"\\U000f006f\" # nf-md-backup_restore\nnet_modem = \"\\U000f03f2\" # nf-md-phone\nnet_cellular = [\n \"\\U000F08FD\", # nf-md-network_strength_off_outline\n \"\\U000F08FE\", # nf-md-network_strength_outline\n \"\\U000F08F4\", # nf-md-network_strength_1\n \"\\U000F08F6\", # nf-md-network_strength_2\n \"\\U000F08F8\", # nf-md-network_strength_3\n \"\\U000F08FA\", # nf-md-network_strength_4\n]\nnet_up = \"\\U000f0552\" # nf-md-upload\nnet_vpn = \"\\U000f0582\" # nf-md-vpn\nnet_wired = \"\\U000f0200\" # nf-md-ethernet\nnet_wireless = [\n\t\"\\U000F092F\", # nf-md-wifi_strength_outline\n\t\"\\U000F091F\", # nf-md-wifi_strength_1\n\t\"\\U000F0922\", # nf-md-wifi_strength_2\n\t\"\\U000F0925\", # nf-md-wifi_strength_3\n\t\"\\U000F0928\", # nf-md-wifi_strength_4\n]\nnotification = \"\\U000f009c\" # nf-md-bell_outline\nphone = \"\\U000f03f2\" # nf-md-phone\nphone_disconnected = \"\\U000f0658\" # nf-md-phone_minus\nping = \"\\U000f051f\" # nf-md-timer_sand\npomodoro = \"\\ue001\" # nf-pom-pomodoro_done\npomodoro_break = \"\\U000f0176\" # nf-md-coffee\npomodoro_paused = \"\\U000f03e4\" # nf-md-pause\npomodoro_started = \"\\U000f040a\" # nf-md-play\npomodoro_stopped = \"\\U000f04db\" # nf-md-stop\nresolution = \"\\U000f0293\" # nf-md-fullscreen\ntasks = \"\\U000f05c7\" # nf-md-playlist_check\ntea = \"\\U000f0d9e\" # nf-md-tea\nthermometer = [\n \"\\U000f10c3\", # nf-md-thermometer_low\n \"\\U000f050f\", # nf-md-thermometer\n \"\\U000f10c2\", # nf-md-thermometer_high\n]\ntime = \"\\U000f0150\" # nf-md-clock_outline\ntoggle_off = \"\\U000f0a19\" # nf-md-toggle_switch_off_outline\ntoggle_on = \"\\U000f0521\" # nf-md-toggle_switch\nunknown = \"\\U000f0186\" # nf-md-comment_question_outline | TODO: Make default?\nupdate = \"\\U000f03d5\" # nf-md-package_up\nuptime = \"\\U000f0153\" # nf-md-clock_in\nvolume_muted = \"\\U000f075f\" # nf-md-volume_mute\nvolume = [\n \"\\U000f057f\", # nf-md-volume_low\n \"\\U000f0580\", # nf-md-volume_medium\n \"\\U000f057e\", # nf-md-volume_high\n]\nmicrophone_muted = \"\\U000f036d\" # nf-md-microphone_off\nmicrophone = [\n\t\"\\U000f036e\", # nf-md-microphone_outline\n \"\\U000f036c\", # nf-md-microphone\n \"\\U000f036c\", # nf-md-microphone\n]\nxrandr = \"\\U000f037a\" # nf-md-monitor_multiple\n\n# Weather icons (https://greshake.github.io/i3status-rust/i3status_rs/blocks/weather/index.html)\nweather_sun = \"\\ue30d\" # nf-weather-day_sunny (when weather is reported as “Clear” during the day)\nweather_moon = \"\\ue32b\" # nf-weather-night_clear (when weather is reported as “Clear” at night)\nweather_clouds = \"\\ue312\" # nf-weather-cloudy (when weather is reported as “Clouds” during the day)\nweather_clouds_night = \"\\ue37e\" # nf-weather-night_alt_cloudy (when weather is reported as “Clouds” at night)\nweather_fog = \"\\ue313\" # nf-weather-fog (when weather is reported as “Fog” or “Mist” during the day)\nweather_fog_night = \"\\ue346\" # nf-weather-night_fog (when weather is reported as “Fog” or “Mist” at night)\nweather_rain = \"\\ue318\" # nf-weather-rain (when weather is reported as “Rain” or “Drizzle” during the day)\nweather_rain_night = \"\\ue325\" # nf-weather-night_alt_rain (when weather is reported as “Rain” or “Drizzle” at night)\nweather_snow = \"\\ue31a\" # nf-weather-snow (when weather is reported as “Snow”)\nweather_thunder = \"\\ue31d\" # nf-weather-thunderstorm (when weather is reported as “Thunderstorm” during the day)\nweather_thunder_night = \"\\ue32a\" # nf-weather-night_alt_thunderstorm (when weather is reported as “Thunderstorm” at night)\n" + "content": "# Icons for the bars (module i3status-rust, novox/hq ADR 0208), from the JetBrains Mono Nerd Font.\n# Owned by the mesh: replaced at every push. Adopted unchanged from the workstations of 2026-10-04.\n# Material from NerdFont\n# Codepoints from the Nerd Fonts cheat sheet\nbacklight = [\n \"\\ue38d\", # nf-weather-moon_new\n \"\\ue3d4\", # nf-weather-moon_alt_waxing_gibbous_6\n \"\\ue3d3\", # nf-weather-moon_alt_waxing_gibbous_5\n \"\\ue3d2\", # nf-weather-moon_alt_waxing_gibbous_4\n \"\\ue3d1\", # nf-weather-moon_alt_waxing_gibbous_3\n \"\\ue3d0\", # nf-weather-moon_alt_waxing_gibbous_2\n \"\\ue3cf\", # nf-weather-moon_alt_waxing_gibbous_1\n \"\\ue3ce\", # nf-weather-moon_alt_first_quarter\n \"\\ue3cd\", # nf-weather-moon_alt_waxing_crescent_6\n \"\\ue3cc\", # nf-weather-moon_alt_waxing_crescent_5\n \"\\ue3cb\", # nf-weather-moon_alt_waxing_crescent_4\n \"\\ue3ca\", # nf-weather-moon_alt_waxing_crescent_3\n \"\\ue3c9\", # nf-weather-moon_alt_waxing_crescent_2\n \"\\ue3c8\", # nf-weather-moon_alt_waxing_crescent_1\n \"\\ue39b\", # nf-weather-moon_full\n]\nbat_charging = \"\\U000f0084\" # nf-md-battery_charging\nbat_not_available = \"\\U000f0091\" # nf-md-battery_unknown\nbat = [\n \"\\U000f007a\", # nf-md-battery_10\n \"\\U000f007b\", # nf-md-battery_20\n \"\\U000f007c\", # nf-md-battery_30\n \"\\U000f007d\", # nf-md-battery_40\n \"\\U000f007e\", # nf-md-battery_50\n \"\\U000f007f\", # nf-md-battery_60\n \"\\U000f0080\", # nf-md-battery_70\n \"\\U000f0081\", # nf-md-battery_80\n \"\\U000f0082\", # nf-md-battery_90\n \"\\U000f0079\", # nf-md-battery\n]\nbell = \"\\U000f009c\" # nf-md-bell_outline\nbell-slash = \"\\U000f009b\" # nf-md-bell_off\nblackberry = \"\\uf307\" # nf-md-blackberry\nbluetooth = \"\\U000f00af\" # nf-md-bluetooth\ncalendar = \"\\U000f00ed\" # nf-md-calendar\ncogs = \"\\U000f0493\" # nf-md-cog\ncpu = [\n\t\"\\U000F0F86\", # nf-md-speedometer_slow\n\t\"\\U000F0F85\", # nf-md-speedometer_medium\n\t\"\\U000F04C5\", # nf-md-speedometer\n]\ncpu_boost_on = \"\\U000f0521\" # nf-md-toggle_switch\ncpu_boost_off = \"\\U000f0a19\" # nf-md-toggle_switch_off_outline\ndisk_drive = \"\\U000f02ca\" # nf-md-harddisk\ndocker = \"\\uf308\" # nf-linux-docker\ngithub = \"\\U000f02a4\" # nf-md-github\ngpu = \"\\U000f0379\" # nf-md-monitor\nheadphones = \"\\U000f02cb\" # nf-md-headphones\njoystick = \"\\U000f0297\" # nf-md-gamepad_variant\nkeyboard = \"\\U000f030c\" # nf-md-keyboard\nmail = \"\\U000f01ee\" # nf-md-email\nmemory_mem = \"\\U000f035b\" # nf-md-memory\nmemory_swap = \"\\U000f02ca\" # nf-md-harddisk\nmouse = \"\\U000f037d\" # nf-md-mouse\nmusic = \"\\U000f075a\" # nf-md-music\nmusic_next = \"\\U000f04ad\" # nf-md-skip_next\nmusic_pause = \"\\U000f03e4\" # nf-md-pause\nmusic_play = \"\\U000f040a\" # nf-md-play\nmusic_prev = \"\\U000f04ae\" # nf-md-skip_previous\nnet_bridge = \"\\U000f04aa\" # nf-md-sitemap\nnet_down = \"\\U000f01da\" # nf-md-download\nnet_loopback = \"\\U000f006f\" # nf-md-backup_restore\nnet_modem = \"\\U000f03f2\" # nf-md-phone\nnet_cellular = [\n \"\\U000F08FD\", # nf-md-network_strength_off_outline\n \"\\U000F08FE\", # nf-md-network_strength_outline\n \"\\U000F08F4\", # nf-md-network_strength_1\n \"\\U000F08F6\", # nf-md-network_strength_2\n \"\\U000F08F8\", # nf-md-network_strength_3\n \"\\U000F08FA\", # nf-md-network_strength_4\n]\nnet_up = \"\\U000f0552\" # nf-md-upload\nnet_vpn = \"\\U000f0582\" # nf-md-vpn\nnet_wired = \"\\U000f0200\" # nf-md-ethernet\nnet_wireless = [\n\t\"\\U000F092F\", # nf-md-wifi_strength_outline\n\t\"\\U000F091F\", # nf-md-wifi_strength_1\n\t\"\\U000F0922\", # nf-md-wifi_strength_2\n\t\"\\U000F0925\", # nf-md-wifi_strength_3\n\t\"\\U000F0928\", # nf-md-wifi_strength_4\n]\nnotification = \"\\U000f009c\" # nf-md-bell_outline\nphone = \"\\U000f03f2\" # nf-md-phone\nphone_disconnected = \"\\U000f0658\" # nf-md-phone_minus\nping = \"\\U000f051f\" # nf-md-timer_sand\npomodoro = \"\\ue001\" # nf-pom-pomodoro_done\npomodoro_break = \"\\U000f0176\" # nf-md-coffee\npomodoro_paused = \"\\U000f03e4\" # nf-md-pause\npomodoro_started = \"\\U000f040a\" # nf-md-play\npomodoro_stopped = \"\\U000f04db\" # nf-md-stop\nresolution = \"\\U000f0293\" # nf-md-fullscreen\ntasks = \"\\U000f05c7\" # nf-md-playlist_check\ntea = \"\\U000f0d9e\" # nf-md-tea\nthermometer = [\n \"\\U000f10c3\", # nf-md-thermometer_low\n \"\\U000f050f\", # nf-md-thermometer\n \"\\U000f10c2\", # nf-md-thermometer_high\n]\ntime = \"\\U000f0150\" # nf-md-clock_outline\ntoggle_off = \"\\U000f0a19\" # nf-md-toggle_switch_off_outline\ntoggle_on = \"\\U000f0521\" # nf-md-toggle_switch\nunknown = \"\\U000f0186\" # nf-md-comment_question_outline | TODO: Make default?\nupdate = \"\\U000f03d5\" # nf-md-package_up\nuptime = \"\\U000f0153\" # nf-md-clock_in\nvolume_muted = \"\\U000f075f\" # nf-md-volume_mute\nvolume = [\n \"\\U000f057f\", # nf-md-volume_low\n \"\\U000f0580\", # nf-md-volume_medium\n \"\\U000f057e\", # nf-md-volume_high\n]\nmicrophone_muted = \"\\U000f036d\" # nf-md-microphone_off\nmicrophone = [\n\t\"\\U000f036e\", # nf-md-microphone_outline\n \"\\U000f036c\", # nf-md-microphone\n \"\\U000f036c\", # nf-md-microphone\n]\nxrandr = \"\\U000f037a\" # nf-md-monitor_multiple\n\n# Weather icons (the names the weather block documents)\nweather_sun = \"\\ue30d\" # nf-weather-day_sunny (when weather is reported as “Clear” during the day)\nweather_moon = \"\\ue32b\" # nf-weather-night_clear (when weather is reported as “Clear” at night)\nweather_clouds = \"\\ue312\" # nf-weather-cloudy (when weather is reported as “Clouds” during the day)\nweather_clouds_night = \"\\ue37e\" # nf-weather-night_alt_cloudy (when weather is reported as “Clouds” at night)\nweather_fog = \"\\ue313\" # nf-weather-fog (when weather is reported as “Fog” or “Mist” during the day)\nweather_fog_night = \"\\ue346\" # nf-weather-night_fog (when weather is reported as “Fog” or “Mist” at night)\nweather_rain = \"\\ue318\" # nf-weather-rain (when weather is reported as “Rain” or “Drizzle” during the day)\nweather_rain_night = \"\\ue325\" # nf-weather-night_alt_rain (when weather is reported as “Rain” or “Drizzle” at night)\nweather_snow = \"\\ue31a\" # nf-weather-snow (when weather is reported as “Snow”)\nweather_thunder = \"\\ue31d\" # nf-weather-thunderstorm (when weather is reported as “Thunderstorm” during the day)\nweather_thunder_night = \"\\ue32a\" # nf-weather-night_alt_thunderstorm (when weather is reported as “Thunderstorm” at night)\n" }, { "id": "updates", From b2c170acda02b62637cec16709777c4ab5592841 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 4 Oct 2026 12:54:13 +0200 Subject: [PATCH 10/15] xorg: the display server holds node-display-server and writes the session's start (hq ADR 0208) The X server, its start and its tools as one module. It provides x11-display with the machine's reach, gated by the host's seat capability. It writes a block at the start of ~/.xinitrc: the account's environment, an explicit import into the user manager, the mesh's X resources merged without cpp, autorandr, the xinitrc slots, ~/.xinitrc.local, and the session's exec from the last slot. Its Go tools serve the seat's displays and layout (autorandr profiles keyed by EDID), and set-mode, primary, dpi, input devices and settings, keyboard, a screenshot (xwd decoded in Go) and the server's log. internal/desktop is how every desktop tool finds the operator's session from the runtime, which has none: from the session's own processes, reading only its words, confirmed with logind. --- modules/xorg/README.md | 189 ++++++ modules/xorg/cmd/xorg/displays.go | 232 +++++++ modules/xorg/cmd/xorg/input.go | 137 ++++ modules/xorg/cmd/xorg/layout.go | 105 +++ modules/xorg/cmd/xorg/main.go | 167 +++++ modules/xorg/cmd/xorg/manifest_test.go | 243 +++++++ modules/xorg/cmd/xorg/testdata/setxkbmap.txt | 3 + .../xorg/cmd/xorg/testdata/xinput-list.txt | 25 + .../cmd/xorg/testdata/xinput-props-16.txt | 48 ++ .../xorg/cmd/xorg/testdata/xrandr-prop.txt | 437 +++++++++++++ modules/xorg/cmd/xorg/tools.go | 602 ++++++++++++++++++ modules/xorg/cmd/xorg/xlog.go | 103 +++ modules/xorg/cmd/xorg/xorg_test.go | 338 ++++++++++ modules/xorg/cmd/xorg/xwd.go | 83 +++ modules/xorg/go.mod | 5 + modules/xorg/go.sum | 2 + modules/xorg/internal/desktop/args.go | 160 +++++ modules/xorg/internal/desktop/copies_test.go | 42 ++ modules/xorg/internal/desktop/run.go | 232 +++++++ modules/xorg/internal/desktop/session.go | 445 +++++++++++++ modules/xorg/internal/desktop/session_test.go | 255 ++++++++ modules/xorg/module.json | 121 ++++ 22 files changed, 3974 insertions(+) create mode 100644 modules/xorg/README.md create mode 100644 modules/xorg/cmd/xorg/displays.go create mode 100644 modules/xorg/cmd/xorg/input.go create mode 100644 modules/xorg/cmd/xorg/layout.go create mode 100644 modules/xorg/cmd/xorg/main.go create mode 100644 modules/xorg/cmd/xorg/manifest_test.go create mode 100644 modules/xorg/cmd/xorg/testdata/setxkbmap.txt create mode 100644 modules/xorg/cmd/xorg/testdata/xinput-list.txt create mode 100644 modules/xorg/cmd/xorg/testdata/xinput-props-16.txt create mode 100644 modules/xorg/cmd/xorg/testdata/xrandr-prop.txt create mode 100644 modules/xorg/cmd/xorg/tools.go create mode 100644 modules/xorg/cmd/xorg/xlog.go create mode 100644 modules/xorg/cmd/xorg/xorg_test.go create mode 100644 modules/xorg/cmd/xorg/xwd.go create mode 100644 modules/xorg/go.mod create mode 100644 modules/xorg/go.sum create mode 100644 modules/xorg/internal/desktop/args.go create mode 100644 modules/xorg/internal/desktop/copies_test.go create mode 100644 modules/xorg/internal/desktop/run.go create mode 100644 modules/xorg/internal/desktop/session.go create mode 100644 modules/xorg/internal/desktop/session_test.go create mode 100644 modules/xorg/module.json diff --git a/modules/xorg/README.md b/modules/xorg/README.md new file mode 100644 index 0000000..cdc9785 --- /dev/null +++ b/modules/xorg/README.md @@ -0,0 +1,189 @@ +# xorg + +The X display server as a module (novox/hq ADR 0208, research 026, to-be 42 phase 2 step 2). + +- **Claims `node-display-server`** and serves its verbs `displays` and `layout`. +- **Provides `x11-display` with the machine's reach**: i3, xterm, picom and the X lock screen require + it, and a requirement for it is met only by this module on the same machine. It is never pulled in + for whatever asked. +- **Gated by the capability `seat`**, which the host reports for a machine with a graphics device + and a connected display. See *Blockers* for why not `graphical-session`. +- **Packages:** `xorg-server`, `xorg-xinit`, `xorg-xrandr`, `xorg-xset`, `xorg-xrdb`, `xorg-xinput`, + `xorg-setxkbmap`, `xorg-xwd` and `autorandr`. The GPU's driver is not here. It follows the machine, + so it belongs to that machine model's hardware module. + +## What it owns + +| path | class (ADR 0182) | what | +|---|---|---| +| `~/.xinitrc`, a block at the start | written into (`block`, `at: start`) | the session's start, below | +| `~/.config/xorg/` | owned directory | | +| `~/.config/xorg/xresources` | owned | the mesh's X resources: font rendering (`Xft.*`, DPI 96) and the three `xresources` slots | + +**The session's start**, in ADR 0208 §5's order: + +1. It sources `~/.config/mesh/environment.sh` (ADR 0203). If pam did not hand over a session bus, it + takes the user manager's socket, never a second bus. +2. It imports an explicit list of the session's words into the user manager and D-Bus activation, + only those that are set. The list is `DISPLAY`, `XAUTHORITY`, `XDG_SESSION_TYPE`, + `XDG_CURRENT_DESKTOP`, `XDG_SESSION_DESKTOP`, `XDG_CONFIG_HOME`, `XDG_DATA_DIRS`, `GTK_THEME`, + `GTK2_RC_FILES`, `QT_QPA_PLATFORMTHEME`, `QT_STYLE_OVERRIDE`, `QT_SELECT`, `XCURSOR_THEME`, + `XCURSOR_SIZE` and `TERMINAL`. It never uses `--all`. +3. It merges `~/.config/xorg/xresources` with `xrdb -nocpp`, then `~/.Xresources` if you keep one, + so yours win. +4. It runs `autorandr --change`, which applies the saved profile matching the connected monitors. +5. It runs the `xinitrc` slots `first` and `normal`, then sources **`~/.xinitrc.local`** if it exists. +6. It runs the `last` slot, where the holder of `node-display-session` starts the session (`exec i3`). + +**Who contributes where**, among the desktop's modules: + +| slot | module | what | +|---|---|---| +| `first` | `gnome-keyring` | `SSH_AUTH_SOCK` | +| `normal` | `adwaita` | its GSettings keys | +| `normal` | `clipmenu` | `clipmenud &` | +| `normal` | `feh` | the wallpaper | +| `normal` | `i3status-rust` | the bar watchdog | +| `normal` | `screen-lock` | the timeouts and the `xss-lock` loop | +| `last` | `i3` | `exec i3` | + +**Slot `last` is the session's.** A module contributing session lines uses `first` or `normal`. +Code in `last` that sorts after the session holder's name would come after its `exec` and never run. + +**Why `~/.xinitrc.local`.** The block ends by starting the session, so no line below it runs. Your own +session lines go into `~/.xinitrc.local`. Like `~/.zshrc.local`, it is yours: found, never written. +This is the one step this module adds to ADR 0208 §5. Without it, a line no module carries yet (a +`DOTNET_ROOT`, a wallpaper) would have nowhere to run. + +**Resources without the preprocessor.** `xrdb -nocpp` needs no C compiler on the machine, and it +skips a line starting with `#`. The controller precedes each contribution with a `# ` line, +which is a cpp directive error under plain `xrdb -merge` but is skipped here. + +## Tools + +| tool | | what | +|---|---|---| +| `node-display-server.displays` | r | the screen and every output: position, rotation, size, DPI, the monitor's EDID identity (manufacturer, product, serial, name, fingerprint), current and preferred mode, every mode and rate, the autorandr profile in force | +| `node-display-server.layout` | r/a | autorandr profiles: `list` (each with the monitors it is for, which match now, which is current), `save` (`replace` to overwrite), `apply` | +| `xorg_set_mode` | a | one output's mode, rate, rotation, scale, position (x/y or beside another), off, primary; `dry_run` | +| `xorg_primary` | r/a | which output is primary; set it | +| `xorg_dpi` | r/a | `Xft.dpi` beside each monitor's physical DPI; set it for the running session | +| `xorg_input_devices` | r | the input devices, and each pointer's libinput settings | +| `xorg_input_set` | a | tap, tap drag, natural scroll, disable while typing, left handed, middle emulation, enabled, acceleration, by device id or name | +| `xorg_keyboard` | r/a | the XKB map; set layout, variant, model, options | +| `xorg_screenshot` | d | a PNG of the screen, one output or one window, inside the home (default `~/Pictures/Screenshots/`) | +| `xorg_x_log` | r | the X server's log for the running session: version, start, errors (and warnings) | + +All answers are structured. Each tool that changes the running server says how long the change lasts. + +**How a tool reaches the session** (`internal/desktop`, the same copy in every desktop module). The +runtime is a system service running as the operator account. It has no `DISPLAY`, no `XAUTHORITY` and +no session bus. The tool reads them from the session's own processes: + +1. It looks at the account's processes, preferring the window manager. +2. It reads only a fixed list of words, never the rest. A session's environment held secrets on these + machines. +3. It asks logind whether that session is active and local. +4. It checks that the display's socket still exists. + +The bus it hands on is the user manager's (`unix:path=/run/user//bus`). With no session, a tool +answers `{"error": "no-graphical-session", "reason": …, "looked": […]}`. + +The screenshot needs no screenshot program. `xwd` dumps the screen, and the module turns the dump +into a PNG itself. + +## What it improves + +- **One environment.** The session sources the shells' environment file. It no longer exports a + hand-kept second copy, and never sources the predecessor's secrets file. +- **No compiler needed for the mesh's resources**, and contributions are placed in order rather than + `#include`d. +- **Monitor layouts by the monitors' identity** (autorandr, research 026/04), not scripts with port + names baked in. The package's own udev rule and service apply the matching profile on hotplug. +- **No second bus.** The `dbus-launch` fallback that once ran the whole session on a private bus is + gone. That stale session can still be seen today on one workstation: `session_bus` in a tool's + answer shows it. + +## What it leaves found + +`~/.xprofile`, `~/.Xresources`, `~/.Xresources.d/`, `~/.screenlayout/`, the arandr scripts, every +line of yours below the block, and `/etc/X11/xinit/xinitrc.d/`. + +## The one-off migration (ADR 0182) + +**Assign the desktop's modules together** (`xorg`, `lemurs`, `i3`, `xterm`, `adwaita` and the +companions above) and do this migration first. **Until `i3` is assigned, nothing changes for you.** The block's `last` slot is empty, so the block +runs and falls through to your own lines below it, which still end in `exec i3`. The environment is +sourced twice and the import runs twice, which is harmless. + +**Once `i3` is assigned, nothing below the block runs.** Before that push, sort today's +`~/.xinitrc` lines (both workstations hold the same file): + +| today's line | where it goes | +|---|---| +| the `/etc/X11/xinit/xinitrc.d/?*.sh` loop | **delete**: the block imports `DISPLAY` and `XAUTHORITY` itself, and the login manager's X setup runs that directory too | +| `eval $(gnome-keyring-daemon --start …)` and `export SSH_AUTH_SOCK` | **delete** once `gnome-keyring` is assigned. PAM starts and unlocks the keyring, and that module names the ssh agent's socket in the `xinitrc` slot `first`. Until then, `~/.xinitrc.local` | +| `export PATH=…` (nine entries) | `~/.local/bin`, `~/scripts` and `~/scripts/bin` come from `zsh`'s environment already. **Delete** `~/scripts/i3-sessions/commands` and `~/scripts/mediahuis`: neither exists on either workstation. Move `~/.cargo/bin`, `~/.config/rofi/scripts`, `~/.dotnet` and `~/.dotnet/tools` to `~/.xinitrc.local` until a module carries them | +| `DOTNET_ROOT`, `DOTNET_CLI_TELEMETRY_OPTOUT` | `~/.xinitrc.local` | +| `XDG_CONFIG_HOME` | **delete**: `zsh` contributes it | +| `XDG_DATA_DIRS` with the flatpak directories | `~/.xinitrc.local` until the `flatpak` module | +| `QT_QPA_PLATFORMTHEME`, `GTK_THEME`, `QT_STYLE_OVERRIDE`, `GTK2_RC_FILES`, `QT_SELECT` | **delete** once `adwaita` is assigned (its environment contributions) | +| `XDG_SESSION_DESKTOP`, `XDG_CURRENT_DESKTOP` and their comment | **delete** once `i3` is assigned | +| `dbus-update-activation-environment --systemd …` and its comment | **delete**: the block's step 2 | +| `~/scripts/xdg-appearance \|\| true` | **delete** once `adwaita` is assigned | +| `MY_KV_PATH`, `MY_LIB_PATH`, `MY_STREAMING_PATH` | `~/.xinitrc.local` (they are yours) | +| `[ -f "$HOME/.config/hal/env" ] && . …` (the secrets file) | **delete** (ADR 0208 §5, research 027 Q2). Whatever in the session needed one of those tokens gets it the way research 027 settles | +| `xset s 1800`, `xset dpms 1800 1800 3600` | **delete** once `screen-lock` is assigned (its `normal` slot line). Until then, `~/.xinitrc.local` | +| `~/.fehbg &` | **delete** once `feh` is assigned (its `normal` slot line). Until then, `~/.xinitrc.local` | +| the `xss-lock` respawn loop | **delete** once `screen-lock` is assigned. Until then, `~/.xinitrc.local` | +| `exec i3 --shmlog-size=26214400` | **delete**: `i3` contributes `exec i3` to the `last` slot | + +Then **delete everything below the block**. The old `#!/bin/sh` line now sits below the block too and +means nothing there. The file is run with `sh` (by the login manager's entry and by `startx`), never +executed by its first line. + +**`~/.xprofile`.** The login manager's X setup sources it, and it sources `~/.xinitrc`. Once `i3` and +`lemurs` are assigned, the session entry `/etc/lemurs/wms/i3` runs `~/.xinitrc` itself, so **delete +`~/.xprofile`**. Its bus logic is the block's now. If you keep it, delete its `. ~/.xinitrc` line, or +the session starts from `.xprofile` and the login manager's entry is never reached. Either way works +once, but only one should. + +**`~/.Xresources`** holds `#include ".Xresources.d/xterm"`, `#include ".Xresources.d/xft"` and the +two `Xcursor` lines: + +- The `xft` include and `~/.Xresources.d/xft` are **deleted** now. This module's file carries the + same five values. +- The `xterm` include and `~/.Xresources.d/xterm` are **deleted** once `xterm` is assigned. Kept, + they win over the module's font and colours. +- The `Xcursor` lines are **deleted** once `adwaita` is assigned. +- A file left empty is deleted. + +**Monitor layouts.** For each place you use, arrange the monitors (`xorg_set_mode`, or arandr once +more), then `layout` `save` it under a name. Once every place has a profile, these retire: the +`~/.screenlayout/` and `~/scripts/.screenlayouts/` scripts, the laptop's hotplug rule, and its i3 +bindings. Those bindings belong to that machine's hardware module, not here. + +## What changes when it is assigned + +| | g14 (laptop) | shanks (desktop) | +|---|---|---| +| packages | `autorandr` installed; the rest are there already | the same | +| files | `~/.config/xorg/xresources` new; a block added at the start of `~/.xinitrc` | the same | +| running session | nothing: everything takes effect at the next login | nothing | +| next login, before `i3` is assigned | the block runs, then the old file below it. Fonts unchanged (96 DPI); `autorandr --change` does nothing with no profiles | the same. Its session moves to the user manager's bus at the next login, as it should have | +| next login, after `i3` is assigned | only the block: what the table above did not move is gone | the same | + +## Blockers + +- **The capability.** ADR 0208 §3 says `graphical-session` gates the display server. The host + reports that capability from its own environment. It is a root daemon with no `DISPLAY`, so the + capability is **no on both workstations** (`node show`, 2026-10-04). Gated on it, `xorg` could + never be assigned. This manifest uses **`seat`** instead: graphics hardware with a connected + display, yes on both. The ADR's wording needs a progressive insight, or the host needs a probe + that finds the session the way `internal/desktop` does. +- **Unassigning removes the packages.** The host takes a package away when its declaration goes, + and `xorg-server` is among them. Do not unassign `xorg` from a workstation you are sitting at + without another display server assigned. +- **The `# ` naming lines in the `xresources` slots** are safe only because this module + merges with `-nocpp`. If the controller rendered `!` for `xresources`, that would be the + format's own comment. diff --git a/modules/xorg/cmd/xorg/displays.go b/modules/xorg/cmd/xorg/displays.go new file mode 100644 index 0000000..26a1900 --- /dev/null +++ b/modules/xorg/cmd/xorg/displays.go @@ -0,0 +1,232 @@ +package main + +import ( + "bufio" + "crypto/sha256" + "encoding/hex" + "fmt" + "regexp" + "strconv" + "strings" +) + +// Screen is the X screen as xrandr reports it. +type Screen struct { + Width int `json:"width"` + Height int `json:"height"` + MaxWidth int `json:"max_width"` + MaxHeight int `json:"max_height"` +} + +// Output is one connector: a monitor when connected. +type Output struct { + Name string `json:"name"` + Connected bool `json:"connected"` + Primary bool `json:"primary,omitempty"` + Enabled bool `json:"enabled"` + Geometry *Geometry `json:"geometry,omitempty"` + Rotation string `json:"rotation,omitempty"` + Reflect string `json:"reflect,omitempty"` + WidthMM int `json:"width_mm,omitempty"` + HeightMM int `json:"height_mm,omitempty"` + // DPI is the physical density of the current mode, from the size the monitor reports. + DPI float64 `json:"dpi,omitempty"` + Monitor *Identity `json:"monitor,omitempty"` + Current *ModeRate `json:"current,omitempty"` + Preferred *ModeRate `json:"preferred,omitempty"` + Modes []Mode `json:"modes,omitempty"` + + edid []byte +} + +// Geometry is where an output's picture sits on the screen. +type Geometry struct { + Width int `json:"width"` + Height int `json:"height"` + X int `json:"x"` + Y int `json:"y"` +} + +// Mode is one resolution and the refresh rates it is offered at. +type Mode struct { + Size string `json:"size"` + Rates []float64 `json:"rates"` +} + +// ModeRate is one resolution at one rate. +type ModeRate struct { + Size string `json:"size"` + Rate float64 `json:"rate"` +} + +// Identity is who the monitor is, from its EDID: what an autorandr profile is keyed by, and a name a +// person recognises. +type Identity struct { + Manufacturer string `json:"manufacturer"` + Product string `json:"product"` + Serial string `json:"serial,omitempty"` + Name string `json:"name,omitempty"` + Year int `json:"year,omitempty"` + // Fingerprint is the first 12 hex characters of the EDID's sha256: one monitor, whatever port. + Fingerprint string `json:"fingerprint"` +} + +var ( + screenLine = regexp.MustCompile(`^Screen \d+: minimum \d+ x \d+, current (\d+) x (\d+), maximum (\d+) x (\d+)`) + geometryRe = regexp.MustCompile(`^(\d+)x(\d+)\+(-?\d+)\+(-?\d+)$`) + sizeMM = regexp.MustCompile(`\)\s+(\d+)mm x (\d+)mm`) +) + +// ParseXrandr reads `xrandr --prop` (or `--query`): the screen, and every output with its modes and, +// where the properties carry one, its EDID decoded. +func ParseXrandr(text string) (Screen, []Output) { + var screen Screen + var outs []Output + var cur *Output + inEDID := false + sc := bufio.NewScanner(strings.NewReader(text)) + sc.Buffer(make([]byte, 1<<20), 1<<22) + for sc.Scan() { + line := sc.Text() + switch { + case strings.HasPrefix(line, "Screen "): + if m := screenLine.FindStringSubmatch(line); m != nil { + screen = Screen{atoi(m[1]), atoi(m[2]), atoi(m[3]), atoi(m[4])} + } + inEDID = false + case line != "" && line[0] != ' ' && line[0] != '\t': + outs = append(outs, parseOutputLine(line)) + cur = &outs[len(outs)-1] + inEDID = false + case cur == nil: + case strings.HasPrefix(line, "\t\t"): + if inEDID { + if b, err := hex.DecodeString(strings.TrimSpace(line)); err == nil { + cur.edid = append(cur.edid, b...) + } + } + case strings.HasPrefix(line, "\t"): + inEDID = strings.HasPrefix(strings.TrimSpace(line), "EDID:") + case strings.HasPrefix(line, " "): + inEDID = false + parseModeLine(cur, line) + } + } + for i := range outs { + o := &outs[i] + if len(o.edid) >= 128 { + o.Monitor = DecodeEDID(o.edid) + } + if o.Geometry != nil && o.WidthMM > 0 { + w := o.Geometry.Width + if o.Rotation == "left" || o.Rotation == "right" { + w = o.Geometry.Height + } + o.DPI = float64(int(float64(w)/(float64(o.WidthMM)/25.4)*10+0.5)) / 10 + } + } + return screen, outs +} + +func parseOutputLine(line string) Output { + f := strings.Fields(line) + o := Output{Name: f[0], Connected: len(f) > 1 && f[1] == "connected"} + for _, tok := range f[2:] { + if strings.HasPrefix(tok, "(") { + break + } + switch { + case tok == "primary": + o.Primary = true + case geometryRe.MatchString(tok): + g := geometryRe.FindStringSubmatch(tok) + o.Geometry = &Geometry{atoi(g[1]), atoi(g[2]), atoi(g[3]), atoi(g[4])} + o.Enabled = true + case tok == "normal" || tok == "left" || tok == "inverted" || tok == "right": + o.Rotation = tok + case tok == "X" || tok == "Y" || tok == "and" || tok == "axis": + o.Reflect = strings.TrimSpace(o.Reflect + " " + tok) + } + } + if o.Enabled && o.Rotation == "" { + o.Rotation = "normal" + } + if m := sizeMM.FindStringSubmatch(line); m != nil { + o.WidthMM, o.HeightMM = atoi(m[1]), atoi(m[2]) + } + return o +} + +// parseModeLine reads ` 2880x1800 60.00*+ 120.00 +`: a rate marked * is in use, + preferred, +// and xrandr writes the + as a token of its own after a rate not in use. A panel may mark several +// rates preferred; the first is the monitor's own preference. +func parseModeLine(o *Output, line string) { + f := strings.Fields(line) + if len(f) == 0 || !strings.Contains(f[0], "x") { + return + } + mode := Mode{Size: f[0]} + for _, tok := range f[1:] { + if tok == "+" { + if n := len(mode.Rates); n > 0 && o.Preferred == nil { + o.Preferred = &ModeRate{mode.Size, mode.Rates[n-1]} + } + continue + } + current := strings.Contains(tok, "*") + preferred := strings.Contains(tok, "+") + rate, err := strconv.ParseFloat(strings.Trim(tok, "*+"), 64) + if err != nil { + continue + } + mode.Rates = append(mode.Rates, rate) + if current { + o.Current = &ModeRate{mode.Size, rate} + } + if preferred && o.Preferred == nil { + o.Preferred = &ModeRate{mode.Size, rate} + } + } + o.Modes = append(o.Modes, mode) +} + +// DecodeEDID reads the vendor block and the descriptors of an EDID. +func DecodeEDID(e []byte) *Identity { + if len(e) < 128 { + return nil + } + sum := sha256.Sum256(e) + id := &Identity{Fingerprint: hex.EncodeToString(sum[:])[:12]} + v := uint16(e[8])<<8 | uint16(e[9]) + id.Manufacturer = string([]byte{ + byte('A' - 1 + (v>>10)&0x1f), byte('A' - 1 + (v>>5)&0x1f), byte('A' - 1 + v&0x1f), + }) + id.Product = fmt.Sprintf("%04X", uint16(e[10])|uint16(e[11])<<8) + if serial := uint32(e[12]) | uint32(e[13])<<8 | uint32(e[14])<<16 | uint32(e[15])<<24; serial != 0 { + id.Serial = strconv.FormatUint(uint64(serial), 10) + } + if e[17] != 0 { + id.Year = 1990 + int(e[17]) + } + for _, at := range []int{54, 72, 90, 108} { + d := e[at : at+18] + if d[0] != 0 || d[1] != 0 || d[2] != 0 { + continue + } + text := strings.TrimSpace(strings.SplitN(string(d[5:18]), "\n", 2)[0]) + switch d[3] { + case 0xfc: + id.Name = text + case 0xff: + if text != "" { + id.Serial = text + } + } + } + return id +} + +func atoi(s string) int { + n, _ := strconv.Atoi(s) + return n +} diff --git a/modules/xorg/cmd/xorg/input.go b/modules/xorg/cmd/xorg/input.go new file mode 100644 index 0000000..6ffb7d5 --- /dev/null +++ b/modules/xorg/cmd/xorg/input.go @@ -0,0 +1,137 @@ +package main + +import ( + "bufio" + "regexp" + "strconv" + "strings" +) + +// Device is one input device the X server knows. +type Device struct { + ID int `json:"id"` + Name string `json:"name"` + Role string `json:"role"` // master or slave + Kind string `json:"kind"` // pointer or keyboard + Settings map[string]any `json:"settings,omitempty"` +} + +var deviceLine = regexp.MustCompile(`^[^A-Za-z0-9]*(.+?)\s+id=(\d+)\s+\[(master|slave|floating)\s+(pointer|keyboard)?`) + +// ParseDevices reads `xinput list`, the tree's drawing characters stripped. +func ParseDevices(text string) []Device { + var out []Device + sc := bufio.NewScanner(strings.NewReader(text)) + for sc.Scan() { + m := deviceLine.FindStringSubmatch(sc.Text()) + if m == nil { + continue + } + id, _ := strconv.Atoi(m[2]) + kind := m[4] + if kind == "" { + kind = "floating" + } + out = append(out, Device{ID: id, Name: strings.TrimSpace(m[1]), Role: m[3], Kind: kind}) + } + return out +} + +// Knob is one setting input-set changes, and the libinput property that holds it. +type Knob struct { + Arg, Property, Kind string // Kind: bool or float +} + +// Knobs are what input-set may change, by libinput's own property names (libinput(4)). +var Knobs = []Knob{ + {"enabled", "Device Enabled", "bool"}, + {"tap", "libinput Tapping Enabled", "bool"}, + {"tap_drag", "libinput Tapping Drag Enabled", "bool"}, + {"natural_scroll", "libinput Natural Scrolling Enabled", "bool"}, + {"disable_while_typing", "libinput Disable While Typing Enabled", "bool"}, + {"left_handed", "libinput Left Handed Enabled", "bool"}, + {"middle_emulation", "libinput Middle Emulation Enabled", "bool"}, + {"accel_speed", "libinput Accel Speed", "float"}, +} + +var propLine = regexp.MustCompile(`^\s+(.+?) \(\d+\):\s*(.*)$`) + +// ParseProps reads `xinput list-props` into the settings Knobs name, as booleans and numbers. A +// device without a property (a keyboard has no tapping) simply lacks the setting. +func ParseProps(text string) map[string]any { + byProp := map[string]string{} + sc := bufio.NewScanner(strings.NewReader(text)) + for sc.Scan() { + if m := propLine.FindStringSubmatch(sc.Text()); m != nil { + byProp[m[1]] = strings.TrimSpace(m[2]) + } + } + out := map[string]any{} + for _, k := range Knobs { + v, ok := byProp[k.Property] + if !ok { + continue + } + first := strings.TrimSpace(strings.Split(v, ",")[0]) + switch k.Kind { + case "bool": + out[k.Arg] = first == "1" + case "float": + if f, err := strconv.ParseFloat(first, 64); err == nil { + out[k.Arg] = f + } + } + } + if v, ok := byProp["libinput Accel Profile Enabled"]; ok { + profiles := []string{"adaptive", "flat", "custom"} + for i, bit := range strings.Split(v, ",") { + if strings.TrimSpace(bit) == "1" && i < len(profiles) { + out["accel_profile"] = profiles[i] + } + } + } + return out +} + +// Keyboard is the X keyboard map as setxkbmap reports it. +type Keyboard struct { + Rules string `json:"rules,omitempty"` + Model string `json:"model,omitempty"` + Layout string `json:"layout,omitempty"` + Variant string `json:"variant,omitempty"` + Options []string `json:"options"` +} + +// ParseKeyboard reads `setxkbmap -query`. +func ParseKeyboard(text string) Keyboard { + k := Keyboard{Options: []string{}} + sc := bufio.NewScanner(strings.NewReader(text)) + for sc.Scan() { + key, value, ok := strings.Cut(sc.Text(), ":") + if !ok { + continue + } + value = strings.TrimSpace(value) + switch strings.TrimSpace(key) { + case "rules": + k.Rules = value + case "model": + k.Model = value + case "layout": + k.Layout = value + case "variant": + k.Variant = value + case "options": + for _, o := range strings.Split(value, ",") { + if o = strings.TrimSpace(o); o != "" { + k.Options = append(k.Options, o) + } + } + } + } + return k +} + +// xkbName is what setxkbmap accepts as a layout, variant, model or option: letters, digits and the +// punctuation XKB names use. Anything else is refused before it reaches a command line. +var xkbName = regexp.MustCompile(`^[A-Za-z0-9_:+(),.-]+$`) diff --git a/modules/xorg/cmd/xorg/layout.go b/modules/xorg/cmd/xorg/layout.go new file mode 100644 index 0000000..8845fab --- /dev/null +++ b/modules/xorg/cmd/xorg/layout.go @@ -0,0 +1,105 @@ +package main + +import ( + "bufio" + "os" + "path/filepath" + "regexp" + "sort" + "strings" +) + +// Profile is one saved autorandr layout: the monitors it is for, by output and EDID fingerprint. +type Profile struct { + Name string `json:"name"` + Path string `json:"path"` + Monitors map[string]string `json:"monitors"` + Detected bool `json:"detected,omitempty"` + Current bool `json:"current,omitempty"` +} + +// profileName is what a profile may be called: it becomes a directory name. +var profileName = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$`) + +// ProfileDirs are where autorandr keeps profiles, the account's first (autorandr(1)). +func ProfileDirs(home string) []string { + cfg := os.Getenv("XDG_CONFIG_HOME") + if cfg == "" { + cfg = filepath.Join(home, ".config") + } + return []string{filepath.Join(cfg, "autorandr"), "/etc/xdg/autorandr"} +} + +// ReadProfiles lists the profiles in dirs; a name in an earlier directory hides a later one, as in +// autorandr itself. Each profile's monitors come from its `setup` file: ` ` per line. +func ReadProfiles(dirs []string) []Profile { + seen := map[string]bool{} + var out []Profile + for _, dir := range dirs { + entries, err := os.ReadDir(dir) + if err != nil { + continue + } + for _, e := range entries { + if !e.IsDir() || seen[e.Name()] { + continue + } + setup := filepath.Join(dir, e.Name(), "setup") + f, err := os.Open(setup) + if err != nil { + continue + } + p := Profile{Name: e.Name(), Path: filepath.Join(dir, e.Name()), Monitors: map[string]string{}} + sc := bufio.NewScanner(f) + for sc.Scan() { + fields := strings.Fields(sc.Text()) + if len(fields) == 2 { + p.Monitors[fields[0]] = shortEDID(fields[1]) + } + } + f.Close() + seen[e.Name()] = true + out = append(out, p) + } + } + sort.Slice(out, func(i, j int) bool { return out[i].Name < out[j].Name }) + return out +} + +// shortEDID is the fingerprint DecodeEDID gives for the same monitor, so a profile's monitors and the +// connected ones are compared by one value. +func shortEDID(hexEDID string) string { + b := make([]byte, 0, len(hexEDID)/2) + for i := 0; i+1 < len(hexEDID); i += 2 { + var v byte + for _, c := range hexEDID[i : i+2] { + v <<= 4 + switch { + case c >= '0' && c <= '9': + v |= byte(c - '0') + case c >= 'a' && c <= 'f': + v |= byte(c - 'a' + 10) + case c >= 'A' && c <= 'F': + v |= byte(c - 'A' + 10) + default: + return hexEDID + } + } + b = append(b, v) + } + if id := DecodeEDID(b); id != nil { + return id.Fingerprint + } + return hexEDID +} + +// names reads autorandr's one-name-per-line answers (--detected, --current). +func names(text string) map[string]bool { + out := map[string]bool{} + for _, l := range strings.Split(text, "\n") { + if l = strings.TrimSpace(l); l != "" { + out[strings.Fields(l)[0]] = true + } + } + return out +} diff --git a/modules/xorg/cmd/xorg/main.go b/modules/xorg/cmd/xorg/main.go new file mode 100644 index 0000000..fd28adf --- /dev/null +++ b/modules/xorg/cmd/xorg/main.go @@ -0,0 +1,167 @@ +// xorg's tools (novox/hq ADR 0208, research 026/05): node-display-server's verbs `displays` and +// `layout`, and the module's own tools for one output's mode, the primary output, DPI, input devices, +// the keyboard map, a screenshot and the server's log. +// +// Every tool that touches the screen acts in the operator's running session, which it finds through +// internal/desktop: the node's runtime has none of its own. With no session, the answer says so as +// structured data. A tool that changes the running server changes it until the next login; the +// answer says what makes it last. +package main + +import ( + "context" + "fmt" + "os" + "time" + + stdio "git.novox.be/novox/mesh-sdk/go" + + "xorg/internal/desktop" +) + +// The session's holders this module prefers as the session's own process. +var sessionHolders = []string{"i3", "sway", "openbox", "bspwm", "awesome", "xmonad"} + +func main() { + if err := stdio.Serve("", tools(desktop.Machine(sessionHolders...))); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +// call bounds one tool call below the runtime's 30 s limit. +func call(run func(ctx context.Context, a desktop.Args) (any, error)) func(map[string]any) (any, error) { + return func(args map[string]any) (any, error) { + ctx, cancel := context.WithTimeout(context.Background(), 25*time.Second) + defer cancel() + return run(ctx, desktop.Args(args)) + } +} + +func tools(d desktop.Desk) []stdio.Tool { + x := xorg{d: d} + return []stdio.Tool{ + { + Name: "node-display-server.displays", + Description: "The X screen and every output: connected or not, primary, where it sits, its rotation, " + + "physical size and DPI, the monitor's identity from its EDID (manufacturer, product, serial, name, " + + "fingerprint), the current and preferred mode, and every mode with its rates. Disconnected outputs " + + "are listed by name only unless all is true. Also the autorandr profile in force, when one matches.", + Input: desktop.Schema(map[string]any{ + "all": desktop.Flag("list disconnected outputs in full (default false)"), + "modes": desktop.Flag("list every mode of each output (default true)"), + }), + Run: call(x.displays), + }, + { + Name: "node-display-server.layout", + Description: "Monitor layout profiles (autorandr), keyed by the connected monitors' identities, so one " + + "profile needs no machine's name. list: every profile with the monitors it is for, which match " + + "the monitors connected now and which is in force. save: the current arrangement under a name " + + "(replace true to overwrite). apply: load one. The profiles are the operator's data, never the mesh's.", + Input: desktop.Schema(map[string]any{ + "action": desktop.Enum("list, save or apply", "list", "save", "apply"), + "name": desktop.Str("the profile to save or apply"), + "replace": desktop.Flag("save over an existing profile of that name (default false)"), + }, "action"), + Run: call(x.layout), + }, + { + Name: "xorg_set_mode", + Description: "Change one output now, through xrandr: its mode (WxH, or auto for the preferred one), rate, " + + "rotation, scale, position (x/y, or beside another output), on or off, primary. dry_run answers " + + "the command without running it. Lasts until the next login or hotplug: save a layout profile to keep it.", + Input: desktop.Schema(map[string]any{ + "output": desktop.Str("the output, as displays names it (e.g. eDP-1)"), + "mode": desktop.Str("WxH, or auto for the monitor's preferred mode"), + "rate": desktop.Num("refresh rate in Hz"), + "rotate": desktop.Enum("rotation", "normal", "left", "right", "inverted"), + "scale": desktop.Num("scale factor, 0.25 to 4 (1 = none)"), + "x": desktop.Int("left edge on the screen, in pixels"), + "y": desktop.Int("top edge on the screen, in pixels"), + "relation": desktop.Enum("place it beside another output instead of at x/y", "right-of", "left-of", "above", "below", "same-as"), + "of": desktop.Str("the output the relation is to"), + "off": desktop.Flag("switch the output off"), + "primary": desktop.Flag("make it the primary output"), + "dry_run": desktop.Flag("answer the command, run nothing"), + }, "output"), + Run: call(x.setMode), + }, + { + Name: "xorg_primary", + Description: "Which output is primary (the one the bar's tray and new windows prefer); with output, make it primary now.", + Input: desktop.Schema(map[string]any{"output": desktop.Str("the output to make primary (optional)")}), + Run: call(x.primary), + }, + { + Name: "xorg_dpi", + Description: "The DPI X programs are told (Xft.dpi) beside each monitor's physical DPI. With value, set " + + "Xft.dpi and the screen's DPI now: programs started after it use it. The module's resources file " + + "sets it again at the next login (96 until it is a setting).", + Input: desktop.Schema(map[string]any{"value": desktop.Int("dots per inch, 48 to 480 (optional)")}), + Run: call(x.dpi), + }, + { + Name: "xorg_input_devices", + Description: "The input devices the X server knows: id, name, pointer or keyboard, master or slave, and " + + "for each pointer its libinput settings (tap, natural scroll, acceleration, disable while typing, " + + "left handed, enabled).", + Input: desktop.Schema(map[string]any{"name": desktop.Str("only devices whose name contains this (optional)")}), + Run: call(x.inputDevices), + }, + { + Name: "xorg_input_set", + Description: "Change libinput settings of a device now: tap, tap_drag, natural_scroll, disable_while_typing, " + + "left_handed, middle_emulation, enabled (true/false), accel_speed (-1 to 1). The device is an id or a " + + "name; a name applies to every device of that name that has the setting. Lasts until the device " + + "reconnects or the next login.", + Input: desktop.Schema(map[string]any{ + "device": desktop.Str("the device's id or exact name"), + "tap": desktop.Flag("tap to click"), + "tap_drag": desktop.Flag("tap and drag"), + "natural_scroll": desktop.Flag("natural (reversed) scrolling"), + "disable_while_typing": desktop.Flag("ignore the touchpad while typing"), + "left_handed": desktop.Flag("swap the buttons"), + "middle_emulation": desktop.Flag("both buttons together are the middle one"), + "enabled": desktop.Flag("the device takes input at all"), + "accel_speed": desktop.Num("pointer acceleration, -1 to 1"), + }, "device"), + Run: call(x.inputSet), + }, + { + Name: "xorg_keyboard", + Description: "The X keyboard map: rules, model, layout, variant and options. With layout, variant, model " + + "or options, set them now (options replace the current ones; an empty list clears them). Lasts " + + "until the next login.", + Input: desktop.Schema(map[string]any{ + "layout": desktop.Str("e.g. us, be, us,be"), + "variant": desktop.Str("e.g. intl"), + "model": desktop.Str("e.g. pc105"), + "options": desktop.List("e.g. [\"caps:escape\", \"compose:ralt\"]"), + }), + Run: call(x.keyboard), + }, + { + Name: "xorg_screenshot", + Description: "Take a screenshot to a PNG file: the whole screen, one output, or one window by its X id. " + + "Written under the account's home (default ~/Pictures/Screenshots/screenshot-

N?}PbPxZ_~wJpzAOz-j(%w5G5;{i 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⋘8Q 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�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%0DGuQDTHU8C$ zDl8n*?g12UsUBI+Nxnqo{E0YCWND86SiY#7rz|QFP-Uu>T>}{zf8~X~`nfMAJ$IEX zvy;4e286#6HUxl+wOghi`YUc%r~B|a4f+jJ@ho9V8u*w_8TZk{O;NBX&)%(HXHXj) zv%S#D6!L}L%nrN8+|f*py;|u5_@I*wm4NOR8Xs2tXI5Xvl$cw9r)48<=+JjFM-W>w zK}e{lEbaT@bxn>=>9F#>ub;eyLKLn`t;_Cc{X}mDJNA|~)%b`*#4COqQ<3dY4O+NA zF@t3B%}Vw1imHExQXqQO$V73K{o-t&Z>jGlMK%V>w{9ja#^EdQ zR+4fo_37;QjXh?H{`>ra)16`ip;HR#J`mvdr=P7446A~dWp9f~J6B6OV_Sl^|)x`(x!Pd4qlqFqeyXi+#eA#Z!Se}DJjxS