Files
nevaforget dddf236ace feat(theme): a splash theme of our own, images in viewnior, a stop timeout for stasis
The Catppuccin splash showed the NixOS logo and the loading animation and
nothing else. The NixOS plymouth module links boot.plymouth.logo into every
theme directory named catppuccin-<flavour>, and the two-step module has no
alignment key for that header image, so its distance from the animation is not
the theme's to set. A theme under a name of its own is outside that loop.
moonarch-plymouth joins as a flake input; pkgs/moonarch-plymouth.nix rewrites
the descriptor's FHS ImageDir to the store path.

Images opened in Chromium although viewnior has been installed since 3e40a70:
no mimeapps.list named image/* at all, so xdg-open took the first candidate
from mimeinfo.cache. xdg.mime points gif, jpeg, png and webp at
viewnior.desktop. webp needs addedAssociations besides, which viewnior.desktop
does not declare, and webp-pixbuf-loader, without which gdk-pixbuf cannot
decode it.

stasis does not answer SIGTERM as part of the session teardown, and the default
90 seconds left the whole user manager waiting on it: niri received its own
SIGTERM only once stasis had been killed, 88 seconds in the journal.
TimeoutStopSec = 5. What it holds is an idle timer, so nothing is lost when it
goes down hard.

glab on the ThinkPad.
2026-09-28 14:52:05 +02:00

198 lines
9.0 KiB
Nix

# ABOUTME: GTK, Qt, Kvantum, Plymouth, cursors and fonts — the look, in one place.
# ABOUTME: Same theme derivations the greeter uses, so the two cannot drift apart.
{ pkgs, moonarchSrc, moonarchPkgs, moonarchThemes, ... }:
let
xdg = "${moonarchSrc}/defaults/xdg";
# The GTK theme name, in the one place both consumers below read it from.
gtkTheme = "catppuccin-mocha-lavender-standard";
# Both distributions ship the same Catppuccin GTK theme, 1.0.3, and still
# disagree on its name — permanently, not as a migration. Arch installs the
# upstream release zips through catppuccin-gtk-theme-mocha, whose directories
# carry the full build name with the `+default` tweak marker; nixpkgs builds
# the same source with no tweaks and so names it without that suffix. Neither
# side can adopt the other's name without going out of its way.
#
# The rewrite therefore has to stay. It matters because GTK3 reads
# settings.ini directly — the dconf entry further down only reaches
# applications that ask GSettings, which on Wayland the GTK3 ones do not — so
# a name that does not resolve puts every GTK3 application on Adwaita, with
# no error anywhere.
gtkSettings = version: pkgs.runCommand "gtk${version}-settings.ini" { } ''
substitute ${xdg}/gtk-${version}/settings.ini "$out" \
--replace-fail catppuccin-mocha-lavender-standard+default ${gtkTheme}
'';
# The theme deployed Kvantum/kvantum.kvconfig selects. It goes into
# systemPackages: nixpkgs patches Kvantum to search XDG_DATA_DIRS for themes
# (tsujan/Kvantum 01989083, in the package's patches list), and
# /run/current-system/sw/share is on that path, so a theme package is found
# system-wide with nothing seeded into the home directory.
#
# Verified under strace: a Qt6 client opens the theme's .kvconfig straight
# out of the package's store path. The patch only takes in the Qt6 build
# (NixOS/nixpkgs#355277) — a Qt5 client searches four roots instead:
# ~/.config/Kvantum, ~/.themes, ~/.local/share/themes and its own store path.
# The tmpfiles rule further down puts the theme in the first of them, which is
# where the published solutions for this put it.
kvantumTheme = pkgs.catppuccin-kvantum.override {
accent = "lavender";
variant = "mocha";
};
# The theme name as both the package directory and the .kvconfig entry spell
# it, so the link target below cannot drift from what Kvantum looks up.
kvantumThemeName = "catppuccin-mocha-lavender";
in
{
environment.etc = {
"xdg/Kvantum/kvantum.kvconfig".source = "${xdg}/Kvantum/kvantum.kvconfig";
"xdg/qt6ct/qt6ct.conf".source = "${xdg}/qt6ct/qt6ct.conf";
# No counterpart in moonarch's defaults: Arch ships qt5ct's own config, and
# this file only has to exist because Qt5 and Qt6 read one variable between
# them, see QT_QPA_PLATFORMTHEME below. Same settings as qt6ct.conf.
"xdg/qt5ct/qt5ct.conf".text = ''
# ABOUTME: System qt5ct config — Qt5 icon theme + Kvantum style, matching qt6ct.conf.
# ABOUTME: Deployed to /etc/xdg/qt5ct/qt5ct.conf; a user copy in ~/.config/qt5ct wins by XDG precedence.
[Appearance]
style=kvantum
icon_theme=Colloid-Grey-Catppuccin-Dark
standard_dialogs=default
'';
"xdg/gtk-3.0/settings.ini".source = gtkSettings "3.0";
"xdg/gtk-4.0/settings.ini".source = gtkSettings "4.0";
};
# Generic-family defaults. Same content as
# defaults/etc/fonts/conf.d/65-moonarch-fonts.conf, but routed through the
# fontconfig module: /etc/fonts/conf.d/ is owned by NixOS and rejects
# environment.etc entries.
# localConf is written to /etc/fonts/local.conf verbatim, so it has to be a
# complete XML document — not just the inner elements.
fonts.fontconfig.localConf = ''
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
<description>Moonarch generic-family defaults</description>
<!-- binding="strong" required: the default weak <prefer> ranks behind
stock generic fallbacks, so it would not take effect. -->
<alias binding="strong">
<family>sans-serif</family>
<prefer>
<family>UbuntuSans Nerd Font</family>
</prefer>
</alias>
<alias binding="strong">
<family>monospace</family>
<prefer>
<family>UbuntuSansMono Nerd Font</family>
</prefer>
</alias>
</fontconfig>
'';
# Set systemwide instead of through the gsettings calls in post-install.sh.
programs.dconf = {
enable = true;
profiles.user.databases = [{
settings."org/gnome/desktop/interface" = {
gtk-theme = gtkTheme;
icon-theme = "Colloid-Grey-Catppuccin-Dark";
color-scheme = "prefer-dark";
font-name = "UbuntuSans Nerd Font 11";
};
}];
};
# The boot splash. `quiet` is already on the kernel command line and the module
# puts `splash` there itself, so nothing else has to change for it to show.
# With systemd in the initrd, which this configuration uses, systemd asks for
# the LUKS passphrase and Plymouth draws that prompt; the script initrd instead
# shows it as text before the splash comes up.
# The theme carries a name of its own, outside the catppuccin-<flavour> set
# that the NixOS plymouth module links its logo into, so the splash shows
# what the theme brings and nothing besides.
boot.plymouth = {
enable = true;
theme = "moonarch";
themePackages = [ moonarchPkgs.moonarch-plymouth ];
};
# Qt applications are wrapped, so each one looks for plugins in its own
# closure and never finds a style installed alongside it — which is why VLC
# kept coming up in the stock Qt style. Enabling this puts the profile's Qt5
# and Qt6 plugin directories on QT_PLUGIN_PATH, which the wrappers append to.
# platformTheme and style stay null: it would add packages that are already
# listed below, and niri's environment block sets both variables already.
qt.enable = true;
fonts.packages = with pkgs; [
nerd-fonts.ubuntu-sans
openmoji-color
];
# niri sets both in its own environment block, but that only reaches what niri
# itself spawns. Anything under the systemd user manager — quickshell, and so
# everything started from its launcher — never sees them, and Qt applications
# come up unstyled. Set here they travel through /etc/profile into
# niri-session's import-environment, and from there into the user manager.
# qt5ct, not qt6ct: Qt5 and Qt6 both read this one variable, and a Qt5 client
# asked for "qt6ct" finds only a Qt6 plugin it cannot load, so it comes up
# with no platform theme at all — no icon theme, no fonts, stock dialogs.
# Under "qt5ct" each version loads the plugin built for it; that pairing is
# what nixpkgs ships as qt.platformTheme "qt5ct", which installs both.
environment.sessionVariables.QT_QPA_PLATFORMTHEME = "qt5ct";
environment.sessionVariables.QT_STYLE_OVERRIDE = "kvantum";
# Same gap, cursors: niri's cursor block reaches xwayland-satellite, so X11
# clients have a themed pointer available, but everything under the user
# manager arrives with XCURSOR_PATH alone and has no theme name to look up.
# The name matches modules/greetd.nix, so greeter and session agree.
environment.sessionVariables.XCURSOR_THEME = "Sweet-cursors";
environment.sessionVariables.XCURSOR_SIZE = "24";
# systemPackages alone does not put the theme on XDG_DATA_DIRS: the system
# path links only the /share subdirectories named here, and Kvantum's is not
# among the defaults.
environment.pathsToLink = [ "/share/Kvantum" ];
systemd.user.tmpfiles.rules = [
# Steam gets XCURSOR_THEME from the block above — verified in its own
# environment — and still drew the core pointer, so parts of it resolve the
# theme literally named 'default' rather than the variable. Xcursor looks
# that name up along XCURSOR_PATH like any other, and ~/.icons is first,
# so pointing it at the theme covers those lookups too. 'L+' replaces the
# link on every activation, unlike the 'C' rules elsewhere, which keeps it
# following the theme instead of freezing at today's one.
"L+ %h/.icons/default - - - - /run/current-system/sw/share/icons/Sweet-cursors"
# Kvantum's Qt5 build never looks at XDG_DATA_DIRS, so the theme installed
# system-wide is invisible to it; ~/.config/Kvantum is the first place it
# does look. 'L+' for the same reason as the rule above: the link follows
# the system profile instead of freezing at one store path.
"L+ %h/.config/Kvantum/${kvantumThemeName} - - - - /run/current-system/sw/share/Kvantum/${kvantumThemeName}"
];
environment.systemPackages = with pkgs; [
moonarchPkgs.sweet-cursors
# Theming. Same derivations the greeter uses, see flake.nix.
moonarchThemes.gtk
moonarchThemes.icons
libsForQt5.qtstyleplugin-kvantum
qt6Packages.qtstyleplugin-kvantum
kvantumTheme
libsForQt5.qt5ct
qt6Packages.qt6ct
qt6.qt5compat
# GTK settings editor; it writes the same settings.ini this module deploys.
nwg-look
];
}