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