Merge pull request 'picom: the backend and damage tracking are each machine's settings (hq issue 345)' (#157) from feat/picom-backend-and-damage-settings into main

This commit was merged in pull request #157.
This commit is contained in:
2026-10-09 10:50:58 +00:00
6 changed files with 90 additions and 13 deletions
+18
View File
@@ -13,6 +13,24 @@ The X compositor as a module (novox/hq ADR 0208, research 026).
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.
## Settings
Two preferences, each a machine's own (the per-node layer of `settings`), because the right values follow
the machine's graphics driver (novox/hq research 037):
| setting | default | what it changes |
|---|---|---|
| `backend` | `glx` | how picom draws: `glx` on the graphics card, `xrender` on the CPU |
| `use-damage` | `true` | `true` repaints only what changed (picom's own default); `false` repaints the whole screen each frame |
The defaults are what every machine ran before, so the file filled with them changes nothing. They exist
for hq issue 345: a window that is mapped but shows nothing (a calendar reminder) or stays stale after a
workspace switch (a chat window) is a known failure of glx with damage tracking on some drivers, and
`xrender` or `use-damage` false is how a machine is set to test that. The file stays trusted, so both are set at the
controller's terminal alone (issue 339): a value is pasted into picom.conf as it is, and a backend of
`xrender"; write-pid-path = "…` would add an option of the caller's (hq issue 346). A changed file is read at
the next `picom_restart` or login: the module has no unit to reload.
## Tools
Served by the node's runtime as the operator account (ADR 0175). The tools find the operator's X
@@ -12,21 +12,29 @@ import (
// 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"`
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"`
Settings map[string]setting `json:"settings"`
Environment *environment `json:"environment"`
Shell []shellCode `json:"shell"`
Resources []map[string]any `json:"resources"`
Build struct {
Artifacts []map[string]any `json:"artifacts"`
} `json:"build"`
}
// setting is one key's default, as the definition gives it (novox/hq ADR 0262).
type setting struct {
Kind string `json:"kind"`
Default any `json:"default"`
Why string `json:"why"`
}
type claim struct {
Name string `json:"name"`
Scope string `json:"scope"`
@@ -59,3 +59,36 @@ func TestTheToolsAgreeWithTheManifest(t *testing.T) {
checkTheToolsAgree(t, m)
checkNoSecretsOrInstallationNames(t)
}
// The backend and damage tracking are each machine's (novox/hq research 037: the backend depends on the
// machine's graphics driver; issue 345: a window left unpainted under glx is the first suspect). Both
// are settings whose defaults are what every machine ran before, so the file filled with them is today's.
func TestTheBackendAndDamageTrackingAreSettingsWithTodaysDefaults(t *testing.T) {
m := readManifest(t)
b, d := m.Settings["backend"], m.Settings["use-damage"]
if b.Kind != "preference" || b.Default != "glx" || b.Why == "" || d.Kind != "preference" || d.Default != true || d.Why == "" {
t.Fatalf("settings: %+v", m.Settings)
}
r := m.resource(t, "configuration")
c := r["content"].(string)
for _, want := range []string{`backend = "${setting:backend}";`, "use-damage = ${setting:use-damage};"} {
if !strings.Contains(c, want) {
t.Errorf("the file asks for %q", want)
}
}
// Trusted (unmarked): a value is pasted into the file as it is, so `xrender"; write-pid-path = "…`
// would add an option of the caller's. Until settings are typed and quoted (hq issue 346), only the
// controller's terminal sets them.
if _, marked := r["trusted"]; marked {
t.Fatal("the file stays trusted: its settings are set at the terminal alone (hq issue 346)")
}
got := parseRules("picom.conf", withDefaults(c), nil)
if got.Global["backend"] != "glx" || got.Global["use-damage"] != "true" || got.Global["vsync"] != "true" {
t.Fatalf("filled with the defaults: %v", got.Global)
}
}
// withDefaults fills the file's settings with their defaults, as a machine without its own values gets it.
func withDefaults(c string) string {
return strings.NewReplacer("${setting:backend}", "glx", "${setting:use-damage}", "true").Replace(c)
}
+1 -1
View File
@@ -16,7 +16,7 @@ func TestTheModulesOwnConfigurationReadsAsRulesInOrder(t *testing.T) {
if err != nil {
t.Fatal(err)
}
r := parseRules("picom.conf", string(raw), nil)
r := parseRules("picom.conf", withDefaults(string(raw)), nil)
if r.Global["backend"] != "glx" || r.Global["vsync"] != "true" || r.Global["shadow"] != "false" {
t.Fatalf("global options: %v", r.Global)
}
+7 -1
View File
@@ -2,7 +2,13 @@
# 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";
# The backend and damage tracking are each machine's settings (backend, use-damage; novox/hq research
# 037, issue 345): the right ones depend on the machine's graphics driver. The defaults are what every
# machine ran before: glx, and picom's own default of repainting only what changed. xrender, or
# use-damage false (repaint the whole screen each frame), is what to try on a machine where a window is
# left unpainted or stale.
backend = "${setting:backend}";
use-damage = ${setting:use-damage};
vsync = true;
fading = true;
+13 -1
View File
@@ -13,6 +13,18 @@
"scope": "node"
}
],
"settings": {
"backend": {
"kind": "preference",
"default": "glx",
"why": "glx draws with the graphics card and has served every machine so far; xrender draws on the CPU and is what to try where glx leaves a window unpainted or stale on the machine's driver (novox/hq research 037, issue 345)"
},
"use-damage": {
"kind": "preference",
"default": true,
"why": "true repaints only what changed, picom's own default; false repaints the whole screen each frame, which costs work and cures a window left stale or unpainted on some drivers (novox/hq issue 345)"
}
},
"tools": [
"picom_restart",
"picom_rules",
@@ -43,7 +55,7 @@
"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"
"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\n# The backend and damage tracking are each machine's settings (backend, use-damage; novox/hq research\n# 037, issue 345): the right ones depend on the machine's graphics driver. The defaults are what every\n# machine ran before: glx, and picom's own default of repainting only what changed. xrender, or\n# use-damage false (repaint the whole screen each frame), is what to try on a machine where a window is\n# left unpainted or stale.\nbackend = \"${setting:backend}\";\nuse-damage = ${setting:use-damage};\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": {