Shortcuts you invent, rules you write, gestures you own - all still just data
Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
@@ -652,6 +652,81 @@ Singleton {
|
||||
root.applyOptions({ directScanoutPolicy: policy });
|
||||
}
|
||||
|
||||
// ── Color filters ───────────────────────────────────────────────────────
|
||||
// The stored preference is an enum; what the compositor wants is a shader
|
||||
// path. That mapping cannot be a `hypr:` block on the schema entry -- the
|
||||
// read-back would compare "grayscale" against a filename and fail every
|
||||
// shape and sweep contract -- so it lives here, and hypr/looks.lua does the
|
||||
// same lookup for the value the config carries at launch.
|
||||
//
|
||||
// The shaders are installed by the hypr directory symlink, so the path is
|
||||
// the deployed one rather than the repository's.
|
||||
readonly property string shaderDir:
|
||||
(Quickshell.env("XDG_CONFIG_HOME") || `${Quickshell.env("HOME")}/.config`) + "/hypr/shaders"
|
||||
|
||||
readonly property var colorFilterShaders: ({
|
||||
"grayscale": "grayscale.frag",
|
||||
"protanopia": "protanopia.frag",
|
||||
"deuteranopia": "deuteranopia.frag",
|
||||
"tritanopia": "tritanopia.frag"
|
||||
})
|
||||
|
||||
// "" for none, and for any value this build does not ship a shader for --
|
||||
// an unknown filter turns the filter off rather than leaving the previous
|
||||
// one on under a new name.
|
||||
function colorFilterPath(name: string): string {
|
||||
const file = root.colorFilterShaders[String(name)];
|
||||
return file === undefined ? "" : `${root.shaderDir}/${file}`;
|
||||
}
|
||||
|
||||
property string colorFilterPending: ""
|
||||
|
||||
Process {
|
||||
id: colorFilterWrite
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
// `hyprctl eval` exits 0 on a Lua error and reports it on
|
||||
// stdout, so the exit status proves nothing. Read it back.
|
||||
if (this.text.indexOf("error:") >= 0) {
|
||||
root.lastError = "The color filter could not be applied.";
|
||||
return;
|
||||
}
|
||||
colorFilterVerify.exec(["hyprctl", "-j", "getoption", "decoration:screen_shader"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: colorFilterVerify
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
try {
|
||||
const observed = String(JSON.parse(this.text).str ?? "");
|
||||
if (observed !== root.colorFilterPending) {
|
||||
root.lastError = "The compositor did not take the color filter.";
|
||||
return;
|
||||
}
|
||||
root.lastError = "";
|
||||
} catch (error) {
|
||||
root.lastError = "The compositor did not say whether the color filter applied.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Applies the filter to the running compositor. The preference is written
|
||||
// by the row that calls this; nothing here stores anything.
|
||||
function applyColorFilter(name: string): void {
|
||||
if (colorFilterWrite.running)
|
||||
return;
|
||||
const path = root.colorFilterPath(name);
|
||||
root.colorFilterPending = path;
|
||||
colorFilterWrite.exec(["hyprctl", "eval",
|
||||
`hl.config({ decoration = { screen_shader = "${path.replace(/["\\]/g, "")}" } })`]);
|
||||
}
|
||||
|
||||
// Replays every compositor-owned preference in one batch at shell start, so
|
||||
// a value the user changed in Settings survives a reboot even though the
|
||||
// Lua config only reads the file once, at launch.
|
||||
|
||||
Reference in New Issue
Block a user