1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 inherit (pkgs) plymouth nixos-icons;
8
9 cfg = config.boot.plymouth;
10
11 nixosBreezePlymouth = pkgs.plasma5Packages.breeze-plymouth.override {
12 logoFile = cfg.logo;
13 logoName = "nixos";
14 osName = "NixOS";
15 osVersion = config.system.nixos.release;
16 };
17
18 plymouthLogos = pkgs.runCommand "plymouth-logos" { inherit (cfg) logo; } ''
19 mkdir -p $out
20
21 # For themes that are compiled with PLYMOUTH_LOGO_FILE
22 mkdir -p $out/etc/plymouth
23 ln -s $logo $out/etc/plymouth/logo.png
24
25 # Logo for bgrt theme
26 # Note this is technically an abuse of watermark for the bgrt theme
27 # See: https://gitlab.freedesktop.org/plymouth/plymouth/-/issues/95#note_813768
28 mkdir -p $out/share/plymouth/themes/spinner
29 ln -s $logo $out/share/plymouth/themes/spinner/watermark.png
30
31 # Logo for spinfinity theme
32 # See: https://gitlab.freedesktop.org/plymouth/plymouth/-/issues/106
33 mkdir -p $out/share/plymouth/themes/spinfinity
34 ln -s $logo $out/share/plymouth/themes/spinfinity/header-image.png
35 '';
36
37 themesEnv = pkgs.buildEnv {
38 name = "plymouth-themes";
39 paths = [
40 plymouth
41 plymouthLogos
42 ] ++ cfg.themePackages;
43 };
44
45 configFile = pkgs.writeText "plymouthd.conf" ''
46 [Daemon]
47 ShowDelay=0
48 DeviceTimeout=8
49 Theme=${cfg.theme}
50 ${cfg.extraConfig}
51 '';
52
53in
54
55{
56
57 options = {
58
59 boot.plymouth = {
60
61 enable = mkEnableOption "Plymouth boot splash screen";
62
63 font = mkOption {
64 default = "${pkgs.dejavu_fonts.minimal}/share/fonts/truetype/DejaVuSans.ttf";
65 defaultText = literalExpression ''"''${pkgs.dejavu_fonts.minimal}/share/fonts/truetype/DejaVuSans.ttf"'';
66 type = types.path;
67 description = ''
68 Font file made available for displaying text on the splash screen.
69 '';
70 };
71
72 themePackages = mkOption {
73 default = lib.optional (cfg.theme == "breeze") nixosBreezePlymouth;
74 type = types.listOf types.package;
75 description = ''
76 Extra theme packages for plymouth.
77 '';
78 };
79
80 theme = mkOption {
81 default = "bgrt";
82 type = types.str;
83 description = ''
84 Splash screen theme.
85 '';
86 };
87
88 logo = mkOption {
89 type = types.path;
90 # Dimensions are 48x48 to match GDM logo
91 default = "${nixos-icons}/share/icons/hicolor/48x48/apps/nix-snowflake-white.png";
92 defaultText = literalExpression ''pkgs.fetchurl {
93 url = "https://nixos.org/logo/nixos-hires.png";
94 sha256 = "1ivzgd7iz0i06y36p8m5w48fd8pjqwxhdaavc0pxs7w1g7mcy5si";
95 }'';
96 description = ''
97 Logo which is displayed on the splash screen.
98 '';
99 };
100
101 extraConfig = mkOption {
102 type = types.lines;
103 default = "";
104 description = ''
105 Literal string to append to <literal>configFile</literal>
106 and the config file generated by the plymouth module.
107 '';
108 };
109
110 };
111
112 };
113
114 config = mkIf cfg.enable {
115
116 boot.kernelParams = [ "splash" ];
117
118 # To be discoverable by systemd.
119 environment.systemPackages = [ plymouth ];
120
121 environment.etc."plymouth/plymouthd.conf".source = configFile;
122 environment.etc."plymouth/plymouthd.defaults".source = "${plymouth}/share/plymouth/plymouthd.defaults";
123 environment.etc."plymouth/logo.png".source = cfg.logo;
124 environment.etc."plymouth/themes".source = "${themesEnv}/share/plymouth/themes";
125 # XXX: Needed because we supply a different set of plugins in initrd.
126 environment.etc."plymouth/plugins".source = "${plymouth}/lib/plymouth";
127
128 systemd.packages = [ plymouth ];
129
130 systemd.services.plymouth-kexec.wantedBy = [ "kexec.target" ];
131 systemd.services.plymouth-halt.wantedBy = [ "halt.target" ];
132 systemd.services.plymouth-quit-wait.wantedBy = [ "multi-user.target" ];
133 systemd.services.plymouth-quit.wantedBy = [ "multi-user.target" ];
134 systemd.services.plymouth-poweroff.wantedBy = [ "poweroff.target" ];
135 systemd.services.plymouth-reboot.wantedBy = [ "reboot.target" ];
136 systemd.services.plymouth-read-write.wantedBy = [ "sysinit.target" ];
137 systemd.services.systemd-ask-password-plymouth.wantedBy = [ "multi-user.target" ];
138 systemd.paths.systemd-ask-password-plymouth.wantedBy = [ "multi-user.target" ];
139
140 boot.initrd.extraUtilsCommands = ''
141 copy_bin_and_libs ${plymouth}/bin/plymouth
142 copy_bin_and_libs ${plymouth}/bin/plymouthd
143
144 # Check if the actual requested theme is here
145 if [[ ! -d ${themesEnv}/share/plymouth/themes/${cfg.theme} ]]; then
146 echo "The requested theme: ${cfg.theme} is not provided by any of the packages in boot.plymouth.themePackages"
147 exit 1
148 fi
149
150 moduleName="$(sed -n 's,ModuleName *= *,,p' ${themesEnv}/share/plymouth/themes/${cfg.theme}/${cfg.theme}.plymouth)"
151
152 mkdir -p $out/lib/plymouth/renderers
153 # module might come from a theme
154 cp ${themesEnv}/lib/plymouth/{text,details,label,$moduleName}.so $out/lib/plymouth
155 cp ${plymouth}/lib/plymouth/renderers/{drm,frame-buffer}.so $out/lib/plymouth/renderers
156
157 mkdir -p $out/share/plymouth/themes
158 cp ${plymouth}/share/plymouth/plymouthd.defaults $out/share/plymouth
159
160 # Copy themes into working directory for patching
161 mkdir themes
162
163 # Use -L to copy the directories proper, not the symlinks to them.
164 # Copy all themes because they're not large assets, and bgrt depends on the ImageDir of
165 # the spinner theme.
166 cp -r -L ${themesEnv}/share/plymouth/themes/* themes
167
168 # Patch out any attempted references to the theme or plymouth's themes directory
169 chmod -R +w themes
170 find themes -type f | while read file
171 do
172 sed -i "s,/nix/.*/share/plymouth/themes,$out/share/plymouth/themes,g" $file
173 done
174
175 # Install themes
176 cp -r themes/* $out/share/plymouth/themes
177
178 # Install logo
179 mkdir -p $out/etc/plymouth
180 cp -r -L ${themesEnv}/etc/plymouth $out
181
182 # Setup font
183 mkdir -p $out/share/fonts
184 cp ${cfg.font} $out/share/fonts
185 mkdir -p $out/etc/fonts
186 cat > $out/etc/fonts/fonts.conf <<EOF
187 <?xml version="1.0"?>
188 <!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
189 <fontconfig>
190 <dir>$out/share/fonts</dir>
191 </fontconfig>
192 EOF
193 '';
194
195 boot.initrd.extraUtilsCommandsTest = ''
196 $out/bin/plymouthd --help >/dev/null
197 $out/bin/plymouth --help >/dev/null
198 '';
199
200 boot.initrd.extraUdevRulesCommands = ''
201 cp ${config.systemd.package}/lib/udev/rules.d/{70-uaccess,71-seat}.rules $out
202 sed -i '/loginctl/d' $out/71-seat.rules
203 '';
204
205 # We use `mkAfter` to ensure that LUKS password prompt would be shown earlier than the splash screen.
206 boot.initrd.preLVMCommands = mkAfter ''
207 mkdir -p /etc/plymouth
208 mkdir -p /run/plymouth
209 ln -s ${configFile} /etc/plymouth/plymouthd.conf
210 ln -s $extraUtils/share/plymouth/plymouthd.defaults /etc/plymouth/plymouthd.defaults
211 ln -s $extraUtils/share/plymouth/logo.png /etc/plymouth/logo.png
212 ln -s $extraUtils/share/plymouth/themes /etc/plymouth/themes
213 ln -s $extraUtils/lib/plymouth /etc/plymouth/plugins
214 ln -s $extraUtils/etc/fonts /etc/fonts
215
216 plymouthd --mode=boot --pid-file=/run/plymouth/pid --attach-to-session
217 plymouth show-splash
218 '';
219
220 boot.initrd.postMountCommands = ''
221 plymouth update-root-fs --new-root-dir="$targetRoot"
222 '';
223
224 # `mkBefore` to ensure that any custom prompts would be visible.
225 boot.initrd.preFailCommands = mkBefore ''
226 plymouth quit --wait
227 '';
228
229 };
230
231}