zen: hot-reload the theme via autoconfig sheet watcher
Gecko has no userChrome.css reload, so wrap zen with a mozilla.cfg script that registers chrome/zen-theme.css through nsIStyleSheetService and re-registers it under a cache-busting URI when its mtime moves. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
b823a0c82a
commit
5ad1ac06ca
2 changed files with 68 additions and 6 deletions
60
apps/zen.nix
60
apps/zen.nix
|
|
@ -1,9 +1,65 @@
|
||||||
#./apps/zen.nix
|
#./apps/zen.nix
|
||||||
{ inputs, pkgs, lib, config, ... }:
|
{ inputs, pkgs, lib, config, ... }:
|
||||||
|
let
|
||||||
|
# Autoconfig (mozilla.cfg) runs privileged JS in the parent process at
|
||||||
|
# startup — the only scriptable way into chrome, since Gecko has no reload
|
||||||
|
# for userChrome.css and Zen exposes no command for one.
|
||||||
|
#
|
||||||
|
# So don't use userChrome.css at all for the wallpaper theme. Register
|
||||||
|
# <profile>/chrome/zen-theme.css as a style-sheet-service USER_SHEET here
|
||||||
|
# and re-register it under a cache-busting URI whenever its mtime moves —
|
||||||
|
# that is what makes a `theme-apply` switch land in a running Zen
|
||||||
|
# (settings/theming.nix writes that file on every switch). A separate file,
|
||||||
|
# not userChrome.css: the legacy loader would hold its own copy of the same
|
||||||
|
# sheet and the two would race on cascade order.
|
||||||
|
themeHotReload = ''
|
||||||
|
try {
|
||||||
|
const { classes: kCc, interfaces: kCi } = Components;
|
||||||
|
const sss = kCc["@mozilla.org/content/style-sheet-service;1"]
|
||||||
|
.getService(kCi.nsIStyleSheetService);
|
||||||
|
|
||||||
|
const file = Services.dirsvc.get("ProfD", kCi.nsIFile);
|
||||||
|
file.append("chrome");
|
||||||
|
file.append("zen-theme.css");
|
||||||
|
const base = Services.io.newFileURI(file).spec;
|
||||||
|
let live = null;
|
||||||
|
|
||||||
|
const apply = () => {
|
||||||
|
if (!file.exists()) return;
|
||||||
|
// install(1) stamps the copy with the current time, so mtime alone
|
||||||
|
// distinguishes one wallpaper's sheet from the next.
|
||||||
|
const stamp = String(file.lastModifiedTime);
|
||||||
|
if (stamp === live) return;
|
||||||
|
// A fresh query string dodges the CSS loader's per-URI cache; without
|
||||||
|
// it a re-register would hand back the sheet parsed at startup.
|
||||||
|
sss.loadAndRegisterSheet(Services.io.newURI(base + "?" + stamp),
|
||||||
|
sss.USER_SHEET);
|
||||||
|
if (live !== null) {
|
||||||
|
const old = Services.io.newURI(base + "?" + live);
|
||||||
|
if (sss.sheetRegistered(old, sss.USER_SHEET))
|
||||||
|
sss.unregisterSheet(old, sss.USER_SHEET);
|
||||||
|
}
|
||||||
|
live = stamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
const timer = kCc["@mozilla.org/timer;1"].createInstance(kCi.nsITimer);
|
||||||
|
// The observer service holds the only strong reference that keeps the
|
||||||
|
// timer (and this closure) off the GC's list for the session.
|
||||||
|
Services.obs.addObserver({ timer, observe() {} }, "quit-application");
|
||||||
|
timer.initWithCallback({ notify: apply }, 2000,
|
||||||
|
kCi.nsITimer.TYPE_REPEATING_SLACK);
|
||||||
|
apply();
|
||||||
|
} catch (e) {
|
||||||
|
Components.utils.reportError(e);
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
in
|
||||||
{
|
{
|
||||||
config = lib.mkIf (lib.elem config.networking.hostName [ "FredOS-Gaming" "FredOS-Macbook" ]) {
|
config = lib.mkIf (lib.elem config.networking.hostName [ "FredOS-Gaming" "FredOS-Macbook" ]) {
|
||||||
environment.systemPackages = [
|
environment.systemPackages = [
|
||||||
inputs.zen-browser.packages.${pkgs.stdenv.hostPlatform.system}.default
|
(inputs.zen-browser.packages.${pkgs.stdenv.hostPlatform.system}.default.override {
|
||||||
|
extraPrefs = themeHotReload;
|
||||||
|
})
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,10 @@
|
||||||
# every app that can reload without restarting.
|
# every app that can reload without restarting.
|
||||||
#
|
#
|
||||||
# What follows a switch immediately: quickshell, hyprland, ghostty (D-Bus
|
# What follows a switch immediately: quickshell, hyprland, ghostty (D-Bus
|
||||||
# reload-config), GTK3 apps such as nemo (each wallpaper installs
|
# reload-config), zen (autoconfig sheet watcher, see apps/zen.nix), GTK3 apps
|
||||||
# its own named GTK theme, switched over gsettings) and the folder icon tint.
|
# such as nemo (each wallpaper installs its own named GTK theme, switched over
|
||||||
# On next launch only: GTK4/libadwaita apps, btop, zen.
|
# gsettings) and the folder icon tint.
|
||||||
|
# On next launch only: GTK4/libadwaita apps, btop.
|
||||||
#
|
#
|
||||||
# stylix stays the source of truth for build-time defaults and for every
|
# stylix stays the source of truth for build-time defaults and for every
|
||||||
# target not listed here — walls/wallpaper.png remains its image.
|
# target not listed here — walls/wallpaper.png remains its image.
|
||||||
|
|
@ -518,7 +519,12 @@ let
|
||||||
# the inode keeps the watch, and vencord hot-swaps quickCss with no reload.
|
# the inode keeps the watch, and vencord hot-swaps quickCss with no reload.
|
||||||
mkdir -p "$HOME/.config/vesktop/settings"
|
mkdir -p "$HOME/.config/vesktop/settings"
|
||||||
cat "$theme/vesktop.css" > "$HOME/.config/vesktop/settings/quickCss.css"
|
cat "$theme/vesktop.css" > "$HOME/.config/vesktop/settings/quickCss.css"
|
||||||
install -Dm644 "$theme/zen.css" "$HOME/${zenChrome}/userChrome.css"
|
# zen-theme.css, not userChrome.css: Zen's autoconfig script watches this
|
||||||
|
# file's mtime and re-registers it as a style sheet, so a switch lands in
|
||||||
|
# the running window (see apps/zen.nix). A userChrome.css copy would keep
|
||||||
|
# loading the wallpaper that was live at startup and fight it.
|
||||||
|
install -Dm644 "$theme/zen.css" "$HOME/${zenChrome}/zen-theme.css"
|
||||||
|
rm -f "$HOME/${zenChrome}/userChrome.css"
|
||||||
|
|
||||||
# Icon theme: replace the directory contents (cheap — the tree is
|
# Icon theme: replace the directory contents (cheap — the tree is
|
||||||
# symlinks into the papirus store path) so GTK's icon-theme monitor sees
|
# symlinks into the papirus store path) so GTK's icon-theme monitor sees
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue