12 Commits

Author SHA1 Message Date
2 * r + 2 * t a00e71d6b7 docs: add iconTheme options to example conf 2026-05-02 22:51:35 +10:00
2 * r + 2 * t 1ec969d9ec fix: use auto bars for cava 2026-05-02 22:48:41 +10:00
2 * r + 2 * t 5273ed514f feat: add theme postHook 2026-05-02 22:24:26 +10:00
github-actions f3b13affc3 [CI] chore: update flake 2026-05-02 03:39:49 +00:00
Haikal 5c9ce66c03 feat: expose more environment variables in post-hook (#107)
* feat: expose more environment variables in post-hook

* fix: formatted
2026-04-29 23:56:07 +10:00
github-actions c18f749f24 [CI] chore: update flake 2026-04-29 03:43:15 +00:00
2 * r + 2 * t 96fcdf5bce fix: use hypr socket instead of hyprctl 2026-04-28 21:20:40 +10:00
github-actions eddee4deca [CI] chore: update flake 2026-04-25 03:06:00 +00:00
Foxlike Creature 68bc03bc17 feat: allow overriding icon theme via cli.json (#106)
* theme: allow overriding Qt icon theme via cli.json

Papirus colors XDG special folders (Downloads, Pictures, Music, etc.)
differently from regular ones - they end up a different color while
everything else stays neutral. With themes like breeze-dark, all folder
icons share the same style, so everything looks consistent.

Add optional `iconTheme` field to the `theme` section of cli.json.
When set, it replaces the Papirus icon theme in the generated qtengine
config with the specified theme.

Example usage in cli.json:
  "theme": { "iconTheme": "breeze-dark" }

* theme: allow overriding Qt and GTK icon theme via cli.json

Some folders in Dolphin end up with Papirus-style icons while others
use the default theme icons, resulting in two different icon styles
mixed together in the same view. Dolphin's default folder icons take
their color directly from the active color scheme, so they always match
the theme exactly - Papirus has a fixed, limited palette and does not
always match.

Add optional iconThemeDark and iconThemeLight fields to the theme
section of cli.json. When set, they override the Papirus icon theme in
both the generated qtengine config and the GTK dconf setting. A generic
iconTheme field is also supported as a fallback for both modes.

Example usage in cli.json:
  "theme": { "iconThemeDark": "breeze-dark", "iconThemeLight": "breeze" }

---------

Co-authored-by: Foxlike Creature <safonovkirill113@gmail.com>
2026-04-24 14:55:47 +10:00
github-actions 023a30b83c [CI] chore: update flake 2026-04-21 03:27:51 +00:00
github-actions a192efae9c [CI] chore: update flake 2026-04-20 03:35:55 +00:00
2 * r + 2 * t 463f36544a docs: add missing theme.enable* opts to example conf 2026-04-19 16:01:09 +10:00
6 changed files with 62 additions and 21 deletions
+13 -2
View File
@@ -191,17 +191,28 @@ All configuration options are in `~/.config/caelestia/cli.json`.
"extraArgs": [] "extraArgs": []
}, },
"wallpaper": { "wallpaper": {
"postHook": "echo $WALLPAPER_PATH" "postHook": "echo $WALLPAPER_PATH $SCHEME_NAME $SCHEME_FLAVOUR $SCHEME_MODE $SCHEME_VARIANT $SCHEME_COLOURS"
}, },
"theme": { "theme": {
"enableTerm": true, "enableTerm": true,
"enableHypr": true, "enableHypr": true,
"enableDiscord": true, "enableDiscord": true,
"enableSpicetify": true, "enableSpicetify": true,
"enablePandora": true,
"enableFuzzel": true, "enableFuzzel": true,
"enableBtop": true, "enableBtop": true,
"enableNvtop": true,
"enableHtop": true,
"enableGtk": true, "enableGtk": true,
"enableQt": true "enableQt": true,
"enableWarp": true,
"enableChromium": true,
"enableZed": true,
"enableCava": true,
"iconTheme": "Papirus-Dark",
"iconThemeLight": "Papirus-Light",
"iconThemeDark": "Papirus-Dark",
"postHook": "echo $SCHEME_NAME $SCHEME_FLAVOUR $SCHEME_MODE $SCHEME_VARIANT $SCHEME_COLOURS"
}, },
"toggles": { "toggles": {
"communication": { "communication": {
Generated
+10 -10
View File
@@ -9,11 +9,11 @@
"quickshell": "quickshell" "quickshell": "quickshell"
}, },
"locked": { "locked": {
"lastModified": 1775801889, "lastModified": 1777688289,
"narHash": "sha256-q1LGwhQbNOurIAClh5YwKVU2kJ5lTCxRYZf48bAb9IM=", "narHash": "sha256-2EaEVkT1oUpjLLp7uEY/hDYDOa2k5R1YgcJpHei+lUM=",
"owner": "caelestia-dots", "owner": "caelestia-dots",
"repo": "shell", "repo": "shell",
"rev": "0e07176ff149d02391531c802b51c28e73185f30", "rev": "4e9e1f4b723f7e3a87cb280d67a25ee92c87fbff",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -24,11 +24,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1775710090, "lastModified": 1777268161,
"narHash": "sha256-ar3rofg+awPB8QXDaFJhJ2jJhu+KqN/PRCXeyuXR76E=", "narHash": "sha256-bxrdOn8SCOv8tN4JbTF/TXq7kjo9ag4M+C8yzzIRYbE=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "4c1018dae018162ec878d42fec712642d214fdfa", "rev": "1c3fe55ad329cbcb28471bb30f05c9827f724c76",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -46,11 +46,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1772925576, "lastModified": 1777341401,
"narHash": "sha256-mMoiXABDtkSJxCYDrkhJ/TrrJf5M46oUfIlJvv2gkZ0=", "narHash": "sha256-QEAVYeXxvTamsYJVBq8+qSJV9ml2MxqRaZvkobfuPWA=",
"ref": "refs/heads/master", "ref": "refs/heads/master",
"rev": "15a84097653593dd15fad59a56befc2b7bdc270d", "rev": "0baa81aa03559ca315668e5a306364cddf1a6f49",
"revCount": 750, "revCount": 812,
"type": "git", "type": "git",
"url": "https://git.outfoxxed.me/outfoxxed/quickshell" "url": "https://git.outfoxxed.me/outfoxxed/quickshell"
}, },
-2
View File
@@ -2,8 +2,6 @@
# Optimized for smooth and responsive visualization # Optimized for smooth and responsive visualization
[general] [general]
# Number of bars (20-200) - fewer bars = better performance
bars = 64
# Framerate (1-144) - higher = smoother but more CPU intensive # Framerate (1-144) - higher = smoother but more CPU intensive
framerate = 60 framerate = 60
+2 -1
View File
@@ -7,6 +7,7 @@ from argparse import Namespace
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
from caelestia.utils import hypr
from caelestia.utils.notify import close_notification, notify from caelestia.utils.notify import close_notification, notify
from caelestia.utils.paths import recording_notif_path, recording_path, recordings_dir, user_config_path from caelestia.utils.paths import recording_notif_path, recording_path, recordings_dir, user_config_path
@@ -36,7 +37,7 @@ class Command:
def start(self) -> None: def start(self) -> None:
args = ["-w"] args = ["-w"]
monitors = json.loads(subprocess.check_output(["hyprctl", "monitors", "-j"])) monitors = hypr.message("monitors")
if self.args.region: if self.args.region:
if self.args.region == "slurp": if self.args.region == "slurp":
region = subprocess.check_output(["slurp", "-f", "%wx%h+%x+%y"], text=True) region = subprocess.check_output(["slurp", "-f", "%wx%h+%x+%y"], text=True)
+27 -5
View File
@@ -1,5 +1,6 @@
import fcntl import fcntl
import json import json
import os
import re import re
import shutil import shutil
import subprocess import subprocess
@@ -17,6 +18,7 @@ from caelestia.utils.paths import (
user_config_path, user_config_path,
user_templates_dir, user_templates_dir,
) )
from caelestia.utils.scheme import get_scheme
def gen_conf(colours: dict[str, str]) -> str: def gen_conf(colours: dict[str, str]) -> str:
@@ -302,7 +304,7 @@ def _determine_hue_color(r: int, g: int, b: int, brightness: int, use_pale: bool
@log_exception @log_exception
def apply_gtk(colours: dict[str, str], mode: str) -> None: def apply_gtk(colours: dict[str, str], mode: str, icon_theme: str | None = None) -> None:
gtk_template = gen_replace(colours, templates_dir / "gtk.css", hash=True) gtk_template = gen_replace(colours, templates_dir / "gtk.css", hash=True)
thunar_template = gen_replace(colours, templates_dir / "thunar.css", hash=True) thunar_template = gen_replace(colours, templates_dir / "thunar.css", hash=True)
@@ -313,18 +315,21 @@ def apply_gtk(colours: dict[str, str], mode: str) -> None:
subprocess.run(["dconf", "write", "/org/gnome/desktop/interface/gtk-theme", "'adw-gtk3-dark'"]) subprocess.run(["dconf", "write", "/org/gnome/desktop/interface/gtk-theme", "'adw-gtk3-dark'"])
subprocess.run(["dconf", "write", "/org/gnome/desktop/interface/color-scheme", f"'prefer-{mode}'"]) subprocess.run(["dconf", "write", "/org/gnome/desktop/interface/color-scheme", f"'prefer-{mode}'"])
subprocess.run(["dconf", "write", "/org/gnome/desktop/interface/icon-theme", f"'Papirus-{mode.capitalize()}'"]) gtk_icon_theme = icon_theme if icon_theme is not None else f"Papirus-{mode.capitalize()}"
subprocess.run(["dconf", "write", "/org/gnome/desktop/interface/icon-theme", f"'{gtk_icon_theme}'"])
sync_papirus_colors(colours["primary"]) sync_papirus_colors(colours["primary"])
@log_exception @log_exception
def apply_qt(colours: dict[str, str], mode: str) -> None: def apply_qt(colours: dict[str, str], mode: str, icon_theme: str | None = None) -> None:
colours = gen_replace(colours, templates_dir / f"qt{mode}.colors", hash=True) colours = gen_replace(colours, templates_dir / f"qt{mode}.colors", hash=True)
write_file(config_dir / "qtengine/caelestia.colors", colours) write_file(config_dir / "qtengine/caelestia.colors", colours)
config = (templates_dir / "qtengine.json").read_text() config = (templates_dir / "qtengine.json").read_text()
config = config.replace("{{ $mode }}", mode.capitalize()) config = config.replace("{{ $mode }}", mode.capitalize())
if icon_theme is not None:
config = config.replace(f'"iconTheme": "Papirus-{mode.capitalize()}"', f'"iconTheme": "{icon_theme}"')
write_file(config_dir / "qtengine/config.json", config) write_file(config_dir / "qtengine/config.json", config)
@@ -438,10 +443,11 @@ def apply_colours(colours: dict[str, str], mode: str) -> None:
apply_nvtop(colours) apply_nvtop(colours)
if check("enableHtop"): if check("enableHtop"):
apply_htop(colours) apply_htop(colours)
icon_theme = cfg.get(f"iconTheme{mode.capitalize()}") or cfg.get("iconTheme")
if check("enableGtk"): if check("enableGtk"):
apply_gtk(colours, mode) apply_gtk(colours, mode, icon_theme)
if check("enableQt"): if check("enableQt"):
apply_qt(colours, mode) apply_qt(colours, mode, icon_theme)
if check("enableWarp"): if check("enableWarp"):
apply_warp(colours, mode) apply_warp(colours, mode)
if check("enableChromium"): if check("enableChromium"):
@@ -452,6 +458,22 @@ def apply_colours(colours: dict[str, str], mode: str) -> None:
apply_cava(colours) apply_cava(colours)
apply_user_templates(colours, mode) apply_user_templates(colours, mode)
if post_hook := cfg.get("postHook"):
scheme = get_scheme()
subprocess.run(
post_hook,
shell=True,
env={
**os.environ,
"SCHEME_NAME": scheme.name,
"SCHEME_FLAVOUR": scheme.flavour,
"SCHEME_MODE": scheme.mode,
"SCHEME_VARIANT": scheme.variant,
"SCHEME_COLOURS": json.dumps(scheme.colours),
},
stderr=subprocess.DEVNULL,
)
finally: finally:
try: try:
lock_file.unlink() lock_file.unlink()
+10 -1
View File
@@ -192,7 +192,16 @@ def set_wallpaper(wall: Path, no_smart: bool) -> None:
subprocess.run( subprocess.run(
post_hook, post_hook,
shell=True, shell=True,
env={**os.environ, "WALLPAPER_PATH": str(wall)}, env={
**os.environ,
"WALLPAPER_PATH": str(wall),
"SCHEME_NAME": scheme.name,
"SCHEME_FLAVOUR": scheme.flavour,
"SCHEME_MODE": scheme.mode,
"SCHEME_VARIANT": scheme.variant,
"SCHEME_COLOURS": json.dumps(scheme.colours),
"THUMBNAIL_PATH": str(thumb),
},
stderr=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
) )
except (FileNotFoundError, json.JSONDecodeError): except (FileNotFoundError, json.JSONDecodeError):