at 15.09-beta 19 kB view raw
1{ config, lib, pkgs, pkgs_i686, ... }: 2 3with lib; 4 5let 6 7 kernelPackages = config.boot.kernelPackages; 8 9 # Abbreviations. 10 cfg = config.services.xserver; 11 xorg = pkgs.xorg; 12 13 14 # Map video driver names to driver packages. FIXME: move into card-specific modules. 15 knownVideoDrivers = { 16 nouveau = { modules = [ pkgs.xf86_video_nouveau ]; }; 17 unichrome = { modules = [ pkgs.xorgVideoUnichrome ]; }; 18 virtualbox = { modules = [ kernelPackages.virtualboxGuestAdditions ]; driverName = "vboxvideo"; }; 19 ati = { modules = [ pkgs.xorg.xf86videoati pkgs.xorg.glamoregl ]; }; 20 intel-testing = { modules = with pkgs.xorg; [ xf86videointel-testing glamoregl ]; driverName = "intel"; }; 21 }; 22 23 fontsForXServer = 24 config.fonts.fonts ++ 25 # We don't want these fonts in fonts.conf, because then modern, 26 # fontconfig-based applications will get horrible bitmapped 27 # Helvetica fonts. It's better to get a substitution (like Nimbus 28 # Sans) than that horror. But we do need the Adobe fonts for some 29 # old non-fontconfig applications. (Possibly this could be done 30 # better using a fontconfig rule.) 31 [ pkgs.xorg.fontadobe100dpi 32 pkgs.xorg.fontadobe75dpi 33 ]; 34 35 36 # Just enumerate all heads without discarding XRandR output information. 37 xrandrHeads = let 38 mkHead = num: output: { 39 name = "multihead${toString num}"; 40 inherit output; 41 }; 42 in imap mkHead cfg.xrandrHeads; 43 44 xrandrDeviceSection = let 45 monitors = flip map xrandrHeads (h: '' 46 Option "monitor-${h.output}" "${h.name}" 47 ''); 48 # First option is indented through the space in the config but any 49 # subsequent options aren't so we need to apply indentation to 50 # them here 51 monitorsIndented = if length monitors > 1 52 then singleton (head monitors) ++ map (m: " " + m) (tail monitors) 53 else monitors; 54 in concatStrings monitorsIndented; 55 56 # Here we chain every monitor from the left to right, so we have: 57 # m4 right of m3 right of m2 right of m1 .----.----.----.----. 58 # Which will end up in reverse ----------> | m1 | m2 | m3 | m4 | 59 # `----^----^----^----' 60 xrandrMonitorSections = let 61 mkMonitor = previous: current: singleton { 62 inherit (current) name; 63 value = '' 64 Section "Monitor" 65 Identifier "${current.name}" 66 ${optionalString (previous != []) '' 67 Option "RightOf" "${(head previous).name}" 68 ''} 69 EndSection 70 ''; 71 } ++ previous; 72 monitors = reverseList (foldl mkMonitor [] xrandrHeads); 73 in concatMapStrings (getAttr "value") monitors; 74 75 configFile = pkgs.stdenv.mkDerivation { 76 name = "xserver.conf"; 77 78 xfs = optionalString (cfg.useXFS != false) 79 ''FontPath "${toString cfg.useXFS}"''; 80 81 inherit (cfg) config; 82 83 buildCommand = 84 '' 85 echo 'Section "Files"' >> $out 86 echo $xfs >> $out 87 88 for i in ${toString fontsForXServer}; do 89 if test "''${i:0:''${#NIX_STORE}}" == "$NIX_STORE"; then 90 for j in $(find $i -name fonts.dir); do 91 echo " FontPath \"$(dirname $j)\"" >> $out 92 done 93 fi 94 done 95 96 for i in $(find ${toString cfg.modules} -type d); do 97 if test $(echo $i/*.so* | wc -w) -ne 0; then 98 echo " ModulePath \"$i\"" >> $out 99 fi 100 done 101 102 echo 'EndSection' >> $out 103 104 echo "$config" >> $out 105 ''; # */ 106 }; 107 108in 109 110{ 111 112 imports = 113 [ ./display-managers/default.nix 114 ./window-managers/default.nix 115 ./desktop-managers/default.nix 116 ]; 117 118 119 ###### interface 120 121 options = { 122 123 services.xserver = { 124 125 enable = mkOption { 126 type = types.bool; 127 default = false; 128 description = '' 129 Whether to enable the X server. 130 ''; 131 }; 132 133 autorun = mkOption { 134 type = types.bool; 135 default = true; 136 description = '' 137 Whether to start the X server automatically. 138 ''; 139 }; 140 141 exportConfiguration = mkOption { 142 type = types.bool; 143 default = false; 144 description = '' 145 Whether to symlink the X server configuration under 146 <filename>/etc/X11/xorg.conf</filename>. 147 ''; 148 }; 149 150 enableTCP = mkOption { 151 type = types.bool; 152 default = false; 153 description = '' 154 Whether to allow the X server to accept TCP connections. 155 ''; 156 }; 157 158 inputClassSections = mkOption { 159 type = types.listOf types.lines; 160 default = []; 161 example = [ '' 162 Identifier "Trackpoint Wheel Emulation" 163 MatchProduct "ThinkPad USB Keyboard with TrackPoint" 164 Option "EmulateWheel" "true 165 Option "EmulateWheelButton" "2" 166 Option "Emulate3Buttons" "false" 167 '' ]; 168 description = "Content of additional InputClass sections of the X server configuration file."; 169 }; 170 171 modules = mkOption { 172 type = types.listOf types.path; 173 default = []; 174 example = literalExample "[ pkgs.xf86_input_wacom ]"; 175 description = "Packages to be added to the module search path of the X server."; 176 }; 177 178 resolutions = mkOption { 179 type = types.listOf types.attrs; 180 default = []; 181 example = [ { x = 1600; y = 1200; } { x = 1024; y = 786; } ]; 182 description = '' 183 The screen resolutions for the X server. The first element 184 is the default resolution. If this list is empty, the X 185 server will automatically configure the resolution. 186 ''; 187 }; 188 189 videoDrivers = mkOption { 190 type = types.listOf types.str; 191 # !!! We'd like "nv" here, but it segfaults the X server. 192 default = [ "ati" "cirrus" "intel" "vesa" "vmware" "modesetting" ]; 193 example = [ "vesa" ]; 194 description = '' 195 The names of the video drivers the configuration 196 supports. They will be tried in order until one that 197 supports your card is found. 198 ''; 199 }; 200 201 videoDriver = mkOption { 202 type = types.nullOr types.str; 203 default = null; 204 example = "i810"; 205 description = '' 206 The name of the video driver for your graphics card. This 207 option is obsolete; please set the 208 <option>services.xserver.videoDrivers</option> instead. 209 ''; 210 }; 211 212 drivers = mkOption { 213 type = types.listOf types.attrs; 214 internal = true; 215 description = '' 216 A list of attribute sets specifying drivers to be loaded by 217 the X11 server. 218 ''; 219 }; 220 221 vaapiDrivers = mkOption { 222 type = types.listOf types.path; 223 default = [ ]; 224 example = literalExample "[ pkgs.vaapiIntel pkgs.vaapiVdpau ]"; 225 description = '' 226 Packages providing libva acceleration drivers. 227 ''; 228 }; 229 230 startGnuPGAgent = mkOption { 231 type = types.bool; 232 default = false; 233 description = '' 234 Whether to start the GnuPG agent when you log in. The GnuPG agent 235 remembers private keys for you so that you don't have to type in 236 passphrases every time you make an SSH connection or sign/encrypt 237 data. Use <command>ssh-add</command> to add a key to the agent. 238 ''; 239 }; 240 241 startDbusSession = mkOption { 242 type = types.bool; 243 default = true; 244 description = '' 245 Whether to start a new DBus session when you log in with dbus-launch. 246 ''; 247 }; 248 249 layout = mkOption { 250 type = types.str; 251 default = "us"; 252 description = '' 253 Keyboard layout. 254 ''; 255 }; 256 257 xkbModel = mkOption { 258 type = types.str; 259 default = "pc104"; 260 example = "presario"; 261 description = '' 262 Keyboard model. 263 ''; 264 }; 265 266 xkbOptions = mkOption { 267 type = types.str; 268 default = "terminate:ctrl_alt_bksp"; 269 example = "grp:caps_toggle, grp_led:scroll"; 270 description = '' 271 X keyboard options; layout switching goes here. 272 ''; 273 }; 274 275 xkbVariant = mkOption { 276 type = types.str; 277 default = ""; 278 example = "colemak"; 279 description = '' 280 X keyboard variant. 281 ''; 282 }; 283 284 config = mkOption { 285 type = types.lines; 286 description = '' 287 The contents of the configuration file of the X server 288 (<filename>xorg.conf</filename>). 289 ''; 290 }; 291 292 deviceSection = mkOption { 293 type = types.lines; 294 default = ""; 295 example = "VideoRAM 131072"; 296 description = "Contents of the first Device section of the X server configuration file."; 297 }; 298 299 screenSection = mkOption { 300 type = types.lines; 301 default = ""; 302 example = '' 303 Option "RandRRotation" "on" 304 ''; 305 description = "Contents of the first Screen section of the X server configuration file."; 306 }; 307 308 monitorSection = mkOption { 309 type = types.lines; 310 default = ""; 311 example = "HorizSync 28-49"; 312 description = "Contents of the first Monitor section of the X server configuration file."; 313 }; 314 315 xrandrHeads = mkOption { 316 default = []; 317 example = [ "HDMI-0" "DVI-0" ]; 318 type = with types; listOf string; 319 description = '' 320 Simple multiple monitor configuration, just specify a list of XRandR 321 outputs which will be mapped from left to right in the order of the 322 list. 323 324 Be careful using this option with multiple graphic adapters or with 325 drivers that have poor support for XRandR, unexpected things might 326 happen with those. 327 ''; 328 }; 329 330 serverFlagsSection = mkOption { 331 default = ""; 332 example = 333 '' 334 Option "BlankTime" "0" 335 Option "StandbyTime" "0" 336 Option "SuspendTime" "0" 337 Option "OffTime" "0" 338 ''; 339 description = "Contents of the ServerFlags section of the X server configuration file."; 340 }; 341 342 moduleSection = mkOption { 343 type = types.lines; 344 default = ""; 345 example = 346 '' 347 SubSection "extmod" 348 EndSubsection 349 ''; 350 description = "Contents of the Module section of the X server configuration file."; 351 }; 352 353 serverLayoutSection = mkOption { 354 type = types.lines; 355 default = ""; 356 example = 357 '' 358 Option "AIGLX" "true" 359 ''; 360 description = "Contents of the ServerLayout section of the X server configuration file."; 361 }; 362 363 extraDisplaySettings = mkOption { 364 type = types.lines; 365 default = ""; 366 example = "Virtual 2048 2048"; 367 description = "Lines to be added to every Display subsection of the Screen section."; 368 }; 369 370 defaultDepth = mkOption { 371 type = types.int; 372 default = 0; 373 example = 8; 374 description = "Default colour depth."; 375 }; 376 377 useXFS = mkOption { 378 # FIXME: what's the type of this option? 379 default = false; 380 example = "unix/:7100"; 381 description = "Determines how to connect to the X Font Server."; 382 }; 383 384 tty = mkOption { 385 type = types.int; 386 default = 7; 387 description = "Virtual console for the X server."; 388 }; 389 390 display = mkOption { 391 type = types.int; 392 default = 0; 393 description = "Display number for the X server."; 394 }; 395 396 virtualScreen = mkOption { 397 type = types.nullOr types.attrs; 398 default = null; 399 example = { x = 2048; y = 2048; }; 400 description = '' 401 Virtual screen size for Xrandr. 402 ''; 403 }; 404 405 useGlamor = mkOption { 406 type = types.bool; 407 default = false; 408 description = '' 409 Whether to use the Glamor module for 2D acceleration, 410 if possible. 411 ''; 412 }; 413 }; 414 415 }; 416 417 418 419 ###### implementation 420 421 config = mkIf cfg.enable { 422 423 hardware.opengl.enable = mkDefault true; 424 425 services.xserver.videoDrivers = mkIf (cfg.videoDriver != null) [ cfg.videoDriver ]; 426 427 # FIXME: somehow check for unknown driver names. 428 services.xserver.drivers = flip concatMap cfg.videoDrivers (name: 429 let driver = 430 attrByPath [name] 431 (if xorg ? ${"xf86video" + name} 432 then { modules = [xorg.${"xf86video" + name}]; } 433 else null) 434 knownVideoDrivers; 435 in optional (driver != null) ({ inherit name; driverName = name; } // driver)); 436 437 assertions = 438 [ { assertion = !(config.programs.ssh.startAgent && cfg.startGnuPGAgent); 439 message = 440 '' 441 The OpenSSH agent and GnuPG agent cannot be started both. Please 442 choose between programs.ssh.startAgent and services.xserver.startGnuPGAgent. 443 ''; 444 } 445 { assertion = config.security.polkit.enable; 446 message = "X11 requires Polkit to be enabled (security.polkit.enable = true)."; 447 } 448 ]; 449 450 environment.etc = 451 (optionals cfg.exportConfiguration 452 [ { source = "${configFile}"; 453 target = "X11/xorg.conf"; 454 } 455 # -xkbdir command line option does not seems to be passed to xkbcomp. 456 { source = "${pkgs.xkeyboard_config}/etc/X11/xkb"; 457 target = "X11/xkb"; 458 } 459 ]); 460 461 environment.systemPackages = 462 [ xorg.xorgserver 463 xorg.xrandr 464 xorg.xrdb 465 xorg.setxkbmap 466 xorg.iceauth # required for KDE applications (it's called by dcopserver) 467 xorg.xlsclients 468 xorg.xset 469 xorg.xsetroot 470 xorg.xinput 471 xorg.xprop 472 pkgs.xterm 473 pkgs.xdg_utils 474 ] 475 ++ optional (elem "virtualbox" cfg.videoDrivers) xorg.xrefresh; 476 477 environment.pathsToLink = 478 [ "/etc/xdg" "/share/xdg" "/share/applications" "/share/icons" "/share/pixmaps" ]; 479 480 # The default max inotify watches is 8192. 481 # Nowadays most apps require a good number of inotify watches, 482 # the value below is used by default on several other distros. 483 boot.kernel.sysctl."fs.inotify.max_user_watches" = mkDefault 524288; 484 485 systemd.defaultUnit = mkIf cfg.autorun "graphical.target"; 486 487 systemd.services.display-manager = 488 { description = "X11 Server"; 489 490 after = [ "systemd-udev-settle.service" "local-fs.target" "acpid.service" ]; 491 492 restartIfChanged = false; 493 494 environment = 495 { 496 XKB_BINDIR = "${xorg.xkbcomp}/bin"; # Needed for the Xkb extension. 497 XORG_DRI_DRIVER_PATH = "/run/opengl-driver/lib/dri"; # !!! Depends on the driver selected at runtime. 498 LD_LIBRARY_PATH = concatStringsSep ":" ( 499 [ "${xorg.libX11}/lib" "${xorg.libXext}/lib" ] 500 ++ concatLists (catAttrs "libPath" cfg.drivers)); 501 } // cfg.displayManager.job.environment; 502 503 preStart = 504 '' 505 ${cfg.displayManager.job.preStart} 506 507 rm -f /tmp/.X0-lock 508 ''; 509 510 script = "${cfg.displayManager.job.execCmd}"; 511 512 serviceConfig = { 513 Restart = "always"; 514 RestartSec = "200ms"; 515 }; 516 }; 517 518 services.xserver.displayManager.xserverArgs = 519 [ "-ac" 520 "-terminate" 521 "-logfile" "/var/log/X.${toString cfg.display}.log" 522 "-config ${configFile}" 523 ":${toString cfg.display}" "vt${toString cfg.tty}" 524 "-xkbdir" "${pkgs.xkeyboard_config}/etc/X11/xkb" 525 ] ++ optional (!cfg.enableTCP) "-nolisten tcp"; 526 527 services.xserver.modules = 528 concatLists (catAttrs "modules" cfg.drivers) ++ 529 [ xorg.xorgserver 530 xorg.xf86inputevdev 531 ]; 532 533 services.xserver.config = 534 '' 535 Section "ServerFlags" 536 Option "AllowMouseOpenFail" "on" 537 ${cfg.serverFlagsSection} 538 EndSection 539 540 Section "Module" 541 ${cfg.moduleSection} 542 EndSection 543 544 Section "Monitor" 545 Identifier "Monitor[0]" 546 ${cfg.monitorSection} 547 EndSection 548 549 Section "InputClass" 550 Identifier "Keyboard catchall" 551 MatchIsKeyboard "on" 552 Option "XkbRules" "base" 553 Option "XkbModel" "${cfg.xkbModel}" 554 Option "XkbLayout" "${cfg.layout}" 555 Option "XkbOptions" "${cfg.xkbOptions}" 556 Option "XkbVariant" "${cfg.xkbVariant}" 557 EndSection 558 559 # Additional "InputClass" sections 560 ${flip concatMapStrings cfg.inputClassSections (inputClassSection: '' 561 Section "InputClass" 562 ${inputClassSection} 563 EndSection 564 '')} 565 566 567 Section "ServerLayout" 568 Identifier "Layout[all]" 569 ${cfg.serverLayoutSection} 570 # Reference the Screen sections for each driver. This will 571 # cause the X server to try each in turn. 572 ${flip concatMapStrings cfg.drivers (d: '' 573 Screen "Screen-${d.name}[0]" 574 '')} 575 EndSection 576 577 ${if cfg.useGlamor then '' 578 Section "Module" 579 Load "dri2" 580 Load "glamoregl" 581 EndSection 582 '' else ""} 583 584 # For each supported driver, add a "Device" and "Screen" 585 # section. 586 ${flip concatMapStrings cfg.drivers (driver: '' 587 588 Section "Device" 589 Identifier "Device-${driver.name}[0]" 590 Driver "${driver.driverName or driver.name}" 591 ${if cfg.useGlamor then ''Option "AccelMethod" "glamor"'' else ""} 592 ${cfg.deviceSection} 593 ${xrandrDeviceSection} 594 EndSection 595 596 Section "Screen" 597 Identifier "Screen-${driver.name}[0]" 598 Device "Device-${driver.name}[0]" 599 ${optionalString (cfg.monitorSection != "") '' 600 Monitor "Monitor[0]" 601 ''} 602 603 ${cfg.screenSection} 604 605 ${optionalString (cfg.defaultDepth != 0) '' 606 DefaultDepth ${toString cfg.defaultDepth} 607 ''} 608 609 ${optionalString 610 (driver.name != "virtualbox" && 611 (cfg.resolutions != [] || 612 cfg.extraDisplaySettings != "" || 613 cfg.virtualScreen != null)) 614 (let 615 f = depth: 616 '' 617 SubSection "Display" 618 Depth ${toString depth} 619 ${optionalString (cfg.resolutions != []) 620 "Modes ${concatMapStrings (res: ''"${toString res.x}x${toString res.y}"'') cfg.resolutions}"} 621 ${cfg.extraDisplaySettings} 622 ${optionalString (cfg.virtualScreen != null) 623 "Virtual ${toString cfg.virtualScreen.x} ${toString cfg.virtualScreen.y}"} 624 EndSubSection 625 ''; 626 in concatMapStrings f [8 16 24] 627 )} 628 629 EndSection 630 '')} 631 632 ${xrandrMonitorSections} 633 ''; 634 635 }; 636 637}