From 5f1d008ccec6266ef313666ebf31ba1d4b428884 Mon Sep 17 00:00:00 2001 From: Yuka <128908897+yukazakiri@users.noreply.github.com> Date: Wed, 15 Apr 2026 14:20:15 +0800 Subject: [PATCH] theme: add live theming for chromium-based browsers (#103) * theme: add live theming for chromium-based browsers Writes the surface colour as an RGB triplet to chromium.theme and applies it as a managed browser policy for chromium, brave, and google-chrome-stable using the --refresh-platform-policy flag (introduced in Chrome 142+). Also fixes write_file to set 0644 permissions so browser processes can read the policy files. * feat: use sudo tee not chmod * chore: update readme --------- Co-authored-by: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> --- README.md | 70 ++++++++++++++++++++---------------- src/caelestia/utils/theme.py | 37 +++++++++++++++++-- 2 files changed, 75 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index ad3af24..64cfd0d 100644 --- a/README.md +++ b/README.md @@ -18,35 +18,6 @@ The main control script for the Caelestia dotfiles. -
Optional dependencies - -- [`papirus-folders`](https://github.com/PapirusDevelopmentTeam/papirus-folders) - automatic folder icon color syncing with theme - -> [!NOTE] -> For automatic Papirus folder icon color syncing, `papirus-folders` needs to be able to run with `sudo` without a password prompt. -> -> **Recommended** - Create a sudoers file: -> -> ```fish -> # Fish shell -> echo "$USER ALL=(ALL) NOPASSWD: "(which papirus-folders) | sudo tee /etc/sudoers.d/papirus-folders -> sudo chmod 440 /etc/sudoers.d/papirus-folders -> ``` -> -> ```sh -> # Bash/other shells -> echo "$USER ALL=(ALL) NOPASSWD: $(which papirus-folders)" | sudo tee /etc/sudoers.d/papirus-folders -> sudo chmod 440 /etc/sudoers.d/papirus-folders -> ``` -> -> **Alternatively** - Edit the main sudoers file by running `sudo visudo` and adding at the end: -> -> ``` -> your_username ALL=(ALL) NOPASSWD: /usr/bin/papirus-folders -> ``` - -
- ## Installation ### Arch linux @@ -122,6 +93,45 @@ sudo python -m installer dist/*.whl sudo cp completions/caelestia.fish /usr/share/fish/vendor_completions.d/caelestia.fish ``` +### Additional steps + +#### Auto folder colour theming + +For automatic Papirus folder icon colour syncing, you must have [`papirus-folders`](https://github.com/PapirusDevelopmentTeam/papirus-folders) +installed, and `papirus-folders` must to be able to run with `sudo` without a password prompt. + +You can allow this by creating a sudoers file: + +```sh +echo "$USER ALL=(ALL) NOPASSWD: $(which papirus-folders)" | sudo tee /etc/sudoers.d/papirus-folders +sudo chmod 440 /etc/sudoers.d/papirus-folders +``` + +#### Chromium-based browser theming + +For live Chromium-based browser theming, the CLI must be allowed to create certain directories in `/etc` +and write to them via `sudo` without a password prompt. + +You can allow this by creating a sudoers file: + +```fish +# Fish shell +for dir in /etc/chromium/policies/managed /etc/brave/policies/managed /etc/opt/chrome/policies/managed + echo "$USER ALL=(ALL) NOPASSWD: $(which mkdir) -p $dir" | sudo tee -a /etc/sudoers.d/caelestia-chromium + echo "$USER ALL=(ALL) NOPASSWD: $(which tee) $dir/caelestia.json" | sudo tee -a /etc/sudoers.d/caelestia-chromium +end +sudo chmod 440 /etc/sudoers.d/caelestia-chromium +``` + +```sh +# Bash/other shells +for dir in /etc/chromium/policies/managed /etc/brave/policies/managed /etc/opt/chrome/policies/managed; do + echo "$USER ALL=(ALL) NOPASSWD: $(which mkdir) -p $dir" | sudo tee -a /etc/sudoers.d/caelestia-chromium + echo "$USER ALL=(ALL) NOPASSWD: $(which tee) $dir/caelestia.json" | sudo tee -a /etc/sudoers.d/caelestia-chromium +done +sudo chmod 440 /etc/sudoers.d/caelestia-chromium +``` + ## Usage All subcommands/options can be explored via the help flag. @@ -151,7 +161,7 @@ subcommands: resizer window resizer daemon ``` -### User Templates +### User templates Custom user templates can be defined in `~/.config/caelestia/templates/`. diff --git a/src/caelestia/utils/theme.py b/src/caelestia/utils/theme.py index 32e5a02..0addb83 100644 --- a/src/caelestia/utils/theme.py +++ b/src/caelestia/utils/theme.py @@ -4,8 +4,6 @@ import re import shutil import subprocess import tempfile -import shutil -import fcntl from pathlib import Path from caelestia.utils.colour import get_dynamic_colours @@ -340,6 +338,39 @@ def apply_warp(colours: dict[str, str], mode: str) -> None: @log_exception +def apply_chromium(colours: dict[str, str]) -> None: + surface_hex = colours["surface"] + theme_color = f"#{surface_hex}" + browsers = [ + ("chromium", Path("/etc/chromium/policies/managed")), + ("brave", Path("/etc/brave/policies/managed")), + ("google-chrome-stable", Path("/etc/opt/chrome/policies/managed")), + ] + + for cmd, policy_dir in browsers: + if shutil.which(cmd) is None: + continue + if not policy_dir.is_dir(): + subprocess.run(["sudo", "-n", "mkdir", "-p", str(policy_dir)], stderr=subprocess.DEVNULL) + if not policy_dir.is_dir(): + print(f"Unable to create {policy_dir} directory") + continue + + # Use tee instead of write_file cause we need sudo + subprocess.run( + ["sudo", "-n", "tee", str(policy_dir / "caelestia.json")], + input=json.dumps({"BrowserThemeColor": theme_color, "BrowserColorScheme": "device"}), + text=True, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + subprocess.run( + [cmd, "--refresh-platform-policy", "--no-startup-window"], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + + def apply_zed(colours: dict[str, str], mode: str) -> None: theme_path = config_dir / "zed/themes/caelestia.json" # Zed's file watcher does not detect changes through symlinks, @@ -413,6 +444,8 @@ def apply_colours(colours: dict[str, str], mode: str) -> None: apply_qt(colours, mode) if check("enableWarp"): apply_warp(colours, mode) + if check("enableChromium"): + apply_chromium(colours) if check("enableZed"): apply_zed(colours, mode) if check("enableCava"):