at master 30 kB view raw
1{ 2 config, 3 lib, 4 utils, 5 pkgs, 6 ... 7}: 8 9with lib; 10 11let 12 13 # Abbreviations. 14 cfg = config.services.xserver; 15 xorg = pkgs.xorg; 16 17 # Map video driver names to driver packages. FIXME: move into card-specific modules. 18 knownVideoDrivers = { 19 # Alias so people can keep using "virtualbox" instead of "vboxvideo". 20 virtualbox = { 21 modules = [ xorg.xf86videovboxvideo ]; 22 driverName = "vboxvideo"; 23 }; 24 25 # Alias so that "radeon" uses the xf86-video-ati driver. 26 radeon = { 27 modules = [ xorg.xf86videoati ]; 28 driverName = "ati"; 29 }; 30 31 # modesetting does not have a xf86videomodesetting package as it is included in xorgserver 32 modesetting = { }; 33 }; 34 35 fontsForXServer = 36 config.fonts.packages 37 ++ 38 # We don't want these fonts in fonts.conf, because then modern, 39 # fontconfig-based applications will get horrible bitmapped 40 # Helvetica fonts. It's better to get a substitution (like Nimbus 41 # Sans) than that horror. But we do need the Adobe fonts for some 42 # old non-fontconfig applications. (Possibly this could be done 43 # better using a fontconfig rule.) 44 [ 45 pkgs.xorg.fontadobe100dpi 46 pkgs.xorg.fontadobe75dpi 47 ]; 48 49 xrandrOptions = { 50 output = mkOption { 51 type = types.str; 52 example = "DVI-0"; 53 description = '' 54 The output name of the monitor, as shown by 55 {manpage}`xrandr(1)` invoked without arguments. 56 ''; 57 }; 58 59 primary = mkOption { 60 type = types.bool; 61 default = false; 62 description = '' 63 Whether this head is treated as the primary monitor, 64 ''; 65 }; 66 67 monitorConfig = mkOption { 68 type = types.lines; 69 default = ""; 70 example = '' 71 DisplaySize 408 306 72 Option "DPMS" "false" 73 ''; 74 description = '' 75 Extra lines to append to the `Monitor` section 76 verbatim. Available options are documented in the MONITOR section in 77 {manpage}`xorg.conf(5)`. 78 ''; 79 }; 80 }; 81 82 # Just enumerate all heads without discarding XRandR output information. 83 xrandrHeads = 84 let 85 mkHead = num: config: { 86 name = "multihead${toString num}"; 87 inherit config; 88 }; 89 in 90 imap1 mkHead cfg.xrandrHeads; 91 92 xrandrDeviceSection = 93 let 94 monitors = forEach xrandrHeads (h: '' 95 Option "monitor-${h.config.output}" "${h.name}" 96 ''); 97 in 98 concatStrings monitors; 99 100 # Here we chain every monitor from the left to right, so we have: 101 # m4 right of m3 right of m2 right of m1 .----.----.----.----. 102 # Which will end up in reverse ----------> | m1 | m2 | m3 | m4 | 103 # `----^----^----^----' 104 xrandrMonitorSections = 105 let 106 mkMonitor = 107 previous: current: 108 singleton { 109 inherit (current) name; 110 value = '' 111 Section "Monitor" 112 Identifier "${current.name}" 113 ${optionalString (current.config.primary) '' 114 Option "Primary" "true" 115 ''} 116 ${optionalString (previous != [ ]) '' 117 Option "RightOf" "${(head previous).name}" 118 ''} 119 ${current.config.monitorConfig} 120 EndSection 121 ''; 122 } 123 ++ previous; 124 monitors = reverseList (foldl mkMonitor [ ] xrandrHeads); 125 in 126 concatMapStrings (getAttr "value") monitors; 127 128 configFile = 129 pkgs.runCommand "xserver.conf" 130 { 131 fontpath = optionalString (cfg.fontPath != null) ''FontPath "${cfg.fontPath}"''; 132 inherit (cfg) config; 133 preferLocalBuild = true; 134 } 135 '' 136 echo 'Section "Files"' >> $out 137 echo "$fontpath" >> $out 138 139 for i in ${toString fontsForXServer}; do 140 if test "''${i:0:''${#NIX_STORE}}" == "$NIX_STORE"; then 141 for j in $(find $i -name fonts.dir); do 142 echo " FontPath \"$(dirname $j)\"" >> $out 143 done 144 fi 145 done 146 147 ${concatMapStrings (m: '' 148 echo " ModulePath \"${m}/lib/xorg/modules\"" >> "$out" 149 '') cfg.modules} 150 151 echo '${cfg.filesSection}' >> $out 152 echo 'EndSection' >> $out 153 echo >> $out 154 155 echo "$config" >> $out 156 ''; # */ 157 158 prefixStringLines = 159 prefix: str: concatMapStringsSep "\n" (line: prefix + line) (splitString "\n" str); 160 161 indent = prefixStringLines " "; 162 163 # A scalable variant of the X11 "core" cursor 164 # 165 # If not running a fancy desktop environment, the cursor is likely set to 166 # the default `cursor.pcf` bitmap font. This is 17px wide, so it's very 167 # small and almost invisible on 4K displays. 168 fontcursormisc_hidpi = pkgs.xorg.fontxfree86type1.overrideAttrs ( 169 old: 170 let 171 # The scaling constant is 230/96: the scalable `left_ptr` glyph at 172 # about 23 points is rendered as 17px, on a 96dpi display. 173 # Note: the XLFD font size is in decipoints. 174 size = 2.39583 * cfg.dpi; 175 sizeString = builtins.head (builtins.split "\\." (toString size)); 176 in 177 { 178 postInstall = '' 179 alias='cursor -xfree86-cursor-medium-r-normal--0-${sizeString}-0-0-p-0-adobe-fontspecific' 180 echo "$alias" > $out/lib/X11/fonts/Type1/fonts.alias 181 ''; 182 } 183 ); 184in 185 186{ 187 188 imports = [ 189 ./display-managers/default.nix 190 ./window-managers/default.nix 191 ./desktop-managers/default.nix 192 (mkRemovedOptionModule [ 193 "services" 194 "xserver" 195 "startGnuPGAgent" 196 ] "See the 16.09 release notes for more information.") 197 (mkRemovedOptionModule [ 198 "services" 199 "xserver" 200 "startDbusSession" 201 ] "The user D-Bus session is now always socket activated and this option can safely be removed.") 202 (mkRemovedOptionModule [ 203 "services" 204 "xserver" 205 "useXFS" 206 ] "Use services.xserver.fontPath instead of useXFS") 207 (mkRemovedOptionModule [ "services" "xserver" "useGlamor" ] 208 "Option services.xserver.useGlamor was removed because it is unnecessary. Drivers that uses Glamor will use it automatically." 209 ) 210 (lib.mkRenamedOptionModuleWith { 211 sinceRelease = 2311; 212 from = [ 213 "services" 214 "xserver" 215 "layout" 216 ]; 217 to = [ 218 "services" 219 "xserver" 220 "xkb" 221 "layout" 222 ]; 223 }) 224 (lib.mkRenamedOptionModuleWith { 225 sinceRelease = 2311; 226 from = [ 227 "services" 228 "xserver" 229 "xkbModel" 230 ]; 231 to = [ 232 "services" 233 "xserver" 234 "xkb" 235 "model" 236 ]; 237 }) 238 (lib.mkRenamedOptionModuleWith { 239 sinceRelease = 2311; 240 from = [ 241 "services" 242 "xserver" 243 "xkbOptions" 244 ]; 245 to = [ 246 "services" 247 "xserver" 248 "xkb" 249 "options" 250 ]; 251 }) 252 (lib.mkRenamedOptionModuleWith { 253 sinceRelease = 2311; 254 from = [ 255 "services" 256 "xserver" 257 "xkbVariant" 258 ]; 259 to = [ 260 "services" 261 "xserver" 262 "xkb" 263 "variant" 264 ]; 265 }) 266 (lib.mkRenamedOptionModuleWith { 267 sinceRelease = 2311; 268 from = [ 269 "services" 270 "xserver" 271 "xkbDir" 272 ]; 273 to = [ 274 "services" 275 "xserver" 276 "xkb" 277 "dir" 278 ]; 279 }) 280 (lib.mkRemovedOptionModule [ 281 "services" 282 "xserver" 283 "tty" 284 ] "'services.xserver.tty' was removed because it was ineffective.") 285 ]; 286 287 ###### interface 288 289 options = { 290 291 services.xserver = { 292 293 enable = mkOption { 294 type = types.bool; 295 default = false; 296 description = '' 297 Whether to enable the X server. 298 ''; 299 }; 300 301 autorun = mkOption { 302 type = types.bool; 303 default = true; 304 description = '' 305 Whether to start the X server automatically. 306 ''; 307 }; 308 309 excludePackages = mkOption { 310 default = [ ]; 311 example = literalExpression "[ pkgs.xterm ]"; 312 type = types.listOf types.package; 313 description = "Which X11 packages to exclude from the default environment"; 314 }; 315 316 exportConfiguration = mkOption { 317 type = types.bool; 318 default = false; 319 description = '' 320 Whether to symlink the X server configuration under 321 {file}`/etc/X11/xorg.conf`. 322 ''; 323 }; 324 325 enableTCP = mkOption { 326 type = types.bool; 327 default = false; 328 description = '' 329 Whether to allow the X server to accept TCP connections. 330 ''; 331 }; 332 333 autoRepeatDelay = mkOption { 334 type = types.nullOr types.int; 335 default = null; 336 description = '' 337 Sets the autorepeat delay (length of time in milliseconds that a key must be depressed before autorepeat starts). 338 ''; 339 }; 340 341 autoRepeatInterval = mkOption { 342 type = types.nullOr types.int; 343 default = null; 344 description = '' 345 Sets the autorepeat interval (length of time in milliseconds that should elapse between autorepeat-generated keystrokes). 346 ''; 347 }; 348 349 inputClassSections = mkOption { 350 type = types.listOf types.lines; 351 default = [ ]; 352 example = literalExpression '' 353 [ ''' 354 Identifier "Trackpoint Wheel Emulation" 355 MatchProduct "ThinkPad USB Keyboard with TrackPoint" 356 Option "EmulateWheel" "true" 357 Option "EmulateWheelButton" "2" 358 Option "Emulate3Buttons" "false" 359 ''' 360 ] 361 ''; 362 description = "Content of additional InputClass sections of the X server configuration file."; 363 }; 364 365 modules = mkOption { 366 type = types.listOf types.path; 367 default = [ ]; 368 example = literalExpression "[ pkgs.xf86_input_wacom ]"; 369 description = "Packages to be added to the module search path of the X server."; 370 }; 371 372 resolutions = mkOption { 373 type = types.listOf types.attrs; 374 default = [ ]; 375 example = [ 376 { 377 x = 1600; 378 y = 1200; 379 } 380 { 381 x = 1024; 382 y = 786; 383 } 384 ]; 385 description = '' 386 The screen resolutions for the X server. The first element 387 is the default resolution. If this list is empty, the X 388 server will automatically configure the resolution. 389 ''; 390 }; 391 392 videoDrivers = mkOption { 393 type = types.listOf types.str; 394 default = [ 395 "modesetting" 396 "fbdev" 397 ]; 398 example = [ 399 "nvidia" 400 "amdgpu" 401 ]; 402 # TODO(@oxij): think how to easily add the rest, like those nvidia things 403 relatedPackages = concatLists ( 404 mapAttrsToList ( 405 n: v: 406 optional (hasPrefix "xf86video" n) { 407 path = [ 408 "xorg" 409 n 410 ]; 411 title = removePrefix "xf86video" n; 412 } 413 ) pkgs.xorg 414 ); 415 description = '' 416 The names of the video drivers the configuration 417 supports. They will be tried in order until one that 418 supports your card is found. 419 Don't combine those with "incompatible" OpenGL implementations, 420 e.g. free ones (mesa-based) with proprietary ones. 421 422 For unfree "nvidia*", the supported GPU lists are on 423 https://www.nvidia.com/object/unix.html 424 ''; 425 }; 426 427 videoDriver = mkOption { 428 type = types.nullOr types.str; 429 default = null; 430 example = "i810"; 431 description = '' 432 The name of the video driver for your graphics card. This 433 option is obsolete; please set the 434 {option}`services.xserver.videoDrivers` instead. 435 ''; 436 }; 437 438 drivers = mkOption { 439 type = types.listOf types.attrs; 440 internal = true; 441 description = '' 442 A list of attribute sets specifying drivers to be loaded by 443 the X11 server. 444 ''; 445 }; 446 447 dpi = mkOption { 448 type = types.nullOr types.int; 449 default = null; 450 description = '' 451 Force global DPI resolution to use for X server. It's recommended to 452 use this only when DPI is detected incorrectly; also consider using 453 `Monitor` section in configuration file instead. 454 ''; 455 }; 456 457 updateDbusEnvironment = mkOption { 458 type = types.bool; 459 default = false; 460 description = '' 461 Whether to update the DBus activation environment after launching the 462 desktop manager. 463 ''; 464 }; 465 466 xkb = { 467 layout = mkOption { 468 type = types.str; 469 default = "us"; 470 description = '' 471 X keyboard layout, or multiple keyboard layouts separated by commas. 472 ''; 473 }; 474 475 model = mkOption { 476 type = types.str; 477 default = "pc104"; 478 example = "presario"; 479 description = '' 480 X keyboard model. 481 ''; 482 }; 483 484 options = mkOption { 485 type = types.commas; 486 default = "terminate:ctrl_alt_bksp"; 487 example = "grp:caps_toggle,grp_led:scroll"; 488 description = '' 489 X keyboard options; layout switching goes here. 490 ''; 491 }; 492 493 variant = mkOption { 494 type = types.str; 495 default = ""; 496 example = "colemak"; 497 description = '' 498 X keyboard variant. 499 ''; 500 }; 501 502 dir = mkOption { 503 type = types.path; 504 default = "${pkgs.xkeyboard_config}/etc/X11/xkb"; 505 defaultText = literalExpression ''"''${pkgs.xkeyboard_config}/etc/X11/xkb"''; 506 description = '' 507 Path used for -xkbdir xserver parameter. 508 ''; 509 }; 510 }; 511 512 config = mkOption { 513 type = types.lines; 514 description = '' 515 The contents of the configuration file of the X server 516 ({file}`xorg.conf`). 517 518 This option is set by multiple modules, and the configs are 519 concatenated together. 520 521 In Xorg configs the last config entries take precedence, 522 so you may want to use `lib.mkAfter` on this option 523 to override NixOS's defaults. 524 ''; 525 }; 526 527 filesSection = mkOption { 528 type = types.lines; 529 default = ""; 530 example = ''FontPath "/path/to/my/fonts"''; 531 description = "Contents of the first `Files` section of the X server configuration file."; 532 }; 533 534 deviceSection = mkOption { 535 type = types.lines; 536 default = ""; 537 example = "VideoRAM 131072"; 538 description = "Contents of the first Device section of the X server configuration file."; 539 }; 540 541 screenSection = mkOption { 542 type = types.lines; 543 default = ""; 544 example = '' 545 Option "RandRRotation" "on" 546 ''; 547 description = "Contents of the first Screen section of the X server configuration file."; 548 }; 549 550 monitorSection = mkOption { 551 type = types.lines; 552 default = ""; 553 example = "HorizSync 28-49"; 554 description = "Contents of the first Monitor section of the X server configuration file."; 555 }; 556 557 enableTearFree = mkEnableOption "the TearFree option in the first Device section"; 558 559 extraConfig = mkOption { 560 type = types.lines; 561 default = ""; 562 description = "Additional contents (sections) included in the X server configuration file"; 563 }; 564 565 xrandrHeads = mkOption { 566 default = [ ]; 567 example = [ 568 "HDMI-0" 569 { 570 output = "DVI-0"; 571 primary = true; 572 } 573 { 574 output = "DVI-1"; 575 monitorConfig = "Option \"Rotate\" \"left\""; 576 } 577 ]; 578 type = 579 with types; 580 listOf ( 581 coercedTo str 582 (output: { 583 inherit output; 584 }) 585 (submodule { 586 options = xrandrOptions; 587 }) 588 ); 589 # Set primary to true for the first head if no other has been set 590 # primary already. 591 apply = 592 heads: 593 let 594 hasPrimary = any (x: x.primary) heads; 595 firstPrimary = head heads // { 596 primary = true; 597 }; 598 newHeads = singleton firstPrimary ++ tail heads; 599 in 600 if heads != [ ] && !hasPrimary then newHeads else heads; 601 description = '' 602 Multiple monitor configuration, just specify a list of XRandR 603 outputs. The individual elements should be either simple strings or 604 an attribute set of output options. 605 606 If the element is a string, it is denoting the physical output for a 607 monitor, if it's an attribute set, you must at least provide the 608 {option}`output` option. 609 610 The monitors will be mapped from left to right in the order of the 611 list. 612 613 By default, the first monitor will be set as the primary monitor if 614 none of the elements contain an option that has set 615 {option}`primary` to `true`. 616 617 ::: {.note} 618 Only one monitor is allowed to be primary. 619 ::: 620 621 Be careful using this option with multiple graphic adapters or with 622 drivers that have poor support for XRandR, unexpected things might 623 happen with those. 624 ''; 625 }; 626 627 serverFlagsSection = mkOption { 628 default = ""; 629 type = types.lines; 630 example = '' 631 Option "BlankTime" "0" 632 Option "StandbyTime" "0" 633 Option "SuspendTime" "0" 634 Option "OffTime" "0" 635 ''; 636 description = "Contents of the ServerFlags section of the X server configuration file."; 637 }; 638 639 moduleSection = mkOption { 640 type = types.lines; 641 default = ""; 642 example = '' 643 SubSection "extmod" 644 EndSubsection 645 ''; 646 description = "Contents of the Module section of the X server configuration file."; 647 }; 648 649 serverLayoutSection = mkOption { 650 type = types.lines; 651 default = ""; 652 example = '' 653 Option "AIGLX" "true" 654 ''; 655 description = "Contents of the ServerLayout section of the X server configuration file."; 656 }; 657 658 extraDisplaySettings = mkOption { 659 type = types.lines; 660 default = ""; 661 example = "Virtual 2048 2048"; 662 description = "Lines to be added to every Display subsection of the Screen section."; 663 }; 664 665 defaultDepth = mkOption { 666 type = types.int; 667 default = 0; 668 example = 8; 669 description = "Default colour depth."; 670 }; 671 672 fontPath = mkOption { 673 type = types.nullOr types.str; 674 default = null; 675 example = "unix/:7100"; 676 description = '' 677 Set the X server FontPath. Defaults to null, which 678 means the compiled in defaults will be used. See 679 man xorg.conf for details. 680 ''; 681 }; 682 683 display = mkOption { 684 type = types.nullOr types.int; 685 default = 0; 686 description = "Display number for the X server."; 687 }; 688 689 virtualScreen = mkOption { 690 type = types.nullOr types.attrs; 691 default = null; 692 example = { 693 x = 2048; 694 y = 2048; 695 }; 696 description = '' 697 Virtual screen size for Xrandr. 698 ''; 699 }; 700 701 logFile = mkOption { 702 type = types.nullOr types.str; 703 default = "/dev/null"; 704 example = "/var/log/Xorg.0.log"; 705 description = '' 706 Controls the file Xorg logs to. 707 708 The default of `/dev/null` is set so that systemd services (like `displayManagers`) only log to the journal and don't create their own log files. 709 710 Setting this to `null` will not pass the `-logfile` argument to Xorg which allows it to log to its default logfile locations instead (see `man Xorg`). You probably only want this behaviour when running Xorg manually (e.g. via `startx`). 711 ''; 712 }; 713 714 verbose = mkOption { 715 type = types.nullOr types.int; 716 default = 3; 717 example = 7; 718 description = '' 719 Controls verbosity of X logging. 720 ''; 721 }; 722 723 enableCtrlAltBackspace = mkOption { 724 type = types.bool; 725 default = false; 726 description = '' 727 Whether to enable the DontZap option, which binds Ctrl+Alt+Backspace 728 to forcefully kill X. This can lead to data loss and is disabled 729 by default. 730 ''; 731 }; 732 733 terminateOnReset = mkOption { 734 type = types.bool; 735 default = true; 736 description = '' 737 Whether to terminate X upon server reset. 738 ''; 739 }; 740 741 upscaleDefaultCursor = mkOption { 742 type = types.bool; 743 default = false; 744 description = '' 745 Upscale the default X cursor to be more visible on high-density displays. 746 Requires `config.services.xserver.dpi` to be set. 747 ''; 748 }; 749 }; 750 751 }; 752 753 ###### implementation 754 755 config = mkIf cfg.enable { 756 services.displayManager.enable = true; 757 758 services.xserver.displayManager.lightdm.enable = 759 let 760 dmConf = cfg.displayManager; 761 default = 762 !( 763 config.services.displayManager.gdm.enable 764 || config.services.displayManager.sddm.enable 765 || dmConf.xpra.enable 766 || dmConf.sx.enable 767 || dmConf.startx.enable 768 || config.services.greetd.enable 769 || config.services.displayManager.ly.enable 770 || config.services.displayManager.lemurs.enable 771 ); 772 in 773 mkIf (default) (mkDefault true); 774 775 services.xserver.videoDrivers = mkIf (cfg.videoDriver != null) [ cfg.videoDriver ]; 776 777 # FIXME: somehow check for unknown driver names. 778 services.xserver.drivers = flip concatMap cfg.videoDrivers ( 779 name: 780 let 781 driver = attrByPath [ name ] ( 782 if xorg ? ${"xf86video" + name} then { modules = [ xorg.${"xf86video" + name} ]; } else null 783 ) knownVideoDrivers; 784 in 785 optional (driver != null) ( 786 { 787 inherit name; 788 modules = [ ]; 789 driverName = name; 790 display = true; 791 } 792 // driver 793 ) 794 ); 795 796 assertions = [ 797 ( 798 let 799 primaryHeads = filter (x: x.primary) cfg.xrandrHeads; 800 in 801 { 802 assertion = length primaryHeads < 2; 803 message = 804 "Only one head is allowed to be primary in " 805 + "services.xserver.xrandrHeads, but there are " 806 + "${toString (length primaryHeads)} heads set to primary: " 807 + concatMapStringsSep ", " (x: x.output) primaryHeads; 808 } 809 ) 810 { 811 assertion = cfg.upscaleDefaultCursor -> cfg.dpi != null; 812 message = "Specify `config.services.xserver.dpi` to upscale the default cursor."; 813 } 814 ]; 815 816 environment.etc = 817 (optionalAttrs cfg.exportConfiguration { 818 "X11/xorg.conf".source = "${configFile}"; 819 # -xkbdir command line option does not seems to be passed to xkbcomp. 820 "X11/xkb".source = "${cfg.xkb.dir}"; 821 }) 822 # Needed since 1.18; see https://bugs.freedesktop.org/show_bug.cgi?id=89023#c5 823 // ( 824 let 825 cfgPath = "X11/xorg.conf.d/10-evdev.conf"; 826 in 827 { 828 ${cfgPath}.source = xorg.xf86inputevdev.out + "/share/" + cfgPath; 829 } 830 ); 831 832 environment.systemPackages = 833 utils.removePackagesByName [ 834 xorg.xorgserver.out 835 xorg.xrandr 836 xorg.xrdb 837 xorg.setxkbmap 838 xorg.iceauth # required for KDE applications (it's called by dcopserver) 839 xorg.xlsclients 840 xorg.xset 841 xorg.xsetroot 842 xorg.xinput 843 xorg.xprop 844 xorg.xauth 845 pkgs.xterm 846 xorg.xf86inputevdev.out # get evdev.4 man page 847 ] config.services.xserver.excludePackages 848 ++ optional (elem "virtualbox" cfg.videoDrivers) xorg.xrefresh; 849 850 environment.pathsToLink = [ "/share/X11" ]; 851 852 systemd.services.display-manager = { 853 description = "Display Manager"; 854 855 after = [ 856 "acpid.service" 857 "systemd-logind.service" 858 "systemd-user-sessions.service" 859 ]; 860 861 restartIfChanged = false; 862 863 environment = config.services.displayManager.environment; 864 865 preStart = '' 866 ${config.services.displayManager.preStart} 867 868 rm -f /tmp/.X0-lock 869 ''; 870 871 # Stop restarting if the display manager stops (crashes) 2 times 872 # in one minute. Starting X typically takes 3-4s. 873 startLimitIntervalSec = 30; 874 startLimitBurst = 3; 875 serviceConfig = { 876 Restart = "always"; 877 RestartSec = "200ms"; 878 SyslogIdentifier = "display-manager"; 879 }; 880 }; 881 882 services.xserver.displayManager.xserverArgs = [ 883 "-config ${configFile}" 884 "-xkbdir" 885 "${cfg.xkb.dir}" 886 ] 887 ++ optional (cfg.display != null) ":${toString cfg.display}" 888 ++ optional (cfg.dpi != null) "-dpi ${toString cfg.dpi}" 889 ++ optional (cfg.logFile != null) "-logfile ${toString cfg.logFile}" 890 ++ optional (cfg.verbose != null) "-verbose ${toString cfg.verbose}" 891 ++ optional (!cfg.enableTCP) "-nolisten tcp" 892 ++ optional (cfg.autoRepeatDelay != null) "-ardelay ${toString cfg.autoRepeatDelay}" 893 ++ optional (cfg.autoRepeatInterval != null) "-arinterval ${toString cfg.autoRepeatInterval}" 894 ++ optional cfg.terminateOnReset "-terminate"; 895 896 services.xserver.modules = concatLists (catAttrs "modules" cfg.drivers) ++ [ 897 xorg.xorgserver.out 898 xorg.xf86inputevdev.out 899 ]; 900 901 system.checks = singleton ( 902 pkgs.runCommand "xkb-validated" 903 { 904 inherit (cfg.xkb) 905 dir 906 model 907 layout 908 variant 909 options 910 ; 911 nativeBuildInputs = with pkgs.buildPackages; [ xkbvalidate ]; 912 preferLocalBuild = true; 913 } 914 '' 915 ${optionalString ( 916 config.environment.sessionVariables ? XKB_CONFIG_ROOT 917 ) "export XKB_CONFIG_ROOT=${config.environment.sessionVariables.XKB_CONFIG_ROOT}"} 918 XKB_CONFIG_ROOT="$dir" xkbvalidate "$model" "$layout" "$variant" "$options" 919 touch "$out" 920 '' 921 ); 922 923 services.xserver.config = '' 924 Section "ServerFlags" 925 Option "AllowMouseOpenFail" "on" 926 Option "DontZap" "${if cfg.enableCtrlAltBackspace then "off" else "on"}" 927 ${indent cfg.serverFlagsSection} 928 EndSection 929 930 Section "Module" 931 ${indent cfg.moduleSection} 932 EndSection 933 934 Section "Monitor" 935 Identifier "Monitor[0]" 936 ${indent cfg.monitorSection} 937 EndSection 938 939 # Additional "InputClass" sections 940 ${flip (concatMapStringsSep "\n") cfg.inputClassSections (inputClassSection: '' 941 Section "InputClass" 942 ${indent inputClassSection} 943 EndSection 944 '')} 945 946 947 Section "ServerLayout" 948 Identifier "Layout[all]" 949 ${indent cfg.serverLayoutSection} 950 # Reference the Screen sections for each driver. This will 951 # cause the X server to try each in turn. 952 ${flip concatMapStrings (filter (d: d.display) cfg.drivers) (d: '' 953 Screen "Screen-${d.name}[0]" 954 '')} 955 EndSection 956 957 # For each supported driver, add a "Device" and "Screen" 958 # section. 959 ${flip concatMapStrings cfg.drivers (driver: '' 960 961 Section "Device" 962 Identifier "Device-${driver.name}[0]" 963 Driver "${driver.driverName or driver.name}" 964 ${indent (optionalString cfg.enableTearFree ''Option "TearFree" "true"'')} 965 ${indent cfg.deviceSection} 966 ${indent (driver.deviceSection or "")} 967 ${indent xrandrDeviceSection} 968 EndSection 969 ${optionalString driver.display '' 970 971 Section "Screen" 972 Identifier "Screen-${driver.name}[0]" 973 Device "Device-${driver.name}[0]" 974 ${optionalString (cfg.monitorSection != "") '' 975 Monitor "Monitor[0]" 976 ''} 977 978 ${indent cfg.screenSection} 979 ${indent (driver.screenSection or "")} 980 981 ${optionalString (cfg.defaultDepth != 0) '' 982 DefaultDepth ${toString cfg.defaultDepth} 983 ''} 984 985 ${optionalString 986 ( 987 driver.name != "virtualbox" 988 && (cfg.resolutions != [ ] || cfg.extraDisplaySettings != "" || cfg.virtualScreen != null) 989 ) 990 ( 991 let 992 f = depth: '' 993 SubSection "Display" 994 Depth ${toString depth} 995 ${optionalString (cfg.resolutions != [ ]) 996 "Modes ${concatMapStrings (res: ''"${toString res.x}x${toString res.y}"'') cfg.resolutions}" 997 } 998 ${indent cfg.extraDisplaySettings} 999 ${optionalString ( 1000 cfg.virtualScreen != null 1001 ) "Virtual ${toString cfg.virtualScreen.x} ${toString cfg.virtualScreen.y}"} 1002 EndSubSection 1003 ''; 1004 in 1005 concatMapStrings f [ 1006 8 1007 16 1008 24 1009 ] 1010 ) 1011 } 1012 1013 EndSection 1014 ''} 1015 '')} 1016 1017 ${xrandrMonitorSections} 1018 1019 ${cfg.extraConfig} 1020 ''; 1021 1022 fonts.packages = [ 1023 (if cfg.upscaleDefaultCursor then fontcursormisc_hidpi else pkgs.xorg.fontcursormisc) 1024 pkgs.xorg.fontmiscmisc 1025 ]; 1026 1027 }; 1028 1029 # uses relatedPackages 1030 meta.buildDocsInSandbox = false; 1031}