at 25.11-pre 9.5 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8let 9 cfg = config.services.displayManager; 10 11 installedSessions = 12 pkgs.runCommand "desktops" 13 { 14 # trivial derivation 15 preferLocalBuild = true; 16 allowSubstitutes = false; 17 } 18 '' 19 mkdir -p "$out/share/"{xsessions,wayland-sessions} 20 21 ${lib.concatMapStrings (pkg: '' 22 for n in ${lib.concatStringsSep " " pkg.providedSessions}; do 23 if ! test -f ${pkg}/share/wayland-sessions/$n.desktop -o \ 24 -f ${pkg}/share/xsessions/$n.desktop; then 25 echo "Couldn't find provided session name, $n.desktop, in session package ${pkg.name}:" 26 echo " ${pkg}" 27 return 1 28 fi 29 done 30 31 if test -d ${pkg}/share/xsessions; then 32 ${pkgs.buildPackages.xorg.lndir}/bin/lndir ${pkg}/share/xsessions $out/share/xsessions 33 fi 34 if test -d ${pkg}/share/wayland-sessions; then 35 ${pkgs.buildPackages.xorg.lndir}/bin/lndir ${pkg}/share/wayland-sessions $out/share/wayland-sessions 36 fi 37 '') cfg.sessionPackages} 38 ''; 39in 40{ 41 options = { 42 services.displayManager = { 43 enable = lib.mkEnableOption "systemd's display-manager service"; 44 45 preStart = lib.mkOption { 46 type = lib.types.lines; 47 default = ""; 48 example = "rm -f /var/log/my-display-manager.log"; 49 description = "Script executed before the display manager is started."; 50 }; 51 52 execCmd = lib.mkOption { 53 type = lib.types.str; 54 example = lib.literalExpression ''"''${pkgs.lightdm}/bin/lightdm"''; 55 description = "Command to start the display manager."; 56 }; 57 58 environment = lib.mkOption { 59 type = with lib.types; attrsOf unspecified; 60 default = { }; 61 description = "Additional environment variables needed by the display manager."; 62 }; 63 64 hiddenUsers = lib.mkOption { 65 type = with lib.types; listOf str; 66 default = [ "nobody" ]; 67 description = '' 68 A list of users which will not be shown in the display manager. 69 ''; 70 }; 71 72 logToFile = lib.mkOption { 73 type = lib.types.bool; 74 default = false; 75 description = '' 76 Whether the display manager redirects the output of the 77 session script to {file}`~/.xsession-errors`. 78 ''; 79 }; 80 81 logToJournal = lib.mkOption { 82 type = lib.types.bool; 83 default = true; 84 description = '' 85 Whether the display manager redirects the output of the 86 session script to the systemd journal. 87 ''; 88 }; 89 90 # Configuration for automatic login. Common for all DM. 91 autoLogin = lib.mkOption { 92 type = lib.types.submodule ( 93 { config, options, ... }: 94 { 95 options = { 96 enable = lib.mkOption { 97 type = lib.types.bool; 98 default = config.user != null; 99 defaultText = lib.literalExpression "config.${options.user} != null"; 100 description = '' 101 Automatically log in as {option}`autoLogin.user`. 102 ''; 103 }; 104 105 user = lib.mkOption { 106 type = with lib.types; nullOr str; 107 default = null; 108 description = '' 109 User to be used for the automatic login. 110 ''; 111 }; 112 }; 113 } 114 ); 115 116 default = { }; 117 description = '' 118 Auto login configuration attrset. 119 ''; 120 }; 121 122 defaultSession = lib.mkOption { 123 type = lib.types.nullOr lib.types.str // { 124 description = "session name"; 125 check = 126 d: 127 lib.assertMsg (d != null -> (lib.types.str.check d && lib.elem d cfg.sessionData.sessionNames)) '' 128 Default graphical session, '${d}', not found. 129 Valid names for 'services.displayManager.defaultSession' are: 130 ${lib.concatStringsSep "\n " cfg.sessionData.sessionNames} 131 ''; 132 }; 133 default = null; 134 example = "gnome"; 135 description = '' 136 Graphical session to pre-select in the session chooser (only effective for GDM, LightDM and SDDM). 137 138 On GDM, LightDM and SDDM, it will also be used as a session for auto-login. 139 140 Set this option to empty string to get an error with a list of currently available sessions. 141 ''; 142 }; 143 144 sessionData = lib.mkOption { 145 description = "Data exported for display managers convenience"; 146 internal = true; 147 default = { }; 148 }; 149 150 sessionPackages = lib.mkOption { 151 type = lib.types.listOf ( 152 lib.types.package 153 // { 154 description = "package with provided sessions"; 155 check = 156 p: 157 lib.assertMsg 158 ( 159 lib.types.package.check p 160 && p ? providedSessions 161 && p.providedSessions != [ ] 162 && lib.all lib.isString p.providedSessions 163 ) 164 '' 165 Package, '${p.name}', did not specify any session names, as strings, in 166 'passthru.providedSessions'. This is required when used as a session package. 167 168 The session names can be looked up in: 169 ${p}/share/xsessions 170 ${p}/share/wayland-sessions 171 ''; 172 } 173 ); 174 default = [ ]; 175 description = '' 176 A list of packages containing x11 or wayland session files to be passed to the display manager. 177 ''; 178 }; 179 }; 180 }; 181 182 imports = [ 183 (lib.mkRenamedOptionModule 184 [ "services" "xserver" "displayManager" "autoLogin" ] 185 [ "services" "displayManager" "autoLogin" ] 186 ) 187 (lib.mkRenamedOptionModule 188 [ "services" "xserver" "displayManager" "defaultSession" ] 189 [ "services" "displayManager" "defaultSession" ] 190 ) 191 (lib.mkRenamedOptionModule 192 [ "services" "xserver" "displayManager" "hiddenUsers" ] 193 [ "services" "displayManager" "hiddenUsers" ] 194 ) 195 (lib.mkRenamedOptionModule 196 [ "services" "xserver" "displayManager" "job" "environment" ] 197 [ "services" "displayManager" "environment" ] 198 ) 199 (lib.mkRenamedOptionModule 200 [ "services" "xserver" "displayManager" "job" "execCmd" ] 201 [ "services" "displayManager" "execCmd" ] 202 ) 203 (lib.mkRenamedOptionModule 204 [ "services" "xserver" "displayManager" "job" "logToFile" ] 205 [ "services" "displayManager" "logToFile" ] 206 ) 207 (lib.mkRenamedOptionModule 208 [ "services" "xserver" "displayManager" "job" "logToJournal" ] 209 [ "services" "displayManager" "logToJournal" ] 210 ) 211 (lib.mkRenamedOptionModule 212 [ "services" "xserver" "displayManager" "job" "preStart" ] 213 [ "services" "displayManager" "preStart" ] 214 ) 215 (lib.mkRenamedOptionModule 216 [ "services" "xserver" "displayManager" "sessionData" ] 217 [ "services" "displayManager" "sessionData" ] 218 ) 219 (lib.mkRenamedOptionModule 220 [ "services" "xserver" "displayManager" "sessionPackages" ] 221 [ "services" "displayManager" "sessionPackages" ] 222 ) 223 ]; 224 225 config = lib.mkIf cfg.enable { 226 assertions = [ 227 { 228 assertion = cfg.autoLogin.enable -> cfg.autoLogin.user != null; 229 message = '' 230 services.displayManager.autoLogin.enable requires services.displayManager.autoLogin.user to be set 231 ''; 232 } 233 ]; 234 235 # Make xsessions and wayland sessions available in XDG_DATA_DIRS 236 # as some programs have behavior that depends on them being present 237 environment.sessionVariables.XDG_DATA_DIRS = lib.mkIf (cfg.sessionPackages != [ ]) [ 238 "${cfg.sessionData.desktops}/share" 239 ]; 240 241 services.displayManager.sessionData = { 242 desktops = installedSessions; 243 sessionNames = lib.concatMap (p: p.providedSessions) cfg.sessionPackages; 244 # We do not want to force users to set defaultSession when they have only single DE. 245 autologinSession = 246 if cfg.defaultSession != null then 247 cfg.defaultSession 248 else if cfg.sessionData.sessionNames != [ ] then 249 lib.head cfg.sessionData.sessionNames 250 else 251 null; 252 }; 253 254 # so that the service won't be enabled when only startx is used 255 systemd.services.display-manager.enable = 256 let 257 dmConf = config.services.xserver.displayManager; 258 noDmUsed = 259 !( 260 dmConf.gdm.enable || cfg.sddm.enable || dmConf.xpra.enable || dmConf.lightdm.enable || cfg.ly.enable 261 ); 262 in 263 lib.mkIf noDmUsed (lib.mkDefault false); 264 265 systemd.services.display-manager = { 266 description = "Display Manager"; 267 after = [ 268 "acpid.service" 269 "systemd-logind.service" 270 "systemd-user-sessions.service" 271 ]; 272 restartIfChanged = false; 273 274 environment = cfg.environment; 275 276 preStart = cfg.preStart; 277 script = lib.mkIf (config.systemd.services.display-manager.enable == true) cfg.execCmd; 278 279 # Stop restarting if the display manager stops (crashes) 2 times 280 # in one minute. Starting X typically takes 3-4s. 281 startLimitIntervalSec = 30; 282 startLimitBurst = 3; 283 serviceConfig = { 284 Restart = "always"; 285 RestartSec = "200ms"; 286 SyslogIdentifier = "display-manager"; 287 }; 288 }; 289 }; 290}