at v206 11 kB view raw
1# This module declares the options to define a *display manager*, the 2# program responsible for handling X logins (such as xdm, kdm, gdb, or 3# SLiM). The display manager allows the user to select a *session 4# type*. When the user logs in, the display manager starts the 5# *session script* ("xsession" below) to launch the selected session 6# type. The session type defines two things: the *desktop manager* 7# (e.g., KDE, Gnome or a plain xterm), and optionally the *window 8# manager* (e.g. kwin or twm). 9 10{ config, lib, pkgs, ... }: 11 12with lib; 13 14let 15 16 cfg = config.services.xserver; 17 xorg = pkgs.xorg; 18 19 vaapiDrivers = pkgs.buildEnv { 20 name = "vaapi-drivers"; 21 paths = cfg.vaapiDrivers; 22 # We only want /lib/dri, but with a single input path, we need "/" for it to work 23 pathsToLink = [ "/" ]; 24 }; 25 26 fontconfig = config.fonts.fontconfig; 27 xresourcesXft = pkgs.writeText "Xresources-Xft" '' 28 ${optionalString (fontconfig.dpi != 0) ''Xft.dpi: ${toString fontconfig.dpi}''} 29 Xft.antialias: ${if fontconfig.antialias then "1" else "0"} 30 Xft.rgba: ${fontconfig.subpixel.rgba} 31 Xft.lcdfilter: lcd${fontconfig.subpixel.lcdfilter} 32 Xft.hinting: ${if fontconfig.hinting.enable then "1" else "0"} 33 Xft.autohint: ${if fontconfig.hinting.autohint then "1" else "0"} 34 Xft.hintstyle: hint${fontconfig.hinting.style} 35 ''; 36 37 # file provided by services.xserver.displayManager.session.script 38 xsession = wm: dm: pkgs.writeScript "xsession" 39 '' 40 #! /bin/sh 41 42 . /etc/profile 43 cd "$HOME" 44 45 # The first argument of this script is the session type. 46 sessionType="$1" 47 if [ "$sessionType" = default ]; then sessionType=""; fi 48 49 ${optionalString (!cfg.displayManager.job.logsXsession) '' 50 exec > ~/.xsession-errors 2>&1 51 ''} 52 53 ${optionalString cfg.startDbusSession '' 54 if test -z "$DBUS_SESSION_BUS_ADDRESS"; then 55 exec ${pkgs.dbus.tools}/bin/dbus-launch --exit-with-session "$0" "$sessionType" 56 fi 57 ''} 58 59 ${optionalString cfg.displayManager.desktopManagerHandlesLidAndPower '' 60 # Stop systemd from handling the power button and lid switch, 61 # since presumably the desktop environment will handle these. 62 if [ -z "$_INHIBITION_LOCK_TAKEN" ]; then 63 export _INHIBITION_LOCK_TAKEN=1 64 if ! ${config.systemd.package}/bin/loginctl show-session $XDG_SESSION_ID | grep -q '^RemoteHost='; then 65 exec ${config.systemd.package}/bin/systemd-inhibit --what=handle-lid-switch:handle-power-key --why="Desktop environment handles power events" "$0" "$sessionType" 66 fi 67 fi 68 69 ''} 70 71 ${optionalString cfg.startGnuPGAgent '' 72 if test -z "$SSH_AUTH_SOCK"; then 73 # Restart this script as a child of the GnuPG agent. 74 exec "${pkgs.gnupg}/bin/gpg-agent" \ 75 --enable-ssh-support --daemon \ 76 --pinentry-program "${pkgs.pinentry}/bin/pinentry-gtk-2" \ 77 --write-env-file "$HOME/.gpg-agent-info" \ 78 "$0" "$sessionType" 79 fi 80 ''} 81 82 # Handle being called by kdm. 83 if test "''${1:0:1}" = /; then eval exec "$1"; fi 84 85 # Start PulseAudio if enabled. 86 ${optionalString (config.hardware.pulseaudio.enable) '' 87 ${optionalString (!config.hardware.pulseaudio.systemWide) 88 "${config.hardware.pulseaudio.package}/bin/pulseaudio --start" 89 } 90 91 # Publish access credentials in the root window. 92 ${config.hardware.pulseaudio.package}/bin/pactl load-module module-x11-publish "display=$DISPLAY" 93 94 # Keep track of devices. Mostly useful for Phonon/KDE. 95 ${config.hardware.pulseaudio.package}/bin/pactl load-module module-device-manager "do_routing=1" 96 ''} 97 98 # Tell systemd about our $DISPLAY. This is needed by the 99 # ssh-agent unit. 100 ${config.systemd.package}/bin/systemctl --user import-environment DISPLAY 101 102 # Load X defaults. 103 ${xorg.xrdb}/bin/xrdb -merge ${xresourcesXft} 104 if test -e ~/.Xresources; then 105 ${xorg.xrdb}/bin/xrdb -merge ~/.Xresources 106 elif test -e ~/.Xdefaults; then 107 ${xorg.xrdb}/bin/xrdb -merge ~/.Xdefaults 108 fi 109 110 export LIBVA_DRIVERS_PATH=${vaapiDrivers}/lib/dri 111 112 # Speed up application start by 50-150ms according to 113 # http://kdemonkey.blogspot.nl/2008/04/magic-trick.html 114 rm -rf $HOME/.compose-cache 115 mkdir $HOME/.compose-cache 116 117 # Work around KDE errors when a user first logs in and 118 # .local/share doesn't exist yet. 119 mkdir -p $HOME/.local/share 120 121 ${cfg.displayManager.sessionCommands} 122 123 # Allow the user to execute commands at the beginning of the X session. 124 if test -f ~/.xprofile; then 125 source ~/.xprofile 126 fi 127 128 # Allow the user to setup a custom session type. 129 if test -x ~/.xsession; then 130 exec ~/.xsession 131 else 132 if test "$sessionType" = "custom"; then 133 sessionType="" # fall-thru if there is no ~/.xsession 134 fi 135 fi 136 137 # The session type is "<desktop-manager> + <window-manager>", so 138 # extract those. 139 windowManager="''${sessionType##* + }" 140 : ''${windowManager:=${cfg.windowManager.default}} 141 desktopManager="''${sessionType% + *}" 142 : ''${desktopManager:=${cfg.desktopManager.default}} 143 144 # Start the window manager. 145 case $windowManager in 146 ${concatMapStrings (s: '' 147 (${s.name}) 148 ${s.start} 149 ;; 150 '') wm} 151 (*) echo "$0: Window manager '$windowManager' not found.";; 152 esac 153 154 # Start the desktop manager. 155 case $desktopManager in 156 ${concatMapStrings (s: '' 157 (${s.name}) 158 ${s.start} 159 ;; 160 '') dm} 161 (*) echo "$0: Desktop manager '$desktopManager' not found.";; 162 esac 163 164 test -n "$waitPID" && wait "$waitPID" 165 exit 0 166 ''; 167 168 mkDesktops = names: pkgs.runCommand "desktops" 169 { # trivial derivation 170 preferLocalBuild = true; 171 allowSubstitutes = false; 172 } 173 '' 174 mkdir -p $out 175 ${concatMapStrings (n: '' 176 cat - > "$out/${n}.desktop" << EODESKTOP 177 [Desktop Entry] 178 Version=1.0 179 Type=XSession 180 TryExec=${cfg.displayManager.session.script} 181 Exec=${cfg.displayManager.session.script} '${n}' 182 X-GDM-BypassXsession=true 183 Name=${n} 184 Comment= 185 EODESKTOP 186 '') names} 187 ''; 188 189in 190 191{ 192 193 options = { 194 195 services.xserver.displayManager = { 196 197 xauthBin = mkOption { 198 internal = true; 199 default = "${xorg.xauth}/bin/xauth"; 200 description = "Path to the <command>xauth</command> program used by display managers."; 201 }; 202 203 xserverBin = mkOption { 204 type = types.path; 205 description = "Path to the X server used by display managers."; 206 }; 207 208 xserverArgs = mkOption { 209 type = types.listOf types.str; 210 default = []; 211 example = [ "-ac" "-logverbose" "-verbose" "-nolisten tcp" ]; 212 description = "List of arguments for the X server."; 213 apply = toString; 214 }; 215 216 sessionCommands = mkOption { 217 type = types.lines; 218 default = ""; 219 example = 220 '' 221 xmessage "Hello World!" & 222 ''; 223 description = "Shell commands executed just before the window or desktop manager is started."; 224 }; 225 226 hiddenUsers = mkOption { 227 type = types.listOf types.str; 228 default = [ "nobody" ]; 229 description = '' 230 A list of users which will not be shown in the display manager. 231 ''; 232 }; 233 234 desktopManagerHandlesLidAndPower = mkOption { 235 type = types.bool; 236 default = false; 237 description = '' 238 Whether the display manager should prevent systemd from handling 239 lid and power events. This is normally handled by the desktop 240 environment's power manager. Turn this off when using a minimal 241 X11 setup without a full power manager. 242 ''; 243 }; 244 245 session = mkOption { 246 default = []; 247 example = literalExample 248 '' 249 [ { manage = "desktop"; 250 name = "xterm"; 251 start = ''' 252 ''${pkgs.xterm}/bin/xterm -ls & 253 waitPID=$! 254 '''; 255 } 256 ] 257 ''; 258 description = '' 259 List of sessions supported with the command used to start each 260 session. Each session script can set the 261 <varname>waitPID</varname> shell variable to make this script 262 wait until the end of the user session. Each script is used 263 to define either a windows manager or a desktop manager. These 264 can be differentiated by setting the attribute 265 <varname>manage</varname> either to <literal>"window"</literal> 266 or <literal>"desktop"</literal>. 267 268 The list of desktop manager and window manager should appear 269 inside the display manager with the desktop manager name 270 followed by the window manager name. 271 ''; 272 apply = list: rec { 273 wm = filter (s: s.manage == "window") list; 274 dm = filter (s: s.manage == "desktop") list; 275 names = flip concatMap dm 276 (d: map (w: d.name + optionalString (w.name != "none") (" + " + w.name)) 277 (filter (w: d.name != "none" || w.name != "none") wm)); 278 desktops = mkDesktops names; 279 script = xsession wm dm; 280 }; 281 }; 282 283 job = { 284 285 preStart = mkOption { 286 type = types.lines; 287 default = ""; 288 example = "rm -f /var/log/my-display-manager.log"; 289 description = "Script executed before the display manager is started."; 290 }; 291 292 execCmd = mkOption { 293 type = types.str; 294 example = literalExample '' 295 "''${pkgs.slim}/bin/slim" 296 ''; 297 description = "Command to start the display manager."; 298 }; 299 300 environment = mkOption { 301 type = types.attrsOf types.unspecified; 302 default = {}; 303 example = { SLIM_CFGFILE = "/etc/slim.conf"; }; 304 description = "Additional environment variables needed by the display manager."; 305 }; 306 307 logsXsession = mkOption { 308 type = types.bool; 309 default = false; 310 description = '' 311 Whether the display manager redirects the 312 output of the session script to 313 <filename>~/.xsession-errors</filename>. 314 ''; 315 }; 316 317 }; 318 319 }; 320 321 }; 322 323 config = { 324 325 services.xserver.displayManager.xserverBin = "${xorg.xorgserver}/bin/X"; 326 327 }; 328 329}