aboutsummaryrefslogtreecommitdiffstats
path: root/zellij-utils/src/input/theme.rs
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-08 22:36:30 +0200
committeruser <user@clank>2026-08-08 22:36:30 +0200
commitcfae103a7afae1541a46cbfe21b011ffe4d09f2d (patch)
tree35db8eac79e73d6cf2a9cb9ccdbf885b815072cc /zellij-utils/src/input/theme.rs
parentchore: stop tracking transient bgrun job artifacts (diff)
downloadsl0ppij-cfae103a7afae1541a46cbfe21b011ffe4d09f2d.tar.gz
sl0ppij-cfae103a7afae1541a46cbfe21b011ffe4d09f2d.tar.xz
sl0ppij-cfae103a7afae1541a46cbfe21b011ffe4d09f2d.zip
sl0p: grayscale the contents of unfocused panes
`ui { pane_frames { inactive_grayscale 0-100 } }`, default 0 (off). Real colour transformation, not the SGR 'faint' attribute zellij already uses for frames: faint is terminal-dependent, several terminals only apply it to the 16 ANSI colours, and it does not remove colour. Each cell's colour is resolved to RGB and blended toward its own Rec.709 luminance, so an unfocused pane keeps its brightness but drains of colour. Colour resolution covers the cases that actually occur: RgbCode directly, ColorIndex via eightbit_to_rgb, and NamedColor by mapping to its 0-15 index. Cells with NO explicit colour are deliberately left alone - they render in the terminal default, which is already unsaturated, and rewriting them would mean emitting an explicit colour for nearly every cell for no visible gain. Two non-obvious pieces were needed to make it actually work: - The output buffer only emits CHANGED cells, so an idle pane would keep its old colours indefinitely after losing focus. Pane::refresh_for_focus_change forces a full repaint, called from ActivePanes::insert (the single place focus changes). It is a no-op when the feature is off, so it costs nothing by default. - Terminal panes render through the SHARED multi-client path. Focus is per client, so once unfocused panes are desaturated two clients may need different output for the same pane. Both tiled and floating panes now fall back to per-client rendering when grayscale is enabled - the reason this is opt-in. Known limitation: sixel/kitty image chunks are not colour-transformed and stay in colour. Hot-reloads like the other sl0p options. Tests cover the transform: full strength yields a true neutral grey, partial sits between original and grey, indexed and named colours resolve rather than being skipped, luminance is perceptual (green brighter than blue) not a flat average, already-grey is unchanged, and non-colour codes are untouched. Baselines held: zellij-server 1436/30, zellij-utils 436/5.
Diffstat (limited to 'zellij-utils/src/input/theme.rs')
-rw-r--r--zellij-utils/src/input/theme.rs5
1 files changed, 5 insertions, 0 deletions
diff --git a/zellij-utils/src/input/theme.rs b/zellij-utils/src/input/theme.rs
index f1e0adf1..e1371f85 100644
--- a/zellij-utils/src/input/theme.rs
+++ b/zellij-utils/src/input/theme.rs
@@ -37,6 +37,9 @@ pub struct FrameConfig {
/// wide, so 1 row of gap needs ~2 columns to look like the same distance.
/// 0 is treated as 1 (no correction).
pub gap_aspect: usize,
+ /// How strongly to desaturate the CONTENT of unfocused panes, 0-100.
+ /// 0 disables it entirely (the default).
+ pub inactive_grayscale: u8,
}
/// Hand-written rather than derived: `gap_aspect` must default to 2 to match
@@ -52,6 +55,7 @@ impl Default for FrameConfig {
gap: 0,
padding: Default::default(),
gap_aspect: 2,
+ inactive_grayscale: 0,
}
}
}
@@ -78,6 +82,7 @@ impl FrameConfig {
merged.gap = other.gap;
merged.padding = other.padding;
merged.gap_aspect = other.gap_aspect;
+ merged.inactive_grayscale = other.inactive_grayscale;
merged
}
}