at v192 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 ${cfg.displayManager.sessionCommands} 118 119 # Allow the user to execute commands at the beginning of the X session. 120 if test -f ~/.xprofile; then 121 source ~/.xprofile 122 fi 123 124 # Allow the user to setup a custom session type. 125 if test -x ~/.xsession; then 126 exec ~/.xsession 127 else 128 if test "$sessionType" = "custom"; then 129 sessionType="" # fall-thru if there is no ~/.xsession 130 fi 131 fi 132 133 # The session type is "<desktop-manager> + <window-manager>", so 134 # extract those. 135 windowManager="''${sessionType##* + }" 136 : ''${windowManager:=${cfg.windowManager.default}} 137 desktopManager="''${sessionType% + *}" 138 : ''${desktopManager:=${cfg.desktopManager.default}} 139 140 # Start the window manager. 141 case $windowManager in 142 ${concatMapStrings (s: '' 143 (${s.name}) 144 ${s.start} 145 ;; 146 '') wm} 147 (*) echo "$0: Window manager '$windowManager' not found.";; 148 esac 149 150 # Start the desktop manager. 151 case $desktopManager in 152 ${concatMapStrings (s: '' 153 (${s.name}) 154 ${s.start} 155 ;; 156 '') dm} 157 (*) echo "$0: Desktop manager '$desktopManager' not found.";; 158 esac 159 160 test -n "$waitPID" && wait "$waitPID" 161 exit 0 162 ''; 163 164 mkDesktops = names: pkgs.runCommand "desktops" 165 { # trivial derivation 166 preferLocalBuild = true; 167 allowSubstitutes = false; 168 } 169 '' 170 mkdir -p $out 171 ${concatMapStrings (n: '' 172 cat - > "$out/${n}.desktop" << EODESKTOP 173 [Desktop Entry] 174 Version=1.0 175 Type=XSession 176 TryExec=${cfg.displayManager.session.script} 177 Exec=${cfg.displayManager.session.script} '${n}' 178 X-GDM-BypassXsession=true 179 Name=${n} 180 Comment= 181 EODESKTOP 182 '') names} 183 ''; 184 185in 186 187{ 188 189 options = { 190 191 services.xserver.displayManager = { 192 193 xauthBin = mkOption { 194 internal = true; 195 default = "${xorg.xauth}/bin/xauth"; 196 description = "Path to the <command>xauth</command> program used by display managers."; 197 }; 198 199 xserverBin = mkOption { 200 type = types.path; 201 description = "Path to the X server used by display managers."; 202 }; 203 204 xserverArgs = mkOption { 205 type = types.listOf types.str; 206 default = []; 207 example = [ "-ac" "-logverbose" "-verbose" "-nolisten tcp" ]; 208 description = "List of arguments for the X server."; 209 apply = toString; 210 }; 211 212 sessionCommands = mkOption { 213 type = types.lines; 214 default = ""; 215 example = 216 '' 217 xmessage "Hello World!" & 218 ''; 219 description = "Shell commands executed just before the window or desktop manager is started."; 220 }; 221 222 hiddenUsers = mkOption { 223 type = types.listOf types.str; 224 default = [ "nobody" ]; 225 description = '' 226 A list of users which will not be shown in the display manager. 227 ''; 228 }; 229 230 desktopManagerHandlesLidAndPower = mkOption { 231 type = types.bool; 232 default = false; 233 description = '' 234 Whether the display manager should prevent systemd from handling 235 lid and power events. This is normally handled by the desktop 236 environment's power manager. Turn this off when using a minimal 237 X11 setup without a full power manager. 238 ''; 239 }; 240 241 session = mkOption { 242 default = []; 243 example = literalExample 244 '' 245 [ { manage = "desktop"; 246 name = "xterm"; 247 start = ''' 248 ''${pkgs.xterm}/bin/xterm -ls & 249 waitPID=$! 250 '''; 251 } 252 ] 253 ''; 254 description = '' 255 List of sessions supported with the command used to start each 256 session. Each session script can set the 257 <varname>waitPID</varname> shell variable to make this script 258 wait until the end of the user session. Each script is used 259 to define either a windows manager or a desktop manager. These 260 can be differentiated by setting the attribute 261 <varname>manage</varname> either to <literal>"window"</literal> 262 or <literal>"desktop"</literal>. 263 264 The list of desktop manager and window manager should appear 265 inside the display manager with the desktop manager name 266 followed by the window manager name. 267 ''; 268 apply = list: rec { 269 wm = filter (s: s.manage == "window") list; 270 dm = filter (s: s.manage == "desktop") list; 271 names = flip concatMap dm 272 (d: map (w: d.name + optionalString (w.name != "none") (" + " + w.name)) 273 (filter (w: d.name != "none" || w.name != "none") wm)); 274 desktops = mkDesktops names; 275 script = xsession wm dm; 276 }; 277 }; 278 279 job = { 280 281 preStart = mkOption { 282 type = types.lines; 283 default = ""; 284 example = "rm -f /var/log/my-display-manager.log"; 285 description = "Script executed before the display manager is started."; 286 }; 287 288 execCmd = mkOption { 289 type = types.str; 290 example = literalExample '' 291 "''${pkgs.slim}/bin/slim" 292 ''; 293 description = "Command to start the display manager."; 294 }; 295 296 environment = mkOption { 297 type = types.attrsOf types.unspecified; 298 default = {}; 299 example = { SLIM_CFGFILE = "/etc/slim.conf"; }; 300 description = "Additional environment variables needed by the display manager."; 301 }; 302 303 logsXsession = mkOption { 304 type = types.bool; 305 default = false; 306 description = '' 307 Whether the display manager redirects the 308 output of the session script to 309 <filename>~/.xsession-errors</filename>. 310 ''; 311 }; 312 313 }; 314 315 }; 316 317 }; 318 319 config = { 320 321 services.xserver.displayManager.xserverBin = "${xorg.xorgserver}/bin/X"; 322 323 }; 324 325}