diff --git a/apps/zen.nix b/apps/zen.nix index abe660a..1cdb812 100644 --- a/apps/zen.nix +++ b/apps/zen.nix @@ -1,9 +1,65 @@ #./apps/zen.nix { 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 + # /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" ]) { environment.systemPackages = [ - inputs.zen-browser.packages.${pkgs.stdenv.hostPlatform.system}.default + (inputs.zen-browser.packages.${pkgs.stdenv.hostPlatform.system}.default.override { + extraPrefs = themeHotReload; + }) ]; }; -} \ No newline at end of file +} diff --git a/settings/theming.nix b/settings/theming.nix index a1566de..ba53d28 100644 --- a/settings/theming.nix +++ b/settings/theming.nix @@ -7,9 +7,10 @@ # every app that can reload without restarting. # # What follows a switch immediately: quickshell, hyprland, ghostty (D-Bus -# reload-config), GTK3 apps such as nemo (each wallpaper installs -# its own named GTK theme, switched over gsettings) and the folder icon tint. -# On next launch only: GTK4/libadwaita apps, btop, zen. +# reload-config), zen (autoconfig sheet watcher, see apps/zen.nix), GTK3 apps +# such as nemo (each wallpaper installs its own named GTK theme, switched over +# 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 # 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. mkdir -p "$HOME/.config/vesktop/settings" 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 # symlinks into the papirus store path) so GTK's icon-theme monitor sees