1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 xcfg = config.services.xserver; 8 dmcfg = xcfg.displayManager; 9 cfg = dmcfg.sddm; 10 xEnv = config.systemd.services."display-manager".environment; 11 12 inherit (pkgs) sddm; 13 14 xserverWrapper = pkgs.writeScript "xserver-wrapper" '' 15 #!/bin/sh 16 ${concatMapStrings (n: "export ${n}=\"${getAttr n xEnv}\"\n") (attrNames xEnv)} 17 exec systemd-cat ${dmcfg.xserverBin} ${toString dmcfg.xserverArgs} "$@" 18 ''; 19 20 Xsetup = pkgs.writeScript "Xsetup" '' 21 #!/bin/sh 22 23 # Prior to Qt 5.9.2, there is a QML cache invalidation bug which sometimes 24 # strikes new Plasma 5 releases. If the QML cache is not invalidated, SDDM 25 # will segfault without explanation. We really tore our hair out for awhile 26 # before finding the bug: 27 # https://bugreports.qt.io/browse/QTBUG-62302 28 # We work around the problem by deleting the QML cache before startup. It 29 # will be regenerated, causing a small but perceptible delay when SDDM 30 # starts. 31 rm -fr /var/lib/sddm/.cache/sddm-greeter/qmlcache 32 33 ${cfg.setupScript} 34 ''; 35 36 Xstop = pkgs.writeScript "Xstop" '' 37 #!/bin/sh 38 ${cfg.stopScript} 39 ''; 40 41 cfgFile = pkgs.writeText "sddm.conf" '' 42 [General] 43 HaltCommand=${pkgs.systemd}/bin/systemctl poweroff 44 RebootCommand=${pkgs.systemd}/bin/systemctl reboot 45 ${optionalString cfg.autoNumlock '' 46 Numlock=on 47 ''} 48 49 [Theme] 50 Current=${cfg.theme} 51 ThemeDir=/run/current-system/sw/share/sddm/themes 52 FacesDir=/run/current-system/sw/share/sddm/faces 53 54 [Users] 55 MaximumUid=${toString config.ids.uids.nixbld} 56 HideUsers=${concatStringsSep "," dmcfg.hiddenUsers} 57 HideShells=/run/current-system/sw/bin/nologin 58 59 [X11] 60 MinimumVT=${toString (if xcfg.tty != null then xcfg.tty else 7)} 61 ServerPath=${xserverWrapper} 62 XephyrPath=${pkgs.xorg.xorgserver.out}/bin/Xephyr 63 SessionCommand=${dmcfg.session.script} 64 SessionDir=${dmcfg.session.desktops} 65 XauthPath=${pkgs.xorg.xauth}/bin/xauth 66 DisplayCommand=${Xsetup} 67 DisplayStopCommand=${Xstop} 68 69 ${optionalString cfg.autoLogin.enable '' 70 [Autologin] 71 User=${cfg.autoLogin.user} 72 Session=${defaultSessionName}.desktop 73 Relogin=${boolToString cfg.autoLogin.relogin} 74 ''} 75 76 ${cfg.extraConfig} 77 ''; 78 79 defaultSessionName = 80 let 81 dm = xcfg.desktopManager.default; 82 wm = xcfg.windowManager.default; 83 in dm + optionalString (wm != "none") ("+" + wm); 84 85in 86{ 87 options = { 88 89 services.xserver.displayManager.sddm = { 90 enable = mkOption { 91 type = types.bool; 92 default = false; 93 description = '' 94 Whether to enable sddm as the display manager. 95 ''; 96 }; 97 98 extraConfig = mkOption { 99 type = types.lines; 100 default = ""; 101 example = '' 102 [Autologin] 103 User=john 104 Session=plasma.desktop 105 ''; 106 description = '' 107 Extra lines appended to the configuration of SDDM. 108 ''; 109 }; 110 111 theme = mkOption { 112 type = types.str; 113 default = ""; 114 description = '' 115 Greeter theme to use. 116 ''; 117 }; 118 119 autoNumlock = mkOption { 120 type = types.bool; 121 default = false; 122 description = '' 123 Enable numlock at login. 124 ''; 125 }; 126 127 setupScript = mkOption { 128 type = types.str; 129 default = ""; 130 example = '' 131 # workaround for using NVIDIA Optimus without Bumblebee 132 xrandr --setprovideroutputsource modesetting NVIDIA-0 133 xrandr --auto 134 ''; 135 description = '' 136 A script to execute when starting the display server. 137 ''; 138 }; 139 140 stopScript = mkOption { 141 type = types.str; 142 default = ""; 143 description = '' 144 A script to execute when stopping the display server. 145 ''; 146 }; 147 148 autoLogin = mkOption { 149 default = {}; 150 description = '' 151 Configuration for automatic login. 152 ''; 153 154 type = types.submodule { 155 options = { 156 enable = mkOption { 157 type = types.bool; 158 default = false; 159 description = '' 160 Automatically log in as <option>autoLogin.user</option>. 161 ''; 162 }; 163 164 user = mkOption { 165 type = types.nullOr types.str; 166 default = null; 167 description = '' 168 User to be used for the automatic login. 169 ''; 170 }; 171 172 relogin = mkOption { 173 type = types.bool; 174 default = false; 175 description = '' 176 If true automatic login will kick in again on session exit (logout), otherwise it 177 will only log in automatically when the display-manager is started. 178 ''; 179 }; 180 }; 181 }; 182 }; 183 184 }; 185 186 }; 187 188 config = mkIf cfg.enable { 189 190 assertions = [ 191 { assertion = cfg.autoLogin.enable -> cfg.autoLogin.user != null; 192 message = '' 193 SDDM auto-login requires services.xserver.displayManager.sddm.autoLogin.user to be set 194 ''; 195 } 196 { assertion = cfg.autoLogin.enable -> elem defaultSessionName dmcfg.session.names; 197 message = '' 198 SDDM auto-login requires that services.xserver.desktopManager.default and 199 services.xserver.windowMananger.default are set to valid values. The current 200 default session: ${defaultSessionName} is not valid. 201 ''; 202 } 203 ]; 204 205 services.xserver.displayManager.slim.enable = false; 206 207 services.xserver.displayManager.job = { 208 logToFile = true; 209 210 environment = { 211 # Load themes from system environment 212 QT_PLUGIN_PATH = "/run/current-system/sw/" + pkgs.qt5.qtbase.qtPluginPrefix; 213 QML2_IMPORT_PATH = "/run/current-system/sw/" + pkgs.qt5.qtbase.qtQmlPrefix; 214 215 XDG_DATA_DIRS = "/run/current-system/sw/share"; 216 }; 217 218 execCmd = "exec /run/current-system/sw/bin/sddm"; 219 }; 220 221 security.pam.services = { 222 sddm = { 223 allowNullPassword = true; 224 startSession = true; 225 }; 226 227 sddm-greeter.text = '' 228 auth required pam_succeed_if.so audit quiet_success user = sddm 229 auth optional pam_permit.so 230 231 account required pam_succeed_if.so audit quiet_success user = sddm 232 account sufficient pam_unix.so 233 234 password required pam_deny.so 235 236 session required pam_succeed_if.so audit quiet_success user = sddm 237 session required pam_env.so envfile=${config.system.build.pamEnvironment} 238 session optional ${pkgs.systemd}/lib/security/pam_systemd.so 239 session optional pam_keyinit.so force revoke 240 session optional pam_permit.so 241 ''; 242 243 sddm-autologin.text = '' 244 auth requisite pam_nologin.so 245 auth required pam_succeed_if.so uid >= 1000 quiet 246 auth required pam_permit.so 247 248 account include sddm 249 250 password include sddm 251 252 session include sddm 253 ''; 254 }; 255 256 users.extraUsers.sddm = { 257 createHome = true; 258 home = "/var/lib/sddm"; 259 group = "sddm"; 260 uid = config.ids.uids.sddm; 261 }; 262 263 environment.etc."sddm.conf".source = cfgFile; 264 265 users.extraGroups.sddm.gid = config.ids.gids.sddm; 266 267 environment.systemPackages = [ sddm ]; 268 services.dbus.packages = [ sddm ]; 269 270 # To enable user switching, allow sddm to allocate TTYs/displays dynamically. 271 services.xserver.tty = null; 272 services.xserver.display = null; 273 }; 274}