1 { config, lib, options, pkgs, ... }:
7 plymouth = pkgs.plymouth.override {
8 systemd = config.boot.initrd.systemd.package;
11 cfg = config.boot.plymouth;
12 opt = options.boot.plymouth;
14 nixosBreezePlymouth = pkgs.plasma5Packages.breeze-plymouth.override {
18 osVersion = config.system.nixos.release;
21 plymouthLogos = pkgs.runCommand "plymouth-logos" { inherit (cfg) logo; } ''
24 # For themes that are compiled with PLYMOUTH_LOGO_FILE
25 mkdir -p $out/etc/plymouth
26 ln -s $logo $out/etc/plymouth/logo.png
29 # Note this is technically an abuse of watermark for the bgrt theme
30 # See: https://gitlab.freedesktop.org/plymouth/plymouth/-/issues/95#note_813768
31 mkdir -p $out/share/plymouth/themes/spinner
32 ln -s $logo $out/share/plymouth/themes/spinner/watermark.png
34 # Logo for spinfinity theme
35 # See: https://gitlab.freedesktop.org/plymouth/plymouth/-/issues/106
36 mkdir -p $out/share/plymouth/themes/spinfinity
37 ln -s $logo $out/share/plymouth/themes/spinfinity/header-image.png
39 # Logo for catppuccin (two-step) theme
40 for flavour in mocha macchiato latte frappe
42 mkdir -p $out/share/plymouth/themes/catppuccin-"$flavour"
43 ln -s $logo $out/share/plymouth/themes/catppuccin-"$flavour"/header-image.png
47 themesEnv = pkgs.buildEnv {
48 name = "plymouth-themes";
52 ] ++ cfg.themePackages;
55 configFile = pkgs.writeText "plymouthd.conf" ''
71 enable = mkEnableOption "Plymouth boot splash screen";
74 default = "${pkgs.dejavu_fonts.minimal}/share/fonts/truetype/DejaVuSans.ttf";
75 defaultText = literalExpression ''"''${pkgs.dejavu_fonts.minimal}/share/fonts/truetype/DejaVuSans.ttf"'';
78 Font file made available for displaying text on the splash screen.
82 themePackages = mkOption {
83 default = lib.optional (cfg.theme == "breeze") nixosBreezePlymouth;
84 defaultText = literalMD ''
85 A NixOS branded variant of the breeze theme when
86 `config.${opt.theme} == "breeze"`, otherwise
89 type = types.listOf types.package;
91 Extra theme packages for plymouth.
105 # Dimensions are 48x48 to match GDM logo
106 default = "${pkgs.nixos-icons}/share/icons/hicolor/48x48/apps/nix-snowflake-white.png";
107 defaultText = literalExpression ''"''${pkgs.nixos-icons}/share/icons/hicolor/48x48/apps/nix-snowflake-white.png"'';
108 example = literalExpression ''
110 url = "https://nixos.org/logo/nixos-hires.png";
111 sha256 = "1ivzgd7iz0i06y36p8m5w48fd8pjqwxhdaavc0pxs7w1g7mcy5si";
115 Logo which is displayed on the splash screen.
116 Currently supports PNG file format only.
120 extraConfig = mkOption {
124 Literal string to append to `configFile`
125 and the config file generated by the plymouth module.
133 config = mkIf cfg.enable {
135 boot.kernelParams = [ "splash" ];
137 # To be discoverable by systemd.
138 environment.systemPackages = [ plymouth ];
140 environment.etc."plymouth/plymouthd.conf".source = configFile;
141 environment.etc."plymouth/plymouthd.defaults".source = "${plymouth}/share/plymouth/plymouthd.defaults";
142 environment.etc."plymouth/logo.png".source = cfg.logo;
143 environment.etc."plymouth/themes".source = "${themesEnv}/share/plymouth/themes";
144 # XXX: Needed because we supply a different set of plugins in initrd.
145 environment.etc."plymouth/plugins".source = "${plymouth}/lib/plymouth";
147 systemd.tmpfiles.rules = [
148 "d /run/plymouth 0755 root root 0 -"
149 "L+ /run/plymouth/plymouthd.defaults - - - - /etc/plymouth/plymouthd.defaults"
150 "L+ /run/plymouth/themes - - - - /etc/plymouth/themes"
151 "L+ /run/plymouth/plugins - - - - /etc/plymouth/plugins"
154 systemd.packages = [ plymouth ];
156 systemd.services.plymouth-kexec.wantedBy = [ "kexec.target" ];
157 systemd.services.plymouth-halt.wantedBy = [ "halt.target" ];
158 systemd.services.plymouth-quit-wait.wantedBy = [ "multi-user.target" ];
159 systemd.services.plymouth-quit.wantedBy = [ "multi-user.target" ];
160 systemd.services.plymouth-poweroff.wantedBy = [ "poweroff.target" ];
161 systemd.services.plymouth-reboot.wantedBy = [ "reboot.target" ];
162 systemd.services.plymouth-read-write.wantedBy = [ "sysinit.target" ];
163 systemd.services.systemd-ask-password-plymouth.wantedBy = [ "multi-user.target" ];
164 systemd.paths.systemd-ask-password-plymouth.wantedBy = [ "multi-user.target" ];
166 # Prevent Plymouth taking over the screen during system updates.
167 systemd.services.plymouth-start.restartIfChanged = false;
169 boot.initrd.systemd = {
170 extraBin.plymouth = "${plymouth}/bin/plymouth"; # for the recovery shell
172 "${lib.getBin config.boot.initrd.systemd.package}/bin/systemd-tty-ask-password-agent"
173 "${plymouth}/bin/plymouthd"
174 "${plymouth}/sbin/plymouthd"
176 packages = [ plymouth ]; # systemd units
179 "/etc/plymouth/plymouthd.conf".source = configFile;
180 "/etc/plymouth/logo.png".source = cfg.logo;
181 "/etc/plymouth/plymouthd.defaults".source = "${plymouth}/share/plymouth/plymouthd.defaults";
183 "/etc/plymouth/plugins".source = pkgs.runCommand "plymouth-initrd-plugins" {} ''
184 # Check if the actual requested theme is here
185 if [[ ! -d ${themesEnv}/share/plymouth/themes/${cfg.theme} ]]; then
186 echo "The requested theme: ${cfg.theme} is not provided by any of the packages in boot.plymouth.themePackages"
190 moduleName="$(sed -n 's,ModuleName *= *,,p' ${themesEnv}/share/plymouth/themes/${cfg.theme}/${cfg.theme}.plymouth)"
192 mkdir -p $out/renderers
193 # module might come from a theme
194 cp ${themesEnv}/lib/plymouth/*.so $out
195 cp ${plymouth}/lib/plymouth/renderers/*.so $out/renderers
196 # useless in the initrd, and adds several megabytes to the closure
197 rm $out/renderers/x11.so
199 "/etc/plymouth/themes".source = pkgs.runCommand "plymouth-initrd-themes" {} ''
200 # Check if the actual requested theme is here
201 if [[ ! -d ${themesEnv}/share/plymouth/themes/${cfg.theme} ]]; then
202 echo "The requested theme: ${cfg.theme} is not provided by any of the packages in boot.plymouth.themePackages"
206 mkdir -p $out/${cfg.theme}
207 cp -r ${themesEnv}/share/plymouth/themes/${cfg.theme}/* $out/${cfg.theme}
208 # Copy more themes if the theme depends on others
209 for theme in $(grep -hRo '/share/plymouth/themes/.*$' $out | xargs -n1 basename); do
210 if [[ -d "${themesEnv}/share/plymouth/themes/$theme" ]]; then
211 if [[ ! -d "$out/$theme" ]]; then
212 echo "Adding dependent theme: $theme"
213 mkdir -p "$out/$theme"
214 cp -r "${themesEnv}/share/plymouth/themes/$theme"/* "$out/$theme"
217 echo "Missing theme dependency: $theme"
221 for theme in $out/*/*.plymouth; do
222 sed -i "s,${builtins.storeDir}/.*/share/plymouth/themes,$out," "$theme"
227 "/etc/plymouth/fonts".source = pkgs.runCommand "plymouth-initrd-fonts" {} ''
229 cp ${escapeShellArg cfg.font} $out
231 "/etc/fonts/fonts.conf".text = ''
232 <?xml version="1.0"?>
233 <!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
235 <dir>/etc/plymouth/fonts</dir>
239 # Properly enable units. These are the units that arch copies
241 plymouth-halt.wantedBy = [ "halt.target" ];
242 plymouth-kexec.wantedBy = [ "kexec.target" ];
243 plymouth-poweroff.wantedBy = [ "poweroff.target" ];
244 plymouth-quit-wait.wantedBy = [ "multi-user.target" ];
245 plymouth-quit.wantedBy = [ "multi-user.target" ];
246 plymouth-read-write.wantedBy = [ "sysinit.target" ];
247 plymouth-reboot.wantedBy = [ "reboot.target" ];
248 plymouth-start.wantedBy = [ "initrd-switch-root.target" "sysinit.target" ];
249 plymouth-switch-root-initramfs.wantedBy = [ "halt.target" "kexec.target" "plymouth-switch-root-initramfs.service" "poweroff.target" "reboot.target" ];
250 plymouth-switch-root.wantedBy = [ "initrd-switch-root.target" ];
252 # Link in runtime files before starting
253 services.plymouth-start.preStart = ''
254 mkdir -p /run/plymouth
255 ln -sf /etc/plymouth/{plymouthd.defaults,themes,plugins} /run/plymouth/
259 # Insert required udev rules. We take stage 2 systemd because the udev
260 # rules are only generated when building with logind.
261 boot.initrd.services.udev.packages = [ (pkgs.runCommand "initrd-plymouth-udev-rules" {} ''
262 mkdir -p $out/etc/udev/rules.d
263 cp ${config.systemd.package.out}/lib/udev/rules.d/{70-uaccess,71-seat}.rules $out/etc/udev/rules.d
264 sed -i '/loginctl/d' $out/etc/udev/rules.d/71-seat.rules
267 boot.initrd.extraUtilsCommands = lib.mkIf (!config.boot.initrd.systemd.enable) ''
268 copy_bin_and_libs ${plymouth}/bin/plymouth
269 copy_bin_and_libs ${plymouth}/bin/plymouthd
271 # Check if the actual requested theme is here
272 if [[ ! -d ${themesEnv}/share/plymouth/themes/${cfg.theme} ]]; then
273 echo "The requested theme: ${cfg.theme} is not provided by any of the packages in boot.plymouth.themePackages"
277 moduleName="$(sed -n 's,ModuleName *= *,,p' ${themesEnv}/share/plymouth/themes/${cfg.theme}/${cfg.theme}.plymouth)"
279 mkdir -p $out/lib/plymouth/renderers
280 # module might come from a theme
281 cp ${themesEnv}/lib/plymouth/*.so $out/lib/plymouth
282 cp ${plymouth}/lib/plymouth/renderers/*.so $out/lib/plymouth/renderers
283 # useless in the initrd, and adds several megabytes to the closure
284 rm $out/lib/plymouth/renderers/x11.so
286 mkdir -p $out/share/plymouth/themes
287 cp ${plymouth}/share/plymouth/plymouthd.defaults $out/share/plymouth
289 # Copy themes into working directory for patching
292 # Use -L to copy the directories proper, not the symlinks to them.
293 # Copy all themes because they're not large assets, and bgrt depends on the ImageDir of
295 cp -r -L ${themesEnv}/share/plymouth/themes/* themes
297 # Patch out any attempted references to the theme or plymouth's themes directory
299 find themes -type f | while read file
301 sed -i "s,${builtins.storeDir}/.*/share/plymouth/themes,$out/share/plymouth/themes,g" $file
305 cp -r themes/* $out/share/plymouth/themes
308 mkdir -p $out/etc/plymouth
309 cp -r -L ${themesEnv}/etc/plymouth $out/etc
312 mkdir -p $out/share/fonts
313 cp ${cfg.font} $out/share/fonts
314 mkdir -p $out/etc/fonts
315 cat > $out/etc/fonts/fonts.conf <<EOF
316 <?xml version="1.0"?>
317 <!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
319 <dir>$out/share/fonts</dir>
324 boot.initrd.extraUtilsCommandsTest = mkIf (!config.boot.initrd.systemd.enable) ''
325 $out/bin/plymouthd --help >/dev/null
326 $out/bin/plymouth --help >/dev/null
329 boot.initrd.extraUdevRulesCommands = mkIf (!config.boot.initrd.systemd.enable) ''
330 cp ${config.systemd.package}/lib/udev/rules.d/{70-uaccess,71-seat}.rules $out
331 sed -i '/loginctl/d' $out/71-seat.rules
334 # We use `mkAfter` to ensure that LUKS password prompt would be shown earlier than the splash screen.
335 boot.initrd.preLVMCommands = mkIf (!config.boot.initrd.systemd.enable) (mkAfter ''
337 for o in $(cat /proc/cmdline); do
345 if [ "$plymouth_enabled" != 0 ]; then
346 mkdir -p /etc/plymouth
347 mkdir -p /run/plymouth
348 ln -s $extraUtils/etc/plymouth/logo.png /etc/plymouth/logo.png
349 ln -s ${configFile} /etc/plymouth/plymouthd.conf
350 ln -s $extraUtils/share/plymouth/plymouthd.defaults /run/plymouth/plymouthd.defaults
351 ln -s $extraUtils/share/plymouth/themes /run/plymouth/themes
352 ln -s $extraUtils/lib/plymouth /run/plymouth/plugins
353 ln -s $extraUtils/etc/fonts /etc/fonts
355 plymouthd --mode=boot --pid-file=/run/plymouth/pid --attach-to-session
360 boot.initrd.postMountCommands = mkIf (!config.boot.initrd.systemd.enable) ''
361 if [ "$plymouth_enabled" != 0 ]; then
362 plymouth update-root-fs --new-root-dir="$targetRoot"
366 # `mkBefore` to ensure that any custom prompts would be visible.
367 boot.initrd.preFailCommands = mkIf (!config.boot.initrd.systemd.enable) (mkBefore ''
368 if [ "$plymouth_enabled" != 0 ]; then