From 0d61fb3c5d71b8995fd706fc08e95481675cf95b Mon Sep 17 00:00:00 2001 From: "s0wlz (Matthias Puchstein)" Date: Fri, 29 May 2026 03:30:14 +0200 Subject: [PATCH] hypr: integrate hyprsunset blue light filter and game bypass --- .chezmoiignore.tmpl | 3 ++ .gitignore | 2 + .../hypr/hyprland.d.lua/keybinds.lua.tmpl | 38 +++++++++++++++++++ dot_config/hypr/hyprland.d.lua/rules.lua.tmpl | 30 +++++++++++++++ dot_config/hypr/hyprsunset.conf.tmpl | 21 ++++++++++ 5 files changed, 94 insertions(+) create mode 100644 .gitignore create mode 100644 dot_config/hypr/hyprsunset.conf.tmpl diff --git a/.chezmoiignore.tmpl b/.chezmoiignore.tmpl index 0975d98..103290a 100644 --- a/.chezmoiignore.tmpl +++ b/.chezmoiignore.tmpl @@ -39,6 +39,9 @@ pkglist/ AGENTS.md GEMINI.md +CLAUDE.md +.antigravitycli/ +.claude/ .config/hypr/AGENTS.md .config/waybar/AGENTS.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0457760 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.antigravitycli/ +.claude/ diff --git a/dot_config/hypr/hyprland.d.lua/keybinds.lua.tmpl b/dot_config/hypr/hyprland.d.lua/keybinds.lua.tmpl index 2163b07..d4f0e4f 100644 --- a/dot_config/hypr/hyprland.d.lua/keybinds.lua.tmpl +++ b/dot_config/hypr/hyprland.d.lua/keybinds.lua.tmpl @@ -400,6 +400,44 @@ hl.bind("SHIFT + XF86MonBrightnessDown", brightness_step("5%-"), { locked = true hl.bind("CTRL + XF86MonBrightnessUp", brightness_step("70%"), { locked = true, description = "Brightness 70%" }) hl.bind("CTRL + XF86MonBrightnessDown", brightness_step("20%"), { locked = true, description = "Brightness 20%" }) +-- Blue light filter manual override +-- TODO: Temporary workaround until `hyprctl hyprsunset reset` is supported in local packages. +-- Once supported, replace `get_scheduled_temperature` and `systemctl`/`hyprctl` workaround with `hyprctl hyprsunset reset`. +local function get_scheduled_temperature() + local time = os.date("*t") + local mins = time.hour * 60 + time.min + -- Profiles matching ~/.config/hypr/hyprsunset.conf: + -- Day: 07:00 (420 mins) -> identity + -- Evening: 19:30 (1170 mins) -> 4500 + -- Night: 22:30 (1350 mins) -> 3200 + if mins >= 1350 or mins < 420 then + return 3200 + elseif mins >= 1170 and mins < 1350 then + return 4500 + else + return "identity" + end +end + +_G._bluelight_enabled = true +local function toggle_bluelight() + _G._bluelight_enabled = not _G._bluelight_enabled + if _G._bluelight_enabled then + local target = get_scheduled_temperature() + if target == "identity" then + hl.dispatch(hl.dsp.exec_cmd("hyprctl hyprsunset identity")) + hl.notification.create({ text = "Blue Light Filter: Auto (OFF/Day)", timeout = 1500, icon = "info" }) + else + hl.dispatch(hl.dsp.exec_cmd("hyprctl hyprsunset temperature " .. tostring(target))) + hl.notification.create({ text = "Blue Light Filter: Auto (" .. tostring(target) .. "K)", timeout = 1500, icon = "ok" }) + end + else + hl.dispatch(hl.dsp.exec_cmd("hyprctl hyprsunset identity")) + hl.notification.create({ text = "Blue Light Filter: OFF", timeout = 1500, icon = "info" }) + end +end +hl.bind(mainMod .. " + SHIFT + B", toggle_bluelight, { description = "Toggle blue light filter" }) + {{- if (index .chezmoi.config.data.tags "laptop") }} -- ─── Surface Type Cover ────────────────────────────────────────────────────── diff --git a/dot_config/hypr/hyprland.d.lua/rules.lua.tmpl b/dot_config/hypr/hyprland.d.lua/rules.lua.tmpl index 19e117d..1c2d0fa 100644 --- a/dot_config/hypr/hyprland.d.lua/rules.lua.tmpl +++ b/dot_config/hypr/hyprland.d.lua/rules.lua.tmpl @@ -70,6 +70,36 @@ hl.window_rule({ match = { class = "Spotify" }, workspace = "6" }) hl.window_rule({ match = { class = "^(steam)$" }, workspace = "5" }) {{- end }} +-- Game Content Bypass (Option A - per-monitor CTM bypass) +-- Automatically mark Steam games as "game" content type +hl.window_rule({ match = { class = "^steam_app_%d+$" }, content = "game" }) + +-- Dynamic bypass for custom environment variable NO_BLUELIGHT=1 +local function get_process_env(pid, name) + if not pid or pid <= 0 then return nil end + local f = io.open("/proc/" .. tostring(pid) .. "/environ", "r") + if not f then return nil end + local content = f:read("*a") + f:close() + if not content then return nil end + for var in content:gmatch("([^%z]+)") do + local k, v = var:match("^([^=]+)=(.*)$") + if k == name then + return v + end + end + return nil +end + +hl.on("window.open", function(w) + if w.pid and w.pid > 0 then + local no_bl = get_process_env(w.pid, "NO_BLUELIGHT") + if no_bl == "1" then + hl.window_rule({ match = { class = "^" .. w.class .. "$" }, content = "game" }) + end + end +end) + -- System hl.window_rule({ match = { class = "com.saivert.pwvucontrol" }, float = true }) diff --git a/dot_config/hypr/hyprsunset.conf.tmpl b/dot_config/hypr/hyprsunset.conf.tmpl new file mode 100644 index 0000000..d262c7a --- /dev/null +++ b/dot_config/hypr/hyprsunset.conf.tmpl @@ -0,0 +1,21 @@ +max-gamma = 150 + +# Day profile: neutral display +profile { + time = 07:00 + identity = true +} + +# Evening profile: warm display +profile { + time = 19:30 + temperature = 4500 + gamma = 0.95 +} + +# Night profile: warmer display +profile { + time = 22:30 + temperature = 3200 + gamma = 0.85 +}